[Hugo] 各ページのconfigにidを付与してみた



Nプログラマ(@Nprog128)です。

Hugoで作ってみたいショートコードがあり、それには各記事に固有のidが必要なので、まずはidをもたせてみました。

WordPressのpost_idみたいなやつですね。

やる分には簡単なのですが、ちょっと大変なトコロもあります。

なプ

簡単なのに大変って、、、なんか矛盾してない?

どうやって固有idをもたせるか?

まずはidをもたせる

これは簡単で各記事のFront Matterにidを書いてやればいいだけです。

この記事のFront Matterから抜粋すると、こんな感じです。

Front Matter コードを開く
Front Matter
1
2---
3id: "000117"
4title: "[Hugo] 各ページのconfigにidを付与してみた "
5# 色々と設定値が続く...
6---

これでこの記事の設定にidをもたせることができました。

ページオブジェクトを使って、こんな感じで参照することができます。

サンプル コードを開く
サンプル
1{{ .Params.id }}

idを固有にするには、、、

さて、固有なidにするにはどうするかというと、、、

連番を手動で振っていきます。

まぁ、、、それだけです。

本当はページを新規作成した時に自動で固有idを付与したいのですが、今の所方法が分からなかったです。。。

手動だと重複してしまう可能性もありますが、そこまで厳密である必要がないですしidを使う時に分かるので、これでいいかなと。

あとは重複があるかを調べるプログラムを作る予定ですので、これでカバーします。

固有idを振るのはいいが、しかし、、、

まぁ固有なidを注意深く各記事に設定していけばこれでいいのですが、それは面倒です。

この記事を書いている時点で下書きを含めて90以上の記事があります。

1記事1分で終わらせたとしても、90分はかかりますし連番を打ち間違える可能性もあります。

そこで今回は、Ruby製の各記事に固有idを付与するスクリプトを作りました。

前置きが長かったですが、こういうスクリプトを作ったよというお話です。

本題、固有idを振るスクリプトを作りました。

さて、ここからが冒頭の大変なトコロ。

idを振るのは簡単だけど、それを全記事に付与するスクリプトを作るのがちょっと大変ってことです。

なプ

なんちゃってプログラマにはちょっと難しくて大変だわ。。。

最初にコードからどどーんと載せますね。

main.rb コードを開く
main.rb
 1count = 1
 2file_paths = `#{"find ./content -name \"*.md\""}`
 3
 4for path in file_paths.split("\n") do
 5  puts "processing " + path + "..."
 6
 7  padding_count = count.to_s.rjust(6, "0") # padding
 8  puts (__dir__ + "/" + path)
 9  markdown_file = File.open(__dir__ + "/" + path)
10  file_contents = markdown_file.read.sub(/---/, "---\nid: \"#{padding_count}\"")
11  markdown_file.close
12
13  markdown_file = File.open(__dir__ + "/" + path, "w")
14  markdown_file.write(file_contents)
15  markdown_file.close
16  count = count + 1
17end

あまりエレガントな処理は書けないので、素直に書いています。

ファイル数も少ないし、実行するのは初回のみですので。。。

なプ

あとはarchetypes/post.mdにidの雛形を追加しておけば大丈夫。

バックアップを!

このスクリプトを実行すると、既存の.mdファイルを上書きしてFront Matterにidを付与します。

失敗しても元に戻せるようにバックアップを取っておくことをおすすめします。

Gitで管理している方はcheckoutするだけでいいですね。

コードの説明

ざっくりと言うと、こんな感じです。

記事のファイルリストを取得して、各記事のFront Matterの始まり部分を連番idを追加した形に置き換えています。

これで終了なのですが、自分でもやっていることを忘れてしまうのでコードの説明も書いておきます。

1. ファイルリストの取得

抜粋 コードを開く
抜粋
1file_paths = `#{"find ./content -name \"*.md\""}`

記事のファイルリストを取得するために、findコマンドを使います。

自分の場合は、Hugoの記事をこんな感じで配置しているので、findで指定したディレクトリ配下のmdファイルを取得するようにしました。

1content
2└── post
3    └── 2020
4        ├── 01
5        │   ├── 01-sample.md
6        │   └── 31-sample.md
7        └── 02
8            └── 01-sample.md

試しにshellでfindコマンドを実行すると、こんな感じでファイルリストを取得することができます。

1> find ./content -name "*.md"
2./content/post/2020/02/01-sample.md
3./content/post/2020/01/01-sample.md
4./content/post/2020/01/31-sample.md

