obj = SomeObject.new
def obj.new_method
"do some things"
end
puts obj.new_method
> "do some things"
This works ok. However, I need to do same thing inside an existing method:
def some_random_method
def obj.new_method
"do some things"
end
end
Works ok as well, but having a method inside开发者_如何转开发 a method looks pretty horrible. The question is, is there any alternate way of adding such a method?
In ruby 1.9+, there's a better way of doing this using define_singleton_method
, as follows:
obj = SomeObject.new
obj.define_singleton_method(:new_method) do
"do some things"
end
Use a Mixin.
module AdditionalMethods
def new_method
"do some things"
end
end
obj = SomeObject.new
obj.extend(AdditionalMethods)
puts obj.new_method
> "do some things"
There are several ways to achieve this, and they are all related to the singleton class:
You can use
class <<
idiom to open the singleton class definition:obj = Object.new class << obj def my_new_method ... end end
Or you can use
define_singleton_method
on the obj:obj = Object.new obj.define_singleton_method(:my_new_method) do ... end
You can also use
define_method
from the singleton class:obj = Object.new obj.singleton_class.define_method(:my_new_method) do ... end
Or you can use
def
directly:obj = Object.new def obj.my_new_method ... end
Pay attention to example 3, I think the concept of a singleton class becomes clearer on that one. There is a difference between these two examples:
a = Object.new
b = Object.new
# -- defining a new method in the object's "class" --
a.class.define_method(:abc) do
puts "hello abc"
end
a.abc # prints "hello abc"
b.abc # also prints "hello abc"
# -- defining a new method in the object's "singleton class" --
a.singleton_class.define_method(:bcd) do
puts "hello bcd"
end
a.bcd # prints "hello bcd"
b.bcd # error undefined method
This is because every object has its own singleton class:
a = Object.new
b = Object.new
p a.class # prints "Object"
p a.singleton_class # prints "#<Class:#<Object:0x000055ebc0b84438>>"
p b.class # also prints "Object"
p b.singleton_class # prints "#<Class:#<Object:0x000055ebc0b84410>>" (a different reference address)
Just an interesting point to note:
if you had instead gone:
def my_method
def my_other_method; end
end
Then my_other_method
would actually be defined on the CLASS of the object not withstanding that the receiver ofmy_method
is an instance.
However if you go (as you did):
def my_method
def self.my_other_method; end
end
Then my_other_method
is defined on the eigenclass of the instance.
Not directly relevant to your question but kind of interesting nonetheless ;)
You can use modules.
module ObjSingletonMethods
def new_method
"do some things"
end
end
obj.extend ObjSingletonMethods
puts obj.new_method # => do some things
Now if you need to add more methods to that object, you just need to implement the methods in the module and you are done.
Use instance_eval
:
obj = SomeObject.new
obj.instance_eval do
def new_method
puts 'do something new'
end
end
obj.new_method
> "do something new"
class Some
end
obj = Some.new
class << obj
def hello
puts 'hello'
end
end
obj.hello
obj2 = Some.new
obj2.hello # error
Syntax class << obj
means that we are opening definition of the class for an object. As you probably know we can define Ruby class methods using syntax like this:
class Math
class << self
def cos(x)
...
end
def sin(x)
...
end
end
end
Then we can use those methods like this:
Math.cos(1)
In Ruby, everything is an object - even classes. self
here is an object of Math class
itself (you can access that object with Math.class
). So syntax class << self
means we are opening class for Math class object
. Yes, it means that Math class
has class too (Math.class.class).
Another way to use a Mixin
obj = SomeObject.new
class << obj
include AnotherModule
end
This includes all of the methods from AnotherModule
into the current object.
精彩评论