aquarium 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- 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]
|