I was trying to create a class that has a private class method. I want this private class method available to be used inside an instance method.
The following was my first attempt:
class Animal
class << self
def public_class_greeter(name)
private_class_greeter(name)
end
private
def private_class_greeter(name)
puts "#{name} greets private class method"
end
end
def public_instance_greeter(name)
self.class.private_class_greeter(name)
end
end
Animal.public_class_greeter('John')
works fine, printing John greets private class method
.
However, Animal.new.public_instance_greeter("John")
throws an error: NoMethodError: private method 'private_class_greeter' called for Animal:Class
.
That is expected, as the invocation self.class.private_class_greeter
is same as Animal.private_class_greeter
, which obviously throws an error.
After searching on how this can be fixed, I came up with the following code, that does the job:
class Animal
class << self
def public_class_greeter(name)
private_class_greeter(name)
end
private
def private_class_greeter(name)
puts "#{name} greets private class method"
end
end
define_method :public_instance_greeter, &method(:private_class_greeter)
end
I don't exactly understand what is happening here: &method(:private_class_greeter)
.
Could you please explain what does this mean?
If I were to replace:
define_method :public_instance_greeter, &method(:private_class_greeter)
with:
def public_instance_greeter
XYZ
end
then, what should be the content in place of XYZ
?
How does Ruby parse
&method(:private_class_greeter)
?The expression
&method(:private_class_greeter)
ismethod(:private_class_greeter)
&
operator.What does the
method
method do?The
method
method looks up the specified method name in the current context and returns aMethod
object that represents it. Example inirb
:Once you have this method, you can do various things with it:
What is the
&
operator for?The
&
operator is used to pass aProc
as a block to a method that expects a block to be passed to it. It also implicitly calls theto_proc
method on the value you pass in, in order to convert values that are notProc
into aProc
.The
Method
class implementsto_proc
— it returns the contents of the method as aProc
. Therefore, you can prefix aMethod
instance with&
and pass it as a block to another method:The
define_method
method just happens to take a block with the contents of the new method that is being defined. In your example,&method(:private_class_greeter)
passes in the existingprivate_class_greeter
method as a block.Is this how
&:symbol
works?Yes.
Symbol
implementsto_proc
so that you can simplify your code like this:How can I replicate
&method(:private_class_greeter)
?You can pass in a block that calls the target method:
Of course, then you don't need to use
define_method
anymore, which results in the same solution Eric mentioned in his answer:First, take good care with your indentation.
private
should be 2 spaces to the right: it gives the impression thatpublic_instance_greeter
is private otherwise.If you don't care about encapsulation, you could simply use
Kernel#send
: