732532b72e
Conflicts: middleman-core/lib/middleman-core/application.rb |
||
---|---|---|
.. | ||
lib | ||
test | ||
.gitignore | ||
.travis.yml | ||
CHANGES.md | ||
Gemfile | ||
hooks.gemspec | ||
LICENSE.txt | ||
Rakefile | ||
README.md |
Hooks
Generic hooks with callbacks for Ruby.
Introduction
Hooks lets you define hooks declaratively in your ruby class. You can add callbacks to your hook, which will be run as soon as you run the hook!
It's almost like ActiveSupport::Callbacks but 76,6% less complex. Instead, it is not more than a few lines of code, one method compilation, no method_missing
and no magic.
Also, you may pass additional arguments to your callbacks when invoking a hook.
Example
Let's take... a cat.
require 'hooks'
class Cat
include Hooks
define_hooks :before_dinner, :after_dinner
Now you can add callbacks to your hook declaratively in your class.
before_dinner :wash_paws
after_dinner do
puts "Ice cream for #{self}!"
end
after_dinner :have_a_desert # => refers to Cat#have_a_desert
def have_a_desert
puts "Hell, yeah!"
end
This will run the block and #have_a_desert
from above.
cat.run_hook :after_dinner
# => Ice cream for #<Cat:0x8df9d84>!
Hell, yeah!
Callback blocks and methods will be executed with instance context. Note how self
in the block refers to the Cat instance.
Inheritance
Hooks are inherited, here's a complete example to put it all together.
class Garfield < Cat
after_dinner :want_some_more
def want_some_more
puts "Is that all?"
end
end
Garfield.new.run_hook :after_dinner
# => Ice cream for #<Cat:0x8df9d84>!
Hell, yeah!
Is that all?
Note how the callbacks are invoked in the order they were inherited.
Options for Callbacks
You're free to pass any number of arguments to #run_callback, those will be passed to the callbacks.
cat.run_hook :before_dinner, cat, Time.now
The callbacks should be ready for receiving parameters.
before_dinner :wash_pawns
before_dinner do |who, when|
...
end
def wash_pawns(who, when)
Not sure why a cat should have ice cream for dinner. Beside that, I was tempted naming this gem hooker.
Running And Halting Hooks
Using #run_hook
doesn't only run all callbacks for this hook but also returns an array of the results from each callback method or block.
class Garfield
include Hooks
define_hook :after_dark
after_dark { "Chase mice" }
after_dark { "Enjoy supper" }
end
Garfield.new.run_hook :after_dark
# => ["Chase mice", "Enjoy supper"]
This is handy if you need to collect data from your callbacks without having to access a global (brrr) variable.
With the :halts_on_falsey
option you can halt the callback chain when a callback returns nil
or false
.
class Garfield
include Hooks
define_hook :after_dark, halts_on_falsey: true
after_dark { "Chase mice" }
after_dark { nil }
after_dark { "Enjoy supper" }
end
result = Garfield.new.run_hook :after_dark
# => ["Chase mice"]
This will only run the first two callbacks. Note that the result doesn't contain the nil
value. You even can check if the chain was halted.
result.halted? #=> true
Instance Hooks
You can also define hooks and/or add callbacks per instance. This is helpful if your class should define a basic set of hooks and callbacks that are then extended by instances.
class Cat
include Hooks
include Hooks::InstanceHooks
define_hook :after_dark
after_dark { "Chase mice" }
end
Note that you have to include Hooks::InstanceHooks
to get this additional functionality.
See how callbacks can be added to a separate object, now.
garfield = Cat.new
garfield.after_dark :sleep
garfield.run_hook(:after_dark) # => invoke "Chase mice" hook and #sleep
This will copy all callbacks from the after_dark
hook to the instance and add a second hook. This all happens on the garfield
instance, only, and leaves the class untouched.
Naturally, adding new hooks works like-wise.
garfield.define_hook :before_six
garfield.before_six { .. }
This feature was added in 0.3.2.
Installation
In your Gemfile, do
gem "hooks"
Anybody using it?
- Hooks is already used in Apotomo, a hot widget framework for Rails.
- The datamappify gem uses hooks and the author Fred Wu contributed to this gem!
Similar libraries
- http://github.com/nakajima/aspectory
- http://github.com/auser/backcall
- http://github.com/mmcgrana/simple_callbacks
License
Copyright (c) 2013, Nick Sutterer
Released under the MIT License.