2010-05-29 59 views
3

我試圖寫一個DSL,讓我做Ruby的元編程

Policy.name do 
author "Foo" 
reviewed_by "Bar" 
end 

下面的代碼幾乎可以處理它:

class Policy 
    include Singleton 
    def self.method_missing(name,&block) 
     puts name 
     puts "#{yield}" 
    end 
    def self.author(name) 
    puts name 
    end 
    def self.reviewed_by(name) 
    puts name 
    end 
end 

定義我的方法類方法(self.method_name )我可以訪問它使用以下語法:

Policy.name do 
Policy.author "Foo" 
Policy.reviewed_by "Bar" 
end 

如果我從方法名稱中刪除「自我」,並嘗試使用我想要的語法,然後我收到一個錯誤「方法未找到」在主,所以它不能找到我的功能,直到模塊內核。它好,我明白錯誤。但我該如何解決它?我如何修復我的課程,使其與我所需的語法一起工作?

回答

4

爲了控制self在塊的範圍內(因爲author解析爲self.author),您可以使用instance_eval

class Policy 
    def self.name(&block) 
    PolicyNameScope.new(block) 
    end 

    class PolicyNameScope 
    def initialize(block) 
     instance_eval(&block)  
    end 

    def author(author) 
     @author = author 
    end 

    def reviewed_by(reviewed_by) 
     @reviewed_by = reviewed_by 
    end 
    end 
end 

policy = Policy.name do 
    author "Dawg" 
    reviewed_by "Dude" 
end 

p policy 
# => #<Policy::PolicyNameScope:0x7fb81ef9f910 @reviewed_by="Dude", @author="Dawg"> 

PolicyNameScope類有被允許在name塊的實例方法。這是因爲Policy的方法在塊內部不可用,使DSL變得更加緊密。

由於您的示例超出了上下文範圍,因此我無法進一步幫助您 - 此代碼本身似乎不太有用。

+0

嗨,八月,我在玩ruby元編程,你的例子+解釋幫了我很多。 StackOverflow規則! – 2010-05-29 18:14:04

1

八月提出的上述答案是正確的,但是如果你想用你的構造函數用於其他目的,那麼上面的方法失敗。因此,在這種情況下,您必須使用除上述之外的其他方法。這是我沒有使用類構造函數準備的解決方案。

class Policy 

    def self.method_missing(name,&block) 
    self.class_eval(&block) 
    end 
    def self.author(name) 
    p name 
    end 
    def self.reviewed_by(name) 
    p name 
    end 

end 

Policy.name do 
    author "Foo" 
    reviewed_by "Bar" 
end 

這不是一個優化的解決方案,而是解決您陳述的問題。