flavour_saver 4.0.2 → 5.0.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +14 -0
  3. data/.standard.yml +1 -0
  4. data/CHANGELOG.md +57 -0
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +48 -5
  7. data/README.md +153 -271
  8. data/flavour_saver.gemspec +17 -19
  9. data/lib/flavour_saver/error.rb +5 -0
  10. data/lib/flavour_saver/helpers.rb +19 -18
  11. data/lib/flavour_saver/lexer.rb +123 -50
  12. data/lib/flavour_saver/nodes.rb +107 -19
  13. data/lib/flavour_saver/parser.rb +339 -161
  14. data/lib/flavour_saver/partial.rb +4 -6
  15. data/lib/flavour_saver/rails_partial.rb +10 -4
  16. data/lib/flavour_saver/runtime.rb +76 -81
  17. data/lib/flavour_saver/template.rb +3 -5
  18. data/lib/flavour_saver/version.rb +1 -1
  19. data/lib/flavour_saver.rb +17 -17
  20. data/spec/acceptance/backtrack_spec.rb +9 -9
  21. data/spec/acceptance/comment_spec.rb +7 -7
  22. data/spec/acceptance/custom_block_helper_spec.rb +12 -12
  23. data/spec/acceptance/custom_helper_spec.rb +8 -8
  24. data/spec/acceptance/ensure_no_rce_spec.rb +64 -53
  25. data/spec/acceptance/handlebars_qunit_spec.rb +295 -297
  26. data/spec/acceptance/if_else_spec.rb +6 -6
  27. data/spec/acceptance/multi_level_with_spec.rb +10 -11
  28. data/spec/acceptance/nesting_depth_spec.rb +34 -0
  29. data/spec/acceptance/one_character_identifier_spec.rb +8 -8
  30. data/spec/acceptance/raw_block_spec.rb +7 -7
  31. data/spec/acceptance/sections_spec.rb +17 -14
  32. data/spec/acceptance/segment_literals_spec.rb +5 -5
  33. data/spec/acceptance/simple_expression_spec.rb +9 -9
  34. data/spec/acceptance/subexpression_spec.rb +18 -17
  35. data/spec/acceptance/unless_spec.rb +19 -6
  36. data/spec/lib/flavour_saver/lexer_spec.rb +103 -89
  37. data/spec/lib/flavour_saver/nodes_spec.rb +85 -0
  38. data/spec/lib/flavour_saver/parser_spec.rb +155 -95
  39. data/spec/lib/flavour_saver/runtime_spec.rb +94 -96
  40. data/spec/lib/flavour_saver/template_spec.rb +1 -2
  41. metadata +19 -48
@@ -1,82 +1,78 @@
1
- require 'flavour_saver/lexer'
1
+ require "flavour_saver/lexer"
2
2
 
3
3
  describe FlavourSaver::Lexer do
4
- it 'is an RLTK lexer' do
5
- expect(subject).to be_a(RLTK::Lexer)
6
- end
7
-
8
- describe 'Tokens' do
9
- describe 'Expressions' do
10
- describe '{{foo}}' do
4
+ describe "Tokens" do
5
+ describe "Expressions" do
6
+ describe "{{foo}}" do
11
7
  subject { FlavourSaver::Lexer.lex "{{foo}}" }
12
8
 
13
- it 'begins with an EXPRST' do
9
+ it "begins with an EXPRST" do
14
10
  expect(subject.first.type).to eq :EXPRST
15
11
  end
16
12
 
17
- it 'ends with an EXPRE' do
13
+ it "ends with an EXPRE" do
18
14
  expect(subject[-2].type).to eq :EXPRE
19
15
  end
20
16
 
21
17
  it 'contains only the identifier "foo"' do
22
18
  expect(subject[1..-3].size).to eq 1
23
19
  expect(subject[1].type).to eq :IDENT
24
- expect(subject[1].value).to eq 'foo'
20
+ expect(subject[1].value).to eq "foo"
25
21
  end
26
22
  end
27
23
 
