Basic ENCAPSULATION help

This example demonstrates the use of ‘private’

class Person
def initialize(name)
set_name(name)
end
def name
@first_name + ’ ’ + @last_name
end
private
def set_name(name)
first_name, last_name = name.split(/\s+/)
set_first_name(first_name)
set_last_name(last_name)
end
def set_first_name(name)
@first_name = name
end
def set_last_name(name)
@last_name = name
end
end

From the book:
" private tells Ruby that any methods declared in this class from
there on should be kept private. This means that only code within the
object’s methods can
access those private methods, whereas code outside of the class cannot.
For example, this code no longer works "

p = Person.new(“Fred Bloggs”)
p.set_last_name(“Smith”)


NoMethodError: private method ‘set_last_name’ called for
#<Person:0x337b68
@last_name=“Bloggs”, @first_name=“Fred”>


When the author says, “only code within the object’s methods can
access those private methods, whereas code outside of the class
cannot.”, what is the code in the example that can “access those private
methods”, and what is the “code outside of the class that cannot” ?

That’s it for now, more questions later. Apologies to the author of
this book, it’s not you, it’s me. I’m a really slow learner.

Thanks guys!

In your example: in the initialize method you call the private method
set_name (with no error). That is calling the code from inside the
class.
p = Person.new
p.set_name(‘foo’)
raises an error. That is calling the code from outside the class.

Hope that helps.


gd

2011/3/30 Kaye Ng [email protected]

On Wed, Mar 30, 2011 at 06:33:00PM +0900, Kaye Ng wrote:

When the author says, “only code within the object’s methods can
access those private methods, whereas code outside of the class
cannot.”, what is the code in the example that can “access those private
methods”, and what is the “code outside of the class that cannot” ?

To expand upon what Gunther D. said:

The initialize method calls the set_name method. Both of these are
within the Person class, so when initialize calls set_name, the private
method set_name is being called by another method within the class. The
set_name method then calls the set_first_name and set_last_name methods.
These are two more cases of private methods (set_first_name and
set_last_name) being called by other code (set_name) inside the Person
class.

Code outside the method that would not be able to call the private
methods might include something like this:

monickers = ['Alan','Bob','Charlie']
johnson = Person.new('Dave J.son')

monickers.each do |fname|
  johnson.set_first_name fname
  puts johnson.name
end

The expected output, if the set_first_name method was not private, would
be something like this:

Alan Johnson
Bob Johnson
Charlie Johnson

Because set_first_name is a private method, however, the monickers.each
block fails to access it, resulting in output that looks more like this:

NoMethodError: private method `set_first_name' called for
#<Person:0x7f4f1457c5c8 @last_name="Johnson", @first_name="Dave">

As you can see, setting those methods to “private” results in an error,
because they are then protected from access by messages sent to the
object from outside of the object.

7stud – wrote in post #990108:

because RULE #1 says you cannot use an explicit receiver to call a
private method.

Whoops. That’s not RULE #1.

One of the key aspects of a private method in ruby is: a private method
cannot be called with an explicit “receiver”. What does that mean? The
receiver is the object calling the method. In the following example:

class Dog
def bark
puts “woof”
end
end

spot = Dog.new
spot.bark

–output:–
woof

…spot is the “receiver” and spot calls the method bark(). However,
according to the rules of ruby, you cannot specify a receiver when you
call a private method.

Well, than how does ruby know which object is calling the method? Now
you enter the tricky realm of what’s known as ‘self’. When a method is
not called with a receiver, ruby implicitly uses whatever object is self
at the instant the method is called.

RULE #1: When ruby executes code inside a method, then inside the method
self is equal to the object that called the method. So, for instance,
in the example above, when spot calls bark(), inside bark(), self is
equal to spot.

class Dog
def bark
make_sound #=> self.make_sound = spot.make_sound
end

private
def make_sound
puts “woof”
end

end

spot = Dog.new
spot.bark

You cannot write:

spot = Dog.new
spot.make_sound

because RULE #1 says you cannot use an explicit receiver to call a
private method.

Practically what that means is that you will usually call private
methods from inside public methods. Private methods are essentially
helper methods that the public methods in a class use to perform some
task.