wrap 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +58 -0
  2. data/lib/wrap.rb +24 -16
  3. data/test/wrap_test.rb +182 -5
  4. data/wrap.gemspec +3 -2
  5. metadata +5 -4
data/README ADDED
@@ -0,0 +1,58 @@
1
+ NAME
2
+ wrap
3
+
4
+ SYNOPSIS
5
+ non-sucking :before and :after filers for any ruby class
6
+
7
+ DESCRIPTION
8
+ yes yes, active_support does this. but crapily. with actice_support you'll
9
+ need to do this
10
+
11
+
12
+ class Record
13
+ include ActiveSupport::Callbacks
14
+ define_callbacks :save
15
+
16
+ def save
17
+ run_callbacks :save do
18
+ puts "- save"
19
+ end
20
+ end
21
+ end
22
+
23
+ but hey, if a subclass forgets to call 'super' or doesn't manually run
24
+ 'run_callbacks' the codez are *screwed*. that sux. why not this?
25
+
26
+
27
+ class Record
28
+ include Wrap
29
+
30
+ wrap :save
31
+ end
32
+
33
+
34
+ yes, it's that simple. you can now do
35
+
36
+ class SubRecord < Record
37
+ before :save do
38
+ special_sauce
39
+ end
40
+
41
+ def save
42
+ no_special_sauce
43
+ end
44
+ end
45
+
46
+ did you get that? the :before and :after hooks will be called no matter
47
+ what the subclass does. the method will be wrapped, period. no special
48
+ work required. of course, if the sublcass messes with 'method_added' their
49
+ will be hell to pay. that's the price for simplicity.
50
+
51
+ the callbacks are very close, but not identical to active_supports. you can
52
+ return 'false' to halt the chain, but you can also simply call 'halt!'.
53
+ another neat trick is that :before callbacks will be called with the
54
+ arguments to the wrapped method itself iff possible and :after callbacks
55
+ will be called with the result of the wrapped method, iff possible.
56
+
57
+ the test suite reads pretty damn clean. have a go.
58
+
@@ -5,7 +5,7 @@
5
5
  ##
6
6
  #
7
7
  class << Wrap
8
- Version = '0.4.2' unless defined?(Version)
8
+ Version = '0.4.3' unless defined?(Version)
9
9
 
10
10
  def version
11
11
  Version
@@ -67,11 +67,14 @@
67
67
  end
68
68
 
