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.
Files changed (32) hide show
  1. data/CHANGES +18 -0
  2. data/README +68 -39
  3. data/RELEASE-PLAN +25 -1
  4. data/UPGRADE +4 -0
  5. data/examples/aspect_design_example.rb +9 -3
  6. data/examples/aspect_design_example_spec.rb +7 -2
  7. data/examples/method_tracing_example.rb +1 -1
  8. data/examples/method_tracing_example_spec.rb +2 -2
  9. data/lib/aquarium/aspects/aspect.rb +53 -60
  10. data/lib/aquarium/aspects/dsl/aspect_dsl.rb +0 -1
  11. data/lib/aquarium/aspects/pointcut.rb +72 -17
  12. data/lib/aquarium/aspects/pointcut_composition.rb +4 -1
  13. data/lib/aquarium/extensions/hash.rb +65 -28
  14. data/lib/aquarium/extensions/set.rb +2 -0
  15. data/lib/aquarium/finders/finder_result.rb +13 -2
  16. data/lib/aquarium/finders/method_finder.rb +54 -28
  17. data/lib/aquarium/finders/type_finder.rb +36 -19
  18. data/lib/aquarium/utils/method_utils.rb +3 -12
  19. data/lib/aquarium/utils/name_utils.rb +27 -1
  20. data/lib/aquarium/version.rb +1 -1
  21. data/spec/aquarium/aspects/aspect_invocation_spec.rb +182 -51
  22. data/spec/aquarium/aspects/aspect_spec.rb +43 -8
  23. data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +32 -3
  24. data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +36 -5
  25. data/spec/aquarium/aspects/pointcut_spec.rb +373 -99
  26. data/spec/aquarium/extensions/hash_spec.rb +129 -38
  27. data/spec/aquarium/finders/finder_result_spec.rb +73 -15
  28. data/spec/aquarium/finders/method_finder_spec.rb +156 -72
  29. data/spec/aquarium/finders/object_finder_spec.rb +1 -0
  30. data/spec/aquarium/finders/type_finder_spec.rb +43 -0
  31. data/spec/aquarium/utils/name_utils_spec.rb +79 -4
  32. metadata +3 -3
@@ -59,7 +59,6 @@ module Aquarium
59
59
  opts
60
60
  end
61
61
  end
62
-
63
62
  end
64
63
  end
65
64
  end
@@ -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 :suppress_ancestor_methods implied, unless explicit method
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 :suppress_ancestor_methods
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 :== :eql?
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 method methods attribute attributes method_options attribute_options default_object].map {|x| x.intern}
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
- @candidate_types = Aquarium::Finders::TypeFinder.new.find :types => type_regexps_or_names
179
- @candidate_types.append_matched(make_hash(explicit_types) {|x| Set.new([])}) # Append already-known types
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].each {|o| object_hash[o] = Set.new([])}
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 += @candidate_join_points.matched.keys
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
- :methods => which_methods,
225
- :options => @specification[:method_options].to_a
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] + Pointcut.make_attribute_method_names(@specification[:attributes], @specification[:attribute_options])
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.intersection_using_eql_comparison value2
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
- # Intersection of self with a second hash, which returns a new hash.
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
- values1 = self[key]
18
- values2 = other_hash[key]
19
- if values1 == values2 or values1.eql?(values2)
20
- result[key] = values1
21
- else block_given?
22
- result[key] = yield values1, values2
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 :intersection
25
+ alias :intersection :and
26
+ alias :& :and
29
27
 
30
- # Union of self with a second hash, which returns a new hash. If both hashes have
31
- # the same key, the value will be the result of evaluating the given block. If no
32
- # block is given, the result will be same behavior that "merge" provides; the
33
- # value in the second hash "wins".
34
- def union other_hash
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.each {|key, value| result[key] = value}
37
- return result if other_hash.nil? or other_hash.empty?
38
- other_hash.each do |key, value|
39
- if result[key].nil? or ! block_given?
40
- result[key] = value
41
- else
42
- result[key] = yield result[key], value
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
- alias :or :union
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).intersection_using_eql_comparison(make_set(value2))
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).union_using_eql_comparison(make_set(value2))
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>:suppress_ancestor_methods</tt>:: Suppress "ancestor" methods. This
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
- method_options = make_array options[:options]
66
- find_all_by types_and_objects, method_names_or_regexps, method_options
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 = make_options_hash scope_options
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 @specification[:suppress_ancestor_methods]
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
- %w[public private protected
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] = make_array(options[:options]) unless options[:options].nil?
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 (type_or_object.instance_of?(Class) or type_or_object.instance_of?(Module))
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 make_options_hash *scope_options
160
- return {} if scope_options.nil?
161
- options = {}
162
- scope_options.flatten.each {|o| options[o] = '' unless o.nil?}
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 = type_or_object.instance_of?(Class) || type_or_object.instance_of?(Module)
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" (public_|private_|)<root_method_name> calls
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 type_or_object, reflect_method
204
- if type_or_object.kind_of?(String) or type_or_object.kind_of?(Symbol)
205
- eval "#{type_or_object.to_s}.#{reflect_method}"
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 type_or_object.respond_to? reflect_method
208
- m = type_or_object.method reflect_method
209
- m.call type_or_object
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 options class instance public private protected suppress_ancestor_methods].map {|x| x.intern}
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]