contextr 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,22 +1,48 @@
1
1
  class Proc
2
+
3
+ # Returns the Proc converted to an UnboundMethod within the the given Class
4
+ #
5
+ # class A
6
+ # def a
7
+ # "a"
8
+ # end
9
+ # end
10
+ #
11
+ # um_a = A.instance_method( :a ) # => #<UnboundMethod: A#a>
12
+ # um_a.bind( A.new ).call # => "a"
13
+ #
14
+ # b = lambda do "b" end
15
+ # um_b = b.to_unbound_method( A ) # => #<UnboundMethod: A#_um_from_proc>
16
+ # um_b.bind( A.new ).call # => "b"
17
+ #
2
18
  def to_unbound_method( klass )
3
19
  raise ArgumentError.new( "Only class objects allowed in parameter list"
4
20
  ) unless klass.kind_of?( Class )
5
21
 
6
22
  proc_object = self
7
23
  klass.class_eval do
8
- define_method( :_tmp_method_from_proc, &proc_object )
24
+ define_method( :_um_from_proc, &proc_object )
9
25
  end
10
26
 
11
- unbound_method = klass.instance_method( :_tmp_method_from_proc )
27
+ unbound_method = klass.instance_method( :_um_from_proc )
12
28
 
13
29
  klass.class_eval do
14
- undef_method( :_tmp_method_from_proc )
30
+ undef_method( :_um_from_proc )
15
31
  end
16
32
 
17
33
  unbound_method
18
34
  end
19
35
 
36
+ # joins to blocks into a new one, that forwards on excution the given
37
+ # arguments.
38
+ #
39
+ # a = lambda do print "a" end
40
+ # b = lambda do print "b" end
41
+ #
42
+ # ab = a + b
43
+ #
44
+ # ab.call # => "ab"
45
+ #
20
46
  def +( other_proc )
21
47
  this_proc = self
22
48
  lambda do | *arguments |
@@ -1,3 +1,13 @@
1
+ # This library was created by Christian Neukirchen in the context of
2
+ # EuRuKo 2005 and is licensed under the same terms as Ruby.
3
+ #
4
+ # It provides dynamically scoped variables. It is used within ContextR to
5
+ # store the current, thread-wide activated layers.
6
+ #
7
+ # For more information see the corresponding slides at
8
+ # http://chneukirchen.org/talks/euruko-2005/chneukirchen-euruko2005-contextr.pdf
9
+ #
10
+ # (c) 2005 - Christian Neukirchen - http://chneukirchen.org
1
11
  module Dynamic
2
12
  class << self
