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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +14 -0
- data/.standard.yml +1 -0
- data/CHANGELOG.md +57 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +48 -5
- data/README.md +153 -271
- data/flavour_saver.gemspec +17 -19
- data/lib/flavour_saver/error.rb +5 -0
- data/lib/flavour_saver/helpers.rb +19 -18
- data/lib/flavour_saver/lexer.rb +123 -50
- data/lib/flavour_saver/nodes.rb +107 -19
- data/lib/flavour_saver/parser.rb +339 -161
- data/lib/flavour_saver/partial.rb +4 -6
- data/lib/flavour_saver/rails_partial.rb +10 -4
- data/lib/flavour_saver/runtime.rb +76 -81
- data/lib/flavour_saver/template.rb +3 -5
- data/lib/flavour_saver/version.rb +1 -1
- data/lib/flavour_saver.rb +17 -17
- data/spec/acceptance/backtrack_spec.rb +9 -9
- data/spec/acceptance/comment_spec.rb +7 -7
- data/spec/acceptance/custom_block_helper_spec.rb +12 -12
- data/spec/acceptance/custom_helper_spec.rb +8 -8
- data/spec/acceptance/ensure_no_rce_spec.rb +64 -53
- data/spec/acceptance/handlebars_qunit_spec.rb +295 -297
- data/spec/acceptance/if_else_spec.rb +6 -6
- data/spec/acceptance/multi_level_with_spec.rb +10 -11
- data/spec/acceptance/nesting_depth_spec.rb +34 -0
- data/spec/acceptance/one_character_identifier_spec.rb +8 -8
- data/spec/acceptance/raw_block_spec.rb +7 -7
- data/spec/acceptance/sections_spec.rb +17 -14
- data/spec/acceptance/segment_literals_spec.rb +5 -5
- data/spec/acceptance/simple_expression_spec.rb +9 -9
- data/spec/acceptance/subexpression_spec.rb +18 -17
- data/spec/acceptance/unless_spec.rb +19 -6
- data/spec/lib/flavour_saver/lexer_spec.rb +103 -89
- data/spec/lib/flavour_saver/nodes_spec.rb +85 -0
- data/spec/lib/flavour_saver/parser_spec.rb +155 -95
- data/spec/lib/flavour_saver/runtime_spec.rb +94 -96
- data/spec/lib/flavour_saver/template_spec.rb +1 -2
- metadata +19 -48
|
@@ -1,82 +1,78 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "flavour_saver/lexer"
|
|
2
2
|
|
|
3
3
|
describe FlavourSaver::Lexer do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
9
|
+
it "begins with an EXPRST" do
|
|
14
10
|
expect(subject.first.type).to eq :EXPRST
|
|
15
11
|
end
|
|
16
12
|
|
|
17
|
-
it
|
|
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
|
|
20
|
+
expect(subject[1].value).to eq "foo"
|
|
25
21
|
end
|
|
26
22
|
end
|
|
27
23
|
|
|
28
|
-
describe
|
|
24
|
+
describe "{{foo bar}}" do
|
|
29
25
|
subject { FlavourSaver::Lexer.lex "{{foo bar}}" }
|
|
30
26
|
|
|
31
|
-
it
|
|
32
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
36
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
44
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
48
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
56
|
-
expect(subject.map(&:type)).to eq
|
|
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
|
|
60
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
68
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
72
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
72
|
+
describe "{{0}}" do
|
|
77
73
|
subject { FlavourSaver::Lexer.lex "{{0}}" }
|
|
78
74
|
|
|
79
|
-
it
|
|
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
|
|
84
|
+
expect(subject[1].value).to eq "0"
|
|
89
85
|
end
|
|
90
86
|
end
|
|
91
87
|
|
|
92
|
-
describe
|
|
88
|
+
describe "{{0.0123456789}}" do
|
|
93
89
|
subject { FlavourSaver::Lexer.lex "{{0.0123456789}}" }
|
|
94
90
|
|
|
95
|
-
it
|
|
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
|
|
100
|
+
expect(subject[1].value).to eq "0.0123456789"
|
|
105
101
|
end
|
|
106
102
|
end
|
|
107
103
|
end
|
|
108
104
|
|
|
109
|
-
describe
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
121
|
-
ids = %w
|
|
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
|
|
131
|
-
subject { FlavourSaver::Lexer.lex
|
|
125
|
+
describe "{{foo bar=(baz qux)}}" do
|
|
126
|
+
subject { FlavourSaver::Lexer.lex "{{foo bar=(baz qux)}}" }
|
|
132
127
|
|
|
133
|
-
it
|
|
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
|
|
138
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
143
|
-
subject { FlavourSaver::Lexer.lex
|
|
137
|
+
describe "{{else}}" do
|
|
138
|
+
subject { FlavourSaver::Lexer.lex "{{else}}" }
|
|
144
139
|
|
|
145
|
-
it
|
|
146
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
151
|
-
describe
|
|
145
|
+
describe "Object path expressions" do
|
|
146
|
+
describe "{{foo.bar}}" do
|
|
152
147
|
subject { FlavourSaver::Lexer.lex "{{foo.bar}}" }
|
|
153
148
|
|
|
154
|
-
it
|
|
155
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
159
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
158
|
+
describe "{{foo.[10].bar}}" do
|
|
164
159
|
subject { FlavourSaver::Lexer.lex "{{foo.[10].bar}}" }
|
|
165
160
|
|
|
166
|
-
it
|
|
167
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
171
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
179
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
183
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
183
|
+
describe "Triple-stash expressions" do
|
|
189
184
|
subject { FlavourSaver::Lexer.lex "{{{foo}}}" }
|
|
190
185
|
|
|
191
|
-
it
|
|
192
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
191
|
+
describe "Comment expressions" do
|
|
197
192
|
subject { FlavourSaver::Lexer.lex "{{! WAT}}" }
|
|
198
193
|
|
|
199
|
-
it
|
|
200
|
-
expect(subject.map(&:type)).to eq [
|
|
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
|
|
199
|
+
describe "Backtrack expression" do
|
|
205
200
|
subject { FlavourSaver::Lexer.lex "{{../foo}}" }
|
|
206
201
|
|
|
207
|
-
it
|
|
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
|
|
207
|
+
describe "Carriage-return and new-lines" do
|
|
213
208
|
subject { FlavourSaver::Lexer.lex "{{foo}}\n{{bar}}\r{{baz}}" }
|
|
214
209
|
|
|
215
|
-
it
|
|
216
|
-
expect(subject.map(&:type)).to eq [:EXPRST
|
|
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
|
|
215
|
+
describe "Block Expressions" do
|
|
221
216
|
subject { FlavourSaver::Lexer.lex "{{#foo}}{{bar}}{{/foo}}" }
|
|
222
217
|
|
|
223
|
-
describe
|
|
224
|
-
it
|
|
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
|
|
234
|
-
expect(subject.map(&:value).compact).to eq [
|
|
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
|
|
234
|
+
describe "Carriage return" do
|
|
240
235
|
subject { FlavourSaver::Lexer.lex "\r" }
|
|
241
236
|
|
|
242
|
-
it
|
|
243
|
-
expect(subject.map(&:type)).to eq [:OUT
|
|
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
|
|
242
|
+
describe "New line" do
|
|
248
243
|
subject { FlavourSaver::Lexer.lex "\n" }
|
|
249
244
|
|
|
250
|
-
it
|
|
251
|
-
expect(subject.map(&:type)).to eq [:OUT
|
|
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
|
|
250
|
+
describe "Single curly bracket" do
|
|
256
251
|
subject { FlavourSaver::Lexer.lex "{" }
|
|
257
252
|
|
|
258
|
-
it
|
|
259
|
-
expect(subject.map(&:type)).to eq [:OUT
|
|
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
|