hooked 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,6 +2,4 @@ source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- group :development do
6
- gem "awesome_print"
7
- end
5
+ gem "awesome_print"
data/README.md CHANGED
@@ -1,12 +1,181 @@
1
- Ruby library for Aspect Oriented Programming
1
+ Ruby Library For Aspect Oriented Programming
2
2
  ============================================
3
3
 
4
- hooked makes AOP a breeze. It lets you define and invoke code that other
5
- gems or parts of your application can hook onto. Supported hooks are before,
6
- after and around.
4
+ Hooked makes AOP a breeze. It lets you define and invoke code that gems or other
5
+ parts of your application can hook onto.
7
6
 
8
- To Do
9
- -----
7
+ Getting Started
8
+ ---------------
10
9
 
11
- * Skip hooks
12
- * Control flow (return, next, break)
10
+ require "hooked"
11
+
12
+ class User
13
+ include Hooked::Container
14
+
15
+ def save
16
+ hookable(:save_user, self)
17
+ end
18
+
19
+ hookable :save_user do |ctx|
20
+ ctx.return(Database.save(ctx.args))
21
+ end
22
+ end
23
+
24
+ class PermissionCheck
25
+ include Hooked::Container
26
+
27
+ def has_permissions?
28
+ false
29
+ end
30
+
31
+ before :save_user, :check_permissions do |ctx|
32
+ ctx.break unless has_permissions?
33
+ end
34
+ end
35
+
36
+ user = User.new
37
+ hooking = Hooked::Controller.new(user, PermissionCheck.new)
38
+ user.save # => false
39
+
40
+ Defining Hookable Code
41
+ ----------------------
42
+
43
+ To be able to define hookable code (as well as hooks) you need to mixin the
44
+ Hooked::Container module. Afterwards you can use the `::hookable` method which
45
+ takes a symbol as the hookable's name as well as a block.
46
+
47
+ class Something
48
+ include Hooked::Container
49
+
50
+ hookable :breakfast do |ctx|
51
+ puts "I'm having breakfast"
52
+ end
53
+ end
54
+
55
+ The hookable will always be executed in the context of its container's object.
56
+
57
+ Defining Hooks
58
+ --------------
59
+
60
+ For defining hooks you can use the methods `::before`, `::after` and
61
+ `::around`. They are shortcuts to `::hook` and take the arguments
62
+ `hookable_name` (name of the hookable you want to hook onto), `hook_name` and
63
+ an optional hash of before/after options.
64
+
65
+ before :breakfast, :get_up do |ctx|
66
+ puts "I'm getting out of the bed"
67
+ end
68
+
69
+ before :breakfast, :make_coffee, :after => :get_up do |ctx|
70
+ puts "I'm making coffee"
71
+ end
72
+
73
+ `:before` and `:after` can be a single hook name, an array of hook names or
74
+ `:all`. More documentation on before/after relations and how they are being
75
+ resolved can be found in the
76
+ [depression gem](http://rubygems.org/gems/depression).
77
+
78
+ Hooks will always be executed in the context of their container's object (just
79
+ as hookables).
80
+
81
+ **Note:** Hooked will at no point guarantee that hooks will be executed in the
82
+ order of definition. If you rely on execution order, you should use the
83
+ `:before` and `:after` options.
84
+
85
+ Hooking Controller
86
+ ------------------
87
+
88
+ The controller is responsible for bringing hooks into the desired order and
89
+ executing them correctly.
90
+
91
+ hooking = Hooked::Controller.new(container1, container2)
92
+ result = hooking.invoke(:my_hookable, arguments)
93
+
94
+ Arguments And Return Values
95
+ ---------------------------
96
+
97
+ All argument and return value stuff (and control flow) is managed through a
98
+ context object that is being passed between the hooks as well as the hookable.
99
+ You can pass in and out whatever you want.
100
+
101
+ after(:lowercase, :confuse_programmer) do |ctx|
102
+ ctx.result = ctx.args.map {|s| s.upper }
103
+ end
104
+
105
+ res = hooking.invoke(:lowercase, ["asdf", :foo, 123]) do |ctx|
106
+ ctx.result = ctx.args.map {|s| s.to_s.lower }
107
+ end
108
+
109
+ p res # => ["ASDF", "FOO", "123"]
110
+
111
+ Control Flow
112
+ ------------
113
+
114
+ If you want to cancel the execution of a hook and immediately start with the
115
+ next one, use `Context#next`. You would probably want to set a return value
116
+ first with `Context#result=`. `Context#return` basically does the same thing,
117
+ but additionally it always sets the return value to whatever you pass as an
118
+ argument.
119
+
120
+ # this
121
+ ctx.return "asd"
122
+ # is equal to
123
+ ctx.result = "asd"
124
+ ctx.next
125
+
126
+ # and this will result in ctx.result being nil after returning
127
+ ctx.result = 123
128
+ ctx.return
129
+
130
+ If you want to cancel the whole invocation you can use `Context#break`. This
131
+ will immediately return to where `Controller#invoke` was called. So if you call
132
+ it before the hookable was executed, it won't be executed at all.
133
+
134
+ hookable :foo do |ctx|
135
+ puts "You won't see me :/"
136
+ end
137
+
138
+ before :foo, :break_the_chain do |ctx|
139
+ ctx.break
140
+ end
141
+
142
+ You can pass a Fixnum to `Context#next` and `Context#break` to specify the
143
+ stack depth you want to jump. If you jump to high (e.g. you're hooking two
144
+ invocations deep but do `ctx.break 3`) a `NameError: uncaught throw 'hooked'`
145
+ will be raised.
146
+
147
+ **NOTE** You should definitely _not_ use Ruby's control flow constructs, they
148
+ may cause serious trouble that can be hard to debug. This may change in future
149
+ versions of Hooked. (I appreciate Pull Requests! :>)
150
+
151
+ Dependencies
152
+ ------------
153
+
154
+ * [depression](https://rubygems.org/gems/depression)
155
+ * Ruby 1.9.2
156
+ * Possibly other versions and platforms, I didn't test any yet.
157
+ * [mocha](https://rubygems.org/gems/mocha) and
158
+ [test-unit](https://rubygems.org/gems/test-unit) for development
159
+
160
+ To do & Ideas
161
+ -------------
162
+
163
+ * Skipping hooks
164
+ * Visualization of hook flow
165
+ * Make backtraces more readable
166
+ * Make Ruby's control flow constructs work for hooks
167
+
168
+ Contributing
169
+ ------------
170
+
171
+ 1. Fork at [github.com/lgierth/hooked](https://github.com/lgierth/hooked)
172
+ 2. Create a new branch
173
+ 3. Commit, commit, commit!
174
+ 4. Open a Pull Request
175
+
176
+ You can also open an issue for discussion first, if you like.
177
+
178
+ License
179
+ -------
180
+
181
+ Hooked is subject to an MIT-style license that can be found in the LICENSE file.
data/hooked.gemspec CHANGED
@@ -10,10 +10,10 @@ Gem::Specification.new do |s|
10
10
  s.authors = ["Lars Gierth"]
11
11
  s.email = ["lars.gierth@gmail.com"]
12
12
  s.homepage = "http://rubygems.org/gems/hooked"
13
- s.summary = %q{Ruby library for Aspect Oriented Programming}
14
- s.description = %q{hooked makes AOP a breeze. It lets you define and invoke
15
- code that other gems or parts of your application can hook
16
- onto. Supported hooks are before, after and around.}
13
+ s.summary = %q{Ruby Library For Aspect Oriented Programming}
14
+ s.description = %q{Hooked makes AOP a breeze. It lets you define and invoke
15
+ code that gems or other parts of your application can hook
16
+ onto.}
17
17
 
18
18
  s.add_dependency "depression"
19
19
 
@@ -0,0 +1,39 @@
1
+ module Hooked
2
+ class Context
3
+ attr_reader :args
4
+ attr_accessor :result
5
+
6
+ def initialize(args)
7
+ @args = args
8
+ end
9
+
10
+ def next(depth = 1)
11
+ return if depth < 1
12
+ throw(:hooked, {
13
+ :type => :next,
14
+ :depth => depth
15
+ })
16
+ end
17
+
18
+ def return(result)
19
+ @result = result
20
+ self.next
21
+ end
22
+
23
+ def break(depth = 1)
24
+ return if depth < 1
25
+ throw(:hooked, {
26
+ :type => :break,
27
+ :depth => depth
28
+ })
29
+ end
30
+
31
+ def skip(*hooks)
32
+ raise "Not yet implemented."
33
+ end
34
+
35
+ def skip_other(hookable, *hooks)
36
+ raise "Not yet implemented."
37
+ end
38
+ end
39
+ end
@@ -2,11 +2,9 @@ module Hooked
2
2
  Result = Struct.new(:type, :value)
3
3
 
4
4
  class Controller
5
- attr_reader :name, :containers, :hookables, :hooks
5
+ attr_reader :containers, :hookables, :hooks
6
6
 
7
- def initialize(name, *containers)
8
- @name = name
9
-
7
+ def initialize(*containers)
10
8
  @containers = []
11
9
  @hookables = {}
12
10
  @hooks = {}
@@ -18,6 +16,7 @@ module Hooked
18
16
  def add(*containers)
19
17
  @containers.push(*containers)
20
18
  containers.each do |c|
19
+ c.hooked = self
21
20
  c.class.hookables.each do |hkbl|
22
21
  hkbl.container = c
23
22
  hookables[hkbl.name] = hkbl
@@ -34,59 +33,48 @@ module Hooked
34
33
  hooks.each {|hkbl_name, hs| hooks[hkbl_name] = Depression.process(hs) }
35
34
  end
36
35
 
37
- def invoke(name, *args, &block)
36
+ def invoke(name, args = nil, &block)
38
37
  if block
39
38
  hookable = Hookable.new(name, &block)
40
39
  else
41
40
  hookable = hookables[name] || raise("Unknown hookable: #{name}")
42
41
  end
43
42
 
44
- result = catch(:hooked) do
45
- (hooks[name] || []).reverse.inject(hookable) do |next_item, item|
46
- proc {|a| call_hook(item, next_item, a) }
47
- end.call(args)
43
+ context = Context.new(args)
44
+ chain = (hooks[name] || []).reverse.inject(hookable) do |next_item, item|
45
+ proc {|ctx| call_hook(item, next_item, ctx) }
48
46
  end
49
- if (result[0] rescue nil) == :hooked_abort_chain
50
- result[1]
51
- else
52
- result
47
+
48
+ ctrl = catch(:hooked) { chain.call(context); nil }
49
+
50
+ if ctrl.respond_to?(:[])
51
+ ctrl[:depth] -= 1
52
+ throw(:hooked, ctrl) if ctrl[:depth] > 0
53
53
  end
54
+
55
+ context.result
54
56
  end
55
57
 
56
- protected
57
-
58
- # def call_wrapped_hook(hook, hookable, args)
59
- # ret = nil
60
- #
61
- # j = (0..1).each do |i|
62
- # ret = call_hook(hook, hookable, args) if i == 0
63
- # end
64
- # unless j
65
- # throw(:hooked, :hooked_abort_chain)
66
- # end
67
- #
68
- # ret
69
- # end
70
-
71
- def call_hook(hook, hookable, args)
72
- args = hook.call(*args) if hook.before?
58
+ def call_hook(hook, hookable, context)
59
+ wrap { hook.call(context) } if hook.before?
73
60
 
74
- result = catch(:hooked) do
61
+ wrap do
75
62
  if hook.around?
76
- hook.call(hookable, *args)
63
+ hook.call(context, hookable)
77
64
  else
78
- hookable.call(*args)
65
+ hookable.call(context)
79
66
  end
80
67
  end
81
- if result == :hooked_abort_chain
82
- throw(:hooked, [:hooked_abort_chain, args])
83
- else
84
- args = result
85
- end
86
-
87
- args = hook.call(*args) if hook.after?
88
68
 
89
- args
69
+ wrap { hook.call(context) } if hook.after?
70
+ end
71
+
72
+ def wrap(&block)
73
+ ctrl = catch(:hooked) { block.call; nil }
74
+ if ctrl.respond_to?(:[]) && (
75
+ ctrl[:type] == :break || ctrl[:depth] > 1)
76
+ throw(:hooked, ctrl)
77
+ end
90
78
  end
91
79
  end
92
80
  end
data/lib/hooked/hook.rb CHANGED
@@ -13,9 +13,9 @@ module Hooked
13
13
  @container, @block = container, block
14
14
  end
15
15
 
16
- def call(*args)
16
+ def call(context)
17
17
  raise RuntimeError, "No container set for hook `#{name}'" unless container
18
- container.instance_exec(*args, &@block)
18
+ container.instance_exec(context, &@block)
19
19
  end
20
20
 
21
21
  def before?
@@ -9,11 +9,11 @@ module Hooked
9
9
  @name, @container, @block = name.to_sym, container, block
10
10
  end
11
11
 
12
- def call(*args)
12
+ def call(context)
13
13
  if container
14
- container.instance_exec(*args, &@block)
14
+ container.instance_exec(context, &@block)
15
15
  else
16
- @block.call(*args)
16
+ @block.call(context)
17
17
  end
18
18
  end
19
19
  end
@@ -1,3 +1,3 @@
1
1
  module Hooked
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/hooked.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "depression"
2
2
 
3
3
  require "hooked/container"
4
+ require "hooked/context"
4
5
  require "hooked/controller"
5
6
  require "hooked/hook"
6
7
  require "hooked/hookable"
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__)) + "/helper.rb"
1
+ require File.expand_path("../helper", __FILE__)
2
2
 
3
3
  class ContainerTest < Test::Unit::TestCase
4
4
  def setup
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__)) + "/helper.rb"
1
+ require File.expand_path("../helper", __FILE__)
2
2
 
