contextr 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/History.txt +5 -18
  2. data/License.txt +20 -0
  3. data/Manifest.txt +15 -19
  4. data/README.txt +2 -49
  5. data/Rakefile +55 -88
  6. data/examples/general.rb +152 -0
  7. data/examples/ordering.rb +29 -0
  8. data/lib/contextr.rb +15 -15
  9. data/lib/contextr/class_methods.rb +90 -0
  10. data/lib/contextr/core_ext.rb +2 -0
  11. data/lib/contextr/core_ext/module.rb +18 -0
  12. data/lib/contextr/core_ext/object.rb +9 -0
  13. data/lib/contextr/event_machine.rb +71 -0
  14. data/lib/contextr/layer.rb +57 -381
  15. data/lib/contextr/modules/mutex_code.rb +22 -0
  16. data/lib/contextr/modules/unique_id.rb +13 -0
  17. data/lib/contextr/public_api.rb +58 -0
  18. data/lib/contextr/version.rb +2 -2
  19. data/lib/ext/active_support_subset.rb +85 -0
  20. data/spec/contextr_spec.rb +11 -0
  21. data/spec/spec.opts +1 -0
  22. data/spec/spec_helper.rb +1 -1
  23. data/test/test_contextr.rb +11 -0
  24. data/website/index.html +23 -101
  25. data/website/index.txt +27 -95
  26. data/website/stylesheets/screen.css +9 -0
  27. data/website/template.rhtml +3 -8
  28. metadata +21 -26
  29. data/COPYING.txt +0 -340
  30. data/LICENSE.txt +0 -57
  31. data/examples/education.rb +0 -71
  32. data/examples/fibonacci.rb +0 -124
  33. data/examples/with_current_context.rb +0 -29
  34. data/lib/contextr/contextr.rb +0 -160
  35. data/lib/core_ext/class.rb +0 -29
  36. data/lib/core_ext/module.rb +0 -62
  37. data/lib/core_ext/proc.rb +0 -53
  38. data/lib/ext/method_nature.rb +0 -80
  39. data/rake/group_spec_task.rb +0 -7
  40. data/rake/specific_group_spec_task.rb +0 -7
  41. data/spec/contextr/contextr_api_spec.rb +0 -126
  42. data/spec/contextr/contextr_class_side_spec.rb +0 -77
  43. data/spec/contextr/contextr_functional_spec.rb +0 -293
  44. data/spec/core_ext/module_spec.rb +0 -101
  45. data/spec/core_ext/proc_spec.rb +0 -61
  46. data/tasks/annotations.rb +0 -107
  47. data/test/contextr/test_contextr.rb +0 -7
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + "/../lib/contextr.rb"
2
+
3
+ class AnyClass
4
+ def test
5
+ puts "base_method"
6
+ end
7
+
8
+ module InnerMethods
9
+ def test
10
+ puts "inner_pre"
11
+ yield(:next)
12
+ puts "inner_post"
13
+ end
14
+ end
15
+ include InnerMethods => :test
16
+
17
+ module OuterMethods
18
+ def test
19
+ puts "outer_pre"
20
+ yield(:next)
21
+ puts "outer_post"
22
+ end
23
+ end
24
+ include OuterMethods => :test
25
+ end
26
+
27
+ ContextR::with_layer :test do
28
+ AnyClass.new.test
29
+ end
@@ -1,19 +1,19 @@
1
- #--
2
- # TODO: get rid of this workaround to avoid double loading on `rake test`
3
- #++
4
- unless Object.const_defined? "ContextR"
5
- if RUBY_VERSION == "1.9.0"
6
- require File.dirname(__FILE__) + '/activesupport/lib/active_support'
7
- else
8
- require 'rubygems'
9
- require 'active_support'
10
- end
1
+ module ContextR
2
+ end
11
3
 
