Reputation: 242
I am aware of just one way to create instance specific methods in ruby i.e.
class Test;end
obj1 = Test.new
class << obj1
def greet
p 'Welcome'
end
end
obj1.greet # "Welcome"
obj2 = Test.new
obj2.greet # through error as,
Traceback (most recent call last):
NoMethodError (undefined method `greet' for #Test:0x0000564fb35acef0>)
or
class Test;end
class << (obj1 = Test.new)
def greet
p 'Welcome'
end
end
obj1.greet # "Welcome"
obj2 = Test.new
obj2.greet # through error as,
Traceback (most recent call last):
NoMethodError (undefined method `greet' for #Test:0x0000564fb35acef0>)
Here I have two questions:
Upvotes: 1
Views: 174
Reputation: 110755
class Test
end
obj = Test.new
Here are some ways to create the hash, other than
class << obj
def greet
...
end
end
and (as mentioned in another answer)
def obj.greet
...
end
#1
obj.singleton_class.class_eval do
def greet1
'Welcome'
end
end
obj.greet1 #=> "Welcome"
#2
obj.singleton_class.class_eval "def greet2
'Get lost'
end"
obj.greet2 #=> "Get lost"
This form can be useful when creating singleton methods dynamically.
#3
obj.singleton_class.instance_eval do
define_method(:greet3) { 'yo' }
end
obj.greet3 #=> "yo"
#4
obj.singleton_class.
public_send(:define_method, :greet4) { 'yo-yo' }
obj.greet4 #=> "yo-yo"
#5
obj.define_singleton_method(:greet5) { 'yo who?' }
obj.greet5 #=> "ho who?"
#6
module M
def greet6
'hi ya'
end
end
obj.extend M
obj.greet6 #=> "hi ya"
#7
module M
def greet7
'hi you'
end
end
obj.singleton_class.include M
obj.greet7 #=> "hi you"
obj.methods(false)
#=> [:greet3, :greet4, :greet1, :greet2, :greet5]
obj.methods.grep /greet/
#=> [:greet3, :greet4, :greet1, :greet2, :greet5,
# :greet6, :greet7]
The practical use of creating singleton methods is obvious for modules (including classes), but calls for an opinion as it concerns other objects.
Upvotes: 2
Reputation: 80105
An example of a use case: suppose you have production code which uses a hash as data structure. As time progresses, it appears that a class would have been a better choice, because smarter behaviour than just holding data is required - for instance data should be validated. This validation code is only meaningful in the context of this specific hash. You could define a method validate_username
in the public namespace or some module, but def the_hash.validate_username;#code;end
would arguably be a better solution.
Upvotes: 1
Reputation: 242
As per @mu_is_too_short comment, another way is,
class Test; end
obj1 = Test.new
def obj1.pancakes
p 'Where is pancakes house?'
end
obj1.pancakes # "Where is pancakes house?"
obj2 = Test.new
obj2.pancakes
Traceback (most recent call last) :
NoMethodError
(undefined method `pancakes' for #<Test:0x0000564fb35ca310>)
Upvotes: 0
Reputation: 5552
You have defined class block as class << obj1
for only obj1
object which is object specific.
So greet
method is only defined for obj1
object and not for other objects of same class.
Better you inspect in following pattern
class Test
attr_accessor :name
def initialize(name)
self.name = name
end
end
obj1 = Test.new('test1')
class << obj1
def greet
puts self.inspect, self.object_id, self.name
puts 'Welcome'
end
end
obj1.greet
obj2 = Test.new
obj2.greet
In above, obj1
& obj2
both have different object ids.
1. What is the real world use of such kind of object specific methods?
It is good practice to know various pattern to define methods. This is useful when you want to define methods dynamically or when you load classes but want to define methods based on columns of model table present in database. Module#define_method is one of the best for such uses, cancancan is one of the gem who define helper methods dynamically in initializer.
2. What are other different ways to create object specific methods in Ruby?
Upvotes: 1