69
69
  running_callbacks(#{ name.inspect }) do
70
- begin
71
- run_callbacks(:before, #{ name.inspect })
72
- wrapped_#{ name }(*args, &block)
73
- ensure
74
- run_callbacks(:after, #{ name.inspect }) unless $!
70
+ catch(:halt) do
71
+ return false unless run_callbacks(:before, #{ name.inspect }, args)
72
+
73
+ begin
74
+ result = wrapped_#{ name }(*args, &block)
75
+ ensure
76
+ run_callbacks(:after, #{ name.inspect }, [result]) unless $!
77
+ end
75
78
  end
76
79
  end
77
80
  end
@@ -148,10 +151,7 @@
148
151
  end
149
152
 
150
153
  def initialize_callbacks!(name)
151
- callbacks[name] ||= Map[
152
- :before, [],
153
- :after, []
154
- ]
154
+ callbacks[name] ||= Map[ :before, [], :after, [] ]
155
155
  callbacks[name]
156
156
  end
157
157
 
@@ -191,7 +191,7 @@
191
191
  end
192
192
  end
193
193
 
194
- def run_callbacks(which, name)
194
+ def run_callbacks(which, name, argv)
195
195
  which = which.to_s.to_sym
196
196
  name = name.to_s
197
197
  list = []
@@ -201,16 +201,24 @@
201
201
 
202
202
  if ancestor.callbacks.is_a?(Map) and ancestor.callbacks[name].is_a?(Map)
203
203
  callbacks = ancestor.callbacks[name][which]
204
- list.unshift(*callbacks) if callbacks.is_a?(Array)
204
+ accumulate = (which == :before ? :unshift : :push)
205
+ list.send(accumulate, *callbacks) if callbacks.is_a?(Array)
205
206
  end
206
207
  end
207
208
 
208
- #p :which => list
209
209
  list.each do |callback|
210
- cb = callback.respond_to?(:call) ? callback : proc{ send(callback.to_s.to_sym) }
211
- #p :cb => cb
212
- instance_eval(&cb)
210
+ block = callback.respond_to?(:call) ? callback : proc{ send(callback.to_s.to_sym) }
211
+ args = argv.slice(0 .. (block.arity > 0 ? block.arity : -1))
212
+ result = instance_exec(*args, &block)
213
+ return false if result == false
213
214
  end
215
+
216
+ true
217
+ end
218
+
219
+ def halt!(*args)
220
+ value = args.size == 0 ? false : args.shift
221
+ throw(:halt, value)
214
222
  end
215
223
  end
216
224
  end
@@ -1,6 +1,8 @@
1
1
 
2
2
  Testing Wrap do
3
3
 
4
+ ##
5
+ #
4
6
  testing 'that wrap can be included in a class' do
5
7
  assert do
6
8
  Class.new do
@@ -9,7 +11,25 @@ Testing Wrap do
9
11
  end
10
12
  end
11
13
 
12
- testing 'that a method can be wrapped before it is defined' do
14
+ ##
15
+ #
16
+ testing 'that a method can be wrapped ***after*** it is defined' do
17
+ assert do
18
+ wrapped_class do
19
+ def foo() 42 end
20
+
21
+ assert{ new.foo() == 42 }
22
+
23
+ wrap :foo
24
+
25
+ assert{ new.foo() == 42 }
26
+ end
27
+ end
28
+ end
29
+
30
+ ##
31
+ #
32
+ testing 'that a method can be wrapped ***before*** it is defined' do
13
33
  assert do
14
34
  wrapped_class do
15
35
  assert_raises(NoMethodError){ new.foo() }
@@ -21,20 +41,173 @@ Testing Wrap do
21
41
  end
22
42
  end
23
43
 
24
- testing 'that a method can be wrapped after it is defined' do
44
+ ##
45
+ #
46
+ testing 'that wrapping gives :before and :after goodness' do
25
47
  assert do
26
48
  wrapped_class do
27
- def foo() 42 end
49
+ wrap :foo
28
50
 
29
- assert{ new.foo() == 42 }
51
+ define_method(:foo){ accum.push(42) }
52
+
53
+ before(:foo){ accum.push(:before) }
54
+ after(:foo){ accum.push(:after) }
55
+
56
+ assert {
57
+ c = new
58
+ c.foo()
59
+ c.accum == [:before, 42, :after]
60
+ }
61
+ end
62
+ end
63
+ end
30
64
 
65
+ ##
66
+ #
67
+ testing 'that callbacks are halted with "false" iff they return "false"' do
68
+ assert do
69
+ wrapped_class do
31
70
  wrap :foo
32
71
 
33
- assert{ new.foo() == 42 }
72
+ define_method(:foo){ accum.push(42) }
73
+
74
+ before(:foo){ accum.push(:foo) }
75
+ before(:foo){ accum.push(:bar); return false}
76
+ before(:foo){ accum.push(:foobar) }
77
+
78
+ assert {
79
+ c = new
80
+ c.foo()
81
+ c.accum == [:foo, :bar]
82
+ }
83
+ end
84
+ end
85
+ end
86
+
87
+ ##
88
+ #
89
+ testing 'that callbacks can be halted with "halt!"' do
90
+ assert do
91
+ wrapped_class do
92
+ wrap :foo
93
+
94
+ define_method(:foo){ accum.push(42) }
95
+
96
+ before(:foo){ accum.push(:foo) }
97
+ before(:foo){ accum.push(:bar); halt!}
98
+ before(:foo){ accum.push(:foobar) }
99
+
100
+ assert {
101
+ c = new
102
+ c.foo()
103
+ c.accum == [:foo, :bar]
104
+ }
105
+ end
106
+ end
107
+
108
+ assert do
109
+ wrapped_class do
110
+ wrap :foo
111
+
112
+ define_method(:foo){ accum.push(42) }
113
+
114
+ after(:foo){ accum.push(:foo) }
115
+ after(:foo){ accum.push(:bar); halt!}
116
+ after(:foo){ accum.push(:foobar) }
117
+
118
+ assert {
119
+ c = new
120
+ c.foo()
121
+ c.accum == [42, :foo, :bar]
122
+ }
34
123
  end
35
124
  end
36
125
  end
37
126
 
127
+ ##
128
+ #
129
+ testing 'that :before callbacks are passed the number of args they can eat, and no more' do
130
+ c =
131
+ assert do
132
+ wrapped_class do
133
+ wrap :foo
134
+
135
+ define_method(:foo){|*a|}
136
+
137
+ before(:foo){|x| accum.push([x]) }
138
+ before(:foo){|x,y| accum.push([x,y]) }
139
+ before(:foo){|x,y,z| accum.push([x,y,z]) }
140
+ end
141
+ end
142
+
143
+ assert do
144
+ o = c.new
145
+ o.foo(1,2,3)
146
+ assert o.accum === [[1], [1,2], [1,2,3]]
147
+ true
148
+ end
149
+ end
150
+
151
+ ##
152
+ #
153
+ testing 'that :after callbacks are passed result of the method they follow, iff possible' do
154
+ c =
155
+ assert do
156
+ wrapped_class do
157
+ wrap :foo
158
+
159
+ define_method(:foo){ result = [1,2,3] }
160
+
161
+ after(:foo){ accum.push(:nada) }
162
+ after(:foo){|result| accum.push(result) }
163
+ end
164
+ end
165
+
166
+ assert do
167
+ o = c.new
168
+ o.foo()
169
+ assert o.accum === [:nada, [1,2,3]]
170
+ true
171
+ end
172
+ end
173
+
174
+ ##
175
+ #
176
+ testing 'that callbacks are inherited cleverly' do
177
+ c =
178
+ assert do
179
+ wrapped_class do
180
+ wrap :foo
181
+
182
+ define_method(:foo){}
183
+
184
+ before(:foo){ accum.push(:before_superclass) }
185
+ after(:foo){ accum.push(:after_superclass) }
186
+ end
187
+ end
188
+
189
+ assert do
190
+ o = c.new
191
+ o.foo()
192
+ assert o.accum === [:before_superclass, :after_superclass]
193
+ end
194
+
195
+ b =
196
+ assert do
197
+ Class.new(c) do
198
+ before(:foo){ accum.push(:before_subclass) }
199
+ after(:foo){ accum.push(:after_subclass) }
200
+ end
201
+ end
202
+
203
+ assert do
204
+ o = b.new
205
+ o.foo()
206
+ assert o.accum === [:before_superclass, :before_subclass, :after_subclass, :after_superclass]
207
+ end
208
+ end
209
+
210
+
38
211
  private
39
212
  def wrapped_class(&block)
40
213
  tc = self
@@ -54,6 +227,10 @@ private
54
227
  end
55
228
  end
56
229
 
230
+ def accum
231
+ @accum ||= []
232
+ end
233
+
57
234
  module_eval(&block)
58
235
  end
59
236
 
@@ -3,13 +3,14 @@
3
3
 
4
4
  Gem::Specification::new do |spec|
5
5
  spec.name = "wrap"
6
- spec.version = "0.4.2"
6
+ spec.version = "0.4.3"
7
7
  spec.platform = Gem::Platform::RUBY
8
8
  spec.summary = "wrap"
9
9
  spec.description = "description: wrap kicks the ass"
10
10
 
11
11
  spec.files =
12
- ["Rakefile",
12
+ ["README",
13
+ "Rakefile",
13
14
  "lib",
14
15
  "lib/wrap",
15
16
  "lib/wrap.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-27 00:00:00.000000000 Z
12
+ date: 2011-11-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: map
16
- requirement: &70233826961320 !ruby/object:Gem::Requirement
16
+ requirement: &70328097412480 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,13 +21,14 @@ dependencies:
21
21
  version: 4.7.1
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70233826961320
24
+ version_requirements: *70328097412480
25
25
  description: ! 'description: wrap kicks the ass'
26
26
  email: ara.t.howard@gmail.com
27
27
  executables: []
28
28
  extensions: []
29
29
  extra_rdoc_files: []
30
30
  files:
31
+ - README
31
32
  - Rakefile
32
33
  - lib/wrap.rb
33
34
  - test/testing.rb