contextr 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/LICENSE.txt +2 -2
- data/Manifest.txt +4 -2
- data/README.txt +36 -3
- data/examples/education.rb +19 -15
- data/lib/contextr.rb +4 -2
- data/lib/contextr/contextr.rb +57 -384
- data/lib/contextr/layer.rb +405 -0
- data/lib/contextr/version.rb +1 -1
- data/lib/core_ext/class.rb +6 -1
- data/lib/core_ext/module.rb +39 -3
- data/lib/core_ext/proc.rb +29 -3
- data/{ext → lib/ext}/dynamic.rb +10 -0
- data/lib/ext/method_nature.rb +80 -0
- data/spec/contextr/contextr_api_spec.rb +0 -39
- data/spec/contextr/contextr_functional_spec.rb +294 -0
- data/test/contextr/test_contextr.rb +2 -160
- data/website/index.html +16 -8
- data/website/index.txt +16 -7
- metadata +6 -5
- data/ext/method_nature.rb +0 -17
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
+++ 0.0.2 2007-05-08
|
2
|
+
|
3
|
+
+ 1 major change:
|
4
|
+
+ Changed the wrapper execution order to a hopefulle more natural ordering
|
5
|
+
+ Added documentation
|
6
|
+
+ 1 minor change:
|
7
|
+
+ finished transition from unit tests to rspec based specification
|
8
|
+
|
1
9
|
+++ 0.0.1 2007-05-08
|
2
10
|
|
3
11
|
+ 1 major enhancement:
|
data/LICENSE.txt
CHANGED
@@ -41,8 +41,8 @@ You can redistribute it and/or modify it under either the terms of the GPL
|
|
41
41
|
software (possibly commercial). But some files in the distribution
|
42
42
|
are not written by the author, so that they are not under this terms.
|
43
43
|
|
44
|
-
They are ./tasks/annotations.rb and all files under the
|
45
|
-
See each file for the copying condition.
|
44
|
+
They are ./tasks/annotations.rb and all files under the lib/ext
|
45
|
+
directory. See each file for the copying condition.
|
46
46
|
|
47
47
|
5. The scripts and library files supplied as input to or produced as
|
48
48
|
output from the software do not automatically fall under the
|
data/Manifest.txt
CHANGED
@@ -6,19 +6,21 @@ README.txt
|
|
6
6
|
Rakefile
|
7
7
|
examples/education.rb
|
8
8
|
examples/fibonacci.rb
|
9
|
-
ext/dynamic.rb
|
10
|
-
ext/method_nature.rb
|
11
9
|
lib/contextr.rb
|
12
10
|
lib/contextr/contextr.rb
|
11
|
+
lib/contextr/layer.rb
|
13
12
|
lib/contextr/version.rb
|
14
13
|
lib/core_ext/class.rb
|
15
14
|
lib/core_ext/module.rb
|
16
15
|
lib/core_ext/proc.rb
|
16
|
+
lib/ext/dynamic.rb
|
17
|
+
lib/ext/method_nature.rb
|
17
18
|
rake/group_spec_task.rb
|
18
19
|
rake/specific_group_spec_task.rb
|
19
20
|
scripts/txt2html
|
20
21
|
setup.rb
|
21
22
|
spec/contextr/contextr_api_spec.rb
|
23
|
+
spec/contextr/contextr_functional_spec.rb
|
22
24
|
spec/core_ext/module_spec.rb
|
23
25
|
spec/core_ext/proc_spec.rb
|
24
26
|
spec/spec_helper.rb
|
data/README.txt
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
ContextR
|
2
|
-
========
|
1
|
+
= ContextR
|
3
2
|
|
4
3
|
A context-oriented programming library for Ruby.
|
5
4
|
|
@@ -7,11 +6,45 @@ Inspired by ContextL (Pascal Costanza) and ContextS (Robert Hirschfeld) with
|
|
7
6
|
thanks to Christian Neukirchen for giving the name and lots of ideas.
|
8
7
|
|
9
8
|
For more information see
|
9
|
+
- http://contextr.rubyforge.org/
|
10
10
|
- http://www.contextr.org/ or
|
11
11
|
- http://www.swa.hpi.uni-potsdam.de/cop/
|
12
12
|
|
13
|
-
This code is published under the same license as Ruby. See LICENSE for more
|
13
|
+
This code is published under the same license as Ruby. See LICENSE.txt for more
|
14
14
|
information.
|
15
15
|
|
16
16
|
(c) 2007 - Gregor Schmidt - Berlin, Germany
|
17
17
|
|
18
|
+
= Usage
|
19
|
+
|
20
|
+
require 'rubygems'
|
21
|
+
require 'contextr'
|
22
|
+
|
23
|
+
class A
|
24
|
+
def a
|
25
|
+
puts "a"
|
26
|
+
end
|
27
|
+
|
28
|
+
layer :foo
|
29
|
+
|
30
|
+
foo.post :a do | n |
|
31
|
+
n.return_value += "_with_context"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
A.new.a # => "a"
|
36
|
+
|
37
|
+
ContextR::with_layers( :foo ) do
|
38
|
+
A.new.a # => "a_with_context"
|
39
|
+
end
|
40
|
+
|
41
|
+
= Starting Points
|
42
|
+
|
43
|
+
For a more detailed description
|
44
|
+
- visit the project homepage at RubyForge[http://contextr.rubyforge.org/]
|
45
|
+
- have a look at the +examples+ folder in the ContextR distribution
|
46
|
+
|
47
|
+
For detailed API descriptions have a look at the following classes and modules
|
48
|
+
- Class
|
49
|
+
- ContextR::LayerInClass
|
50
|
+
- ContextR::ClassMethods
|
data/examples/education.rb
CHANGED
@@ -2,8 +2,6 @@ require "rubygems"
|
|
2
2
|
require "contextr"
|
3
3
|
|
4
4
|
class Person
|
5
|
-
layer :address, :education
|
6
|
-
|
7
5
|
attr_accessor :name, :address, :university
|
8
6
|
|
9
7
|
def initialize name, address, university
|
@@ -15,19 +13,9 @@ class Person
|
|
15
13
|
def to_s
|
16
14
|
"Name: #{name}"
|
17
15
|
end
|
18
|
-
|
19
|
-
address.post :to_s do | n |
|
20
|
-
n.return_value += "; Address: #{address}"
|
21
|
-
end
|
22
|
-
|
23
|
-
education.post :to_s do | n |
|
24
|
-
n.return_value += ";\n[Education] #{university}"
|
25
|
-
end
|
26
16
|
end
|
27
17
|
|
28
18
|
class University
|
29
|
-
layer :address
|
30
|
-
|
31
19
|
attr_accessor :name, :address
|
32
20
|
|
33
21
|
def initialize name, address
|
@@ -38,6 +26,22 @@ class University
|
|
38
26
|
def to_s
|
39
27
|
"Name: #{name}"
|
40
28
|
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Person
|
32
|
+
layer :address, :education
|
33
|
+
|
34
|
+
address.post :to_s do | n |
|
35
|
+
n.return_value += "; Address: #{address}"
|
36
|
+
end
|
37
|
+
|
38
|
+
education.post :to_s do | n |
|
39
|
+
n.return_value += ";\n[Education] #{university}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class University
|
44
|
+
layer :address
|
41
45
|
|
42
46
|
address.post :to_s do | n |
|
43
47
|
n.return_value += "; Address: #{address}"
|
@@ -50,15 +54,15 @@ somePerson = Person.new( "Gregor Schmidt", "Berlin", hpi )
|
|
50
54
|
|
51
55
|
puts
|
52
56
|
puts somePerson
|
53
|
-
ContextR::with_layers :
|
57
|
+
ContextR::with_layers :education do
|
54
58
|
puts
|
55
59
|
puts somePerson
|
56
60
|
|
57
|
-
ContextR::with_layers :
|
61
|
+
ContextR::with_layers :address do
|
58
62
|
puts
|
59
63
|
puts somePerson
|
60
64
|
|
61
|
-
ContextR::without_layers :
|
65
|
+
ContextR::without_layers :education do
|
62
66
|
puts
|
63
67
|
puts somePerson
|
64
68
|
end
|
data/lib/contextr.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
+
#--
|
1
2
|
# TODO: get rid of this workaround to avoid double loading on `rake test`
|
3
|
+
#++
|
2
4
|
unless Object.const_defined? "ContextR"
|
3
5
|
require 'rubygems'
|
4
6
|
require 'active_support'
|
5
7
|
|
6
|
-
Dir[File.join(File.dirname(__FILE__), '
|
8
|
+
Dir[File.join(File.dirname(__FILE__), 'ext/**/*.rb')].sort.each { |lib| require lib }
|
7
9
|
Dir[File.join(File.dirname(__FILE__), 'core_ext/**/*.rb')].sort.each { |lib| require lib }
|
8
10
|
Dir[File.join(File.dirname(__FILE__), 'contextr/**/*.rb')].sort.each { |lib| require lib }
|
9
11
|
|
10
12
|
end
|
11
13
|
unless Dynamic.variables.include?( :layers )
|
12
|
-
Dynamic.variable( :layers => [ ContextR::
|
14
|
+
Dynamic.variable( :layers => [ ContextR::layer_by_symbol( :default ) ] )
|
13
15
|
end
|
data/lib/contextr/contextr.rb
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
module ContextR
|
2
|
-
@@genid = 0
|
3
|
-
class << self
|
4
|
-
def gensym( name, kind = "", postfix = "_%05d_" )
|
5
|
-
@@genid += 1
|
6
|
-
( "_#{name}_#{kind}#{postfix}" % @@genid ).intern
|
7
|
-
end
|
8
|
-
|
9
|
-
def symbolize( layer_klass )
|
10
|
-
layer_klass.namespace_free_name.gsub( "Layer", "" ).downcase.to_sym
|
11
|
-
end
|
12
|
-
|
13
|
-
def layerize( layer_symbol )
|
14
|
-
"#{layer_symbol}_layer".camelize
|
15
|
-
end
|
16
2
|
|
3
|
+
# This module is mixed into ContextR module, so that all public methods
|
4
|
+
# are available via
|
5
|
+
# ContextR::current_layers
|
6
|
+
# ContextR::with_layers( layer_name, ... ) { ... }
|
7
|
+
# ContextR::without_layers( layer_name, ... ) { ... }
|
8
|
+
module ClassMethods
|
9
|
+
# allows the explicit activation of layers within a block context
|
10
|
+
#
|
11
|
+
# ContextR::with_layers( :foo, :bar ) do
|
12
|
+
# ContextR::current_layers # => [:default, :foo, :bar]
|
13
|
+
#
|
14
|
+
# ContextR::with_layers( :baz ) do
|
15
|
+
# ContextR::current_layers # => [:default, :foo, :bar, :baz]
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# :call-seq:
|
21
|
+
# with_layers( layer_name, ... ) { ... }
|
22
|
+
#
|
17
23
|
def with_layers( *layer_symbols, &block )
|
18
24
|
layers = layer_symbols.collect do | layer_symbol |
|
19
25
|
ContextR.layer_by_name( ContextR.layerize( layer_symbol ) )
|
@@ -21,6 +27,20 @@ module ContextR
|
|
21
27
|
Dynamic.let( { :layers => Dynamic[:layers] | layers }, &block )
|
22
28
|
end
|
23
29
|
|
30
|
+
# allows the explicit deactivation of layers within a block context
|
31
|
+
#
|
32
|
+
# ContextR::with_layers( :foo, :bar ) do
|
33
|
+
# ContextR::current_layers # => [:default, :foo, :bar]
|
34
|
+
#
|
35
|
+
# ContextR::without_layers( :foo ) do
|
36
|
+
# ContextR::current_layers # => [:default, :bar]
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# :call-seq:
|
42
|
+
# without_layers( layer_name, ... ) { ... }
|
43
|
+
#
|
24
44
|
def without_layers( *layer_symbols, &block )
|
25
45
|
layers = layer_symbols.collect do | layer_symbol |
|
26
46
|
ContextR.layer_by_name( ContextR.layerize( layer_symbol ) )
|
@@ -28,11 +48,30 @@ module ContextR
|
|
28
48
|
Dynamic.let( { :layers => Dynamic[:layers] - layers }, &block )
|
29
49
|
end
|
30
50
|
|
31
|
-
|
51
|
+
# returns the names of the currently activated layers
|
52
|
+
#
|
53
|
+
# ContextR::current_layers # => [:default]
|
54
|
+
#
|
55
|
+
# ContextR::with_layers :foo do
|
56
|
+
# ContextR::current_layers # => [:default, :foo]
|
57
|
+
# end
|
58
|
+
def current_layers
|
59
|
+
Dynamic[:layers].collect{ | layer_class | self.symbolize( layer_class ) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def symbolize( layer_klass ) # :nodoc:
|
63
|
+
layer_klass.namespace_free_name.gsub( "Layer", "" ).downcase.to_sym
|
64
|
+
end
|
65
|
+
|
66
|
+
def layerize( layer_symbol ) # :nodoc:
|
67
|
+
"#{layer_symbol}_layer".camelize
|
68
|
+
end
|
69
|
+
|
70
|
+
def layer_by_symbol( layer_symbol ) # :nodoc:
|
32
71
|
layer_by_name( layerize( layer_symbol ) )
|
33
72
|
end
|
34
73
|
|
35
|
-
def layer_by_name( layer_name )
|
74
|
+
def layer_by_name( layer_name ) # :nodoc:
|
36
75
|
unless ContextR.const_defined?( layer_name )
|
37
76
|
ContextR::module_eval(
|
38
77
|
"class #{layer_name} < Layer; end", __FILE__, __LINE__ )
|
@@ -41,377 +80,11 @@ module ContextR
|
|
41
80
|
ContextR.const_get( layer_name )
|
42
81
|
end
|
43
82
|
|
44
|
-
def current_layer
|
83
|
+
def current_layer # :nodoc:
|
45
84
|
Layer.compose( Dynamic[:layers] )
|
46
85
|
end
|
47
|
-
end
|
48
|
-
|
49
|
-
|
50
|
-
class Layer # its role as base instance of all layers
|
51
|
-
class << self
|
52
|
-
attr_accessor_with_default_setter :base_layers, :combined_layers do
|
53
|
-
Hash.new
|
54
|
-
end
|
55
|
-
|
56
|
-
def core_methods
|
57
|
-
@core_methods ||= Hash.new do | hash, extended_class |
|
58
|
-
add_redefine_callback( extended_class )
|
59
|
-
hash[extended_class] = Hash.new do | class_hash, method_name |
|
60
|
-
um = extended_class.instance_method( method_name )
|
61
|
-
replace_core_method( extended_class, method_name )
|
62
|
-
class_hash[method_name] = um
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def inherited( new_base_layer )
|
68
|
-
unless new_base_layer.name.empty?
|
69
|
-
base_layers[ContextR::symbolize( new_base_layer )] = new_base_layer
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def compose( layers )
|
74
|
-
# TODO: Add better caching
|
75
|
-
combined_layers[ layers ] ||=
|
76
|
-
layers.reverse.inject( nil ) do | akku, layer |
|
77
|
-
layer + akku
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
protected
|
82
|
-
def replace_core_method( extended_class, method_name )
|
83
|
-
num_of_args = extended_class.instance_method( method_name ).arity
|
84
|
-
arg_signature = case num_of_args <=> 0
|
85
|
-
when 0
|
86
|
-
""
|
87
|
-
when 1
|
88
|
-
"%s" % Array.new( num_of_args ) { |i| "arg%d" % i }.join( ", " )
|
89
|
-
else
|
90
|
-
"*arguments"
|
91
|
-
end
|
92
|
-
arg_call = arg_signature.empty? ? "" : ", " + arg_signature
|
93
|
-
|
94
|
-
extended_class.class_eval( %Q{
|
95
|
-
remove_method :#{method_name}
|
96
|
-
def #{method_name} #{arg_signature}
|
97
|
-
ContextR::current_layer.extended( self ).send(
|
98
|
-
:#{method_name}#{arg_call} )
|
99
|
-
end
|
100
|
-
}, __FILE__, __LINE__ )
|
101
|
-
end
|
102
|
-
|
103
|
-
def add_redefine_callback( extended_class )
|
104
|
-
(class << extended_class; self; end).instance_eval do
|
105
|
-
define_method( :method_added ) do | method_name |
|
106
|
-
if ContextR::Layer.core_methods[extended_class].
|
107
|
-
include?( method_name )
|
108
|
-
warn( caller.first + " : ContextR - Redefining already wrapped methods is not supported yet. Your changes _may_ have no effect." )
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
class Layer # its role as base class for all other layers
|
117
|
-
class << self
|
118
|
-
attr_accessor_with_default_setter :extended_classes do
|
119
|
-
Hash.new do | classes, extended_class |
|
120
|
-
classes[extended_class] = Hash.new do | hash, key |
|
121
|
-
hash[key] = ContextualizedMethod.new(
|
122
|
-
ContextR::Layer.core_methods[ extended_class ][ key ] )
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
attr_accessor :extended_objects
|
127
|
-
|
128
|
-
def methods_of( extended_class )
|
129
|
-
self.extended_classes[extended_class]
|
130
|
-
end
|
131
|
-
|
132
|
-
def extended( object )
|
133
|
-
self.extended_objects ||= Hash.new do | cache, object |
|
134
|
-
cache[ object ] =
|
135
|
-
ExtendedObject.new( object, self.methods_of( object.class ) )
|
136
|
-
end
|
137
|
-
self.extended_objects[object]
|
138
|
-
end
|
139
|
-
|
140
|
-
def + other_layer
|
141
|
-
if other_layer.nil?
|
142
|
-
self
|
143
|
-
else
|
144
|
-
combined_layer = Class.new( Layer )
|
145
|
-
combined_layer.extended_classes = self.merge_extended_classes_with(
|
146
|
-
other_layer.extended_classes )
|
147
|
-
combined_layer
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
protected
|
152
|
-
|
153
|
-
def merge_extended_classes_with( other_ec )
|
154
|
-
extended_classes.merge( other_ec ) do | extended_c, my_ms, other_ms |
|
155
|
-
my_ms.merge( other_ms ) do | method_name, my_cm, other_cm |
|
156
|
-
my_cm + other_cm
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
86
|
|
163
|
-
class LayerInClass # its public interface
|
164
|
-
attr_accessor :contextualized_class
|
165
|
-
attr_accessor :layer
|
166
|
-
|
167
|
-
def initialize( contextualized_class, layer )
|
168
|
-
self.contextualized_class = contextualized_class
|
169
|
-
self.layer = layer
|
170
|
-
end
|
171
|
-
|
172
|
-
def pre( method_name, &block )
|
173
|
-
layer.methods_of( self.contextualized_class )[method_name].pres <<
|
174
|
-
block.to_unbound_method( self.contextualized_class )
|
175
|
-
nil
|
176
|
-
end
|
177
|
-
def post( method_name, &block )
|
178
|
-
layer.methods_of( self.contextualized_class )[method_name].posts <<
|
179
|
-
block.to_unbound_method( self.contextualized_class )
|
180
|
-
nil
|
181
|
-
end
|
182
|
-
def around( method_name, &block )
|
183
|
-
layer.methods_of( self.contextualized_class )[method_name].arounds <<
|
184
|
-
block.to_unbound_method( self.contextualized_class )
|
185
|
-
nil
|
186
|
-
end
|
187
|
-
alias :wrap :around
|
188
|
-
end
|
189
|
-
|
190
|
-
class ExtendedObject
|
191
|
-
attr_accessor :proxied_object
|
192
|
-
attr_accessor :extended_methods
|
193
|
-
attr_accessor :behaviours
|
194
|
-
|
195
|
-
def initialize( proxied_object, extended_methods )
|
196
|
-
self.proxied_object = proxied_object
|
197
|
-
self.extended_methods = extended_methods
|
198
|
-
self.behaviours = {}
|
199
|
-
end
|
200
|
-
|
201
|
-
def send( method_name, *arguments )
|
202
|
-
( self.behaviours[method_name] ||=
|
203
|
-
self.extended_methods[method_name].behaviour( self.proxied_object )
|
204
|
-
).call( *arguments )
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
class ContextualizedMethod
|
209
|
-
attr_accessor :core
|
210
|
-
attr_accessor :behaviour_cache
|
211
|
-
|
212
|
-
attr_accessor_with_default_setter :pres, :posts, :arounds do
|
213
|
-
Array.new
|
214
|
-
end
|
215
|
-
|
216
|
-
def initialize( unbound_core_method )
|
217
|
-
self.core = unbound_core_method
|
218
|
-
self.behaviour_cache = {}
|
219
|
-
end
|
220
|
-
|
221
|
-
def + other_cm
|
222
|
-
new_cm = ContextualizedMethod.new( self.core )
|
223
|
-
new_cm.pres = self.pres + other_cm.pres
|
224
|
-
new_cm.posts = self.posts + other_cm.posts
|
225
|
-
new_cm.arounds = self.arounds + other_cm.arounds
|
226
|
-
new_cm
|
227
|
-
end
|
228
|
-
|
229
|
-
def behaviour( instance )
|
230
|
-
self.behaviour_cache[instance] ||=
|
231
|
-
self.send( self.behaviour_name, instance )
|
232
|
-
end
|
233
|
-
|
234
|
-
def behaviour_name
|
235
|
-
wrappers = []
|
236
|
-
wrappers << "pres" unless self.pres.empty?
|
237
|
-
wrappers << "arounds" unless self.arounds.empty?
|
238
|
-
wrappers << "posts" unless self.posts.empty?
|
239
|
-
|
240
|
-
"behaviour_" + ( wrappers.empty? ? "without_wrappers" :
|
241
|
-
"with_" + wrappers.join( "_and_" ) )
|
242
|
-
end
|
243
|
-
|
244
|
-
def behaviour_without_wrappers( instance )
|
245
|
-
self.core.bind( instance )
|
246
|
-
end
|
247
|
-
|
248
|
-
def behaviour_with_pres( instance )
|
249
|
-
combined_pres = self.combine_pres( instance )
|
250
|
-
bound_core = self.bind_core( instance )
|
251
|
-
|
252
|
-
lambda do | *arguments |
|
253
|
-
nature = MethodNature.new( arguments, nil, false )
|
254
|
-
|
255
|
-
combined_pres.call( nature )
|
256
|
-
unless nature.break
|
257
|
-
bound_core.call( *nature.arguments )
|
258
|
-
else
|
259
|
-
nature.return_value
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
def behaviour_with_posts( instance )
|
265
|
-
bound_core = self.bind_core( instance )
|
266
|
-
combined_posts = self.combine_posts( instance )
|
267
|
-
|
268
|
-
lambda do | *arguments |
|
269
|
-
nature = MethodNature.new( arguments, nil, false )
|
270
|
-
|
271
|
-
nature.return_value = bound_core.call( *arguments )
|
272
|
-
combined_posts.call( nature )
|
273
|
-
|
274
|
-
nature.return_value
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
def behaviour_with_pres_and_posts( instance )
|
279
|
-
combined_pres = self.combine_pres( instance )
|
280
|
-
bound_core = self.bind_core( instance )
|
281
|
-
combined_posts = self.combine_posts( instance )
|
282
|
-
|
283
|
-
lambda do | *arguments |
|
284
|
-
nature = MethodNature.new( arguments, nil, false )
|
285
|
-
|
286
|
-
combined_pres.call( nature )
|
287
|
-
unless nature.break
|
288
|
-
nature.return_value = bound_core.call( *nature.arguments )
|
289
|
-
combined_posts.call( nature )
|
290
|
-
end
|
291
|
-
nature.return_value
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
def behaviour_with_arounds( instance )
|
296
|
-
bound_core = self.bind_core( instance )
|
297
|
-
bound_arounds = self.bind_arounds( instance )
|
298
|
-
|
299
|
-
lambda do | *arguments |
|
300
|
-
working_arounds = bound_arounds.clone
|
301
|
-
nature = MethodNature.new( arguments, nil, false)
|
302
|
-
nature.block = around_block( nature, working_arounds, bound_core )
|
303
|
-
|
304
|
-
catch( :break_in_around ) do
|
305
|
-
working_arounds.pop.call( nature )
|
306
|
-
end
|
307
|
-
nature.return_value
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
def behaviour_with_pres_and_arounds( instance )
|
312
|
-
combined_pres = self.combine_pres( instance )
|
313
|
-
bound_core = self.bind_core( instance )
|
314
|
-
bound_arounds = self.bind_arounds( instance )
|
315
|
-
|
316
|
-
lambda do | *arguments |
|
317
|
-
nature = MethodNature.new( arguments, nil, false )
|
318
|
-
|
319
|
-
combined_pres.call( nature )
|
320
|
-
unless nature.break
|
321
|
-
working_arounds = bound_arounds.clone
|
322
|
-
nature.block = around_block( nature, working_arounds, bound_core )
|
323
|
-
catch( :break_in_around ) do
|
324
|
-
working_arounds.pop.call( nature )
|
325
|
-
end
|
326
|
-
end
|
327
|
-
nature.return_value
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
def behaviour_with_arounds_and_posts( instance )
|
332
|
-
bound_core = self.bind_core( instance )
|
333
|
-
bound_arounds = self.bind_arounds( instance )
|
334
|
-
combined_posts = self.combine_posts( instance )
|
335
|
-
|
336
|
-
lambda do | *arguments |
|
337
|
-
working_arounds = bound_arounds.clone
|
338
|
-
nature = MethodNature.new( arguments, nil, false,
|
339
|
-
around_block( nature, working_arounds, bound_core ) )
|
340
|
-
|
341
|
-
catch( :break_in_around ) do
|
342
|
-
working_arounds.pop.call( nature )
|
343
|
-
end
|
344
|
-
combinded_posts.call( nature ) unless nature.break
|
345
|
-
|
346
|
-
nature.return_value
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
def behaviour_with_pres_and_arounds_and_posts( instance )
|
351
|
-
combined_pres = self.combine_pres( instance )
|
352
|
-
bound_core = self.bind_core( instance )
|
353
|
-
bound_arounds = self.bind_arounds( instance )
|
354
|
-
combined_posts = self.combine_posts( instance )
|
355
|
-
|
356
|
-
lambda do | *arguments |
|
357
|
-
nature = MethodNature.new( arguments, nil, false )
|
358
|
-
|
359
|
-
combined_pres.call( nature )
|
360
|
-
unless nature.break
|
361
|
-
working_arounds = bound_arounds.clone
|
362
|
-
nature.block = around_block( nature, working_arounds, bound_core )
|
363
|
-
catch( :break_in_around ) do
|
364
|
-
working_arounds.pop.call( nature )
|
365
|
-
end
|
366
|
-
unless nature.break
|
367
|
-
combined_posts.call( nature )
|
368
|
-
end
|
369
|
-
end
|
370
|
-
nature.return_value
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
|
375
|
-
# helpers
|
376
|
-
def combine_pres( instance )
|
377
|
-
bound_pres = self.pres.collect { | p | p.bind( instance ) }
|
378
|
-
lambda do | nature |
|
379
|
-
bound_pres.reverse.each do | bound_pre |
|
380
|
-
bound_pre.call( nature )
|
381
|
-
break if nature.break
|
382
|
-
end
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
def bind_arounds( instance )
|
387
|
-
self.arounds.collect { | a | a.bind( instance ) }
|
388
|
-
end
|
389
|
-
|
390
|
-
def around_block( nature, bound_arounds, bound_core )
|
391
|
-
lambda do
|
392
|
-
unless bound_arounds.empty?
|
393
|
-
bound_arounds.pop.call( nature )
|
394
|
-
throw( :break_in_around ) if nature.break
|
395
|
-
else
|
396
|
-
nature.return_value = bound_core.call( *nature.arguments )
|
397
|
-
end
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
def bind_core( instance )
|
402
|
-
self.core.bind( instance )
|
403
|
-
end
|
404
|
-
|
405
|
-
def combine_posts( instance )
|
406
|
-
bound_posts = self.posts.collect { | p | p.bind( instance ) }
|
407
|
-
lambda do | nature |
|
408
|
-
bound_posts.each do | bound_post |
|
409
|
-
bound_post.call( nature )
|
410
|
-
break if nature.break
|
411
|
-
end
|
412
|
-
end
|
413
|
-
end
|
414
87
|
end
|
415
88
|
|
416
|
-
|
89
|
+
extend ClassMethods
|
417
90
|
end
|