Extensible
Use Extensible on your custom extensions in order to get the following set of advantages over traditional extensions
that override the Module#extended
method directly:
- Calls to
super
are handled internally to ensure all your extensible extensions are properly initialized. - Your extensible extensions will be automatically able to become the base of other, more specific extensions while proper initialization is maintained by simply including them.
- Bundle several extensible extensions in a single module by including them and they will all be correctly initialized when extending the bundler module.
Specific examples for each of these scenarios can be found in the usage section.
Installation
Add this line to your application's Gemfile:
gem "extensible"
And then execute:
$ bundle
Or install it yourself as:
$ gem install extensible
When should I use Extensible?
You should use Extensible every time you're implementing a module that is intended to be used as an extension for a module or a class and that extension needs to have some initialization code.
In short: if you are going to override Module#extended
, use Extensible instead.
Usage
Basic
Creating an extensible extension module is, arguably, simpler than creating a traditional extension that overrides
Module#extended
. Note that we do not need to call super
within the code block since it will be called "under the
hood" before the code is executed:
module MyExtension
extend Extensible
when_extended {|m| puts "#{self} has extended #{m}." }
end
As you would expect, this is what happens when you use your extensible extension in a class (or module):
class MyClass
extend MyExtension
end #=> MyExtension has extended MyClass.
Extending extensions
The extensions you create using Extensible are "extensible" in the sense that you (or someone else) can use them as the base for other, more specific extensions. The best bit is you get this at no additional cost. Simply include them and extend away!
Suppose we have a base extension that sets an instance variable that holds the reversed name of the module or class extending it:
module MyBaseExtension
extend Extensible
when_extended do |m|
m.instance_variable_set(:@reversed_name, m.to_s.reverse)
end
end
Now we can use MyBaseExtension
on its own, but we can also extend it to, for example, create a reader method for the
@reversed_name
variable by including it on our more specific MySubExtension
:
module MySubExtension
include MyBaseExtension
attr_reader :reversed_name
end
We can now extend MySubExtension
ensuring that the initialization routine of MyBaseExtension
is executed as
expected:
class MyClass
extend MySubExtension
end
MyClass.reversed_name #=> "ssalCyM"
Note: MySubExtension
could have (if needed) extended Extensible to provide its own initialization routine. In this
case both initialization routines (the one for MyBaseExtension
and the one for MySubExtension
) would have been
executed when MyClass
extended it.
Bundling extensions
Traditional extensions that override the Module#extended
method work correctly as long as they are explicitly extended
in the module or class that will ultimately use them. This can become really cumbersome really fast when you want to
apply several extensions to a set of different modules or classes.
Using extensible extensions you can bundle many of them within a single module, and then extend all of them at the same time by extending the bundler module.
Suppose you have two extensions (A
and B
) that you want to bundle together:
module A
extend Extensible
when_extended { puts "A was extended!" }
end
module B
extend Extensible
when_extended { puts "B was extended!" }
end
Simply include them in your bundler module:
module Bundle
include A
include B
end
And extend it!
module MyClass
extend Bundle
end #=> A was extended!
#=> B was extended!
Contributing
- Fork it ( https://github.com/gdeoliveira/extensible/fork )
- 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