介紹
對包含代碼的字串和block求解,是我最鐘愛的Ruby特性之一。Ruby提供了多種不同類型的求解方式;不過我最常用的是下面這些:eval、instance_eval和class_eval。
Module.class_eval
使用Module類的class_eval(及其別名module_eval)方法,可以在一個類的定義或者module定義的上下文中對給定字串或block進行求解。我們常常用class_eval來向類的定義中加入方法,或是包含其他的module。
klass = Class.new
klass.class_eval do
include ERB::Util
def encoded_hello
htnl_escape "Hello World"
end
end
klass.new.encoded_hello #=> Hello World
不使用class_eval也可以達到上面的效果,但是要犧牲代碼的可讀性。
klass = Class.new
klass.send :include, ERB::Util
klass.send :define_method, :encoded_hello do
html_escape "Hello World"
end
klass.send :public, :encoded_hello
klass.new.encoded_hello #=> Hello World
Object.instance_eval
使用Object的instance_eval方法,可以在一個類執行個體的上下文中對給定字串或block進行求解。這是個功能強大的概念:你可以先在任何上下文中建立一塊代碼,然後在一個單獨的對象執行個體的上下文中對這塊代碼進行求解。為了設定代碼執行的上下文,self變數要設定為執行代碼時所在的對象執行個體,以使得代碼可以訪問對象執行個體的變數。
class Navigator
def initialize
@page_index = 0
end
def next
@page_index += 1
end
end
navigator = Navigator.new
navigator.next
navigator.next
navigator.instance_eval "@page_index" #=> 2
navigator.instance_eval { @page_index } #=> 2
與使用class_eval的樣本類似,執行個體變數的值可以通過其他的方式擷取,不過使用instance_eval是一種非常直觀的做法。