Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redefining a single ruby method on a single instance with a lambda

Tags:

oop

ruby

In Ruby, is there a way to redefine a method of a particular instance of a class using a proc? For example:

class Foo
  def bar()
    return "hello"
  end
end

x = Foo.new
y = Foo.new

(Something like):

y.method(:bar) = lambda { return "goodbye" }

x.bar
y.bar

Producing:

hello
goodbye

Thanks.

like image 591
kmorris511 Avatar asked Apr 29 '09 15:04

kmorris511


3 Answers

def define_singleton_method_by_proc(obj, name, block)
  metaclass = class << obj; self; end
  metaclass.send(:define_method, name, block)
end
p = proc { "foobar!" }
define_singleton_method_by_proc(y, :bar, p)

or, if you want to monkey-patch Object to make it easy

class Object
  # note that this method is already defined in Ruby 1.9
  def define_singleton_method(name, callable = nil, &block)
    block ||= callable
    metaclass = class << self; self; end
    metaclass.send(:define_method, name, block)
  end
end

p = proc { "foobar!" }
y.define_singleton_method(:bar, p)
#or
y.define_singleton_method(:bar) do
   "foobar!"
end

or, if you want to define your proc inline, this may be more readable

class << y
  define_method(:bar, proc { "foobar!" })
end

or,

class << y
  define_method(:bar) { "foobar!" }
end

this is the most readable, but probably doesn't fit your needs

def y.bar
  "goodbye"
end

This question is highly related

like image 162
John Douthat Avatar answered Oct 31 '22 19:10

John Douthat


I'm not sure what version of Ruby this was added in (at least 1.8.7), but there seems to be an even simpler way of doing this:

str1 = "Hello"
str2 = "Goodbye"
def str1.to_spanish
  "Hola"
end
puts str1 # => Hello
puts str1.to_spanish # => Hola
puts str2 # => Goodbye
puts str2.to_spanish # => Throws a NoMethodError

Learnt about this whilst reading the Ruby Koans (about_class_methods.rb lesson). I'm still not entirely sure what the purpose of this is since it seems a bit dangerous to me.

like image 32
Patrick Avatar answered Oct 31 '22 21:10

Patrick


You can use the syntax class <<object to get an object's "singleton class" (that's a special parent class belonging only to that object) and define methods only for that instance. For example:

str1 = "Hello"
str2 = "Foo"

class <<str1
  def to_spanish
    'Hola'
  end
end

Now if you do str1.to_spanish, it will return "Hola", but str2.to_spanish will give you a NoMethodFound exception.

like image 17
Chuck Avatar answered Oct 31 '22 19:10

Chuck