3
3
  class ControllerTest < Test::Unit::TestCase
4
4
  def setup
@@ -20,15 +20,8 @@ class ControllerTest < Test::Unit::TestCase
20
20
  ].map {|c| c.new }
21
21
  end
22
22
 
23
- def test_has_a_name
24
- name = :foo
25
- controller = Hooked::Controller.new(name)
26
-
27
- assert_equal name, controller.name
28
- end
29
-
30
23
  def test_has_containers
31
- controller = Hooked::Controller.new(:foo, @containers[0])
24
+ controller = Hooked::Controller.new(@containers[0])
32
25
  controller.add(*@containers[1..2])
33
26
 
34
27
  assert_equal @containers, controller.containers
@@ -40,7 +33,7 @@ class ControllerTest < Test::Unit::TestCase
40
33
  @containers[0].class.hooks[:foo][0],
41
34
  @containers[1].class.hooks[:foo][0]
42
35
  ]
43
- controller = Hooked::Controller.new(:baz, *@containers)
36
+ controller = Hooked::Controller.new(*@containers)
44
37
 
45
38
  assert_equal hookable, controller.hookables[hookable.name]
46
39
  assert_equal hooks, controller.hooks[:foo]
@@ -57,10 +50,10 @@ class ControllerTest < Test::Unit::TestCase
57
50
  end
