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
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'aquarium/utils/array_utils'
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
module Aquarium
|
4
5
|
module Aspects
|
5
|
-
# Some classes and modules support a :
|
6
|
+
# Some classes and modules support a :default_objects flag and use it if no type or
|
6
7
|
# object is specified. For "convenience", requires that classes and modules including
|
7
|
-
# this module have a hash @specification defined with keys :
|
8
|
+
# this module have a hash @specification defined with keys :default_objects, :types,
|
8
9
|
# and :objects.
|
9
|
-
module
|
10
|
+
module DefaultObjectsHandler
|
10
11
|
include Aquarium::Utils::ArrayUtils
|
11
12
|
|
12
13
|
def default_objects_given
|
@@ -22,15 +23,15 @@ module Aquarium
|
|
22
23
|
not default_objects_given.empty?
|
23
24
|
end
|
24
25
|
|
25
|
-
def
|
26
|
+
def use_default_objects_if_defined
|
26
27
|
return unless default_objects_given?
|
27
28
|
default_objects_given.each do |object|
|
28
29
|
if (object.kind_of?(Class) || object.kind_of?(Module))
|
29
30
|
@specification[:types] ||= []
|
30
|
-
@specification[:types] <<
|
31
|
+
@specification[:types] << object
|
31
32
|
else
|
32
33
|
@specification[:objects] ||= []
|
33
|
-
@specification[:objects] <<
|
34
|
+
@specification[:objects] << object
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
@@ -52,9 +52,9 @@ module Aquarium
|
|
52
52
|
def append_implicit_self options
|
53
53
|
opts = options.dup
|
54
54
|
if (!opts.empty?) && opts.last.kind_of?(Hash)
|
55
|
-
opts.last[:
|
55
|
+
opts.last[:default_objects] = self
|
56
56
|
else
|
57
|
-
opts << {:
|
57
|
+
opts << {:default_objects => self}
|
58
58
|
end
|
59
59
|
opts
|
60
60
|
end
|
@@ -6,7 +6,7 @@ require 'aquarium/extensions'
|
|
6
6
|
require 'aquarium/finders/finder_result'
|
7
7
|
require 'aquarium/finders/type_finder'
|
8
8
|
require 'aquarium/finders/method_finder'
|
9
|
-
require 'aquarium/aspects/
|
9
|
+
require 'aquarium/aspects/default_objects_handler'
|
10
10
|
|
11
11
|
module Aquarium
|
12
12
|
module Aspects
|
@@ -18,43 +18,83 @@ module Aquarium
|
|
18
18
|
class Pointcut
|
19
19
|
include Aquarium::Utils::ArrayUtils
|
20
20
|
include Aquarium::Utils::HashUtils
|
21
|
+
include Aquarium::Utils::OptionsUtils
|
21
22
|
include Aquarium::Utils::SetUtils
|
22
23
|
include ExclusionHandler
|
23
|
-
include
|
24
|
+
include DefaultObjectsHandler
|
24
25
|
|
25
26
|
attr_reader :specification
|
26
27
|
|
27
28
|
# Construct a Pointcut for methods in types or objects.
|
28
|
-
# Pointcut.new :type{s} => [...] | :object{s} => [...] \
|
29
|
+
# Pointcut.new :join_points => [...] | :type{s} => [...] | :object{s} => [...] \
|
29
30
|
# {, :method{s} => [], :method_options => [...], \
|
30
31
|
# :attribute{s} => [...], :attribute_options[...]}
|
31
|
-
# where
|
32
|
-
#
|
33
|
-
#
|
32
|
+
# where the "{}" indicate optional elements. Most of the arguments have many
|
33
|
+
# synonyms, shown below, to promote an English-like DSL.
|
34
|
+
#
|
35
|
+
# <tt>:join_points => join_point || [join_point_list]</tt>::
|
36
|
+
# <tt>:join_point => join_point || [join_point_list]</tt>::
|
37
|
+
# <tt>:for_join_points => join_point || [join_point_list]</tt>::
|
38
|
+
# <tt>:for_join_point => join_point || [join_point_list]</tt>::
|
39
|
+
# <tt>:on_join_points => join_point || [join_point_list]</tt>::
|
40
|
+
# <tt>:on_join_point => join_point || [join_point_list]</tt>::
|
41
|
+
# <tt>:within_join_points => join_point || [join_point_list]</tt>::
|
42
|
+
# <tt>:within_join_point => join_point || [join_point_list]</tt>::
|
43
|
+
# One or an array of join_points.
|
34
44
|
#
|
35
45
|
# <tt>:types => type || [type_list]</tt>::
|
36
46
|
# <tt>:type => type || [type_list]</tt>::
|
47
|
+
# <tt>:for_types => type || [type_list]</tt>::
|
48
|
+
# <tt>:for_type => type || [type_list]</tt>::
|
49
|
+
# <tt>:on_types => type || [type_list]</tt>::
|
50
|
+
# <tt>:on_type => type || [type_list]</tt>::
|
51
|
+
# <tt>:within_types => type || [type_list]</tt>::
|
52
|
+
# <tt>:within_type => type || [type_list]</tt>::
|
37
53
|
# One or an array of types, type names and/or type regular expessions to match.
|
38
54
|
#
|
39
55
|
# <tt>:types_and_descendents => type || [type_list]</tt>::
|
40
56
|
# <tt>:type_and_descendents => type || [type_list]</tt>::
|
41
57
|
# <tt>:types_and_ancestors => type || [type_list]</tt>::
|
42
58
|
# <tt>:type_and_ancestors => type || [type_list]</tt>::
|
59
|
+
# <tt>:for_types_and_ancestors => type || [type_list]</tt>::
|
60
|
+
# <tt>:for_type_and_ancestors => type || [type_list]</tt>::
|
61
|
+
# <tt>:on_types_and_descendents => type || [type_list]</tt>::
|
62
|
+
# <tt>:on_type_and_descendents => type || [type_list]</tt>::
|
63
|
+
# <tt>:on_types_and_ancestors => type || [type_list]</tt>::
|
64
|
+
# <tt>:on_type_and_ancestors => type || [type_list]</tt>::
|
65
|
+
# <tt>:within_types_and_descendents => type || [type_list]</tt>::
|
66
|
+
# <tt>:within_type_and_descendents => type || [type_list]</tt>::
|
67
|
+
# <tt>:within_types_and_ancestors => type || [type_list]</tt>::
|
68
|
+
# <tt>:within_type_and_ancestors => type || [type_list]</tt>::
|
43
69
|
# One or an array of types and either their descendents or ancestors.
|
44
70
|
# If you want both the descendents _and_ ancestors, use both options.
|
45
71
|
#
|
46
72
|
# <tt>:objects => object || [object_list]</tt>::
|
47
73
|
# <tt>:object => object || [object_list]</tt>::
|
74
|
+
# <tt>:for_objects => object || [object_list]</tt>::
|
75
|
+
# <tt>:for_object => object || [object_list]</tt>::
|
76
|
+
# <tt>:on_objects => object || [object_list]</tt>::
|
77
|
+
# <tt>:on_object => object || [object_list]</tt>::
|
78
|
+
# <tt>:within_objects => object || [object_list]</tt>::
|
79
|
+
# <tt>:within_object => object || [object_list]</tt>::
|
48
80
|
# Objects to match.
|
49
81
|
#
|
50
|
-
# <tt>:
|
82
|
+
# <tt>:default_objects => object || [object_list]</tt>::
|
83
|
+
# <tt>:default_object => object || [object_list]</tt>::
|
51
84
|
# An "internal" flag used by AspectDSL#pointcut when no object or type is specified,
|
52
|
-
# the value of :
|
85
|
+
# the value of :default_objects will be used, if defined. AspectDSL#pointcut sets the
|
53
86
|
# value to self, so that the user doesn't have to in the appropriate contexts.
|
54
87
|
# This flag is subject to change, so don't use it explicitly!
|
55
88
|
#
|
56
89
|
# <tt>:methods => method || [method_list]</tt>::
|
57
90
|
# <tt>:method => method || [method_list]</tt>::
|
91
|
+
# <tt>:within_methods => method || [method_list]</tt>::
|
92
|
+
# <tt>:within_method => method || [method_list]</tt>::
|
93
|
+
# <tt>:calling => method || [method_list]</tt>::
|
94
|
+
# <tt>:calls_to => method || [method_list]</tt>::
|
95
|
+
# <tt>:invoking => method || [method_list]</tt>::
|
96
|
+
# <tt>:invocations_of => method || [method_list]</tt>::
|
97
|
+
# <tt>:sending_message_to => method || [method_list]</tt>::
|
58
98
|
# One or an array of methods, method names and/or method regular expessions to match.
|
59
99
|
# By default, unless :attributes are specified, searches for public instance methods
|
60
100
|
# with the method option :exclude_ancestor_methods implied, unless explicit method
|
@@ -64,17 +104,34 @@ module Aquarium
|
|
64
104
|
# One or more options supported by Aquarium::Finders::MethodFinder. The :exclude_ancestor_methods
|
65
105
|
# option is most useful.
|
66
106
|
#
|
107
|
+
# <tt>:reading => attribute || [attribute_list]</tt>::
|
108
|
+
# <tt>:writing => attribute || [attribute_list]</tt>::
|
109
|
+
# <tt>:changing => attribute || [attribute_list]</tt>::
|
110
|
+
# <tt>:accessing => attribute || [attribute_list]</tt>::
|
111
|
+
# One or an array of attribute names and/or regular expessions to match.
|
112
|
+
# This is syntactic sugar for the corresponding attribute readers and/or writers
|
113
|
+
# methods.
|
114
|
+
# If <tt>:reading</tt> is specified, just attribute readers are matched.
|
115
|
+
# If <tt>:writing</tt> is specified, just attribute writers are matched.
|
116
|
+
# If <tt>:accessing</tt> is specified, both readers and writers are matched.
|
117
|
+
# Any matches will be joined with the matched <tt>:methods.</tt>.
|
118
|
+
#
|
67
119
|
# <tt>:attributes => attribute || [attribute_list]</tt>::
|
68
120
|
# <tt>:attribute => attribute || [attribute_list]</tt>::
|
69
121
|
# One or an array of attribute names and/or regular expessions to match.
|
70
122
|
# This is syntactic sugar for the corresponding attribute readers and/or writers
|
71
123
|
# methods, as specified using the <tt>:attrbute_options</tt>. Any matches will be
|
72
|
-
# joined with the matched
|
124
|
+
# joined with the matched <tt>:methods.</tt>.
|
73
125
|
#
|
74
126
|
# <tt>:attribute_options => [options]</tt>::
|
75
127
|
# One or more of <tt>:readers</tt>, <tt>:reader</tt> (synonymous),
|
76
128
|
# <tt>:writers</tt>, and/or <tt>:writer</tt> (synonymous). By default, both
|
77
|
-
# readers and writers are matched.
|
129
|
+
# readers and writers are matched.
|
130
|
+
# <tt>:reading => ...</tt> is synonymous with <tt>:attributes => ...,
|
131
|
+
# :attribute_options => [:readers]</tt>.
|
132
|
+
# <tt>:writing => ...</tt> and <tt>:changing => ...</tt> are synonymous with <tt>:attributes => ...,
|
133
|
+
# :attribute_options => [:writers]</tt>.
|
134
|
+
# <tt>:accessing => ...</tt> is synonymous with <tt>:attributes => ...</tt>.
|
78
135
|
#
|
79
136
|
# <tt>:exclude_pointcuts => pc || [pc_list]</tt>::
|
80
137
|
# <tt>:exclude_pointcut => pc || [pc_list]</tt>::
|
@@ -89,6 +146,7 @@ module Aquarium
|
|
89
146
|
# <tt>:exclude_method => method || [method_list]</tt>::
|
90
147
|
# <tt>:exclude_attributes => attribute || [attribute_list]</tt>::
|
91
148
|
# <tt>:exclude_attribute => attribute || [attribute_list]</tt>::
|
149
|
+
# Also <tt>exclude_{synonyms}</tt> of the same options...
|
92
150
|
# Exclude the specified "things" from the matched join points. If pointcuts are
|
93
151
|
# excluded, they should be subsets of the matched pointcuts. Otherwise, the
|
94
152
|
# resulting pointcut will be empty!
|
@@ -101,7 +159,7 @@ module Aquarium
|
|
101
159
|
# If you want to exclude both the descendents _and_ ancestors, use both options.
|
102
160
|
#
|
103
161
|
def initialize options = {}
|
104
|
-
init_specification options
|
162
|
+
init_specification options, canonical_options
|
105
163
|
init_candidate_types
|
106
164
|
init_candidate_objects
|
107
165
|
init_candidate_join_points
|
@@ -135,91 +193,42 @@ module Aquarium
|
|
135
193
|
|
136
194
|
alias to_s inspect
|
137
195
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
196
|
+
CANONICAL_OPTIONS = {
|
197
|
+
"types" => %w[type for_type for_types on_type on_types in_type in_types within_type within_types],
|
198
|
+
"objects" => %w[object for_object for_objects on_object on_objects in_object in_objects within_object within_objects],
|
199
|
+
"join_points" => %w[join_point for_join_point for_join_points on_join_point on_join_points within_join_point within_join_points],
|
200
|
+
"methods" => %w[method within_method within_methods calling invoking calls_to invocations_of sending_message_to sending_messages_to],
|
201
|
+
"attributes" => %w[attribute accessing],
|
202
|
+
"method_options" => %w[method_option restricting_methods_to],
|
203
|
+
"attribute_options" => %w[attribute_option],
|
204
|
+
"types_and_descendents" => %w[type_and_descendents on_type_and_descendents on_types_and_descendents within_type_and_descendents within_types_and_descendents],
|
205
|
+
"types_and_ancestors" => %w[type_and_ancestors on_type_and_ancestors on_types_and_ancestors within_type_and_ancestors within_types_and_ancestors],
|
206
|
+
"default_objects" => %w[default_object]
|
207
|
+
}
|
208
|
+
%w[types objects join_points methods types_and_descendents types_and_ancestors].each do |key|
|
209
|
+
CANONICAL_OPTIONS["exclude_#{key}"] = CANONICAL_OPTIONS[key].map {|x| "exclude_#{x}"}
|
145
210
|
end
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
attr_writer :join_points_matched, :join_points_not_matched, :specification, :candidate_types, :candidate_types_excluded, :candidate_objects, :candidate_join_points
|
150
|
-
|
151
|
-
ALLOWED_OPTIONS_SINGULAR = %w[
|
152
|
-
type object join_point method
|
153
|
-
exclude_type exclude_object exclude_join_point exclude_pointcut exclude_method
|
154
|
-
default_object attribute method_option attribute_option]
|
155
|
-
|
156
|
-
OTHER_ALLOWED_OPTIONS = %w[
|
157
|
-
type_and_descendents types_and_descendents type_and_ancestors types_and_ancestors
|
158
|
-
exclude_type_and_descendents exclude_types_and_descendents exclude_type_and_ancestors exclude_types_and_ancestors]
|
159
|
-
|
160
|
-
OTHER_ALLOWED_SPEC_KEYS = {
|
161
|
-
"types_and_descendents" => "type_and_descendents",
|
162
|
-
"types_and_ancestors" => "type_and_ancestors",
|
163
|
-
"exclude_types_and_descendents" => "exclude_type_and_descendents",
|
164
|
-
"exclude_types_and_ancestors" => "exclude_type_and_ancestors" }
|
165
|
-
|
166
|
-
def init_specification options
|
167
|
-
@specification = {}
|
168
|
-
options ||= {}
|
169
|
-
validate_options options
|
170
|
-
ALLOWED_OPTIONS_SINGULAR.each do |option|
|
171
|
-
self.instance_eval(<<-EOF, __FILE__, __LINE__)
|
172
|
-
@specification[:#{option}s]= Set.new(make_array(options[:#{option}], options[:#{option}s]))
|
173
|
-
EOF
|
174
|
-
end
|
175
|
-
OTHER_ALLOWED_SPEC_KEYS.keys.each do |option|
|
176
|
-
self.instance_eval(<<-EOF, __FILE__, __LINE__)
|
177
|
-
@specification[:#{option}]= Set.new(make_array(options[:#{option}], options[:#{OTHER_ALLOWED_SPEC_KEYS[option]}]))
|
178
|
-
EOF
|
179
|
-
end
|
180
|
-
|
181
|
-
use_default_object_if_defined unless (types_given? || objects_given?)
|
182
|
-
|
183
|
-
raise Aquarium::Utils::InvalidOptions.new(":all is not yet supported for :attributes.") if @specification[:attributes] == Set.new([:all])
|
184
|
-
init_methods_specification options
|
185
|
-
end
|
186
|
-
|
187
|
-
def init_methods_specification options
|
188
|
-
@specification[:methods] = Set.new(make_array(options[:methods], options[:method]))
|
189
|
-
@specification[:methods].add(:all) if @specification[:methods].empty? and @specification[:attributes].empty?
|
211
|
+
CANONICAL_OPTIONS["methods"].dup.each do |synonym|
|
212
|
+
CANONICAL_OPTIONS["methods"] << "#{synonym}_methods_matching"
|
190
213
|
end
|
214
|
+
CANONICAL_OPTIONS["exclude_pointcuts"] = %w[exclude_pointcut exclude_on_pointcut exclude_on_pointcuts exclude_within_pointcut exclude_within_pointcuts]
|
191
215
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
unknowns = options.keys - knowns
|
202
|
-
raise Aquarium::Utils::InvalidOptions.new("Unknown options specified: #{unknowns.inspect}") if unknowns.size > 0
|
203
|
-
end
|
204
|
-
|
205
|
-
def self.read_only attribute_options
|
206
|
-
read_option(attribute_options) && !write_option(attribute_options)
|
207
|
-
end
|
208
|
-
|
209
|
-
def self.write_only attribute_options
|
210
|
-
write_option(attribute_options) && !read_option(attribute_options)
|
211
|
-
end
|
212
|
-
|
213
|
-
def self.read_option attribute_options
|
214
|
-
attribute_options.include?(:readers) || attribute_options.include?(:reader)
|
216
|
+
ATTRIBUTE_OPTIONS = %w[reading writing changing]
|
217
|
+
|
218
|
+
ALL_ALLOWED_OPTIONS = ATTRIBUTE_OPTIONS +
|
219
|
+
CANONICAL_OPTIONS.keys.inject([]) {|ary,i| ary << i << CANONICAL_OPTIONS[i]}.flatten
|
220
|
+
|
221
|
+
ALL_ALLOWED_OPTION_SYMBOLS = ALL_ALLOWED_OPTIONS.map {|o| o.intern}
|
222
|
+
|
223
|
+
def canonical_options
|
224
|
+
CANONICAL_OPTIONS
|
215
225
|
end
|
216
|
-
|
217
|
-
|
218
|
-
attribute_options.include?(:writers) || attribute_options.include?(:writer)
|
226
|
+
def all_allowed_option_symbols
|
227
|
+
ALL_ALLOWED_OPTION_SYMBOLS
|
219
228
|
end
|
220
|
-
|
221
|
-
|
222
|
-
|
229
|
+
|
230
|
+
CANONICAL_OPTIONS.keys.each do |name|
|
231
|
+
module_eval(<<-EOF, __FILE__, __LINE__)
|
223
232
|
def #{name}_given
|
224
233
|
@specification[:#{name}]
|
225
234
|
end
|
@@ -230,18 +239,60 @@ module Aquarium
|
|
230
239
|
EOF
|
231
240
|
end
|
232
241
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
242
|
+
def self.make_attribute_reading_writing_options options_hash
|
243
|
+
result = {}
|
244
|
+
[:writing, :changing, :reading].each do |attr_key|
|
245
|
+
unless options_hash[attr_key].nil? or options_hash[attr_key].empty?
|
246
|
+
result[:attributes] ||= Set.new([])
|
247
|
+
result[:attribute_options] ||= Set.new([])
|
248
|
+
result[:attributes].merge(Aquarium::Utils::ArrayUtils.make_array(options_hash[attr_key]))
|
249
|
+
attr_opt = attr_key == :reading ? :readers : :writers
|
250
|
+
result[:attribute_options] << attr_opt
|
237
251
|
end
|
252
|
+
end
|
253
|
+
result
|
254
|
+
end
|
255
|
+
|
256
|
+
protected
|
238
257
|
|
239
|
-
|
240
|
-
|
258
|
+
attr_writer :join_points_matched, :join_points_not_matched, :specification, :candidate_types, :candidate_types_excluded, :candidate_objects, :candidate_join_points
|
259
|
+
|
260
|
+
def init_type_specific_specification original_options, options_hash
|
261
|
+
@specification.merge! Pointcut.make_attribute_reading_writing_options(options_hash)
|
262
|
+
# Map the method options to their canonical values:
|
263
|
+
@specification[:method_options] = Aquarium::Finders::MethodFinder.init_method_options(@specification[:method_options])
|
264
|
+
use_default_objects_if_defined unless (types_given? || objects_given?)
|
265
|
+
|
266
|
+
raise Aquarium::Utils::InvalidOptions.new(":all is not yet supported for :attributes.") if @specification[:attributes] == Set.new([:all])
|
267
|
+
if options_hash[:reading] and (options_hash[:writing] or options_hash[:changing])
|
268
|
+
unless options_hash[:reading].eql?(options_hash[:writing]) or options_hash[:reading].eql?(options_hash[:changing])
|
269
|
+
raise Aquarium::Utils::InvalidOptions.new(":reading and :writing/:changing can only be used together if they refer to the same set of attributes.")
|
241
270
|
end
|
242
|
-
|
271
|
+
end
|
272
|
+
init_methods_specification options_hash
|
273
|
+
end
|
274
|
+
|
275
|
+
def init_methods_specification options
|
276
|
+
match_all_methods if ((no_methods_specified and no_attributes_specified) or all_methods_specified)
|
243
277
|
end
|
244
278
|
|
279
|
+
def match_all_methods
|
280
|
+
@specification[:methods] = Set.new([:all])
|
281
|
+
end
|
282
|
+
|
283
|
+
def no_methods_specified
|
284
|
+
@specification[:methods].nil? or @specification[:methods].empty?
|
285
|
+
end
|
286
|
+
|
287
|
+
def all_methods_specified
|
288
|
+
methods_spec = @specification[:methods].to_a
|
289
|
+
methods_spec.include?(:all) or methods_spec.include?(:all_methods)
|
290
|
+
end
|
291
|
+
|
292
|
+
def no_attributes_specified
|
293
|
+
@specification[:attributes].nil? or @specification[:attributes].empty?
|
294
|
+
end
|
295
|
+
|
245
296
|
private
|
246
297
|
|
247
298
|
def init_candidate_types
|
@@ -316,7 +367,7 @@ module Aquarium
|
|
316
367
|
Aquarium::Finders::MethodFinder.new.find type_or_object_sym => candidates.matched_keys,
|
317
368
|
:methods => which_methods,
|
318
369
|
:exclude_methods => @specification[:exclude_methods],
|
319
|
-
:options =>
|
370
|
+
:options => method_options
|
320
371
|
end
|
321
372
|
|
322
373
|
def add_join_points search_results, type_or_object_sym
|
@@ -325,24 +376,36 @@ module Aquarium
|
|
325
376
|
end
|
326
377
|
|
327
378
|
def add_join_points_to which_join_points_list, results_hash, type_or_object_sym
|
328
|
-
instance_method = @specification[:method_options].include?(:class) ? false : true
|
329
379
|
results_hash.each_pair do |type_or_object, method_name_list|
|
330
380
|
method_name_list.each do |method_name|
|
331
381
|
which_join_points_list << Aquarium::Aspects::JoinPoint.new(
|
332
382
|
type_or_object_sym => type_or_object,
|
333
383
|
:method_name => method_name,
|
334
|
-
:instance_method =>
|
384
|
+
:instance_method => is_instance_methods?)
|
335
385
|
end
|
336
386
|
end
|
337
387
|
end
|
338
388
|
|
389
|
+
def is_instance_methods?
|
390
|
+
not @specification[:method_options].include? :class
|
391
|
+
end
|
392
|
+
|
339
393
|
def make_all_method_names
|
340
394
|
@specification[:methods] +
|
341
|
-
|
342
|
-
|
395
|
+
make_attribute_method_names(@specification[:attributes], @specification[:attribute_options]) -
|
396
|
+
@specification[:exclude_methods]
|
343
397
|
end
|
344
398
|
|
345
|
-
def
|
399
|
+
def make_attribute_method_names attribute_name_regexps_or_names, attribute_options = []
|
400
|
+
readers = make_attribute_readers attribute_name_regexps_or_names
|
401
|
+
return readers if read_only attribute_options
|
402
|
+
|
403
|
+
writers = make_attribute_writers readers
|
404
|
+
return writers if write_only attribute_options
|
405
|
+
return readers + writers
|
406
|
+
end
|
407
|
+
|
408
|
+
def make_attribute_readers attributes
|
346
409
|
readers = attributes.map do |regexp_or_name|
|
347
410
|
if regexp_or_name.kind_of? Regexp
|
348
411
|
exp = remove_trailing_equals_and_or_dollar regexp_or_name.source
|
@@ -355,7 +418,7 @@ module Aquarium
|
|
355
418
|
Set.new(readers.sort_by {|exp| exp.to_s})
|
356
419
|
end
|
357
420
|
|
358
|
-
def
|
421
|
+
def make_attribute_writers attributes
|
359
422
|
writers = attributes.map do |regexp_or_name|
|
360
423
|
if regexp_or_name.kind_of? Regexp
|
361
424
|
# remove the "\b$" from the end of the reader expression, if present.
|
@@ -367,11 +430,31 @@ module Aquarium
|
|
367
430
|
Set.new(writers.sort_by {|exp| exp.to_s})
|
368
431
|
end
|
369
432
|
|
370
|
-
def
|
433
|
+
def read_only attribute_options
|
434
|
+
read_option(attribute_options) && !write_option(attribute_options)
|
435
|
+
end
|
436
|
+
|
437
|
+
def write_only attribute_options
|
438
|
+
write_option(attribute_options) && !read_option(attribute_options)
|
439
|
+
end
|
440
|
+
|
441
|
+
def read_option attribute_options
|
442
|
+
attribute_options.include?(:readers) or attribute_options.include?(:reader)
|
443
|
+
end
|
444
|
+
|
445
|
+
def write_option attribute_options
|
446
|
+
attribute_options.include?(:writers) or attribute_options.include?(:writer)
|
447
|
+
end
|
448
|
+
|
449
|
+
def method_options
|
450
|
+
@specification[:method_options].to_a.map {|mo| mo == :all_methods ? :all : mo }
|
451
|
+
end
|
452
|
+
|
453
|
+
def remove_trailing_equals_and_or_dollar exp
|
371
454
|
exp.gsub(/\=?\$?$/, '')
|
372
455
|
end
|
373
456
|
|
374
|
-
def
|
457
|
+
def remove_leading_colon_or_at_sign exp
|
375
458
|
exp.gsub(/^\^?(@|:)/, '')
|
376
459
|
end
|
377
460
|
end
|