• Stars
    star
    281
  • Rank 147,023 (Top 3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created about 14 years ago
  • Updated almost 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Generic hooks with callbacks for Ruby.

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_dessert   # => refers to Cat#have_a_dessert

  def have_a_dessert
    puts "Hell, yeah!"
  end

This will run the block and #have_a_dessert 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

Execution Scope

Normally, callbacks are executed in object context. You're free to provide your own context object using :scope.

define_hook :before_lunch, scope: lambda { |callback, scope| Logger }

This will evaluate the lambda in Logger class context.

Return nil to execute the lambda in the original context.

define_hook :before_lunch, scope: lambda { |*| nil }
what = "hands"
before_lunch << lambda { puts "wash #{what}" } # executed in original context.

The :scope lambda is executed for every added callback per run, hence the block options.

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.

Callbacks can now be added to a single object.

garfield = Cat.new

garfield.after_dark :sleep
garfield.run_hook(:after_dark) # => invoke "Chase mice" hook and #sleep

What happens is that the garfield object inherits existing hooks with all their callbacks from the Cat class, namely, this is :after_dark. It can then add local callbacks (or even more hooks) to itself without affecting the Cat class.

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

License

Copyright (c) 2013-2015, Nick Sutterer

Released under the MIT License.

More Repositories

1

apotomo

MVC Components for Rails.
Ruby
654
star
2

disposable

Decorators on top of your ORM layer.
Ruby
171
star
3

gemgem-trbrb

The Trailblazer book's example app.
Ruby
137
star
4

paperdragon

Explicit image processing based on Dragonfly.
Ruby
114
star
5

uber

Gem-authoring extensions for classes and modules.
Ruby
94
star
6

cells_examples

A rails project to demonstrate cells in action.
Ruby
83
star
7

nit

Nit improves your git workflow.
Ruby
65
star
8

onfire

Have bubbling events and observers in all your Ruby objects.
Ruby
58
star
9

tyrant

Agnostic authentication gem with signup, signin, forgot password, sticky login, and so on.
Ruby
50
star
10

erbse

Next-generation ERB.
Ruby
48
star
11

kaminari-cells

Kaminari pagination in Cells.
Ruby
23
star
12

cells-blog-example

An exemplary Rails 3 Blog app using Cells.
JavaScript
22
star
13

pingback_engine

A Rails plugin for sending and receiving pingbacks.
Ruby
22
star
14

declarative

DSL for nested schemas.
Ruby
22
star
15

active_helper

Finally - helpers with proper encapsulation, delegation, interfaces and inheritance!
Ruby
19
star
16

gemgem

Sample Rails app using Trailblazer like a boss.com.au.
Ruby
18
star
17

rspec-apotomo

Spec your widgets.
Ruby
16
star
18

dashboard_tutorial

Rails app showing how to build dashboards with Apotomo.
Ruby
15
star
19

gemgem-hanami

Hanami with Trailblazer.
Ruby
14
star
20

cells-capture

Provides content_for for Cells.
Ruby
12
star
21

cells-sinatra

View Components for Sinatra.
Ruby
10
star
22

trb-cart

Shopping cart app with Trailblazer.
Ruby
10
star
23

declarative-option

Dynamic Options to evaluate at runtime.
Ruby
7
star
24

webmachinelovesroar

Ruby services to implement a RESTful shopping cart system with webmachine + roar.
Ruby
7
star
25

www.apotomo.de

Sources for the Apotomo project page, bundled as a Torture app (unreleased!).
Ruby
6
star
26

ruby-on-rest

The example apps from my" Ruby On REST" blog series.
Ruby
6
star
27

exp

My expense application, a Trailblazer+Sinatra example.
Ruby
6
star
28

torture

Tool collection to write and layout programmer's manuals.
Ruby
6
star
29

buildalib

The example app for the "Building your own authentication library with Trailblazer" book.
Ruby
6
star
30

gemgem-grape

HTTP API example application with Grape and Trailblazer.
Ruby
5
star
31

apotomo-stateful

Statefulness for your Apotomo widgets.
Ruby
5
star
32

cheatsheets

Cheatsheets for Cells, Apotomo and ROAR.
4
star
33

declarative-builder

Generic builder pattern.
Ruby
3
star
34

torture-server

Documentation framework
Ruby
3
star
35

pipetree

Functional nested pipeline dialect.
Ruby
3
star
36

screencastsofglory

The example project used for "Apotomo - Screencasts Of Glory"
Ruby
3
star
37

cells-filters

Before and after filters for your cells.
Ruby
3
star
38

cells-widget

Cells view models that can be updated via AJAX.
2
star
39

sinatra-on-cells

Sinatra app using Rails cells and cool Rails gems like simple_form.
Ruby
2
star
40

trb-rubyday

Where's my limoncello?
Ruby
2
star
41

cells-examples

Examples of using Cells with plain Ruby, Lotus, Sinatra, and more. Includes caching, view inheritance, etc.
Ruby
1
star
42

subliminal

My Sublime 3 configuration and snippets.
1
star
43

roar-form_json

Representers for the (unofficial) Form+JSON media type.
Ruby
1
star