58
51
  order = [:do_laundry, :do_something_more, :do_something_else, :do_something, :do_dishes]
59
52
 
60
- controller = Hooked::Controller.new(:baz, container.new)
53
+ controller = Hooked::Controller.new(container.new)
61
54
  assert_equal order, controller.hooks[:foo].map {|h| h.name }
62
55
 
63
- controller = Hooked::Controller.new(:baz)
56
+ controller = Hooked::Controller.new
64
57
  controller.add(container.new)
65
58
  assert_not_equal order, controller.hooks[:foo].map {|h| h.name }
66
59
 
@@ -70,11 +63,18 @@ class ControllerTest < Test::Unit::TestCase
70
63
  end
71
64
 
72
65
  def test_sets_the_container_on_hookables_and_hooks
73
- controller = Hooked::Controller.new(:foo, *@containers[1..2])
66
+ controller = Hooked::Controller.new(*@containers[1..2])
74
67
  assert_equal @containers[1], controller.hooks[:foo][0].container
75
68
  assert_equal @containers[2], controller.hookables[:foo].container
76
69
  end
77
70
 
71
+ def test_containers_are_aware_of_their_controller
72
+ controller = Hooked::Controller.new(*@containers)
73
+ @containers.each do |c|
74
+ assert_equal controller, c.hooked
75
+ end
76
+ end
77
+
78
78
  def test_invokes_hooks_in_their_containers_scope
