Skip to content

Instantly share code, notes, and snippets.

@Integralist
Created December 18, 2014 09:12
Show Gist options
  • Save Integralist/bb8760d11a03c88da151 to your computer and use it in GitHub Desktop.
Save Integralist/bb8760d11a03c88da151 to your computer and use it in GitHub Desktop.
Ruby: private class level methods
class Foo
class << self
def bar
p "im public"
end
private
def baz
p "im private"
end
end
end
Foo.bar # => im public
Foo.baz # => NoMethodError: private method `baz' called for Foo:Class
class Foo
def self.bar
p "im public"
end
private
def self.baz
p "im private"
end
end
Foo.bar # => im public
Foo.baz # => im private
@Integralist
Copy link
Author

Information found here (it has useful diagrams too):
http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html


When creating singleton methods (i.e. def self.foo) Ruby will create an anonymous class to hold these methods. The anonymous class then assumes the role of the object's class and the original class is re-designated as the superclass of that anonymous class.

This means the standard "method lookup" pattern (this is how Ruby implements looking up methods on an object) is unaltered - both the singleton methods (in the anonymous class) and the instance methods (in the superclass) will be found along the method lookup path when the object receives a method call.

The anonymous class is known as an Eigenclass.

This is where the following syntax comes from (it effectively allows you to open up the eigenclass)...

class << self
  def foo; end
end

@Integralist
Copy link
Author

It has been suggested that private is actually a method (not a directive or special syntax) and so the private method only changes the visibility of instance methods. Class methods on the other hand are instance methods of the Eigenclass.

In the first example (class << self) the private method goes through the Eigenclass (so the class methods technically become instance methods on the Eigenclass and so the private directive is enforced) but in the second example the private method goes through the Foo class (and its class level methods aren't affected by the private method).

@Integralist
Copy link
Author

You can get the second example (def self.baz) to work by using private_class_method :baz...

class Foo
  def self.bar
    p "im public"
  end

  def self.baz
    p "im private"
  end
  private_class_method :baz
end

Foo.bar # => im public
Foo.baz # => NoMethodError: private method `baz' called for Foo:Class

@Nakilon
Copy link

Nakilon commented Mar 28, 2019

See also https://stackoverflow.com/a/12925407/322020 and other answers there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment