rcmdnk's blog

Persons in Context: The Challenge of Individuality in Theory and Practice: 32 (Psychoanalytic Inquiry Book Series)

Octopressで画像を設置する{% img~ %}等には、 通常第二引数以降は単に文字列として渡すので yamlブロックで指定した値やLiquid文法でassignした変数をそのまま渡すことが出来ません。 (単なる文字列として処理される)

ただ、変数を渡すためには一旦文字列で変数名を与えて 何らかの形でタグクラスの中で文字列を変換してあげれば 出来たのでその方法について。

やりたいこと

サイトのロゴを_config.ymlで指定していたりする場合 その画像を

sitelogo: /images/MacApp/MacLogoMiddle.png

と指定しておいて

1
<img src="{{site.sitelogo}}"/>

としてやれば{{site.sitelogo}}部分は変換されて正しく表示できますが、

1
{% img {{site.sitelogo}} %}

のようにimgタグを使うことは出来ません。 この場合、{{site.sitelogo}}部分は そのまま{{site.sitelogo}}という文字列として渡されます。 両側の{{~}}を外してもそのまま渡されるだけです。

1つの決まった画像ならhtmlでも良いのですが、 他のタグ等でも直接変数が渡せたら便利だと思ったので そのやり方について調べてみました。

contextから取れる

Liquid::Tagを継承して新しいタグを作っているプラグインを見ると、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module Jekyll
  class NewTag < Liquid::Tag
    def initialize(tag_name, markup, tokens)
      @markup = markup
      # または"markup"から適当な変数を摘出
      super
    end

    def render(context)
      # 処理
    end
  end
end

Liquid::Template.register_tag('newtag', Jekyll::Newtag)

大体こんな感じです。 initializeの方のtag_nameはタグの名前(つまりこの場合は必ずnewtag)、 markupにはタグに書いた第二引数以降が入ります(imgタグならクラスや画像位置等)。 tokens

Finally, the tokens are all of the other tags that appear within this block tag, including the closing endnavigation tag.

なんだそうで、特にBlockタグの場合に中で処理するのに必要なんだと思います。 通常、継承したクラスで自分で扱うことはあまり無いです 1

imgタグを定義してるplugins/image_tag.rbでは

1
2
3
if markup =~ /(?<class>\S.*\s+)?(?<src>(?:https?:\/\/|\/|\S+\/)\S+)(?:\s+(?<width>\d+))?(?:\s+(?<height>\d+))?(?<title>\s+.+)?/i
  @img = attributes.reduce({}) { |img, attr| img[attr] = $~[attr].strip if $~[attr]; img }
  ...

こんなかんじでmarkupを@imgに入れていってrenderで使います。 (http(s)://で始まったり/を含むような文字列の場合それをsrcとする)

一方、render関数ではcontextという引数を持っていて ページの情報等を持っています。 従って、上のsite.sitelogoの情報も持っていて、 context['site.sitelogo']としてやれば_config.ymlで指定したsitelogoの値を 取ってこれます2

同じようにページの途中で

{% assign img=/image/a.jpg %}

assignしたものやcaptureブロックで設定した値もそのまま使えます。

これを適用してあげればいいんですが、普段は直接URLを書いて 必要なときだけ変換して欲しいので、画像パスにval:と言う 値をつけた時だけ変換するようにしました。

image_tag.rb.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
diff --git a/plugins/image_tag.rb b/plugins/image_tag.rb
index 4567000..55e8ea3 100644
--- a/plugins/image_tag.rb
+++ b/plugins/image_tag.rb
@@ -24,7 +24,7 @@ module Jekyll
     def initialize(tag_name, markup, tokens)
       attributes = ['class', 'src', 'width', 'height', 'title']
 
-      if markup =~ /(?<class>\S.*\s+)?(?<src>(?:https?:\/\/|\/|\S+\/)\S+)(?:\s+(?<width>\d+))?(?:\s+(?<height>\d+))?(?<title>\s+.+)?/i
+      if markup =~ /(?<class>\S.*\s+)?(?<src>(?:https?:\/\/|\S*\/|val:)\S+)(?:\s+(?<width>\d+))?(?:\s+(?<height>\d+))?(?<title>\s+.+)?/i
         @img = attributes.reduce({}) { |img, attr| img[attr] = $~[attr].strip if $~[attr]; img }
         if /(?:"|')(?<title>[^"']+)?(?:"|')\s+(?:"|')(?<alt>[^"']+)?(?:"|')/ =~ @img['title']
           @img['title']  = title
@@ -39,6 +39,12 @@ module Jekyll
 
     def render(context)
       if @img
+        @img['src'] = context[@img['src'].split(':')[1]] if @img['src'] =~ /^val:/
+        if @img['class'] and ! @img['class'].include?('noimgpath')
+          if context['site.imgpath'] and @img['src'] !~ /^(http|#{context['site.imgpath']})/
+            @img['src'] = context['site.imgpath']+@img['src']
+          end
+        end
         "<img #{@img.collect {|k,v| "#{k}=\"#{v}\"" if v}.join(" ")}>"
       else
         "Error processing input, expected syntax: {% img [class name(s)] [http[s]:/]/path/to/image [width [height]] [title text | \"title text\" [\"alt text\"]] %}"

initializeの方でval:という値の時にもsrcに入れて、 renderの中でval:だった場合には変換しています。

加えて、画像置き場を変えたい時もあるので、その値をimgpathとして _config.ymlで設定して、httpから始まるものでない場合には そのパスを最初に与えるようにもしました。 自己サイト内の別の場所も指定できるように、 パスを追加したくない場合はnoimgpathをクラスに(つまりは画像URLより先に書く) 与えます。

まとめ

yamlブロックで指定した値やLiquid文法で作った値は render関数の中でcontextから直接値を引き出せる、と言うことが分かってれば 後はやり方しだいで、と言った感じです。

Sponsored Links
  1. Blockタグの場合には特にendnavigationを見つけるのに必要ですが、 タグの場合はそもそもどの範囲が指定されてるのかも良くわかりません。 出力させてみると呼び出されてる部分のほぼ全体を表示している様に見えます。

  2. contextregistersというhash変数を持っていて

    config = context.registers[:site].config
    puts config['sitelogo']
    

    みたいな取り方をしているプラグインが多いですが、 直接アウトプットタグ({{~}})で使う値をcontextに 与える様な上の形でも取れます。

Sponsored Links

« Windowsでミラードライバーが問題でエアロが有効にできない時の対処法 Vimでハイライト表示を調べる »

}