handlebars 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/lib/handlebars/context.rb +3 -5
  2. data/lib/handlebars/version.rb +1 -1
  3. data/spec/handlebars_spec.rb +3 -3
  4. data/vendor/handlebars/.gitignore +3 -1
  5. data/vendor/handlebars/.jshintrc +2 -0
  6. data/vendor/handlebars/.npmignore +0 -1
  7. data/vendor/handlebars/.rspec +1 -0
  8. data/vendor/handlebars/Gemfile +1 -1
  9. data/vendor/handlebars/LICENSE +0 -1
  10. data/vendor/handlebars/README.markdown +8 -6
  11. data/vendor/handlebars/Rakefile +14 -21
  12. data/vendor/handlebars/bench/benchwarmer.js +1 -1
  13. data/vendor/handlebars/bench/handlebars.js +43 -34
  14. data/vendor/handlebars/bin/handlebars +56 -2
  15. data/vendor/handlebars/dist/handlebars.js +2201 -0
  16. data/vendor/handlebars/dist/handlebars.runtime.js +321 -0
  17. data/vendor/handlebars/lib/handlebars/base.js +68 -15
  18. data/vendor/handlebars/lib/handlebars/compiler/ast.js +50 -20
  19. data/vendor/handlebars/lib/handlebars/compiler/base.js +7 -13
  20. data/vendor/handlebars/lib/handlebars/compiler/compiler.js +758 -299
  21. data/vendor/handlebars/lib/handlebars/compiler/printer.js +24 -30
  22. data/vendor/handlebars/lib/handlebars/runtime.js +23 -3
  23. data/vendor/handlebars/lib/handlebars/utils.js +9 -10
  24. data/vendor/handlebars/package.json +15 -5
  25. data/vendor/handlebars/spec/acceptance_spec.rb +5 -5
  26. data/vendor/handlebars/spec/parser_spec.rb +201 -32
  27. data/vendor/handlebars/spec/qunit_spec.js +462 -159
  28. data/vendor/handlebars/spec/spec_helper.rb +7 -7
  29. data/vendor/handlebars/spec/tokenizer_spec.rb +55 -8
  30. data/vendor/handlebars/src/handlebars.l +14 -3
  31. data/vendor/handlebars/src/handlebars.yy +15 -5
  32. data/vendor/handlebars/src/parser-prefix.js +1 -0
  33. data/vendor/handlebars/src/parser-suffix.js +4 -0
  34. metadata +8 -3
