Reputation: 8588
Given a Class in Ruby:
class MyClass
def self.my_class_method
puts "class method"
end
private
def my_method
puts "regular method"
end
private_class_method :my_class_method
end
To access private methods I can call .send(:my_method)
on the Class Object, but how does that work for class methods?
Upvotes: 13
Views: 19798
Reputation: 369458
There are no such things as class methods. Class methods are just singleton methods of the class. But there are no such things as singleton methods either. Singleton methods are just instance methods of the singleton class. So, class methods are just instance methods of the class's singleton class.
Since there is no such thing as a class method, only instance methods, you already know what to do:
To access private methods I can call
.send(:my_method)
on the Class Object, but how does that work for class methods?
Upvotes: -1
Reputation: 12412
First off, MyClass.send(:my_method)
would not work. You have to send it to an instance: MyClass.new.send(:my_method)
.
Then, your my_class_method
is not really private.
Ruby's semantic of private
are somewhat different from what you might be used to in other languages. Since Ruby allows you to bypass encapsulation if you choose to, private
just means that a method can only be called implicitly, without sending a message to an actual object.
For example:
class Example
def test
'foobar'
end
def hello
puts test # implicit receiver
puts self.test # explicit receiver
end
end
This is all good, but why is this important for your question?
Because you're declaring my_class_method
explicitly on self
. Doing so bypasses the private
modifier, and the method is public. This means that you can just call it with:
MyClass.my_class_method
If you really need private
class methods, then you can define them on the metaclass:
class MyClass
class << self
private
def my_class_method
puts "class method"
end
end
private
def my_method
puts "regular method"
end
end
This will make my_class_method
actually private, and force you to invoke it with any of these:
MyClass.send :my_class_method
MyClass.class_exec { my_class_method }
MyClass.class_eval { my_class_method }
MyClass.class_eval "my_class_method"
Upvotes: 7
Reputation: 118271
You should do:
class MyClass
def self.my_class_method
puts "class method"
end
private
def my_method
puts "regular method"
end
private_class_method :my_class_method
end
# to call class method
MyClass.send :my_class_method # => class method
# to call instance method
MyClass.new.send :my_method # => regular method
In Ruby, class(s) are also objects, so you can call the #send
method on the class also.
In Ruby, you can define private class methods as
class MyClass
class << self
private
def my_class_method
puts "class method"
end
end
end
Or using thhis macro like method: private_class_method
Upvotes: 22
Reputation: 14402
Just for reference, that's not how you create a private class method.
class A
private
def self.foo
"foo"
end
end
A.foo # => "foo"
To create a private class method, you need to use private_class_method.
class A
def self.foo
"foo"
end
private_class_method :foo
end
A.foo # => private method `foo' called for A:Class
Upvotes: 1