28
- describe '{{foo bar}}' do
24
+ describe "{{foo bar}}" do
29
25
  subject { FlavourSaver::Lexer.lex "{{foo bar}}" }
30
26
 
31
- it 'has tokens in the correct order' do
32
- expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :IDENT, :EXPRE, :EOS ]
27
+ it "has tokens in the correct order" do
28
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :WHITE, :IDENT, :EXPRE, :EOS]
33
29
  end
34
30
 
35
- it 'has values in the correct order' do
36
- expect(subject.map(&:value).compact).to eq [ 'foo', 'bar' ]
31
+ it "has values in the correct order" do
32
+ expect(subject.map(&:value).compact).to eq ["foo", "bar"]
37
33
  end
38
34
  end
39
35
 
40
36
  describe '{{foo "bar"}}' do
41
37
  subject { FlavourSaver::Lexer.lex "{{foo \"bar\"}}" }
42
38
 
43
- it 'has tokens in the correct order' do
44
- expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :STRING, :EXPRE, :EOS ]
39
+ it "has tokens in the correct order" do
40
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :WHITE, :STRING, :EXPRE, :EOS]
45
41
  end
46
42
 
47
- it 'has values in the correct order' do
48
- expect(subject.map(&:value).compact).to eq [ 'foo', 'bar' ]
43
+ it "has values in the correct order" do
44
+ expect(subject.map(&:value).compact).to eq ["foo", "bar"]
49
45
  end
50
46
  end
51
47
 
52
48
  describe '{{foo (bar "baz")}}' do
53
49
  subject { FlavourSaver::Lexer.lex "{{foo (bar 'baz')}}" }
54
50
 
55
- it 'has tokens in the correct order' do
56
- expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :OPAR, :IDENT, :WHITE, :S_STRING, :CPAR, :EXPRE, :EOS ]
51
+ it "has tokens in the correct order" do
52
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :WHITE, :OPAR, :IDENT, :WHITE, :S_STRING, :CPAR, :EXPRE, :EOS]
57
53
  end
58
54
 
59
- it 'has values in the correct order' do
60
- expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'baz' ]
55
+ it "has values in the correct order" do
56
+ expect(subject.map(&:value).compact).to eq ["foo", "bar", "baz"]
61
57
  end
62
58
  end
63
59
 
64
60
  describe '{{foo bar="baz" hello="goodbye"}}' do
65
61
  subject { FlavourSaver::Lexer.lex '{{foo bar="baz" hello="goodbye"}}' }
66
62
 
67
- it 'has tokens in the correct order' do
68
- expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :IDENT, :EQ, :STRING, :WHITE, :IDENT, :EQ, :STRING, :EXPRE, :EOS ]
63
+ it "has tokens in the correct order" do
64
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :WHITE, :IDENT, :EQ, :STRING, :WHITE, :IDENT, :EQ, :STRING, :EXPRE, :EOS]
69
65
  end
70
66
 
71
- it 'has values in the correct order' do
72
- expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'baz', 'hello', 'goodbye' ]
67
+ it "has values in the correct order" do
68
+ expect(subject.map(&:value).compact).to eq ["foo", "bar", "baz", "hello", "goodbye"]
73
69
  end
74
70
  end
75
71
 
76
- describe '{{0}}' do
72
+ describe "{{0}}" do
77
73
  subject { FlavourSaver::Lexer.lex "{{0}}" }
78
74
 
79
- it 'properly lexes the expression' do
75
+ it "properly lexes the expression" do
80
76
  expect(subject.map(&:type)).to eq(
81
77
  [:EXPRST, :NUMBER, :EXPRE, :EOS]
82
78
  )
@@ -85,14 +81,14 @@ describe FlavourSaver::Lexer do
85
81
  it 'contains only the number "0"' do
86
82
  expect(subject[1..-3].size).to eq 1
87
83
  expect(subject[1].type).to eq :NUMBER
88
- expect(subject[1].value).to eq '0'
84
+ expect(subject[1].value).to eq "0"
89
85
  end
90
86
  end
