poirot 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/poirot/version.rb +1 -1
- data/lib/poirot/view.rb +2 -0
- data/lib/poirot/view_helper.rb +7 -0
- data/lib/poirot.rb +1 -0
- data/vendor/assets/javascripts/poirot-mustache/mustache.js +490 -376
- metadata +7 -6
data/lib/poirot/version.rb
CHANGED
data/lib/poirot/view.rb
CHANGED
data/lib/poirot.rb
CHANGED
@@ -1,422 +1,536 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
// fail fast
|
29
|
-
if(!this.includes("", template)) {
|
30
|
-
if(in_recursion) {
|
31
|
-
return template;
|
32
|
-
} else {
|
33
|
-
this.send(template);
|
34
|
-
return;
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
// get the pragmas together
|
39
|
-
template = this.render_pragmas(template);
|
40
|
-
|
41
|
-
// render the template
|
42
|
-
var html = this.render_section(template, context, partials);
|
43
|
-
|
44
|
-
// render_section did not find any sections, we still need to render the tags
|
45
|
-
if (html === false) {
|
46
|
-
html = this.render_tags(template, context, partials, in_recursion);
|
47
|
-
}
|
48
|
-
|
49
|
-
if (in_recursion) {
|
50
|
-
return html;
|
51
|
-
} else {
|
52
|
-
this.sendLines(html);
|
53
|
-
}
|
54
|
-
},
|
55
|
-
|
56
|
-
/*
|
57
|
-
Sends parsed lines
|
58
|
-
*/
|
59
|
-
send: function(line) {
|
60
|
-
if(line !== "") {
|
61
|
-
this.buffer.push(line);
|
62
|
-
}
|
63
|
-
},
|
1
|
+
/*!
|
2
|
+
* mustache.js - Logic-less {{mustache}} templates with JavaScript
|
3
|
+
* http://github.com/janl/mustache.js
|
4
|
+
*/
|
5
|
+
var Mustache = (typeof module !== "undefined" && module.exports) || {};
|
6
|
+
|
7
|
+
(function (exports) {
|
8
|
+
|
9
|
+
exports.name = "mustache.js";
|
10
|
+
exports.version = "0.5.0-dev";
|
11
|
+
exports.tags = ["{{", "}}"];
|
12
|
+
exports.parse = parse;
|
13
|
+
exports.compile = compile;
|
14
|
+
exports.render = render;
|
15
|
+
exports.clearCache = clearCache;
|
16
|
+
|
17
|
+
// This is here for backwards compatibility with 0.4.x.
|
18
|
+
exports.to_html = function (template, view, partials, send) {
|
19
|
+
var result = render(template, view, partials);
|
20
|
+
|
21
|
+
if (typeof send === "function") {
|
22
|
+
send(result);
|
23
|
+
} else {
|
24
|
+
return result;
|
25
|
+
}
|
26
|
+
};
|
64
27
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
28
|
+
var _toString = Object.prototype.toString;
|
29
|
+
var _isArray = Array.isArray;
|
30
|
+
var _forEach = Array.prototype.forEach;
|
31
|
+
var _trim = String.prototype.trim;
|
32
|
+
|
33
|
+
var isArray;
|
34
|
+
if (_isArray) {
|
35
|
+
isArray = _isArray;
|
36
|
+
} else {
|
37
|
+
isArray = function (obj) {
|
38
|
+
return _toString.call(obj) === "[object Array]";
|
39
|
+
};
|
40
|
+
}
|
41
|
+
|
42
|
+
var forEach;
|
43
|
+
if (_forEach) {
|
44
|
+
forEach = function (obj, callback, scope) {
|
45
|
+
return _forEach.call(obj, callback, scope);
|
46
|
+
};
|
47
|
+
} else {
|
48
|
+
forEach = function (obj, callback, scope) {
|
49
|
+
for (var i = 0, len = obj.length; i < len; ++i) {
|
50
|
+
callback.call(scope, obj[i], i, obj);
|
81
51
|
}
|
52
|
+
};
|
53
|
+
}
|
54
|
+
|
55
|
+
var spaceRe = /^\s*$/;
|
56
|
+
|
57
|
+
function isWhitespace(string) {
|
58
|
+
return spaceRe.test(string);
|
59
|
+
}
|
60
|
+
|
61
|
+
var trim;
|
62
|
+
if (_trim) {
|
63
|
+
trim = function (string) {
|
64
|
+
return string == null ? "" : _trim.call(string);
|
65
|
+
};
|
66
|
+
} else {
|
67
|
+
var trimLeft, trimRight;
|
68
|
+
|
69
|
+
if (isWhitespace("\xA0")) {
|
70
|
+
trimLeft = /^\s+/;
|
71
|
+
trimRight = /\s+$/;
|
72
|
+
} else {
|
73
|
+
// IE doesn't match non-breaking spaces with \s, thanks jQuery.
|
74
|
+
trimLeft = /^[\s\xA0]+/;
|
75
|
+
trimRight = /[\s\xA0]+$/;
|
76
|
+
}
|
82
77
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
78
|
+
trim = function (string) {
|
79
|
+
return string == null ? "" :
|
80
|
+
String(string).replace(trimLeft, "").replace(trimRight, "");
|
81
|
+
};
|
82
|
+
}
|
83
|
+
|
84
|
+
var escapeMap = {
|
85
|
+
"&": "&",
|
86
|
+
"<": "<",
|
87
|
+
">": ">",
|
88
|
+
'"': '"',
|
89
|
+
"'": '''
|
90
|
+
};
|
87
91
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
}
|
112
|
-
if(typeof(context[name]) != "object") {
|
113
|
-
return this.render(partials[name], context, partials, true);
|
114
|
-
}
|
115
|
-
return this.render(partials[name], context[name], partials, true);
|
116
|
-
},
|
117
|
-
|
118
|
-
/*
|
119
|
-
Renders inverted (^) and normal (#) sections
|
120
|
-
*/
|
121
|
-
render_section: function(template, context, partials) {
|
122
|
-
if(!this.includes("#", template) && !this.includes("^", template)) {
|
123
|
-
// did not render anything, there were no sections
|
124
|
-
return false;
|
125
|
-
}
|
92
|
+
function escapeHTML(string) {
|
93
|
+
return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) {
|
94
|
+
return escapeMap[s] || s;
|
95
|
+
});
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Adds the `template`, `line`, and `file` properties to the given error
|
100
|
+
* object and alters the message to provide more useful debugging information.
|
101
|
+
*/
|
102
|
+
function debug(e, template, line, file) {
|
103
|
+
file = file || "<template>";
|
104
|
+
|
105
|
+
var lines = template.split("\n"),
|
106
|
+
start = Math.max(line - 3, 0),
|
107
|
+
end = Math.min(lines.length, line + 3),
|
108
|
+
context = lines.slice(start, end);
|
109
|
+
|
110
|
+
var c;
|
111
|
+
for (var i = 0, len = context.length; i < len; ++i) {
|
112
|
+
c = i + start + 1;
|
113
|
+
context[i] = (c === line ? " >> " : " ") + context[i];
|
114
|
+
}
|
126
115
|
|
127
|
-
|
116
|
+
e.template = template;
|
117
|
+
e.line = line;
|
118
|
+
e.file = file;
|
119
|
+
e.message = [file + ":" + line, context.join("\n"), "", e.message].join("\n");
|
128
120
|
|
129
|
-
|
130
|
-
|
131
|
-
return new RegExp(
|
132
|
-
"^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
|
121
|
+
return e;
|
122
|
+
}
|
133
123
|
|
134
|
-
|
135
|
-
|
136
|
-
|
124
|
+
/**
|
125
|
+
* Looks up the value of the given `name` in the given context `stack`.
|
126
|
+
*/
|
127
|
+
function lookup(name, stack, defaultValue) {
|
128
|
+
if (name === ".") {
|
129
|
+
return stack[stack.length - 1];
|
130
|
+
}
|
137
131
|
|
138
|
-
|
132
|
+
var names = name.split(".");
|
133
|
+
var lastIndex = names.length - 1;
|
134
|
+
var target = names[lastIndex];
|
139
135
|
|
140
|
-
|
141
|
-
|
142
|
-
|
136
|
+
var value, context, i = stack.length, j, localStack;
|
137
|
+
while (i) {
|
138
|
+
localStack = stack.slice(0);
|
139
|
+
context = stack[--i];
|
143
140
|
|
144
|
-
|
141
|
+
j = 0;
|
142
|
+
while (j < lastIndex) {
|
143
|
+
context = context[names[j++]];
|
145
144
|
|
146
|
-
|
147
|
-
|
145
|
+
if (context == null) {
|
146
|
+
break;
|
147
|
+
}
|
148
148
|
|
149
|
+
localStack.push(context);
|
150
|
+
}
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
152
|
+
if (context && typeof context === "object" && target in context) {
|
153
|
+
value = context[target];
|
154
|
+
break;
|
155
|
+
}
|
156
|
+
}
|
154
157
|
|
155
|
-
|
156
|
-
|
158
|
+
// If the value is a function, call it in the current context.
|
159
|
+
if (typeof value === "function") {
|
160
|
+
value = value.call(localStack[localStack.length - 1]);
|
161
|
+
}
|
157
162
|
|
158
|
-
|
159
|
-
|
163
|
+
if (value == null) {
|
164
|
+
return defaultValue;
|
165
|
+
}
|
160
166
|
|
161
|
-
|
167
|
+
return value;
|
168
|
+
}
|
162
169
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
renderedContent = that.render(content, context, partials, true);
|
167
|
-
} else {
|
168
|
-
renderedContent = "";
|
169
|
-
}
|
170
|
-
} else if (type === "#") { // normal section
|
171
|
-
if (that.is_array(value)) { // Enumerable, Let's loop!
|
172
|
-
renderedContent = that.map(value, function(row) {
|
173
|
-
return that.render(content, that.create_context(row), partials, true);
|
174
|
-
}).join("");
|
175
|
-
} else if (that.is_object(value)) { // Object, Use it as subcontext!
|
176
|
-
renderedContent = that.render(content, that.create_context(value),
|
177
|
-
partials, true);
|
178
|
-
} else if (typeof value === "function") {
|
179
|
-
// higher order section
|
180
|
-
renderedContent = value.call(context, content, function(text) {
|
181
|
-
return that.render(text, context, partials, true);
|
182
|
-
});
|
183
|
-
} else if (value) { // boolean section
|
184
|
-
renderedContent = that.render(content, context, partials, true);
|
185
|
-
} else {
|
186
|
-
renderedContent = "";
|
187
|
-
}
|
188
|
-
}
|
170
|
+
function renderSection(name, stack, callback, inverted) {
|
171
|
+
var buffer = "";
|
172
|
+
var value = lookup(name, stack);
|
189
173
|
|
190
|
-
|
174
|
+
if (inverted) {
|
175
|
+
// From the spec: inverted sections may render text once based on the
|
176
|
+
// inverse value of the key. That is, they will be rendered if the key
|
177
|
+
// doesn't exist, is false, or is an empty list.
|
178
|
+
if (value == null || value === false || (isArray(value) && value.length === 0)) {
|
179
|
+
buffer += callback();
|
180
|
+
}
|
181
|
+
} else if (isArray(value)) {
|
182
|
+
forEach(value, function (value) {
|
183
|
+
stack.push(value);
|
184
|
+
buffer += callback();
|
185
|
+
stack.pop();
|
191
186
|
});
|
192
|
-
}
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
var new_regex = function() {
|
204
|
-
return that.getCachedRegex("render_tags", function(otag, ctag) {
|
205
|
-
return new RegExp(otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + ctag + "+", "g");
|
206
|
-
});
|
187
|
+
} else if (typeof value === "object") {
|
188
|
+
stack.push(value);
|
189
|
+
buffer += callback();
|
190
|
+
stack.pop();
|
191
|
+
} else if (typeof value === "function") {
|
192
|
+
var scope = stack[stack.length - 1];
|
193
|
+
var scopedRender = function (template) {
|
194
|
+
return render(template, scope);
|
207
195
|
};
|
196
|
+
buffer += value.call(scope, callback(), scopedRender) || "";
|
197
|
+
} else if (value) {
|
198
|
+
buffer += callback();
|
199
|
+
}
|
208
200
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
201
|
+
return buffer;
|
202
|
+
}
|
203
|
+
|
204
|
+
/**
|
205
|
+
* Parses the given `template` and returns the source of a function that,
|
206
|
+
* with the proper arguments, will render the template. Recognized options
|
207
|
+
* include the following:
|
208
|
+
*
|
209
|
+
* - file The name of the file the template comes from (displayed in
|
210
|
+
* error messages)
|
211
|
+
* - tags An array of open and close tags the `template` uses. Defaults
|
212
|
+
* to the value of Mustache.tags
|
213
|
+
* - debug Set `true` to log the body of the generated function to the
|
214
|
+
* console
|
215
|
+
* - space Set `true` to preserve whitespace from lines that otherwise
|
216
|
+
* contain only a {{tag}}. Defaults to `false`
|
217
|
+
*/
|
218
|
+
function parse(template, options) {
|
219
|
+
options = options || {};
|
220
|
+
|
221
|
+
var tags = options.tags || exports.tags,
|
222
|
+
openTag = tags[0],
|
223
|
+
closeTag = tags[tags.length - 1];
|
224
|
+
|
225
|
+
var code = [
|
226
|
+
'var buffer = "";', // output buffer
|
227
|
+
"\nvar line = 1;", // keep track of source line number
|
228
|
+
"\ntry {",
|
229
|
+
'\nbuffer += "'
|
230
|
+
];
|
231
|
+
|
232
|
+
var spaces = [], // indices of whitespace in code on the current line
|
233
|
+
hasTag = false, // is there a {{tag}} on the current line?
|
234
|
+
nonSpace = false; // is there a non-space char on the current line?
|
235
|
+
|
236
|
+
// Strips all space characters from the code array for the current line
|
237
|
+
// if there was a {{tag}} on it and otherwise only spaces.
|
238
|
+
var stripSpace = function () {
|
239
|
+
if (hasTag && !nonSpace && !options.space) {
|
240
|
+
while (spaces.length) {
|
241
|
+
code.splice(spaces.pop(), 1);
|
231
242
|
}
|
243
|
+
} else {
|
244
|
+
spaces = [];
|
232
245
|
}
|
233
246
|
|
234
|
-
|
235
|
-
|
247
|
+
hasTag = false;
|
248
|
+
nonSpace = false;
|
249
|
+
};
|
250
|
+
|
251
|
+
var sectionStack = [], updateLine, nextOpenTag, nextCloseTag;
|
252
|
+
|
253
|
+
var setTags = function (source) {
|
254
|
+
tags = trim(source).split(/\s+/);
|
255
|
+
nextOpenTag = tags[0];
|
256
|
+
nextCloseTag = tags[tags.length - 1];
|
257
|
+
};
|
258
|
+
|
259
|
+
var includePartial = function (source) {
|
260
|
+
code.push(
|
261
|
+
'";',
|
262
|
+
updateLine,
|
263
|
+
'\nvar partial = partials["' + trim(source) + '"];',
|
264
|
+
'\nif (partial) {',
|
265
|
+
'\n buffer += render(partial,stack[stack.length - 1],partials);',
|
266
|
+
'\n}',
|
267
|
+
'\nbuffer += "'
|
268
|
+
);
|
269
|
+
};
|
270
|
+
|
271
|
+
var openSection = function (source, inverted) {
|
272
|
+
var name = trim(source);
|
273
|
+
|
274
|
+
if (name === "") {
|
275
|
+
throw debug(new Error("Section name may not be empty"), template, line, options.file);
|
236
276
|
}
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
277
|
+
|
278
|
+
sectionStack.push({name: name, inverted: inverted});
|
279
|
+
|
280
|
+
code.push(
|
281
|
+
'";',
|
282
|
+
updateLine,
|
283
|
+
'\nvar name = "' + name + '";',
|
284
|
+
'\nvar callback = (function () {',
|
285
|
+
'\n return function () {',
|
286
|
+
'\n var buffer = "";',
|
287
|
+
'\nbuffer += "'
|
288
|
+
);
|
289
|
+
};
|
290
|
+
|
291
|
+
var openInvertedSection = function (source) {
|
292
|
+
openSection(source, true);
|
293
|
+
};
|
294
|
+
|
295
|
+
var closeSection = function (source) {
|
296
|
+
var name = trim(source);
|
297
|
+
var openName = sectionStack.length != 0 && sectionStack[sectionStack.length - 1].name;
|
298
|
+
|
299
|
+
if (!openName || name != openName) {
|
300
|
+
throw debug(new Error('Section named "' + name + '" was never opened'), template, line, options.file);
|
255
301
|
}
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
302
|
+
|
303
|
+
var section = sectionStack.pop();
|
304
|
+
|
305
|
+
code.push(
|
306
|
+
'";',
|
307
|
+
'\n return buffer;',
|
308
|
+
'\n };',
|
309
|
+
'\n})();'
|
310
|
+
);
|
311
|
+
|
312
|
+
if (section.inverted) {
|
313
|
+
code.push("\nbuffer += renderSection(name,stack,callback,true);");
|
314
|
+
} else {
|
315
|
+
code.push("\nbuffer += renderSection(name,stack,callback);");
|
269
316
|
}
|
270
317
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
318
|
+
code.push('\nbuffer += "');
|
319
|
+
};
|
320
|
+
|
321
|
+
var sendPlain = function (source) {
|
322
|
+
code.push(
|
323
|
+
'";',
|
324
|
+
updateLine,
|
325
|
+
'\nbuffer += lookup("' + trim(source) + '",stack,"");',
|
326
|
+
'\nbuffer += "'
|
327
|
+
);
|
328
|
+
};
|
329
|
+
|
330
|
+
var sendEscaped = function (source) {
|
331
|
+
code.push(
|
332
|
+
'";',
|
333
|
+
updateLine,
|
334
|
+
'\nbuffer += escapeHTML(lookup("' + trim(source) + '",stack,""));',
|
335
|
+
'\nbuffer += "'
|
336
|
+
);
|
337
|
+
};
|
338
|
+
|
339
|
+
var line = 1, c, callback;
|
340
|
+
for (var i = 0, len = template.length; i < len; ++i) {
|
341
|
+
if (template.slice(i, i + openTag.length) === openTag) {
|
342
|
+
i += openTag.length;
|
343
|
+
c = template.substr(i, 1);
|
344
|
+
updateLine = '\nline = ' + line + ';';
|
345
|
+
nextOpenTag = openTag;
|
346
|
+
nextCloseTag = closeTag;
|
347
|
+
hasTag = true;
|
348
|
+
|
349
|
+
switch (c) {
|
350
|
+
case "!": // comment
|
351
|
+
i++;
|
352
|
+
callback = null;
|
353
|
+
break;
|
354
|
+
case "=": // change open/close tags, e.g. {{=<% %>=}}
|
355
|
+
i++;
|
356
|
+
closeTag = "=" + closeTag;
|
357
|
+
callback = setTags;
|
358
|
+
break;
|
359
|
+
case ">": // include partial
|
360
|
+
i++;
|
361
|
+
callback = includePartial;
|
362
|
+
break;
|
363
|
+
case "#": // start section
|
364
|
+
i++;
|
365
|
+
callback = openSection;
|
366
|
+
break;
|
367
|
+
case "^": // start inverted section
|
368
|
+
i++;
|
369
|
+
callback = openInvertedSection;
|
370
|
+
break;
|
371
|
+
case "/": // end section
|
372
|
+
i++;
|
373
|
+
callback = closeSection;
|
374
|
+
break;
|
375
|
+
case "{": // plain variable
|
376
|
+
closeTag = "}" + closeTag;
|
377
|
+
// fall through
|
378
|
+
case "&": // plain variable
|
379
|
+
i++;
|
380
|
+
nonSpace = true;
|
381
|
+
callback = sendPlain;
|
382
|
+
break;
|
383
|
+
default: // escaped variable
|
384
|
+
nonSpace = true;
|
385
|
+
callback = sendEscaped;
|
278
386
|
}
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
value = this.context[name];
|
387
|
+
|
388
|
+
var end = template.indexOf(closeTag, i);
|
389
|
+
|
390
|
+
if (end === -1) {
|
391
|
+
throw debug(new Error('Tag "' + openTag + '" was not closed properly'), template, line, options.file);
|
285
392
|
}
|
286
|
-
}
|
287
393
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
return value;
|
293
|
-
}
|
294
|
-
// silently ignore unkown variables
|
295
|
-
return "";
|
296
|
-
},
|
297
|
-
|
298
|
-
walk_context: function(name, context){
|
299
|
-
var path = name.split('.');
|
300
|
-
// if the var doesn't exist in current context, check the top level context
|
301
|
-
var value_context = (context[path[0]] != undefined) ? context : this.context;
|
302
|
-
var value = value_context[path.shift()];
|
303
|
-
while(value != undefined && path.length > 0){
|
304
|
-
value_context = value;
|
305
|
-
value = value[path.shift()];
|
306
|
-
}
|
307
|
-
// if the value is a function, call it, binding the correct context
|
308
|
-
if(typeof value === "function") {
|
309
|
-
return value.apply(value_context);
|
310
|
-
}
|
311
|
-
return value;
|
312
|
-
},
|
313
|
-
|
314
|
-
// Utility methods
|
315
|
-
|
316
|
-
/* includes tag */
|
317
|
-
includes: function(needle, haystack) {
|
318
|
-
return haystack.indexOf(this.otag + needle) != -1;
|
319
|
-
},
|
320
|
-
|
321
|
-
/*
|
322
|
-
Does away with nasty characters
|
323
|
-
*/
|
324
|
-
escape: function(s) {
|
325
|
-
s = String(s === null ? "" : s);
|
326
|
-
return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
|
327
|
-
switch(s) {
|
328
|
-
case "&": return "&";
|
329
|
-
case '"': return '"';
|
330
|
-
case "'": return ''';
|
331
|
-
case "<": return "<";
|
332
|
-
case ">": return ">";
|
333
|
-
default: return s;
|
394
|
+
var source = template.substring(i, end);
|
395
|
+
|
396
|
+
if (callback) {
|
397
|
+
callback(source);
|
334
398
|
}
|
335
|
-
});
|
336
|
-
},
|
337
399
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
var iterator = ".";
|
344
|
-
if(this.pragmas["IMPLICIT-ITERATOR"]) {
|
345
|
-
iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
|
400
|
+
// Maintain line count for \n in source.
|
401
|
+
var n = 0;
|
402
|
+
while (~(n = source.indexOf("\n", n))) {
|
403
|
+
line++;
|
404
|
+
n++;
|
346
405
|
}
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
},
|
352
|
-
|
353
|
-
is_object: function(a) {
|
354
|
-
return a && typeof a == "object";
|
355
|
-
},
|
356
|
-
|
357
|
-
is_array: function(a) {
|
358
|
-
return Object.prototype.toString.call(a) === '[object Array]';
|
359
|
-
},
|
360
|
-
|
361
|
-
/*
|
362
|
-
Gets rid of leading and trailing whitespace
|
363
|
-
*/
|
364
|
-
trim: function(s) {
|
365
|
-
return s.replace(/^\s*|\s*$/g, "");
|
366
|
-
},
|
367
|
-
|
368
|
-
/*
|
369
|
-
Why, why, why? Because IE. Cry, cry cry.
|
370
|
-
*/
|
371
|
-
map: function(array, fn) {
|
372
|
-
if (typeof array.map == "function") {
|
373
|
-
return array.map(fn);
|
406
|
+
|
407
|
+
i = end + closeTag.length - 1;
|
408
|
+
openTag = nextOpenTag;
|
409
|
+
closeTag = nextCloseTag;
|
374
410
|
} else {
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
411
|
+
c = template.substr(i, 1);
|
412
|
+
|
413
|
+
switch (c) {
|
414
|
+
case '"':
|
415
|
+
case "\\":
|
416
|
+
nonSpace = true;
|
417
|
+
code.push("\\" + c);
|
418
|
+
break;
|
419
|
+
case "\r":
|
420
|
+
// Ignore carriage returns.
|
421
|
+
break;
|
422
|
+
case "\n":
|
423
|
+
spaces.push(code.length);
|
424
|
+
code.push("\\n");
|
425
|
+
stripSpace(); // Check for whitespace on the current line.
|
426
|
+
line++;
|
427
|
+
break;
|
428
|
+
default:
|
429
|
+
if (isWhitespace(c)) {
|
430
|
+
spaces.push(code.length);
|
431
|
+
} else {
|
432
|
+
nonSpace = true;
|
433
|
+
}
|
434
|
+
|
435
|
+
code.push(c);
|
379
436
|
}
|
380
|
-
return r;
|
381
437
|
}
|
382
|
-
}
|
438
|
+
}
|
383
439
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
byOtag = regexCache[this.otag] = {};
|
388
|
-
}
|
440
|
+
if (sectionStack.length != 0) {
|
441
|
+
throw debug(new Error('Section "' + sectionStack[sectionStack.length - 1].name + '" was not closed properly'), template, line, options.file);
|
442
|
+
}
|
389
443
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
}
|
444
|
+
// Clean up any whitespace from a closing {{tag}} that was at the end
|
445
|
+
// of the template without a trailing \n.
|
446
|
+
stripSpace();
|
394
447
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
}
|
448
|
+
code.push(
|
449
|
+
'";',
|
450
|
+
"\nreturn buffer;",
|
451
|
+
"\n} catch (e) { throw {error: e, line: line}; }"
|
452
|
+
);
|
399
453
|
|
400
|
-
|
454
|
+
// Ignore `buffer += "";` statements.
|
455
|
+
var body = code.join("").replace(/buffer \+= "";\n/g, "");
|
456
|
+
|
457
|
+
if (options.debug) {
|
458
|
+
if (typeof console != "undefined" && console.log) {
|
459
|
+
console.log(body);
|
460
|
+
} else if (typeof print === "function") {
|
461
|
+
print(body);
|
462
|
+
}
|
401
463
|
}
|
402
|
-
};
|
403
464
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
465
|
+
return body;
|
466
|
+
}
|
467
|
+
|
468
|
+
/**
|
469
|
+
* Used by `compile` to generate a reusable function for the given `template`.
|
470
|
+
*/
|
471
|
+
function _compile(template, options) {
|
472
|
+
var args = "view,partials,stack,lookup,escapeHTML,renderSection,render";
|
473
|
+
var body = parse(template, options);
|
474
|
+
var fn = new Function(args, body);
|
475
|
+
|
476
|
+
// This anonymous function wraps the generated function so we can do
|
477
|
+
// argument coercion, setup some variables, and handle any errors
|
478
|
+
// encountered while executing it.
|
479
|
+
return function (view, partials) {
|
480
|
+
partials = partials || {};
|
481
|
+
|
482
|
+
var stack = [view]; // context stack
|
483
|
+
|
484
|
+
try {
|
485
|
+
return fn(view, partials, stack, lookup, escapeHTML, renderSection, render);
|
486
|
+
} catch (e) {
|
487
|
+
throw debug(e.error, template, e.line, options.file);
|
415
488
|
}
|
416
|
-
|
417
|
-
|
418
|
-
|
489
|
+
};
|
490
|
+
}
|
491
|
+
|
492
|
+
// Cache of pre-compiled templates.
|
493
|
+
var _cache = {};
|
494
|
+
|
495
|
+
/**
|
496
|
+
* Clear the cache of compiled templates.
|
497
|
+
*/
|
498
|
+
function clearCache() {
|
499
|
+
_cache = {};
|
500
|
+
}
|
501
|
+
|
502
|
+
/**
|
503
|
+
* Compiles the given `template` into a reusable function using the given
|
504
|
+
* `options`. In addition to the options accepted by Mustache.parse,
|
505
|
+
* recognized options include the following:
|
506
|
+
*
|
507
|
+
* - cache Set `false` to bypass any pre-compiled version of the given
|
508
|
+
* template. Otherwise, a given `template` string will be cached
|
509
|
+
* the first time it is parsed
|
510
|
+
*/
|
511
|
+
function compile(template, options) {
|
512
|
+
options = options || {};
|
513
|
+
|
514
|
+
// Use a pre-compiled version from the cache if we have one.
|
515
|
+
if (options.cache !== false) {
|
516
|
+
if (!_cache[template]) {
|
517
|
+
_cache[template] = _compile(template, options);
|
419
518
|
}
|
519
|
+
|
520
|
+
return _cache[template];
|
420
521
|
}
|
421
|
-
|
422
|
-
|
522
|
+
|
523
|
+
return _compile(template, options);
|
524
|
+
}
|
525
|
+
|
526
|
+
/**
|
527
|
+
* High-level function that renders the given `template` using the given
|
528
|
+
* `view` and `partials`. If you need to use any of the template options (see
|
529
|
+
* `compile` above), you must compile in a separate step, and then call that
|
530
|
+
* compiled function.
|
531
|
+
*/
|
532
|
+
function render(template, view, partials) {
|
533
|
+
return compile(template)(view, partials);
|
534
|
+
}
|
535
|
+
|
536
|
+
})(Mustache);
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: poirot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-04-26 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &70162223413260 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>'
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '3'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70162223413260
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: mustache
|
28
|
-
requirement: &
|
28
|
+
requirement: &70162223412840 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70162223412840
|
37
37
|
description: mustaches are cool
|
38
38
|
email:
|
39
39
|
- oliver.nightingale1@gmail.com
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- lib/poirot/handler.rb
|
53
53
|
- lib/poirot/version.rb
|
54
54
|
- lib/poirot/view.rb
|
55
|
+
- lib/poirot/view_helper.rb
|
55
56
|
- poirot.gemspec
|
56
57
|
- vendor/assets/javascripts/poirot-base/index.js
|
57
58
|
- vendor/assets/javascripts/poirot-base/poirot.js
|