Calling Protected Class Method from Instance Method in Ruby

Calling protected class method from instance method in Ruby

EDIT: Answering the updated question

It is forbidden to call private methods with explicit receiver. You either have to use implicit receiver (private_bang, without self) or use send. Please see my another answer for more information.

By the way, the original question is about calling class instance methods from instance methods. Your clarification doesn't include that. But if that's still true, you have to use self.class.send or make the method public (so that you can use explicit receiver).

Is there a way to call a private Class method from an instance in Ruby?

Here is a code snippet to go along with the question. Using "private" in a class definition does not apply to class methods. You need to use "private_class_method" as in the following example.

class Foo
def self.private_bar
# Complex logic goes here
puts "hi"
end
private_class_method :private_bar
class <<self
private
def another_private_bar
puts "bar"
end
end
public
def instance_bar
self.class.private_bar
end
def instance_bar2
self.class.another_private_bar
end
end

f=Foo.new
f=instance_bar # NoMethodError: private method `private_bar' called for Foo:Class
f=instance_bar2 # NoMethodError: private method `another_private_bar' called for Foo:Class

I don't see a way to get around this. The documentation says that you cannot specify the receive of a private method. Also you can only access a private method from the same instance. The class Foo is a different object than a given instance of Foo.

Don't take my answer as final. I'm certainly not an expert, but I wanted to provide a code snippet so that others who attempt to answer will have properly private class methods.

Calling a private instance method from a class method in Ruby

Using private or protected really don't do that much in Ruby. You can call send on any object and use any method it has.

class Foo
def Foo.bar(my_instance, n)
my_instance.send(:plus, n)
end
end

Ruby: Calling class method from instance

Rather than referring to the literal name of the class, inside an instance method you can just call self.class.whatever.

class Foo
def self.some_class_method
puts self
end

def some_instance_method
self.class.some_class_method
end
end

print "Class method: "
Foo.some_class_method

print "Instance method: "
Foo.new.some_instance_method

Outputs:


Class method: Foo
Instance method: Foo

Calling an instance method from a class method

In order to call an instance method you need to create an instance of the object. In ruby calling 'new' creates an instance of a class.

You can change this line

puts "#{action}"

To this:

puts "#{new.action}"

.new inside of the class will make a new instance of the class you are in. Which will also run your initialize and decrease @@variable by one. The way the class is written right now we never past if @@variable <9 unless you are making instances of the class outside of the code you shared.

Overall this is a pretty odd class. It isn't common to use class variables like this. It is much more common to create an instance of a class, use instance variables/methods to house your logic.

Calling inherited class method from instance method in Ruby

It won't work, because the instance of C is not kind_of?(B.singleton_class).

In ruby, a protected method can be called within the context of an object which is kind_of? the class which defines the method, with an explicit receiver which is also kind_of? the class which defines the method.

You defined a protected method on the singleton class of B, so that method can only be called within the objects which are kind_of?(B.singleton_class). The class C inherits B, so C's singleton class inherits B's singleton class, so C is kind_of? B.singleton_class. Thus in your first case, it works. But obviously, C.new is not kind_of? B.singleton_class, so it won't work.

How does one access protected class methods from instance methods in Ruby?

Upon further discussions with rue: and drbrain: in ruby-lang, it turns out that my impulse to save memory by placing utility functions at the class level was misplaced.

In Ruby, the instance methods hang off the class anyway, and the answer is to go ahead and place the utility functions at the instance level as private.

In summary, a utility function that is accessed only by instance methods:

class Foo
def what
"it is '#{zoop}'"
end
private
def zoop
"zoop"
end
end

p Foo.new.what # => "it is 'zoop'"

For a utility function that needs to be called from instance and class methods, a nested module seemed to be a popular approach:

class Foo
module Util
def self.zoop
"zoop"
end
end
def what
"it is '#{Util.zoop}'"
end
class << self
def class_what
"for all time it is '#{Util.zoop}'"
end
end
end

p Foo.new.what # => "it is 'zoop'"
p Foo.class_what # => "for all time it is 'zoop'"
p Foo::Util.zoop # visible, alas

Use or misuse of private class methods in Ruby

There is no such thing as a "class method" in Ruby. There are only instance methods. "Class methods" are actually singleton methods (on an object which just so happens to be an instance of Class), and "singleton methods" are just instance methods of the singleton class.

private methods can only be called with an implicit receiver (which is self), i.e. they can only be called by other methods on the same object (which in turn means they must be methods of the same class or one of its ancestors, i.e. superclasses, prepended modules or included modules).

This means that private "class methods" can only be called by other "class methods", i.e. methods defined in Example's singleton class, Class, Module, Object, Kernel, or BasicObject. You cannot call them from methods defined in Example.

Think about it: what's the purpose of private? Its purpose is encapsulation, we want to encapsulate the internal implementation and representation details from the external protocol. There are two kinds of encapsulation in wide use currently: Abstract Data Type-Oriented Encapsulation (where instances of different types are encapsulated from each other, but instances of the same type can access each other's internals, e.g. classes in Java) and Object-Oriented Encapsulation (where different objects are encapsulated from each other, even if they are instances of the same type, e.g. Ruby and interfaces in Java). Ruby is an object-oriented language, therefore it uses object-oriented encapsulation. (Java OTOH uses ADT-oriented encapsulation for classes, which is counter-intuitive, since it is usually claimed to be an object-oriented language).

In your case, we have two objects, Example and an instance of Example. They are two different objects, so object-oriented encapsulation simply forbids you from accessing one object's private parts from the other object. Even if Ruby did use ADT-oriented encapsulation, it still wouldn't work: ADT-oriented encapsulation allows two instances of the same type to access each other's privates, but the two objects aren't of the same type, one is an instance of Class and the other is an instance of Example.

Basically, you want to manipulate two object's internals at the same time and that is just not possible in OOP. It's a fundamental design principle of OOP that each object (and each object alone) is responsible for its private parts, and you can only interact with that object by sending it messages through its public protocol.

tl;dr: what you want goes directly against the basic encapsulation principles in OO. Either Example::g must be public or you need to change your design. (Resorting to reflective hacks to circumvent access protection in code you have no control over is a code smell at best. Resorting to reflective hacks to circumvent access protection in code you own is just plain wrong, because you control the access protection, you could just change it.)


One possible solution is to leave OOP behind altogether, and look to functional programming for help. We could try and use closures for encapsulation:

We start out with your original example:

class Example
private_class_method def self.g
puts 4711
end

def f
self.class.send(:g)
end
end

Example.new.f
# 4711

Now, we turn g into a local variable and assign a lambda to it, and in turn use that lambda to define f:

class Example
g = -> {
puts 4711
}

define_method(:f, &g)
end

Example.new.f
# 4711

Now, g is (in some sense) even more "private" than before, because it only exists within the lexical scope of the class body, not even class methods defined in a different class body can access it. However, the lambda being referenced by g is a proper object and can be passed around even into different scopes.

But, presumably you don't want f and g to be just identical (otherwise you could just have used module_function, after all), instead you want f to do something other than just delegate to g. That is also possible:

class Example
g = -> {
puts 4711
}

define_method(:f) do
puts 42
g.()
end
end

Example.new.f
# 42
# 4711

This works, because in some other sense g is less "private" than before: lexical scopes can nest, in particular the lexical scopes of blocks (and only blocks) nest, so that the nested block (the block passed to define_method in this case) can access the lexical environment of the outer lexical scope (the class body in this case) even after that lexical scope no longer exists (the class body has finished evaluating).



Related Topics



Leave a reply



Submit