@@ -0,0 +1,321 @@
1
+ /*
2
+
3
+ Copyright (C) 2011 by Yehuda Katz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+
23
+ */
24
+
25
+ // lib/handlebars/base.js
26
+
27
+ /*jshint eqnull:true*/
28
+ this.Handlebars = {};
29
+
30
+ (function(Handlebars) {
31
+
32
+ Handlebars.VERSION = "1.0.0-rc.3";
33
+ Handlebars.COMPILER_REVISION = 2;
34
+
35
+ Handlebars.REVISION_CHANGES = {
36
+ 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
37
+ 2: '>= 1.0.0-rc.3'
38
+ };
39
+
40
+ Handlebars.helpers = {};
41
+ Handlebars.partials = {};
42
+
43
+ Handlebars.registerHelper = function(name, fn, inverse) {
44
+ if(inverse) { fn.not = inverse; }
45
+ this.helpers[name] = fn;
46
+ };
47
+
48
+ Handlebars.registerPartial = function(name, str) {
49
+ this.partials[name] = str;
50
+ };
51
+
52
+ Handlebars.registerHelper('helperMissing', function(arg) {
53
+ if(arguments.length === 2) {
54
+ return undefined;
55
+ } else {
56
+ throw new Error("Could not find property '" + arg + "'");
57
+ }
58
+ });
59
+
60
+ var toString = Object.prototype.toString, functionType = "[object Function]";
61
+
62
+ Handlebars.registerHelper('blockHelperMissing', function(context, options) {
63
+ var inverse = options.inverse || function() {}, fn = options.fn;
64
+
65
+
66
+ var ret = "";
67
+ var type = toString.call(context);
68
+
69
+ if(type === functionType) { context = context.call(this); }
70
+
71
+ if(context === true) {
72
+ return fn(this);
73
+ } else if(context === false || context == null) {
74
+ return inverse(this);
75
+ } else if(type === "[object Array]") {
76
+ if(context.length > 0) {
77
+ return Handlebars.helpers.each(context, options);
78
+ } else {
79
+ return inverse(this);
80
+ }
81
+ } else {
82
+ return fn(context);
83
+ }
84
+ });
85
+
86
+ Handlebars.K = function() {};
87
+
88
+ Handlebars.createFrame = Object.create || function(object) {
89
+ Handlebars.K.prototype = object;
90
+ var obj = new Handlebars.K();
91
+ Handlebars.K.prototype = null;
92
+ return obj;
93
+ };
94
+
95
+ Handlebars.logger = {
96
+ DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
97
+
98
+ methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
99
+
100
+ // can be overridden in the host environment
101
+ log: function(level, obj) {
102
+ if (Handlebars.logger.level <= level) {
103
+ var method = Handlebars.logger.methodMap[level];
104
+ if (typeof console !== 'undefined' && console[method]) {
105
+ console[method].call(console, obj);
106
+ }
107
+ }
108
+ }
109
+ };
110
+
111
+ Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
112
+
113
+ Handlebars.registerHelper('each', function(context, options) {
114
+ var fn = options.fn, inverse = options.inverse;
115
+ var i = 0, ret = "", data;
116
+
117
+ if (options.data) {
118
+ data = Handlebars.createFrame(options.data);
119
+ }
120
+
121
+ if(context && typeof context === 'object') {
122
+ if(context instanceof Array){
123
+ for(var j = context.length; i<j; i++) {
124
+ if (data) { data.index = i; }
125
+ ret = ret + fn(context[i], { data: data });
126
+ }
127
+ } else {
128
+ for(var key in context) {
129
+ if(context.hasOwnProperty(key)) {
130
+ if(data) { data.key = key; }
131
+ ret = ret + fn(context[key], {data: data});
132
+ i++;
133
+ }
134
+ }
135
+ }
136
+ }
137
+
138
+ if(i === 0){
139
+ ret = inverse(this);
140
+ }
141
+
142
+ return ret;
143
+ });
144
+
145
+ Handlebars.registerHelper('if', function(context, options) {
146
+ var type = toString.call(context);
147
+ if(type === functionType) { context = context.call(this); }
148
+
149
+ if(!context || Handlebars.Utils.isEmpty(context)) {
150
+ return options.inverse(this);
151
+ } else {
152
+ return options.fn(this);
153
+ }
154
+ });
155
+
156
+ Handlebars.registerHelper('unless', function(context, options) {
157
+ var fn = options.fn, inverse = options.inverse;
158
+ options.fn = inverse;
159
+ options.inverse = fn;
160
+
161
+ return Handlebars.helpers['if'].call(this, context, options);
162
+ });
163
+
164
+ Handlebars.registerHelper('with', function(context, options) {
165
+ return options.fn(context);
166
+ });
167
+
168
+ Handlebars.registerHelper('log', function(context, options) {
169
+ var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
170
+ Handlebars.log(level, context);
171
+ });
172
+
173
+ }(this.Handlebars));
174
+ ;
175
+ // lib/handlebars/utils.js
176
+
177
+ var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
178
+
179
+ Handlebars.Exception = function(message) {
180
+ var tmp = Error.prototype.constructor.apply(this, arguments);
181
+
182
+ // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
183
+ for (var idx = 0; idx < errorProps.length; idx++) {
184
+ this[errorProps[idx]] = tmp[errorProps[idx]];
185
+ }
186
+ };
187
+ Handlebars.Exception.prototype = new Error();
188
+
189
+ // Build out our basic SafeString type
190
+ Handlebars.SafeString = function(string) {
191
+ this.string = string;
192
+ };
193
+ Handlebars.SafeString.prototype.toString = function() {
194
+ return this.string.toString();
195
+ };
196
+
197
+ (function() {
198
+ var escape = {
199
+ "&": "&amp;",
200
+ "<": "&lt;",
201
+ ">": "&gt;",
202
+ '"': "&quot;",
203
+ "'": "&#x27;",
204
+ "`": "&#x60;"
205
+ };
206
+
207
+ var badChars = /[&<>"'`]/g;
208
+ var possible = /[&<>"'`]/;
209
+
210
+ var escapeChar = function(chr) {
211
+ return escape[chr] || "&amp;";
212
+ };
213
+
214
+ Handlebars.Utils = {
215
+ escapeExpression: function(string) {
216
+ // don't escape SafeStrings, since they're already safe
217
+ if (string instanceof Handlebars.SafeString) {
218
+ return string.toString();
219
+ } else if (string == null || string === false) {
220
+ return "";
221
+ }
222
+
223
+ if(!possible.test(string)) { return string; }
224
+ return string.replace(badChars, escapeChar);
225
+ },
226
+
227
+ isEmpty: function(value) {
228
+ if (!value && value !== 0) {
229
+ return true;
230
+ } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
231
+ return true;
232
+ } else {
233
+ return false;
234
+ }
235
+ }
236
+ };
237
+ })();;
238
+ // lib/handlebars/runtime.js
239
+ Handlebars.VM = {
240
+ template: function(templateSpec) {
241
+ // Just add water
242
+ var container = {
243
+ escapeExpression: Handlebars.Utils.escapeExpression,
244
+ invokePartial: Handlebars.VM.invokePartial,
245
+ programs: [],
246
+ program: function(i, fn, data) {
247
+ var programWrapper = this.programs[i];
248
+ if(data) {
249
+ return Handlebars.VM.program(fn, data);
250
+ } else if(programWrapper) {
251
+ return programWrapper;
252
+ } else {
253
+ programWrapper = this.programs[i] = Handlebars.VM.program(fn);
254
+ return programWrapper;
255
+ }
256
+ },
257
+ programWithDepth: Handlebars.VM.programWithDepth,
258
+ noop: Handlebars.VM.noop,
259
+ compilerInfo: null
260
+ };
261
+
262
+ return function(context, options) {
263
+ options = options || {};
264
+ var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
265
+
266
+ var compilerInfo = container.compilerInfo || [],
267
+ compilerRevision = compilerInfo[0] || 1,
268
+ currentRevision = Handlebars.COMPILER_REVISION;
269
+
270
+ if (compilerRevision !== currentRevision) {
271
+ if (compilerRevision < currentRevision) {
272
+ var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
273
+ compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
274
+ throw "Template was precompiled with an older version of Handlebars than the current runtime. "+
275
+ "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").";
276
+ } else {
277
+ // Use the embedded version info since the runtime doesn't know about this revision yet
278
+ throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+
279
+ "Please update your runtime to a newer version ("+compilerInfo[1]+").";
280
+ }
281
+ }
282
+
283
+ return result;
284
+ };
285
+ },
286
+
287
+ programWithDepth: function(fn, data, $depth) {
288
+ var args = Array.prototype.slice.call(arguments, 2);
289
+
290
+ return function(context, options) {
291
+ options = options || {};
292
+
293
+ return fn.apply(this, [context, options.data || data].concat(args));
294
+ };
295
+ },
296
+ program: function(fn, data) {
297
+ return function(context, options) {
298
+ options = options || {};
299
+
300
+ return fn(context, options.data || data);
301
+ };
302
+ },
303
+ noop: function() { return ""; },
304
+ invokePartial: function(partial, name, context, helpers, partials, data) {
305
+ var options = { helpers: helpers, partials: partials, data: data };
306
+
307
+ if(partial === undefined) {
308
+ throw new Handlebars.Exception("The partial " + name + " could not be found");
309
+ } else if(partial instanceof Function) {
310
+ return partial(context, options);
311
+ } else if (!Handlebars.compile) {
312
+ throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
313
+ } else {
314
+ partials[name] = Handlebars.compile(partial, {data: data !== undefined});
315
+ return partials[name](context, options);
316
+ }
317
+ }
318
+ };
319
+
320
+ Handlebars.template = Handlebars.VM.template;
321
+ ;
@@ -1,9 +1,17 @@
1
1
  // BEGIN(BROWSER)
