Donato Donato - 6 months ago 29
Ruby Question

Ruby: Handle arbitrary method names

I remember watching a ruby screencast from Dave Thomas about using metaprogramming to create method names that do not need to adhere to identifier syntax requirements. Typically, an identifier must not contain spaces. And he showed how to create methods with spaces. But I don't remember how it's done.

I have arbitrary field names for a class that

s Mongoid::Document. This works fine, where _field can be a string like 'Hello World':

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

I want to override the setter. So I tried this:

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

Unfortunately, if the _field is a string like 'Hello World', I will get an error:

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

How can I get around this?


define_method lets you do this:

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

But you have to call it with send since the method name in normal invocation syntax is not allowed either.

You can do this from a class definition as well.

class MyClass
  def name

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

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

Lastly, I feel obliged to say this is probably a terrible idea. I'm not sure exactly what you're after here, but there is probably a better way. :can != :should.