あなたは虐待することができますmethod_missing
。トリッキーなことは、ブロックのローカル変数に直接アクセスできないことです。ブロックの内部バインディングをどこかにキャプチャする必要があります(残念ながらblock.binding
、ブロックの外部バインディングを返します)。
次のコードを実行できます。
DSL.new do
a = [1, 2, 3]
b = 2
a contains b
end
次のように:
class DSL
attr_reader :last_binding
def initialize(&block)
set_trace_func method(:trace).to_proc
instance_eval(&block)
set_trace_func nil
end
def trace(event, file, line, id, binding, klass)
if event.to_s == "call" and klass == self.class and id.to_s == "method_missing"
@last_binding ||= @current_binding
set_trace_func nil
else
@current_binding = binding
end
end
def lvars
eval('local_variables', last_binding).map(&:to_s)
end
def method_missing(name, *args)
name = name.to_s
if lvars.include? name
eval(name, last_binding).send(*args.flatten)
else
["#{name}?", *args]
end
end
end
class Array
alias contains? include?
end