hotcell 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|