2016-10-12 34 views
1

我記得看過Dave Thomas的ruby屏幕截圖,講述如何使用元編程創建不需要遵守標識符語法要求的方法名稱。通常,標識符不能包含空格。他展示瞭如何用空格創建方法。但我不記得它是如何完成的。Ruby:處理任意方法名稱

我有一個類的任意字段名稱include s Mongoid :: Document。這工作正常,_field可以是像'Hello World'這樣的字符串:

MyClass.class_eval <<-EOS 
    field :'#{ _field }', type: #{_type} 
EOS 

我想重寫setter。所以,我想這一點:

MyClass.class_eval <<-EOS 
    field :'#{ _field }', type: #{_type} 
    def #{ _field }=(val) 
    self['#{ _field }'] = [self.send('#{ _field }')[0], val] 
    end 
EOS 

不幸的是,如果_field像的「Hello World」的字符串,我會得到一個錯誤:

SyntaxError: (eval):2: formal argument cannot be a constant 
      def Hello World=(val) 

我怎樣才能解決這個得到什麼?

+0

僅僅因爲該屬性在MongoDB內部被稱爲「Hello World」並不意味着您必須(甚至不應該)在Ruby中使用該名稱。 ORM/ODM的一部分工作是處理數據庫與使用O [RD] M的代碼之間的阻抗不匹配,重命名數據庫屬性/字段以匹配Ruby屬性約定肯定會成爲其中的一部分。 –

+0

你知道,Mongoid支持[動態字段](https://docs.mongodb.com/ruby-driver/master/tutorials/6.0.0/mongoid-documents/#dynamic-fields)開箱即用,aren你呢? – Stefan

+1

@ muistooshort你是對的。我的決定是使用:as選項:Mongoid提供:field:'Hello World',輸入:Array,如::hello_world – Donato

回答

4

define_method讓你這樣做:

define_method(:"hello world") { puts 'hello world' } 
send :"hello world" 

但是你既然在正常調用語法方法名是不允許的或者與send調用它。


您也可以從類定義中做到這一點。

class MyClass 
    def name 
    @name 
    end 

    define_method :"set name" do |new_name| 
    @name = new_name 
    end 
end 

instance = MyClass.new 
instance.send :"set name", 'Bob' 
instance.name #=> Bob 

最後,我覺得有必要說,這可能是一個可怕的想法。我不確定究竟是你在這裏之後,但可能有更好的方法。 :can != :should

+0

我正在使用Rails和Mongoid,我不認爲Rails會在不使用send的情況下顯式調用它。 – Donato

+1

其中包含空格的方法名稱非常堅固,但也可以在此處演示。 – tadman

+0

@Donato因爲您通常使用語法上有效的方法名稱,因爲方法名稱是您在代碼中鍵入的內容。如果你正在生成這樣的方法,你可能需要一個接受鍵作爲參數的方法。我敢打賭,Mongoid有一個接口,看起來像'instance.set('hello world','new value')'(或其他)。這可能是你想要重寫的。 –