在Ruby中对字符串和block求解

http://tech.ddvip.com   2008年01月18日    社区交流

内容摘要:对包含代码的字符串和block求解,是我最钟爱的Ruby特性之一。Ruby提供了多种不同类型的求解方式;不过我最常用的是下面这些:eval、instance_eval和class_eval。

  应对一般的简单查询,上面的做法不存在问题;但如果涉及到子查询的话,就另当别论了。前述实现对下面示例中的代码是无效的。

Delete.from[:table1].where do
exists(Select[:column2].from[:table2].where do
equal table1.column1, table2.column2
end
end

  不过我们可以使用eval与指定的binding一起,让上面的代码正常工作。此处的技巧是:将表名数组从外部的block隐式地传递到内部的block中。用显式方式传递会让DSL看起来很丑陋。

  在Select类的where方法中,我们使用block的binding对象来得到Delete实例的tables集合。我们能够这样做,在于Delete实例的where方法被作为上下文(亦即block的binding)传递给了select实例的where方法。binding对象(或上下文)是block被创建时的作用范围。下面的代码是对where方法的完整实现。

def where(&block)
@text += " where "
tables.concat(eval("respond_to?(:tables) ? tables : []", block.binding)).inspect
instance_eval &block
end

  我们把eval所在的语句拆开看看它都干了什么。它做的第一件事情是:

eval "respond_to?(:tables) ? tables : []", block.binding

  它的作用是“在block的作用范围中对语句进行求解”。在当前例子中,block的作用范围是:

Delete.from[:table1].where do .. end

  这个范围是一个Delete类的实例,Delete类中确实有tables方法,其作用是暴露表名数组(tables#=>[:table1])。因此,语句被求解后会返回表名数组。剩余的语句就可以看作:

责编:豆豆技术应用

正在加载评论...