hooks 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +8 -0
- data/Gemfile.lock +12 -0
- data/README.rdoc +87 -0
- data/Rakefile +33 -0
- data/lib/hooks.rb +67 -0
- data/test/hooks_test.rb +64 -0
- data/test/test_helper.rb +11 -0
- metadata +84 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
= Hooks
|
2
|
+
|
3
|
+
<em>Generic hooks with callbacks for Ruby.</em>
|
4
|
+
|
5
|
+
|
6
|
+
== Introduction
|
7
|
+
|
8
|
+
Hooks lets you define hooks declaratively in your ruby class. You can add callbacks to your hook, which will be
|
9
|
+
run as soon as _you_ run the hook!
|
10
|
+
|
11
|
+
It's almost like ActiveSupport::Callbacks but 76,6% less complex.
|
12
|
+
|
13
|
+
Instead, it is not more than 80 lines of code, one method compilation, no +method_missing+ and no magic.
|
14
|
+
|
15
|
+
|
16
|
+
== Example
|
17
|
+
|
18
|
+
Let's take... a cat.
|
19
|
+
|
20
|
+
class Cat
|
21
|
+
include Hooks
|
22
|
+
|
23
|
+
define_hook :after_dinner
|
24
|
+
|
25
|
+
Now you can add callbacks to your hook declaratively in your class.
|
26
|
+
|
27
|
+
after_dinner do
|
28
|
+
puts "Ice cream!"
|
29
|
+
end
|
30
|
+
|
31
|
+
after_dinner :have_a_desert # => refers to Cat#have_a_desert
|
32
|
+
|
33
|
+
|
34
|
+
def have_a_desert
|
35
|
+
puts "Hell, yeah!"
|
36
|
+
end
|
37
|
+
|
38
|
+
Running the callbacks happens on instances. It will run the block and +#have_a_desert+ from above.
|
39
|
+
|
40
|
+
cat.run_hook :after_dinner
|
41
|
+
# => Ice cream!
|
42
|
+
Hell, yeah!
|
43
|
+
|
44
|
+
|
45
|
+
== Options
|
46
|
+
|
47
|
+
You're free to pass any number of arguments to #run_callback.
|
48
|
+
|
49
|
+
cat.run_hook :before_dinner, cat, Time.now
|
50
|
+
|
51
|
+
The callbacks should be ready for receiving parameters.
|
52
|
+
|
53
|
+
before_dinner :wash_pawns
|
54
|
+
before_dinner do |who, when|
|
55
|
+
...
|
56
|
+
end
|
57
|
+
|
58
|
+
def wash_pawns(who, when)
|
59
|
+
|
60
|
+
|
61
|
+
Not sure why a cat should have ice cream for dinner. Beside that, I was tempted naming this gem _hooker_.
|
62
|
+
|
63
|
+
|
64
|
+
== Installation
|
65
|
+
|
66
|
+
gem install hooks
|
67
|
+
|
68
|
+
|
69
|
+
== Dependencies
|
70
|
+
|
71
|
+
The current gem requires
|
72
|
+
|
73
|
+
* active_support 2.3.x
|
74
|
+
|
75
|
+
|
76
|
+
== Similar libraries
|
77
|
+
|
78
|
+
* http://github.com/nakajima/aspectory/tree/master/lib/aspectory/
|
79
|
+
* http://github.com/auser/backcall
|
80
|
+
* http://github.com/mmcgrana/simple_callbacks
|
81
|
+
|
82
|
+
|
83
|
+
== License
|
84
|
+
|
85
|
+
Copyright (c) 2010, Nick Sutterer
|
86
|
+
|
87
|
+
Released under the MIT License.
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the hooks plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |test|
|
10
|
+
test.libs << 'test'
|
11
|
+
test.test_files = FileList['test/*_test.rb']
|
12
|
+
test.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'jeweler'
|
16
|
+
$:.unshift File.dirname(__FILE__) # add current dir to LOAD_PATHS
|
17
|
+
require 'lib/hooks'
|
18
|
+
|
19
|
+
Jeweler::Tasks.new do |spec|
|
20
|
+
spec.name = "hooks"
|
21
|
+
spec.version = ::Hooks::VERSION
|
22
|
+
spec.summary = %{Generic hooks with callbacks for Ruby. }
|
23
|
+
spec.description = "Declaratively define hooks, add callbacks and run them with the options you like."
|
24
|
+
spec.homepage = "http://nicksda.apotomo.de/category/hooks"
|
25
|
+
spec.authors = ["Nick Sutterer"]
|
26
|
+
spec.email = "apotonick@gmail.com"
|
27
|
+
|
28
|
+
spec.files = FileList["[A-Z]*", File.join(*%w[{lib} ** *]).to_s]
|
29
|
+
|
30
|
+
spec.add_dependency 'activesupport', '>= 2.3.0'
|
31
|
+
end
|
32
|
+
|
33
|
+
Jeweler::GemcutterTasks.new
|
data/lib/hooks.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'active_support/core_ext/class/inheritable_attributes.rb'
|
2
|
+
|
3
|
+
# Almost like ActiveSupport::Callbacks but 76,6% less complex.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
#
|
7
|
+
# class CatWidget < Apotomo::Widget
|
8
|
+
# define_hook :after_dinner
|
9
|
+
#
|
10
|
+
# Now you can add callbacks to your hook declaratively in your class.
|
11
|
+
#
|
12
|
+
# after_dinner do puts "Ice cream!" end
|
13
|
+
# after_dinner :have_a_desert # => refers to CatWidget#have_a_desert
|
14
|
+
#
|
15
|
+
# Running the callbacks happens on instances. It will run the block and #have_a_desert from above.
|
16
|
+
#
|
17
|
+
# cat.run_hook :after_dinner
|
18
|
+
module Hooks
|
19
|
+
VERSION = "0.1"
|
20
|
+
|
21
|
+
def self.included(base)
|
22
|
+
base.extend ClassMethods
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
def define_hook(name)
|
27
|
+
accessor_name = "_#{name}_callbacks"
|
28
|
+
|
29
|
+
setup_hook_accessors(accessor_name)
|
30
|
+
define_hook_writer(name, accessor_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def define_hook_writer(hook, accessor_name)
|
35
|
+
instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
36
|
+
def #{hook}(method=nil, &block)
|
37
|
+
callback = block_given? ? block : method
|
38
|
+
#{accessor_name} << callback
|
39
|
+
end
|
40
|
+
RUBY_EVAL
|
41
|
+
end
|
42
|
+
|
43
|
+
def setup_hook_accessors(accessor_name)
|
44
|
+
class_inheritable_array(accessor_name, :instance_writer => false)
|
45
|
+
send("#{accessor_name}=", []) # initialize ivar.
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
# Runs the callbacks (method/block) for the specified hook +name+. Additional arguments will
|
51
|
+
# be passed to the callback.
|
52
|
+
#
|
53
|
+
# Example:
|
54
|
+
#
|
55
|
+
# cat.run_hook :after_dinner, "i want ice cream!"
|
56
|
+
#
|
57
|
+
# will invoke the callbacks like
|
58
|
+
#
|
59
|
+
# desert("i want ice cream!")
|
60
|
+
# block.call("i want ice cream!")
|
61
|
+
def run_hook(name, *args)
|
62
|
+
self.class.send("_#{name}_callbacks").each do |callback|
|
63
|
+
send(callback, *args) and next if callback.kind_of? Symbol
|
64
|
+
callback.call(*args)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/test/hooks_test.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class HooksTest < ActiveSupport::TestCase
|
4
|
+
context "Hooks.define_hook" do
|
5
|
+
setup do
|
6
|
+
@klass = Class.new(Object) do
|
7
|
+
include Hooks
|
8
|
+
|
9
|
+
def executed
|
10
|
+
@executed ||= [];
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
@mum = @klass.new
|
15
|
+
@mum.class.define_hook :after_eight
|
16
|
+
end
|
17
|
+
|
18
|
+
should "provide accessors to the stored callbacks" do
|
19
|
+
assert_equal [], @klass._after_eight_callbacks
|
20
|
+
@klass._after_eight_callbacks << :dine
|
21
|
+
assert_equal [:dine], @klass._after_eight_callbacks
|
22
|
+
end
|
23
|
+
|
24
|
+
context "creates a public writer for the hook that" do
|
25
|
+
should "accepts method names" do
|
26
|
+
@klass.after_eight :dine
|
27
|
+
assert_equal [:dine], @klass._after_eight_callbacks
|
28
|
+
end
|
29
|
+
|
30
|
+
should "accepts blocks" do
|
31
|
+
@klass.after_eight do true; end
|
32
|
+
assert @klass._after_eight_callbacks.first.kind_of? Proc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "Hooks.run_hook"do
|
37
|
+
should "run without parameters" do
|
38
|
+
@mum.instance_eval do
|
39
|
+
def a; executed << :a; end
|
40
|
+
def b; executed << :b; end
|
41
|
+
|
42
|
+
self.class.after_eight :b
|
43
|
+
self.class.after_eight :a
|
44
|
+
end
|
45
|
+
|
46
|
+
@mum.run_hook(:after_eight)
|
47
|
+
|
48
|
+
assert_equal [:b, :a], @mum.executed
|
49
|
+
end
|
50
|
+
|
51
|
+
should "accept arbitrary parameters" do
|
52
|
+
@mum.instance_eval do
|
53
|
+
def a(me, arg); executed << arg+1; end
|
54
|
+
end
|
55
|
+
@mum.class.after_eight :a
|
56
|
+
@mum.class.after_eight lambda { |me, arg| me.executed << arg-1 }
|
57
|
+
|
58
|
+
@mum.run_hook(:after_eight, @mum, 1)
|
59
|
+
|
60
|
+
assert_equal [2, 0], @mum.executed
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hooks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Nick Sutterer
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-09-24 00:00:00 +02:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: activesupport
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 3
|
30
|
+
- 0
|
31
|
+
version: 2.3.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: Declaratively define hooks, add callbacks and run them with the options you like.
|
35
|
+
email: apotonick@gmail.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README.rdoc
|
42
|
+
files:
|
43
|
+
- Gemfile
|
44
|
+
- Gemfile.lock
|
45
|
+
- README.rdoc
|
46
|
+
- Rakefile
|
47
|
+
- lib/hooks.rb
|
48
|
+
- test/test_helper.rb
|
49
|
+
- test/hooks_test.rb
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://nicksda.apotomo.de/category/hooks
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options:
|
56
|
+
- --charset=UTF-8
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.3.7
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: Generic hooks with callbacks for Ruby.
|
82
|
+
test_files:
|
83
|
+
- test/test_helper.rb
|
84
|
+
- test/hooks_test.rb
|