Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding String functionality to class

Consider this class

class Duck
  attr_accessor :name

  def initialize(name)
    @name = name || 'Donald'
  end

  # Some quacking methods..

  def to_s
    "#{@name} (Duck)"
  end

end

I would like my duck to respond to methods like upcase, sub, gsub, etc.., so I can do

my_duck = Duck.new("Scrooge")
my_duck.upcase  
   --> "SCROOGE (DUCK)"

Besides manually implementing these methods, is there a nifty way I can pick out String methods that are not self-mutating and automatically have my class respond to those, then call to_s and then call the method on the resulting string?

like image 794
Niels B. Avatar asked Feb 13 '26 06:02

Niels B.


1 Answers

You could use the Forwardable module:

require 'forwardable'

class Duck      
  extend Forwardable

  # This defines Duck#upcase and Duck#sub, you can
  # add as many methods as you like.
  def_delegators(:to_s, :upcase, :sub) 

  # All the other code here... 
end

Duck.new('duffy').upcase
# => DUFFY (DUCK)

Duck.new('rubber').respond_to?(:upcase)
# => true

In general calling def_delegators(:foo, :bar) is equivalent to define the bar method by hand like this:

def bar(*args, &block)
  foo.bar(*args, &block)
end

The first argument to def_delegators can be the name of an instance variable, i.e. def_delegators(:@foo, :bar, :baz).

like image 67
toro2k Avatar answered Feb 15 '26 19:02

toro2k



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!