Soptq

Soptq

Probably a full-stack, mainly focusing on Distributed System / Consensus / Privacy-preserving Tech etc. Decentralization is a trend, privacy must be protected.
twitter
github
bilibili

ゼロから自分のJekyllプラグインを実装する:フィルター

Filter プラグインとは何ですか?#

Filters プラグインは、Jekyll プラグインの中で最も一般的なタイプであり、Ruby の内部メソッドを Liquid に公開し、最終的にページで呼び出すことができます。たとえば、Jekyll で構築された静的ウェブページを使用している場合、次のようなコンテンツが多く表示されることに気付くかもしれません:

{% assign foo = 10 %}
{% foo | plus: 4 %}
{{ foo }}

これは Liquid 言語です。最初の行と 2 番目の行は、{% %}で囲まれた演算式であり、3 番目の行は、{{ }}で囲まれた変数を出力することを示しています。Liquid は非常にシンプルなテンプレート言語であり、半日で学び終わることができます。Liquid に興味がある場合は、公式のドキュメントを参照してください。

したがって、これまでの説明から、Filter とは何でしょうか?実際、上記のコードの 2 行目のplusは Filter であり、fooを入力として受け取り、fooに 4 を加えて再びfooに代入することを意味します。つまり、foo = foo + 4と同じです。

Filter の利点は何ですか?#

Filter は実際には、Jekyll が許可するプラグインの中で 2 番目に便利なプラグインタイプかもしれません(最も便利なプラグインタイプは Hook である可能性があります)。Filter は非常に広範で、次のようなことに使用できますが、これに限定されません:

  • 2 つの日付間の差を簡単に計算する。
  • 記事に目次を生成する。
  • メールアドレスを自動的に隠す。
  • 記事の文字数と読了時間を計算する。

なぜこれらは JavaScript で実装できると思うのですか?#

確かに、理論的には Filter プラグインで実現できることはすべて、実行時に JavaScript を使用して実行することができます。ただし、これらのタスクをプラグインを使用してコンパイル時に完了させることで、ウェブサイトのパフォーマンスを向上させることができるため、非常に便利です。

注意!Pages ではプラグインを使用できません#

GitHub Pages(または他のほとんどの Pages)は、セキュリティ上の理由からプラグイン機能を--safeオプションで無効にしています。したがって、ウェブサイトを GitHub Pages にデプロイしている場合、プラグインは機能しません。

ただし、GitHub Pages に公開する方法はあります。ローカルで変換を行い、生成されたファイルを Jekyll ではなく GitHub にアップロードするだけです。

さあ始めましょう#

この記事では、最も簡単な Filter から始めて、記事の文字数と読了時間を計算する簡単な Filter を実装します。この Filter は、ウェブページが記事を表示する際に文字数と予想される読了時間を表示するのに役立ちます。

Jekyll の公式ドキュメントによると、すべての Jekyll プラグインは、プロジェクトディレクトリの_pluginsフォルダに保存する必要があります。したがって、プロジェクトのルートディレクトリに_pluginsフォルダがない場合は、まず手動で_pluginsフォルダを作成する必要があります。次に、新しく作成した_pluginsフォルダにjekyll_reading_time.rbという名前の Ruby ファイルを作成します。そして、このファイルを開き、このプラグインをReadingTimeという名前にします。

module ReadingTime

end 

Liquid に公開する必要がある 2 つのメソッドがあります。1 つ目はcount_words(html)メソッドで、ウェブページを渡して記事の文字数を計算します。2 つ目はreading_time(html)メソッドで、ウェブページを渡しておおよその読了時間を計算します。reading_time(html)メソッドは簡単に書くことができ、文字数を取得し、1 分あたりの読了文字数で割り、切り上げることで読了時間を計算します。

module ReadingTime

	def count_words(html)
		
	end

	def reading_time(html)
		(count_words(html) / 140.0).ceil
	end

end 

ウェブページの文字数を計算するために、まず Ruby ライブラリのnokogiriを使用して html をオブジェクトに解析し、再帰的に各 html オブジェクトを処理し、テキストのないオブジェクトを無視し、他のオブジェクトの中にテキストがあるかどうかをクエリします。このプロセスを処理するために、プライベート関数を使用します。

require ‘nokogiri’

module ReadingTime

	def count_words(html)
		words(html)
	end

	def reading_time(html)
		(count_words(html) / 140.0).ceil
	end

	private

	def text_nodes(root)
		ignored_tags = %w[ area audio canvas code embed footer form img map math nav object pre script svg table track video ]

		texts = 0
		root.children.each { |node|
			if node.text?
		    	text_array = node.text.unpack(“U*”)
		    	text_array.each { |c|
		        	texts = texts + 1
		    	}
			elsif not ignored_tags.include? node.name
				texts = texts + text_nodes(node)
			end
		}
		texts
	end

	def words(html)
		fragment = Nokogiri::HTML.fragment html
		text_nodes(fragment)
	end

end 

プラグインの全体的な形ができましたが、最後のステップは Jekyll にこのプラグインを登録することです。

Jekyll に新しいプラグインを登録するためには、モジュールの外で Jekyll の登録メソッドを呼び出すだけです。

require ‘nokogiri’

module ReadingTime

	def count_words(html)
		words(html)
	end

	def reading_time(html)
		(count_words(html) / 140.0).ceil
	end

	private

	def text_nodes(root)
		ignored_tags = %w[ area audio canvas code embed footer form img map math nav object pre script svg table track video ]

		texts = 0
		root.children.each { |node|
			if node.text?
		    	text_array = node.text.unpack(“U*”)
		    	text_array.each { |c|
		        	texts = texts + 1
		    	}
			elsif not ignored_tags.include? node.name
				texts = texts + text_nodes(node)
			end
		}
		texts
	end

	def words(html)
		fragment = Nokogiri::HTML.fragment html
		text_nodes(fragment)
	end

end 

Liquid::Template.register_filter(ReadingTime)

完成しました!最初のプラグインが完成しました!これからウェブページを作成する際に、記事の文字数と予想される読了時間を取得したい場合は、html コード内で次のように書くだけです:

この記事は{{ post.content | count_words }}文字です
おおよその読了時間は{{ post.content | reading_time }}分です
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。