Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Ruby class vs instance methods

Tags:

ruby

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?

like image 796
randombits Avatar asked Nov 24 '25 14:11

randombits


1 Answers

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.

like image 174
Wayne Conrad Avatar answered Nov 26 '25 11:11

Wayne Conrad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!