aquarium 0.2.0 → 0.3.0
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/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
|