10

You can refine your class with

module RefinedString
  refine String do
    def to_boolean(text)
    !!(text =~ /^(true|t|yes|y|1)$/i)
    end
  end
end

but how to refine module method? This:

module RefinedMath
  refine Math do
    def PI
      22/7
    end
  end
end

raises: TypeError: wrong argument type Module (expected Class)

Filip Bartuzi
  • 5,711
  • 7
  • 54
  • 102

2 Answers2

16

This piece of code will work:

module Math
  def self.pi
    puts 'original method'
   end
end

module RefinementsInside
  refine Math.singleton_class do
    def pi
      puts 'refined method'
    end
  end
end

module Main
  using RefinementsInside
  Math.pi #=> refined method
end

Math.pi #=> original method

Explanation:

Defining a module #method is equivalent to defining an instance method on its #singleton_class.

Evgenia Karunus
  • 10,715
  • 5
  • 56
  • 70
1

Refinements only modify classes, not modules so the argument must be a class.

http://ruby-doc.org/core-2.1.1/doc/syntax/refinements_rdoc.html

As soon as you are aware of what you are doing, you have two options to refine module methods globally. Since ruby has open classes, you might simply override the method:

▶ Math.exp 2
#⇒ 7.38905609893065
▶ module Math
▷   def self.exp arg
▷     Math::E ** arg
▷   end  
▷ end  
#⇒ :exp
▶ Math.exp 2
#⇒ 7.3890560989306495

Whether you want to save the functionality of the method to be overwritten:

▶ module Math
▷   class << self
▷     alias_method :_____exp, :exp  
▷     def exp arg  
▷       _____exp arg    
▷     end  
▷   end  
▷ end  
#⇒ Math
▶ Math.exp 2
#⇒ 7.3890560989306495

Please be aware of side effects.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160