79
79
  scope = nil
80
80
  container = Class.new do
@@ -83,7 +83,7 @@ class ControllerTest < Test::Unit::TestCase
83
83
  before(:something, :do_something_else) { scope = self }
84
84
  end.new
85
85
 
86
- controller = Hooked::Controller.new(:foo, container)
86
+ controller = Hooked::Controller.new(container)
87
87
  controller.invoke(:something)
88
88
 
89
89
  assert_equal(container, scope)
@@ -96,14 +96,14 @@ class ControllerTest < Test::Unit::TestCase
96
96
  hookable(:something) { scope = self }
97
97
  end.new
98
98
 
99
- controller = Hooked::Controller.new(:foo, container)
99
+ controller = Hooked::Controller.new(container)
100
100
  controller.invoke(:something)
101
101
 
102
102
  assert_equal(container, scope)
103
103
  end
104
104
 
105
105
  def test_invokes_dynamic_hookables_in_their_original_scope
106
- controller = Hooked::Controller.new(:foo)
106
+ controller = Hooked::Controller.new
107
107
 
108
108
  scope = nil
109
109
  controller.invoke(:something) { scope = self }
@@ -111,66 +111,124 @@ class ControllerTest < Test::Unit::TestCase
111
111
  assert_equal(self, scope)
