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?
In Ruby 1.8.7, "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
The built-in module Forwardable can do this just as well:
require 'forwardable'
class Person
extend Forwardable
def self.speak
puts "Hello"
puts "Chatter"
end
def_delegator self, :speak
end
def_delegator also bypasses protections against private methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With