aquarium 0.1.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 +4 -0
- data/EXAMPLES.rd +4 -0
- data/MIT-LICENSE +20 -0
- data/README +250 -0
- data/RELEASE-PLAN +1 -0
- data/Rakefile +236 -0
- data/UPGRADE +3 -0
- data/examples/aspect_design_example.rb +36 -0
- data/examples/design_by_contract_example.rb +88 -0
- data/examples/method_missing_example.rb +44 -0
- data/examples/method_tracing_example.rb +64 -0
- data/lib/aquarium.rb +7 -0
- data/lib/aquarium/aspects.rb +6 -0
- data/lib/aquarium/aspects/advice.rb +189 -0
- data/lib/aquarium/aspects/aspect.rb +577 -0
- data/lib/aquarium/aspects/default_object_handler.rb +27 -0
- data/lib/aquarium/aspects/dsl.rb +1 -0
- data/lib/aquarium/aspects/dsl/aspect_dsl.rb +61 -0
- data/lib/aquarium/aspects/join_point.rb +158 -0
- data/lib/aquarium/aspects/pointcut.rb +254 -0
- data/lib/aquarium/aspects/pointcut_composition.rb +36 -0
- data/lib/aquarium/extensions.rb +5 -0
- data/lib/aquarium/extensions/hash.rb +85 -0
- data/lib/aquarium/extensions/regexp.rb +20 -0
- data/lib/aquarium/extensions/set.rb +49 -0
- data/lib/aquarium/extensions/string.rb +13 -0
- data/lib/aquarium/extensions/symbol.rb +22 -0
- data/lib/aquarium/extras.rb +4 -0
- data/lib/aquarium/extras/design_by_contract.rb +64 -0
- data/lib/aquarium/finders.rb +4 -0
- data/lib/aquarium/finders/finder_result.rb +121 -0
- data/lib/aquarium/finders/method_finder.rb +228 -0
- data/lib/aquarium/finders/object_finder.rb +74 -0
- data/lib/aquarium/finders/type_finder.rb +127 -0
- data/lib/aquarium/utils.rb +9 -0
- data/lib/aquarium/utils/array_utils.rb +29 -0
- data/lib/aquarium/utils/hash_utils.rb +28 -0
- data/lib/aquarium/utils/html_escaper.rb +17 -0
- data/lib/aquarium/utils/invalid_options.rb +9 -0
- data/lib/aquarium/utils/method_utils.rb +18 -0
- data/lib/aquarium/utils/nil_object.rb +13 -0
- data/lib/aquarium/utils/set_utils.rb +32 -0
- data/lib/aquarium/version.rb +30 -0
- data/rake_tasks/examples.rake +7 -0
- data/rake_tasks/examples_specdoc.rake +8 -0
- data/rake_tasks/examples_with_rcov.rake +8 -0
- data/rake_tasks/verify_rcov.rake +7 -0
- data/spec/aquarium/aspects/advice_chain_node_spec.rb +34 -0
- data/spec/aquarium/aspects/advice_spec.rb +103 -0
- data/spec/aquarium/aspects/aspect_invocation_spec.rb +111 -0
- data/spec/aquarium/aspects/aspect_spec.rb +978 -0
- data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +129 -0
- data/spec/aquarium/aspects/concurrent_aspects_spec.rb +423 -0
- data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +103 -0
- data/spec/aquarium/aspects/concurrently_accessed.rb +21 -0
- data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +514 -0
- data/spec/aquarium/aspects/join_point_spec.rb +302 -0
- data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +131 -0
- data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +111 -0
- data/spec/aquarium/aspects/pointcut_spec.rb +800 -0
- data/spec/aquarium/extensions/hash_spec.rb +187 -0
- data/spec/aquarium/extensions/regex_spec.rb +40 -0
- data/spec/aquarium/extensions/set_spec.rb +105 -0
- data/spec/aquarium/extensions/string_spec.rb +25 -0
- data/spec/aquarium/extensions/symbol_spec.rb +37 -0
- data/spec/aquarium/extras/design_by_contract_spec.rb +68 -0
- data/spec/aquarium/finders/finder_result_spec.rb +359 -0
- data/spec/aquarium/finders/method_finder_spec.rb +878 -0
- data/spec/aquarium/finders/method_sorting_spec.rb +16 -0
- data/spec/aquarium/finders/object_finder_spec.rb +230 -0
- data/spec/aquarium/finders/type_finder_spec.rb +210 -0
- data/spec/aquarium/spec_example_classes.rb +117 -0
- data/spec/aquarium/spec_helper.rb +3 -0
- data/spec/aquarium/utils/array_utils_spec.rb +47 -0
- data/spec/aquarium/utils/hash_utils_spec.rb +48 -0
- data/spec/aquarium/utils/html_escaper_spec.rb +18 -0
- data/spec/aquarium/utils/method_utils_spec.rb +50 -0
- data/spec/aquarium/utils/nil_object_spec.rb +19 -0
- data/spec/aquarium/utils/set_utils_spec.rb +60 -0
- metadata +132 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'set'
|
2
|
+
require File.dirname(__FILE__) + '/../utils/array_utils'
|
3
|
+
require File.dirname(__FILE__) + '/type_finder'
|
4
|
+
|
5
|
+
|
6
|
+
# Queries the ObjectSpace, so "immediate" objects are never returned.
|
7
|
+
# Uses Aquarium::Finders::TypeFinder to map type name regular expressions to types.
|
8
|
+
|
9
|
+
module Aquarium
|
10
|
+
module Finders
|
11
|
+
class ObjectFinder
|
12
|
+
include Aquarium::Utils::ArrayUtils
|
13
|
+
|
14
|
+
# finder_result = ObjectFinder.new.find [:types => [type_names_and_regexps] | :type => type_name_or_regexp]
|
15
|
+
# where the input types are regular expressions, there may be 0 to
|
16
|
+
# many matching types that appear in the returned hash.
|
17
|
+
# Use #find_all_by_types to find objects matching actual types, not just
|
18
|
+
# names or regular expressions.
|
19
|
+
# <tt>:types => type_names_and_regexps</tt>::
|
20
|
+
# One or an array of type names and regular expessions to match.
|
21
|
+
#
|
22
|
+
# <tt>:type => type_name_or_regexp</tt>::
|
23
|
+
# A type name or regular expession to match.
|
24
|
+
#
|
25
|
+
# Actually, there is effectively no difference between <tt>:types</tt> and
|
26
|
+
# <tt>:type</tt>. The singular form is "sugar"...
|
27
|
+
def find options = {}
|
28
|
+
type_regexpes_or_names = make_array options[:types]
|
29
|
+
type_regexpes_or_names += make_array options[:type]
|
30
|
+
if type_regexpes_or_names.empty?
|
31
|
+
return Aquarium::Finders::FinderResult.new
|
32
|
+
end
|
33
|
+
self.find_all_by type_regexpes_or_names
|
34
|
+
end
|
35
|
+
|
36
|
+
# Input is a list or array object with names and/or regular expressions.
|
37
|
+
def find_all_by *possible_type_regexpes_or_names
|
38
|
+
raise "Input name or name array can't be nil!" if possible_type_regexpes_or_names.nil?
|
39
|
+
result = Aquarium::Finders::FinderResult.new
|
40
|
+
make_array(*possible_type_regexpes_or_names).each do |expression|
|
41
|
+
found_types = Aquarium::Finders::TypeFinder.new.find :types => expression
|
42
|
+
found_types.matched_keys.each do |type|
|
43
|
+
result << find_all_by_types(type)
|
44
|
+
end
|
45
|
+
found_types.not_matched_keys.each do |type|
|
46
|
+
result.append_not_matched({type => Set.new([])})
|
47
|
+
end
|
48
|
+
end
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return the objects in ObjectSpace for the input classes and modules.
|
53
|
+
def find_all_by_types *types
|
54
|
+
result = Aquarium::Finders::FinderResult.new
|
55
|
+
make_array(*types).each do |type|
|
56
|
+
object_space.each_object(type) do |obj|
|
57
|
+
result.append_matched type => obj
|
58
|
+
end
|
59
|
+
result.append_not_matched type => [] unless result.matched[type]
|
60
|
+
end
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize object_space = ObjectSpace
|
65
|
+
@object_space = object_space
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
attr_reader :object_space
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'set'
|
2
|
+
require File.dirname(__FILE__) + '/../utils/array_utils'
|
3
|
+
require File.dirname(__FILE__) + '/../utils/invalid_options'
|
4
|
+
require File.dirname(__FILE__) + '/../extensions/regexp'
|
5
|
+
require File.dirname(__FILE__) + '/../extensions/symbol'
|
6
|
+
require File.dirname(__FILE__) + '/finder_result'
|
7
|
+
|
8
|
+
# Finds types known to the runtime environment.
|
9
|
+
module Aquarium
|
10
|
+
module Finders
|
11
|
+
class TypeFinder
|
12
|
+
include Aquarium::Utils::ArrayUtils
|
13
|
+
|
14
|
+
# Usage:
|
15
|
+
# finder_result = TypeFinder.new.find [ :types => ... | :names => ... ], [ :options => [...] ]
|
16
|
+
# where
|
17
|
+
# <tt>:types => types_and_type_names_and_regexps</tt>::
|
18
|
+
# The types or type names/regular expessions to match.
|
19
|
+
# Specify one or an array of values.
|
20
|
+
#
|
21
|
+
# <tt>:names => types_and_type_names_and_regexps</tt>::
|
22
|
+
# A synonym for <tt>:types</tt>. (Sugar)
|
23
|
+
#
|
24
|
+
# <tt>:type => type_or_type_name_or_regexp</tt>::
|
25
|
+
# Sugar for specifying one type
|
26
|
+
#
|
27
|
+
# <tt>:name => type_or_type_name_or_regexp</tt>::
|
28
|
+
# Sugar for specifying one type name.
|
29
|
+
#
|
30
|
+
# Actually, there is actually no difference between <tt>:types</tt>,
|
31
|
+
# <tt>:type</tt>, <tt>:names</tt>, and <tt>:name</tt>. The extra forms are "sugar"...
|
32
|
+
def find options = {}
|
33
|
+
result = Aquarium::Finders::FinderResult.new
|
34
|
+
unknown_options = []
|
35
|
+
options.each do |option, value|
|
36
|
+
case option.to_s
|
37
|
+
when "names", "types", "name", "type"
|
38
|
+
result << find_all_by(value)
|
39
|
+
else
|
40
|
+
unknown_options << option
|
41
|
+
end
|
42
|
+
end
|
43
|
+
raise Aquarium::Utils::InvalidOptions.new("Unknown options: #{unknown_options.inspect}.") if unknown_options.size > 0
|
44
|
+
return result
|
45
|
+
end
|
46
|
+
|
47
|
+
# For a name (not a regular expression), return the corresponding type.
|
48
|
+
# (Adapted from the RubyQuiz #113 solution by James Edward Gray II)
|
49
|
+
def find_by_name type_name
|
50
|
+
name = type_name.to_s # in case it's a symbol...
|
51
|
+
return nil if name.nil? || name.strip.empty?
|
52
|
+
name.strip!
|
53
|
+
found = []
|
54
|
+
begin
|
55
|
+
found << name.split("::").inject(Object) { |parent, const| parent.const_get(const) }
|
56
|
+
Aquarium::Finders::FinderResult.new(make_return_hash(found, []))
|
57
|
+
rescue NameError => ne
|
58
|
+
Aquarium::Finders::FinderResult.new(make_return_hash([], [type_name]))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
alias :find_by_type :find_by_name
|
63
|
+
|
64
|
+
def find_all_by regexpes_or_names
|
65
|
+
raise Aquarium::Utils::InvalidOptions.new("Input type(s) can't be nil!") if regexpes_or_names.nil?
|
66
|
+
result = Aquarium::Finders::FinderResult.new
|
67
|
+
expressions = make_array regexpes_or_names
|
68
|
+
expressions.each do |expression|
|
69
|
+
expr = strip expression
|
70
|
+
next if empty expr
|
71
|
+
result_for_expression = find_namespace_matched expr
|
72
|
+
if result_for_expression.size > 0
|
73
|
+
result.append_matched result_for_expression
|
74
|
+
else
|
75
|
+
result.append_not_matched({expression => Set.new([])})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.is_recognized_option option_or_symbol
|
82
|
+
%w[name names type types].include? option_or_symbol.to_s
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def strip expression
|
88
|
+
return nil if expression.nil?
|
89
|
+
expression.respond_to?(:strip) ? expression.strip : expression
|
90
|
+
end
|
91
|
+
|
92
|
+
def empty expression
|
93
|
+
expression.nil? || (expression.respond_to?(:empty?) && expression.empty?)
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_namespace_matched expression
|
97
|
+
return {} if expression.nil?
|
98
|
+
found_types = [Module]
|
99
|
+
expr = expression.class.eql?(Regexp) ? expression.source : expression.to_s
|
100
|
+
return {} if expr.empty?
|
101
|
+
expr.split("::").each do |subexp|
|
102
|
+
found_types = find_next_types found_types, subexp
|
103
|
+
break if found_types.size == 0
|
104
|
+
end
|
105
|
+
make_return_hash found_types, []
|
106
|
+
end
|
107
|
+
|
108
|
+
def find_next_types parent_types, subname
|
109
|
+
# grep <parent>.constants because "subname" may be a regexp string!.
|
110
|
+
# Then use const_get to get the type itself.
|
111
|
+
found_types = []
|
112
|
+
parent_types.each do |parent|
|
113
|
+
matched = parent.constants.grep(/^#{subname}$/)
|
114
|
+
matched.each {|m| found_types << parent.const_get(m)}
|
115
|
+
end
|
116
|
+
found_types
|
117
|
+
end
|
118
|
+
|
119
|
+
def make_return_hash found, unmatched
|
120
|
+
h={}
|
121
|
+
h[:not_matched] = unmatched if unmatched.size > 0
|
122
|
+
found.each {|x| h[x] = Set.new([])}
|
123
|
+
h
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'aquarium/utils/array_utils'
|
2
|
+
require 'aquarium/utils/hash_utils'
|
3
|
+
require 'aquarium/utils/set_utils'
|
4
|
+
|
5
|
+
require 'aquarium/utils/method_utils'
|
6
|
+
|
7
|
+
require 'aquarium/utils/html_escaper'
|
8
|
+
require 'aquarium/utils/invalid_options'
|
9
|
+
require 'aquarium/utils/nil_object'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'aquarium/extensions/symbol'
|
2
|
+
require 'aquarium/utils/html_escaper'
|
3
|
+
|
4
|
+
module Aquarium
|
5
|
+
module Utils
|
6
|
+
module ArrayUtils
|
7
|
+
|
8
|
+
# Return an array containing the input item or list of items. If the input
|
9
|
+
# is an array, it is returned. In all cases, the constructed array is a
|
10
|
+
# flattened version of the input and any nil elements are removed by #strip_nils.
|
11
|
+
# Note that this behavior effectively converts +nil+ to +[]+.
|
12
|
+
def make_array *value_or_enum
|
13
|
+
strip_nils do_make_array(value_or_enum)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return a copy of the input array with all nils removed.
|
17
|
+
def strip_nils array
|
18
|
+
array.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def do_make_array value_or_enum
|
23
|
+
v = value_or_enum.flatten
|
24
|
+
v = v[0].to_a if (v.empty? == false && v[0].kind_of?(Set))
|
25
|
+
v
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'aquarium/utils/array_utils'
|
2
|
+
|
3
|
+
module Aquarium
|
4
|
+
module Utils
|
5
|
+
module HashUtils
|
6
|
+
include Aquarium::Utils::ArrayUtils
|
7
|
+
|
8
|
+
# Convert the input item or array into a hash with a nil value or the result
|
9
|
+
# of evaluating the optional input block, which takes a single argument for the item.
|
10
|
+
# If the input is already a hash, it is returned unmodified.
|
11
|
+
def make_hash item_or_array_or_hash
|
12
|
+
return {} if item_or_array_or_hash.nil?
|
13
|
+
return strip_nil_keys(item_or_array_or_hash) if item_or_array_or_hash.kind_of?(Hash)
|
14
|
+
hash = {}
|
15
|
+
[item_or_array_or_hash].flatten.each do |element|
|
16
|
+
unless element.nil?
|
17
|
+
hash[element] = block_given? ? yield(element) : nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
|
23
|
+
def strip_nil_keys hash
|
24
|
+
hash.reject {|k,v| k.nil?}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Aquarium
|
2
|
+
module Utils
|
3
|
+
module HtmlEscaper
|
4
|
+
def self.escape message
|
5
|
+
do_escape message
|
6
|
+
end
|
7
|
+
def escape message
|
8
|
+
HtmlEscaper.do_escape message
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def self.do_escape message
|
13
|
+
message.gsub(/\</, "<").gsub(/\>/, ">")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Aquarium
|
2
|
+
module Utils
|
3
|
+
module MethodUtils
|
4
|
+
def self.method_args_to_hash *args
|
5
|
+
return {} if args.empty? || (args.size == 1 && args[0].nil?)
|
6
|
+
hash = (args[-1] and args[-1].kind_of? Hash) ? args.pop : {}
|
7
|
+
args.each do |arg|
|
8
|
+
if block_given?
|
9
|
+
hash[arg] = yield arg
|
10
|
+
else
|
11
|
+
hash[arg] = nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# One implementation of the Null Object Pattern (renamed "Nil" for Ruby).
|
2
|
+
# All methods not defined by Object simply return the Aquarium::Utils::NilObject itself.
|
3
|
+
# Users can subclass or add methods to instances to customize the behavior.
|
4
|
+
|
5
|
+
module Aquarium
|
6
|
+
module Utils
|
7
|
+
class Aquarium::Utils::NilObject
|
8
|
+
def method_missing method_sym, *args
|
9
|
+
self
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Aquarium
|
4
|
+
module Utils
|
5
|
+
module SetUtils
|
6
|
+
|
7
|
+
# Return a set containing the input item or list of items. If the input
|
8
|
+
# is a set or an array, it is returned. In all cases, the constructed set is a
|
9
|
+
# flattened version of the input and any nil elements are removed by #strip_nils.
|
10
|
+
# Note that this behavior effectively converts +nil+ to +[]+.
|
11
|
+
def make_set *value_or_set_or_array
|
12
|
+
strip_nils(convert_to_set(*value_or_set_or_array))
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return a new set that is a copy of the input set with all nils removed.
|
16
|
+
def strip_nils set
|
17
|
+
set.delete_if {|x| x.nil?}
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
def convert_to_set *value_or_set_or_array
|
22
|
+
if value_or_set_or_array.nil? or value_or_set_or_array.empty?
|
23
|
+
Set.new
|
24
|
+
elsif value_or_set_or_array[0].kind_of?(Set)
|
25
|
+
value_or_set_or_array[0]
|
26
|
+
else
|
27
|
+
Set.new value_or_set_or_array.flatten
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Aquarium
|
2
|
+
module VERSION
|
3
|
+
def self.build_tag
|
4
|
+
tag = "REL_" + [MAJOR, MINOR, TINY].join('_')
|
5
|
+
if defined?(RELEASE_CANDIDATE)
|
6
|
+
tag << "_" << RELEASE_CANDIDATE
|
7
|
+
end
|
8
|
+
tag
|
9
|
+
end
|
10
|
+
|
11
|
+
unless defined? MAJOR
|
12
|
+
MAJOR = 0
|
13
|
+
MINOR = 1
|
14
|
+
TINY = 0
|
15
|
+
RELEASE_CANDIDATE = ""
|
16
|
+
|
17
|
+
# RANDOM_TOKEN: 0.598704893979657
|
18
|
+
REV = "$LastChangedRevision: 7 $".match(/LastChangedRevision: (\d+)/)[1]
|
19
|
+
|
20
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
21
|
+
FULL_VERSION = "#{STRING} (r#{REV})"
|
22
|
+
TAG = build_tag
|
23
|
+
|
24
|
+
NAME = "Aquarium"
|
25
|
+
URL = "http://aquarium.rubyforge.org"
|
26
|
+
|
27
|
+
DESCRIPTION = "#{NAME}-#{FULL_VERSION} - Aspect-Oriented Programming toolkit for Ruby\n#{URL}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
require File.dirname(__FILE__) + '/../spec_example_classes'
|
3
|
+
require 'aquarium'
|
4
|
+
|
5
|
+
# Some of AdviceChainNode and related classes are tested through advice_spec.rb. We rely on rcov to
|
6
|
+
# tell us otherwise...
|
7
|
+
describe Aquarium::Aspects::AdviceChainNode, "#each" do
|
8
|
+
it "should return each node in succession" do
|
9
|
+
static_join_point = :static_join_point
|
10
|
+
advice = lambda {|jp, *args| p "none advice"}
|
11
|
+
options = {
|
12
|
+
:advice_kind => :none,
|
13
|
+
:advice => advice,
|
14
|
+
:next_node => nil,
|
15
|
+
:static_join_point => static_join_point}
|
16
|
+
advice_chain = Aquarium::Aspects::AdviceChainNodeFactory.make_node options
|
17
|
+
|
18
|
+
Aquarium::Aspects::Advice.kinds_in_priority_order.each do |advice_kind|
|
19
|
+
advice = lambda {|jp, *args| p "#{advice_kind} advice"}
|
20
|
+
options[:advice_kind] = advice_kind
|
21
|
+
options[:advice] = advice,
|
22
|
+
options[:next_node] = advice_chain
|
23
|
+
advice_chain = Aquarium::Aspects::AdviceChainNodeFactory.make_node options
|
24
|
+
end
|
25
|
+
|
26
|
+
advice_chain.size.should == 6
|
27
|
+
expected_advice_kinds = Aquarium::Aspects::Advice.kinds_in_priority_order.reverse + [:none]
|
28
|
+
count = 0
|
29
|
+
advice_chain.each do |node|
|
30
|
+
node.advice_kind.should == expected_advice_kinds[count]
|
31
|
+
count += 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|