3
13
  Thread.main[:DYNAMIC] = Hash.new { |hash, key|
@@ -0,0 +1,80 @@
1
+ # This class was created by Christian Neukirchen in the context of
2
+ # EuRuKo 2005 and is licensed under the same terms as Ruby.
3
+ #
4
+ # It is used within ContextR to provide an interface to manipulate the calling
5
+ # context within a method wrapper.
6
+ #
7
+ # For more information see the corresponding slides at
8
+ # http://chneukirchen.org/talks/euruko-2005/chneukirchen-euruko2005-contextr.pdf
9
+ #
10
+ # (c) 2005 - Christian Neukirchen - http://chneukirchen.org
11
+ #
12
+ # ---
13
+ #
14
+ # It provides access
15
+ # [+arguments+] to read and manipulate method's arguments.
16
+ # [+return_value+] to read and manipulate the method's return value
17
+ #
18
+ class MethodNature < Struct.new(:arguments, :return_value, :break, :block)
19
+
20
+ # stops the execution of the following method wrappers and potentially the
21
+ # core method.
22
+ #
23
+ # class A
24
+ # def a
25
+ # "a"
26
+ # end
27
+ #
28
+ # layer :foo
29
+ #
30
+ # foo.pre :a do | method_nature |
31
+ # method_nature.break! "b"
32
+ # end
33
+ # end
34
+ #
35
+ # A.new.a # => "a"
36
+ # ContextR::with_layers :foo do
37
+ # A.new.a # => "b"
38
+ # end
39
+ #
40
+ # If it is called without parameter, the return value will not be changed.
41
+ #
42
+ # :call-seq:
43
+ # break!
44
+ # break!( return_value )
45
+ #
46
+ def break!( *value )
47
+ self.break = true
48
+ self.return_value = value.first unless value.empty?
49
+ end
50
+
51
+ # calls the next wrapper with an around method. It corresponds to a super call
52
+ # in an inheritance hierarchy.
53
+ #
54
+ # The example attaches to each method in the class A an around wrapper which
55
+ # logs access.
56
+ #
57
+ # class A
58
+ # def a
59
+ # "a"
60
+ # end
61
+ #
62
+ # layer :log
63
+ #
64
+ # instance_methods.each do | method |
65
+ #
66
+ # log.around method.to_sym do | method_nature |
67
+ # logger.info "before #{self.class}##{method}"
68
+ #
69
+ # method_nature.call_next
70
+ #
71
+ # logger.info "after #{self.class}##{method}"
72
+ # end
73
+ # end
74
+ #
75
+ # end
76
+ #
77
+ def call_next
78
+ block.call( *arguments )
79
+ end
80
+ end
@@ -76,42 +76,3 @@ context 'Each layer in a class' do
76
76
  end
77
77
  end
78
78
 
79
- context "An instance of a contextified class" do
80
- setup do
81
- @instance = ContextRApiFoo.new
82
- end
83
-
84
- specify "should run a simple method " +
85
- "*normally* when all layers are deactivated" do
86
- @instance.non_contextified_method.should == "non_contextified_method"
87
- end
88
-
89
- specify "should run a simple method " +
90
- "*normally* when any layer is activated" do
91
- ContextR.with_layers( :bar ) do
92
- @instance.non_contextified_method.should == "non_contextified_method"
93
- end
94
- end
95
-
96
- specify "should run a contextified method " +
97
- "*normally* when all layers are deactivated" do
98
- @instance.foo.should == "foo"
99
- end
100
-
101
- specify "should run a contextified method " +
102
- "*normally* when any layer is activated" do
103
- ContextR.with_layers( :baz ) do
104
- @instance.foo.should == "foo"
105
- end
106
- end
107
-
108
- specify "should run a contextified method with " +
109
- "additional behaviour when a specific layer is activated" do
110
- ContextR.with_layers( :bar ) do
111
- @instance.foo.should == "foo"
112
- end
113
- @instance.instance_variable_get( :@pre_visited ).should == true
114
- @instance.instance_variable_get( :@post_visited ).should == true
115
- @instance.instance_variable_get( :@around_visited ).should == true
116
- end
117
- end
@@ -0,0 +1,294 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class SimpleWrapperClass
4
+ def non_contextified_method
5
+ "non_contextified_method"
6
+ end
7
+ def pre_wrapped_method
8
+ "pre_wrapped_method"
9
+ end
10
+ def post_wrapped_method
11
+ "post_wrapped_method"
12
+ end
13
+ def around_wrapped_method
14
+ "around_wrapped_method"
15
+ end
16
+
17
+ layer :simple_wrappers, :dummy
18
+
19
+ simple_wrappers.pre :pre_wrapped_method do
20
+ @pre_wrapped_method_called = true
21
+ end
22
+ simple_wrappers.post :post_wrapped_method do
23
+ @post_wrapped_method_called = true
24
+ end
25
+ simple_wrappers.around :around_wrapped_method do | n |
26
+ @around_wrapped_method_called = true
27
+ n.call_next
28
+ end
29
+ end
30
+ context "An instance of a contextified class" do
31
+ setup do
32
+ @instance = SimpleWrapperClass.new
33
+ end
34
+
35
+ specify "should run a simple method " +
36
+ "*normally* when all layers are deactivated" do
37
+ @instance.non_contextified_method.should == "non_contextified_method"
38
+ end
39
+
40
+ specify "should run a simple method " +
41
+ "*normally* when any layer is activated" do
42
+ ContextR.with_layers( :simple_wrappers ) do
43
+ @instance.non_contextified_method.should == "non_contextified_method"
44
+ end
45
+ end
46
+
47
+ %w{pre post around}.each do | qualifier |
48
+ specify "should run a #{qualifier}-ed method " +
49
+ "*normally* when all layers are deactivated" do
50
+ @instance.send( "#{qualifier}_wrapped_method" ).should ==
51
+ "#{qualifier}_wrapped_method"
52
+ @instance.instance_variables.should_not_include(
53
+ "@#{qualifier}_wrapped_method_called" )
54
+ end
55
+
56
+ specify "should run a #{qualifier}-ed method " +
57
+ "*normally* when any layer is activated" do
58
+ ContextR.with_layers( :dummy ) do
59
+ @instance.send( "#{qualifier}_wrapped_method" ).should ==
60
+ "#{qualifier}_wrapped_method"
61
+ @instance.instance_variables.should_not_include(
62
+ "@#{qualifier}_wrapped_method_called" )
63
+ end
64
+ end
65
+
66
+ specify "should run a #{qualifier}-ed method with " +
67
+ "additional behaviour when a specific layer is activated" do
68
+ ContextR.with_layers( :simple_wrappers ) do
69
+ @instance.send( "#{qualifier}_wrapped_method" ).should ==
70
+ "#{qualifier}_wrapped_method"
71
+ @instance.instance_variables.should_include(
72
+ "@#{qualifier}_wrapped_method_called" )
73
+ end
74
+ end
75
+
76
+ specify "should run a #{qualifier}-ed method without additional " +
77
+ "behaviour when a specific layer is activated and afterwards " +
78
+ "deactivated" do
79
+ ContextR.with_layers( :simple_wrappers ) do
80
+ ContextR.without_layers( :simple_wrappers ) do
81
+ @instance.send( "#{qualifier}_wrapped_method" ).should ==
82
+ "#{qualifier}_wrapped_method"
83
+ @instance.instance_variables.should_not_include(
84
+ "@#{qualifier}_wrapped_method_called" )
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ class NestedLayerActivationClass
92
+ attr_accessor :execution
93
+ def initialize
94
+ @execution = []
95
+ end
96
+
97
+ def preed_method
98
+ @execution << "core"
99
+ "preed_method"
100
+ end
101
+
102
+ def posted_method
103
+ @execution << "core"
104
+ "posted_method"
105
+ end
106
+
107
+ def arounded_method
108
+ @execution << "core"
109
+ "arounded_method"
110
+ end
111
+
112
+ layer :outer_layer, :inner_layer
113
+
114
+ inner_layer.pre :preed_method do
115
+ @execution << "inner_layer"
116
+ end
117
+
118
+ outer_layer.pre :preed_method do
119
+ @execution << "outer_layer"
120
+ end
121
+
122
+ inner_layer.post :posted_method do
123
+ @execution << "inner_layer"
124
+ end
125
+
126
+ outer_layer.post :posted_method do
127
+ @execution << "outer_layer"
128
+ end
129
+
130
+ inner_layer.around :arounded_method do | n |
131
+ @execution << "inner_layer_pre"
132
+ n.call_next
133
+ @execution << "inner_layer_post"
134
+ end
135
+
136
+ outer_layer.around :arounded_method do | n |
137
+ @execution << "outer_layer_pre"
138
+ n.call_next
139
+ @execution << "outer_layer_post"
140
+ end
141
+
142
+ def contextualized_method
143
+ @execution << "core"
144
+ "contextualized_method"
145
+ end
146
+
147
+ layer :break_in_pre, :break_in_post, :break_in_around
148
+ layer :other_layer
149
+
150
+ break_in_pre.pre :contextualized_method do | n |
151
+ n.return_value = "contextualized_method"
152
+ @execution << "breaking_pre"
153
+ n.break!
154
+ end
155
+ break_in_post.post :contextualized_method do | n |
156
+ @execution << "breaking_post"
157
+ n.break!
158
+ end
159
+ break_in_around.around :contextualized_method do | n |
160
+ @execution << "breaking_around"
161
+ n.return_value = "contextualized_method"
162
+ n.break!
163
+ n.call_next
164
+ end
165
+
166
+ other_layer.pre :contextualized_method do | n |
167
+ @execution << "other_pre"
168
+ end
169
+ other_layer.post :contextualized_method do | n |
170
+ @execution << "other_post"
171
+ end
172
+ other_layer.around :contextualized_method do | n |
173
+ @execution << "other_around"
174
+ n.call_next
175
+ end
176
+
177
+ layer :multiple_pres, :multiple_posts, :multiple_arounds
178
+ multiple_pres.pre :contextualized_method do
179
+ @execution << "first_pre"
180
+ end
181
+ multiple_pres.pre :contextualized_method do
182
+ @execution << "second_pre"
183
+ end
184
+
185
+ multiple_posts.post :contextualized_method do
186
+ @execution << "first_post"
187
+ end
188
+ multiple_posts.post :contextualized_method do
189
+ @execution << "second_post"
190
+ end
191
+
192
+ multiple_arounds.around :contextualized_method do | n |
193
+ @execution << "first_around_pre"
194
+ n.call_next
195
+ @execution << "first_around_post"
196
+ end
197
+ multiple_arounds.around :contextualized_method do | n |
198
+ @execution << "second_around_pre"
199
+ n.call_next
200
+ @execution << "second_around_post"
201
+ end
202
+ end
203
+
204
+ pre_spec = lambda do | instance |
205
+ instance.execution.shift.should == "outer_layer"
206
+ instance.execution.shift.should == "inner_layer"
207
+ instance.execution.shift.should == "core"
208
+ end
209
+ post_spec = lambda do | instance |
210
+ instance.execution.shift.should == "core"
211
+ instance.execution.shift.should == "inner_layer"
212
+ instance.execution.shift.should == "outer_layer"
213
+ end
214
+ around_spec = lambda do | instance |
215
+ instance.execution.shift.should == "outer_layer_pre"
216
+ instance.execution.shift.should == "inner_layer_pre"
217
+ instance.execution.shift.should == "core"
218
+ instance.execution.shift.should == "inner_layer_post"
219
+ instance.execution.shift.should == "outer_layer_post"
220
+ end
221
+
222
+ pre_break_spec = lambda do | instance |
223
+ instance.execution.shift.should == "breaking_pre"
224
+ end
225
+ post_break_spec = lambda do | instance |
226
+ instance.execution.shift.should == "other_pre"
227
+ instance.execution.shift.should == "other_around"
228
+ instance.execution.shift.should == "core"
229
+ instance.execution.shift.should == "other_post"
230
+ instance.execution.shift.should == "breaking_post"
231
+ end
232
+ around_break_spec = lambda do | instance |
233
+ instance.execution.shift.should == "other_pre"
234
+ instance.execution.shift.should == "breaking_around"
235
+ end
236
+
237
+ pre_multiple_spec = lambda do | instance |
238
+ instance.execution.shift.should == "first_pre"
239
+ instance.execution.shift.should == "second_pre"
240
+ instance.execution.shift.should == "core"
241
+ end
242
+ post_multiple_spec = lambda do | instance |
243
+ instance.execution.shift.should == "core"
244
+ instance.execution.shift.should == "second_post"
245
+ instance.execution.shift.should == "first_post"
246
+ end
247
+ around_multiple_spec = lambda do | instance |
248
+ instance.execution.shift.should == "first_around_pre"
249
+ instance.execution.shift.should == "second_around_pre"
250
+ instance.execution.shift.should == "core"
251
+ instance.execution.shift.should == "second_around_post"
252
+ instance.execution.shift.should == "first_around_post"
253
+ end
254
+
255
+ %w{pre post around}.each do | qualifier |
256
+ context "#{qualifier.capitalize} wrappers within a method" do
257
+ setup do
258
+ @instance = NestedLayerActivationClass.new
259
+ end
260
+ specify "should run in the sequence of nesting, when using nested " +
261
+ "activation" do
262
+ ContextR::with_layers :outer_layer do
263
+ ContextR::with_layers :inner_layer do
264
+ @instance.send( "#{qualifier}ed_method" ).should ==
265
+ "#{qualifier}ed_method"
266
+ end
267
+ end
268
+ eval("#{qualifier}_spec").call( @instance )
269
+ end
270
+ specify "should run in the sequence of nesting, when using simultaneous " +
271
+ "activation" do
272
+ ContextR::with_layers :outer_layer, :inner_layer do
273
+ @instance.send( "#{qualifier}ed_method" ).should ==
274
+ "#{qualifier}ed_method"
275
+ end
276
+ eval("#{qualifier}_spec").call( @instance )
277
+ end
278
+
279
+ specify "should run in the sequence of definition within the same layer" do
280
+ ContextR::with_layers "multiple_#{qualifier}s".to_sym do
281
+ @instance.contextualized_method.should == "contextualized_method"
282
+ end
283
+ eval("#{qualifier}_multiple_spec").call( @instance )
284
+ end
285
+
286
+ specify "should be able to stop the execution with `break!`" do
287
+ ContextR::with_layers "break_in_#{qualifier}".to_sym, :other_layer do
288
+ @instance.contextualized_method.should == "contextualized_method"
289
+ end
290
+ eval("#{qualifier}_break_spec").call( @instance )
291
+ end
292
+ end
293
+ end
294
+