Posted at

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

More than 1 year has passed since last update.

テキストで雛形を作って、てきとーにそこに値を埋め込みたい。

埋め込む値は、どっか他から与えられる。

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


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)

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