contextr 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -18
- data/License.txt +20 -0
- data/Manifest.txt +15 -19
- data/README.txt +2 -49
- data/Rakefile +55 -88
- data/examples/general.rb +152 -0
- data/examples/ordering.rb +29 -0
- data/lib/contextr.rb +15 -15
- data/lib/contextr/class_methods.rb +90 -0
- data/lib/contextr/core_ext.rb +2 -0
- data/lib/contextr/core_ext/module.rb +18 -0
- data/lib/contextr/core_ext/object.rb +9 -0
- data/lib/contextr/event_machine.rb +71 -0
- data/lib/contextr/layer.rb +57 -381
- data/lib/contextr/modules/mutex_code.rb +22 -0
- data/lib/contextr/modules/unique_id.rb +13 -0
- data/lib/contextr/public_api.rb +58 -0
- data/lib/contextr/version.rb +2 -2
- data/lib/ext/active_support_subset.rb +85 -0
- data/spec/contextr_spec.rb +11 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +1 -1
- data/test/test_contextr.rb +11 -0
- data/website/index.html +23 -101
- data/website/index.txt +27 -95
- data/website/stylesheets/screen.css +9 -0
- data/website/template.rhtml +3 -8
- metadata +21 -26
- data/COPYING.txt +0 -340
- data/LICENSE.txt +0 -57
- data/examples/education.rb +0 -71
- data/examples/fibonacci.rb +0 -124
- data/examples/with_current_context.rb +0 -29
- data/lib/contextr/contextr.rb +0 -160
- data/lib/core_ext/class.rb +0 -29
- data/lib/core_ext/module.rb +0 -62
- data/lib/core_ext/proc.rb +0 -53
- data/lib/ext/method_nature.rb +0 -80
- data/rake/group_spec_task.rb +0 -7
- data/rake/specific_group_spec_task.rb +0 -7
- data/spec/contextr/contextr_api_spec.rb +0 -126
- data/spec/contextr/contextr_class_side_spec.rb +0 -77
- data/spec/contextr/contextr_functional_spec.rb +0 -293
- data/spec/core_ext/module_spec.rb +0 -101
- data/spec/core_ext/proc_spec.rb +0 -61
- data/tasks/annotations.rb +0 -107
- 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
|
data/lib/contextr.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
|
2
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
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 => [
|
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,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,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
|
data/lib/contextr/layer.rb
CHANGED
@@ -1,410 +1,86 @@
|
|
1
1
|
module ContextR
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
-
|
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
|
82
|
-
|
83
|
-
|
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
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
-
|
280
|
-
unless
|
281
|
-
|
282
|
-
|
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
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
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
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
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
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
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
|
-
|