hotcell 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +15 -0
- data/Guardfile +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +17 -0
- data/hotcell.gemspec +22 -0
- data/lib/hotcell/.DS_Store +0 -0
- data/lib/hotcell/config.rb +31 -0
- data/lib/hotcell/context.rb +36 -0
- data/lib/hotcell/errors.rb +43 -0
- data/lib/hotcell/extensions.rb +42 -0
- data/lib/hotcell/lexer.rb +783 -0
- data/lib/hotcell/lexer.rl +299 -0
- data/lib/hotcell/manipulator.rb +31 -0
- data/lib/hotcell/node/arrayer.rb +7 -0
- data/lib/hotcell/node/assigner.rb +11 -0
- data/lib/hotcell/node/block.rb +58 -0
- data/lib/hotcell/node/calculator.rb +35 -0
- data/lib/hotcell/node/command.rb +41 -0
- data/lib/hotcell/node/hasher.rb +7 -0
- data/lib/hotcell/node/joiner.rb +7 -0
- data/lib/hotcell/node/sequencer.rb +7 -0
- data/lib/hotcell/node/summoner.rb +11 -0
- data/lib/hotcell/node/tag.rb +26 -0
- data/lib/hotcell/node.rb +55 -0
- data/lib/hotcell/parser.rb +1186 -0
- data/lib/hotcell/parser.y +231 -0
- data/lib/hotcell/scope.rb +57 -0
- data/lib/hotcell/template.rb +29 -0
- data/lib/hotcell/version.rb +3 -0
- data/lib/hotcell.rb +19 -0
- data/misc/rage.rl +1999 -0
- data/misc/unicode2ragel.rb +305 -0
- data/spec/data/dstrings +8 -0
- data/spec/data/sstrings +6 -0
- data/spec/lib/hotcell/config_spec.rb +57 -0
- data/spec/lib/hotcell/context_spec.rb +53 -0
- data/spec/lib/hotcell/lexer_spec.rb +340 -0
- data/spec/lib/hotcell/manipulator_spec.rb +64 -0
- data/spec/lib/hotcell/node/block_spec.rb +188 -0
- data/spec/lib/hotcell/node/command_spec.rb +71 -0
- data/spec/lib/hotcell/parser_spec.rb +382 -0
- data/spec/lib/hotcell/scope_spec.rb +160 -0
- data/spec/lib/hotcell/template_spec.rb +41 -0
- data/spec/lib/hotcell_spec.rb +8 -0
- data/spec/spec_helper.rb +44 -0
- metadata +139 -0
@@ -0,0 +1,382 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Hotcell::Parser do
|
5
|
+
def method_missing method, *args, &block
|
6
|
+
klass = Hotcell::Calculator::HANDLERS[method] ?
|
7
|
+
Hotcell::Calculator : Hotcell::Node
|
8
|
+
|
9
|
+
instance = Hotcell::Assigner.new *args if method == :ASSIGN
|
10
|
+
instance = Hotcell::Summoner.new *args if method == :METHOD
|
11
|
+
klass = Hotcell::Arrayer if [:ARRAY, :PAIR].include?(method)
|
12
|
+
klass = Hotcell::Hasher if method == :HASH
|
13
|
+
klass = Hotcell::Sequencer if method == :SEQUENCE
|
14
|
+
|
15
|
+
klass = Hotcell::Tag if method == :TAG
|
16
|
+
instance = Hotcell::Command.new *args if method == :COMMAND
|
17
|
+
instance = Hotcell::Block.new *args if method == :BLOCK
|
18
|
+
klass = Hotcell::Joiner if method == :JOINER
|
19
|
+
|
20
|
+
instance || klass.new(method, *args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse *args
|
24
|
+
described_class.new(*args).parse
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'template' do
|
28
|
+
specify { parse('').should be_equal_node_to JOINER() }
|
29
|
+
specify { parse(' ').should be_equal_node_to JOINER(' ') }
|
30
|
+
specify { parse('{{ }}').should be_equal_node_to JOINER(TAG(mode: :normal)) }
|
31
|
+
specify { parse('hello {{ }}').should be_equal_node_to JOINER('hello ', TAG(mode: :normal)) }
|
32
|
+
specify { parse('{{ }}hello').should be_equal_node_to JOINER(TAG(mode: :normal), 'hello') }
|
33
|
+
specify { parse('hello{{ }} hello').should be_equal_node_to JOINER('hello', TAG(mode: :normal), ' hello') }
|
34
|
+
specify { parse('hello {{ hello(\'world\') }} hello').should be_equal_node_to JOINER(
|
35
|
+
'hello ', TAG(METHOD(nil, 'hello', 'world'), mode: :normal), ' hello'
|
36
|
+
) }
|
37
|
+
specify { parse('hello {{ hello(\'world\') }} hello {{! a = 5; }} {}').should be_equal_node_to JOINER(
|
38
|
+
'hello ', TAG(METHOD(nil, 'hello', 'world'), mode: :normal),
|
39
|
+
' hello ', TAG(ASSIGN('a', 5), mode: :silence), ' {}'
|
40
|
+
) }
|
41
|
+
specify { parse('{{ hello(\'world\') }} hello {{! a = 5; }} {}').should be_equal_node_to JOINER(
|
42
|
+
TAG(METHOD(nil, 'hello', 'world'), mode: :normal),
|
43
|
+
' hello ', TAG(ASSIGN('a', 5), mode: :silence), ' {}'
|
44
|
+
) }
|
45
|
+
specify { parse('{{ hello(\'world\') }} hello {{! a = 5; }}').should be_equal_node_to JOINER(
|
46
|
+
TAG(METHOD(nil, 'hello', 'world'), mode: :normal),
|
47
|
+
' hello ', TAG(ASSIGN('a', 5), mode: :silence)
|
48
|
+
) }
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'multiline' do
|
52
|
+
specify { parse(<<-TPL
|
53
|
+
{{
|
54
|
+
hello;
|
55
|
+
42
|
56
|
+
[1, 2, 3];
|
57
|
+
|
58
|
+
;
|
59
|
+
|
60
|
+
|
61
|
+
"hello"; {}
|
62
|
+
(/regexp/; 43)
|
63
|
+
|
64
|
+
foo = (3; 5)
|
65
|
+
bar = 3; 5
|
66
|
+
}}
|
67
|
+
TPL
|
68
|
+
).should be_equal_node_to JOINER(' ', TAG(
|
69
|
+
METHOD(nil, 'hello'),
|
70
|
+
42,
|
71
|
+
ARRAY(1, 2, 3),
|
72
|
+
'hello',
|
73
|
+
HASH(),
|
74
|
+
SEQUENCE(/regexp/, 43),
|
75
|
+
ASSIGN('foo', SEQUENCE(3, 5)),
|
76
|
+
ASSIGN('bar', 3),
|
77
|
+
5,
|
78
|
+
mode: :normal), "\n") }
|
79
|
+
specify { parse(<<-TPL
|
80
|
+
{{
|
81
|
+
foo(
|
82
|
+
)
|
83
|
+
hello(
|
84
|
+
7,
|
85
|
+
8
|
86
|
+
)
|
87
|
+
!
|
88
|
+
true
|
89
|
+
[
|
90
|
+
]
|
91
|
+
2 +
|
92
|
+
foo
|
93
|
+
46 -
|
94
|
+
moo
|
95
|
+
46
|
96
|
+
- moo
|
97
|
+
2 **
|
98
|
+
bar
|
99
|
+
false ||
|
100
|
+
nil
|
101
|
+
baz >=
|
102
|
+
5; foo =
|
103
|
+
10
|
104
|
+
{
|
105
|
+
}
|
106
|
+
[
|
107
|
+
42, 43,
|
108
|
+
44
|
109
|
+
]
|
110
|
+
{
|
111
|
+
foo: 'hello',
|
112
|
+
bar:
|
113
|
+
'world'
|
114
|
+
}
|
115
|
+
}}
|
116
|
+
TPL
|
117
|
+
).should be_equal_node_to JOINER(' ', TAG(
|
118
|
+
METHOD(nil, 'foo'),
|
119
|
+
METHOD(nil, 'hello', 7, 8),
|
120
|
+
false,
|
121
|
+
ARRAY(),
|
122
|
+
PLUS(2, METHOD(nil, 'foo')),
|
123
|
+
MINUS(46, METHOD(nil, 'moo')),
|
124
|
+
46,
|
125
|
+
UMINUS(METHOD(nil, 'moo')),
|
126
|
+
POWER(2, METHOD(nil, 'bar')),
|
127
|
+
nil,
|
128
|
+
GTE(METHOD(nil, 'baz'), 5),
|
129
|
+
ASSIGN('foo', 10),
|
130
|
+
HASH(),
|
131
|
+
ARRAY(42, 43, 44),
|
132
|
+
HASH(PAIR('foo', 'hello'), PAIR('bar', 'world')),
|
133
|
+
mode: :normal), "\n") }
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'expressions' do
|
137
|
+
specify { parse('{{ 2 + hello }}').should be_equal_node_to JOINER(TAG(PLUS(2, METHOD(nil, 'hello')), mode: :normal)) }
|
138
|
+
specify { parse('{{ --2 }}').should be_equal_node_to JOINER(TAG(2, mode: :normal)) }
|
139
|
+
specify { parse('{{ --hello }}').should be_equal_node_to JOINER(TAG(UMINUS(UMINUS(METHOD(nil, 'hello'))), mode: :normal)) }
|
140
|
+
specify { parse('{{ \'hello\' + \'world\' }}').should be_equal_node_to JOINER(TAG('helloworld', mode: :normal)) }
|
141
|
+
specify { parse('{{ 2 - hello }}').should be_equal_node_to JOINER(TAG(MINUS(2, METHOD(nil, 'hello')), mode: :normal)) }
|
142
|
+
specify { parse('{{ 2 * hello }}').should be_equal_node_to JOINER(TAG(MULTIPLY(2, METHOD(nil, 'hello')), mode: :normal)) }
|
143
|
+
specify { parse('{{ 2 / hello }}').should be_equal_node_to JOINER(TAG(DIVIDE(2, METHOD(nil, 'hello')), mode: :normal)) }
|
144
|
+
specify { parse('{{ 2 % hello }}').should be_equal_node_to JOINER(TAG(MODULO(2, METHOD(nil, 'hello')), mode: :normal)) }
|
145
|
+
specify { parse('{{ 2 ** hello }}').should be_equal_node_to JOINER(TAG(POWER(2, METHOD(nil, 'hello')), mode: :normal)) }
|
146
|
+
specify { parse('{{ -hello }}').should be_equal_node_to JOINER(TAG(UMINUS(METHOD(nil, 'hello')), mode: :normal)) }
|
147
|
+
specify { parse('{{ +hello }}').should be_equal_node_to JOINER(TAG(UPLUS(METHOD(nil, 'hello')), mode: :normal)) }
|
148
|
+
specify { parse('{{ -2 }}').should be_equal_node_to JOINER(TAG(-2, mode: :normal)) }
|
149
|
+
specify { parse('{{ +2 }}').should be_equal_node_to JOINER(TAG(2, mode: :normal)) }
|
150
|
+
specify { parse('{{ 2 + lol * 2 }}').should be_equal_node_to JOINER(TAG(PLUS(2, MULTIPLY(METHOD(nil, 'lol'), 2)), mode: :normal)) }
|
151
|
+
specify { parse('{{ 2 + lol - 2 }}').should be_equal_node_to JOINER(TAG(MINUS(PLUS(2, METHOD(nil, 'lol')), 2), mode: :normal)) }
|
152
|
+
specify { parse('{{ 2 ** foo * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(POWER(2, METHOD(nil, 'foo')), 2), mode: :normal)) }
|
153
|
+
specify { parse('{{ 1 ** foo ** 3 }}').should be_equal_node_to JOINER(TAG(POWER(1, POWER(METHOD(nil, 'foo'), 3)), mode: :normal)) }
|
154
|
+
specify { parse('{{ (2 + foo) * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(PLUS(2, METHOD(nil, 'foo')), 2), mode: :normal)) }
|
155
|
+
specify { parse('{{ (nil) }}').should be_equal_node_to JOINER(TAG(nil, mode: :normal)) }
|
156
|
+
specify { parse('{{ (3) }}').should be_equal_node_to JOINER(TAG(3, mode: :normal)) }
|
157
|
+
specify { parse('{{ (\'hello\') }}').should be_equal_node_to JOINER(TAG('hello', mode: :normal)) }
|
158
|
+
specify { parse('{{ () }}').should be_equal_node_to JOINER(TAG(nil, mode: :normal)) }
|
159
|
+
|
160
|
+
specify { parse('{{ bar > 2 }}').should be_equal_node_to JOINER(TAG(GT(METHOD(nil, 'bar'), 2), mode: :normal)) }
|
161
|
+
specify { parse('{{ 2 < bar }}').should be_equal_node_to JOINER(TAG(LT(2, METHOD(nil, 'bar')), mode: :normal)) }
|
162
|
+
specify { parse('{{ 2 >= tru }}').should be_equal_node_to JOINER(TAG(GTE(2, METHOD(nil, 'tru')), mode: :normal)) }
|
163
|
+
specify { parse('{{ some <= 2 }}').should be_equal_node_to JOINER(TAG(LTE(METHOD(nil, 'some'), 2), mode: :normal)) }
|
164
|
+
specify { parse('{{ 2 && false }}').should be_equal_node_to JOINER(TAG(false, mode: :normal)) }
|
165
|
+
specify { parse('{{ null || 2 }}').should be_equal_node_to JOINER(TAG(2, mode: :normal)) }
|
166
|
+
specify { parse('{{ 2 > bar < 2 }}').should be_equal_node_to JOINER(TAG(LT(GT(2, METHOD(nil, 'bar')), 2), mode: :normal)) }
|
167
|
+
specify { parse('{{ 2 || bar && 2 }}').should be_equal_node_to JOINER(TAG(OR(2, AND(METHOD(nil, 'bar'), 2)), mode: :normal)) }
|
168
|
+
specify { parse('{{ 2 && foo || 2 }}').should be_equal_node_to JOINER(TAG(OR(AND(2, METHOD(nil, 'foo')), 2), mode: :normal)) }
|
169
|
+
specify { parse('{{ !2 && moo }}').should be_equal_node_to JOINER(TAG(AND(false, METHOD(nil, 'moo')), mode: :normal)) }
|
170
|
+
specify { parse('{{ !(2 && moo) }}').should be_equal_node_to JOINER(TAG(NOT(AND(2, METHOD(nil, 'moo'))), mode: :normal)) }
|
171
|
+
|
172
|
+
specify { parse('{{ hello = bzz + 2 }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', PLUS(METHOD(nil, 'bzz'), 2)), mode: :normal)) }
|
173
|
+
specify { parse('{{ hello = 2 ** bar }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', POWER(2, METHOD(nil, 'bar'))), mode: :normal)) }
|
174
|
+
specify { parse('{{ hello = 2 == 2 }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', true), mode: :normal)) }
|
175
|
+
specify { parse('{{ hello = 2 && var }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', AND(2, METHOD(nil, 'var'))), mode: :normal)) }
|
176
|
+
specify { parse('{{ hello = world() }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', METHOD(nil, 'world')), mode: :normal)) }
|
177
|
+
specify { parse('{{ !hello = 2 >= 2 }}').should be_equal_node_to JOINER(TAG(NOT(ASSIGN('hello', true)), mode: :normal)) }
|
178
|
+
|
179
|
+
specify { parse('{{ !foo ** 2 + 3 }}').should be_equal_node_to JOINER(TAG(PLUS(POWER(NOT(METHOD(nil, 'foo')), 2), 3), mode: :normal)) }
|
180
|
+
specify { parse('{{ -bla ** 2 }}').should be_equal_node_to JOINER(TAG(UMINUS(POWER(METHOD(nil, 'bla'), 2)), mode: :normal)) }
|
181
|
+
specify { parse('{{ -2 % bla }}').should be_equal_node_to JOINER(TAG(MODULO(-2, METHOD(nil, 'bla')), mode: :normal)) }
|
182
|
+
specify { parse('{{ -hello ** 2 }}').should be_equal_node_to JOINER(TAG(UMINUS(POWER(METHOD(nil, 'hello'), 2)), mode: :normal)) }
|
183
|
+
specify { parse('{{ -hello * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(UMINUS(METHOD(nil, 'hello')), 2), mode: :normal)) }
|
184
|
+
specify { parse('{{ haha + 2 == 2 * 2 }}').should be_equal_node_to JOINER(TAG(EQUAL(PLUS(METHOD(nil, 'haha'), 2), 4), mode: :normal)) }
|
185
|
+
specify { parse('{{ 2 * foo != 2 && bar }}').should be_equal_node_to JOINER(TAG(AND(INEQUAL(MULTIPLY(2, METHOD(nil, 'foo')), 2), METHOD(nil, 'bar')), mode: :normal)) }
|
186
|
+
|
187
|
+
context 'method call' do
|
188
|
+
specify { parse('{{ foo.bar.baz }}').should be_equal_node_to JOINER(TAG(
|
189
|
+
METHOD(METHOD(METHOD(nil, 'foo'), 'bar'), 'baz'),
|
190
|
+
mode: :normal)) }
|
191
|
+
specify { parse('{{ foo(\'hello\').bar[2].baz(-42) }}').should be_equal_node_to JOINER(TAG(
|
192
|
+
METHOD(
|
193
|
+
METHOD(
|
194
|
+
METHOD(
|
195
|
+
METHOD(
|
196
|
+
nil, 'foo', 'hello'
|
197
|
+
), 'bar'
|
198
|
+
), '[]', 2
|
199
|
+
), 'baz', -42
|
200
|
+
),
|
201
|
+
mode: :normal)) }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'arrays' do
|
206
|
+
specify { parse('{{ [] }}').should be_equal_node_to JOINER(TAG(ARRAY(), mode: :normal)) }
|
207
|
+
specify { parse('{{ [ 2 ] }}').should be_equal_node_to JOINER(TAG(ARRAY(2), mode: :normal)) }
|
208
|
+
specify { parse('{{ [ 2, 3 ] }}').should be_equal_node_to JOINER(TAG(ARRAY(2, 3), mode: :normal)) }
|
209
|
+
specify { parse('{{ [2, 3][42] }}').should be_equal_node_to JOINER(TAG(METHOD(ARRAY(2, 3), '[]', 42), mode: :normal)) }
|
210
|
+
specify { parse('{{ [2 + foo, (2 * bar)] }}').should be_equal_node_to JOINER(TAG(ARRAY(PLUS(2, METHOD(nil, 'foo')), MULTIPLY(2, METHOD(nil, 'bar'))), mode: :normal)) }
|
211
|
+
specify { parse('{{ [[2, 3], 42] }}').should be_equal_node_to JOINER(TAG(ARRAY(ARRAY(2, 3), 42), mode: :normal)) }
|
212
|
+
end
|
213
|
+
|
214
|
+
context 'hashes' do
|
215
|
+
specify { parse('{{ {} }}').should be_equal_node_to JOINER(TAG(HASH(), mode: :normal)) }
|
216
|
+
specify { parse('{{ { hello: \'world\' } }}').should be_equal_node_to(
|
217
|
+
JOINER(TAG(HASH(PAIR('hello', 'world')), mode: :normal))
|
218
|
+
) }
|
219
|
+
specify { parse('{{ {hello: \'world\'}[\'hello\'] }}').should be_equal_node_to(
|
220
|
+
JOINER(TAG(METHOD(HASH(PAIR('hello', 'world')), '[]', 'hello'), mode: :normal))
|
221
|
+
) }
|
222
|
+
specify { parse('{{ { hello: 3, world: 6 * foo } }}').should be_equal_node_to(
|
223
|
+
JOINER(TAG(HASH(
|
224
|
+
PAIR('hello', 3),
|
225
|
+
PAIR('world', MULTIPLY(6, METHOD(nil, 'foo')))
|
226
|
+
), mode: :normal))
|
227
|
+
) }
|
228
|
+
end
|
229
|
+
|
230
|
+
context '[]' do
|
231
|
+
specify { parse('{{ hello[3] }}').should be_equal_node_to JOINER(TAG(METHOD(METHOD(nil, 'hello'), '[]', 3), mode: :normal)) }
|
232
|
+
specify { parse('{{ \'boom\'[3] }}').should be_equal_node_to JOINER(TAG(METHOD('boom', '[]', 3), mode: :normal)) }
|
233
|
+
specify { parse('{{ 7[3] }}').should be_equal_node_to JOINER(TAG(METHOD(7, '[]', 3), mode: :normal)) }
|
234
|
+
specify { parse('{{ 3 + 5[7] }}').should be_equal_node_to JOINER(TAG(PLUS(3, METHOD(5, '[]', 7)), mode: :normal)) }
|
235
|
+
specify { parse('{{ (3 + 5)[7] }}').should be_equal_node_to JOINER(TAG(METHOD(8, '[]', 7), mode: :normal)) }
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'function arguments' do
|
239
|
+
specify { parse('{{ hello() }}').should be_equal_node_to JOINER(TAG(METHOD(nil, 'hello'), mode: :normal)) }
|
240
|
+
specify { parse('{{ hello(2 * foo) }}').should be_equal_node_to(
|
241
|
+
JOINER(TAG(METHOD(nil, 'hello', MULTIPLY(2, METHOD(nil, 'foo'))), mode: :normal))
|
242
|
+
) }
|
243
|
+
specify { parse('{{ hello([2 * car]) }}').should be_equal_node_to(
|
244
|
+
JOINER(TAG(METHOD(nil, 'hello', ARRAY(MULTIPLY(2, METHOD(nil, 'car')))), mode: :normal))
|
245
|
+
) }
|
246
|
+
specify { parse('{{ hello({hello: \'world\'}) }}').should be_equal_node_to(
|
247
|
+
JOINER(TAG(METHOD(nil, 'hello', HASH(PAIR('hello', 'world'))), mode: :normal))
|
248
|
+
) }
|
249
|
+
specify { parse('{{ hello(hello: \'world\') }}').should be_equal_node_to(
|
250
|
+
JOINER(TAG(METHOD(nil, 'hello', HASH(PAIR('hello', 'world'))), mode: :normal))
|
251
|
+
) }
|
252
|
+
specify { parse('{{ hello(2 * foo, \'bla\', {hello: \'world\'}) }}').should be_equal_node_to(
|
253
|
+
JOINER(TAG(METHOD(nil, 'hello',
|
254
|
+
MULTIPLY(2, METHOD(nil, 'foo')),
|
255
|
+
'bla',
|
256
|
+
HASH(PAIR('hello', 'world'))
|
257
|
+
), mode: :normal))
|
258
|
+
) }
|
259
|
+
specify { parse('{{ hello(moo * 3, \'bla\', hello: \'world\') }}').should be_equal_node_to(
|
260
|
+
JOINER(TAG(METHOD(nil, 'hello',
|
261
|
+
MULTIPLY(METHOD(nil, 'moo'), 3),
|
262
|
+
'bla',
|
263
|
+
HASH(PAIR('hello', 'world'))
|
264
|
+
), mode: :normal))
|
265
|
+
) }
|
266
|
+
end
|
267
|
+
|
268
|
+
context 'sequences' do
|
269
|
+
specify { parse('{{ 42; }}').should be_equal_node_to JOINER(TAG(42, mode: :normal)) }
|
270
|
+
specify { parse('{{ (42) }}').should be_equal_node_to JOINER(TAG(42, mode: :normal)) }
|
271
|
+
specify { parse('{{ ((42)) }}').should be_equal_node_to JOINER(TAG(42, mode: :normal)) }
|
272
|
+
specify { parse('{{ ;;;; }}').should be_equal_node_to JOINER(TAG(mode: :normal)) }
|
273
|
+
specify { parse('{{ ;;;;;;; 42 }}').should be_equal_node_to JOINER(TAG(42, mode: :normal)) }
|
274
|
+
specify { parse('{{ ;;;111;;;; 42 }}').should be_equal_node_to JOINER(TAG(111, 42, mode: :normal)) }
|
275
|
+
specify { parse("{{ 42 ;;;;\n;;; }}").should be_equal_node_to JOINER(TAG(42, mode: :normal)) }
|
276
|
+
specify { parse('{{ 42 ;;;;;;1 }}').should be_equal_node_to JOINER(TAG(42, 1, mode: :normal)) }
|
277
|
+
specify { parse('{{ 42; 43 }}').should be_equal_node_to JOINER(TAG(42, 43, mode: :normal)) }
|
278
|
+
specify { parse('{{ ; 42; 43 }}').should be_equal_node_to JOINER(TAG(42, 43, mode: :normal)) }
|
279
|
+
specify { parse('{{ 42; 43; 44 }}').should be_equal_node_to JOINER(TAG(42, 43, 44, mode: :normal)) }
|
280
|
+
specify { parse('{{ 42; \'hello\'; 44; }}').should be_equal_node_to JOINER(TAG(42, 'hello', 44, mode: :normal)) }
|
281
|
+
specify { parse('{{ (42; \'hello\'); 44; }}').should be_equal_node_to JOINER(TAG(SEQUENCE(42, 'hello'), 44, mode: :normal)) }
|
282
|
+
specify { parse('{{ 42; (\'hello\'; 44;) }}').should be_equal_node_to JOINER(TAG(42, SEQUENCE('hello', 44), mode: :normal)) }
|
283
|
+
specify { parse('{{ hello(42, (43; 44), 45) }}').should be_equal_node_to JOINER(TAG(METHOD(nil, 'hello', 42, SEQUENCE(43, 44), 45), mode: :normal)) }
|
284
|
+
specify { parse('{{ hello(42, ((43; 44)), 45) }}').should be_equal_node_to JOINER(TAG(METHOD(nil, 'hello', 42, SEQUENCE(43, 44), 45), mode: :normal)) }
|
285
|
+
specify { parse('{{ hello((42)) }}').should be_equal_node_to JOINER(TAG(METHOD(nil, 'hello', 42), mode: :normal)) }
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'comments' do
|
289
|
+
specify { parse('hello # world').should be_equal_node_to JOINER('hello # world') }
|
290
|
+
specify { parse('hello {{# world').should be_equal_node_to JOINER('hello ') }
|
291
|
+
specify { parse('hello {{# world #}} friend').should be_equal_node_to JOINER('hello ', ' friend') }
|
292
|
+
specify { parse('hello {{!# world #}}').should be_equal_node_to JOINER('hello ', TAG(mode: :silence)) }
|
293
|
+
specify { parse('hello {{ # world}}').should be_equal_node_to JOINER('hello ', TAG(mode: :normal)) }
|
294
|
+
specify { parse('hello {{ # world; foo}}').should be_equal_node_to JOINER('hello ', TAG(mode: :normal)) }
|
295
|
+
specify { parse("hello {{ # world\n foo}}").should be_equal_node_to JOINER('hello ', TAG(METHOD(nil, 'foo'), mode: :normal)) }
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'commands' do
|
299
|
+
specify { parse("{{ include 'some/partial' }}",
|
300
|
+
commands: [:include, :snippet]).should be_equal_node_to JOINER(
|
301
|
+
COMMAND('include', 'some/partial', mode: :normal)
|
302
|
+
) }
|
303
|
+
specify { parse("{{ include }}",
|
304
|
+
commands: [:include, :snippet]).should be_equal_node_to JOINER(
|
305
|
+
COMMAND('include', mode: :normal)
|
306
|
+
) }
|
307
|
+
specify { parse("{{! include 'some/partial' }}\n{{ snippet 'sidebar' }}",
|
308
|
+
commands: [:include, :snippet]).should be_equal_node_to JOINER(
|
309
|
+
COMMAND('include', 'some/partial', mode: :silence),
|
310
|
+
"\n",
|
311
|
+
COMMAND('snippet', 'sidebar', mode: :normal),
|
312
|
+
) }
|
313
|
+
specify { parse("{{! variable = include }}",
|
314
|
+
commands: [:include, :snippet]).should be_equal_node_to JOINER(
|
315
|
+
COMMAND('include', mode: :silence, assign: 'variable')
|
316
|
+
) }
|
317
|
+
specify { parse("{{ variable = include 'some/partial' }}",
|
318
|
+
commands: [:include, :snippet]).should be_equal_node_to JOINER(
|
319
|
+
COMMAND('include', 'some/partial', mode: :normal, assign: 'variable')
|
320
|
+
) }
|
321
|
+
end
|
322
|
+
|
323
|
+
context 'blocks' do
|
324
|
+
specify { parse("{{ scoped var: 'hello' }}{{ endscoped }}",
|
325
|
+
blocks: [:scoped, :for]).should be_equal_node_to JOINER(
|
326
|
+
BLOCK('scoped', HASH(PAIR('var', 'hello')), mode: :normal)
|
327
|
+
) }
|
328
|
+
specify { parse("{{ scoped }}{{ end scoped }}",
|
329
|
+
blocks: [:scoped, :for]).should be_equal_node_to JOINER(
|
330
|
+
BLOCK('scoped', mode: :normal)
|
331
|
+
) }
|
332
|
+
specify { parse("<article>\n{{ for post, in: posts }}\n<h1>{{ post.title }}</h1>\n{{ end for }}\n</article>",
|
333
|
+
blocks: [:scoped, :for]).should be_equal_node_to JOINER(
|
334
|
+
"<article>\n",
|
335
|
+
BLOCK('for',
|
336
|
+
METHOD(nil, 'post'),
|
337
|
+
HASH(PAIR('in', METHOD(nil, 'posts'))),
|
338
|
+
mode: :normal,
|
339
|
+
subnodes: [JOINER(
|
340
|
+
"\n<h1>",
|
341
|
+
TAG(METHOD(METHOD(nil, 'post'), 'title'), mode: :normal),
|
342
|
+
"</h1>\n"
|
343
|
+
)]
|
344
|
+
),
|
345
|
+
"\n</article>"
|
346
|
+
) }
|
347
|
+
specify { parse("{{! posts = for post, in: posts }}\n<h1>{{ post.title }}</h1>\n{{ end for }}",
|
348
|
+
blocks: [:scoped, :for]).should be_equal_node_to JOINER(
|
349
|
+
BLOCK('for',
|
350
|
+
METHOD(nil, 'post'),
|
351
|
+
HASH(PAIR('in', METHOD(nil, 'posts'))),
|
352
|
+
mode: :silence,
|
353
|
+
assign: 'posts',
|
354
|
+
subnodes: [JOINER(
|
355
|
+
"\n<h1>",
|
356
|
+
TAG(METHOD(METHOD(nil, 'post'), 'title'), mode: :normal),
|
357
|
+
"</h1>\n"
|
358
|
+
)]
|
359
|
+
),
|
360
|
+
) }
|
361
|
+
specify { parse("{{ capture = scoped }} hello {{ for post, in: posts }} {{ loop }} {{ end for }}{{ endscoped }}",
|
362
|
+
blocks: [:scoped, :for]).should be_equal_node_to JOINER(
|
363
|
+
BLOCK('scoped',
|
364
|
+
mode: :normal,
|
365
|
+
assign: 'capture',
|
366
|
+
subnodes: [JOINER(
|
367
|
+
' hello ',
|
368
|
+
BLOCK('for',
|
369
|
+
METHOD(nil, 'post'),
|
370
|
+
HASH(PAIR('in', METHOD(nil, 'posts'))),
|
371
|
+
mode: :normal,
|
372
|
+
subnodes: [JOINER(
|
373
|
+
' ',
|
374
|
+
TAG(METHOD(nil, 'loop'), mode: :normal),
|
375
|
+
' '
|
376
|
+
)]
|
377
|
+
)
|
378
|
+
)]
|
379
|
+
)
|
380
|
+
) }
|
381
|
+
end
|
382
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hotcell::Scope do
|
4
|
+
subject { described_class.new }
|
5
|
+
describe '#initialize' do
|
6
|
+
its(:scope) { should == [{}] }
|
7
|
+
specify { described_class.new(foo: 1, 'bar' => 2).send(:scope).should == [{foo: 1, 'bar' => 2}] }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#push' do
|
11
|
+
context do
|
12
|
+
before { subject.push(hello: 'world') }
|
13
|
+
its(:scope) { should == [{}, {hello: 'world'}] }
|
14
|
+
end
|
15
|
+
|
16
|
+
context do
|
17
|
+
before do
|
18
|
+
subject.push(hello: 'world')
|
19
|
+
subject.push(hello: 'hell', foo: 42)
|
20
|
+
end
|
21
|
+
its(:scope) { should == [{}, {hello: 'world'}, {hello: 'hell', foo: 42}] }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#pop' do
|
26
|
+
subject { described_class.new bar: 'baz' }
|
27
|
+
before do
|
28
|
+
subject.send(:cache)
|
29
|
+
subject.push(hello: 'world')
|
30
|
+
subject.push(hello: 'hell', foo: 42)
|
31
|
+
subject.send(:cache)
|
32
|
+
end
|
33
|
+
|
34
|
+
context do
|
35
|
+
specify { subject[:bar].should == 'baz' }
|
36
|
+
specify { subject[:hello].should == 'hell' }
|
37
|
+
specify { subject[:foo].should == 42 }
|
38
|
+
end
|
39
|
+
|
40
|
+
context do
|
41
|
+
before { subject.pop }
|
42
|
+
its(:scope) { should == [{bar: 'baz'}, {hello: 'world'}] }
|
43
|
+
specify { subject[:bar].should == 'baz' }
|
44
|
+
specify { subject[:hello].should == 'world' }
|
45
|
+
specify { subject[:foo].should be_nil }
|
46
|
+
end
|
47
|
+
|
48
|
+
context do
|
49
|
+
before { 2.times { subject.pop } }
|
50
|
+
its(:scope) { should == [{bar: 'baz'}] }
|
51
|
+
specify { subject[:bar].should == 'baz' }
|
52
|
+
specify { subject[:hello].should be_nil }
|
53
|
+
specify { subject[:foo].should be_nil }
|
54
|
+
end
|
55
|
+
|
56
|
+
context do
|
57
|
+
before { 4.times { subject.pop } }
|
58
|
+
its(:scope) { should == [{bar: 'baz'}] }
|
59
|
+
specify { subject[:bar].should == 'baz' }
|
60
|
+
specify { subject[:hello].should be_nil }
|
61
|
+
specify { subject[:foo].should be_nil }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#scoped' do
|
66
|
+
specify do
|
67
|
+
subject.send(:scope).should == [{}]
|
68
|
+
subject.scoped(foo: 'bar') do
|
69
|
+
subject.send(:scope).should == [{}, {foo: 'bar'}]
|
70
|
+
subject.scoped(moo: 'baz', hello: 42) do
|
71
|
+
subject.send(:scope).should == [{}, {foo: 'bar'}, {moo: 'baz', hello: 42}]
|
72
|
+
end
|
73
|
+
subject.send(:scope).should == [{}, {foo: 'bar'}]
|
74
|
+
end
|
75
|
+
subject.send(:scope).should == [{}]
|
76
|
+
end
|
77
|
+
|
78
|
+
specify 'exception safety' do
|
79
|
+
begin
|
80
|
+
subject.send(:scope).should == [{}]
|
81
|
+
subject.scoped(foo: 'bar') do
|
82
|
+
subject.send(:scope).should == [{}, {foo: 'bar'}]
|
83
|
+
raise
|
84
|
+
end
|
85
|
+
rescue
|
86
|
+
subject.send(:scope).should == [{}]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#[]' do
|
92
|
+
subject { described_class.new bar: 'baz' }
|
93
|
+
|
94
|
+
specify { subject[:foo].should be_nil }
|
95
|
+
specify { subject['bar'].should be_nil }
|
96
|
+
specify { subject[:bar].should == 'baz' }
|
97
|
+
|
98
|
+
context do
|
99
|
+
before do
|
100
|
+
subject.push(hello: 42)
|
101
|
+
subject.push(bar: 'world')
|
102
|
+
end
|
103
|
+
|
104
|
+
specify { subject[:hello].should == 42 }
|
105
|
+
specify { subject[:bar].should == 'world' }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#key?' do
|
110
|
+
subject { described_class.new bar: 'baz' }
|
111
|
+
|
112
|
+
specify { subject.key?(:foo).should be_false }
|
113
|
+
specify { subject.key?('bar').should be_false }
|
114
|
+
specify { subject.key?(:bar).should be_true }
|
115
|
+
|
116
|
+
context do
|
117
|
+
before do
|
118
|
+
subject.push(hello: 42)
|
119
|
+
subject.push(bar: 'world')
|
120
|
+
end
|
121
|
+
|
122
|
+
specify { subject.key?(:hello).should be_true }
|
123
|
+
specify { subject.key?(:bar).should be_true }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '#[]=' do
|
128
|
+
subject { described_class.new bar: 'baz' }
|
129
|
+
|
130
|
+
context do
|
131
|
+
before do
|
132
|
+
subject['foo'] = 1
|
133
|
+
subject[:foo] = 2
|
134
|
+
end
|
135
|
+
|
136
|
+
its(:scope) { should == [{bar: "baz", 'foo' => 1, foo: 2}] }
|
137
|
+
specify { subject['foo'].should == 1 }
|
138
|
+
specify { subject[:foo].should == 2 }
|
139
|
+
end
|
140
|
+
|
141
|
+
context do
|
142
|
+
before do
|
143
|
+
subject.push(hello: 42)
|
144
|
+
subject.push(bar: 'world')
|
145
|
+
subject.send(:cache)
|
146
|
+
end
|
147
|
+
|
148
|
+
before do
|
149
|
+
subject['foo'] = 1
|
150
|
+
subject[:bar] = 2
|
151
|
+
subject[:hello] = 3
|
152
|
+
end
|
153
|
+
|
154
|
+
its(:scope) { should == [{bar: 'baz'}, {hello: 3}, {bar: 2, 'foo' => 1}] }
|
155
|
+
specify { subject['foo'].should == 1 }
|
156
|
+
specify { subject[:bar].should == 2 }
|
157
|
+
specify { subject[:hello].should == 3 }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hotcell::Template do
|
4
|
+
describe '.parse' do
|
5
|
+
before do
|
6
|
+
Hotcell.stub(:commands) { { 'include' => Class.new } }
|
7
|
+
Hotcell.stub(:blocks) { { 'for' => Class.new } }
|
8
|
+
Hotcell.stub(:subcommands) { { 'else' => Class.new } }
|
9
|
+
end
|
10
|
+
|
11
|
+
specify { described_class.parse('').should be_a described_class }
|
12
|
+
specify { described_class.parse('').options.should == {
|
13
|
+
commands: ['include'], blocks: ['for'], subcommands: ['else']
|
14
|
+
} }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#syntax' do
|
18
|
+
specify { described_class.new('').syntax.should be_a Hotcell::Joiner }
|
19
|
+
specify { described_class.new('hello').syntax.should be_a Hotcell::Joiner }
|
20
|
+
specify { described_class.new('hello {{ tag }}').syntax.should be_a Hotcell::Joiner }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#render' do
|
24
|
+
context do
|
25
|
+
subject { described_class.new('Hello, {{ name }}!') }
|
26
|
+
specify { subject.render.should == 'Hello, !' }
|
27
|
+
specify { subject.render(variables: { name: 'Friend' }).should == 'Hello, Friend!' }
|
28
|
+
end
|
29
|
+
|
30
|
+
context do
|
31
|
+
subject { described_class.new('Hello, {{ name * 2 }}!') }
|
32
|
+
specify { subject.render.should =~ /Hello.*NoMethodError/ }
|
33
|
+
specify { subject.render(variables: { name: 'Friend' }).should == 'Hello, FriendFriend!' }
|
34
|
+
end
|
35
|
+
|
36
|
+
context do
|
37
|
+
subject { described_class.new('Hello, {{! name }}!') }
|
38
|
+
specify { subject.render(variables: { name: 'Friend' }).should == 'Hello, !' }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'hotcell'
|
2
|
+
require 'awesome_print'
|
3
|
+
|
4
|
+
AwesomePrint::Formatter.class_eval do
|
5
|
+
def cast_with_hotcell_node(object, type)
|
6
|
+
cast = cast_without_hotcell_node(object, type)
|
7
|
+
cast = :hotcell_node if object.is_a?(Hotcell::Node)
|
8
|
+
cast
|
9
|
+
end
|
10
|
+
|
11
|
+
def awesome_hotcell_node(object)
|
12
|
+
"#{colorize(object.class.name, :class)} #{colorize(object.name.to_s, :method)}" +
|
13
|
+
((awesome_hash(object.options) + "\n") if object.options.present?).to_s +
|
14
|
+
awesome_array(object.children)
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method_chain :cast, :hotcell_node
|
18
|
+
end
|
19
|
+
|
20
|
+
RSpec::Matchers.define :be_equal_node_to do |expected|
|
21
|
+
match do |actual|
|
22
|
+
actual == expected
|
23
|
+
end
|
24
|
+
|
25
|
+
failure_message_for_should do |actual|
|
26
|
+
"expected:\n#{expected.ai(raw: true, indent: 2)}\ngot:\n#{actual.ai(raw: true, indent: 2)}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
RSpec.configure do |config|
|
31
|
+
def data name
|
32
|
+
File.read File.join(File.dirname(__FILE__), 'data', name)
|
33
|
+
end
|
34
|
+
|
35
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
36
|
+
config.run_all_when_everything_filtered = true
|
37
|
+
config.filter_run :focus
|
38
|
+
|
39
|
+
# Run specs in random order to surface order dependencies. If you find an
|
40
|
+
# order dependency and want to debug it, you can fix the order by providing
|
41
|
+
# the seed, which is printed after each run.
|
42
|
+
# --seed 1234
|
43
|
+
config.order = 'random'
|
44
|
+
end
|