title-logo

Drops - A template for Middleman blog

November 22, 2014

このブログで使っているテンプレートを公開しました。テンプレートの名前は Drops といいます。上にいるキャラが水滴くんっぽかったので。

https://github.com/5t111111/middleman-blog-drops-template

せっかく公開したので、Middleman 公式のテンプレートリストにも載せてもらえるように Middleman Directory にリクエストも出してみました。これで載っけてくれるものなのかどうかはわからないけど。

ぶっちゃけ、公開すること自体が目的だったというよりは、公開するという体でソースを整理したかった…要は、ほっとくと自分もワケわかんなくなってしまうので、その前にリファクタリングしとく動機が欲しかった、というのが正直なところです。できれば、公開したテンプレートをそのまま自分でも使えるのが理想的だったんですが、ある程度まではうまくいったものの、いくつかどうしてもうまく解決できない問題があって最終的には完全な共通化は諦めました。

method_missing をフックして動的に割り当てられる属性のチェック

うまく解決できなかった問題その 1 です。

config.rb で設定した値が動的に属性に割り当てられる仕組みになっているところがあって、しっかりコードを読んだわけじゃないけど、おそらく以下のような感じで method_missing をフックしてるんだろうなと推測されます。

class Foo

  def initialize(**arg)
    @bar = arg
  end

  def method_missing(name)
    @bar[name.to_sym] || super
  end
end

foo = Foo.new(key1: 1, key2: 2)
puts "foo.key1 #=> #{foo.key1}"
puts "foo.key2 #=> #{foo.key2}"
puts "foo.key3 #=> #{foo.key3}"

実行するとこんな感じで、属性が動的に割り当てられているかのように扱うことができます。ハッシュにキーが存在しない場合は、親クラスの method_missing を呼び出すので、 最終的に例外が発生します。

foo.key1 #=> 1
foo.key2 #=> 2
test.rb:9:in `method_missing': undefined method `key3' for #<Foo:0x007f98c1886718 @bar={:key1=>1, :key2=>2}> (NoMethodError)
	from test.rb:16:in `<main>'

で、この属性の値をビュー側で参照したい、でも値がセットされていないこともあるので、事前にチェックしたい、と考えたんですが、このチェックが難しい。実際にオブジェクトに定義されているわけではないので、当然 defined?respond_to? も偽の値しか返してくれません。

defined?(foo.key1) #=> nil
foo.respond_to?(:key1) #=> false
defined?(foo.key3) #=> nil
foo.respond_to?(:key3) #=> false

結局、NameError の例外をハンドリングするヘルパーメソッドを作って、ビューからはそれを経由してアクセスすることで事前のチェックができるようになりましたが、なんか他にいいやり方がある気がしています。

config.rb で定義されている変数を SCSS で参照したい

うまく解決できなかった問題その 2 です。

config.rb で設定されている変数を SCSS (Sass) から参照し、その値によって SCSS で処理を分岐させようとしました。

実際には、これはうまくいかなかったというより、「やっぱ SCSS と Ruby コードの結合はしない方がいいかな…」と思ってやめた、という方が正しいです。ココでもこう言ってる人がいるし。

You should never need to use ruby in your css and javascript, if you find yourself doing it you are probably approaching it in the wrong way.

一応、config.rb 内で Sass::Script::Functions モジュールを再オープンしてメソッドを定義しておけば、SCSS の中からそのメソッドを実行できるようなので、もしどうしても必要なときが来たら試してみようかな、と思います。