0

Quiet new to ruby I can't figure out something. Here's a Sample code

class Big
  def self.metaclass; class << self; self; end; end

  def self.convertor b
    metaclass.instance_eval do
      define_method( :convert ) do |val|
        return b val
       end
    end
  end
end

class Small < Big
  convertor { |v| v.to_i + 1 }
end

puts Small.convert('18')

The aim is to have a lot of subclass to Big and i like to avoid to define in each

def convert(val)
  return conversion_specific_to_subclass(val)
end

Doing the former way i just have one line for each subclass. But can't get it to work. What is it i'm doing wrong? Is there a better way to accomplish what i wish?

Thanks in advance

edit: As asked here are the errors this code produce (with ruby 2.1.0)

test2.rb:4:in `convertor': wrong number of arguments (0 for 1) (ArgumentError)
from test2.rb:14:in `<class:Small>'`
zedryas
  • 718
  • 6
  • 19
  • What do you mean "doesn't work"? Is there an error? Other output? Please be more specific. – Linuxios Feb 20 '14 at 23:37
  • using the amperstamp (b&) i then have: test2.rb:14:in `': undefined method `convertor' for Small:Class (NoMethodError) Hopefully it will helps ;) – zedryas Feb 20 '14 at 23:38

2 Answers2

3

You're overcomplicating this - since all you want is the ability to bind a block to a specific method name, just do that!

class Big
  def self.converter(&block)
    define_singleton_method :convert, &block
  end
end

class Small < Big
  converter {|v| v.to_i + 1 }
end

That way, when you invoke Small::converter, it will define a class method that accepts a parameter list as defined in your block args, and the return value will be the return value of your block.

Chris Heald
  • 61,439
  • 10
  • 123
  • 137
  • OUps - not understood completely - how come when calling Small.convert we're calling the generated function? – zedryas Feb 20 '14 at 23:58
  • Oops. My code defines `convert` as an instance method; I'll fix it. – Chris Heald Feb 20 '14 at 23:58
  • and when running it i've got: test2.rb:2:in `convert': wrong number of arguments (1 for 0) (ArgumentError) from test2.rb:11:in `
    '
    – zedryas Feb 20 '14 at 23:59
  • Updated. That should be closer to what you want. – Chris Heald Feb 21 '14 at 00:03
  • yep that works - gonna check doc on singleton now :D Thanks a lot ;) – zedryas Feb 21 '14 at 00:09
  • `singleton_class` is just the eigenclass/metaclass. `define_singleton_method` just defines the methods on the class's metaclass (making it a class method) rather than the class itself (where it would be an instance method) – Chris Heald Feb 21 '14 at 00:10
0

Try this code:

class Big
  def self.metaclass; class << self; self; end; end

  def self.convertor(&b)
    metaclass.instance_eval do
      define_method( :convert ) do |val|
        return b[val]
       end
    end
  end
end

class Small < Big
  convertor { |v| v.to_i + 1 }
end

puts Small.convert('18')

There were two problems in your code. One, you have to capture the block using an & argument. So, this is the new method declaration:

def self.convertor(&b)

And finally, you have to call the block using block call syntax in your return, like this:

return b[val]

Or this:

return b.call(val)

You cannot call a block like b val.

Also, it's good style in Ruby to always include the parenthesis everywhere.

Linuxios
  • 34,849
  • 13
  • 91
  • 116
  • That has done it thanks a lot :):). Quick question is it preferable to use the block as is or use yield in the Big#convertor method? And finally how do i close the subject? – zedryas Feb 20 '14 at 23:51
  • @dryas: You can just use yield, but Chris's solution above is cleaner. Also, by accepting an answer, you can marked the question as solved. – Linuxios Feb 20 '14 at 23:54