aquarium 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +35 -0
- data/MIT-LICENSE +1 -1
- data/README +66 -20
- data/Rakefile +1 -1
- data/UPGRADE +5 -0
- data/examples/aspect_design_example.rb +5 -4
- data/examples/aspect_design_example_spec.rb +6 -5
- data/examples/design_by_contract_example.rb +3 -3
- data/examples/design_by_contract_example_spec.rb +4 -4
- data/examples/method_missing_example.rb +1 -1
- data/examples/method_missing_example_spec.rb +2 -2
- data/examples/method_tracing_example.rb +3 -3
- data/examples/method_tracing_example_spec.rb +6 -6
- data/lib/aquarium/aspects/advice.rb +2 -3
- data/lib/aquarium/aspects/aspect.rb +100 -246
- data/lib/aquarium/aspects/{default_object_handler.rb → default_objects_handler.rb} +7 -6
- data/lib/aquarium/aspects/dsl/aspect_dsl.rb +2 -2
- data/lib/aquarium/aspects/pointcut.rb +190 -107
- data/lib/aquarium/finders/method_finder.rb +120 -34
- data/lib/aquarium/finders/type_finder.rb +2 -5
- data/lib/aquarium/utils.rb +1 -0
- data/lib/aquarium/utils/array_utils.rb +11 -3
- data/lib/aquarium/utils/options_utils.rb +74 -0
- data/lib/aquarium/utils/type_utils.rb +25 -11
- data/lib/aquarium/version.rb +1 -1
- data/spec/aquarium/aspects/advice_chain_node_spec.rb +1 -1
- data/spec/aquarium/aspects/advice_spec.rb +1 -1
- data/spec/aquarium/aspects/aspect_invocation_spec.rb +179 -145
- data/spec/aquarium/aspects/aspect_spec.rb +1 -1
- data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +1 -1
- data/spec/aquarium/aspects/aspect_with_subtypes_spec.rb +1 -1
- data/spec/aquarium/aspects/concurrent_aspects_spec.rb +1 -1
- data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +1 -1
- data/spec/aquarium/aspects/default_objects_handler_spec.rb +147 -0
- data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +72 -121
- data/spec/aquarium/aspects/join_point_spec.rb +1 -1
- data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +1 -1
- data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +48 -47
- data/spec/aquarium/aspects/pointcut_spec.rb +727 -410
- data/spec/aquarium/extensions/hash_spec.rb +1 -1
- data/spec/aquarium/extensions/regex_spec.rb +1 -1
- data/spec/aquarium/extensions/set_spec.rb +1 -1
- data/spec/aquarium/extensions/string_spec.rb +1 -1
- data/spec/aquarium/extensions/symbol_spec.rb +1 -1
- data/spec/aquarium/extras/design_by_contract_spec.rb +1 -1
- data/spec/aquarium/finders/finder_result_spec.rb +1 -1
- data/spec/aquarium/finders/method_finder_spec.rb +49 -16
- data/spec/aquarium/finders/type_finder_spec.rb +1 -1
- data/spec/aquarium/finders/type_finder_with_descendents_and_ancestors_spec.rb +16 -1
- data/spec/aquarium/utils/array_utils_spec.rb +31 -6
- data/spec/aquarium/utils/hash_utils_spec.rb +1 -1
- data/spec/aquarium/utils/html_escaper_spec.rb +1 -1
- data/spec/aquarium/utils/logic_error_spec.rb +1 -1
- data/spec/aquarium/utils/method_utils_spec.rb +1 -1
- data/spec/aquarium/utils/name_utils_spec.rb +1 -1
- data/spec/aquarium/utils/nil_object_spec.rb +1 -1
- data/spec/aquarium/utils/set_utils_spec.rb +1 -1
- data/spec/aquarium/utils/type_utils_spec.rb +1 -1
- metadata +9 -7
data/CHANGES
CHANGED
@@ -1,3 +1,38 @@
|
|
1
|
+
== Version 0.3.0
|
2
|
+
|
3
|
+
V0.3.0 adds numerous improvements to the DSL, making aspect specification more intuitive and
|
4
|
+
English-like. For example, where you previously wrote, e.g.,
|
5
|
+
|
6
|
+
around :methods => :all, :types => [Foo, Bar], :advice => advice_proc
|
7
|
+
after :attribute => name, :attribute_options => [:readers], :objects => [foo, bar] ...
|
8
|
+
|
9
|
+
Now you can write the same aspects as follows:
|
10
|
+
|
11
|
+
around :calls_to => :all_methods, :within_types => [Foo, Bar], :use_advice => advice_proc
|
12
|
+
after :reading => name, :on_objects => [foo, bar] ...
|
13
|
+
|
14
|
+
Other improvements include performance and robustness enhancements and miscellaneous internal
|
15
|
+
refactoring and DRY improvements.
|
16
|
+
|
17
|
+
Bug fixes:
|
18
|
+
16267 gem not updating
|
19
|
+
|
20
|
+
Enhancements:
|
21
|
+
17154 More intuitive synonyms for specifying types, methods and attributes
|
22
|
+
|
23
|
+
For #17154, the following changes were made:
|
24
|
+
Added :all_methods as a synonym for the :all special value.
|
25
|
+
Added :reading as a synonym for :attributes => ..., :attribute_options => [:readers]
|
26
|
+
Added :writing and :changing as synonyms for :attributes => ..., :attribute_options => [:writers]
|
27
|
+
Added :accessing as a synonym for :attributes => ...
|
28
|
+
Added :calls_to, :calling, :invoking, :sending_message_to as synonyms for :methods.
|
29
|
+
Added :on_types, :in_types, :within_types and :for_types as synonyms for :types. The same
|
30
|
+
set of prefixes is supported for :type, :objects, :object, and the various :exclude_*,
|
31
|
+
:*_and_ancestors, and :*_and_descendents.
|
32
|
+
|
33
|
+
The full list of possible synonyms are shown in the spec examples. In particular, see "pointcut_spec.rb".
|
34
|
+
|
35
|
+
|
1
36
|
== Version 0.2.0
|
2
37
|
|
3
38
|
V0.2.0 changes the parameter list used for advice blocks and adds numerous enhancements, robustness
|
data/MIT-LICENSE
CHANGED
data/README
CHANGED
@@ -56,12 +56,12 @@ Many of AspectJ's behaviors that aren't currently supported are planned for futu
|
|
56
56
|
|
57
57
|
Several complete examples are provided in the "examples" directory.
|
58
58
|
|
59
|
-
In most cases, you can either declare the appropriate classes or use the optional DSL, which adds convenience methods to classes, objects, or even Object itself.
|
59
|
+
In most cases, you can either declare the appropriate classes or use the optional DSL, which adds convenience methods to classes, objects, or even Object itself. The API also supports many synonyms for things like types, objects, and methods. The best place to see the full list of synonyms is the output of "pointcut_spec.rb".
|
60
60
|
|
61
61
|
Here is an example that traces invocations of all public instance methods (included inherited ones) of the classes or modules Foo and Bar.
|
62
62
|
|
63
63
|
require 'aquarium'
|
64
|
-
Aspect.new :around, :
|
64
|
+
Aspect.new :around, :calls_to => :all_methods, :on_types => [Foo, Bar] do |join_point, object, *args|
|
65
65
|
p "Entering: #{join_point.target_type.name}##{join_point.method_name} for object #{object}"
|
66
66
|
result = join_point.proceed
|
67
67
|
p "Leaving: #{join_point.target_type.name}##{join_point.method_name} for object #{object}"
|
@@ -71,7 +71,7 @@ Here is an example that traces invocations of all public instance methods (inclu
|
|
71
71
|
The advice to execute at each join point is the block. The pointcut is the set of all public instance methods in Foo and Bar. (There are additional options available for specifying class methods, protected methods, excluding inherited (ancestor) methods, etc.) Here is the same example using the convenience DSL that adds aspect methods to Object (available only if you require aquarium/aspects/dsl/object_dsl', since other toolkits, like Rails, define similar methods on Object!).
|
72
72
|
|
73
73
|
require 'aquarium/aspects/dsl/object_dsl'
|
74
|
-
around :
|
74
|
+
around :calls_to => :all_methods, :on_types => [Foo, Bar] do |join_point, object, *args|
|
75
75
|
p "Entering: #{join_point.target_type.name}##{join_point.method_name} for object #{object}"
|
76
76
|
result = join_point.proceed
|
77
77
|
p "Leaving: #{join_point.target_type.name}##{join_point.method_name} for object #{object}"
|
@@ -118,11 +118,11 @@ It is important to note that aspect "instances" usually behave like class (stati
|
|
118
118
|
|
119
119
|
A common mistake is to create an aspect in an initialize method and assign it to an attribute. This usually means that you are creating long-lived, redundant aspects every time an instance of your class is created. The aspect modifications remain in effect even when the instances themselves are garbage collected!
|
120
120
|
|
121
|
-
Here are some more succinct examples, illustrating the API (using the DSL methods).
|
121
|
+
Here are some more succinct examples, illustrating the API (using the DSL methods) and some of the various synonyms for methods, types, etc.
|
122
122
|
|
123
123
|
You can pass in pointcuts defined elsewhere:
|
124
124
|
|
125
|
-
my_pointcut = Pointcut.new :
|
125
|
+
my_pointcut = Pointcut.new :invocations_of => /^do_/, :within_types => /Foo::Bar::/
|
126
126
|
around :pointcuts => my_pointcut do |jp, obj, *args| ... # Pass in a pointcut
|
127
127
|
around :pointcuts => [my_pointcut, ...] do |jp, obj, *args| ... # Pass in a pointcut array
|
128
128
|
|
@@ -133,7 +133,7 @@ my_join_point2 = JoinPoint.new :type => Foo::Bar, :method => do_that
|
|
133
133
|
around :pointcuts => my_join_point1 do |jp, obj, *args| ...
|
134
134
|
around :pointcuts => [my_join_point1, my_join_point2, ...] do |jp, obj, *args| ...
|
135
135
|
|
136
|
-
You can specify a single type, a type name, a type regular expression, or an array of the same. Note that :type and :types are synonymous
|
136
|
+
You can specify a single type, a type name, a type regular expression, or an array of the same. Note that :type and :types are synonymous. Use the singular form for better readability when you are specifying just one type. Other synonyms include :on_types, :within_types, and :in_types, plus the singular forms.
|
137
137
|
|
138
138
|
around :type = A, ...
|
139
139
|
around :type = "A", ...
|
@@ -141,22 +141,41 @@ You can specify a single type, a type name, a type regular expression, or an arr
|
|
141
141
|
around :types => %w[A, B, ...], ...
|
142
142
|
around :types => /A::.*Helper$/, ...
|
143
143
|
around :types => [/A::.*Helper$/, /B::Foo.*/], ...
|
144
|
-
|
145
|
-
|
144
|
+
|
145
|
+
Using the plural versions of the synonyms, with method specifications so they read better:
|
146
|
+
|
147
|
+
around :calls_to => :all_methods, :on_types => [A, B, ...], ...
|
148
|
+
around :calls_to => :all_methods, :in_types => [A, B, ...], ...
|
149
|
+
around :calls_to => :all_methods, :within_types => [A, B, ...], ...
|
150
|
+
|
151
|
+
You can specify types and their descendents (subclasses or included modules) or ancestors. The same synonym prefixes for :types and :type also apply.
|
146
152
|
|
147
153
|
around :type_and_ancestors = A, ...
|
148
154
|
around :types_and_ancestors = A, ...
|
149
155
|
around :type_and_descendents = A, ...
|
150
156
|
around :types_and_descendents = A, ...
|
157
|
+
|
158
|
+
Some of the synonyms:
|
159
|
+
|
160
|
+
around :calls_to => :all_methods, :on_types_and_ancestors = A, ...
|
161
|
+
around :calls_to => :all_methods, :in_types_and_ancestors = A, ...
|
162
|
+
around :calls_to => :all_methods, :within_types_and_ancestors = A, ...
|
163
|
+
and similarly for descendents
|
151
164
|
|
152
|
-
You can specify a single object or an array of objects.
|
165
|
+
You can specify a single object or an array of objects. As for :types, you can use :object, :objects, :on_objects, :within_object, :in_objects, and the singular forms synonymously.
|
153
166
|
|
154
167
|
a1 = A.new
|
155
168
|
a2 = A.new
|
156
169
|
around :object = a1, ...
|
157
170
|
around :objects => [a1, a2], ...
|
158
171
|
|
159
|
-
|
172
|
+
Some of the synonyms:
|
173
|
+
|
174
|
+
around :calls_to => :all_methods, :on_objects = [a1, a2], ...
|
175
|
+
around :calls_to => :all_methods, :in_objects = [a1, a2], ...
|
176
|
+
around :calls_to => :all_methods, :within_objects = [a1, a2], ...
|
177
|
+
|
178
|
+
If no types or objects are specified, the object defaults to "self". However, this default is only supported when using the DSL to create an aspect, e.g.,
|
160
179
|
|
161
180
|
class MyClass
|
162
181
|
include Aquarium::Aspects::DSL::AspectDSL
|
@@ -165,15 +184,23 @@ If no types or objects are specified, the object defaults to "self". However, th
|
|
165
184
|
around :method => doit, ... # Implicit :object => self, i.e., MyClass
|
166
185
|
end
|
167
186
|
|
168
|
-
You can specify a single method symbol (name), a regular expression, or an array of the same.
|
187
|
+
You can specify a single method symbol (name), a regular expression, or an array of the same. The synonyms for :methods include :method, :calls_to, :invoking, :invocations_of, and :sending_messages_to. The special keywords :all and :all_methods mean match all methods, subject to the :method_options discussed next.
|
169
188
|
|
170
|
-
around :method = :
|
189
|
+
around :method = :all_methods, ...
|
171
190
|
around :method = :foo, ...
|
172
191
|
around :methods = [:foo, :bar, :baz], ...
|
173
192
|
around :methods = /^foo/, ...
|
174
193
|
around :methods = [/^foo/, /bar$/], ...
|
175
194
|
|
176
|
-
|
195
|
+
Using the synonyms:
|
196
|
+
|
197
|
+
around :calls_to = :all_methods, ...
|
198
|
+
after :invoking = :all_methods, ...
|
199
|
+
after :invocations_of = :all_methods, ...
|
200
|
+
after :sending_messages_to = :all_methods, ...
|
201
|
+
after :within_methods = :all_methods, ...
|
202
|
+
|
203
|
+
You can specify method options. By default, public instance methods only are matched. Note that :methods => :all or :all_methods with no method options matches all public instance methods, including ancestor (inherited and included module) methods. For all the method options (except for :exclude_ancestor_methods), you can append the suffix "_methods". You can also use the :restrict_methods_to synonym for :method_options.
|
177
204
|
|
178
205
|
around :methods = /foo/, :method_options => [:instance], ... # match instance methods (default)
|
179
206
|
around :methods = /foo/, :method_options => [:class], ... # match class methods
|
@@ -183,12 +210,23 @@ You can specify method options. By default, public instance methods only are mat
|
|
183
210
|
around :methods = /foo/, :method_options => [:exclude_ancestor_methods], ...
|
184
211
|
# ignore methods defined in ancestors, inherited classes and included modules
|
185
212
|
|
186
|
-
|
187
|
-
|
213
|
+
With synonyms:
|
214
|
+
|
215
|
+
around :calls_to = /foo/, :restricting_methods_to => [:singleton_methods], ...
|
216
|
+
|
217
|
+
You can specify attributes, which are actually convenience methods for the attribute accessors. They work very much like the :method options. Note that :all is NOT supported in this case. The available synonyms are slightly more complicated, as shown in these examples.
|
218
|
+
|
219
|
+
around :attribute = :foo, ... # defaults to methods #foo and #foo=
|
220
|
+
around :attributes = :foo, ... # the same
|
221
|
+
around :accessing = :foo, ... # the same
|
188
222
|
|
189
|
-
around :attribute = :foo, ... # defaults to methods #foo and #foo=
|
190
223
|
around :attribute = :foo, :attribute_options => [:readers]... # only matches #foo
|
224
|
+
around :reading = :foo # the same
|
225
|
+
|
226
|
+
|
191
227
|
around :attribute = :foo, :attribute_options => [:writers]... # only matches #foo=
|
228
|
+
around :writing = :foo # the same
|
229
|
+
|
192
230
|
around :attributes = [:foo, :bar, :baz], ...
|
193
231
|
around :attributes = /^foo/, ...
|
194
232
|
around :attributes = [/^foo/, /bar$/], ...
|
@@ -201,9 +239,14 @@ You can specify a "Pointcut" that encapsulates one or more pre-defined Pointcuts
|
|
201
239
|
around :pointcuts = [jp, ...], ... # for pre-defined join point list
|
202
240
|
around :pointcut = {:type => T, :method => :m}, ... # same as around :type => T, :method => :m, ..
|
203
241
|
|
204
|
-
|
205
|
-
|
206
|
-
|
242
|
+
Using the plural versions of the synonyms, with method specifications so they read better:
|
243
|
+
|
244
|
+
around :on_pointcuts => [pc1, pc2, ...], ...
|
245
|
+
around :in_pointcuts => [pc1, pc2, ...], ...
|
246
|
+
around :within_pointcuts => [pc1, pc2, ...], ...
|
247
|
+
|
248
|
+
You can specifically exclude particular pointcuts, join points, types, objects, methods, or attributes. This is useful when you specify a list or regular expression of "items" to match and you want to exclude some of the items.
|
249
|
+
Note that there is an open bug (#15202) that appears to affect advising types, unadvising the types, then advising objects of the same types. (This is not likely to happen a lot in real applications, but it shows up when running Aquarium's specs.)
|
207
250
|
|
208
251
|
around ..., :exclude_pointcut = pc, ...
|
209
252
|
around ..., :exclude_pointcuts = [pc, ...]
|
@@ -222,6 +265,8 @@ of the same types. (This is not likely to happen a lot in real applications, but
|
|
222
265
|
around ..., :exclude_attribute = a, ...
|
223
266
|
around ..., :exclude_attributes = [a, ...]
|
224
267
|
|
268
|
+
All the same synonyms for :types, :objects, and :methods apply here as well (after the "exclude_" prefix).
|
269
|
+
|
225
270
|
You can advice methods before execution:
|
226
271
|
|
227
272
|
before :types => ...
|
@@ -258,7 +303,7 @@ If you pass a block to Aspect.new, it will be the advice. When invoked, the advi
|
|
258
303
|
1) the JoinPoint, which will contain a JoinPoint::Context object with useful context information,
|
259
304
|
2) the object being sent the current message, and
|
260
305
|
3) the parameters passed with the original message.
|
261
|
-
Recall that Proc
|
306
|
+
Recall that a Proc doesn't check the number of arguments (while lambdas do), so if you don't care about any of the trailing parameters, you can leave them out of the parameter list. Recall that the other difference between the two is that a return statement in a Proc returns from the method that contains it. As rule, do NOT use return statements in advices!
|
262
307
|
|
263
308
|
around :type => [...], :methods => :all do |join_point, object, *args|
|
264
309
|
advice_to_execute_before_the_jp
|
@@ -279,6 +324,7 @@ Rather than passing a block as the advice, you can pass a previously-created Pro
|
|
279
324
|
around :type => [...], :methods => :all, :call => advice # synonym for advice.
|
280
325
|
around :type => [...], :methods => :all, :invoke => advice # synonym for advice.
|
281
326
|
|
327
|
+
|
282
328
|
=== Packages
|
283
329
|
|
284
330
|
Aquarium::Aspects contains the Aspect class and supporting classes Pointcut, JoinPoint, etc.
|
data/Rakefile
CHANGED
@@ -87,7 +87,7 @@ aquarium = Gem::Specification.new do |s|
|
|
87
87
|
s.bindir = 'bin'
|
88
88
|
s.executables = []
|
89
89
|
s.default_executable = ''
|
90
|
-
s.
|
90
|
+
s.authors = ["Aquarium Development Team"]
|
91
91
|
s.email = "aquarium-devel@rubyforge.org"
|
92
92
|
s.homepage = "http://aquarium.rubyforge.org"
|
93
93
|
s.rubyforge_project = "aquarium"
|
data/UPGRADE
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
== Upgrading to Aquarium-0.3.0
|
2
|
+
|
3
|
+
There are no known upgrade issues with this release. Although many new synonyms were added for API method
|
4
|
+
parameters, all changes are backwards compatible.
|
5
|
+
|
1
6
|
== Upgrading to Aquarium-0.2.0
|
2
7
|
|
3
8
|
This release changes the expected advice parameter list from |join_point, *method_args| to
|
@@ -19,14 +19,15 @@ module Aquarium
|
|
19
19
|
end
|
20
20
|
attr_accessor :state
|
21
21
|
|
22
|
-
#
|
22
|
+
# Two alternative versions of the following pointcut would be
|
23
23
|
# STATE_CHANGE = pointcut :method => :state=
|
24
|
-
#
|
24
|
+
# STATE_CHANGE = pointcut :attribute => :state, :attribute_options => [:writers]
|
25
|
+
# Note that only matching on the attribute writers is important, especially
|
25
26
|
# given the advice block below, because if the reader is allowed to be advised,
|
26
27
|
# we get an infinite recursion of advice invocation! The correct solution is
|
27
28
|
# the planned extension of the pointcut language to support condition tests for
|
28
|
-
# context. I.e., we don't want the advice applied when it's already inside advice
|
29
|
-
STATE_CHANGE = pointcut :
|
29
|
+
# context. I.e., we don't want the advice applied when it's already inside advice.
|
30
|
+
STATE_CHANGE = pointcut :writing => :state
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper
|
1
|
+
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper'
|
2
2
|
require 'aquarium'
|
3
3
|
|
4
4
|
# Example demonstrating emerging ideas about good aspect-oriented design. Specifically, this
|
@@ -17,14 +17,15 @@ module Aquarium
|
|
17
17
|
end
|
18
18
|
attr_accessor :state
|
19
19
|
|
20
|
-
#
|
20
|
+
# Two alternative versions of the following pointcut would be
|
21
21
|
# STATE_CHANGE = pointcut :method => :state=
|
22
|
-
#
|
22
|
+
# STATE_CHANGE = pointcut :attribute => :state, :attribute_options => [:writers]
|
23
|
+
# Note that only matching on the attribute writers is important, especially
|
23
24
|
# given the advice block below, because if the reader is allowed to be advised,
|
24
25
|
# we get an infinite recursion of advice invocation! The correct solution is
|
25
26
|
# the planned extension of the pointcut language to support condition tests for
|
26
|
-
# context. I.e., we don't want the advice applied when it's already inside advice
|
27
|
-
STATE_CHANGE = pointcut :
|
27
|
+
# context. I.e., we don't want the advice applied when it's already inside advice.
|
28
|
+
STATE_CHANGE = pointcut :writing => :state
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
@@ -15,7 +15,7 @@ module Aquarium
|
|
15
15
|
p "inside :action"
|
16
16
|
end
|
17
17
|
|
18
|
-
precondition :
|
18
|
+
precondition :calls_to => :action, :message => "Must pass more than one argument." do |jp, obj, *args|
|
19
19
|
args.size > 0
|
20
20
|
end
|
21
21
|
end
|
@@ -36,7 +36,7 @@ module Aquarium
|
|
36
36
|
p "inside :action"
|
37
37
|
end
|
38
38
|
|
39
|
-
postcondition :
|
39
|
+
postcondition :calls_to => :action,
|
40
40
|
:message => "Must pass more than one argument and first argument must be non-empty." do |jp, obj, *args|
|
41
41
|
args.size > 0 && ! args[0].empty?
|
42
42
|
end
|
@@ -71,7 +71,7 @@ module Aquarium
|
|
71
71
|
@invar = 1
|
72
72
|
end
|
73
73
|
|
74
|
-
invariant :
|
74
|
+
invariant :calls_to => /action$/, :message => "Must not change the @invar value." do |jp, obj, *args|
|
75
75
|
obj.invar == 0
|
76
76
|
end
|
77
77
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper
|
1
|
+
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper'
|
2
2
|
require 'aquarium'
|
3
3
|
require 'aquarium/extras/design_by_contract'
|
4
4
|
|
@@ -16,7 +16,7 @@ module Aquarium
|
|
16
16
|
end
|
17
17
|
attr_reader :state
|
18
18
|
|
19
|
-
precondition :
|
19
|
+
precondition :calls_to => :action, :message => "Must pass more than one argument." do |jp, obj, *args|
|
20
20
|
args.size > 0
|
21
21
|
end
|
22
22
|
end
|
@@ -41,7 +41,7 @@ module Aquarium
|
|
41
41
|
end
|
42
42
|
attr_reader :state
|
43
43
|
|
44
|
-
postcondition :
|
44
|
+
postcondition :calls_to => :action,
|
45
45
|
:message => "Must pass more than one argument and first argument must be non-empty." do |jp, obj, *args|
|
46
46
|
args.size > 0 && ! args[0].empty?
|
47
47
|
end
|
@@ -73,7 +73,7 @@ module Aquarium
|
|
73
73
|
@invar = 1
|
74
74
|
end
|
75
75
|
|
76
|
-
invariant :
|
76
|
+
invariant :calls_to => /action$/, :message => "Must not change the @invar value." do |jp, obj, *args|
|
77
77
|
obj.invar == 0
|
78
78
|
end
|
79
79
|
end
|
@@ -31,7 +31,7 @@ echo1.say "hello", "world!"
|
|
31
31
|
echo1.log "something", "interesting..."
|
32
32
|
echo1.shout "theater", "in", "a", "crowded", "firehouse!"
|
33
33
|
|
34
|
-
Aquarium::Aspects::Aspect.new :around, :
|
34
|
+
Aquarium::Aspects::Aspect.new :around, :calls_to => :method_missing, :for_type => Aquarium::Echo, do |join_point, obj, sym, *args|
|
35
35
|
if sym == :log
|
36
36
|
p "--- Sending to log: #{args.join(" ")}"
|
37
37
|
else
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper
|
1
|
+
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper'
|
2
2
|
require 'aquarium'
|
3
3
|
|
4
4
|
# Example demonstrating "around" advice for method_missing. This is a technique for
|
@@ -42,7 +42,7 @@ end
|
|
42
42
|
describe "An example of a class' method_missing with around advice" do
|
43
43
|
it "should only handle invocations not processed by the around advice." do
|
44
44
|
@intercepted_message = nil
|
45
|
-
aspect = Aquarium::Aspects::Aspect.new :around, :
|
45
|
+
aspect = Aquarium::Aspects::Aspect.new :around, :calls_to => :method_missing, :for_type => Aquarium::Echo do |join_point, obj, sym, *args|
|
46
46
|
if sym == :log
|
47
47
|
@intercepted_message = "log: #{args.join(" ")}"
|
48
48
|
else
|
@@ -38,7 +38,7 @@ bar1.do_something_else :b3, :b4
|
|
38
38
|
|
39
39
|
include Aquarium::Aspects
|
40
40
|
|
41
|
-
Aspect.new :around, :
|
41
|
+
Aspect.new :around, :calls_to => :all_methods, :for_types => [Aquarium::Foo, Aquarium::Bar],
|
42
42
|
:method_options => :exclude_ancestor_methods do |execution_point, obj, *args|
|
43
43
|
begin
|
44
44
|
p "Entering: #{execution_point.target_type.name}##{execution_point.method_name}: args = #{args.inspect}"
|
@@ -57,8 +57,8 @@ bar1.do_something_else :b7, :b8
|
|
57
57
|
|
58
58
|
# The "begin/ensure/end" idiom shown causes the advice to return the correct value; the result
|
59
59
|
# of the "proceed", rather than the value returned by "p"!
|
60
|
-
Aspect.new :around, :
|
61
|
-
:
|
60
|
+
Aspect.new :around, :invocations_of => :initialize, :for_types => [Aquarium::Foo, Aquarium::Bar],
|
61
|
+
:restricting_methods_to => :private_methods do |execution_point, obj, *args|
|
62
62
|
begin
|
63
63
|
p "Entering: #{execution_point.target_type.name}##{execution_point.method_name}: args = #{args.inspect}"
|
64
64
|
execution_point.proceed
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper
|
1
|
+
require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper'
|
2
2
|
require 'aquarium'
|
3
3
|
|
4
4
|
# Example demonstrating "around" advice that traces calls to all methods in
|
@@ -57,7 +57,7 @@ describe "An example with advice on the public instance methods (excluding ances
|
|
57
57
|
# The "begin/ensure/end" idiom shown causes the advice to return the correct value; the result
|
58
58
|
# of the "proceed", rather than the value returned by "p"!
|
59
59
|
aspect = Aquarium::Aspects::Aspect.new :around,
|
60
|
-
:
|
60
|
+
:invocations_of => :all_methods, :for_type => Aquarium::Foo, :restricting_methods_to => :exclude_ancestor_methods do |execution_point, obj, *args|
|
61
61
|
begin
|
62
62
|
obj.log "Entering: #{execution_point.target_type.name}##{execution_point.method_name}: args = #{args.inspect}"
|
63
63
|
execution_point.proceed
|
@@ -80,7 +80,7 @@ end
|
|
80
80
|
describe "An example with advice on the public instance methods (excluding ancestor methods) of Bar" do
|
81
81
|
it "should not trace any calls to the public methods defined by the included BarModule" do
|
82
82
|
aspect = Aquarium::Aspects::Aspect.new :around,
|
83
|
-
:
|
83
|
+
:invocations_of => :all_methods, :for_type => Aquarium::Bar, :restricting_methods_to => :exclude_ancestor_methods do |execution_point, obj, *args|
|
84
84
|
begin
|
85
85
|
obj.log "Entering: #{execution_point.target_type.name}##{execution_point.method_name}: args = #{args.inspect}"
|
86
86
|
execution_point.proceed
|
@@ -99,7 +99,7 @@ end
|
|
99
99
|
describe "An example with advice on the public instance methods (including ancestor methods) of Bar" do
|
100
100
|
it "should trace all calls to the public methods defined by the included BarModule" do
|
101
101
|
aspect = Aquarium::Aspects::Aspect.new :around,
|
102
|
-
:
|
102
|
+
:calls_to_methods_matching => /^do_/, :for_type => Aquarium::Bar do |execution_point, obj, *args|
|
103
103
|
begin
|
104
104
|
obj.log "Entering: #{execution_point.target_type.name}##{execution_point.method_name}: args = #{args.inspect}"
|
105
105
|
execution_point.proceed
|
@@ -123,8 +123,8 @@ end
|
|
123
123
|
describe "An example with advice on the private initialize method of Foo and Bar" do
|
124
124
|
it "should trace all calls to initialize" do
|
125
125
|
before_methods = Aquarium::Foo.private_instance_methods.sort #- Object.private_methods.sort
|
126
|
-
aspect = Aquarium::Aspects::Aspect.new :around,
|
127
|
-
|
126
|
+
aspect = Aquarium::Aspects::Aspect.new :around, :calls_to => :initialize, :for_types => [Aquarium::Foo, Aquarium::Bar],
|
127
|
+
:restricting_methods_to => :private_methods do |execution_point, obj, *args|
|
128
128
|
begin
|
129
129
|
obj.log "Entering: #{execution_point.target_type.name}##{execution_point.method_name}: args = #{args.inspect}"
|
130
130
|
execution_point.proceed
|