redefining a single ruby method on a single instance with a lambda
Solution 1
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
Solution 2
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.
Solution 3
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.
kmorris511
Updated on July 09, 2022Comments
-
kmorris511 almost 2 years
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.
-
John Douthat about 15 yearsif he has an externally defined proc in a simple variable, it's difficult to get it into the new scope created by class<<str1, without resorting to global or instance variables
-
Cyril Duchon-Doris about 9 yearsThank you for posting this (more) up-to-date answer !
-
Daniel A. R. Werner almost 8 yearsAssuming
str.to_spanish
was already defined and I wanted to “redefine” it, how would I call the “original”str.to_spanish
from within the newly defined one? -
BRPocock almost 8 yearsIf
str
is your instance object andString
is your class, you can call the class's version of the method byString.to_spanish
-
Benjineer over 5 yearsGod I love Ruby
-
Abdul Rahman K about 4 yearswondering why 'probably doesn't fit your needs' for the last solution?
-
Abdul Rahman K about 4 yearsBoth: ``` class Foo end obj = Foo.new class << obj def method1; end end def obj.method2; end
-
John Douthat about 4 years@AbdulRahmanK because he asked how to do it with a lambda, and that way doesn't use a lambda, but I wanted to include it anyway