2016-10-12 30 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')'(或其他)。这可能是你想要重写的。 –