rattler 0.3.0 → 0.4.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/README.rdoc +57 -37
- data/features/command_line/dest_option.feature +8 -21
- data/features/command_line/lib_option.feature +37 -0
- data/features/command_line/parser_generator.feature +7 -4
- data/features/grammar/back_reference.feature +37 -0
- data/features/grammar/fail.feature +3 -3
- data/features/grammar/labels.feature +11 -3
- data/features/grammar/list_matching.feature +14 -5
- data/features/grammar/literal.feature +30 -4
- data/features/grammar/nonterminal.feature +1 -1
- data/features/grammar/ordered_choice.feature +2 -2
- data/features/grammar/skip_operator.feature +1 -1
- data/features/grammar/symantic_action.feature +7 -7
- data/features/grammar/whitespace.feature +2 -2
- data/features/step_definitions/grammar_steps.rb +2 -2
- data/lib/rattler/back_end.rb +1 -0
- data/lib/rattler/back_end/compiler.rb +19 -20
- data/lib/rattler/back_end/optimizer.rb +100 -0
- data/lib/rattler/back_end/optimizer/composite_reducing.rb +18 -0
- data/lib/rattler/back_end/optimizer/flatten_choice.rb +31 -0
- data/lib/rattler/back_end/optimizer/flatten_sequence.rb +59 -0
- data/lib/rattler/back_end/optimizer/flattening.rb +17 -0
- data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +46 -0
- data/lib/rattler/back_end/optimizer/join_match_capturing_sequence.rb +71 -0
- data/lib/rattler/back_end/optimizer/join_match_choice.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_match_matching_sequence.rb +38 -0
- data/lib/rattler/back_end/optimizer/join_match_sequence.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_nested_match.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_nested_match.rb +36 -0
- data/lib/rattler/back_end/optimizer/match_joining.rb +60 -0
- data/lib/rattler/back_end/optimizer/optimization.rb +94 -0
- data/lib/rattler/back_end/optimizer/optimization_context.rb +72 -0
- data/lib/rattler/back_end/optimizer/optimization_sequence.rb +37 -0
- data/lib/rattler/back_end/optimizer/optimize_children.rb +46 -0
- data/lib/rattler/back_end/optimizer/reduce_repeat_match.rb +44 -0
- data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +32 -0
- data/lib/rattler/back_end/optimizer/simplify_redundant_repeat.rb +43 -0
- data/lib/rattler/back_end/optimizer/simplify_token_match.rb +38 -0
- data/lib/rattler/back_end/parser_generator.rb +21 -14
- data/lib/rattler/back_end/parser_generator/apply_generator.rb +35 -35
- data/lib/rattler/back_end/parser_generator/assert_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/back_reference_generator.rb +93 -0
- data/lib/rattler/back_end/parser_generator/choice_generator.rb +33 -49
- data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +14 -14
- data/lib/rattler/back_end/parser_generator/disallow_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +11 -13
- data/lib/rattler/back_end/parser_generator/expr_generator.rb +36 -56
- data/lib/rattler/back_end/parser_generator/fail_generator.rb +18 -18
- data/lib/rattler/back_end/parser_generator/group_match.rb +18 -0
- data/lib/rattler/back_end/parser_generator/group_match_generator.rb +76 -0
- data/lib/rattler/back_end/parser_generator/label_generator.rb +25 -6
- data/lib/rattler/back_end/parser_generator/list1_generator.rb +7 -7
- data/lib/rattler/back_end/parser_generator/list_generating.rb +19 -20
- data/lib/rattler/back_end/parser_generator/list_generator.rb +5 -5
- data/lib/rattler/back_end/parser_generator/match_generator.rb +52 -52
- data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +6 -6
- data/lib/rattler/back_end/parser_generator/optional_generator.rb +30 -29
- data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +8 -8
- data/lib/rattler/back_end/parser_generator/repeat_generating.rb +23 -25
- data/lib/rattler/back_end/parser_generator/rule_generator.rb +27 -79
- data/lib/rattler/back_end/parser_generator/rule_set_generator.rb +102 -0
- data/lib/rattler/back_end/parser_generator/sequence_generator.rb +49 -41
- data/lib/rattler/back_end/parser_generator/skip_generator.rb +14 -20
- data/lib/rattler/back_end/parser_generator/skip_propogating.rb +4 -4
- data/lib/rattler/back_end/parser_generator/sub_generating.rb +6 -0
- data/lib/rattler/back_end/parser_generator/token_generator.rb +12 -12
- data/lib/rattler/back_end/parser_generator/token_propogating.rb +2 -2
- data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +4 -4
- data/lib/rattler/grammar.rb +4 -3
- data/lib/rattler/grammar/analysis.rb +91 -0
- data/lib/rattler/grammar/grammar.rb +37 -25
- data/lib/rattler/grammar/grammar_parser.rb +19 -11
- data/lib/rattler/grammar/metagrammar.rb +569 -800
- data/lib/rattler/grammar/rattler.rtlr +162 -144
- data/lib/rattler/parsers.rb +5 -1
- data/lib/rattler/parsers/action_code.rb +29 -15
- data/lib/rattler/parsers/apply.rb +5 -5
- data/lib/rattler/parsers/assert.rb +4 -18
- data/lib/rattler/parsers/back_reference.rb +46 -0
- data/lib/rattler/parsers/choice.rb +6 -39
- data/lib/rattler/parsers/combinator_parser.rb +32 -0
- data/lib/rattler/parsers/combining.rb +3 -29
- data/lib/rattler/parsers/direct_action.rb +27 -30
- data/lib/rattler/parsers/disallow.rb +4 -18
- data/lib/rattler/parsers/dispatch_action.rb +30 -25
- data/lib/rattler/parsers/label.rb +9 -18
- data/lib/rattler/parsers/list.rb +3 -34
- data/lib/rattler/parsers/list1.rb +4 -36
- data/lib/rattler/parsers/list_parser.rb +64 -0
- data/lib/rattler/parsers/match.rb +7 -42
- data/lib/rattler/parsers/node_code.rb +44 -0
- data/lib/rattler/parsers/one_or_more.rb +7 -27
- data/lib/rattler/parsers/optional.rb +5 -25
- data/lib/rattler/parsers/parser.rb +16 -44
- data/lib/rattler/parsers/parser_dsl.rb +13 -3
- data/lib/rattler/parsers/predicate.rb +4 -12
- data/lib/rattler/parsers/rule.rb +18 -19
- data/lib/rattler/parsers/rule_set.rb +63 -0
- data/lib/rattler/parsers/sequence.rb +12 -46
- data/lib/rattler/parsers/skip.rb +12 -26
- data/lib/rattler/parsers/token.rb +6 -21
- data/lib/rattler/parsers/zero_or_more.rb +6 -26
- data/lib/rattler/runner.rb +66 -28
- data/lib/rattler/runtime/extended_packrat_parser.rb +26 -20
- data/lib/rattler/runtime/packrat_parser.rb +17 -21
- data/lib/rattler/runtime/parser.rb +12 -2
- data/lib/rattler/runtime/recursive_descent_parser.rb +3 -11
- data/lib/rattler/util.rb +2 -1
- data/lib/rattler/util/graphviz.rb +29 -0
- data/lib/rattler/util/graphviz/digraph_builder.rb +71 -0
- data/lib/rattler/util/graphviz/node_builder.rb +84 -0
- data/lib/rattler/util/node.rb +37 -19
- data/lib/rattler/util/parser_spec_helper.rb +61 -35
- data/spec/rattler/back_end/compiler_spec.rb +6 -860
- data/spec/rattler/back_end/optimizer/flatten_choice_spec.rb +70 -0
- data/spec/rattler/back_end/optimizer/flatten_sequence_spec.rb +130 -0
- data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +80 -0
- data/spec/rattler/back_end/optimizer/join_match_capturing_sequence_spec.rb +241 -0
- data/spec/rattler/back_end/optimizer/join_match_choice_spec.rb +100 -0
- data/spec/rattler/back_end/optimizer/join_match_matching_sequence_spec.rb +112 -0
- data/spec/rattler/back_end/optimizer/join_predicate_bare_match_spec.rb +194 -0
- data/spec/rattler/back_end/optimizer/join_predicate_nested_match_spec.rb +180 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_bare_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_nested_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb +98 -0
- data/spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb +226 -0
- data/spec/rattler/back_end/optimizer/simplify_token_match_spec.rb +85 -0
- data/spec/rattler/back_end/parser_generator/apply_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/assert_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb +181 -0
- data/spec/rattler/back_end/parser_generator/choice_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/disallow_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +185 -0
- data/spec/rattler/back_end/parser_generator/label_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/match_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/one_or_more_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/optional_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/rule_generator_spec.rb +13 -46
- data/spec/rattler/back_end/parser_generator/rule_set_generator_spec.rb +97 -0
- data/spec/rattler/back_end/parser_generator/sequence_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/skip_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/token_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/zero_or_more_generator_spec.rb +39 -34
- data/spec/rattler/back_end/shared_compiler_examples.rb +885 -0
- data/spec/rattler/grammar/analysis_spec.rb +167 -0
- data/spec/rattler/grammar/grammar_parser_spec.rb +169 -179
- data/spec/rattler/grammar/grammar_spec.rb +24 -21
- data/spec/rattler/parsers/action_code_spec.rb +64 -19
- data/spec/rattler/parsers/apply_spec.rb +9 -9
- data/spec/rattler/parsers/back_reference_spec.rb +38 -0
- data/spec/rattler/parsers/combinator_parser_spec.rb +14 -0
- data/spec/rattler/parsers/direct_action_spec.rb +16 -2
- data/spec/rattler/parsers/dispatch_action_spec.rb +15 -32
- data/spec/rattler/parsers/fail_spec.rb +6 -4
- data/spec/rattler/parsers/label_spec.rb +10 -28
- data/spec/rattler/parsers/node_code_spec.rb +48 -0
- data/spec/rattler/parsers/parser_dsl_spec.rb +1 -1
- data/spec/rattler/parsers/rule_set_spec.rb +35 -0
- data/spec/rattler/parsers/sequence_spec.rb +15 -24
- data/spec/rattler/runtime/extended_packrat_parser_spec.rb +22 -17
- data/spec/rattler/runtime/packrat_parser_spec.rb +1 -1
- data/spec/rattler/runtime/parse_node_spec.rb +15 -19
- data/spec/rattler/runtime/recursive_descent_parser_spec.rb +1 -1
- data/spec/rattler/runtime/shared_parser_examples.rb +61 -28
- data/spec/rattler/util/graphviz/node_builder_spec.rb +84 -0
- data/spec/rattler/util/node_spec.rb +92 -65
- data/spec/rattler_spec.rb +16 -16
- data/spec/support/combinator_parser_spec_helper.rb +19 -18
- data/spec/support/compiler_spec_helper.rb +56 -87
- data/spec/support/runtime_parser_spec_helper.rb +6 -14
- metadata +117 -22
- data/features/grammar/regex.feature +0 -24
- data/lib/rattler/parsers/match_joining.rb +0 -67
- data/lib/rattler/parsers/rules.rb +0 -43
@@ -2,59 +2,92 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
2
|
|
3
3
|
shared_examples_for 'a recursive descent parser' do
|
4
4
|
include RuntimeParserSpecHelper
|
5
|
-
|
5
|
+
|
6
|
+
describe '#parse' do
|
7
|
+
|
8
|
+
let(:grammar) { define_grammar do
|
9
|
+
rule(:word) { match(/\w+/) }
|
10
|
+
end }
|
11
|
+
|
12
|
+
it 'applies the start rule to the source' do
|
13
|
+
parsing('Hello World!').should result_in('Hello').at(5)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
shared_examples_for 'a generated recursive descent parser' do
|
20
|
+
include RuntimeParserSpecHelper
|
21
|
+
|
22
|
+
it_behaves_like 'a recursive descent parser'
|
23
|
+
|
24
|
+
let(:parser_class) do
|
25
|
+
Rattler::BackEnd::Compiler.compile_parser described_class, grammar
|
26
|
+
end
|
27
|
+
|
6
28
|
describe '#match' do
|
7
|
-
|
29
|
+
|
30
|
+
let(:grammar) { define_grammar do
|
31
|
+
rule(:word) { match(/\w+/) }
|
32
|
+
end }
|
33
|
+
|
8
34
|
it 'dispatches to the correct match method' do
|
9
|
-
|
10
|
-
parsing('Hello World!').as(:foo).should result_in('Hello').at(5)
|
35
|
+
matching('Hello World!').as(:word).should result_in('Hello').at(5)
|
11
36
|
end
|
12
|
-
|
37
|
+
|
13
38
|
it 'registers parse errors' do
|
14
|
-
|
15
|
-
|
16
|
-
should fail.at(0).with_message('foo expected')
|
39
|
+
matching('@').as(:word).
|
40
|
+
should fail.at(0).with_message('word expected')
|
17
41
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
42
|
+
|
43
|
+
context 'given recursive rules' do
|
44
|
+
|
45
|
+
let(:grammar) { define_grammar do
|
21
46
|
rule :a do
|
22
47
|
( match(/\d/) & match(:a) \
|
23
48
|
| match(/\d/) )
|
24
49
|
end
|
25
|
-
end
|
26
|
-
|
50
|
+
end }
|
51
|
+
|
52
|
+
it 'applies the rules recursively' do
|
53
|
+
matching('1234abc').as(:a).should result_in(['1', ['2', ['3', '4']]]).at(4)
|
54
|
+
end
|
27
55
|
end
|
28
|
-
|
29
56
|
end
|
30
|
-
|
57
|
+
|
31
58
|
end
|
32
59
|
|
33
|
-
shared_examples_for 'a packrat parser' do
|
60
|
+
shared_examples_for 'a generated packrat parser' do
|
34
61
|
include RuntimeParserSpecHelper
|
35
62
|
|
36
|
-
it_behaves_like 'a recursive descent parser'
|
63
|
+
it_behaves_like 'a generated recursive descent parser'
|
64
|
+
|
65
|
+
let(:parser_class) do
|
66
|
+
Rattler::BackEnd::Compiler.compile_parser described_class, grammar
|
67
|
+
end
|
37
68
|
|
38
69
|
describe '#match' do
|
39
70
|
|
40
|
-
|
41
|
-
|
71
|
+
context 'given recursive rules' do
|
72
|
+
|
73
|
+
let(:grammar) { define_grammar do
|
42
74
|
rule :a do
|
43
75
|
( match(:b) & match('a') \
|
44
|
-
| match(:b) &
|
76
|
+
| match(:b) & eof )
|
45
77
|
end
|
46
78
|
rule :b do
|
47
|
-
match('b')
|
79
|
+
match('b') & disallow(:a)
|
48
80
|
end
|
49
|
-
end
|
50
|
-
|
51
|
-
example.
|
52
|
-
|
53
|
-
|
81
|
+
end }
|
82
|
+
|
83
|
+
let(:example) { matching('bag').as(:a) }
|
84
|
+
|
85
|
+
it 'memoizes parse results' do
|
86
|
+
example.parser.should_receive(:match_b!).
|
87
|
+
and_return { example.parser.pos += 1; 'b' }
|
88
|
+
example.should result_in(['b', 'a']).at(2)
|
54
89
|
end
|
55
|
-
example.should result_in(['b', 'b']).at(2)
|
56
90
|
end
|
57
|
-
|
58
91
|
end
|
59
92
|
|
60
93
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
describe Rattler::Util::GraphViz::NodeBuilder do
|
5
|
+
|
6
|
+
describe '#array_like?' do
|
7
|
+
|
8
|
+
context 'given an array' do
|
9
|
+
it 'returns true' do
|
10
|
+
subject.array_like?(['a']).should be_true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'given a hash' do
|
15
|
+
it 'returns true' do
|
16
|
+
subject.array_like?({:a => 'a'}).should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'given a string' do
|
21
|
+
it 'returns false' do
|
22
|
+
subject.array_like?('a').should be_false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#record_like?' do
|
28
|
+
|
29
|
+
context 'given a hash of simple values' do
|
30
|
+
it 'returns true' do
|
31
|
+
subject.record_like?({:a => 'a', :b => 'b'}).should be_true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'given a hash with compound values' do
|
36
|
+
it 'returns false' do
|
37
|
+
subject.record_like?({:a => ['a1', 'a2'], :b => 'b'}).should be_false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'given an array' do
|
42
|
+
it 'returns false' do
|
43
|
+
subject.record_like?(['a']).should be_false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#each_child_of' do
|
49
|
+
|
50
|
+
context 'given an array' do
|
51
|
+
|
52
|
+
let(:object) { ['a', 'b', 'c'] }
|
53
|
+
|
54
|
+
it 'iterates over the members' do
|
55
|
+
children = []
|
56
|
+
subject.each_child_of(object) {|_| children << _ }
|
57
|
+
children.should == ['a', 'b', 'c']
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'given a hash with compound values' do
|
62
|
+
|
63
|
+
let(:object) { {:a => ['a1', 'a2'], :b => 'b'} }
|
64
|
+
|
65
|
+
it 'iterates over the pairs' do
|
66
|
+
children = Set[]
|
67
|
+
subject.each_child_of(object) {|_| children << _ }
|
68
|
+
children.should == Set[[:a, ['a1', 'a2']], [:b, 'b']]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'given a hash with simple values' do
|
73
|
+
|
74
|
+
let(:object) { {:a => 'a', :b => 'b'} }
|
75
|
+
|
76
|
+
it 'does nothing' do
|
77
|
+
children = Set[]
|
78
|
+
subject.each_child_of(object) {|_| children << _}
|
79
|
+
children.should be_empty
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -3,100 +3,100 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
3
3
|
include Rattler::Util
|
4
4
|
|
5
5
|
describe Node do
|
6
|
-
|
6
|
+
|
7
7
|
describe '#children' do
|
8
|
-
|
8
|
+
|
9
9
|
context 'when the Node has children' do
|
10
10
|
subject do
|
11
11
|
Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar'))
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
it 'returns the children' do
|
15
15
|
subject.children.
|
16
16
|
should == [Node.new(:name => 'foo'), Node.new(:name => 'bar')]
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
context 'when the Node has no children' do
|
21
|
-
|
21
|
+
|
22
22
|
subject { Node.new }
|
23
|
-
|
23
|
+
|
24
24
|
it 'returns an empty array' do
|
25
25
|
subject.children.should == []
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
context 'when the Node has children and attributes' do
|
30
30
|
subject do
|
31
31
|
Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar'), :foo => 'bar')
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
it 'returns the children' do
|
35
35
|
subject.children.
|
36
36
|
should == [Node.new(:name => 'foo'), Node.new(:name => 'bar')]
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
context 'when the Node has only attributes' do
|
41
|
-
|
41
|
+
|
42
42
|
subject { Node.new(:foo => 'bar', :bar => nil) }
|
43
|
-
|
43
|
+
|
44
44
|
it 'returns an empty array' do
|
45
45
|
subject.children.should == []
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
describe '#attrs' do
|
51
51
|
context 'when the Node has attributes' do
|
52
|
-
|
52
|
+
|
53
53
|
subject { Node.new(:foo => 'bar', :bar => nil) }
|
54
|
-
|
54
|
+
|
55
55
|
it 'returns a Hash of the attributes' do
|
56
56
|
subject.attrs.should == { :foo => 'bar', :bar => nil }
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
context 'when the Node has no attributes' do
|
61
|
-
|
61
|
+
|
62
62
|
subject { Node.new }
|
63
|
-
|
63
|
+
|
64
64
|
it 'returns an empty Hash' do
|
65
65
|
subject.attrs.should == {}
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
context 'when the Node has children and attributes' do
|
70
70
|
subject do
|
71
71
|
Node.new(Node.new(:name => 'foo'), :foo => 'bar', :bar => nil)
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
it 'returns a Hash of the attributes' do
|
75
75
|
subject.attrs.should == { :foo => 'bar', :bar => nil }
|
76
76
|
end
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
context 'when the Node has only children' do
|
80
80
|
subject do
|
81
81
|
Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar'))
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
it 'returns an empty Hash' do
|
85
85
|
subject.attrs.should == {}
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
describe '#child' do
|
91
91
|
context 'when the Node has children' do
|
92
92
|
subject do
|
93
93
|
Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar'))
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
it 'returns the first child' do
|
97
97
|
subject.child.should == Node.new(:name => 'foo')
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
context 'given an index' do
|
101
101
|
it 'returns the child at the index' do
|
102
102
|
subject.child(0).should == Node.new(:name => 'foo')
|
@@ -104,63 +104,63 @@ describe Node do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
context 'when the Node has no children' do
|
109
|
-
|
109
|
+
|
110
110
|
subject { Node.new }
|
111
|
-
|
111
|
+
|
112
112
|
it 'returns nil' do
|
113
113
|
subject.child.should be_nil
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
describe '#name' do
|
119
119
|
context 'when the Node as a name attribute' do
|
120
|
-
|
120
|
+
|
121
121
|
subject { Node.new(:name => 'foo' ) }
|
122
|
-
|
122
|
+
|
123
123
|
it 'uses the name attribute as name' do
|
124
124
|
subject.name.should == 'foo'
|
125
125
|
end
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
context 'when the Node has no name attribute' do
|
129
|
-
|
129
|
+
|
130
130
|
subject { Node.new }
|
131
|
-
|
131
|
+
|
132
132
|
it 'uses the class name as name' do
|
133
133
|
subject.name.should == 'Rattler::Util::Node'
|
134
134
|
end
|
135
135
|
end
|
136
136
|
end
|
137
|
-
|
137
|
+
|
138
138
|
describe '#[]' do
|
139
139
|
context 'when the Node has children' do
|
140
140
|
subject do
|
141
141
|
Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar'))
|
142
142
|
end
|
143
|
-
|
143
|
+
|
144
144
|
context 'given a single index' do
|
145
145
|
it 'returns the child at the index' do
|
146
146
|
subject[0].should == Node.new(:name => 'foo')
|
147
147
|
subject[1].should == Node.new(:name => 'bar')
|
148
148
|
end
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
context 'given a negative index' do
|
152
152
|
it 'counts backward from the last child' do
|
153
153
|
subject[-1].should == Node.new(:name => 'bar')
|
154
154
|
subject[-2].should == Node.new(:name => 'foo')
|
155
155
|
end
|
156
156
|
end
|
157
|
-
|
157
|
+
|
158
158
|
context 'given an out-of-range index' do
|
159
159
|
it 'returns nil' do
|
160
160
|
subject[3].should be_nil
|
161
161
|
end
|
162
162
|
end
|
163
|
-
|
163
|
+
|
164
164
|
context 'given an index and a length' do
|
165
165
|
it 'returns an array of children starting at the index' do
|
166
166
|
subject[0, 2].should == [Node.new(:name => 'foo'), Node.new(:name => 'bar')]
|
@@ -168,7 +168,7 @@ describe Node do
|
|
168
168
|
subject[1, 1].should == [Node.new(:name => 'bar')]
|
169
169
|
end
|
170
170
|
end
|
171
|
-
|
171
|
+
|
172
172
|
context 'given a negative index and a length' do
|
173
173
|
it 'counts backward from the last child' do
|
174
174
|
subject[-2, 2].should == [Node.new(:name => 'foo'), Node.new(:name => 'bar')]
|
@@ -176,19 +176,19 @@ describe Node do
|
|
176
176
|
subject[-1, 1].should == [Node.new(:name => 'bar')]
|
177
177
|
end
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
context 'given an out-of-range index and a length' do
|
181
181
|
it 'returns nil' do
|
182
182
|
subject[3].should be_nil
|
183
183
|
end
|
184
184
|
end
|
185
|
-
|
185
|
+
|
186
186
|
context 'given an index exactly one past the last child and a length' do
|
187
187
|
it 'returns an empty array' do
|
188
188
|
subject[2, 2].should == []
|
189
189
|
end
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
context 'given a range' do
|
193
193
|
it 'return an array of children indexed by the range' do
|
194
194
|
subject[0..1].should == [Node.new(:name => 'foo'), Node.new(:name => 'bar')]
|
@@ -196,7 +196,7 @@ describe Node do
|
|
196
196
|
subject[1..1].should == [Node.new(:name => 'bar')]
|
197
197
|
end
|
198
198
|
end
|
199
|
-
|
199
|
+
|
200
200
|
context 'given a range with a negative index' do
|
201
201
|
it 'counts backward from the last child' do
|
202
202
|
subject[-2..-1].should == [Node.new(:name => 'foo'), Node.new(:name => 'bar')]
|
@@ -204,13 +204,13 @@ describe Node do
|
|
204
204
|
subject[-1..-1].should == [Node.new(:name => 'bar')]
|
205
205
|
end
|
206
206
|
end
|
207
|
-
|
207
|
+
|
208
208
|
context 'given a range with an out-of-range index' do
|
209
209
|
it 'returns nil' do
|
210
210
|
subject[3..3].should be_nil
|
211
211
|
end
|
212
212
|
end
|
213
|
-
|
213
|
+
|
214
214
|
context 'given a range starting exactly one past the last child' do
|
215
215
|
it 'returns an empty array' do
|
216
216
|
subject[2..2].should == []
|
@@ -218,101 +218,128 @@ describe Node do
|
|
218
218
|
end
|
219
219
|
end
|
220
220
|
end
|
221
|
-
|
221
|
+
|
222
222
|
describe '#count' do
|
223
223
|
context 'when the Node has children' do
|
224
224
|
subject do
|
225
225
|
Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar'))
|
226
226
|
end
|
227
|
-
|
227
|
+
|
228
228
|
it 'returns the number of children' do
|
229
229
|
subject.count.should == 2
|
230
230
|
end
|
231
231
|
end
|
232
|
-
|
232
|
+
|
233
233
|
context 'when the Node has no children' do
|
234
234
|
subject { Node.new }
|
235
|
-
|
235
|
+
|
236
236
|
it 'returns 0' do
|
237
237
|
subject.count.should == 0
|
238
238
|
end
|
239
239
|
end
|
240
240
|
end
|
241
|
-
|
241
|
+
|
242
242
|
describe '#==' do
|
243
243
|
subject { Node.new(Node.new(:name => 'foo'), :foo => 'bar') }
|
244
|
-
|
244
|
+
|
245
245
|
context 'given a node with the same children and attributes' do
|
246
246
|
it 'returns true' do
|
247
247
|
subject.should == Node.new(Node.new(:name => 'foo'), :foo => 'bar')
|
248
248
|
end
|
249
249
|
end
|
250
|
-
|
250
|
+
|
251
251
|
context 'given a node with different children' do
|
252
252
|
it 'returns false' do
|
253
253
|
subject.should_not == Node.new(Node.new(:name => 'boo'), :foo => 'bar')
|
254
254
|
end
|
255
255
|
end
|
256
|
-
|
256
|
+
|
257
257
|
context 'given a node with extra children' do
|
258
258
|
it 'returns false' do
|
259
259
|
subject.should_not ==
|
260
260
|
Node.new(Node.new(:name => 'boo'), Node.new, :foo => 'bar')
|
261
261
|
end
|
262
262
|
end
|
263
|
-
|
263
|
+
|
264
264
|
context 'given a node with no children' do
|
265
265
|
it 'returns false' do
|
266
266
|
subject.should_not == Node.new(:foo => 'bar')
|
267
267
|
end
|
268
268
|
end
|
269
|
-
|
269
|
+
|
270
270
|
context 'given a node with the same children and different attributes' do
|
271
271
|
it 'returns false' do
|
272
272
|
subject.should_not == Node.new(Node.new(:name => 'foo'), :foo => 'baz')
|
273
273
|
end
|
274
274
|
end
|
275
|
-
|
275
|
+
|
276
276
|
context 'given a node with the same children and extra attributes' do
|
277
277
|
it 'returns false' do
|
278
278
|
subject.should_not ==
|
279
279
|
Node.new(Node.new(:name => 'foo'), :foo => 'bar', :bar => 'baz')
|
280
280
|
end
|
281
281
|
end
|
282
|
-
|
282
|
+
|
283
283
|
context 'given a node with the same children but no attributes' do
|
284
284
|
it 'returns false' do
|
285
285
|
subject.should_not == Node.new(Node.new(:name => 'foo'))
|
286
286
|
end
|
287
287
|
end
|
288
288
|
end
|
289
|
-
|
289
|
+
|
290
|
+
describe '#each' do
|
291
|
+
|
292
|
+
subject { Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar')) }
|
293
|
+
|
294
|
+
let(:expected_items) do
|
295
|
+
[Node.new(:name => 'foo'), Node.new(:name => 'bar')]
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'iterates over #children' do
|
299
|
+
subject.each {|_| _.should == expected_items.shift }
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
describe '#with_children' do
|
304
|
+
|
305
|
+
subject { Node.new(Node.new(:name => 'foo'), Node.new(:name => 'bar')) }
|
306
|
+
|
307
|
+
let :new_children do
|
308
|
+
[Node.new(:name => 'boo'), Node.new(:name => 'baz')]
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'returns a new node with the children replaced' do
|
312
|
+
subject.with_children(new_children).should ==
|
313
|
+
Node.new(Node.new(:name => 'boo'), Node.new(:name => 'baz'))
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
290
317
|
describe '#method_missing' do
|
291
|
-
|
318
|
+
|
292
319
|
subject { Node.new(:foo => 'bar', :bar => nil) }
|
293
|
-
|
320
|
+
|
294
321
|
it 'provides accessor methods for attributes' do
|
295
322
|
subject.foo.should == 'bar'
|
296
323
|
subject.bar.should == nil
|
297
324
|
end
|
298
325
|
end
|
299
|
-
|
326
|
+
|
300
327
|
describe '#respond_to?' do
|
301
|
-
|
328
|
+
|
302
329
|
subject { Node.new(:foo => 'bar', :bar => nil) }
|
303
|
-
|
330
|
+
|
304
331
|
context 'given an attribute name' do
|
305
332
|
it 'returns true' do
|
306
333
|
subject.should respond_to(:foo)
|
307
334
|
subject.should respond_to(:bar)
|
308
335
|
end
|
309
336
|
end
|
310
|
-
|
337
|
+
|
311
338
|
context 'given a meaningless name' do
|
312
339
|
it 'returns false' do
|
313
340
|
subject.should_not respond_to(:fred)
|
314
341
|
end
|
315
342
|
end
|
316
343
|
end
|
317
|
-
|
344
|
+
|
318
345
|
end
|