contextr 0.0.3 → 0.1.0

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