112
112
  end
113
113
 
114
- def test_hookables_and_hooks_can_use_next
115
- pend
114
+ def test_passes_arguments_into_the_context
115
+ input = "asd"
116
+ args = []
116
117
 
117
- called = []
118
118
  container = Class.new do
119
119
  include(Hooked::Container)
120
- hookable(:something) { called << :something }
121
- before(:something, :do_something_more) { called << :do_something_more }
122
- before(:something, :do_something_else) { next; called << :do_something_else }
120
+ before(:something, :do_something_else) {|ctx| args << ctx.args}
121
+ hookable(:something) {|ctx| args << ctx.args }
123
122
  end
123
+
124
+ controller = Hooked::Controller.new(container.new)
125
+ controller.invoke(:something, input)
124
126
 
125
- controller = Hooked::Controller.new(:foo, container.new)
126
- controller.invoke(:something)
127
- assert_equal [:do_something_more, :something], called
127
+ assert_equal [input.object_id, input.object_id], args.map {|a| a.object_id }
128
128
  end
129
129
 
130
- def test_hookables_and_hooks_can_use_return
131
- pend
130
+ def test_returns_the_contexts_result
131
+ input = ["asd", "def"]
132
132
 
133
- called = []
134
- returned_arg = nil
135
133
  container = Class.new do
136
134
  include(Hooked::Container)
137
- hookable(:something) { called << :something }
138
- before(:something, :do_something_more) {|arg| return arg + 1; called << :do_something_more }
139
- before(:something, :do_something_else) {|arg| returned_arg = arg; return; called << :do_something_else }
135
+ hookable(:something) {|ctx| ctx.result = [input[0]] }
136
+ after(:something, :do_something_else) {|ctx| ctx.result << input[1] }
140
137
  end
