Why can a private class method be explicitly invoked in Ruby?

260 views Asked by At

As we know, the private methods cannot be called with an explicit receiver in ruby. But when I define a class, I can invoke a private class method by the class itself.

For example:

class A
   private
     def self.test
        puts "hello,world!"
     end
end

A.test => hello,world!
A.new.test NoMethodError: private method `test' called for #<A:0x007f80b91a10f8>

it is contradictory with the definition of private. Anyone can tell me the reason. Thanks in advance!

2

There are 2 answers

4
Amadan On BEST ANSWER

private only affects instance methods. To make a private class method, use private_class_method:

class A
   private_class_method def self.test
      puts "hello,world!"
   end
end

or

class A
   def self.test
      puts "hello,world!"
   end
   private_class_method :test
end

EDIT: Yet another way to do it is to define methods on the metaclass - they will behave as class methods.

class A
  class << self
    private
    def test
      puts "hello,world!"
    end
  end
end

Unfortunately, there is no such thing as protected_class_method - but this last option gives us a hint on how to do it:

class A
  class << self
    protected
    def test
      puts "hello,world!"
    end
  end
end

but note that it can be only called from class methods of the descendant classes:

class B < A
  def self.test_class
    A.test
  end
  def test_instance
    A.test
  end
end

B.test_class
# => hello,world!
B.new.test_instance
# => `test_instance': protected method `test' called for A:Class (NoMethodError)
0
deceze On

def self.test declares a class method, not an instance method. To make class methods private you need to use private_class_method, not private.