In Ruby, classes are open. They can be modified at any time. You can add new methods to existing classes and even re-define methods. Rubyists call this monkey-patching.
In the example below, I’ve added
String#word_count to return the number of words in a string.
class String def word_count self.split.count end end
"Don't put your blues where your shoes should be.".word_count # => 9
However, this change is global. What happens if someone else defines their own version of
String#word_count based on different rules? Say, they might want to count the individual parts of a contraction, or ignore digits and any non-word characters.
Refinements allow us to monkey-patch classes and modules locally.
Here, I’ve created a new module and used
Module#refine to add
module MyStringUtilities refine String do def word_count self.split.count end end end
The refinement isn’t available in the global scope:
"Take my shoes off and throw them in the lake.".word_count # => NoMethodError: undefined method `word_count' for…
To activate the refinment, I need to use
using MyStringUtilities "Take my shoes off and throw them in the lake.".word_count # => 10 "A pseudonym to fool him".word_count # => 5
If I activate the refinement within a class or module, the refinement is available until the end of the class or module definition.
Below, the refinement is not available at the top level because it is scoped to
module MyStringUtilities refine String do def word_count self.split.count end end end class MyClass using MyStringUtilities def self.number_of_words_in(string) string.word_count end end "Out on the wily, windy moors".word_count #=> NoMethodError MyClass.number_of_words_in("Out on the wily, windy moors") #=> 6