141
138
 
142
- controller = Hooked::Controller.new(:foo, container.new)
143
- fail("Doesn't reach the code after controller.invoke()")
144
- controller.invoke(:something, 1)
145
- assert_equal [:do_something_more, :asd], called
146
- assert_equal 3, returned_arg
139
+ controller = Hooked::Controller.new(container.new)
140
+ result = controller.invoke(:something)
141
+
142
+ assert_equal(input.map {|i| i.object_id }, result.map {|r| r.object_id })
147
143
  end
148
144
 
149
- def test_hookables_and_hooks_can_use_break
150
- pend
145
+ def test_jumps_to_the_next_hook_or_hookable_when_it_catches_next
146
+ container = Class.new do
147
+ include(Hooked::Container)
148
+ before(:something, :asd, :before => :foo) {|ctx| ctx.result = [] }
149
+ before(:something, :foo) {|ctx| ctx.next; ctx.result << :foo }
150
+ hookable(:something) {|ctx| ctx.result << :something }
151
+ after(:something, :bar) {|ctx| ctx.result << :bar }
152
+ end
151
153
 
154
+ result = Hooked::Controller.new(container.new).invoke(:something)
155
+ assert_equal [:something, :bar], result
156
+ end
157
+
158
+ def test_next_can_jump_out_of_the_current_invocation
152
159
  called = []
160
+
161
+ container1 = Class.new do
162
+ include(Hooked::Container)
163
+ hookable(:something) do |ctx|
164
+ hookable(:something_else)
165
+ called << :something
166
+ end
167
+ after(:something, :bar) {|ctx| called << :bar }
168
+ end
169
+ container2 = Class.new do
170
+ include(Hooked::Container)
171
+ before(:something_else, :foo_else) {|ctx| called << :foo_else }
172
+ hookable(:something_else) {|ctx| ctx.next(2); called << :something_else }
173
+ end
174
+
175
+ Hooked::Controller.new(container1.new, container2.new).invoke(:something)
176
+ assert_equal [:foo_else, :bar], called
177
+ end
178
+
179
+ def test_crashes_if_next_depth_is_bigger_than_invocation_depth
153
180
  container = Class.new do
154
181
  include(Hooked::Container)
155
- hookable(:something) { called << :something }
156
- before(:something, :do_something_more) { called << :do_something_more }
157
- before(:something, :do_something_else) { called << :do_something_else; break }
182
+ hookable(:something) {|ctx| ctx.next(2) }
158
183
  end
159
184
 
160
- controller = Hooked::Controller.new(:foo, container.new)
161
- controller.invoke(:something)
162
- assert_equal [:do_something_more, :do_something_else], called
185
+ assert_throw(:hooked) do
186
+ Hooked::Controller.new(container.new).invoke(:something)
187
+ end
163
188
  end
164
189
 
165
- def test_arguments_and_return_values_are_passed_in_and_out
190
+ def test_returns_from_the_current_invocation_when_it_catches_break
166
191
  container = Class.new do
167
192
  include(Hooked::Container)
