Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add the same method to multiple classes

Tags:

ruby

I have some code that calculates the nth root of a number. Right now, that method only works on Fixnum, because I defined it inside the Fixnum class. It would be very easy to just do

class Float
    #same code as was in Fixnum
end

but that seems unneccessary. I have no idea how to dynamically call classes. I tried:

classes = [Fixnum, Float]
classes.each do |x|
    x.instance_eval do
        def root(pow)
            return self ** (1/pow.to_f)
        end
    end
end

but that did not work. How do I do this? Note: After posting, I realized this might be a better fit for Programmers.SE, as it is theoretical, as well as single-problem based. Feel free to migrate accordingly...

like image 330
Bobby Tables Avatar asked May 03 '12 20:05

Bobby Tables


2 Answers

The relevant part of the class hierarchy looks like this:

  • Numeric
    • Integer
      • Older versions had Fixnum and Bignum as subclasses of Integer.
    • Float
    • Rational

So patch your change into Numeric to cover them all at once:

class Numeric
  def root(pow)
    return self ** (1/pow.to_f)
  end
end

Then you can do these things:

>> 11.root(2) # Integer
=> 3.3166247903554
>> 2.18.root(3) # Float
=> 1.296638256974172
>> Rational(23, 42).root(6) # Rational
=> 0.9045094132598528
>> 2**1000.root(42) # Integer
=> 2.2638347236157763
like image 146
mu is too short Avatar answered Nov 13 '22 22:11

mu is too short


You'll want to use #class_eval:

classes = [Fixnum, Float]
classes.each do |x|
    x.class_eval do
        def root(pow)
            return self ** (1/pow.to_f)
        end
    end
end

See this blog post as a reference.

Alternatively, you could create a module and include it into each class:

module MyRoot
  def root(pow)
    return self ** (1/pow.to_f)
  end
end

class Fixnum
  include MyRoot
end

class Float
  include MyRoot
end

I lean towards the latter. It's clearer what you're doing and allows one-off additions as well.

like image 42
tihm Avatar answered Nov 13 '22 22:11

tihm