handlebars 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/handlebars/context.rb +3 -5
- data/lib/handlebars/version.rb +1 -1
- data/spec/handlebars_spec.rb +3 -3
- data/vendor/handlebars/.gitignore +3 -1
- data/vendor/handlebars/.jshintrc +2 -0
- data/vendor/handlebars/.npmignore +0 -1
- data/vendor/handlebars/.rspec +1 -0
- data/vendor/handlebars/Gemfile +1 -1
- data/vendor/handlebars/LICENSE +0 -1
- data/vendor/handlebars/README.markdown +8 -6
- data/vendor/handlebars/Rakefile +14 -21
- data/vendor/handlebars/bench/benchwarmer.js +1 -1
- data/vendor/handlebars/bench/handlebars.js +43 -34
- data/vendor/handlebars/bin/handlebars +56 -2
- data/vendor/handlebars/dist/handlebars.js +2201 -0
- data/vendor/handlebars/dist/handlebars.runtime.js +321 -0
- data/vendor/handlebars/lib/handlebars/base.js +68 -15
- data/vendor/handlebars/lib/handlebars/compiler/ast.js +50 -20
- data/vendor/handlebars/lib/handlebars/compiler/base.js +7 -13
- data/vendor/handlebars/lib/handlebars/compiler/compiler.js +758 -299
- data/vendor/handlebars/lib/handlebars/compiler/printer.js +24 -30
- data/vendor/handlebars/lib/handlebars/runtime.js +23 -3
- data/vendor/handlebars/lib/handlebars/utils.js +9 -10
- data/vendor/handlebars/package.json +15 -5
- data/vendor/handlebars/spec/acceptance_spec.rb +5 -5
- data/vendor/handlebars/spec/parser_spec.rb +201 -32
- data/vendor/handlebars/spec/qunit_spec.js +462 -159
- data/vendor/handlebars/spec/spec_helper.rb +7 -7
- data/vendor/handlebars/spec/tokenizer_spec.rb +55 -8
- data/vendor/handlebars/src/handlebars.l +14 -3
- data/vendor/handlebars/src/handlebars.yy +15 -5
- data/vendor/handlebars/src/parser-prefix.js +1 -0
- data/vendor/handlebars/src/parser-suffix.js +4 -0
- metadata +8 -3
@@ -18,31 +18,17 @@ Handlebars.PrintVisitor.prototype.pad = function(string, newline) {
|
|
18
18
|
};
|
19
19
|
|
20
20
|
Handlebars.PrintVisitor.prototype.program = function(program) {
|
21
|
-
var out =
|
21
|
+
var out = "",
|
22
22
|
statements = program.statements,
|
23
23
|
inverse = program.inverse,
|
24
24
|
i, l;
|
25
25
|
|
26
|
-
this.padding++;
|
27
|
-
|
28
26
|
for(i=0, l=statements.length; i<l; i++) {
|
29
27
|
out = out + this.accept(statements[i]);
|
30
28
|
}
|
31
29
|
|
32
30
|
this.padding--;
|
33
31
|
|
34
|
-
if(inverse) {
|
35
|
-
out = out + this.pad("{{^}}");
|
36
|
-
|
37
|
-
this.padding++;
|
38
|
-
|
39
|
-
for(i=0, l=inverse.statements.length; i<l; i++) {
|
40
|
-
out = out + this.accept(inverse.statements[i]);
|
41
|
-
}
|
42
|
-
}
|
43
|
-
|
44
|
-
this.padding--;
|
45
|
-
|
46
32
|
return out;
|
47
33
|
};
|
48
34
|
|
@@ -52,25 +38,25 @@ Handlebars.PrintVisitor.prototype.block = function(block) {
|
|
52
38
|
out = out + this.pad("BLOCK:");
|
53
39
|
this.padding++;
|
54
40
|
out = out + this.accept(block.mustache);
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
41
|
+
if (block.program) {
|
42
|
+
out = out + this.pad("PROGRAM:");
|
43
|
+
this.padding++;
|
44
|
+
out = out + this.accept(block.program);
|
45
|
+
this.padding--;
|
46
|
+
}
|
47
|
+
if (block.inverse) {
|
48
|
+
if (block.program) { this.padding++; }
|
49
|
+
out = out + this.pad("{{^}}");
|
50
|
+
this.padding++;
|
51
|
+
out = out + this.accept(block.inverse);
|
52
|
+
this.padding--;
|
53
|
+
if (block.program) { this.padding--; }
|
54
|
+
}
|
68
55
|
this.padding--;
|
69
56
|
|
70
57
|
return out;
|
71
58
|
};
|
72
59
|
|
73
|
-
|
74
60
|
Handlebars.PrintVisitor.prototype.mustache = function(mustache) {
|
75
61
|
var params = mustache.params, paramStrings = [], hash;
|
76
62
|
|
@@ -86,7 +72,7 @@ Handlebars.PrintVisitor.prototype.mustache = function(mustache) {
|
|
86
72
|
};
|
87
73
|
|
88
74
|
Handlebars.PrintVisitor.prototype.partial = function(partial) {
|
89
|
-
var content = this.accept(partial.
|
75
|
+
var content = this.accept(partial.partialName);
|
90
76
|
if(partial.context) { content = content + " " + this.accept(partial.context); }
|
91
77
|
return this.pad("{{> " + content + " }}");
|
92
78
|
};
|
@@ -125,6 +111,14 @@ Handlebars.PrintVisitor.prototype.ID = function(id) {
|
|
125
111
|
}
|
126
112
|
};
|
127
113
|
|
114
|
+
Handlebars.PrintVisitor.prototype.PARTIAL_NAME = function(partialName) {
|
115
|
+
return "PARTIAL:" + partialName.name;
|
116
|
+
};
|
117
|
+
|
118
|
+
Handlebars.PrintVisitor.prototype.DATA = function(data) {
|
119
|
+
return "@" + data.id;
|
120
|
+
};
|
121
|
+
|
128
122
|
Handlebars.PrintVisitor.prototype.content = function(content) {
|
129
123
|
return this.pad("CONTENT[ '" + content.string + "' ]");
|
130
124
|
};
|
@@ -20,12 +20,32 @@ Handlebars.VM = {
|
|
20
20
|
}
|
21
21
|
},
|
22
22
|
programWithDepth: Handlebars.VM.programWithDepth,
|
23
|
-
noop: Handlebars.VM.noop
|
23
|
+
noop: Handlebars.VM.noop,
|
24
|
+
compilerInfo: null
|
24
25
|
};
|
25
26
|
|
26
27
|
return function(context, options) {
|
27
28
|
options = options || {};
|
28
|
-
|
29
|
+
var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
|
30
|
+
|
31
|
+
var compilerInfo = container.compilerInfo || [],
|
32
|
+
compilerRevision = compilerInfo[0] || 1,
|
33
|
+
currentRevision = Handlebars.COMPILER_REVISION;
|
34
|
+
|
35
|
+
if (compilerRevision !== currentRevision) {
|
36
|
+
if (compilerRevision < currentRevision) {
|
37
|
+
var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
|
38
|
+
compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
|
39
|
+
throw "Template was precompiled with an older version of Handlebars than the current runtime. "+
|
40
|
+
"Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").";
|
41
|
+
} else {
|
42
|
+
// Use the embedded version info since the runtime doesn't know about this revision yet
|
43
|
+
throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+
|
44
|
+
"Please update your runtime to a newer version ("+compilerInfo[1]+").";
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
return result;
|
29
49
|
};
|
30
50
|
},
|
31
51
|
|
@@ -56,7 +76,7 @@ Handlebars.VM = {
|
|
56
76
|
} else if (!Handlebars.compile) {
|
57
77
|
throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
|
58
78
|
} else {
|
59
|
-
partials[name] = Handlebars.compile(partial);
|
79
|
+
partials[name] = Handlebars.compile(partial, {data: data !== undefined});
|
60
80
|
return partials[name](context, options);
|
61
81
|
}
|
62
82
|
}
|
@@ -1,14 +1,16 @@
|
|
1
1
|
var Handlebars = require("./base");
|
2
2
|
|
3
3
|
// BEGIN(BROWSER)
|
4
|
+
|
5
|
+
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
|
6
|
+
|
4
7
|
Handlebars.Exception = function(message) {
|
5
8
|
var tmp = Error.prototype.constructor.apply(this, arguments);
|
6
9
|
|
7
|
-
|
8
|
-
|
10
|
+
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
|
11
|
+
for (var idx = 0; idx < errorProps.length; idx++) {
|
12
|
+
this[errorProps[idx]] = tmp[errorProps[idx]];
|
9
13
|
}
|
10
|
-
|
11
|
-
this.message = tmp.message;
|
12
14
|
};
|
13
15
|
Handlebars.Exception.prototype = new Error();
|
14
16
|
|
@@ -22,6 +24,7 @@ Handlebars.SafeString.prototype.toString = function() {
|
|
22
24
|
|
23
25
|
(function() {
|
24
26
|
var escape = {
|
27
|
+
"&": "&",
|
25
28
|
"<": "<",
|
26
29
|
">": ">",
|
27
30
|
'"': """,
|
@@ -29,7 +32,7 @@ Handlebars.SafeString.prototype.toString = function() {
|
|
29
32
|
"`": "`"
|
30
33
|
};
|
31
34
|
|
32
|
-
var badChars =
|
35
|
+
var badChars = /[&<>"'`]/g;
|
33
36
|
var possible = /[&<>"'`]/;
|
34
37
|
|
35
38
|
var escapeChar = function(chr) {
|
@@ -50,11 +53,7 @@ Handlebars.SafeString.prototype.toString = function() {
|
|
50
53
|
},
|
51
54
|
|
52
55
|
isEmpty: function(value) {
|
53
|
-
if (
|
54
|
-
return true;
|
55
|
-
} else if (value === null) {
|
56
|
-
return true;
|
57
|
-
} else if (value === false) {
|
56
|
+
if (!value && value !== 0) {
|
58
57
|
return true;
|
59
58
|
} else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
|
60
59
|
return true;
|
@@ -1,14 +1,14 @@
|
|
1
1
|
{
|
2
2
|
"name": "handlebars",
|
3
3
|
"description": "Extension of the Mustache logicless template language",
|
4
|
-
"version": "1.0.
|
4
|
+
"version": "1.0.8",
|
5
5
|
"homepage": "http://www.handlebarsjs.com/",
|
6
6
|
"keywords": [
|
7
7
|
"handlebars mustache template html"
|
8
8
|
],
|
9
9
|
"repository": {
|
10
10
|
"type": "git",
|
11
|
-
"url": "git://github.com/
|
11
|
+
"url": "git://github.com/wycats/handlebars.js.git"
|
12
12
|
},
|
13
13
|
"engines": {
|
14
14
|
"node": ">=0.4.7"
|
@@ -17,9 +17,19 @@
|
|
17
17
|
"optimist": "~0.3",
|
18
18
|
"uglify-js": "~1.2"
|
19
19
|
},
|
20
|
-
"devDependencies": {
|
20
|
+
"devDependencies": {
|
21
|
+
"benchmark": "~1.0",
|
22
|
+
"dust": "~0.3",
|
23
|
+
"jison": "~0.3",
|
24
|
+
"mocha": "*",
|
25
|
+
"mustache": "~0.7.2"
|
26
|
+
},
|
21
27
|
"main": "lib/handlebars.js",
|
22
28
|
"bin": {
|
23
29
|
"handlebars": "bin/handlebars"
|
24
|
-
}
|
25
|
-
|
30
|
+
},
|
31
|
+
"scripts": {
|
32
|
+
"test": "node_modules/.bin/mocha -u qunit spec/qunit_spec.js"
|
33
|
+
},
|
34
|
+
"optionalDependencies": {}
|
35
|
+
}
|
@@ -39,11 +39,11 @@ Module.new do
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
js_context["p"] = proc do |str|
|
42
|
+
js_context["p"] = proc do |this, str|
|
43
43
|
p str
|
44
44
|
end
|
45
45
|
|
46
|
-
js_context["ok"] = proc do |ok, message|
|
46
|
+
js_context["ok"] = proc do |this, ok, message|
|
47
47
|
js_context["$$RSPEC1$$"] = ok
|
48
48
|
|
49
49
|
result = js_context.eval("!!$$RSPEC1$$")
|
@@ -58,7 +58,7 @@ Module.new do
|
|
58
58
|
assert result, message
|
59
59
|
end
|
60
60
|
|
61
|
-
js_context["equals"] = proc do |first, second, message|
|
61
|
+
js_context["equals"] = proc do |this, first, second, message|
|
62
62
|
js_context["$$RSPEC1$$"] = first
|
63
63
|
js_context["$$RSPEC2$$"] = second
|
64
64
|
|
@@ -77,11 +77,11 @@ Module.new do
|
|
77
77
|
|
78
78
|
js_context["equal"] = js_context["equals"]
|
79
79
|
|
80
|
-
js_context["
|
80
|
+
js_context["suite"] = proc do |this, name|
|
81
81
|
test_context.module(name)
|
82
82
|
end
|
83
83
|
|
84
|
-
js_context["test"] = proc do |name, function|
|
84
|
+
js_context["test"] = proc do |this, name, function|
|
85
85
|
test_context.test(name, function)
|
86
86
|
end
|
87
87
|
|
@@ -7,11 +7,9 @@ describe "Parser" do
|
|
7
7
|
@compiles = true
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def root(&block)
|
11
11
|
ASTBuilder.build do
|
12
|
-
|
13
|
-
instance_eval(&block)
|
14
|
-
end
|
12
|
+
instance_eval(&block)
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
@@ -112,115 +110,143 @@ describe "Parser" do
|
|
112
110
|
"ID:#{id}"
|
113
111
|
end
|
114
112
|
|
113
|
+
def data(id)
|
114
|
+
"@#{id}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def partial_name(name)
|
118
|
+
"PARTIAL:#{name}"
|
119
|
+
end
|
120
|
+
|
115
121
|
def path(*parts)
|
116
122
|
"PATH:#{parts.join("/")}"
|
117
123
|
end
|
118
124
|
end
|
119
125
|
|
120
126
|
it "parses simple mustaches" do
|
121
|
-
ast_for("{{foo}}").should ==
|
127
|
+
ast_for("{{foo}}").should == root { mustache id("foo") }
|
128
|
+
end
|
129
|
+
|
130
|
+
it "parses simple mustaches with data" do
|
131
|
+
ast_for("{{@foo}}").should == root { mustache data("foo") }
|
122
132
|
end
|
123
133
|
|
124
134
|
it "parses mustaches with paths" do
|
125
|
-
ast_for("{{foo/bar}}").should ==
|
135
|
+
ast_for("{{foo/bar}}").should == root { mustache path("foo", "bar") }
|
126
136
|
end
|
127
137
|
|
128
138
|
it "parses mustaches with this/foo" do
|
129
|
-
ast_for("{{this/foo}}").should ==
|
139
|
+
ast_for("{{this/foo}}").should == root { mustache id("foo") }
|
130
140
|
end
|
131
141
|
|
132
142
|
it "parses mustaches with - in a path" do
|
133
|
-
ast_for("{{foo-bar}}").should ==
|
143
|
+
ast_for("{{foo-bar}}").should == root { mustache id("foo-bar") }
|
134
144
|
end
|
135
145
|
|
136
146
|
it "parses mustaches with parameters" do
|
137
|
-
ast_for("{{foo bar}}").should ==
|
147
|
+
ast_for("{{foo bar}}").should == root { mustache id("foo"), [id("bar")] }
|
138
148
|
end
|
139
149
|
|
140
150
|
it "parses mustaches with hash arguments" do
|
141
|
-
ast_for("{{foo bar=baz}}").should ==
|
151
|
+
ast_for("{{foo bar=baz}}").should == root do
|
142
152
|
mustache id("foo"), [], hash(["bar", id("baz")])
|
143
153
|
end
|
144
154
|
|
145
|
-
ast_for("{{foo bar=1}}").should ==
|
155
|
+
ast_for("{{foo bar=1}}").should == root do
|
146
156
|
mustache id("foo"), [], hash(["bar", integer("1")])
|
147
157
|
end
|
148
158
|
|
149
|
-
ast_for("{{foo bar=true}}").should ==
|
159
|
+
ast_for("{{foo bar=true}}").should == root do
|
150
160
|
mustache id("foo"), [], hash(["bar", boolean("true")])
|
151
161
|
end
|
152
162
|
|
153
|
-
ast_for("{{foo bar=false}}").should ==
|
163
|
+
ast_for("{{foo bar=false}}").should == root do
|
154
164
|
mustache id("foo"), [], hash(["bar", boolean("false")])
|
155
165
|
end
|
156
166
|
|
157
|
-
ast_for("{{foo bar
|
167
|
+
ast_for("{{foo bar=@baz}}").should == root do
|
168
|
+
mustache id("foo"), [], hash(["bar", data("baz")])
|
169
|
+
end
|
170
|
+
|
171
|
+
ast_for("{{foo bar=baz bat=bam}}").should == root do
|
158
172
|
mustache id("foo"), [], hash(["bar", "ID:baz"], ["bat", "ID:bam"])
|
159
173
|
end
|
160
174
|
|
161
|
-
ast_for("{{foo bar=baz bat=\"bam\"}}").should ==
|
175
|
+
ast_for("{{foo bar=baz bat=\"bam\"}}").should == root do
|
162
176
|
mustache id("foo"), [], hash(["bar", "ID:baz"], ["bat", "\"bam\""])
|
163
177
|
end
|
164
178
|
|
165
|
-
ast_for("{{foo
|
179
|
+
ast_for("{{foo bat='bam'}}").should == root do
|
180
|
+
mustache id("foo"), [], hash(["bat", "\"bam\""])
|
181
|
+
end
|
182
|
+
|
183
|
+
ast_for("{{foo omg bar=baz bat=\"bam\"}}").should == root do
|
166
184
|
mustache id("foo"), [id("omg")], hash(["bar", id("baz")], ["bat", string("bam")])
|
167
185
|
end
|
168
186
|
|
169
|
-
ast_for("{{foo omg bar=baz bat=\"bam\" baz=1}}").should ==
|
187
|
+
ast_for("{{foo omg bar=baz bat=\"bam\" baz=1}}").should == root do
|
170
188
|
mustache id("foo"), [id("omg")], hash(["bar", id("baz")], ["bat", string("bam")], ["baz", integer("1")])
|
171
189
|
end
|
172
190
|
|
173
|
-
ast_for("{{foo omg bar=baz bat=\"bam\" baz=true}}").should ==
|
191
|
+
ast_for("{{foo omg bar=baz bat=\"bam\" baz=true}}").should == root do
|
174
192
|
mustache id("foo"), [id("omg")], hash(["bar", id("baz")], ["bat", string("bam")], ["baz", boolean("true")])
|
175
193
|
end
|
176
194
|
|
177
|
-
ast_for("{{foo omg bar=baz bat=\"bam\" baz=false}}").should ==
|
195
|
+
ast_for("{{foo omg bar=baz bat=\"bam\" baz=false}}").should == root do
|
178
196
|
mustache id("foo"), [id("omg")], hash(["bar", id("baz")], ["bat", string("bam")], ["baz", boolean("false")])
|
179
197
|
end
|
180
198
|
end
|
181
199
|
|
182
200
|
it "parses mustaches with string parameters" do
|
183
|
-
ast_for("{{foo bar \"baz\" }}").should ==
|
201
|
+
ast_for("{{foo bar \"baz\" }}").should == root { mustache id("foo"), [id("bar"), string("baz")] }
|
184
202
|
end
|
185
203
|
|
186
204
|
it "parses mustaches with INTEGER parameters" do
|
187
|
-
ast_for("{{foo 1}}").should ==
|
205
|
+
ast_for("{{foo 1}}").should == root { mustache id("foo"), [integer("1")] }
|
188
206
|
end
|
189
207
|
|
190
208
|
it "parses mustaches with BOOLEAN parameters" do
|
191
|
-
ast_for("{{foo true}}").should ==
|
192
|
-
ast_for("{{foo false}}").should ==
|
209
|
+
ast_for("{{foo true}}").should == root { mustache id("foo"), [boolean("true")] }
|
210
|
+
ast_for("{{foo false}}").should == root { mustache id("foo"), [boolean("false")] }
|
211
|
+
end
|
212
|
+
|
213
|
+
it "parses mutaches with DATA parameters" do
|
214
|
+
ast_for("{{foo @bar}}").should == root { mustache id("foo"), [data("bar")] }
|
193
215
|
end
|
194
216
|
|
195
217
|
it "parses contents followed by a mustache" do
|
196
|
-
ast_for("foo bar {{baz}}").should ==
|
218
|
+
ast_for("foo bar {{baz}}").should == root do
|
197
219
|
content "foo bar "
|
198
220
|
mustache id("baz")
|
199
221
|
end
|
200
222
|
end
|
201
223
|
|
202
224
|
it "parses a partial" do
|
203
|
-
ast_for("{{> foo }}").should ==
|
225
|
+
ast_for("{{> foo }}").should == root { partial partial_name("foo") }
|
204
226
|
end
|
205
227
|
|
206
228
|
it "parses a partial with context" do
|
207
|
-
ast_for("{{> foo bar}}").should ==
|
229
|
+
ast_for("{{> foo bar}}").should == root { partial partial_name("foo"), id("bar") }
|
230
|
+
end
|
231
|
+
|
232
|
+
it "parses a partial with a complex name" do
|
233
|
+
ast_for("{{> shared/partial}}").should == root { partial partial_name("shared/partial") }
|
208
234
|
end
|
209
235
|
|
210
236
|
it "parses a comment" do
|
211
|
-
ast_for("{{! this is a comment }}").should ==
|
237
|
+
ast_for("{{! this is a comment }}").should == root do
|
212
238
|
comment " this is a comment "
|
213
239
|
end
|
214
240
|
end
|
215
241
|
|
216
242
|
it "parses a multi-line comment" do
|
217
|
-
ast_for("{{!\nthis is a multi-line comment\n}}").should ==
|
243
|
+
ast_for("{{!\nthis is a multi-line comment\n}}").should == root do
|
218
244
|
multiline_comment "this is a multi-line comment"
|
219
245
|
end
|
220
246
|
end
|
221
247
|
|
222
248
|
it "parses an inverse section" do
|
223
|
-
ast_for("{{#foo}} bar {{^}} baz {{/foo}}").should ==
|
249
|
+
ast_for("{{#foo}} bar {{^}} baz {{/foo}}").should == root do
|
224
250
|
block do
|
225
251
|
mustache id("foo")
|
226
252
|
|
@@ -235,12 +261,136 @@ describe "Parser" do
|
|
235
261
|
end
|
236
262
|
end
|
237
263
|
|
238
|
-
it "parses
|
239
|
-
ast_for("{{
|
240
|
-
|
264
|
+
it "parses an inverse ('else'-style) section" do
|
265
|
+
ast_for("{{#foo}} bar {{else}} baz {{/foo}}").should == root do
|
266
|
+
block do
|
267
|
+
mustache id("foo")
|
268
|
+
|
269
|
+
program do
|
270
|
+
content " bar "
|
271
|
+
end
|
272
|
+
|
273
|
+
inverse do
|
274
|
+
content " baz "
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
it "parses empty blocks" do
|
281
|
+
ast_for("{{#foo}}{{/foo}}").should == root do
|
282
|
+
block do
|
241
283
|
mustache id("foo")
|
242
284
|
|
243
285
|
program do
|
286
|
+
# empty program
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it "parses empty blocks with empty inverse section" do
|
293
|
+
ast_for("{{#foo}}{{^}}{{/foo}}").should == root do
|
294
|
+
block do
|
295
|
+
mustache id("foo")
|
296
|
+
|
297
|
+
program do
|
298
|
+
# empty program
|
299
|
+
end
|
300
|
+
|
301
|
+
inverse do
|
302
|
+
# empty inverse
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
it "parses empty blocks with empty inverse ('else'-style) section" do
|
309
|
+
ast_for("{{#foo}}{{else}}{{/foo}}").should == root do
|
310
|
+
block do
|
311
|
+
mustache id("foo")
|
312
|
+
|
313
|
+
program do
|
314
|
+
# empty program
|
315
|
+
end
|
316
|
+
|
317
|
+
inverse do
|
318
|
+
# empty inverse
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
it "parses non-empty blocks with empty inverse section" do
|
325
|
+
ast_for("{{#foo}} bar {{^}}{{/foo}}").should == root do
|
326
|
+
block do
|
327
|
+
mustache id("foo")
|
328
|
+
|
329
|
+
program do
|
330
|
+
content " bar "
|
331
|
+
end
|
332
|
+
|
333
|
+
inverse do
|
334
|
+
# empty inverse
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
it "parses non-empty blocks with empty inverse ('else'-style) section" do
|
341
|
+
ast_for("{{#foo}} bar {{else}}{{/foo}}").should == root do
|
342
|
+
block do
|
343
|
+
mustache id("foo")
|
344
|
+
|
345
|
+
program do
|
346
|
+
content " bar "
|
347
|
+
end
|
348
|
+
|
349
|
+
inverse do
|
350
|
+
# empty inverse
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
it "parses empty blocks with non-empty inverse section" do
|
357
|
+
ast_for("{{#foo}}{{^}} bar {{/foo}}").should == root do
|
358
|
+
block do
|
359
|
+
mustache id("foo")
|
360
|
+
|
361
|
+
program do
|
362
|
+
# empty program
|
363
|
+
end
|
364
|
+
|
365
|
+
inverse do
|
366
|
+
content " bar "
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
it "parses empty blocks with non-empty inverse ('else'-style) section" do
|
373
|
+
ast_for("{{#foo}}{{else}} bar {{/foo}}").should == root do
|
374
|
+
block do
|
375
|
+
mustache id("foo")
|
376
|
+
|
377
|
+
program do
|
378
|
+
# empty program
|
379
|
+
end
|
380
|
+
|
381
|
+
inverse do
|
382
|
+
content " bar "
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
it "parses a standalone inverse section" do
|
389
|
+
ast_for("{{^foo}}bar{{/foo}}").should == root do
|
390
|
+
block do
|
391
|
+
mustache id("foo")
|
392
|
+
|
393
|
+
inverse do
|
244
394
|
content "bar"
|
245
395
|
end
|
246
396
|
end
|
@@ -261,4 +411,23 @@ describe "Parser" do
|
|
261
411
|
it "knows how to report the correct line number in errors when the first character is a newline" do
|
262
412
|
lambda { ast_for("\n\nhello\n\nmy\n\n{{foo}") }.should raise_error(V8::JSError, /Parse error on line 7/m)
|
263
413
|
end
|
414
|
+
|
415
|
+
context "externally compiled AST" do
|
416
|
+
|
417
|
+
it "can pass through an already-compiled AST" do
|
418
|
+
ast_for(@context.eval('new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")]);')).should == root do
|
419
|
+
content "Hello"
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
it "can pass through an already-compiled AST via compile/precompile" do
|
424
|
+
@context = Handlebars::Spec::FULL_CONTEXT
|
425
|
+
|
426
|
+
code = 'Handlebars.compile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")]))();'
|
427
|
+
@context.eval(code).should == "Hello"
|
428
|
+
|
429
|
+
code = @context.eval 'Handlebars.precompile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")]))'
|
430
|
+
@context.eval("(#{code})(this)").should == "Hello"
|
431
|
+
end
|
432
|
+
end
|
264
433
|
end
|