How can I redefine Fixnum's + (plus) method in Ruby and keep original + functionality?
Asked Answered
T

2

9

This throws me a SystemStackError in 1.9.2 Ruby (but works in Rubinius):

class Fixnum
  def +(other)
   self + other * 2
  end
end

but there is no super for + (based on other errors).

How can I access the original + functionality?

Transponder answered 16/3, 2012 at 22:7 Comment(9)
Wait, you're saying this works as you expect in Rubinius?Anuria
I just tested it, doesn't work in Rubinius. The overridden method is just ignored.Jacktar
Are you sure you want to do this? That's a loaded fully automatic foot gun right there.Deluge
It's not immediately obvious from the question, but this is a duplicate (or rather a special case) of When monkey patching a method, can you call the overridden method from the new implementation.Kohn
possible duplicate of When monkey patching a method, can you call the overridden method from the new implementationKohn
Don't do this! But do read @JörgWMittag 's answer at the linked question!Glutathione
I just wanted to use this as a testing ground, but as I see it was not a good idea to modify a method almost everything depends on...Transponder
There. Are. Four. Lights! +1 (or is that +3?)Glossematics
@muistooshort: it's an exercise from a book :)Aridatha
R
16

Use alias_method. Alias Fixnum's + to something else, then refer to it in the new +:

class Fixnum
  alias_method :old_add, :+
  def +(other)
    self.old_add(other) * 2
  end
end
Revolt answered 16/3, 2012 at 22:34 Comment(5)
Also, doing this seems to really confuse my IRb somehow, but does in fact work in plain Ruby.Anuria
@NiklasB. I usually try and refrain from editing answers within the first few minutes. And people seem to mix up the syntax for alias vs. alias_method a lot.Anuria
@Andrew: I am not suprised to hear that overriding freakin' integer addition doesn't go down too well for the IRb... This is so bad a hack that I can barely describe it through words.Jacktar
@NiklasB. Yea, when I do end for the class it returns nothing—not nil nothing, as in blank. Trying to look at _ yields the same: nothing. Agreed that this is a horribly bad idea, but interesting solution.Anuria
Is this a good practice? I really need to do something like this, but all common sense tells me this is a bad idea.Unicameral
E
1

Another interesting approach would be to pass a block to Fixnum's module_eval method. So, for instance:

module FixnumExtend
  puts '..loading FixnumExtend module'

  Fixnum.module_eval do |m|
    alias_method :plus,     :+
    alias_method :min,      :-
    alias_method :div,      :/
    alias_method :mult,     :*
    alias_method :modu,     :%
    alias_method :pow,      :**

    def sqrt
     Math.sqrt(self)
    end

  end

end

Now, after including FixnumExtend throughout my app I can do:

2.plus 2   
=> 4

81.sqrt
=> 9

I am using this approach to help my OCR engine recognize handwritten code. It has an easier time with 2.div 2 than 2/2.

Escolar answered 30/4, 2012 at 18:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.