hotcell 0.0.1
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/.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
|