2
2
 
3
3
  /*jshint eqnull:true*/
4
- var Handlebars = {};
4
+ this.Handlebars = {};
5
5
 
6
- Handlebars.VERSION = "1.0.beta.5";
6
+ (function(Handlebars) {
7
+
8
+ Handlebars.VERSION = "1.0.0-rc.3";
9
+ Handlebars.COMPILER_REVISION = 2;
10
+
11
+ Handlebars.REVISION_CHANGES = {
12
+ 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
13
+ 2: '>= 1.0.0-rc.3'
14
+ };
7
15
 
8
16
  Handlebars.helpers = {};
9
17
  Handlebars.partials = {};
@@ -42,29 +50,71 @@ Handlebars.registerHelper('blockHelperMissing', function(context, options) {
42
50
  return inverse(this);
43
51
  } else if(type === "[object Array]") {
44
52
  if(context.length > 0) {
45
- for(var i=0, j=context.length; i<j; i++) {
46
- ret = ret + fn(context[i]);
47
- }
53
+ return Handlebars.helpers.each(context, options);
48
54
  } else {
49
- ret = inverse(this);
55
+ return inverse(this);
50
56
  }
51
- return ret;
52
57
  } else {
53
58
  return fn(context);
54
59
  }
55
60
  });
56
61
 
62
+ Handlebars.K = function() {};
63
+
64
+ Handlebars.createFrame = Object.create || function(object) {
65
+ Handlebars.K.prototype = object;
66
+ var obj = new Handlebars.K();
67
+ Handlebars.K.prototype = null;
68
+ return obj;
69
+ };
70
+
71
+ Handlebars.logger = {
72
+ DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
73
+
74
+ methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
75
+
76
+ // can be overridden in the host environment
77
+ log: function(level, obj) {
78
+ if (Handlebars.logger.level <= level) {
79
+ var method = Handlebars.logger.methodMap[level];
80
+ if (typeof console !== 'undefined' && console[method]) {
81
+ console[method].call(console, obj);
82
+ }
83
+ }
84
+ }
85
+ };
86
+
87
+ Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
88
+
57
89
  Handlebars.registerHelper('each', function(context, options) {
58
90
  var fn = options.fn, inverse = options.inverse;
59
- var ret = "";
91
+ var i = 0, ret = "", data;
60
92
 
61
- if(context && context.length > 0) {
62
- for(var i=0, j=context.length; i<j; i++) {
63
- ret = ret + fn(context[i]);
93
+ if (options.data) {
94
+ data = Handlebars.createFrame(options.data);
95
+ }
96
+
97
+ if(context && typeof context === 'object') {
98
+ if(context instanceof Array){
99
+ for(var j = context.length; i<j; i++) {
100
+ if (data) { data.index = i; }
101
+ ret = ret + fn(context[i], { data: data });
102
+ }
103
+ } else {
104
+ for(var key in context) {
105
+ if(context.hasOwnProperty(key)) {
106
+ if(data) { data.key = key; }
107
+ ret = ret + fn(context[key], {data: data});
108
+ i++;
109
+ }
110
+ }
64
111
  }
65
- } else {
112
+ }
113
+
114
+ if(i === 0){
66
115
  ret = inverse(this);
67
116
  }
117
+
68
118
  return ret;
69
119
  });
70
120
 
@@ -91,11 +141,14 @@ Handlebars.registerHelper('with', function(context, options) {
91
141
  return options.fn(context);
92
142
  });
93
143
 
94
- Handlebars.registerHelper('log', function(context) {
95
- Handlebars.log(context);
144
+ Handlebars.registerHelper('log', function(context, options) {
145
+ var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
146
+ Handlebars.log(level, context);
96
147
  });
97
148
 
149
+ }(this.Handlebars));
150
+
98
151
  // END(BROWSER)
99
152
 
100
- module.exports = Handlebars;
153
+ module.exports = this.Handlebars;
101
154
 
@@ -11,21 +11,32 @@ var Handlebars = require('./base');
11
11
  if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
12
12
  };
13
13
 
14
- Handlebars.AST.MustacheNode = function(params, hash, unescaped) {
14
+ Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
15
15
  this.type = "mustache";
16
- this.id = params[0];
17
- this.params = params.slice(1);
18
- this.hash = hash;
19
16
  this.escaped = !unescaped;
20
- };
17
+ this.hash = hash;
21
18
 
22
- Handlebars.AST.PartialNode = function(id, context) {
23
- this.type = "partial";
19
+ var id = this.id = rawParams[0];
20
+ var params = this.params = rawParams.slice(1);
24
21
 
25
- // TODO: disallow complex IDs
22
+ // a mustache is an eligible helper if:
23
+ // * its id is simple (a single part, not `this` or `..`)
24
+ var eligibleHelper = this.eligibleHelper = id.isSimple;
26
25
 
27
- this.id = id;
28
- this.context = context;
26
+ // a mustache is definitely a helper if:
27
+ // * it is an eligible helper, and
28
+ // * it has at least one parameter or hash segment
29
+ this.isHelper = eligibleHelper && (params.length || hash);
30
+
31
+ // if a mustache is an eligible helper but not a definite
32
+ // helper, it is ambiguous, and will be resolved in a later
33
+ // pass or at runtime.
34
+ };
35
+
36
+ Handlebars.AST.PartialNode = function(partialName, context) {
37
+ this.type = "partial";
38
+ this.partialName = partialName;
39
+ this.context = context;
29
40
  };
30
41
 
31
42
  var verifyMatch = function(open, close) {
@@ -34,18 +45,16 @@ var Handlebars = require('./base');
34
45
  }
35
46
  };
36
47
 
37
- Handlebars.AST.BlockNode = function(mustache, program, close) {
48
+ Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
38
49
  verifyMatch(mustache.id, close);
39
50
  this.type = "block";
40
51
  this.mustache = mustache;
41
52
  this.program = program;
42
- };
53
+ this.inverse = inverse;
43
54
 
44
- Handlebars.AST.InverseNode = function(mustache, program, close) {
45
- verifyMatch(mustache.id, close);
46
- this.type = "inverse";
47
- this.mustache = mustache;
48
- this.program = program;
55
+ if (this.inverse && !this.program) {
56
+ this.isInverse = true;
57
+ }
49
58
  };
50
59
 
51
60
  Handlebars.AST.ContentNode = function(string) {
@@ -67,30 +76,51 @@ var Handlebars = require('./base');
67
76
  for(var i=0,l=parts.length; i<l; i++) {
68
77
  var part = parts[i];
69
78
 
70
- if(part === "..") { depth++; }
71
- else if(part === "." || part === "this") { this.isScoped = true; }
79
+ if (part === ".." || part === "." || part === "this") {
80
+ if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + this.original); }
81
+ else if (part === "..") { depth++; }
82
+ else { this.isScoped = true; }
83
+ }
72
84
  else { dig.push(part); }
73
85
  }
