Extending core classes with so called monkey-paching pollutes the global scope, so it affects all files on the
$LOAD_PATH, i.e. whole application including used gems.
It’s not usually so big deal when you’re doing it in your application, but it’s very dangerous when used in a gem (library).
This can result in strange and hard to debug behaviour if another gem overrides a core class with the same method as your gem, but different implementation, and both gems are used together.
Refinements basically allows you to put monkey patches in an isolated namespace, so that your changes to core classes don’t affect other code.
Add this line to your application’s Gemfile:
gem 'corefines', '~> 1.11.1'
or to your gemspec:
s.add_runtime_dependency 'corefines', '~> 1.11.1'
and then execute:
$ bundle install
First, you must require
corefines prior using:
This will not activate any extensions (just register them), even when running in compatibility mode.
Extensions (refinements) are activated selectively with the method
Refinements are organized into modules by class which they refine, and further into submodules for individual methods. When an extension refines multiple classes, then it’s included in a module named after their nearest common ancestor (superclass).
A single extension can be imported into the current scope classically, e.g.:
or preferably using its “alias”:
If you want to include all extensions for the class, then you can just import the parent module, e.g.:
But more often you want to include multiple extensions for the class, but not all of them, e.g.:
using Corefines::Object::then_if using Corefines::Object::in?
this can be abbreviated to:
using Corefines::Object[:then_if, :in?]
If you feel that Corefines is too long, then you can also use abbreviation CF instead:
Refinements can be activated (with
using) at top-level (per file), inside a class, module or a method.
Refinements are still a young feature, so there’s a possibility that your gem or application will have to work on a Ruby platform that doesn’t fully support refinements yet.
The main Ruby implementation, MRI (aka CRuby), supports refinements since version 2.1.0 (released in 25 Dec 2013).  Version 2.0.0 (released in 24 Feb 2013) is still supported though. JRuby doesn’t support refinements yet, it’s planned in the upcoming version 188.8.131.52 (#1062). Rubinius also doesn’t support refinements yet.
This gem is a collection of pure refinements, and yet, it works even on older Rubies that don’t support refinements. Wait… how? Well, when you use the gem with an older Ruby, it’s actually cheating. Instead of locally scoped changes, it falls back to global monkey-patching.
The Corefines gem adds
using methods to the core classes, so you can define and use refinements just like in newer Rubies.
But internally it works very differently.
refine method adds a given block to a collection of pending “refinements” inside its module.
using is called first time for the module, it evaluates module’s “refinements” in context of the target classes (i.e. do a monkey-patch).
Not ideal indeed, but probably the best of what we can achieve.
List of refinements
Most of the extension methods are based on, or highly inspired from:
Very useful articles about refinements and how to “trick” them:
Create your feature branch (
git checkout -b my-new-feature).
Commit your changes (
git commit -am 'Add some feature').
Push to the branch (
git push origin my-new-feature).
Create a new Pull Request.
This project is licensed under MIT License. For the full text of the license, see the LICENSE file.