tags:

views:

69

answers:

2

I have the following code:

#!/usr/bin/ruby

class Person
  def self.speak
    p = self.new
    puts "Hello"
    p.chatter
  end

private

  def chatter
    puts "Chattering"
  end
end

p = Person.new
Person.speak

I'd like to make chatter private, accessible only within p.. but I want p to be able to access it within the class method. Is there a better way to design this so chatter isn't available to the public, but a "factory" method like self.speak can call chatter?

A: 

There's a number of ways to do this. One approach would be a class method which instantiates a new instance and calls the #speak method on the instance.

class Person
  def self.speak
    new.speak
  end

  def speak
    puts "Hello"
    chatter
  end

  private

  def chatter
    puts "Chattering"
  end
end

Then you could call it in either the class or instance context:

p = Person.new
p.speak
# ...or...
Person.speak
Oshuma
+3  A: 

"send" bypasses the usual protections against calling private methods:

#!/usr/bin/ruby1.8

class Person

  def self.speak
    puts "Hello"
    new.send(:chatter)
  end

  def speak
    puts "Hello"
    puts chatter
  end

  private

  def chatter
    puts "Chattering"
  end

end

Person.speak        # => Hello
                    # => Chattering
Person.new.speak    # => Hello
                    # => Chattering

However, what you want can be achieved without any voodoo, by simply having the class method do all the work, and the instance method defer to the class method:

class Person

  def self.speak
    puts "Hello"
    puts "Chatter"
  end

  def speak
    self.class.speak
  end

end

If you had more than a few of these forwarding methods, it might be convenient to make a helper method that makes them for you:

module DelegateToClass

  def delegate_to_class(name)
    define_method(name) do |*args|
      self.class.send(name, *args)
    end
  end

end

class Person

  extend DelegateToClass

  def self.speak
    puts "Hello"
    puts "Chatter"
  end
  delegate_to_class :speak

end
Wayne Conrad
Nice solution, although I have the feeling that if the OP has to resort to such tricks, there is something much more fundamentally wrong with the design.
Jörg W Mittag
@Jörg W Mittag, I agree. It may be a sign that the method really out to move out, get a job, and settle down in its own module or class.
Wayne Conrad