91
87
 
92
- describe '{{0.0123456789}}' do
88
+ describe "{{0.0123456789}}" do
93
89
  subject { FlavourSaver::Lexer.lex "{{0.0123456789}}" }
94
90
 
95
- it 'properly lexes the expression' do
91
+ it "properly lexes the expression" do
96
92
  expect(subject.map(&:type)).to eq(
97
93
  [:EXPRST, :NUMBER, :EXPRE, :EOS]
98
94
  )
@@ -101,15 +97,14 @@ describe FlavourSaver::Lexer do
101
97
  it 'contains only the number "0.0123456789"' do
102
98
  expect(subject[1..-3].size).to eq 1
103
99
  expect(subject[1].type).to eq :NUMBER
104
- expect(subject[1].value).to eq '0.0123456789'
100
+ expect(subject[1].value).to eq "0.0123456789"
105
101
  end
106
102
  end
107
103
  end
108
104
 
109
- describe 'Identities' do
110
-
111
- it 'supports as ruby methods' do
112
- ids = %w( _ __ __123__ __ABC__ ABC123 Abc134def )
105
+ describe "Identities" do
106
+ it "supports as ruby methods" do
107
+ ids = %w[_ __ __123__ __ABC__ ABC123 Abc134def]
113
108
  ids.each do |id|
114
109
  subject = FlavourSaver::Lexer.lex "{{#{id}}}"
115
110
  expect(subject[1].type).to eq :IDENT
@@ -117,8 +112,8 @@ describe FlavourSaver::Lexer do
117
112
  end
118
113
  end
119
114
 
120
- it 'maps non-ruby identities to literals' do
121
- ids = %w( A-B 12_Mine - :example 0A test? )
115
+ it "maps non-ruby identities to literals" do
116
+ ids = %w[A-B 12_Mine - :example 0A test?]
122
117
  ids.each do |id|
123
118
  subject = FlavourSaver::Lexer.lex "{{#{id}}}"
124
119
  expect(subject[1].type).to eq :LITERAL
@@ -127,101 +122,101 @@ describe FlavourSaver::Lexer do
127
122
  end
128
123
  end
129
124
 
130
- describe '{{foo bar=(baz qux)}}' do
131
- subject { FlavourSaver::Lexer.lex '{{foo bar=(baz qux)}}' }
125
+ describe "{{foo bar=(baz qux)}}" do
126
+ subject { FlavourSaver::Lexer.lex "{{foo bar=(baz qux)}}" }
132
127
 
133
- it 'has tokens in the correct order' do
128
+ it "has tokens in the correct order" do
134
129
  expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :WHITE, :IDENT, :EQ, :OPAR, :IDENT, :WHITE, :IDENT, :CPAR, :EXPRE, :EOS]
135
130
  end
136
131
 
137
- it 'has values in the correct order' do
138
- expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'baz', 'qux' ]
132
+ it "has values in the correct order" do
133
+ expect(subject.map(&:value).compact).to eq ["foo", "bar", "baz", "qux"]
139
134
  end
140
135
  end
141
136
 
142
- describe '{{else}}' do
143
- subject { FlavourSaver::Lexer.lex '{{else}}' }
137
+ describe "{{else}}" do
138
+ subject { FlavourSaver::Lexer.lex "{{else}}" }
144
139
 
145
- it 'has tokens in the correct order' do
146
- expect(subject.map(&:type)).to eq [ :EXPRST, :ELSE, :EXPRE, :EOS ]
140
+ it "has tokens in the correct order" do
141
+ expect(subject.map(&:type)).to eq [:EXPRST, :ELSE, :EXPRE, :EOS]
147
142
  end
148
143
  end
149
144
 
150
- describe 'Object path expressions' do
151
- describe '{{foo.bar}}' do
145
+ describe "Object path expressions" do
146
+ describe "{{foo.bar}}" do
152
147
  subject { FlavourSaver::Lexer.lex "{{foo.bar}}" }
153
148
 
