contextr 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|