aquarium 0.1.6 → 0.1.7
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 +18 -0
- data/README +68 -39
- data/RELEASE-PLAN +25 -1
- data/UPGRADE +4 -0
- data/examples/aspect_design_example.rb +9 -3
- data/examples/aspect_design_example_spec.rb +7 -2
- data/examples/method_tracing_example.rb +1 -1
- data/examples/method_tracing_example_spec.rb +2 -2
- data/lib/aquarium/aspects/aspect.rb +53 -60
- data/lib/aquarium/aspects/dsl/aspect_dsl.rb +0 -1
- data/lib/aquarium/aspects/pointcut.rb +72 -17
- data/lib/aquarium/aspects/pointcut_composition.rb +4 -1
- data/lib/aquarium/extensions/hash.rb +65 -28
- data/lib/aquarium/extensions/set.rb +2 -0
- data/lib/aquarium/finders/finder_result.rb +13 -2
- data/lib/aquarium/finders/method_finder.rb +54 -28
- data/lib/aquarium/finders/type_finder.rb +36 -19
- data/lib/aquarium/utils/method_utils.rb +3 -12
- data/lib/aquarium/utils/name_utils.rb +27 -1
- data/lib/aquarium/version.rb +1 -1
- data/spec/aquarium/aspects/aspect_invocation_spec.rb +182 -51
- data/spec/aquarium/aspects/aspect_spec.rb +43 -8
- data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +32 -3
- data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +36 -5
- data/spec/aquarium/aspects/pointcut_spec.rb +373 -99
- data/spec/aquarium/extensions/hash_spec.rb +129 -38
- data/spec/aquarium/finders/finder_result_spec.rb +73 -15
- data/spec/aquarium/finders/method_finder_spec.rb +156 -72
- data/spec/aquarium/finders/object_finder_spec.rb +1 -0
- data/spec/aquarium/finders/type_finder_spec.rb +43 -0
- data/spec/aquarium/utils/name_utils_spec.rb +79 -4
- metadata +3 -3
@@ -48,11 +48,11 @@ module Aquarium
|
|
48
48
|
# <tt>:method => method || [method_list]</tt>::
|
49
49
|
# One or an array of methods, method names and/or method regular expessions to match.
|
50
50
|
# By default, unless :attributes are specified, searches for public instance methods
|
51
|
-
# with the method option :
|
51
|
+
# with the method option :exclude_ancestor_methods implied, unless explicit method
|
52
52
|
# options are given.
|
53
53
|
#
|
54
54
|
# <tt>:method_options => [options]</tt>::
|
55
|
-
# One or more options supported by Aquarium::Finders::MethodFinder. The :
|
55
|
+
# One or more options supported by Aquarium::Finders::MethodFinder. The :exclude_ancestor_methods
|
56
56
|
# option is most useful.
|
57
57
|
#
|
58
58
|
# <tt>:attributes => attribute || [attribute_list]</tt>::
|
@@ -88,8 +88,7 @@ module Aquarium
|
|
88
88
|
join_points_not_matched == other.join_points_not_matched)
|
89
89
|
end
|
90
90
|
|
91
|
-
alias :==
|
92
|
-
alias :=== :eql?
|
91
|
+
alias :== :eql?
|
93
92
|
|
94
93
|
def empty?
|
95
94
|
return join_points_matched.empty? && join_points_not_matched.empty?
|
@@ -123,6 +122,10 @@ module Aquarium
|
|
123
122
|
@specification[:types] = Set.new(make_array(options[:types], options[:type]))
|
124
123
|
@specification[:objects] = Set.new(make_array(options[:objects], options[:object]))
|
125
124
|
@specification[:join_points] = Set.new(make_array(options[:join_points], options[:join_point]))
|
125
|
+
@specification[:exclude_types] = Set.new(make_array(options[:exclude_type], options[:exclude_types]))
|
126
|
+
@specification[:exclude_objects] = Set.new(make_array(options[:exclude_object], options[:exclude_objects]))
|
127
|
+
@specification[:exclude_join_points] = Set.new(make_array(options[:exclude_join_point], options[:exclude_join_points]))
|
128
|
+
@specification[:exclude_methods] = Set.new(make_array(options[:exclude_method], options[:exclude_methods]))
|
126
129
|
@specification[:default_object] = Set.new(make_array(options[:default_object]))
|
127
130
|
use_default_object_if_defined unless (types_given? || objects_given?)
|
128
131
|
@specification[:attributes] = Set.new(make_array(options[:attributes], options[:attribute]))
|
@@ -136,7 +139,10 @@ module Aquarium
|
|
136
139
|
end
|
137
140
|
|
138
141
|
def validate_options options
|
139
|
-
knowns = %w[object objects type types join_point join_points
|
142
|
+
knowns = %w[object objects type types join_point join_points
|
143
|
+
exclude_object exclude_objects exclude_type exclude_types exclude_join_point exclude_join_points exclude_method exclude_methods
|
144
|
+
method methods attribute attributes
|
145
|
+
method_options attribute_options default_object].map {|x| x.intern}
|
140
146
|
unknowns = options.keys - knowns
|
141
147
|
raise Aquarium::Utils::InvalidOptions.new("Unknown options specified: #{unknowns.inspect}") if unknowns.size > 0
|
142
148
|
end
|
@@ -169,19 +175,38 @@ module Aquarium
|
|
169
175
|
EOF
|
170
176
|
end
|
171
177
|
|
178
|
+
%w[types objects join_points methods].each do |name|
|
179
|
+
class_eval(<<-EOF, __FILE__, __LINE__)
|
180
|
+
def exclude_#{name}_given
|
181
|
+
@specification[:exclude_#{name}]
|
182
|
+
end
|
183
|
+
|
184
|
+
def exclude_#{name}_given?
|
185
|
+
not (exclude_#{name}_given.nil? or exclude_#{name}_given.empty?)
|
186
|
+
end
|
187
|
+
EOF
|
188
|
+
end
|
189
|
+
|
172
190
|
private
|
173
191
|
|
174
192
|
def init_candidate_types
|
175
193
|
explicit_types, type_regexps_or_names = @specification[:types].partition do |type|
|
176
|
-
is_type? type
|
194
|
+
Aquarium::Utils::TypeUtils.is_type? type
|
195
|
+
end
|
196
|
+
excluded_explicit_types, excluded_type_regexps_or_names = @specification[:exclude_types].partition do |type|
|
197
|
+
Aquarium::Utils::TypeUtils.is_type? type
|
177
198
|
end
|
178
|
-
|
179
|
-
|
199
|
+
possible_types = Aquarium::Finders::TypeFinder.new.find :types => type_regexps_or_names, :exclude_types => excluded_type_regexps_or_names
|
200
|
+
possible_types.append_matched(make_hash(explicit_types) {|x| Set.new([])})
|
201
|
+
@candidate_types = possible_types - Aquarium::Finders::TypeFinder.new.find(:types => excluded_type_regexps_or_names)
|
202
|
+
@candidate_types.matched.delete_if {|type, value| excluded_explicit_types.include? type}
|
180
203
|
end
|
181
204
|
|
182
205
|
def init_candidate_objects
|
183
206
|
object_hash = {}
|
184
|
-
@specification[:objects].
|
207
|
+
(@specification[:objects].flatten - @specification[:exclude_objects].flatten).each do |o|
|
208
|
+
object_hash[o] = Set.new([])
|
209
|
+
end
|
185
210
|
@candidate_objects = Aquarium::Finders::FinderResult.new object_hash
|
186
211
|
end
|
187
212
|
|
@@ -204,12 +229,10 @@ module Aquarium
|
|
204
229
|
add_join_points_for_candidate_join_points
|
205
230
|
end
|
206
231
|
|
207
|
-
def is_type? candidate_type
|
208
|
-
candidate_type.kind_of?(Module) || candidate_type.kind_of?(Class)
|
209
|
-
end
|
210
|
-
|
211
232
|
def add_join_points_for_candidate_join_points
|
212
|
-
@join_points_matched
|
233
|
+
@join_points_matched += @candidate_join_points.matched.keys.find_all do |jp|
|
234
|
+
not (is_excluded_join_point?(jp) or is_excluded_type_or_object?(jp.type_or_object) or is_excluded_method?(jp.method_name))
|
235
|
+
end
|
213
236
|
@join_points_not_matched += @candidate_join_points.not_matched.keys
|
214
237
|
end
|
215
238
|
|
@@ -221,8 +244,9 @@ module Aquarium
|
|
221
244
|
def find_methods_for type_or_object_sym, candidates, which_methods
|
222
245
|
return Aquarium::Finders::FinderResult::NIL_OBJECT if candidates.matched.size == 0
|
223
246
|
Aquarium::Finders::MethodFinder.new.find type_or_object_sym => candidates.matched_keys,
|
224
|
-
|
225
|
-
|
247
|
+
:methods => which_methods,
|
248
|
+
:exclude_methods => @specification[:exclude_methods],
|
249
|
+
:options => @specification[:method_options].to_a
|
226
250
|
end
|
227
251
|
|
228
252
|
def add_join_points search_results, type_or_object_sym
|
@@ -243,9 +267,40 @@ module Aquarium
|
|
243
267
|
end
|
244
268
|
|
245
269
|
def make_all_method_names
|
246
|
-
@specification[:methods] +
|
270
|
+
@specification[:methods] +
|
271
|
+
Pointcut.make_attribute_method_names(@specification[:attributes], @specification[:attribute_options]) -
|
272
|
+
@specification[:exclude_methods]
|
247
273
|
end
|
248
274
|
|
275
|
+
def is_excluded_join_point? jp
|
276
|
+
@specification[:exclude_join_points].include? jp
|
277
|
+
end
|
278
|
+
|
279
|
+
def is_excluded_type_or_object? type_or_object
|
280
|
+
return true if @specification[:exclude_objects].include?(type_or_object)
|
281
|
+
@specification[:exclude_types].find do |t|
|
282
|
+
case t
|
283
|
+
when String: type_or_object.name.eql?(t)
|
284
|
+
when Symbol: type_or_object.name.eql?(t.to_s)
|
285
|
+
when Regexp: type_or_object.name =~ t
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def is_excluded_method? method
|
291
|
+
is_explicitly_excluded_method?(method) or matches_excluded_method_regex?(method)
|
292
|
+
end
|
293
|
+
|
294
|
+
def is_explicitly_excluded_method? method
|
295
|
+
@specification[:exclude_methods].include? method
|
296
|
+
end
|
297
|
+
|
298
|
+
def matches_excluded_method_regex? method
|
299
|
+
regexs = @specification[:exclude_methods].find_all {|s| s.kind_of? Regexp}
|
300
|
+
return false if regexs.empty?
|
301
|
+
regexs.find {|re| method.to_s =~ re}
|
302
|
+
end
|
303
|
+
|
249
304
|
def self.make_attribute_readers attributes
|
250
305
|
readers = attributes.map do |regexp_or_name|
|
251
306
|
if regexp_or_name.kind_of? Regexp
|
@@ -19,11 +19,13 @@ class Aquarium::Aspects::Pointcut
|
|
19
19
|
end
|
20
20
|
|
21
21
|
alias :union :or
|
22
|
+
alias :| :or
|
22
23
|
|
23
24
|
def and pointcut2
|
24
25
|
result = Aquarium::Aspects::Pointcut.new
|
25
26
|
result.specification = specification.and(pointcut2.specification) do |value1, value2|
|
26
|
-
value1
|
27
|
+
value1 & value2
|
28
|
+
# value1.intersection_using_eql_comparison value2
|
27
29
|
end
|
28
30
|
result.join_points_matched = join_points_matched.intersection_using_eql_comparison pointcut2.join_points_matched
|
29
31
|
result.join_points_not_matched = join_points_not_matched.intersection_using_eql_comparison pointcut2.join_points_not_matched
|
@@ -33,4 +35,5 @@ class Aquarium::Aspects::Pointcut
|
|
33
35
|
end
|
34
36
|
|
35
37
|
alias :intersection :and
|
38
|
+
alias :& :and
|
36
39
|
end
|
@@ -4,49 +4,86 @@ module Aquarium
|
|
4
4
|
module Extensions
|
5
5
|
module HashHelper
|
6
6
|
|
7
|
-
|
8
|
-
# If the same key is present in both, but the values are
|
9
|
-
# not "==" or "eql?", then the optional block is invoked to compute the intersection
|
10
|
-
# of the two values. If no block is given, it is assumed that the two key-value pairs
|
11
|
-
# should not be considered overlapping.
|
12
|
-
def intersection other_hash
|
7
|
+
def and other_hash
|
13
8
|
return {} if other_hash.nil? or other_hash.empty?
|
14
9
|
keys2 = Set.new(self.keys).intersection(Set.new(other_hash.keys))
|
15
10
|
result = {}
|
16
11
|
keys2.each do |key|
|
17
|
-
|
18
|
-
|
19
|
-
if
|
20
|
-
result[key] =
|
21
|
-
|
22
|
-
result[key] =
|
12
|
+
value1 = self[key]
|
13
|
+
value2 = other_hash[key]
|
14
|
+
if block_given?
|
15
|
+
result[key] = yield value1, value2
|
16
|
+
elsif value1 == value2 or value1.eql?(value2)
|
17
|
+
result[key] = value1
|
18
|
+
elsif value1.class == value2.class && value1.respond_to?(:&)
|
19
|
+
result[key] = (value1 & value2)
|
23
20
|
end
|
24
21
|
end
|
25
22
|
result
|
26
23
|
end
|
27
24
|
|
28
|
-
alias :and
|
25
|
+
alias :intersection :and
|
26
|
+
alias :& :and
|
29
27
|
|
30
|
-
# Union of self with a second hash, which returns a new hash.
|
31
|
-
#
|
32
|
-
# block
|
33
|
-
#
|
34
|
-
def
|
28
|
+
# Union of self with a second hash, which returns a new hash. It's different from
|
29
|
+
# Hash#merge in that it attempts to merge non-equivalent values for the same key,
|
30
|
+
# using a block, if given, or if they are of the same type and respond to #|, using
|
31
|
+
# #| to merge the two values. Otherwise, it behaves like Hash#merge.
|
32
|
+
def or other_hash
|
33
|
+
return self if other_hash.nil?
|
35
34
|
result = {}
|
36
|
-
self.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
new_keys = self.keys | other_hash.keys
|
36
|
+
new_keys.each do |key|
|
37
|
+
value1 = self[key]
|
38
|
+
value2 = other_hash[key]
|
39
|
+
if block_given?
|
40
|
+
result[key] = yield value1, value2
|
41
|
+
elsif value1.nil? and not value2.nil?
|
42
|
+
result[key] = value2
|
43
|
+
elsif (not value1.nil?) and value2.nil?
|
44
|
+
result[key] = value1
|
45
|
+
elsif value1 == value2 or value1.eql?(value2)
|
46
|
+
result[key] = value1
|
47
|
+
elsif value1.class == value2.class && value1.respond_to?(:|)
|
48
|
+
result[key] = (value1 | value2)
|
49
|
+
else # Hash#merge behavior
|
50
|
+
result[key] = value2
|
43
51
|
end
|
44
52
|
end
|
45
53
|
result
|
46
54
|
end
|
55
|
+
|
56
|
+
alias :union :or
|
57
|
+
alias :| :or
|
47
58
|
|
48
|
-
|
49
|
-
|
59
|
+
def minus other_hash
|
60
|
+
result = self.dup
|
61
|
+
return result if other_hash.nil? or other_hash.empty?
|
62
|
+
result.each do |key, value|
|
63
|
+
if other_hash.include?(key)
|
64
|
+
value1 = self[key]
|
65
|
+
value2 = other_hash[key]
|
66
|
+
if block_given?
|
67
|
+
result[key] = yield value1, value2
|
68
|
+
elsif value2.nil?
|
69
|
+
# do nothing
|
70
|
+
elsif value1 == value2 or value1.eql?(value2)
|
71
|
+
result.delete key
|
72
|
+
elsif value1.class == value2.class && value1.respond_to?(:-)
|
73
|
+
result[key] = (value1 - value2)
|
74
|
+
else # Hash#merge behavior
|
75
|
+
result.delete key
|
76
|
+
end
|
77
|
+
elsif block_given?
|
78
|
+
# Since the block might change the value's type (e.g., [] => Set...)
|
79
|
+
result[key] = yield result[key], nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
result
|
83
|
+
end
|
84
|
+
|
85
|
+
alias :- :minus
|
86
|
+
|
50
87
|
# It appears that Hash#== uses Object#== (i.e., self.object_id == other.object_id) when
|
51
88
|
# comparing hash keys. (Array#== uses the overridden #== for the elements.)
|
52
89
|
def eql_when_keys_compared? other
|
@@ -61,7 +98,7 @@ module Aquarium
|
|
61
98
|
end
|
62
99
|
true
|
63
100
|
end
|
64
|
-
|
101
|
+
|
65
102
|
def equivalent_key key
|
66
103
|
i = keys.index(key)
|
67
104
|
i.nil? ? nil : keys[i]
|
@@ -13,12 +13,14 @@ class Set
|
|
13
13
|
|
14
14
|
alias :eql? :==
|
15
15
|
|
16
|
+
# It seems that Set#| should work, but for some reason, it doesn't.
|
16
17
|
def union_using_eql_comparison other
|
17
18
|
first = dup
|
18
19
|
second = other.dup
|
19
20
|
first.size > second.size ? do_union(first, second) : do_union(second, first)
|
20
21
|
end
|
21
22
|
|
23
|
+
# It seems that Set#& should work, but for some reason, it doesn't.
|
22
24
|
def intersection_using_eql_comparison other
|
23
25
|
first = dup
|
24
26
|
second = other.dup
|
@@ -57,6 +57,7 @@ module Aquarium
|
|
57
57
|
end
|
58
58
|
|
59
59
|
alias :union :or
|
60
|
+
alias :| :or
|
60
61
|
|
61
62
|
# "And" two results together
|
62
63
|
def and other_result
|
@@ -67,7 +68,17 @@ module Aquarium
|
|
67
68
|
end
|
68
69
|
|
69
70
|
alias :intersection :and
|
71
|
+
alias :& :and
|
70
72
|
|
73
|
+
def minus other_result
|
74
|
+
result = FinderResult.new
|
75
|
+
result.matched = matched - other_result.matched
|
76
|
+
result.not_matched = not_matched - other_result.not_matched
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
alias :- :minus
|
81
|
+
|
71
82
|
def append_matched other_hash = {}
|
72
83
|
@matched = convert_hash_values_to_sets hash_union(matched, other_hash)
|
73
84
|
end
|
@@ -105,7 +116,7 @@ module Aquarium
|
|
105
116
|
def hash_intersection hash1, hash2
|
106
117
|
return {} if hash1.nil? or hash2.nil?
|
107
118
|
hash1.intersection(hash2) do |value1, value2|
|
108
|
-
make_set(value1)
|
119
|
+
make_set(value1) & (make_set(value2))
|
109
120
|
end
|
110
121
|
end
|
111
122
|
|
@@ -113,7 +124,7 @@ module Aquarium
|
|
113
124
|
return hash1 if hash2.nil? or hash2.empty?
|
114
125
|
return hash2 if hash1.nil? or hash1.empty?
|
115
126
|
hash1.union(hash2) do |value1, value2|
|
116
|
-
make_set(value1)
|
127
|
+
make_set(value1) | (make_set(value2))
|
117
128
|
end
|
118
129
|
end
|
119
130
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'set'
|
2
2
|
require File.dirname(__FILE__) + '/../utils/array_utils'
|
3
3
|
require File.dirname(__FILE__) + '/../utils/invalid_options'
|
4
|
+
require File.dirname(__FILE__) + '/../utils/type_utils'
|
4
5
|
require File.dirname(__FILE__) + '/finder_result'
|
5
6
|
|
6
7
|
# Find methods and types and objects.
|
@@ -34,6 +35,11 @@ module Aquarium
|
|
34
35
|
# One or more method names and regular expressions to match.
|
35
36
|
# Specify one or an array of values.
|
36
37
|
#
|
38
|
+
# <tt>:exclude_methods => method_names_and_regexps</tt>::
|
39
|
+
# <tt>:exclude_method => method_names_and_regexps</tt>::
|
40
|
+
# One or more method names and regular expressions to exclude from the match.
|
41
|
+
# Specify one or an array of values.
|
42
|
+
#
|
37
43
|
# <tt>:options => method_options</tt>::
|
38
44
|
# By default, searches for public instance methods. Specify one or more
|
39
45
|
# of the following options for alternatives. You can combine any of the
|
@@ -48,30 +54,38 @@ module Aquarium
|
|
48
54
|
# <tt>:singleton</tt>:: Search for singleton methods. (Using :class for objects
|
49
55
|
# won't work and :class, :public, :protected, and :private are ignored when
|
50
56
|
# looking for singleton methods.)
|
51
|
-
# <tt>:
|
57
|
+
# <tt>:exclude_ancestor_methods</tt>:: Suppress "ancestor" methods. This
|
52
58
|
# means that if you search for a override method +foo+ in a
|
53
59
|
# +Derived+ class that is defined in the +Base+ class, you won't find it!
|
54
60
|
#
|
55
61
|
def find options = {}
|
56
62
|
init_specification options
|
63
|
+
return Aquarium::Finders::FinderResult.new if nothing_to_find?
|
57
64
|
types_and_objects = input_types + input_objects
|
58
|
-
return Aquarium::Finders::FinderResult.new if types_and_objects.empty?
|
59
65
|
method_names_or_regexps = input_methods
|
60
66
|
if method_names_or_regexps.empty?
|
61
67
|
not_matched = {}
|
62
68
|
types_and_objects.each {|t| not_matched[t] = []}
|
63
69
|
return Aquarium::Finders::FinderResult.new(:not_matched => not_matched)
|
64
70
|
end
|
65
|
-
|
66
|
-
|
71
|
+
result = do_find_all_by types_and_objects, method_names_or_regexps
|
72
|
+
unless (input_exclude_methods.nil? or input_exclude_methods.empty?)
|
73
|
+
result -= do_find_all_by types_and_objects, input_exclude_methods
|
74
|
+
end
|
75
|
+
result
|
67
76
|
end
|
68
77
|
|
69
78
|
# finder_result = MethodFinder.new.find_all_by types_and_objects, [methods, [options]]
|
70
79
|
# where if no +methods+ are specified, all are returned, subject to the +options+,
|
71
80
|
# as in #find.
|
81
|
+
# Note: Does not support the :exclude_method(s) options.
|
72
82
|
def find_all_by types_and_objects, method_names_or_regexps = :all, *scope_options
|
73
|
-
return Aquarium::Finders::FinderResult.new if types_and_objects.nil?
|
74
|
-
@specification =
|
83
|
+
return Aquarium::Finders::FinderResult.new if types_and_objects.nil?
|
84
|
+
@specification = { :options => init_method_options(scope_options) }
|
85
|
+
do_find_all_by types_and_objects, method_names_or_regexps
|
86
|
+
end
|
87
|
+
|
88
|
+
def do_find_all_by types_and_objects, method_names_or_regexps
|
75
89
|
types_and_objects = make_array types_and_objects
|
76
90
|
names_or_regexps = make_methods_array method_names_or_regexps
|
77
91
|
types_and_objects_to_matched_methods = {}
|
@@ -84,7 +98,7 @@ module Aquarium
|
|
84
98
|
reflection_method_names.each do |reflect|
|
85
99
|
method_array += reflect_methods(type_or_object, reflect).grep(make_regexp(name_or_regexp))
|
86
100
|
end
|
87
|
-
if
|
101
|
+
if exclude_ancestor_methods?
|
88
102
|
method_array = remove_ancestor_methods type_or_object, reflection_method_names, method_array
|
89
103
|
end
|
90
104
|
found_methods += method_array
|
@@ -99,20 +113,27 @@ module Aquarium
|
|
99
113
|
end
|
100
114
|
|
101
115
|
NIL_OBJECT = MethodFinder.new unless const_defined?(:NIL_OBJECT)
|
116
|
+
|
117
|
+
RECOGNIZED_METHOD_OPTIONS = %w[public private protected
|
118
|
+
instance class exclude_ancestor_methods exclude_ancestor_methods]
|
102
119
|
|
103
120
|
def self.is_recognized_method_option string_or_symbol
|
104
|
-
|
105
|
-
instance class suppress_ancestor_methods].include? string_or_symbol.to_s
|
121
|
+
RECOGNIZED_METHOD_OPTIONS.include? string_or_symbol.to_s
|
106
122
|
end
|
107
123
|
|
108
124
|
protected
|
109
125
|
|
110
126
|
def init_specification options
|
111
|
-
options[:options] =
|
127
|
+
options[:options] = init_method_options(options[:options])
|
112
128
|
validate options
|
113
129
|
@specification = options
|
114
130
|
end
|
115
131
|
|
132
|
+
def nothing_to_find?
|
133
|
+
types_and_objects = input_types + input_objects
|
134
|
+
types_and_objects.nil? or types_and_objects.empty? or input_exclude_methods.include?(:all)
|
135
|
+
end
|
136
|
+
|
116
137
|
def input_types
|
117
138
|
make_array @specification[:types], @specification[:type]
|
118
139
|
end
|
@@ -125,6 +146,14 @@ module Aquarium
|
|
125
146
|
make_array @specification[:methods], @specification[:method]
|
126
147
|
end
|
127
148
|
|
149
|
+
def input_exclude_methods
|
150
|
+
make_array @specification[:exclude_methods], @specification[:exclude_method]
|
151
|
+
end
|
152
|
+
|
153
|
+
def exclude_ancestor_methods?
|
154
|
+
@specification[:options].include?(:exclude_ancestor_methods) or @specification[:options].include?(:suppress_ancestor_methods)
|
155
|
+
end
|
156
|
+
|
128
157
|
private
|
129
158
|
|
130
159
|
def make_methods_array *array_or_single_item
|
@@ -139,7 +168,7 @@ module Aquarium
|
|
139
168
|
|
140
169
|
def remove_ancestor_methods type_or_object, reflection_method_names, method_array
|
141
170
|
type = type_or_object
|
142
|
-
unless (
|
171
|
+
unless (Aquarium::Utils::TypeUtils.is_type? type_or_object)
|
143
172
|
type = type_or_object.class
|
144
173
|
# Must recalc reflect methods if we've switched to the type of the input object.
|
145
174
|
reflection_method_names = make_methods_reflection_method_names type, "methods"
|
@@ -156,21 +185,18 @@ module Aquarium
|
|
156
185
|
method_array
|
157
186
|
end
|
158
187
|
|
159
|
-
def
|
160
|
-
return
|
161
|
-
options =
|
162
|
-
|
163
|
-
unless options[:class] || options[:instance] || options[:singleton]
|
164
|
-
options[:instance] = ''
|
165
|
-
end
|
188
|
+
def init_method_options *scope_options
|
189
|
+
return [] if scope_options.nil?
|
190
|
+
options = scope_options.flatten
|
191
|
+
options << :instance unless options.include?(:class) or options.include?(:instance) or options.include?(:singleton)
|
166
192
|
options
|
167
193
|
end
|
168
194
|
|
169
195
|
def make_methods_reflection_method_names type_or_object, root_method_name
|
170
|
-
is_type =
|
196
|
+
is_type = Aquarium::Utils::TypeUtils.is_type?(type_or_object)
|
171
197
|
scope_prefixes = []
|
172
198
|
class_instance_prefixes = []
|
173
|
-
@specification.each do |opt, value|
|
199
|
+
@specification[:options].each do |opt, value|
|
174
200
|
opt_string = opt.to_s
|
175
201
|
case opt_string
|
176
202
|
when "public", "private", "protected"
|
@@ -178,7 +204,7 @@ module Aquarium
|
|
178
204
|
when "instance"
|
179
205
|
class_instance_prefixes += is_type ? [opt_string + "_"] : [""]
|
180
206
|
when "class"
|
181
|
-
# We want to use the "bare" (
|
207
|
+
# We want to use the "bare" (public|private)_<root_method_name> calls
|
182
208
|
# to get class methods, because we will invoke these methods on class objects!
|
183
209
|
# For instances, class methods aren't supported.
|
184
210
|
class_instance_prefixes += [""] if is_type
|
@@ -200,18 +226,18 @@ module Aquarium
|
|
200
226
|
results
|
201
227
|
end
|
202
228
|
|
203
|
-
def reflect_methods
|
204
|
-
if
|
205
|
-
eval "#{
|
229
|
+
def reflect_methods object, reflect_method
|
230
|
+
if object.kind_of?(String) or object.kind_of?(Symbol)
|
231
|
+
eval "#{object.to_s}.#{reflect_method}"
|
206
232
|
else
|
207
|
-
return [] unless
|
208
|
-
|
209
|
-
|
233
|
+
return [] unless object.respond_to? reflect_method
|
234
|
+
method = object.method reflect_method
|
235
|
+
method.call object
|
210
236
|
end
|
211
237
|
end
|
212
238
|
|
213
239
|
def validate options
|
214
|
-
allowed = %w[type types object objects method methods
|
240
|
+
allowed = (%w[type types object objects method methods exclude_method exclude_methods options] + RECOGNIZED_METHOD_OPTIONS).map {|x| x.intern}
|
215
241
|
okay, bad = options.keys.partition {|x| allowed.include?(x)}
|
216
242
|
raise Aquarium::Utils::InvalidOptions.new("Unrecognized option(s): #{bad.inspect}") unless bad.empty?
|
217
243
|
method_options = options[:options]
|