12
- Dir[File.join(File.dirname(__FILE__), 'ext/**/*.rb')].sort.each { |lib| require lib }
13
- Dir[File.join(File.dirname(__FILE__), 'core_ext/**/*.rb')].sort.each { |lib| require lib }
14
- Dir[File.join(File.dirname(__FILE__), 'contextr/**/*.rb')].sort.each { |lib| require lib }
4
+ # vendor code by rails and Cristian Neukirchen and _why
5
+ %w{active_support_subset dynamic}.each { |file|
6
+ require File.dirname(__FILE__) + "/ext/#{file}" }
7
+
8
+ # modules that encapsulate certain simple aspects
9
+ %w{mutex_code unique_id}.each { |file|
10
+ require File.dirname(__FILE__) + "/contextr/modules/#{file}" }
11
+
12
+ # the basic library code
13
+ %w{public_api class_methods layer
14
+ event_machine core_ext version}.each { | file |
15
+ require File.dirname(__FILE__) + "/contextr/#{file}" }
15
16
 
16
- end
17
17
  unless Dynamic.variables.include?( :layers )
18
- Dynamic.variable( :layers => [ ContextR::layer_by_symbol( :default ) ] )
18
+ Dynamic.variable( :layers => [] )
19
19
  end
@@ -0,0 +1,90 @@
1
+ module ContextR
2
+ module ClassMethods
3
+ def const_missing(const_name)
4
+ if const_name.to_s =~ /.*Layer$/
5
+ self.const_set(const_name, Class.new(ContextR::Layer))
6
+ else
7
+ super
8
+ end
9
+ end
10
+
11
+ def stored_core_methods
12
+ @stored_core_methods ||= Hash.new do | hash, key |
13
+ hash[key] = Hash.new
14
+ end
15
+ end
16
+
17
+ def symbol_by_layer(lay)
18
+ lay.to_s.gsub( /^ContextR::(.*)Layer$/, '\1' ).underscore
19
+ end
20
+
21
+ def layer_by_symbol(sym)
22
+ "ContextR::#{sym.to_s.camelize}Layer".constantize
23
+ end
24
+
25
+ def call_methods_stack(stack, receiver, method_name, arguments, block)
26
+ if stack.size == 1
27
+ stack.pop.call(*arguments, &block)
28
+ else
29
+ stack.pop.send(method_name, *arguments) do | action, *rest_args |
30
+ case action
31
+ when :receiver
32
+ receiver
33
+ when :block
34
+ block.call(*rest_args)
35
+ when :next
36
+ call_methods_stack(stack, receiver, method_name, rest_args, block)
37
+ else
38
+ raise ArgumentError.new("Use only :receiver, :block or :next " +
39
+ "as first argument.")
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ def on_core_method_called(receiver, contextified_class,
46
+ method_name, arguments, block)
47
+ proxies = []
48
+ layers.each do |layer|
49
+ proxies += layer.context_proxies(contextified_class, method_name)
50
+ end.compact
51
+
52
+ proxies << core_proxy(receiver, contextified_class, method_name)
53
+ call_methods_stack(proxies.reverse, receiver,
54
+ method_name, arguments, block)
55
+ end
56
+
57
+ def core_proxy(receiver, contextified_class, method_name)
58
+ ContextR::stored_core_methods[contextified_class][
59
+ method_name][:code].bind(receiver)
60
+ end
61
+
62
+ def observe_core_method(klass, method_name, version)
63
+ only_once do
64
+ klass.class_eval(%Q{
65
+ def #{method_name}(*arguments, &block)
66
+ ContextR::on_core_method_called(
67
+ self,
68
+ ObjectSpace._id2ref(#{klass.object_id}),
69
+ :#{method_name},
70
+ arguments, block)
71
+ end
72
+ }, __FILE__, __LINE__) if save_core_method(klass, method_name, version)
73
+ end
74
+ end
75
+
76
+ def save_core_method(klass, method_name, version)
77
+ if !meta_method?(method_name) and
78
+ (!stored_core_methods[klass].include?(method_name) or
79
+ stored_core_methods[klass][method_name][:version] < version)
80
+ stored_core_methods[klass][method_name] =
81
+ { :version => version, :code => klass.instance_method(method_name) }
82
+ end
83
+ end
84
+
85
+ def meta_method?(method_name)
86
+ method_name.to_s =~ /method_added(_with(out)?_contextr_listener)?/
87
+ end
88
+ end
89
+ self.extend(ClassMethods)
90
+ end
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/core_ext/object'
2
+ require File.dirname(__FILE__) + '/core_ext/module'
@@ -0,0 +1,18 @@
1
+ class Module
2
+ alias_method :include_without_layers, :include
3
+ def include_with_layers(associations)
4
+ if associations.delete(:class_side)
5
+ klass = class << self; self; end
6
+ else
7
+ klass = self
8
+ end
9
+ associations.each do | modul, layer |
10
+ ContextR::layer_by_symbol(layer).add_method_collection(klass, modul)
11
+ end
12
+ end
13
+
14
+ def include(*args)
15
+ args.first.is_a?(Module) ? include_without_layers(*args) :
16
+ include_with_layers(*args)
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ class Object
2
+ def behavioural_class
3
+ if self.kind_of?(Module)
4
+ class << self; self; end
5
+ else
6
+ self.class
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,71 @@
1
+ module ContextR
2
+ class EventMachine
3
+ module ClassMethods
4
+ include UniqueId
5
+
6
+ def listeners
7
+ @listeners ||= { :method_added => {} }
8
+ end
9
+
10
+ def register(listener, callback, options)
11
+ observed = check_options_hash(options)
12
+ register_observers_on_demand(observed)
13
+ self.listeners[observed[:event]][observed[:module]][listener] = callback
14
+ end
15
+
16
+ def unregister(listener, *cumulated_options)
17
+ observed = check_options_hash(cumulated_options.last)
18
+ self.listeners[observed[:event]][observed[:module]].delete(listener)
19
+ end
20
+
21
+ def on_method_added(modul, name)
22
+ version = self.new_unique_id
23
+ self.listeners[:method_added][modul].each do | listener, method_name |
24
+ listener.send( method_name, modul, name, version )
25
+ end
26
+ end
27
+
28
+ def check_options_hash(options)
29
+ observed = {}
30
+ observed[:event] = options[:on_event]
31
+ observed[:module] = options[:in_class] || options[:in_module]
32
+ [:event, :module].each do |key|
33
+ unless observed[key]
34
+ raise ArgumentError.new("Missing Argument in options Hash")
35
+ end
36
+ end
37
+ unless self.listeners.keys.include?(observed[:event])
38
+ raise ArgumentError.new("Unknown event `#{observed[:event]}`. " +
39
+ "Please use one of these: #{self.listeners.keys.join(', ')}")
40
+ end
41
+ observed
42
+ end
43
+
44
+ def register_observers_on_demand(observed)
45
+ unless self.listeners[observed[:event]].include?(observed[:module])
46
+ self.listeners[observed[:event]][observed[:module]] = {}
47
+ case observed[:event]
48
+ when :method_added
49
+ observe_method_added(observed[:module])
50
+ end
51
+ end
52
+ end
53
+
54
+ def observe_method_added(modul)
55
+ modul.class_eval(%Q{
56
+ def self.method_added_with_contextr_listener(name)
57
+ ContextR::EventMachine::on_method_added(self, name)
58
+ method_added_without_contextr_listener(name)
59
+ end
60
+ unless self.methods.include? "method_added"
61
+ def self.method_added(name); end
62
+ end
63
+ class << self
64
+ alias_method_chain(:method_added, :contextr_listener)
65
+ end
66
+ }, __FILE__, __LINE__)
67
+ end
68
+ end
69
+ self.extend(ClassMethods)
70
+ end
71
+ end
@@ -1,410 +1,86 @@
1
1
  module ContextR
2
- # This is the public interface of a Layer within a class definition. Use it
3
- # to add context-dependent behaviour. It is available after calling
4
- # +layer <em>layer_name</em>+ within a class body via
5
- # +<em>layer_name</em>+. Each wrapper block should expect an instance of
6
- # MethodNature to manipulate arguments or return values.
7
- #
8
- # class Foo
9
- # layer :any
10
- #
11
- # def bar
12
- # "bar"
13
- # end
14
- #
15
- # any.pre :bar do | n |
16
- # logger.info "Foo#bar called"
17
- # end
18
- # end
19
- class LayerInClass
20
- attr_accessor :contextualized_class, :layer # :nodoc:
21
-
22
- def initialize( contextualized_class, layer ) # :nodoc:
23
- self.contextualized_class = contextualized_class
24
- self.layer = layer
25
- end
26
-
27
- # Adds a pre-wrapper to a single method.
28
- #
29
- # :call-seq:
30
- # pre( method_name ) { | method_nature | ... }
31
- #
32
- def pre( method_name, &block )
33
- layer.methods_of( self.contextualized_class )[method_name].pres <<
34
- block.to_unbound_method( self.contextualized_class )
35
- nil
36
- end
37
-
38
- # Adds a post-wrapper to a single method
39
- #
40
- # :call-seq:
41
- # post( method_name ) { | method_nature | ... }
42
- #
43
- def post( method_name, &block )
44
- layer.methods_of( self.contextualized_class )[method_name].posts <<
45
- block.to_unbound_method( self.contextualized_class )
46
- nil
47
- end
48
-
49
- # Adds an around-wrapper to a single method
50
- #
51
- # :call-seq:
52
- # around( method_name ) { | method_nature | ... }
53
- #
54
- def around( method_name, &block )
55
- layer.methods_of( self.contextualized_class )[method_name].arounds <<
56
- block.to_unbound_method( self.contextualized_class )
57
- nil
58
- end
59
-
60
- alias :wrap :around
61
- end
62
-
63
- class Layer # :nodoc:
64
- # its role as base instance of all layers
65
- class << self
66
- attr_accessor_with_default_setter :base_layers, :combined_layers do
67
- Hash.new
2
+ class Layer
3
+ module ClassMethods
4
+ def definitions
5
+ @definitions ||= {}
68
6
  end
69
-
70
- def core_methods
71
- @core_methods ||= Hash.new do | hash, extended_class |
72
- add_redefine_callback( extended_class )
73
- hash[extended_class] = Hash.new do | class_hash, method_name |
74
- um = extended_class.instance_method( method_name )
75
- replace_core_method( extended_class, method_name )
76
- class_hash[method_name] = um
77
- end
78
- end
7
+ def proxies
8
+ @proxies ||= {}
79
9
  end
80
10
 
81
- def inherited( new_base_layer )
82
- unless new_base_layer.name.nil? or new_base_layer.name.empty?
83
- base_layers[ContextR::symbolize( new_base_layer )] = new_base_layer
11
+ def add_method_collection(contextified_class, methods_module)
12
+ definitions[contextified_class] ||= []
13
+ definitions[contextified_class] |= [methods_module]
14
+ (methods_module.instance_methods &
15
+ contextified_class.instance_methods).each do | method_name |
16
+ replace_core_method(contextified_class, method_name, 0)
84
17
  end
18
+ register_callbacks(contextified_class, methods_module)
85
19
  end
86
20
 
87
- def compose( layers )
88
- # TODO: Add better caching
89
- combined_layers[ layers ] ||=
90
- layers.reverse.inject( nil ) do | akku, layer |
91
- layer + akku
92
- end
93
- end
94
-
95
- protected
96
- def replace_core_method( extended_class, method_name )
97
- num_of_args = extended_class.instance_method( method_name ).arity
98
- arg_signature = case num_of_args <=> 0
99
- when 0
100
- ""
101
- when 1
102
- "%s" % Array.new( num_of_args ) { |i| "arg%d" % i }.join( ", " )
103
- else
104
- "*arguments"
105
- end
106
- arg_call = arg_signature.empty? ? "" : ", " + arg_signature
107
-
108
- extended_class.class_eval( %Q{
109
- remove_method :#{method_name}
110
- def #{method_name} #{arg_signature}
111
- ContextR::current_layer.extended( self ).send(
112
- :#{method_name}#{arg_call} )
113
- end
114
- }, __FILE__, __LINE__ )
115
- end
116
-
117
- def add_redefine_callback( extended_class )
118
- (class << extended_class; self; end).instance_eval do
119
- define_method( :method_added ) do | method_name |
120
- if ContextR::Layer.core_methods[extended_class].
121
- include?( method_name )
122
- warn( caller.first + " : ContextR - Redefining already wrapped methods is not supported yet. Your changes _may_ have no effect." )
123
- end
124
- end
125
- end
126
- end
127
- end
128
- end
129
-
130
- class Layer # :nodoc:
131
- # its role as base class for all other layers
132
- class << self
133
- attr_accessor_with_default_setter :extended_classes do
134
- Hash.new do | classes, extended_class |
135
- classes[extended_class] = Hash.new do | hash, key |
136
- hash[key.to_sym] = ContextualizedMethod.new(
137
- ContextR::Layer.core_methods[ extended_class ][ key.to_sym ] )
138
- end
139
- end
140
- end
141
- attr_accessor :extended_objects
142
-
143
- def methods_of( extended_class )
144
- self.extended_classes[extended_class]
145
- end
146
-
147
- def extended( object )
148
- self.extended_objects ||= Hash.new do | cache, object |
149
- object_class = if object.kind_of? Class
150
- (class << object; self; end)
151
- else
152
- object.class
21
+ def methods_modules_containing_method(contextified_class, method_name)
22
+ if definitions.include?(contextified_class)
23
+ definitions[contextified_class].select do | methods_module |
24
+ methods_module.instance_methods.include?(method_name.to_s)
153
25
  end
154
- cache[ object ] =
155
- ExtendedObject.new( object, self.methods_of( object_class ) )
156
- end
157
- self.extended_objects[object]
158
- end
159
-
160
- def + other_layer
161
- if other_layer.nil?
162
- self
163
26
  else
164
- combined_layer = Class.new( Layer )
165
- combined_layer.extended_classes = self.merge_extended_classes_with(
166
- other_layer.extended_classes )
167
- combined_layer
27
+ []
168
28
  end
169
29
  end
170
30
 
171
- protected
172
-
173
- def merge_extended_classes_with( other_ec )
174
- extended_classes.merge( other_ec ) do | extended_c, my_ms, other_ms |
175
- my_ms.merge( other_ms ) do | method_name, my_cm, other_cm |
176
- my_cm + other_cm
177
- end
178
- end
31
+ def context_proxies(contextified_class, method_name)
32
+ methods_modules_containing_method(contextified_class, method_name).
33
+ collect do | methods_module |
34
+ context_proxy_for_module(methods_module)
35
+ end.reverse
179
36
  end
180
- end
181
- end
182
-
183
- class ExtendedObject # :nodoc:
184
- attr_accessor :proxied_object
185
- attr_accessor :extended_methods
186
- attr_accessor :behaviours
187
-
188
- def initialize( proxied_object, extended_methods )
189
- self.proxied_object = proxied_object
190
- self.extended_methods = extended_methods
191
- self.behaviours = {}
192
- end
193
37
 
194
- def send( method_name, *arguments )
195
- ( self.behaviours[method_name] ||=
196
- self.extended_methods[method_name].behaviour( self.proxied_object )
197
- ).call( *arguments )
198
- end
199
- end
200
-
201
- class ContextualizedMethod # :nodoc:
202
- attr_accessor :core
203
- attr_accessor :behaviour_cache
204
-
205
- attr_accessor_with_default_setter :pres, :posts, :arounds do
206
- Array.new
207
- end
208
-
209
- def initialize( unbound_core_method )
210
- self.core = unbound_core_method
211
- self.behaviour_cache = {}
212
- end
213
-
214
- def + other_cm
215
- new_cm = ContextualizedMethod.new( self.core )
216
- new_cm.pres = self.pres + other_cm.pres
217
- new_cm.posts = self.posts + other_cm.posts
218
- new_cm.arounds = self.arounds + other_cm.arounds
219
- new_cm
220
- end
221
-
222
- def behaviour( instance )
223
- self.behaviour_cache[instance] ||=
224
- self.send( self.behaviour_name, instance )
225
- end
226
-
227
- def behaviour_name
228
- wrappers = []
229
- wrappers << "pres" unless self.pres.empty?
230
- wrappers << "arounds" unless self.arounds.empty?
231
- wrappers << "posts" unless self.posts.empty?
232
-
233
- "behaviour_" + ( wrappers.empty? ? "without_wrappers" :
234
- "with_" + wrappers.join( "_and_" ) )
235
- end
236
-
237
- def behaviour_without_wrappers( instance )
238
- self.core.bind( instance )
239
- end
240
-
241
- def behaviour_with_pres( instance )
242
- combined_pres = self.combine_pres( instance )
243
- bound_core = self.bind_core( instance )
244
-
245
- lambda do | *arguments |
246
- nature = MethodNature.new( arguments, nil, false )
247
-
248
- combined_pres.call( nature )
249
- unless nature.break
250
- bound_core.call( *nature.arguments )
251
- else
252
- nature.return_value
38
+ def context_proxy_for_module(methods_module)
39
+ proxies[methods_module] ||= begin
40
+ c = Class.new
41
+ c.class_eval(%Q{
42
+ include ObjectSpace._id2ref(#{methods_module.object_id})
43
+ }, __FILE__, __LINE__)
44
+ c.new
253
45
  end
254
46
  end
255
- end
256
-
257
- def behaviour_with_posts( instance )
258
- bound_core = self.bind_core( instance )
259
- combined_posts = self.combine_posts( instance )
260
-
261
- lambda do | *arguments |
262
- nature = MethodNature.new( arguments, nil, false )
263
-
264
- nature.return_value = bound_core.call( *arguments )
265
- combined_posts.call( nature )
266
-
267
- nature.return_value
268
- end
269
- end
270
-
271
- def behaviour_with_pres_and_posts( instance )
272
- combined_pres = self.combine_pres( instance )
273
- bound_core = self.bind_core( instance )
274
- combined_posts = self.combine_posts( instance )
275
-
276
- lambda do | *arguments |
277
- nature = MethodNature.new( arguments, nil, false )
278
47
 
279
- combined_pres.call( nature )
280
- unless nature.break
281
- nature.return_value = bound_core.call( *nature.arguments )
282
- combined_posts.call( nature )
48
+ def on_class_method_added(contextified_class, method_name, version)
49
+ unless methods_modules_containing_method(contextified_class,
50
+ method_name).empty?
51
+ replace_core_method(contextified_class, method_name, version)
283
52
  end
284
- nature.return_value
285
53
  end
286
- end
287
-
288
- def behaviour_with_arounds( instance )
289
- bound_core = self.bind_core( instance )
290
- bound_arounds = self.bind_arounds( instance )
291
54
 
292
- lambda do | *arguments |
293
- working_arounds = bound_arounds.clone
294
- nature = MethodNature.new( arguments, nil, false)
295
- nature.block = around_block( nature, working_arounds, bound_core )
296
-
297
- catch( :break_in_around ) do
298
- working_arounds.shift.call( nature )
55
+ def on_wrapper_method_added(methods_module, method_name, version)
56
+ self.definitions.collect do | each_class, each_methods_modules |
57
+ if each_methods_modules.include?(methods_module)
58
+ each_class
59
+ end
60
+ end.compact.each do | contextified_class |
61
+ replace_core_method(contextified_class, method_name, 0)
299
62
  end
300
- nature.return_value
301
63
  end
302
- end
303
64
 
304
- def behaviour_with_pres_and_arounds( instance )
305
- combined_pres = self.combine_pres( instance )
306
- bound_core = self.bind_core( instance )
307
- bound_arounds = self.bind_arounds( instance )
308
-
309
- lambda do | *arguments |
310
- nature = MethodNature.new( arguments, nil, false )
311
-
312
- combined_pres.call( nature )
313
- unless nature.break
314
- working_arounds = bound_arounds.clone
315
- nature.block = around_block( nature, working_arounds, bound_core )
316
- catch( :break_in_around ) do
317
- working_arounds.shift.call( nature )
318
- end
319
- end
320
- nature.return_value
65
+ def replace_core_method(contextified_class, method_name, version)
66
+ ContextR::observe_core_method(contextified_class, method_name.to_sym,
67
+ version)
321
68
  end
322
- end
323
-
324
- def behaviour_with_arounds_and_posts( instance )
325
- bound_core = self.bind_core( instance )
326
- bound_arounds = self.bind_arounds( instance )
327
- combined_posts = self.combine_posts( instance )
328
-
329
- lambda do | *arguments |
330
- working_arounds = bound_arounds.clone
331
- nature = MethodNature.new( arguments, nil, false,
332
- around_block( nature, working_arounds, bound_core ) )
333
69
 
334
- catch( :break_in_around ) do
335
- working_arounds.shift.call( nature )
336
- end
337
- combinded_posts.call( nature ) unless nature.break
338
-
339
- nature.return_value
340
- end
70
+ def register_callbacks(cclass, mmodule)
71
+ { :on_wrapper_method_added => mmodule,
72
+ :on_class_method_added => cclass }.each do | callback, klass |
73
+ ContextR::EventMachine.register(self, callback,
74
+ :on_event => :method_added,
75
+ :in_class => klass)
76
+ end
77
+ end
341
78
  end
342
-
343
- def behaviour_with_pres_and_arounds_and_posts( instance )
344
- combined_pres = self.combine_pres( instance )
345
- bound_core = self.bind_core( instance )
346
- bound_arounds = self.bind_arounds( instance )
347
- combined_posts = self.combine_posts( instance )
348
-
349
- lambda do | *arguments |
350
- nature = MethodNature.new( arguments, nil, false )
351
-
352
- combined_pres.call( nature )
353
- unless nature.break
354
- working_arounds = bound_arounds.clone
355
- nature.block = around_block( nature, working_arounds, bound_core )
356
- catch( :break_in_around ) do
357
- working_arounds.shift.call( nature )
358
- end
359
- unless nature.break
360
- combined_posts.call( nature )
361
- end
362
- end
363
- nature.return_value
364
- end
365
- end
366
-
367
-
368
- # helpers
369
- def combine_pres( instance )
370
- bound_pres = self.pres.collect { | p | p.bind( instance ) }
371
- lambda do | nature |
372
- bound_pres.each do | bound_pre |
373
- bound_pre.call( nature )
374
- break if nature.break
375
- end
376
- end
377
- end
378
-
379
- def bind_arounds( instance )
380
- self.arounds.collect { | a | a.bind( instance ) }
381
- end
382
-
383
- def around_block( nature, bound_arounds, bound_core )
384
- lambda do
385
- unless bound_arounds.empty?
386
- bound_arounds.shift.call( nature )
387
- throw( :break_in_around ) if nature.break
388
- else
389
- nature.return_value = bound_core.call( *nature.arguments )
390
- end
391
- end
392
- end
393
-
394
- def bind_core( instance )
395
- self.core.bind( instance )
396
- end
397
-
398
- def combine_posts( instance )
399
- bound_posts = self.posts.collect { | p | p.bind( instance ) }
400
- lambda do | nature |
401
- bound_posts.reverse.each do | bound_post |
402
- bound_post.call( nature )
403
- break if nature.break
404
- end
405
- nature.return_value
406
- end
79
+
80
+ self.extend(ClassMethods)
81
+
82
+ def self.inherited(klass)
83
+ klass.extend(ClassMethods)
407
84
  end
408
85
  end
409
86
  end
410
-