le_me
le_me

Reputation: 3419

How to overwrite a class just for a module in ruby?

Why doesn't this work?

module Magic
  class Fixnum
    def div2(other)
      self.to_f / other
    end

    alias :"/" :div2
  end
end

module SomeModule
  include Magic

  1/4 == 0.25 #should be true in here
end

1/4 == 0.25 #should be false everywhere else

Upvotes: 0

Views: 73

Answers (3)

blom
blom

Reputation: 3092

If you want your modifications to Fixnum to only apply certain places, you can use refinements:

module Magic
  refine Fixnum do
    def foo
      "Hello"
    end
  end
end

class SomeClass
  using Magic

  10.foo # => "Hello"

  def initialize
    10.foo # => "Hello"
  end
end

10.foo # Raises NoMethodError

Your original example defines an new class called Fixnum within Magic (Magic::Fixnum). It does not touch the global Fixnum. The response you posted where you said ::Fixnum modifies the global Fixnum class.

Upvotes: 0

Daniël Knippers
Daniël Knippers

Reputation: 3055

The answer you posted yourself is actually changing Fixnum globally, which is not what you want. That is, with your solution:

module Magic
  class ::Fixnum
    def div2(other)
      self.to_f / other
    end

    alias :"/" :div2
  end
end

# Yields 0.25 instead of expected 0. 
# This line should not be affected by your Fixnum change, but is.
1/4 

For the use case you describe, Ruby 2.0 introduced refinements, which you can use like below. Please note that using a Module inside another Module is not possible in Ruby 2.0, but is in Ruby 2.1. So to use the Magic module inside SomeModule you will require Ruby 2.1. This might be a problem if you are using Windows since you will have to compile 2.1 yourself, the Windows binaries and installer are still at 2.0.

module Magic
  refine Fixnum do
    def /(other)
      self.to_f / other
    end
  end
end

1/4 # => 0
using Magic
1/4 # => 0.25

Upvotes: 5

le_me
le_me

Reputation: 3419

OK, I need to access the Fixnum class at toplevel, the code should be:

module Magic
  class ::Fixnum
    def div2(other)
      self.to_f / other
    end

    alias :"/" :div2
  end
end

This works!

Upvotes: 0

Related Questions