contextr 0.0.1 → 0.0.2

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.
@@ -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
+