Overridable is a pure ruby library which helps you to make your methods which are defined in classes to be able to be overrided by mixed-in modules.
Some people are overusing alias_method_chain
in their codes like what wycats mentioned in his post. One of the reasons that people like using alias_method_chain
is because it's impossible for modules to override methods that are defined in classes when they are included. For example:
class Thing
def foo
'Thing.foo'
end
end
module Extension
def foo
'Extension.foo'
end
end
Thing.send :include, Extension
Thing.new.foo #=> Thing.foo # not Extension.foo
In order to achieve that goal, some will write the Extension module like this: module Extension def foo_with_redef 'Extension.foo' end # you can also do this by: alias_method_chain :foo, :redef, if you use ActiveSupport. alias foo_without_redef foo alias foo foo_with_redef end
Thing.send :include, Extension
Thing.new.foo #=> Extension.foo
But according to the post, this is a bad practice. And overridable is a gem that provides a neat mean to resolve this problem.
There are two ways to do this with overridable: in class or in module.
Remember Thing and Extension in our first example? Let's make some changes: require 'overridable'
Thing.class_eval {
include Overridable
overrides :foo
include Extension
}
Thing.new.foo #=> Extension.foo
That's it! You can specify which methods can be overrided by overrides
method. One more example based on the previous one:
Thing.class_eval {
def bar; 'Thing.bar' end
def baz; 'Thing.baz' end
def id; 'Thing' end
overrides :bar, :baz
}
Extension.module_eval {
def bar; 'Extension.bar' end
def baz; 'Extension baz' end
def id; 'Extension' end
}
thing = Thing.new
thing.bar #=> 'Extension.bar'
thing.baz #=> 'Extension.baz'
thing.id #=> 'Thing'
Of course it's not the end of our story ;) How could I call this override if we cannot use super
? Go on with our example:
Extension.module_eval {
def bar
parent = super
me = 'Extension.bar'
"I'm #{me} and I overrided #{parent}"
end
}
Thing.new.bar => I'm Extension.bar and I overrided Thing.bar
If you have many methods in your module and find that it's too annoying to use overrides
, then you can mix Overridable::ModuleMixin in your module. Example ( we all like examples, don't we? ):
class Thing
def method_one; ... end
def method_two; ... end
...
def method_n; ... end
end
module Extension
include Overridable::ModuleMixin
def method_one; ... end
def method_two; ... end
...
def method_n; ... end
end
Thing.send :include, Extension #=> method_one, method_two, ..., method_n are all overrided.
Since version 0.3.1, you can use overrides
in your module to specify which method should be overrided and which should not. Let's rewrite the Extension module above:
module Extension
include Overridable::ModuleMixin
overrides :only => [:method_one, :method_two]
# define methods here...
end
Thing.send :include, Extension #=> only method_one and method_two will be overrided.
You can also use overrides :except => [:method_one, :method_two]
to tell the module not to override method_one and method_two in the classes which include it.
gem source -a http://gemcutter.org # you neednot do this if you have already had gemcutter in your source list
gem install overridable
- Ruby >= 1.8.7
- riot >= 0.10.0 just for test
- yard >= 0.4.0 just for generating document
$> cd $GEM_HOME/gems/overridable-x.y.z
$> rake test # requires riot
These features only will be added when they are asked for.
- :all and :except for overrides overrides :all, :except => [:whatever, :excepts]
- override with block
override :foo do |*args| super # or not # any other stuff end - tell me what's missing.
- Fork the project.
- Make your feature addition or bug fix.
- Add tests for it. This is important so I don't break it in a future version unintentionally.
- Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
- Send me a pull request. Bonus points for topic branches.
Copyright (c) 2009 梁智敏. See LICENSE for details.