74
86
 
75
87
  this.parts = dig;
76
88
  this.string = dig.join('.');
77
89
  this.depth = depth;
78
- this.isSimple = (dig.length === 1) && (depth === 0);
90
+
91
+ // an ID is simple if it only has one part, and that part is not
92
+ // `..` or `this`.
93
+ this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
94
+
95
+ this.stringModeValue = this.string;
96
+ };
97
+
98
+ Handlebars.AST.PartialNameNode = function(name) {
99
+ this.type = "PARTIAL_NAME";
100
+ this.name = name;
101
+ };
102
+
103
+ Handlebars.AST.DataNode = function(id) {
104
+ this.type = "DATA";
105
+ this.id = id;
79
106
  };
80
107
 
81
108
  Handlebars.AST.StringNode = function(string) {
82
109
  this.type = "STRING";
83
110
  this.string = string;
111
+ this.stringModeValue = string;
84
112
  };
85
113
 
86
114
  Handlebars.AST.IntegerNode = function(integer) {
87
115
  this.type = "INTEGER";
88
116
  this.integer = integer;
117
+ this.stringModeValue = Number(integer);
89
118
  };
90
119
 
91
120
  Handlebars.AST.BooleanNode = function(bool) {
92
121
  this.type = "BOOLEAN";
93
122
  this.bool = bool;
123
+ this.stringModeValue = bool === "true";
94
124
  };
95
125
 
96
126
  Handlebars.AST.CommentNode = function(comment) {