168
- hookable(:something) {|arg| arg += 1; arg }
169
- before(:something, :do_something_more) {|arg| arg += 1; [arg] }
170
- after(:something, :do_something_else) {|arg| arg += 1; arg }
193
+ before(:something, :asd, :before => :foo) {|ctx| ctx.result = [] }
194
+ before(:something, :foo) {|ctx| ctx.result << :foo; ctx.break }
195
+ hookable(:something) {|ctx| ctx.result << :something }
196
+ after(:something, :bar) {|ctx| ctx.result << :bar }
197
+ end
198
+
199
+ result = Hooked::Controller.new(container.new).invoke(:something)
200
+ assert_equal [:foo], result
201
+ end
202
+
203
+ def test_break_can_jump_out_of_the_current_invocation
204
+ called = []
205
+
206
+ container1 = Class.new do
207
+ include(Hooked::Container)
208
+ hookable(:something) do |ctx|
209
+ hookable(:something_else)
210
+ called << :something
211
+ end
212
+ after(:something, :bar) {|ctx| called << :bar }
213
+ end
214
+ container2 = Class.new do
215
+ include(Hooked::Container)
216
+ before(:something_else, :foo_else) {|ctx| called << :foo_else }
217
+ hookable(:something_else) {|ctx| ctx.break(2); called << :something_else }
218
+ end
219
+
220
+ Hooked::Controller.new(container1.new, container2.new).invoke(:something)
221
+ assert_equal [:foo_else], called
222
+ end
223
+
224
+ def test_crashes_if_break_depth_is_bigger_than_invocation_depth
225
+ container = Class.new do
226
+ include(Hooked::Container)
227
+ hookable(:something) {|ctx| ctx.break(2) }
228
+ end
229
+
230
+ assert_throw(:hooked) do
231
+ Hooked::Controller.new(container.new).invoke(:something)
171
232
  end
172
-
173
- controller = Hooked::Controller.new(:foo, container.new)
174
- assert_equal 4, controller.invoke(:something, 1)
175
233
  end
176
234
  end
data/test/helper.rb CHANGED
@@ -4,6 +4,7 @@ Bundler.setup(:default, :development)
4
4
 
5
5
  require "test/unit"
6
6
  require "mocha"
7
- require "awesome_print"
7
+
8
+ require "awesome_print" rescue nil
8
9
 
9
10
  require "hooked"
data/test/hook_test.rb CHANGED
@@ -1,6 +1,10 @@
1
- require File.dirname(__FILE__) + "/helper.rb"
1
+ require File.expand_path("../helper", __FILE__)
2
2
 
3
3
  class HookTest < Test::Unit::TestCase
4
+ def context
5
+ Hooked::Context
6
+ end
7
+
4
8
  def test_has_a_name
5
9
  name = :foo
6
10
  hook = Hooked::Hook.new(:before, name) {}
@@ -65,31 +69,22 @@ class HookTest < Test::Unit::TestCase
65
69
  scope = self
66
70
  end
67
71
 
68
- assert_raise(RuntimeError) { hook.call }
72
+ assert_raise(RuntimeError) { hook.call(context) }
69
73
 
70
74
  container = stub("container")
71
75
  hook.container = container
72
- hook.call
76
+ hook.call(context)
73
77
  assert_equal(container, scope)
74
78
  end
75
79
 
76
- def test_passes_arguments_to_the_block
77
- args = [123, "asd"]
78
- passed_args = nil
79
- hook = Hooked::Hook.new(:before, :foo, {}, stub("container")) do |*args|
80
- passed_args = args
81
- end
82
-
83
- hook.call(args)
84
- assert_equal(args, passed_args)
85
- end
86
-
87
- def test_passes_blocks_return_to_the_caller
88
- ret = 123
89
- hook = Hooked::Hook.new(:before, :foo, {}, stub("container")) do
90
- ret
80
+ def test_passes_context_to_the_block
81
+ ctx = context
82
+ ctx2 = nil
83
+ hook = Hooked::Hook.new(:before, :foo, {}, stub("container")) do |c|
84
+ ctx2 = c
91
85
  end
92
86
 
93
- assert_equal(ret, hook.call)
87
+ hook.call(ctx)
88
+ assert_equal(ctx, ctx2)
94
89
  end
95
90
  end
@@ -1,6 +1,10 @@
1
- require File.dirname(__FILE__) + "/helper.rb"
1
+ require File.expand_path("../helper", __FILE__)
2
2
 
3
3
  class HookableTest < Test::Unit::TestCase
4
+ def context
5
+ Hooked::Context
6
+ end
7
+
4
8
  def test_has_a_name
5
9
  name = :foo
