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
@@ -2,6 +2,7 @@ require 'set'
|
|
2
2
|
require File.dirname(__FILE__) + '/../utils/array_utils'
|
3
3
|
require File.dirname(__FILE__) + '/../utils/invalid_options'
|
4
4
|
require File.dirname(__FILE__) + '/../utils/type_utils'
|
5
|
+
require File.dirname(__FILE__) + '/../utils/options_utils'
|
5
6
|
require File.dirname(__FILE__) + '/finder_result'
|
6
7
|
|
7
8
|
# Find methods and types and objects.
|
@@ -9,6 +10,7 @@ module Aquarium
|
|
9
10
|
module Finders
|
10
11
|
class MethodFinder
|
11
12
|
include Aquarium::Utils::ArrayUtils
|
13
|
+
include Aquarium::Utils::OptionsUtils
|
12
14
|
|
13
15
|
# Returns a Aquarium::Finders::FinderResult for the hash of types, type names, and/or regular expressions
|
14
16
|
# and the corresponding method name <b>symbols</b> found.
|
@@ -21,37 +23,66 @@ module Aquarium
|
|
21
23
|
#
|
22
24
|
# <tt>:types => types_and_type_names_and_regexps</tt>::
|
23
25
|
# <tt>:type => types_and_type_names_and_regexps</tt>::
|
26
|
+
# <tt>:for_types => types_and_type_names_and_regexps</tt>::
|
27
|
+
# <tt>:for_type => types_and_type_names_and_regexps</tt>::
|
28
|
+
# <tt>:on_types => types_and_type_names_and_regexps</tt>::
|
29
|
+
# <tt>:on_type => types_and_type_names_and_regexps</tt>::
|
30
|
+
# <tt>:in_types => types_and_type_names_and_regexps</tt>::
|
31
|
+
# <tt>:in_type => types_and_type_names_and_regexps</tt>::
|
32
|
+
# <tt>:within_types => types_and_type_names_and_regexps</tt>::
|
33
|
+
# <tt>:within_type => types_and_type_names_and_regexps</tt>::
|
24
34
|
# One or more types, type names and/or regular expessions to match.
|
25
35
|
# Specify one or an array of values.
|
26
36
|
#
|
27
37
|
# <tt>:objects => objects</tt>::
|
28
38
|
# <tt>:object => objects</tt>::
|
39
|
+
# <tt>:for_objects => objects</tt>::
|
40
|
+
# <tt>:for_object => objects</tt>::
|
41
|
+
# <tt>:on_objects => objects</tt>::
|
42
|
+
# <tt>:on_object => objects</tt>::
|
43
|
+
# <tt>:in_objects => objects</tt>::
|
44
|
+
# <tt>:in_object => objects</tt>::
|
45
|
+
# <tt>:within_objects => objects</tt>::
|
46
|
+
# <tt>:within_object => objects</tt>::
|
29
47
|
# One or more objects to match.
|
30
48
|
# Specify one or an array of values.
|
31
49
|
# Note: Currently, string or symbol objects will be misinterpreted as type names!
|
32
50
|
#
|
33
51
|
# <tt>:methods => method_names_and_regexps</tt>::
|
34
52
|
# <tt>:method => method_names_and_regexps</tt>::
|
53
|
+
# <tt>:within_methods => method_names_and_regexps</tt>::
|
54
|
+
# <tt>:within_method => method_names_and_regexps</tt>::
|
55
|
+
# <tt>:calling => method_names_and_regexps</tt>::
|
56
|
+
# <tt>:invoking => method_names_and_regexps</tt>::
|
57
|
+
# <tt>:calls_to => method_names_and_regexps</tt>::
|
58
|
+
# <tt>:sending_message_to => method_names_and_regexps</tt>::
|
59
|
+
# <tt>:sending_messages_to => method_names_and_regexps</tt>::
|
35
60
|
# One or more method names and regular expressions to match.
|
36
|
-
# Specify one or an array of values.
|
61
|
+
# Specify one or an array of values. If :all or :all_methods is specified, all
|
62
|
+
# methods will be matched. That is, these special values are equivalent to the
|
63
|
+
# the regular expression /.+/.
|
37
64
|
#
|
38
65
|
# <tt>:exclude_methods => method_names_and_regexps</tt>::
|
39
66
|
# <tt>:exclude_method => method_names_and_regexps</tt>::
|
67
|
+
# <tt>:exclude_<other_method_synonyms> => method_names_and_regexps</tt>::
|
40
68
|
# One or more method names and regular expressions to exclude from the match.
|
41
69
|
# Specify one or an array of values.
|
42
70
|
#
|
43
71
|
# <tt>:options => method_options</tt>::
|
72
|
+
# <tt>:method_options => method_options</tt>::
|
73
|
+
# <tt>:method_option => method_options</tt>::
|
74
|
+
# <tt>:restricting_methods_to => method_options</tt>::
|
44
75
|
# By default, searches for public instance methods. Specify one or more
|
45
76
|
# of the following options for alternatives. You can combine any of the
|
46
77
|
# <tt>:public</tt>, <tt>:protected</tt>, and <tt>:private</tt>, as well as
|
47
78
|
# <tt>:instance</tt> and <tt>:class</tt>.
|
48
79
|
#
|
49
|
-
# <tt>:public</tt>:: Search for public methods (default).
|
50
|
-
# <tt>:private</tt>:: Search for private methods.
|
51
|
-
# <tt>:protected</tt>:: Search for protected methods.
|
52
|
-
# <tt>:instance</tt>:: Search for instance methods.
|
53
|
-
# <tt>:class</tt>:: Search for class methods.
|
54
|
-
# <tt>:singleton</tt>:: Search for singleton methods. (Using :class for objects
|
80
|
+
# <tt>:public</tt> or <tt>:public_methods</tt>:: Search for public methods (default).
|
81
|
+
# <tt>:private</tt> or <tt>:private_methods</tt>:: Search for private methods.
|
82
|
+
# <tt>:protected</tt> or <tt>:protected_methods</tt>:: Search for protected methods.
|
83
|
+
# <tt>:instance</tt> or <tt>:instance_methods</tt>:: Search for instance methods.
|
84
|
+
# <tt>:class</tt> or <tt>:class_methods</tt>:: Search for class methods.
|
85
|
+
# <tt>:singleton</tt> or <tt>:singleton_methods</tt>:: Search for singleton methods. (Using :class for objects
|
55
86
|
# won't work and :class, :public, :protected, and :private are ignored when
|
56
87
|
# looking for singleton methods.)
|
57
88
|
# <tt>:exclude_ancestor_methods</tt>:: Suppress "ancestor" methods. This
|
@@ -59,7 +90,7 @@ module Aquarium
|
|
59
90
|
# +Derived+ class that is defined in the +Base+ class, you won't find it!
|
60
91
|
#
|
61
92
|
def find options = {}
|
62
|
-
init_specification options
|
93
|
+
init_specification options, canonical_options
|
63
94
|
return Aquarium::Finders::FinderResult.new if nothing_to_find?
|
64
95
|
types_and_objects = input_types + input_objects
|
65
96
|
method_names_or_regexps = input_methods
|
@@ -77,11 +108,69 @@ module Aquarium
|
|
77
108
|
|
78
109
|
NIL_OBJECT = MethodFinder.new unless const_defined?(:NIL_OBJECT)
|
79
110
|
|
80
|
-
|
81
|
-
|
111
|
+
CANONICAL_OPTIONS = {
|
112
|
+
"types" => %w[type for_type for_types on_type on_types in_type in_types within_type within_types],
|
113
|
+
"objects" => %w[object for_object for_objects on_object on_objects in_object in_objects within_object within_objects],
|
114
|
+
"methods" => %w[method within_method within_methods calling invoking invocations_of calls_to sending_message_to sending_messages_to],
|
115
|
+
"options" => %w[method_options method_option restricting_methods_to]
|
116
|
+
}
|
117
|
+
|
118
|
+
%w[types objects methods].each do |key|
|
119
|
+
CANONICAL_OPTIONS["exclude_#{key}"] = CANONICAL_OPTIONS[key].map {|x| "exclude_#{x}"}
|
120
|
+
end
|
121
|
+
CANONICAL_OPTIONS["methods"].dup.each do |synonym|
|
122
|
+
CANONICAL_OPTIONS["methods"] << "#{synonym}_methods_matching"
|
123
|
+
end
|
124
|
+
|
125
|
+
ALL_ALLOWED_OPTIONS = CANONICAL_OPTIONS.keys.inject([]) {|ary,i| ary << i << CANONICAL_OPTIONS[i]}.flatten
|
126
|
+
|
127
|
+
ALL_ALLOWED_OPTION_SYMBOLS = ALL_ALLOWED_OPTIONS.map {|o| o.intern}
|
128
|
+
|
129
|
+
def canonical_options
|
130
|
+
CANONICAL_OPTIONS
|
131
|
+
end
|
132
|
+
def all_allowed_option_symbols
|
133
|
+
ALL_ALLOWED_OPTION_SYMBOLS
|
134
|
+
end
|
135
|
+
|
136
|
+
RECOGNIZED_METHOD_OPTIONS = {
|
137
|
+
"all" => %w[all_methods],
|
138
|
+
"public" => %w[public_methods],
|
139
|
+
"private" => %w[private_methods],
|
140
|
+
"protected" => %w[protected_methods],
|
141
|
+
"instance" => %w[instance_methods],
|
142
|
+
"class" => %w[class_methods],
|
143
|
+
"singleton" => %w[singleton_methods],
|
144
|
+
"exclude_ancestor_methods" => %w[exclude_ancestors exclude_ancestors_methods suppress_ancestors suppress_ancestor_methods suppress_ancestors_methods]
|
145
|
+
}
|
146
|
+
|
147
|
+
def self.init_method_options scope_options_set
|
148
|
+
return Set.new([]) if scope_options_set.nil?
|
149
|
+
options = []
|
150
|
+
scope_options_set.each do |opt|
|
151
|
+
if RECOGNIZED_METHOD_OPTIONS.keys.include?(opt.to_s)
|
152
|
+
options << opt
|
153
|
+
else
|
154
|
+
RECOGNIZED_METHOD_OPTIONS.keys.each do |key|
|
155
|
+
options << key.intern if RECOGNIZED_METHOD_OPTIONS[key].include?(opt.to_s)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
options << :instance unless (options.include?(:class) or options.include?(:singleton))
|
160
|
+
Set.new(options.sort.uniq)
|
161
|
+
end
|
82
162
|
|
163
|
+
def self.all_recognized_method_option_symbols
|
164
|
+
all = RECOGNIZED_METHOD_OPTIONS.keys.map {|key| key.intern}
|
165
|
+
RECOGNIZED_METHOD_OPTIONS.keys.inject(all) do |all, key|
|
166
|
+
all += RECOGNIZED_METHOD_OPTIONS[key].map {|value| value.intern}
|
167
|
+
all
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
83
171
|
def self.is_recognized_method_option string_or_symbol
|
84
|
-
|
172
|
+
sym = string_or_symbol.respond_to?(:intern) ? string_or_symbol.intern : string_or_symbol
|
173
|
+
all_recognized_method_option_symbols.include? sym
|
85
174
|
end
|
86
175
|
|
87
176
|
protected
|
@@ -113,44 +202,51 @@ module Aquarium
|
|
113
202
|
Aquarium::Finders::FinderResult.new types_and_objects_to_matched_methods.merge(:not_matched => types_and_objects_not_matched)
|
114
203
|
end
|
115
204
|
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
@specification = options
|
205
|
+
def init_type_specific_specification original_options, options_hash
|
206
|
+
@specification[:options] = MethodFinder.init_method_options(@specification[:options]) if @specification[:options]
|
207
|
+
extra_validation
|
120
208
|
end
|
121
209
|
|
122
210
|
def nothing_to_find?
|
123
211
|
types_and_objects = input_types + input_objects
|
124
|
-
types_and_objects.nil? or types_and_objects.empty? or
|
212
|
+
types_and_objects.nil? or types_and_objects.empty? or all_exclude_all_methods?
|
125
213
|
end
|
126
214
|
|
127
215
|
def input_types
|
128
|
-
|
216
|
+
@specification[:types]
|
129
217
|
end
|
130
218
|
|
131
219
|
def input_objects
|
132
|
-
|
220
|
+
@specification[:objects]
|
133
221
|
end
|
134
222
|
|
135
223
|
def input_methods
|
136
|
-
|
224
|
+
@specification[:methods]
|
137
225
|
end
|
138
226
|
|
139
227
|
def input_exclude_methods
|
140
|
-
|
228
|
+
@specification[:exclude_methods]
|
229
|
+
end
|
230
|
+
|
231
|
+
def all_exclude_all_methods?
|
232
|
+
input_exclude_methods.include?(:all) or input_exclude_methods.include?(:all_methods)
|
141
233
|
end
|
142
234
|
|
143
235
|
def exclude_ancestor_methods?
|
144
|
-
@specification[:options].include?(:exclude_ancestor_methods)
|
236
|
+
@specification[:options].include?(:exclude_ancestor_methods)
|
145
237
|
end
|
146
238
|
|
147
239
|
private
|
148
240
|
|
149
241
|
def make_methods_array *array_or_single_item
|
150
242
|
ary = make_array(*array_or_single_item).reject {|m| m.to_s.strip.empty?}
|
151
|
-
ary = [/^.+$/] if
|
243
|
+
ary = [/^.+$/] if include_all_methods?(ary)
|
152
244
|
ary
|
153
245
|
end
|
246
|
+
|
247
|
+
def include_all_methods? array
|
248
|
+
array.include?(:all) or array.include?(:all_methods)
|
249
|
+
end
|
154
250
|
|
155
251
|
def make_regexp name_or_regexp
|
156
252
|
name_or_regexp.kind_of?(Regexp) ? name_or_regexp : /^#{Regexp.escape(name_or_regexp.to_s)}$/
|
@@ -175,13 +271,6 @@ module Aquarium
|
|
175
271
|
method_array
|
176
272
|
end
|
177
273
|
|
178
|
-
def init_method_options *scope_options
|
179
|
-
return [] if scope_options.nil?
|
180
|
-
options = scope_options.flatten
|
181
|
-
options << :instance unless options.include?(:class) or options.include?(:instance) or options.include?(:singleton)
|
182
|
-
options
|
183
|
-
end
|
184
|
-
|
185
274
|
def make_methods_reflection_method_names type_or_object, root_method_name
|
186
275
|
is_type = Aquarium::Utils::TypeUtils.is_type?(type_or_object)
|
187
276
|
scope_prefixes = []
|
@@ -226,11 +315,8 @@ module Aquarium
|
|
226
315
|
end
|
227
316
|
end
|
228
317
|
|
229
|
-
def
|
230
|
-
|
231
|
-
okay, bad = options.keys.partition {|x| allowed.include?(x)}
|
232
|
-
raise Aquarium::Utils::InvalidOptions.new("Unrecognized option(s): #{bad.inspect}") unless bad.empty?
|
233
|
-
method_options = options[:options]
|
318
|
+
def extra_validation
|
319
|
+
method_options = @specification[:options]
|
234
320
|
return if method_options.nil?
|
235
321
|
if method_options.include?(:singleton) &&
|
236
322
|
(method_options.include?(:class) || method_options.include?(:public) ||
|
@@ -148,7 +148,7 @@ module Aquarium
|
|
148
148
|
def find_namespace_matched expression, option
|
149
149
|
expr = expression.kind_of?(Regexp) ? expression.source : expression.to_s
|
150
150
|
return nil if expr.empty?
|
151
|
-
found_types = [
|
151
|
+
found_types = [Object]
|
152
152
|
split_expr = expr.split("::")
|
153
153
|
split_expr.each_with_index do |subexp, index|
|
154
154
|
next if subexp.size == 0
|
@@ -186,10 +186,7 @@ module Aquarium
|
|
186
186
|
enclosing_types.each do |parent|
|
187
187
|
next unless parent.respond_to?(:constants)
|
188
188
|
parent.constants.grep(regexp) do |name|
|
189
|
-
|
190
|
-
found_types << parent.const_get(name)
|
191
|
-
rescue NameError # ignore
|
192
|
-
end
|
189
|
+
found_types << parent.const_get(name)
|
193
190
|
end
|
194
191
|
end
|
195
192
|
found_types
|
data/lib/aquarium/utils.rb
CHANGED
@@ -10,16 +10,24 @@ module Aquarium
|
|
10
10
|
# flattened version of the input and any nil elements are removed by #strip_nils.
|
11
11
|
# Note that this behavior effectively converts +nil+ to +[]+.
|
12
12
|
def make_array *value_or_enum
|
13
|
-
|
13
|
+
ArrayUtils.make_array value_or_enum
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.make_array *value_or_enum
|
17
|
+
strip_nils do_make_array(value_or_enum)
|
18
|
+
end
|
19
|
+
|
16
20
|
# Return a copy of the input array with all nils removed.
|
17
21
|
def strip_nils array
|
18
|
-
array
|
22
|
+
ArrayUtils.strip_nils array
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.strip_nils array
|
26
|
+
array.to_a.compact
|
19
27
|
end
|
20
28
|
|
21
29
|
private
|
22
|
-
def do_make_array value_or_enum
|
30
|
+
def self.do_make_array value_or_enum
|
23
31
|
v = value_or_enum.flatten
|
24
32
|
v = v[0].to_a if (v.empty? == false && v[0].kind_of?(Set))
|
25
33
|
v
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Aquarium
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
# Support parsing and processing of key-value pairs of options.
|
5
|
+
# Including types must define the following methods (see Pointcut for an example):
|
6
|
+
# canonical_options # Return the hash of canonical options
|
7
|
+
# all_allowed_option_symbols # Returns an array of all allowed options as symbols.
|
8
|
+
# init_type_specific_specification(original_options, options_hash) for any unique options handling (optional).
|
9
|
+
module OptionsUtils
|
10
|
+
|
11
|
+
def self.universal_options
|
12
|
+
[:verbose, :log, :noop]
|
13
|
+
end
|
14
|
+
|
15
|
+
def init_specification options, canonical_options, &optional_block
|
16
|
+
@canonical_options = canonical_options
|
17
|
+
@original_options = options.dup unless options.nil?
|
18
|
+
@specification = {}
|
19
|
+
options ||= {}
|
20
|
+
options_hash = hashify options
|
21
|
+
@canonical_options.keys.each do |key|
|
22
|
+
all_related_options = make_array(options_hash[key.intern]) || []
|
23
|
+
@canonical_options[key].inject(all_related_options) do |ary, o|
|
24
|
+
ary << options_hash[o.intern] if options_hash[o.intern]
|
25
|
+
ary
|
26
|
+
end
|
27
|
+
@specification[key.intern] = Set.new(make_array(all_related_options))
|
28
|
+
end
|
29
|
+
uopts = {
|
30
|
+
:log => options_hash[:log] || "",
|
31
|
+
:verbose => options_hash[:verbose] || 0,
|
32
|
+
:noop => options_hash[:noop] || false
|
33
|
+
}
|
34
|
+
OptionsUtils::universal_options.each { |uopt| @specification[uopt] = Set.new [uopts[uopt]] }
|
35
|
+
init_type_specific_specification @original_options, options_hash, &optional_block
|
36
|
+
validate_options options_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
OptionsUtils::universal_options.each do |name|
|
40
|
+
module_eval(<<-EOF, __FILE__, __LINE__)
|
41
|
+
def #{name}
|
42
|
+
@specification[:#{name}].to_a.first
|
43
|
+
end
|
44
|
+
def #{name}= value
|
45
|
+
@specification[:#{name}] = Set.new([value])
|
46
|
+
end
|
47
|
+
EOF
|
48
|
+
end
|
49
|
+
|
50
|
+
# Override for type-specific initialization
|
51
|
+
def init_type_specific_specification options, &optional_block
|
52
|
+
end
|
53
|
+
|
54
|
+
def hashify options
|
55
|
+
return options if options.kind_of?(Hash)
|
56
|
+
new_options = {}
|
57
|
+
options.each do |x|
|
58
|
+
if x.kind_of?(Hash)
|
59
|
+
new_options.merge!(x)
|
60
|
+
else
|
61
|
+
new_options[x] = Set.new([])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
new_options
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_options options
|
68
|
+
unknowns = options.keys - all_allowed_option_symbols - OptionsUtils::universal_options
|
69
|
+
raise Aquarium::Utils::InvalidOptions.new("Unknown options specified: #{unknowns.inspect}") if unknowns.size > 0
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -6,22 +6,36 @@ module Aquarium
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.descendents clazz
|
9
|
-
|
9
|
+
visited_types = [Class, Object, Module, clazz]
|
10
|
+
result = Module.constants.inject([clazz]) do |result, const|
|
11
|
+
mod = Module.class_eval(const)
|
12
|
+
if mod.respond_to?(:ancestors)
|
13
|
+
result << mod if mod.ancestors.include?(clazz)
|
14
|
+
do_descendents clazz, mod, visited_types, result
|
15
|
+
end
|
16
|
+
result
|
17
|
+
end
|
18
|
+
result.uniq
|
10
19
|
end
|
11
20
|
|
12
21
|
protected
|
13
22
|
|
14
|
-
def self.do_descendents clazz,
|
15
|
-
|
16
|
-
visited <<
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
next unless
|
21
|
-
|
22
|
-
|
23
|
+
def self.do_descendents clazz, visiting_module, visited, result
|
24
|
+
# p "#{clazz}, #{visiting_module}<br/>"
|
25
|
+
visited << visiting_module
|
26
|
+
# TODO Odd ruby behavior; a class is constant on the class, yet if it is nested in a module
|
27
|
+
# it comes up undefined! However, doing class_eval works around it. Is there a better way??
|
28
|
+
visiting_module.constants.each do |const|
|
29
|
+
next unless visiting_module.const_defined?(const)
|
30
|
+
clazz2 = visiting_module.const_get(const)
|
31
|
+
# clazz2 = visiting_module.const_defined?(const) ?
|
32
|
+
# visiting_module.const_get(const) :
|
33
|
+
# visiting_module.class_eval(const)
|
34
|
+
next if visited.include?(clazz2) or not clazz2.respond_to?(:ancestors)
|
35
|
+
visited << clazz2
|
36
|
+
result << clazz2 if clazz2.ancestors.include?(clazz)
|
37
|
+
do_descendents clazz, clazz2, visited, result
|
23
38
|
end
|
24
|
-
result.flatten.uniq
|
25
39
|
end
|
26
40
|
end
|
27
41
|
end
|