154
- it 'has tokens in the correct order' do
155
- expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :DOT, :IDENT, :EXPRE, :EOS ]
149
+ it "has tokens in the correct order" do
150
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :DOT, :IDENT, :EXPRE, :EOS]
156
151
  end
157
152
 
158
- it 'has the correct values' do
159
- expect(subject.map(&:value).compact).to eq ['foo', 'bar']
153
+ it "has the correct values" do
154
+ expect(subject.map(&:value).compact).to eq ["foo", "bar"]
160
155
  end
161
156
  end
162
157
 
163
- describe '{{foo.[10].bar}}' do
158
+ describe "{{foo.[10].bar}}" do
164
159
  subject { FlavourSaver::Lexer.lex "{{foo.[10].bar}}" }
165
160
 
166
- it 'has tokens in the correct order' do
167
- expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS ]
161
+ it "has tokens in the correct order" do
162
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS]
168
163
  end
169
164
 
170
- it 'has the correct values' do
171
- expect(subject.map(&:value).compact).to eq ['foo', '10', 'bar']
165
+ it "has the correct values" do
166
+ expect(subject.map(&:value).compact).to eq ["foo", "10", "bar"]
172
167
  end
173
168
  end
174
169
 
175
170
  describe '{{foo.[he!@#$(&@klA)].bar}}' do
176
171
  subject { FlavourSaver::Lexer.lex '{{foo.[he!@#$(&@klA)].bar}}' }
177
172
 
178
- it 'has tokens in the correct order' do
179
- expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS ]
173
+ it "has tokens in the correct order" do
174
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS]
180
175
  end
181
176
 
182
- it 'has the correct values' do
183
- expect(subject.map(&:value).compact).to eq ['foo', 'he!@#$(&@klA)', 'bar']
177
+ it "has the correct values" do
178
+ expect(subject.map(&:value).compact).to eq ["foo", 'he!@#$(&@klA)', "bar"]
184
179
  end
185
180
  end
186
181
  end
187
182
 
188
- describe 'Triple-stash expressions' do
183
+ describe "Triple-stash expressions" do
189
184
  subject { FlavourSaver::Lexer.lex "{{{foo}}}" }
190
185
 
191
- it 'has tokens in the correct order' do
192
- expect(subject.map(&:type)).to eq [ :TEXPRST, :IDENT, :TEXPRE, :EOS ]
186
+ it "has tokens in the correct order" do
187
+ expect(subject.map(&:type)).to eq [:TEXPRST, :IDENT, :TEXPRE, :EOS]
193
188
  end
194
189
  end
195
190
 
196
- describe 'Comment expressions' do
191
+ describe "Comment expressions" do
197
192
  subject { FlavourSaver::Lexer.lex "{{! WAT}}" }
198
193
 
199
- it 'has tokens in the correct order' do
200
- expect(subject.map(&:type)).to eq [ :EXPRST, :BANG, :COMMENT, :EXPRE, :EOS ]
194
+ it "has tokens in the correct order" do
195
+ expect(subject.map(&:type)).to eq [:EXPRST, :BANG, :COMMENT, :EXPRE, :EOS]
201
196
  end
202
197
  end
203
198
 
204
- describe 'Backtrack expression' do
199
+ describe "Backtrack expression" do
205
200
  subject { FlavourSaver::Lexer.lex "{{../foo}}" }
206
201
 
207
- it 'has tokens in the correct order' do
202
+ it "has tokens in the correct order" do
208
203
  expect(subject.map(&:type)).to eq [:EXPRST, :DOT, :DOT, :FWSL, :IDENT, :EXPRE, :EOS]
209
204
  end
210
205
  end
211
206
 
212
- describe 'Carriage-return and new-lines' do
207
+ describe "Carriage-return and new-lines" do
213
208
  subject { FlavourSaver::Lexer.lex "{{foo}}\n{{bar}}\r{{baz}}" }
214
209
 
