Ruby

BasicObjectで雑なテンプレートエンジンみたいなものを作る

テキストで雛形を作って、てきとーにそこに値を埋め込みたい。
埋め込む値は、どっか他から与えられる。

どうすんのかなぁ、と思って、試しに雑に作ってみた。

my_template.rb
class MyTemplate < BasicObject
  def initialize(template, parameters={})
    @template = template
    @parameters = parameters
  end

  def compile
    instance_eval("\"#{@template}\"")
  end

  def method_missing(name, *args)
    return @parameters[name] if @parameters.key?(name)
    super
  end
end

使い方は、こんな感じ。
第一引数にテンプレートの文字列、第二引数に埋め込みたい値を持ったHashを与える。

sample_code1.rb
template = MyTemplate.new('Hello, #{name}!', { name: 'World' })
template.compile #=> Hello, World!

埋め込みたい値の名前はマルチバイト文字列もやろうと思えばできる。

sample_code2.rb
template = MyTemplate.new('Hello, #{名前}!', { %s"名前": 'World' })
template.compile #=> Hello, World!

BasicObjectinstance_evalを使うことで、他の定数やクラスは見えない。
そのため、ある程度は悪いことはできないようにできていそう。

sample_code3.rb
template = MyTemplate.new('Hello, #{Dir.glob("./**/*.rb")}!', { name: 'World' })
template.compile #=> NameError (Dir cannot be autoloaded from an anonymous class or module)

実際のテンプレートエンジンのソースを読んだことないので、これと近いことをしているのかはわかりません。