1

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!

Craig S. Anderson
  • 6,966
  • 4
  • 33
  • 46
pangpang
  • 8,581
  • 11
  • 60
  • 96

2 Answers2

8

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)
Amadan
  • 191,408
  • 23
  • 240
  • 301
  • 2
    @test: First option only works in newer Rubies, where `def` returns a symbol. – Amadan Jun 09 '15 at 07:37
  • @Amadan Thanks for your help, and protected also only affects instance methods? – pangpang Jun 09 '15 at 07:52
  • @pangpang: Yes, `protected` also only affects instance methods. Added further examples on how to make protected class methods, if you really need them. – Amadan Jun 10 '15 at 01:16
  • I just want to 100% confirm if I got what you were saying. You cannot define private class methods explicitly using private followed by the class method (i.e.: `private;def self.method;"x";end`)? – the12 Jan 11 '17 at 21:53
3

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.

deceze
  • 510,633
  • 85
  • 743
  • 889