215
- it 'has tokens in the correct order' do
216
- expect(subject.map(&:type)).to eq [:EXPRST,:IDENT,:EXPRE,:OUT,:EXPRST,:IDENT,:EXPRE,:OUT,:EXPRST,:IDENT,:EXPRE,:EOS]
210
+ it "has tokens in the correct order" do
211
+ expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :EXPRE, :OUT, :EXPRST, :IDENT, :EXPRE, :OUT, :EXPRST, :IDENT, :EXPRE, :EOS]
217
212
  end
218
213
  end
219
214
 
220
- describe 'Block Expressions' do
215
+ describe "Block Expressions" do
221
216
  subject { FlavourSaver::Lexer.lex "{{#foo}}{{bar}}{{/foo}}" }
222
217
 
223
- describe '{{#foo}}{{bar}}{{/foo}}' do
224
- it 'has tokens in the correct order' do
218
+ describe "{{#foo}}{{bar}}{{/foo}}" do
219
+ it "has tokens in the correct order" do
225
220
  expect(subject.map(&:type)).to eq [
226
221
  :EXPRST, :HASH, :IDENT, :EXPRE,
227
222
  :EXPRST, :IDENT, :EXPRE,
@@ -230,34 +225,53 @@ describe FlavourSaver::Lexer do
230
225
  ]
231
226
  end
232
227
 
233
- it 'has identifiers in the correct order' do
234
- expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'foo' ]
228
+ it "has identifiers in the correct order" do
229
+ expect(subject.map(&:value).compact).to eq ["foo", "bar", "foo"]
235
230
  end
236
231
  end
237
232
  end
238
233
 
239
- describe 'Carriage return' do
234
+ describe "Carriage return" do
240
235
  subject { FlavourSaver::Lexer.lex "\r" }
241
236
 
242
- it 'has tokens in the correct order' do
243
- expect(subject.map(&:type)).to eq [:OUT,:EOS]
237
+ it "has tokens in the correct order" do
238
+ expect(subject.map(&:type)).to eq [:OUT, :EOS]
244
239
  end
245
240
  end
246
241
 
247
- describe 'New line' do
242
+ describe "New line" do
248
243
  subject { FlavourSaver::Lexer.lex "\n" }
249
244
 
250
- it 'has tokens in the correct order' do
251
- expect(subject.map(&:type)).to eq [:OUT,:EOS]
245
+ it "has tokens in the correct order" do
246
+ expect(subject.map(&:type)).to eq [:OUT, :EOS]
252
247
  end
253
248
  end
254
249
 
255
- describe 'Single curly bracket' do
250
+ describe "Single curly bracket" do
256
251
  subject { FlavourSaver::Lexer.lex "{" }
257
252
 
258
- it 'has tokens in the correct order' do
259
- expect(subject.map(&:type)).to eq [:OUT,:EOS]
253
+ it "has tokens in the correct order" do
254
+ expect(subject.map(&:type)).to eq [:OUT, :EOS]
260
255
  end
261
256
  end
262
257
  end
258
+ describe "{{foo %}}" do
259
+ subject { FlavourSaver::Lexer.lex "{{foo %}}" }
260
+
261
+ it "raises a lexing error naming the unmatched input" do
262
+ expect { subject }.to raise_error(FlavourSaver::Lexer::LexingError, /: %}}\z/)
263
+ end
264
+
265
+ it "is a FlavourSaver::Error" do
266
+ expect { subject }.to raise_error(FlavourSaver::Error)
267
+ end
268
+ end
269
+
270
+ describe "an unlexable expression followed by a long template" do
271
+ subject { FlavourSaver::Lexer.lex "{{foo %}}#{"x" * 1000}" }
272
+
273
+ it "quotes only the start of the unmatched input" do
274
+ expect { subject }.to raise_error(FlavourSaver::Lexer::LexingError, /: %}}x{47}\.\.\.\z/)
275
+ end
276
+ end
263
277
  end
