Ruby爱好者!我正在尝试用红宝石编写DSL,我希望能够创建一些神奇的方法(不确定这是我想要的最准确的术语)。
我希望能够做到以下几点:
a = [1, 2, 3]
b = 2
(a contains b)
让它解决为真或假。
基本上,我如何定义函数“contains”以便它需要一个数组a
和一个变量b
并执行a.contains?(b)
,但是没有所有相关的ruby特定的语法?
答案 0 :(得分:2)
如果你想要一个不使用ruby语法的DSL,你至少需要编写一个解析器来执行转换(raganwalds重写lib可能是一个起点,http://github.com/raganwald/rewrite)
那就是说,你不想这样做。这是需要维护的更多代码,Ruby已经做出了许多艰难的决定,这使得编写语言语法变得困难。自然语言编程对于非程序员来说也不容易使用,因为格式的精确性是具有挑战性的方面(例如参见Applecript)。
答案 1 :(得分:1)
您可以滥用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
答案 2 :(得分:0)
我能想到的最接近的事情是:
def contains var, useless_symbol, arr
arr.include? var
end
然后你可以这样称呼它:
contains b, :in, a
我认为没有办法在你自己的职能中使用中缀符号。