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?

karatedog
  • 2,508
  • 19
  • 29
  • Wait, you're saying this works as you expect in Rubinius? – Andrew Marshall Mar 16 '12 at 22:24
  • I just tested it, doesn't work in Rubinius. The overridden method is just ignored. – Niklas B. Mar 16 '12 at 23:03
  • 2
    Are you sure you want to do this? That's a loaded fully automatic foot gun right there. – mu is too short Mar 16 '12 at 23:09
  • 2
    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](http://StackOverflow.Com/a/4471202/2988/). – Jörg W Mittag Mar 16 '12 at 23:35
  • possible duplicate of [When monkey patching a method, can you call the overridden method from the new implementation](http://stackoverflow.com/questions/4470108/when-monkey-patching-a-method-can-you-call-the-overridden-method-from-the-new-i) – Jörg W Mittag Mar 16 '12 at 23:39
  • Don't do this! But do read @JörgWMittag 's answer at the linked question! – dbenhur Mar 17 '12 at 02:41
  • 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... – karatedog Mar 17 '12 at 07:56
  • There. Are. Four. Lights! +1 (or is that +3?) – Andrew Grimm Mar 18 '12 at 22:29
  • @muistooshort: it's an exercise from [a book](http://pragprog.com/book/ppmetr/metaprogramming-ruby) :) – Sergio Tulentsev Mar 30 '12 at 03:16

2 Answers2

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
Fraser
  • 1,521
  • 2
  • 14
  • 23
  • 1
    Also, doing this seems to really confuse my IRb somehow, but does in fact work in plain Ruby. – Andrew Marshall Mar 16 '12 at 22:44
  • @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. – Andrew Marshall Mar 16 '12 at 22:47
  • 3
    @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. – Niklas B. Mar 16 '12 at 22:48
  • @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. – Andrew Marshall Mar 16 '12 at 22:53
  • Is this a good practice? I really need to do something like this, but all common sense tells me this is a bad idea. – mehulkar Dec 16 '14 at 08:05
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.

briangonzalez
  • 1,606
  • 16
  • 21