6
10
  hookable = Hooked::Hookable.new(name) {}
@@ -35,7 +39,7 @@ class HookableTest < Test::Unit::TestCase
35
39
  scope = self
36
40
  end
37
41
 
38
- hookable.call
42
+ hookable.call(context)
39
43
  assert_equal container, scope
40
44
  end
41
45
 
@@ -45,27 +49,18 @@ class HookableTest < Test::Unit::TestCase
45
49
  scope = self
46
50
  end
47
51
 
48
- hookable.call
52
+ hookable.call(context)
49
53
  assert_equal self, scope
50
54
  end
51
55
 
52
- def test_passes_arguments_to_the_block
53
- args = [123, "asd"]
54
- passed_args = nil
55
- hookable = Hooked::Hookable.new(:foo) do |*args|
56
- passed_args = args
57
- end
58
-
59
- hookable.call(args)
60
- assert_equal(args, passed_args)
61
- end
62
-
63
- def test_passes_block_return_to_the_caller
64
- ret = 123
65
- hookable = Hooked::Hookable.new(:foo) do
66
- ret
56
+ def test_passes_context_to_the_block
57
+ ctx = context
58
+ ctx2 = nil
59
+ hookable = Hooked::Hookable.new(:foo) do |c|
60
+ ctx2 = c
67
61
  end
68
62
 
69
- assert_equal(ret, hookable.call)
63
+ hookable.call(ctx)
64
+ assert_equal(ctx, ctx2)
70
65
  end
71
66
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hooked
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 0
9
7
  - 1
10
- version: 0.0.1
8
+ - 0
9
+ version: 0.1.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Lars Gierth
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-11-25 00:00:00 +01:00
17
+ date: 2010-12-20 00:00:00 +01:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- hash: 3
30
28
  segments:
31
29
  - 0
32
30
  version: "0"
@@ -40,7 +38,6 @@ dependencies:
40
38
  requirements:
41
39
  - - ">="
42
40
  - !ruby/object:Gem::Version
43
- hash: 3
44
41
  segments:
45
42
  - 0
46
43
  version: "0"
@@ -54,16 +51,15 @@ dependencies:
54
51
  requirements:
55
52
  - - ">="
56
53
  - !ruby/object:Gem::Version
57
- hash: 3
58
54
  segments:
59
55
  - 0
60
56
  version: "0"
61
57
  type: :development
62
58
  version_requirements: *id003
63
59
  description: |-
64
- hooked makes AOP a breeze. It lets you define and invoke
65
- code that other gems or parts of your application can hook
66
- onto. Supported hooks are before, after and around.
60
+ Hooked makes AOP a breeze. It lets you define and invoke
61
+ code that gems or other parts of your application can hook
62
+ onto.
67
63
  email:
68
64
  - lars.gierth@gmail.com
69
65
  executables: []
@@ -80,6 +76,7 @@ files:
80
76
  - hooked.gemspec
81
77
  - lib/hooked.rb
82
78
  - lib/hooked/container.rb
79
+ - lib/hooked/context.rb
83
80
  - lib/hooked/controller.rb
84
81
  - lib/hooked/hook.rb
85
82
  - lib/hooked/hookable.rb
@@ -103,7 +100,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
100
  requirements:
104
101
  - - ">="
105
102
  - !ruby/object:Gem::Version
106
- hash: 3
107
103
  segments:
108
104
  - 0
109
105
  version: "0"
@@ -112,7 +108,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
108
  requirements:
113
109
  - - ">="
114
110
  - !ruby/object:Gem::Version
115
- hash: 3
116
111
  segments:
117
112
  - 0
118
113
  version: "0"
@@ -122,6 +117,6 @@ rubyforge_project:
122
117
  rubygems_version: 1.3.7
123
118
  signing_key:
124
119
  specification_version: 3
125
- summary: Ruby library for Aspect Oriented Programming
120
+ summary: Ruby Library For Aspect Oriented Programming
126
121
  test_files: []
127
122