@@ -0,0 +1,85 @@
1
+ require "flavour_saver/nodes"
2
+
3
+ describe FlavourSaver::Node do
4
+ describe "field inheritance" do
5
+ let(:parent) { Class.new(FlavourSaver::Node) { value :name, String } }
6
+
7
+ it "gives a subclass the fields its parent had when the subclass was defined" do
8
+ subclass = Class.new(parent)
9
+ parent.value :depth, Integer
10
+
11
+ expect(subclass.value_names).to eq [:name]
12
+ end
13
+
14
+ it "doesn't add a subclass's fields to its parent" do
15
+ Class.new(parent) { value :depth, Integer }
16
+
17
+ expect(parent.value_names).to eq [:name]
18
+ end
19
+ end
20
+
21
+ describe "field types" do
22
+ let(:call) { FlavourSaver::CallNode.new("foo", []) }
23
+
24
+ it "accepts fields of the declared types" do
25
+ expression = FlavourSaver::ExpressionNode.new([call])
26
+
27
+ expect(expression.method).to eq [call]
28
+ expect(call.parent).to eq expression
29
+ end
30
+
31
+ it "accepts nil for a field typed with a class" do
32
+ expect(FlavourSaver::PartialNode.new("foo", [], nil).context_value).to be_nil
33
+ end
34
+
35
+ it "raises TypeMismatch for a value of the wrong class" do
36
+ expect { FlavourSaver::CallNode.new(:foo, []) }
37
+ .to raise_error(FlavourSaver::Node::TypeMismatch, "FlavourSaver::CallNode#name must be String, not Symbol")
38
+ end
39
+
40
+ it "raises TypeMismatch for a child of the wrong class" do
41
+ expect { FlavourSaver::BlockExpressionNode.new([call], call) }
42
+ .to raise_error(FlavourSaver::Node::TypeMismatch, /#contents must be FlavourSaver::TemplateNode, not FlavourSaver::CallNode/)
43
+ end
44
+
45
+ it "raises TypeMismatch for an array containing the wrong class" do
46
+ expect { FlavourSaver::ExpressionNode.new([call, FlavourSaver::StringNode.new("bar")]) }
47
+ .to raise_error(FlavourSaver::Node::TypeMismatch, /#method must be \[FlavourSaver::CallNode\], not an Array of FlavourSaver::CallNode, FlavourSaver::StringNode/)
48
+ end
49
+
50
+ it "raises TypeMismatch when an array field is not an array" do
51
+ expect { FlavourSaver::ExpressionNode.new({foo: call}) }
52
+ .to raise_error(FlavourSaver::Node::TypeMismatch, /#method must be \[FlavourSaver::CallNode\], not Hash/)
53
+ expect { FlavourSaver::ExpressionNode.new(nil) }.to raise_error(FlavourSaver::Node::TypeMismatch)
54
+ end
55
+
56
+ it "checks fields set after the node is built" do
57
+ expect { call.name = 1 }.to raise_error(FlavourSaver::Node::TypeMismatch)
58
+ end
59
+
60
+ it "is a StandardError, as RLTK::TypeMismatch was" do
61
+ expect(FlavourSaver::Node::TypeMismatch.superclass).to eq StandardError
62
+ end
63
+ end
64
+
65
+ describe "field declarations" do
66
+ it "requires a type" do
67
+ expect { Class.new(FlavourSaver::Node) { value :name } }.to raise_error(ArgumentError)
68
+ end
69
+
70
+ it "doesn't allow a value to be typed as a node" do
71
+ expect { Class.new(FlavourSaver::Node) { value :call, FlavourSaver::CallNode } }
72
+ .to raise_error(ArgumentError, /type can't be a Node/)
73
+ end
74
+
75
+ it "requires a child to be typed as a node" do
76
+ expect { Class.new(FlavourSaver::Node) { child :name, [String] } }
77
+ .to raise_error(ArgumentError, /type must be a Node/)
78
+ end
79
+
80
+ it "requires the type to be a class or a class in an array" do
81
+ expect { Class.new(FlavourSaver::Node) { child :calls, [FlavourSaver::CallNode, FlavourSaver::StringNode] } }
82
+ .to raise_error(ArgumentError, /must have a class, or a class in an array/)
83
+ end
84
+ end
85
+ end