hotcell 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -1
- data/.rspec +1 -0
- data/.rvmrc +1 -1
- data/.travis.yml +7 -0
- data/Gemfile +4 -1
- data/README.md +361 -2
- data/Rakefile +28 -6
- data/ext/lexerc/extconf.rb +3 -0
- data/ext/lexerc/lexerc.c +618 -0
- data/ext/lexerc/lexerc.h +20 -0
- data/ext/lexerc/lexerc.rl +167 -0
- data/hotcell.gemspec +8 -7
- data/lib/hotcell/commands/case.rb +59 -0
- data/lib/hotcell/commands/cycle.rb +38 -0
- data/lib/hotcell/commands/for.rb +70 -0
- data/lib/hotcell/commands/if.rb +51 -0
- data/lib/hotcell/commands/include.rb +21 -0
- data/lib/hotcell/commands/scope.rb +13 -0
- data/lib/hotcell/commands/unless.rb +23 -0
- data/lib/hotcell/commands.rb +13 -0
- data/lib/hotcell/config.rb +33 -6
- data/lib/hotcell/context.rb +40 -7
- data/lib/hotcell/errors.rb +37 -28
- data/lib/hotcell/extensions.rb +4 -0
- data/lib/hotcell/lexer.rb +19 -635
- data/lib/hotcell/lexerr.rb +572 -0
- data/lib/hotcell/lexerr.rl +137 -0
- data/lib/hotcell/node/assigner.rb +1 -5
- data/lib/hotcell/node/block.rb +17 -40
- data/lib/hotcell/node/command.rb +29 -22
- data/lib/hotcell/node/hasher.rb +1 -1
- data/lib/hotcell/node/summoner.rb +2 -6
- data/lib/hotcell/node/tag.rb +10 -7
- data/lib/hotcell/node.rb +12 -1
- data/lib/hotcell/parser.rb +474 -408
- data/lib/hotcell/parser.y +175 -117
- data/lib/hotcell/resolver.rb +44 -0
- data/lib/hotcell/source.rb +35 -0
- data/lib/hotcell/template.rb +15 -6
- data/lib/hotcell/version.rb +1 -1
- data/lib/hotcell.rb +15 -10
- data/spec/data/templates/simple.hc +1 -0
- data/spec/lib/hotcell/commands/case_spec.rb +39 -0
- data/spec/lib/hotcell/commands/cycle_spec.rb +29 -0
- data/spec/lib/hotcell/commands/for_spec.rb +65 -0
- data/spec/lib/hotcell/commands/if_spec.rb +35 -0
- data/spec/lib/hotcell/commands/include_spec.rb +39 -0
- data/spec/lib/hotcell/commands/scope_spec.rb +16 -0
- data/spec/lib/hotcell/commands/unless_spec.rb +23 -0
- data/spec/lib/hotcell/config_spec.rb +35 -10
- data/spec/lib/hotcell/context_spec.rb +58 -18
- data/spec/lib/hotcell/lexer_spec.rb +37 -28
- data/spec/lib/hotcell/node/block_spec.rb +28 -56
- data/spec/lib/hotcell/node/command_spec.rb +7 -31
- data/spec/lib/hotcell/node/tag_spec.rb +16 -0
- data/spec/lib/hotcell/parser_spec.rb +152 -123
- data/spec/lib/hotcell/resolver_spec.rb +28 -0
- data/spec/lib/hotcell/source_spec.rb +41 -0
- data/spec/lib/hotcell/template_spec.rb +47 -4
- data/spec/lib/hotcell_spec.rb +2 -1
- data/spec/spec_helper.rb +6 -2
- metadata +54 -24
- data/lib/hotcell/.DS_Store +0 -0
- data/lib/hotcell/lexer.rl +0 -299
- data/misc/rage.rl +0 -1999
- data/misc/unicode2ragel.rb +0 -305
@@ -32,18 +32,18 @@ describe Hotcell::Parser do
|
|
32
32
|
specify { parse('{{ }}hello').should be_equal_node_to JOINER(TAG(mode: :normal), 'hello') }
|
33
33
|
specify { parse('hello{{ }} hello').should be_equal_node_to JOINER('hello', TAG(mode: :normal), ' hello') }
|
34
34
|
specify { parse('hello {{ hello(\'world\') }} hello').should be_equal_node_to JOINER(
|
35
|
-
'hello ', TAG(METHOD(
|
35
|
+
'hello ', TAG(METHOD('hello', nil, 'world'), mode: :normal), ' hello'
|
36
36
|
) }
|
37
37
|
specify { parse('hello {{ hello(\'world\') }} hello {{! a = 5; }} {}').should be_equal_node_to JOINER(
|
38
|
-
'hello ', TAG(METHOD(
|
38
|
+
'hello ', TAG(METHOD('hello', nil, 'world'), mode: :normal),
|
39
39
|
' hello ', TAG(ASSIGN('a', 5), mode: :silence), ' {}'
|
40
40
|
) }
|
41
41
|
specify { parse('{{ hello(\'world\') }} hello {{! a = 5; }} {}').should be_equal_node_to JOINER(
|
42
|
-
TAG(METHOD(
|
42
|
+
TAG(METHOD('hello', nil, 'world'), mode: :normal),
|
43
43
|
' hello ', TAG(ASSIGN('a', 5), mode: :silence), ' {}'
|
44
44
|
) }
|
45
45
|
specify { parse('{{ hello(\'world\') }} hello {{! a = 5; }}').should be_equal_node_to JOINER(
|
46
|
-
TAG(METHOD(
|
46
|
+
TAG(METHOD('hello', nil, 'world'), mode: :normal),
|
47
47
|
' hello ', TAG(ASSIGN('a', 5), mode: :silence)
|
48
48
|
) }
|
49
49
|
end
|
@@ -66,7 +66,7 @@ describe Hotcell::Parser do
|
|
66
66
|
}}
|
67
67
|
TPL
|
68
68
|
).should be_equal_node_to JOINER(' ', TAG(
|
69
|
-
METHOD(
|
69
|
+
METHOD('hello'),
|
70
70
|
42,
|
71
71
|
ARRAY(1, 2, 3),
|
72
72
|
'hello',
|
@@ -115,17 +115,17 @@ describe Hotcell::Parser do
|
|
115
115
|
}}
|
116
116
|
TPL
|
117
117
|
).should be_equal_node_to JOINER(' ', TAG(
|
118
|
-
METHOD(
|
119
|
-
METHOD(
|
118
|
+
METHOD('foo'),
|
119
|
+
METHOD('hello', nil, 7, 8),
|
120
120
|
false,
|
121
121
|
ARRAY(),
|
122
|
-
PLUS(2, METHOD(
|
123
|
-
MINUS(46, METHOD(
|
122
|
+
PLUS(2, METHOD('foo')),
|
123
|
+
MINUS(46, METHOD('moo')),
|
124
124
|
46,
|
125
|
-
UMINUS(METHOD(
|
126
|
-
POWER(2, METHOD(
|
125
|
+
UMINUS(METHOD('moo')),
|
126
|
+
POWER(2, METHOD('bar')),
|
127
127
|
nil,
|
128
|
-
GTE(METHOD(
|
128
|
+
GTE(METHOD('baz'), 5),
|
129
129
|
ASSIGN('foo', 10),
|
130
130
|
HASH(),
|
131
131
|
ARRAY(42, 43, 44),
|
@@ -134,69 +134,79 @@ describe Hotcell::Parser do
|
|
134
134
|
end
|
135
135
|
|
136
136
|
context 'expressions' do
|
137
|
-
specify { parse('{{ 2 + hello }}').should be_equal_node_to JOINER(TAG(PLUS(2, METHOD(
|
137
|
+
specify { parse('{{ 2 + hello }}').should be_equal_node_to JOINER(TAG(PLUS(2, METHOD('hello')), mode: :normal)) }
|
138
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(
|
139
|
+
specify { parse('{{ --hello }}').should be_equal_node_to JOINER(TAG(UMINUS(UMINUS(METHOD('hello'))), mode: :normal)) }
|
140
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(
|
142
|
-
specify { parse('{{ 2 * hello }}').should be_equal_node_to JOINER(TAG(MULTIPLY(2, METHOD(
|
143
|
-
specify { parse('{{ 2 / hello }}').should be_equal_node_to JOINER(TAG(DIVIDE(2, METHOD(
|
144
|
-
specify { parse('{{ 2 % hello }}').should be_equal_node_to JOINER(TAG(MODULO(2, METHOD(
|
145
|
-
specify { parse('{{ 2 ** hello }}').should be_equal_node_to JOINER(TAG(POWER(2, METHOD(
|
146
|
-
specify { parse('{{ -hello }}').should be_equal_node_to JOINER(TAG(UMINUS(METHOD(
|
147
|
-
specify { parse('{{ +hello }}').should be_equal_node_to JOINER(TAG(UPLUS(METHOD(
|
141
|
+
specify { parse('{{ 2 - hello }}').should be_equal_node_to JOINER(TAG(MINUS(2, METHOD('hello')), mode: :normal)) }
|
142
|
+
specify { parse('{{ 2 * hello }}').should be_equal_node_to JOINER(TAG(MULTIPLY(2, METHOD('hello')), mode: :normal)) }
|
143
|
+
specify { parse('{{ 2 / hello }}').should be_equal_node_to JOINER(TAG(DIVIDE(2, METHOD('hello')), mode: :normal)) }
|
144
|
+
specify { parse('{{ 2 % hello }}').should be_equal_node_to JOINER(TAG(MODULO(2, METHOD('hello')), mode: :normal)) }
|
145
|
+
specify { parse('{{ 2 ** hello }}').should be_equal_node_to JOINER(TAG(POWER(2, METHOD('hello')), mode: :normal)) }
|
146
|
+
specify { parse('{{ -hello }}').should be_equal_node_to JOINER(TAG(UMINUS(METHOD('hello')), mode: :normal)) }
|
147
|
+
specify { parse('{{ +hello }}').should be_equal_node_to JOINER(TAG(UPLUS(METHOD('hello')), mode: :normal)) }
|
148
148
|
specify { parse('{{ -2 }}').should be_equal_node_to JOINER(TAG(-2, mode: :normal)) }
|
149
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(
|
151
|
-
specify { parse('{{ 2 + lol - 2 }}').should be_equal_node_to JOINER(TAG(MINUS(PLUS(2, METHOD(
|
152
|
-
specify { parse('{{ 2 ** foo * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(POWER(2, METHOD(
|
153
|
-
specify { parse('{{ 1 ** foo ** 3 }}').should be_equal_node_to JOINER(TAG(POWER(1, POWER(METHOD(
|
154
|
-
specify { parse('{{ (2 + foo) * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(PLUS(2, METHOD(
|
150
|
+
specify { parse('{{ 2 + lol * 2 }}').should be_equal_node_to JOINER(TAG(PLUS(2, MULTIPLY(METHOD('lol'), 2)), mode: :normal)) }
|
151
|
+
specify { parse('{{ 2 + lol - 2 }}').should be_equal_node_to JOINER(TAG(MINUS(PLUS(2, METHOD('lol')), 2), mode: :normal)) }
|
152
|
+
specify { parse('{{ 2 ** foo * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(POWER(2, METHOD('foo')), 2), mode: :normal)) }
|
153
|
+
specify { parse('{{ 1 ** foo ** 3 }}').should be_equal_node_to JOINER(TAG(POWER(1, POWER(METHOD('foo'), 3)), mode: :normal)) }
|
154
|
+
specify { parse('{{ (2 + foo) * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(PLUS(2, METHOD('foo')), 2), mode: :normal)) }
|
155
155
|
specify { parse('{{ (nil) }}').should be_equal_node_to JOINER(TAG(nil, mode: :normal)) }
|
156
156
|
specify { parse('{{ (3) }}').should be_equal_node_to JOINER(TAG(3, mode: :normal)) }
|
157
157
|
specify { parse('{{ (\'hello\') }}').should be_equal_node_to JOINER(TAG('hello', mode: :normal)) }
|
158
158
|
specify { parse('{{ () }}').should be_equal_node_to JOINER(TAG(nil, mode: :normal)) }
|
159
159
|
|
160
|
-
specify { parse('{{ bar > 2 }}').should be_equal_node_to JOINER(TAG(GT(METHOD(
|
161
|
-
specify { parse('{{ 2 < bar }}').should be_equal_node_to JOINER(TAG(LT(2, METHOD(
|
162
|
-
specify { parse('{{ 2 >= tru }}').should be_equal_node_to JOINER(TAG(GTE(2, METHOD(
|
163
|
-
specify { parse('{{ some <= 2 }}').should be_equal_node_to JOINER(TAG(LTE(METHOD(
|
160
|
+
specify { parse('{{ bar > 2 }}').should be_equal_node_to JOINER(TAG(GT(METHOD('bar'), 2), mode: :normal)) }
|
161
|
+
specify { parse('{{ 2 < bar }}').should be_equal_node_to JOINER(TAG(LT(2, METHOD('bar')), mode: :normal)) }
|
162
|
+
specify { parse('{{ 2 >= tru }}').should be_equal_node_to JOINER(TAG(GTE(2, METHOD('tru')), mode: :normal)) }
|
163
|
+
specify { parse('{{ some <= 2 }}').should be_equal_node_to JOINER(TAG(LTE(METHOD('some'), 2), mode: :normal)) }
|
164
164
|
specify { parse('{{ 2 && false }}').should be_equal_node_to JOINER(TAG(false, mode: :normal)) }
|
165
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(
|
167
|
-
specify { parse('{{ 2 || bar && 2 }}').should be_equal_node_to JOINER(TAG(OR(2, AND(METHOD(
|
168
|
-
specify { parse('{{ 2 && foo || 2 }}').should be_equal_node_to JOINER(TAG(OR(AND(2, METHOD(
|
169
|
-
specify { parse('{{ !2 && moo }}').should be_equal_node_to JOINER(TAG(AND(false, METHOD(
|
170
|
-
specify { parse('{{ !(2 && moo) }}').should be_equal_node_to JOINER(TAG(NOT(AND(2, METHOD(
|
166
|
+
specify { parse('{{ 2 > bar < 2 }}').should be_equal_node_to JOINER(TAG(LT(GT(2, METHOD('bar')), 2), mode: :normal)) }
|
167
|
+
specify { parse('{{ 2 || bar && 2 }}').should be_equal_node_to JOINER(TAG(OR(2, AND(METHOD('bar'), 2)), mode: :normal)) }
|
168
|
+
specify { parse('{{ 2 && foo || 2 }}').should be_equal_node_to JOINER(TAG(OR(AND(2, METHOD('foo')), 2), mode: :normal)) }
|
169
|
+
specify { parse('{{ !2 && moo }}').should be_equal_node_to JOINER(TAG(AND(false, METHOD('moo')), mode: :normal)) }
|
170
|
+
specify { parse('{{ !(2 && moo) }}').should be_equal_node_to JOINER(TAG(NOT(AND(2, METHOD('moo'))), mode: :normal)) }
|
171
171
|
|
172
|
-
specify { parse('{{ hello = bzz + 2 }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', PLUS(METHOD(
|
173
|
-
specify { parse('{{ hello = 2 ** bar }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', POWER(2, METHOD(
|
172
|
+
specify { parse('{{ hello = bzz + 2 }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', PLUS(METHOD('bzz'), 2)), mode: :normal)) }
|
173
|
+
specify { parse('{{ hello = 2 ** bar }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', POWER(2, METHOD('bar'))), mode: :normal)) }
|
174
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(
|
176
|
-
specify { parse('{{ hello = world() }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', METHOD(
|
175
|
+
specify { parse('{{ hello = 2 && var }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', AND(2, METHOD('var'))), mode: :normal)) }
|
176
|
+
specify { parse('{{ hello = world() }}').should be_equal_node_to JOINER(TAG(ASSIGN('hello', METHOD('world')), mode: :normal)) }
|
177
177
|
specify { parse('{{ !hello = 2 >= 2 }}').should be_equal_node_to JOINER(TAG(NOT(ASSIGN('hello', true)), mode: :normal)) }
|
178
178
|
|
179
|
-
specify { parse('{{ !foo ** 2 + 3 }}').should be_equal_node_to JOINER(TAG(PLUS(POWER(NOT(METHOD(
|
180
|
-
specify { parse('{{ -bla ** 2 }}').should be_equal_node_to JOINER(TAG(UMINUS(POWER(METHOD(
|
181
|
-
specify { parse('{{ -2 % bla }}').should be_equal_node_to JOINER(TAG(MODULO(-2, METHOD(
|
182
|
-
specify { parse('{{ -hello ** 2 }}').should be_equal_node_to JOINER(TAG(UMINUS(POWER(METHOD(
|
183
|
-
specify { parse('{{ -hello * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(UMINUS(METHOD(
|
184
|
-
specify { parse('{{ haha + 2 == 2 * 2 }}').should be_equal_node_to JOINER(TAG(EQUAL(PLUS(METHOD(
|
185
|
-
specify { parse('{{ 2 * foo != 2 && bar }}').should be_equal_node_to JOINER(TAG(AND(INEQUAL(MULTIPLY(2, METHOD(
|
179
|
+
specify { parse('{{ !foo ** 2 + 3 }}').should be_equal_node_to JOINER(TAG(PLUS(POWER(NOT(METHOD('foo')), 2), 3), mode: :normal)) }
|
180
|
+
specify { parse('{{ -bla ** 2 }}').should be_equal_node_to JOINER(TAG(UMINUS(POWER(METHOD('bla'), 2)), mode: :normal)) }
|
181
|
+
specify { parse('{{ -2 % bla }}').should be_equal_node_to JOINER(TAG(MODULO(-2, METHOD('bla')), mode: :normal)) }
|
182
|
+
specify { parse('{{ -hello ** 2 }}').should be_equal_node_to JOINER(TAG(UMINUS(POWER(METHOD('hello'), 2)), mode: :normal)) }
|
183
|
+
specify { parse('{{ -hello * 2 }}').should be_equal_node_to JOINER(TAG(MULTIPLY(UMINUS(METHOD('hello')), 2), mode: :normal)) }
|
184
|
+
specify { parse('{{ haha + 2 == 2 * 2 }}').should be_equal_node_to JOINER(TAG(EQUAL(PLUS(METHOD('haha'), 2), 4), mode: :normal)) }
|
185
|
+
specify { parse('{{ 2 * foo != 2 && bar }}').should be_equal_node_to JOINER(TAG(AND(INEQUAL(MULTIPLY(2, METHOD('foo')), 2), METHOD('bar')), mode: :normal)) }
|
186
186
|
|
187
187
|
context 'method call' do
|
188
188
|
specify { parse('{{ foo.bar.baz }}').should be_equal_node_to JOINER(TAG(
|
189
|
-
METHOD(
|
189
|
+
METHOD('baz', METHOD('bar', METHOD('foo'))),
|
190
|
+
mode: :normal)) }
|
191
|
+
specify { parse('{{ -bar.baz }}').should be_equal_node_to JOINER(TAG(
|
192
|
+
UMINUS(METHOD('baz', METHOD('bar'))),
|
193
|
+
mode: :normal)) }
|
194
|
+
specify { parse('{{ -42.baz }}').should be_equal_node_to JOINER(TAG(
|
195
|
+
METHOD('baz', -42),
|
196
|
+
mode: :normal)) }
|
197
|
+
specify { parse('{{ - 42.baz }}').should be_equal_node_to JOINER(TAG(
|
198
|
+
UMINUS(METHOD('baz', 42)),
|
199
|
+
mode: :normal)) }
|
200
|
+
specify { parse('{{ -42.42.baz }}').should be_equal_node_to JOINER(TAG(
|
201
|
+
METHOD('baz', -42.42),
|
190
202
|
mode: :normal)) }
|
191
203
|
specify { parse('{{ foo(\'hello\').bar[2].baz(-42) }}').should be_equal_node_to JOINER(TAG(
|
192
|
-
METHOD(
|
193
|
-
METHOD(
|
194
|
-
METHOD(
|
195
|
-
METHOD(
|
196
|
-
|
197
|
-
|
198
|
-
), '[]', 2
|
199
|
-
), 'baz', -42
|
204
|
+
METHOD('baz',
|
205
|
+
METHOD('manipulator_brackets',
|
206
|
+
METHOD('bar',
|
207
|
+
METHOD('foo', nil, 'hello')
|
208
|
+
), 2
|
209
|
+
), -42
|
200
210
|
),
|
201
211
|
mode: :normal)) }
|
202
212
|
end
|
@@ -206,8 +216,8 @@ describe Hotcell::Parser do
|
|
206
216
|
specify { parse('{{ [] }}').should be_equal_node_to JOINER(TAG(ARRAY(), mode: :normal)) }
|
207
217
|
specify { parse('{{ [ 2 ] }}').should be_equal_node_to JOINER(TAG(ARRAY(2), mode: :normal)) }
|
208
218
|
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),
|
210
|
-
specify { parse('{{ [2 + foo, (2 * bar)] }}').should be_equal_node_to JOINER(TAG(ARRAY(PLUS(2, METHOD(
|
219
|
+
specify { parse('{{ [2, 3][42] }}').should be_equal_node_to JOINER(TAG(METHOD('manipulator_brackets', ARRAY(2, 3), 42), mode: :normal)) }
|
220
|
+
specify { parse('{{ [2 + foo, (2 * bar)] }}').should be_equal_node_to JOINER(TAG(ARRAY(PLUS(2, METHOD('foo')), MULTIPLY(2, METHOD('bar'))), mode: :normal)) }
|
211
221
|
specify { parse('{{ [[2, 3], 42] }}').should be_equal_node_to JOINER(TAG(ARRAY(ARRAY(2, 3), 42), mode: :normal)) }
|
212
222
|
end
|
213
223
|
|
@@ -217,48 +227,48 @@ describe Hotcell::Parser do
|
|
217
227
|
JOINER(TAG(HASH(PAIR('hello', 'world')), mode: :normal))
|
218
228
|
) }
|
219
229
|
specify { parse('{{ {hello: \'world\'}[\'hello\'] }}').should be_equal_node_to(
|
220
|
-
JOINER(TAG(METHOD(HASH(PAIR('hello', 'world')), '
|
230
|
+
JOINER(TAG(METHOD('manipulator_brackets', HASH(PAIR('hello', 'world')), 'hello'), mode: :normal))
|
221
231
|
) }
|
222
232
|
specify { parse('{{ { hello: 3, world: 6 * foo } }}').should be_equal_node_to(
|
223
233
|
JOINER(TAG(HASH(
|
224
234
|
PAIR('hello', 3),
|
225
|
-
PAIR('world', MULTIPLY(6, METHOD(
|
235
|
+
PAIR('world', MULTIPLY(6, METHOD('foo')))
|
226
236
|
), mode: :normal))
|
227
237
|
) }
|
228
238
|
end
|
229
239
|
|
230
240
|
context '[]' do
|
231
|
-
specify { parse('{{ hello[3] }}').should be_equal_node_to JOINER(TAG(METHOD(METHOD(
|
232
|
-
specify { parse('{{ \'boom\'[3] }}').should be_equal_node_to JOINER(TAG(METHOD('
|
233
|
-
specify { parse('{{ 7[3] }}').should be_equal_node_to JOINER(TAG(METHOD(
|
234
|
-
specify { parse('{{ 3 + 5[7] }}').should be_equal_node_to JOINER(TAG(PLUS(3, METHOD(
|
235
|
-
specify { parse('{{ (3 + 5)[7] }}').should be_equal_node_to JOINER(TAG(METHOD(
|
241
|
+
specify { parse('{{ hello[3] }}').should be_equal_node_to JOINER(TAG(METHOD('manipulator_brackets', METHOD('hello'), 3), mode: :normal)) }
|
242
|
+
specify { parse('{{ \'boom\'[3] }}').should be_equal_node_to JOINER(TAG(METHOD('manipulator_brackets', 'boom', 3), mode: :normal)) }
|
243
|
+
specify { parse('{{ 7[3] }}').should be_equal_node_to JOINER(TAG(METHOD('manipulator_brackets', 7, 3), mode: :normal)) }
|
244
|
+
specify { parse('{{ 3 + 5[7] }}').should be_equal_node_to JOINER(TAG(PLUS(3, METHOD('manipulator_brackets', 5, 7)), mode: :normal)) }
|
245
|
+
specify { parse('{{ (3 + 5)[7] }}').should be_equal_node_to JOINER(TAG(METHOD('manipulator_brackets', 8, 7), mode: :normal)) }
|
236
246
|
end
|
237
247
|
|
238
248
|
context 'function arguments' do
|
239
|
-
specify { parse('{{ hello() }}').should be_equal_node_to JOINER(TAG(METHOD(
|
249
|
+
specify { parse('{{ hello() }}').should be_equal_node_to JOINER(TAG(METHOD('hello'), mode: :normal)) }
|
240
250
|
specify { parse('{{ hello(2 * foo) }}').should be_equal_node_to(
|
241
|
-
JOINER(TAG(METHOD(
|
251
|
+
JOINER(TAG(METHOD('hello', nil, MULTIPLY(2, METHOD('foo'))), mode: :normal))
|
242
252
|
) }
|
243
253
|
specify { parse('{{ hello([2 * car]) }}').should be_equal_node_to(
|
244
|
-
JOINER(TAG(METHOD(
|
254
|
+
JOINER(TAG(METHOD('hello', nil, ARRAY(MULTIPLY(2, METHOD('car')))), mode: :normal))
|
245
255
|
) }
|
246
256
|
specify { parse('{{ hello({hello: \'world\'}) }}').should be_equal_node_to(
|
247
|
-
JOINER(TAG(METHOD(
|
257
|
+
JOINER(TAG(METHOD('hello', nil, HASH(PAIR('hello', 'world'))), mode: :normal))
|
248
258
|
) }
|
249
259
|
specify { parse('{{ hello(hello: \'world\') }}').should be_equal_node_to(
|
250
|
-
JOINER(TAG(METHOD(
|
260
|
+
JOINER(TAG(METHOD('hello', nil, HASH(PAIR('hello', 'world'))), mode: :normal))
|
251
261
|
) }
|
252
262
|
specify { parse('{{ hello(2 * foo, \'bla\', {hello: \'world\'}) }}').should be_equal_node_to(
|
253
|
-
JOINER(TAG(METHOD(
|
254
|
-
MULTIPLY(2, METHOD(
|
263
|
+
JOINER(TAG(METHOD('hello', nil,
|
264
|
+
MULTIPLY(2, METHOD('foo')),
|
255
265
|
'bla',
|
256
266
|
HASH(PAIR('hello', 'world'))
|
257
267
|
), mode: :normal))
|
258
268
|
) }
|
259
269
|
specify { parse('{{ hello(moo * 3, \'bla\', hello: \'world\') }}').should be_equal_node_to(
|
260
|
-
JOINER(TAG(METHOD(
|
261
|
-
MULTIPLY(METHOD(
|
270
|
+
JOINER(TAG(METHOD('hello', nil,
|
271
|
+
MULTIPLY(METHOD('moo'), 3),
|
262
272
|
'bla',
|
263
273
|
HASH(PAIR('hello', 'world'))
|
264
274
|
), mode: :normal))
|
@@ -280,9 +290,9 @@ describe Hotcell::Parser do
|
|
280
290
|
specify { parse('{{ 42; \'hello\'; 44; }}').should be_equal_node_to JOINER(TAG(42, 'hello', 44, mode: :normal)) }
|
281
291
|
specify { parse('{{ (42; \'hello\'); 44; }}').should be_equal_node_to JOINER(TAG(SEQUENCE(42, 'hello'), 44, mode: :normal)) }
|
282
292
|
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(
|
284
|
-
specify { parse('{{ hello(42, ((43; 44)), 45) }}').should be_equal_node_to JOINER(TAG(METHOD(
|
285
|
-
specify { parse('{{ hello((42)) }}').should be_equal_node_to JOINER(TAG(METHOD(
|
293
|
+
specify { parse('{{ hello(42, (43; 44), 45) }}').should be_equal_node_to JOINER(TAG(METHOD('hello', nil, 42, SEQUENCE(43, 44), 45), mode: :normal)) }
|
294
|
+
specify { parse('{{ hello(42, ((43; 44)), 45) }}').should be_equal_node_to JOINER(TAG(METHOD('hello', nil, 42, SEQUENCE(43, 44), 45), mode: :normal)) }
|
295
|
+
specify { parse('{{ hello((42)) }}').should be_equal_node_to JOINER(TAG(METHOD('hello', nil, 42), mode: :normal)) }
|
286
296
|
end
|
287
297
|
|
288
298
|
context 'comments' do
|
@@ -292,91 +302,110 @@ describe Hotcell::Parser do
|
|
292
302
|
specify { parse('hello {{!# world #}}').should be_equal_node_to JOINER('hello ', TAG(mode: :silence)) }
|
293
303
|
specify { parse('hello {{ # world}}').should be_equal_node_to JOINER('hello ', TAG(mode: :normal)) }
|
294
304
|
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(
|
305
|
+
specify { parse("hello {{ # world\n foo}}").should be_equal_node_to JOINER('hello ', TAG(METHOD('foo'), mode: :normal)) }
|
306
|
+
specify { parse("hello {{ world# foo}}").should be_equal_node_to JOINER('hello ', TAG(METHOD('world'), mode: :normal)) }
|
296
307
|
end
|
297
308
|
|
298
309
|
context 'commands' do
|
310
|
+
let(:include_tag) { Class.new(Hotcell::Command) }
|
311
|
+
let(:snippet_tag) { Class.new(Hotcell::Command) }
|
312
|
+
let(:commands) do
|
313
|
+
{
|
314
|
+
include: include_tag,
|
315
|
+
snippet: snippet_tag
|
316
|
+
}.stringify_keys
|
317
|
+
end
|
318
|
+
|
299
319
|
specify { parse("{{ include 'some/partial' }}",
|
300
|
-
commands:
|
301
|
-
|
320
|
+
commands: commands).should be_equal_node_to JOINER(
|
321
|
+
TAG(include_tag.build('include', 'some/partial'), mode: :normal)
|
302
322
|
) }
|
303
323
|
specify { parse("{{ include }}",
|
304
|
-
commands:
|
305
|
-
|
324
|
+
commands: commands).should be_equal_node_to JOINER(
|
325
|
+
TAG(include_tag.build('include'), mode: :normal)
|
306
326
|
) }
|
307
327
|
specify { parse("{{! include 'some/partial' }}\n{{ snippet 'sidebar' }}",
|
308
|
-
commands:
|
309
|
-
|
328
|
+
commands: commands).should be_equal_node_to JOINER(
|
329
|
+
TAG(include_tag.build('include', 'some/partial'), mode: :silence),
|
310
330
|
"\n",
|
311
|
-
|
331
|
+
TAG(snippet_tag.build('snippet', 'sidebar'), mode: :normal),
|
312
332
|
) }
|
313
333
|
specify { parse("{{! variable = include }}",
|
314
|
-
commands:
|
315
|
-
|
334
|
+
commands: commands).should be_equal_node_to JOINER(
|
335
|
+
TAG(ASSIGN('variable', include_tag.build('include')), mode: :silence)
|
316
336
|
) }
|
317
337
|
specify { parse("{{ variable = include 'some/partial' }}",
|
318
|
-
commands:
|
319
|
-
|
338
|
+
commands: commands).should be_equal_node_to JOINER(
|
339
|
+
TAG(ASSIGN('variable', include_tag.build('include', 'some/partial')), mode: :normal)
|
320
340
|
) }
|
321
341
|
end
|
322
342
|
|
323
343
|
context 'blocks' do
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
344
|
+
let(:scoped_tag) { Class.new(Hotcell::Block) }
|
345
|
+
let(:each_tag) { Class.new(Hotcell::Block) }
|
346
|
+
let(:blocks) do
|
347
|
+
{
|
348
|
+
scoped: scoped_tag,
|
349
|
+
each: each_tag
|
350
|
+
}.stringify_keys
|
351
|
+
end
|
352
|
+
|
328
353
|
specify { parse("{{ scoped }}{{ end scoped }}",
|
329
|
-
blocks:
|
330
|
-
|
354
|
+
blocks: blocks).should be_equal_node_to JOINER(
|
355
|
+
TAG(scoped_tag.build('scoped'), mode: :normal)
|
356
|
+
) }
|
357
|
+
specify { parse("{{ scoped var: 'hello' }}{{ endscoped }}",
|
358
|
+
blocks: blocks).should be_equal_node_to JOINER(
|
359
|
+
TAG(scoped_tag.build('scoped', HASH(PAIR('var', 'hello'))), mode: :normal)
|
331
360
|
) }
|
332
|
-
specify { parse("<article>\n{{
|
333
|
-
blocks:
|
361
|
+
specify { parse("<article>\n{{ each post, in: posts }}\n<h1>{{ post.title }}</h1>\n{{ end each }}\n</article>",
|
362
|
+
blocks: blocks).should be_equal_node_to JOINER(
|
334
363
|
"<article>\n",
|
335
|
-
|
336
|
-
METHOD(
|
337
|
-
HASH(PAIR('in', METHOD(
|
338
|
-
mode: :normal,
|
364
|
+
TAG(each_tag.build('each',
|
365
|
+
METHOD('post'),
|
366
|
+
HASH(PAIR('in', METHOD('posts'))),
|
339
367
|
subnodes: [JOINER(
|
340
368
|
"\n<h1>",
|
341
|
-
TAG(METHOD(
|
369
|
+
TAG(METHOD('title', METHOD('post')), mode: :normal),
|
342
370
|
"</h1>\n"
|
343
371
|
)]
|
344
|
-
),
|
372
|
+
), mode: :normal),
|
345
373
|
"\n</article>"
|
346
374
|
) }
|
347
|
-
specify { parse("{{!
|
348
|
-
blocks:
|
349
|
-
|
350
|
-
METHOD(
|
351
|
-
HASH(PAIR('in', METHOD(
|
352
|
-
mode: :silence,
|
353
|
-
assign: 'posts',
|
375
|
+
specify { parse("{{! iter = each post, in: posts }}\n<h1>{{ post.title }}</h1>\n{{ end each }}",
|
376
|
+
blocks: blocks).should be_equal_node_to JOINER(
|
377
|
+
TAG(ASSIGN('iter', each_tag.build('each',
|
378
|
+
METHOD('post'),
|
379
|
+
HASH(PAIR('in', METHOD('posts'))),
|
354
380
|
subnodes: [JOINER(
|
355
381
|
"\n<h1>",
|
356
|
-
TAG(METHOD(
|
382
|
+
TAG(METHOD('title', METHOD('post')), mode: :normal),
|
357
383
|
"</h1>\n"
|
358
384
|
)]
|
359
|
-
),
|
385
|
+
)), mode: :silence),
|
360
386
|
) }
|
361
|
-
specify { parse("{{ capture = scoped }} hello {{
|
362
|
-
blocks:
|
363
|
-
|
364
|
-
mode: :normal,
|
365
|
-
assign: 'capture',
|
387
|
+
specify { parse("{{ capture = scoped }} hello {{ each post, in: posts }} {{ loop }} {{ end each }}{{ endscoped }}",
|
388
|
+
blocks: blocks).should be_equal_node_to JOINER(
|
389
|
+
TAG(ASSIGN('capture', scoped_tag.build('scoped',
|
366
390
|
subnodes: [JOINER(
|
367
391
|
' hello ',
|
368
|
-
|
369
|
-
METHOD(
|
370
|
-
HASH(PAIR('in', METHOD(
|
371
|
-
mode: :normal,
|
392
|
+
TAG(each_tag.build('each',
|
393
|
+
METHOD('post'),
|
394
|
+
HASH(PAIR('in', METHOD('posts'))),
|
372
395
|
subnodes: [JOINER(
|
373
396
|
' ',
|
374
|
-
TAG(METHOD(
|
397
|
+
TAG(METHOD('loop'), mode: :normal),
|
375
398
|
' '
|
376
399
|
)]
|
377
|
-
)
|
400
|
+
), mode: :normal)
|
378
401
|
)]
|
379
|
-
)
|
402
|
+
)), mode: :normal)
|
380
403
|
) }
|
381
404
|
end
|
405
|
+
|
406
|
+
context 'errors' do
|
407
|
+
let(:error) { Hotcell::UnexpectedLexem }
|
408
|
+
|
409
|
+
specify { expect { parse("{{ var = 3 * 5; hello(, 3) }}") }.to raise_error error, 'Unexpected COMMA `,` at 1:23' }
|
410
|
+
end
|
382
411
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hotcell::Resolver do
|
4
|
+
specify { expect { subject.template 'any/path' }.to raise_error NotImplementedError }
|
5
|
+
|
6
|
+
describe '#template' do
|
7
|
+
let(:dummy) do
|
8
|
+
Class.new(described_class) do
|
9
|
+
def resolve path, context = nil
|
10
|
+
path
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
subject { dummy.new.template('template/source') }
|
15
|
+
|
16
|
+
it { should be_a Hotcell::Template }
|
17
|
+
its('source.source') { should == 'template/source' }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Hotcell::FileSystemResolver do
|
22
|
+
subject(:resolver) { described_class.new(data_path('templates')) }
|
23
|
+
|
24
|
+
describe '#resolve' do
|
25
|
+
specify { subject.resolve('simple').should == 'Hello, {{ name }}' }
|
26
|
+
specify { expect { subject.resolve('unexisting') }.to raise_error Errno::ENOENT }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Hotcell::Source do
|
6
|
+
subject(:source) { described_class.new('hello', 'file/path') }
|
7
|
+
|
8
|
+
describe '.wrap' do
|
9
|
+
specify { described_class.wrap('hello').should be_a described_class }
|
10
|
+
specify { described_class.wrap('hello').source.should == 'hello' }
|
11
|
+
specify { described_class.wrap(source).should === source }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#initialize' do
|
15
|
+
its(:source) { should == 'hello' }
|
16
|
+
its(:file) { should == 'file/path' }
|
17
|
+
specify { described_class.new('hello').source.should == 'hello' }
|
18
|
+
specify { described_class.new('hello').file.should be_nil }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#data' do
|
22
|
+
its(:data) { should == [104, 101, 108, 108, 111] }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#info' do
|
26
|
+
def info source, position
|
27
|
+
described_class.new(source, 'file/path').info(position)
|
28
|
+
end
|
29
|
+
|
30
|
+
specify { info('hello', 0).should == { line: 1, column: 1 } }
|
31
|
+
specify { info('hello', 100).should == { line: 1, column: 5 } }
|
32
|
+
specify { info('hello', 2).should == { line: 1, column: 3 } }
|
33
|
+
specify { info('привет', 0).should == { line: 1, column: 1 } }
|
34
|
+
specify { info('привет', 4).should == { line: 1, column: 3 } }
|
35
|
+
specify { info('привет', 100).should == { line: 1, column: 6 } }
|
36
|
+
specify { info("привет\nhello", 0).should == { line: 1, column: 1 } }
|
37
|
+
specify { info("привет\nhello", 100).should == { line: 2, column: 5 } }
|
38
|
+
specify { info("привет\nhello", 15).should == { line: 2, column: 3 } }
|
39
|
+
specify { info("привет\nhello", 7).should == { line: 1, column: 4 } }
|
40
|
+
end
|
41
|
+
end
|
@@ -5,13 +5,10 @@ describe Hotcell::Template do
|
|
5
5
|
before do
|
6
6
|
Hotcell.stub(:commands) { { 'include' => Class.new } }
|
7
7
|
Hotcell.stub(:blocks) { { 'for' => Class.new } }
|
8
|
-
Hotcell.stub(:subcommands) { { 'else' => Class.new } }
|
9
8
|
end
|
10
9
|
|
11
10
|
specify { described_class.parse('').should be_a described_class }
|
12
|
-
specify { described_class.parse('').options.should ==
|
13
|
-
commands: ['include'], blocks: ['for'], subcommands: ['else']
|
14
|
-
} }
|
11
|
+
specify { described_class.parse('').options.values.map(&:keys).should == [['include'], ['for']] }
|
15
12
|
end
|
16
13
|
|
17
14
|
describe '#syntax' do
|
@@ -37,5 +34,51 @@ describe Hotcell::Template do
|
|
37
34
|
subject { described_class.new('Hello, {{! name }}!') }
|
38
35
|
specify { subject.render(variables: { name: 'Friend' }).should == 'Hello, !' }
|
39
36
|
end
|
37
|
+
|
38
|
+
context do
|
39
|
+
let(:helper) do
|
40
|
+
Module.new do
|
41
|
+
def name string
|
42
|
+
string.capitalize
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
subject { described_class.new("Hello, {{ name('pyra') }}!") }
|
47
|
+
specify { subject.render(helpers: helper).should == 'Hello, Pyra!' }
|
48
|
+
|
49
|
+
context do
|
50
|
+
before { Hotcell.stub(:helpers) { [helper] } }
|
51
|
+
specify { subject.render.should == 'Hello, Pyra!' }
|
52
|
+
specify { subject.render(helpers: []).should == 'Hello, !' }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'render!' do
|
58
|
+
subject { described_class.new('Hello, {{ 2 * foo }}!') }
|
59
|
+
specify { expect { subject.render! }.to raise_error TypeError }
|
60
|
+
specify { expect { subject.render!(foo: 42) }.not_to raise_error }
|
61
|
+
specify { expect { subject.render!(bar: 42) }.to raise_error TypeError }
|
62
|
+
specify { expect { subject.render!(Hotcell::Context.new) }.to raise_error TypeError }
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'complex tags test' do
|
66
|
+
specify { described_class.parse(<<-SOURCE
|
67
|
+
{{ for i, in: [1, 2, 3, 4] }}
|
68
|
+
{{ if i % 2 == 1 }}
|
69
|
+
{{ i }}
|
70
|
+
{{ end if }}
|
71
|
+
{{ end for }}
|
72
|
+
SOURCE
|
73
|
+
).render.gsub(/[\s\n]+/, ' ').strip.should == '1 3' }
|
74
|
+
|
75
|
+
specify { described_class.parse(<<-SOURCE
|
76
|
+
{{ for i, in: [1, 2, 3, 4] }}
|
77
|
+
{{ for j, in: [4, 3, 2, 1] }}
|
78
|
+
{{ i * j }}
|
79
|
+
{{ end for }}
|
80
|
+
{{ end for }}
|
81
|
+
SOURCE
|
82
|
+
).render.gsub(/[\s\n]+/, ' ').strip.should == '4 3 2 1 8 6 4 2 12 9 6 3 16 12 8 4' }
|
40
83
|
end
|
41
84
|
end
|
data/spec/lib/hotcell_spec.rb
CHANGED
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe Hotcell do
|
4
4
|
it { should respond_to :commands }
|
5
5
|
it { should respond_to :blocks }
|
6
|
-
it { should respond_to :
|
6
|
+
it { should respond_to :helpers }
|
7
7
|
it { should respond_to :register_command }
|
8
|
+
it { should respond_to :register_helpers }
|
8
9
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,7 +9,7 @@ AwesomePrint::Formatter.class_eval do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def awesome_hotcell_node(object)
|
12
|
-
"#{colorize(object.class.
|
12
|
+
"#{colorize(object.class.to_s, :class)} #{colorize(object.name.to_s, :method)}" +
|
13
13
|
((awesome_hash(object.options) + "\n") if object.options.present?).to_s +
|
14
14
|
awesome_array(object.children)
|
15
15
|
end
|
@@ -28,8 +28,12 @@ RSpec::Matchers.define :be_equal_node_to do |expected|
|
|
28
28
|
end
|
29
29
|
|
30
30
|
RSpec.configure do |config|
|
31
|
+
def data_path name
|
32
|
+
File.join(File.dirname(__FILE__), 'data', name)
|
33
|
+
end
|
34
|
+
|
31
35
|
def data name
|
32
|
-
File.read
|
36
|
+
File.read data_path(name)
|
33
37
|
end
|
34
38
|
|
35
39
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|