Why won't Ruby allow me to specify self as a receiver inside a private method?
The Problem
In Ruby, private methods can't be called directly with an explicit receiver; self doesn't get any special treatment here. By definition, when you call self.some_method
you are specifying self as the explicit receiver, so Ruby says "No!"
The Solution
Ruby has rules for its method lookups. There may be a more canonical source for the rules (other than going to the Ruby source), but this blog post lays out the rules right at the top:
1) Methods defined in the object’s singleton class (i.e. the object itself)
2) Modules mixed into the singleton class in reverse order of inclusion
3) Methods defined by the object’s class
4) Modules included into the object’s class in reverse order of inclusion
5) Methods defined by the object’s superclass, i.e. inherited methods
In other words, private methods are first looked up in self without requiring (or allowing) an explicit receiver.
When using a private attr_accessor, why does self.attribute= work, but self.attribute doesn't?
According to a comment by @Jörg W Mittag to Alan Skorkin's blog entry Ruby Access Control – Are Private And Protected Methods Only A Guideline?:
Quick note: there is a special case where calling private methods with an explicit receiver is allowed:
If the method name ends with '=' (i.e. it is an attribute writer) and the explicit receiver is 'self', then this works. This is necessary, because setters can only be called with an explicit receiver because of the method/variable ambiguity. Otherwise it wouldn't be possible to call private setters.
Jörg cites no sources, but he's pretty reliable.
Understanding private methods in Ruby
Here's the short and the long of it. What private means in Ruby is a method cannot be called with an explicit receivers, e.g. some_instance.private_method(value). So even though the implicit receiver is self, in your example you explicitly use self so the private methods are not accessible.
Think of it this way, would you expect to be able to call a private method using a variable that you have assigned to an instance of a class? No. Self is a variable so it has to follow the same rules. However when you just call the method inside the instance then it works as expected because you aren't explicitly declaring the receiver.
Ruby being what it is you actually can call private methods using instance_eval:
class Foo
private
def bar(value)
puts "value = #{value}"
end
end
f = Foo.new
begin
f.bar("This won't work")
rescue Exception=>e
puts "That didn't work: #{e}"
end
f.instance_eval{ bar("But this does") }
Hope that's a little more clear.
-- edit --
I'm assuming you knew this will work:
class Foo
def public_m
private_m # Removed self.
end
private
def private_m
puts 'Hello'
end
end
Foo.new.public_m
How to create a private class method?
private
doesn't seem to work if you are defining a method on an explicit object (in your case self
). You can use private_class_method
to define class methods as private (or like you described).
class Person
def self.get_name
persons_name
end
def self.persons_name
"Sam"
end
private_class_method :persons_name
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
Alternatively (in ruby 2.1+), since a method definition returns a symbol of the method name, you can also use this as follows:
class Person
def self.get_name
persons_name
end
private_class_method def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
Is Ruby private method accessible in sub class?
Here's a brief explanation from this source:
- Public methods can be called by anyone---there is no access control. Methods are public by default (except for initialize, which is always private).
- Protected methods can be invoked only by objects of the defining class and its subclasses. Access is kept within the family.
- Private methods cannot be called with an explicit receiver. Because you cannot specify an object when using them, private methods can be called only in the defining class and by direct descendants within that same object.
This answer from a similar question expands on the topic in more detail: https://stackoverflow.com/a/1565640/814591
How and why should I avoid using self in a Ruby method declaration
There's nothing wrong with using self, but it bypasses the requirement to create a variable instance of your object, so some die-hard OO programmers would suggest avoiding self for that reason. If you avoid "self" then you are forced to initialize your class and assign it to a variable name which forces you think of it as a true object, and not just a collection of functions.
Here's an example class to demonstrate how you would call methods with and without "self"
class StaticVersusObjectMethod
def self.class_method
puts 'Hello, static class method world!'
end
def object_method
puts 'Hello, object-oriented world!'
end
end
# No need to create an object instance variable if the method was defined with 'self'
StaticVersusObjectMethod.class_method
# You must create an object instance variable to call methods without 'self'
object = StaticVersusObjectMethod.new
object.object_method
output:
Hello, static class method world!
Hello, object-oriented world!
Whether you use self in the declaration should depend on the data you want your method to use. If the methods will only operate on the variables you pass in as parameters, then use 'self'. On the other hand, don't use 'self' if you want them to act as true object methods. "True" object methods can operate on the state of the class variables (fields) in the objects which you create and assign to a one or more variable names.
Related Topics
Undefined Method 'Require_Relative' for Main:Object (Nomethoderror)
Argumenterror: Unknown Key: :Conditions. Valid Keys Are: :Class_Name, :Class, :Foreign_Key
Losing an Attribute When Saving Through an Association W/ Scope (Rails 4.0.0)
Ruby + Tk Command Binding - Scope Issue
Bundle Install' Fails (Because of Git Protocol)
Prepared Statements Already Exists
When to Use Association Extensions VS Named Scopes
Problem Installing Ruby 1.9.2 on MAC Os Lion
Find Both Pattern and Position of Multiple Regex Matches in Ruby
Can't All or Most Cases of 'Each' Be Replaced with 'Map'
How to Start Ruby 1.9 Without Rubygems
Mongodb Group Using Ruby Driver