2. forでファイルリストを処理していく

抜粋 コードを開く
抜粋
1for path in file_paths.split("\n") do

ruby内のfindコマンドを実行した結果が、改行を含めた1行で返ってきているのでsplitメソッドで分割して、forでクルクルと回します。

なプ

ちなみに、puts関数はデバッグ用なので不要な削除してもらってオッケーです。

次は、一つずつファイルに対してidを付与していく処理になります。

2.1 forの中: idの0詰め

抜粋 コードを開く
抜粋
1padding_count = count.to_s.rjust(6, "0") # padding

0詰めは好みですが、自分はidを6桁の0詰めで表示することにしました。

6桁あれば人生で記事を書き続けても十分足りると思います。

少し計算してみましょう。

記事を毎日書いたとして、1年で365記事、10年で3650記事です。

自分がガリガリとパソコンを使える年数を考えると、あと30年くらいです。

ということで30年 * 365 = 10950記事くらいがMAXです。

なプ

あれ、5桁でよくね?

書いている最中に計算してみたら、5桁で良かった気がします。。。

試算で1桁間違えました。

2.2 forの中: Front Matterの始まりを置換する

抜粋 コードを開く
抜粋
1  markdown_file = File.open(__dir__ + "/" + path)
2  file_contents = markdown_file.read.sub(/---/, "---\nid: \"#{padding_count}\"")
3  markdown_file.close

ファイルを読み取りモードで開き、FrontMatterの始まりを探して、それを始まり + 改行 + idという形に置換し、そのファイルの全内容を変数に入れています。

置換処理にはsubメソッドを使っており、これは最初に見つかったものを置換してくれます。

configはファイルの先頭に記述しているので、一番最初に見つかった—がFront Matterの始まりになる、という感じです。

今回はFront MatterをYAMLで記述しているので、始まりはになります。

なプ

tomlなら+++ですね

ここが実行されると、こんな感じでFrontMatterの部分が置き換わります。

idは000001の場合で書いています。

変更前のFront Matter コードを開く
変更前のFront Matter
1---
2title: "記事のタイトル"
3# 色々と設定値が続く...
4---
変更後のFront Matter コードを開く
変更後のFront Matter
1---
2id: "000001"
3title: "記事のタイトル"
4# 色々と設定値が続く...
5---

置き換わった状態のファイルの全内容を変数に入れておき、closeメソッドでファイルを閉じます。

2.3 forの中: 置き換えた内容でファイルを上書き

抜粋 コードを開く
抜粋
1  markdown_file = File.open(__dir__ + "/" + path, "w")
2  markdown_file.write(file_contents)
3  markdown_file.close
4  count = count + 1

先程はファイルを読み取りモードで開いていましたが、今度は書き込みモードで開きます。

writeメソッドを使い、先程置換した内容が入っているfile_contentsを書き込みます。

最後にcloseメソッドでファイルをクローズすれば、保存完了です。

ファイルを一つ置換したので、固有のidを一つ増やします。

これを全てのファイルリスト分繰り返していきます。

スクリプトを実行する

これを実行してうまくいけば、全記事にidが付与されます。

スクリプトと記事の入ったディレクトリはこんな感じです。

 1.
 2├── content
 3│   └── post
 4│       └── 2020
 5│           ├── 01
 6│           │   ├── 01-sample.md
 7│           │   └── 31-sample.md
 8│           └── 02
 9│               └── 01-sample.md
10└── main.rb

この状態で以下のコマンドを実行します。

実行コマンド 開く
実行コマンド
1ruby main.rb
2# デバッグ用のputs関数がある場合は、それが終わるまで表示される。

処理が終わった後、idが付与されているかを確認しましょう。

gitを使っている場合は、diffで確認できますね。

なプ

差分確認も数が多くて大変だった。。。

おわりに

今回は、Hugoで各記事のconfigに固有idを付与する、という内容でした。

まだこれだけでは何も変化がありませんが、自分の作ってみたい機能には必要な準備です。

うまく実装できるといいのですが。。。

ちなみにこのスクリプトを作るのに30分くらいかかりました。

subメソッドを見つけるまでに時間がかかってしまいましたね(それまで自作でゴリゴリ書いてた。。。orz)

idを手動で書くより正確で早く付与することができたので、良かったと思います。

なプ

一回しか使わないけどね。

それでは、このへんで。
バイナリー!

\ ちょっとお買い物 /


関連した記事