gumdrop 0.3 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/ChangeLog.md +6 -0
  2. data/lib/gumdrop/cli.rb +4 -4
  3. data/lib/gumdrop/generator.rb +2 -15
  4. data/lib/gumdrop/stitch_ex.rb +14 -0
  5. data/lib/gumdrop/template/backbone/Gemfile +29 -0
  6. data/lib/gumdrop/template/backbone/Rakefile +38 -0
  7. data/lib/gumdrop/template/backbone/app_src/app.js.coffee +32 -0
  8. data/lib/gumdrop/template/backbone/app_src/init.js.coffee +10 -0
  9. data/lib/gumdrop/template/backbone/app_src/utils/index.js.coffee +29 -0
  10. data/lib/gumdrop/template/backbone/config.ru +21 -0
  11. data/lib/gumdrop/template/backbone/data/config.yml +4 -0
  12. data/lib/gumdrop/template/backbone/lib/javascript/all.js.coffee +18 -0
  13. data/lib/gumdrop/template/backbone/lib/javascript/backbone.js +1158 -0
  14. data/lib/gumdrop/template/backbone/lib/javascript/hogan.js +509 -0
  15. data/lib/gumdrop/template/backbone/lib/javascript/jquery.js +9266 -0
  16. data/lib/gumdrop/template/backbone/lib/javascript/underscore.js +981 -0
  17. data/lib/gumdrop/template/backbone/lib/site.rb +58 -0
  18. data/lib/gumdrop/template/backbone/lib/stitch_compilers.rb +85 -0
  19. data/lib/gumdrop/template/backbone/lib/view_helpers.rb +17 -0
  20. data/lib/gumdrop/template/backbone/powrc +2 -0
  21. data/lib/gumdrop/template/backbone/source/default.htaccess +22 -0
  22. data/lib/gumdrop/template/backbone/source/favicon.ico +0 -0
  23. data/lib/gumdrop/template/backbone/source/feed.xml.builder.txt +23 -0
  24. data/lib/gumdrop/template/backbone/source/index.html.erb +2 -0
  25. data/lib/gumdrop/template/backbone/source/theme/screen.css.sass +9 -0
  26. data/lib/gumdrop/template/backbone/source/theme/scripts/app.js.coffee +4 -0
  27. data/lib/gumdrop/template/backbone/source/theme/styles/_tools.scss +434 -0
  28. data/lib/gumdrop/template/backbone/source/theme/templates/app.template.slim +14 -0
  29. data/lib/gumdrop/template/backbone/source/theme/templates/site.template.slim +33 -0
  30. data/lib/gumdrop/version.rb +1 -1
  31. metadata +39 -13
@@ -0,0 +1,509 @@
1
+ /*
2
+ * Copyright 2011 Twitter, Inc.
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ */
15
+
16
+ var HoganTemplate = (function () {
17
+
18
+ function constructor(text) {
19
+ this.text = text;
20
+ }
21
+
22
+ constructor.prototype = {
23
+ // render: replaced by generated code.
24
+ r: function (context, partials) { return ''; },
25
+
26
+ // variable escaping
27
+ v: hoganEscape,
28
+
29
+ render: function render(context, partials) {
30
+ return this.r(context, partials);
31
+ },
32
+
33
+ // tries to find a partial in the curent scope and render it
34
+ rp: function(name, context, partials, indent) {
35
+ var partial = partials[name];
36
+
37
+ if (!partial) {
38
+ return '';
39
+ }
40
+
41
+ return partial.render(context, partials);
42
+ },
43
+
44
+ // render a section
45
+ rs: function(context, partials, section) {
46
+ var buf = '',
47
+ tail = context[context.length - 1];
48
+
49
+ if (!isArray(tail)) {
50
+ buf = section(context, partials);
51
+ return buf;
52
+ }
53
+
54
+ for (var i = 0; i < tail.length; i++) {
55
+ context.push(tail[i]);
56
+ buf += section(context, partials);
57
+ context.pop();
58
+ }
59
+ return buf;
60
+ },
61
+
62
+ // maybe start a section
63
+ s: function(val, ctx, partials, inverted, start, end) {
64
+ var pass;
65
+
66
+ if (isArray(val) && val.length === 0) {
67
+ return false;
68
+ }
69
+
70
+ if (!inverted && typeof val == 'function') {
71
+ val = this.ls(val, ctx, partials, start, end);
72
+ }
73
+
74
+ pass = (val === '') || !!val;
75
+
76
+ if (!inverted && pass && ctx) {
77
+ ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);
78
+ }
79
+
80
+ return pass;
81
+ },
82
+
83
+ // find values with dotted names
84
+ d: function(key, ctx, partials, returnFound) {
85
+
86
+ var names = key.split('.'),
87
+ val = this.f(names[0], ctx, partials, returnFound),
88
+ cx = null;
89
+
90
+ if (key === '.' && isArray(ctx[ctx.length - 2])) {
91
+ return ctx[ctx.length - 1];
92
+ }
93
+
94
+ for (var i = 1; i < names.length; i++) {
95
+ if (val && typeof val == 'object' && names[i] in val) {
96
+ cx = val;
97
+ val = val[names[i]];
98
+ } else {
99
+ val = '';
100
+ }
101
+ }
102
+
103
+ if (returnFound && !val) {
104
+ return false;
105
+ }
106
+
107
+ if (!returnFound && typeof val == 'function') {
108
+ ctx.push(cx);
109
+ val = this.lv(val, ctx, partials);
110
+ ctx.pop();
111
+ }
112
+
113
+ return val;
114
+ },
115
+
116
+ // find values with normal names
117
+ f: function(key, ctx, partials, returnFound) {
118
+ var val = false,
119
+ v = null,
120
+ found = false;
121
+
122
+ for (var i = ctx.length - 1; i >= 0; i--) {
123
+ v = ctx[i];
124
+ if (v && typeof v == 'object' && key in v) {
125
+ val = v[key];
126
+ found = true;
127
+ break;
128
+ }
129
+ }
130
+
131
+ if (!found) {
132
+ return (returnFound) ? false : "";
133
+ }
134
+
135
+ if (!returnFound && typeof val == 'function') {
136
+ val = this.lv(val, ctx, partials);
137
+ }
138
+
139
+ return val;
140
+ },
141
+
142
+ // higher order templates
143
+ ho: function(val, cx, partials, text) {
144
+ var t = val.call(cx, text, function(t) {
145
+ return Hogan.compile(t).render(cx);
146
+ });
147
+ var s = Hogan.compile(t.toString()).render(cx, partials);
148
+ this.b = s;
149
+ return false;
150
+ },
151
+
152
+ // higher order template result buffer
153
+ b: '',
154
+
155
+ // lambda replace section
156
+ ls: function(val, ctx, partials, start, end) {
157
+ var cx = ctx[ctx.length - 1],
158
+ t = val.call(cx);
159
+
160
+ if (val.length > 0) {
161
+ return this.ho(val, cx, partials, this.text.substring(start, end));
162
+ }
163
+
164
+ if (typeof t == 'function') {
165
+ return this.ho(t, cx, partials, this.text.substring(start, end));
166
+ }
167
+ return t;
168
+ },
169
+
170
+ // lambda replace variable
171
+ lv: function(val, ctx, partials) {
172
+ var cx = ctx[ctx.length - 1];
173
+ return Hogan.compile(val.call(cx).toString()).render(cx, partials);
174
+ }
175
+ };
176
+
177
+ var rAmp = /&/g, rLt = /</g, rGt = />/g, rApos =/\'/g,
178
+ rQuot = /\"/g, hChars =/[&<>\"\']/;
179
+ function hoganEscape(str) {
180
+ var s = String(str === null ? '' : str);
181
+ return hChars.test(s) ? s.replace(rAmp,'&amp;')
182
+ .replace(rLt,'&lt;').replace(rGt,'&gt;')
183
+ .replace(rApos,'&#39;').replace(rQuot, '&quot;') : s;
184
+ }
185
+
186
+ var isArray = Array.isArray || function(a) {
187
+ return Object.prototype.toString.call(a) === '[object Array]';
188
+ };
189
+
190
+ return constructor;
191
+ })();
192
+
193
+ var Hogan = (function () {
194
+
195
+ // Setup regex assignments
196
+ // remove whitespace according to Mustache spec
197
+ var rIsWhitespace = /\S/,
198
+ rQuot = /\"/g,
199
+ rNewline = /\n/g,
200
+ rCr = /\r/g,
201
+ rSlash = /\\/g,
202
+ tagTypes = {
203
+ '#': 1, '^': 2, '/': 3, '!': 4, '>': 5,
204
+ '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10
205
+ };
206
+
207
+ function scan(text) {
208
+ var len = text.length,
209
+ IN_TEXT = 0,
210
+ IN_TAG_TYPE = 1,
211
+ IN_TAG = 2,
212
+ state = IN_TEXT,
213
+ tagType = null,
214
+ tag = null,
215
+ buf = '',
216
+ tokens = [],
217
+ seenTag = false,
218
+ i = 0,
219
+ lineStart = 0,
220
+ otag = '{{',
221
+ ctag = '}}';
222
+
223
+ function addBuf() {
224
+ if (buf.length > 0) {
225
+ tokens.push(new String(buf));
226
+ buf = '';
227
+ }
228
+ }
229
+
230
+ function lineIsWhitespace() {
231
+ var isAllWhitespace = true;
232
+ for (var j = lineStart; j < tokens.length; j++) {
233
+ isAllWhitespace =
234
+ (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) ||
235
+ (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null);
236
+ if (!isAllWhitespace) {
237
+ return false;
238
+ }
239
+ }
240
+
241
+ return isAllWhitespace;
242
+ }
243
+
244
+ function filterLine(haveSeenTag, noNewLine) {
245
+ addBuf();
246
+ if (haveSeenTag && lineIsWhitespace()) {
247
+ for (var j = lineStart; j < tokens.length; j++) {
248
+ if (!tokens[j].tag) {
249
+ tokens.splice(j, 1);
250
+ }
251
+ }
252
+ } else if (!noNewLine) {
253
+ tokens.push({tag:'\n'});
254
+ }
255
+
256
+ seenTag = false;
257
+ lineStart = tokens.length;
258
+ }
259
+
260
+ function changeDelimiters(text, index) {
261
+ var close = '=' + ctag,
262
+ closeIndex = text.indexOf(close, index),
263
+ delimiters = trim(text.substring(text.indexOf('=', index) + 1,
264
+ closeIndex)).split(' ');
265
+ otag = delimiters[0];
266
+ ctag = delimiters[1];
267
+ return closeIndex + close.length - 1;
268
+ }
269
+
270
+ for (i = 0; i < len; i++) {
271
+ if (state == IN_TEXT) {
272
+ if (tagChange(otag, text, i)) {
273
+ --i;
274
+ addBuf();
275
+ state = IN_TAG_TYPE;
276
+ } else {
277
+ if (text[i] == '\n') {
278
+ filterLine(seenTag);
279
+ } else {
280
+ buf += text[i];
281
+ }
282
+ }
283
+ } else if (state == IN_TAG_TYPE) {
284
+ i += otag.length - 1;
285
+ tag = tagTypes[text[i + 1]];
286
+ tagType = tag ? text[i + 1] : '_v';
287
+ seenTag = i;
288
+ if (tagType == '=') {
289
+ i = changeDelimiters(text, i);
290
+ state = IN_TEXT;
291
+ } else {
292
+ if (tag) {
293
+ i++;
294
+ }
295
+ state = IN_TAG;
296
+ }
297
+ } else {
298
+ if (tagChange(ctag, text, i)) {
299
+ i += ctag.length - 1;
300
+ tokens.push({tag: tagType, n: trim(buf),
301
+ i: (tagType == '/') ? seenTag - 1 : i + 1});
302
+ buf = '';
303
+ state = IN_TEXT;
304
+ if (tagType == '{') {
305
+ i++;
306
+ }
307
+ } else {
308
+ buf += text[i];
309
+ }
310
+ }
311
+ }
312
+
313
+ filterLine(seenTag, true);
314
+
315
+ return tokens;
316
+ }
317
+
318
+ function trim(s) {
319
+ if (s.trim) {
320
+ return s.trim();
321
+ }
322
+
323
+ return s.replace(/^\s*|\s*$/g, '');
324
+ }
325
+
326
+ function tagChange(tag, text, index) {
327
+ if (text[index] != tag[0]) {
328
+ return false;
329
+ }
330
+
331
+ for (var i = 1, l = tag.length; i < l; i++) {
332
+ if (text[index + i] != tag[i]) {
333
+ return false;
334
+ }
335
+ }
336
+
337
+ return true;
338
+ }
339
+
340
+ function buildTree(tokens, kind, stack, customTags) {
341
+ var instructions = [],
342
+ opener = null,
343
+ token = null;
344
+
345
+ while (tokens.length > 0) {
346
+ token = tokens.shift();
347
+ if (token.tag == '#' || token.tag == '^' ||
348
+ isOpener(token, customTags)) {
349
+ stack.push(token);
350
+ token.nodes = buildTree(tokens, token.tag, stack, customTags);
351
+ instructions.push(token);
352
+ } else if (token.tag == '/') {
353
+ if (stack.length === 0) {
354
+ throw new Error('Closing tag without opener: /' + token.n);
355
+ }
356
+ opener = stack.pop();
357
+ if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {
358
+ throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);
359
+ }
360
+ opener.end = token.i;
361
+ return instructions;
362
+ } else {
363
+ instructions.push(token);
364
+ }
365
+ }
366
+
367
+ if (stack.length > 0) {
368
+ throw new Error('missing closing tag: ' + stack.pop().n);
369
+ }
370
+
371
+ return instructions;
372
+ }
373
+
374
+ function isOpener(token, tags) {
375
+ for (var i = 0, l = tags.length; i < l; i++) {
376
+ if (tags[i].o == token.n) {
377
+ token.tag = '#';
378
+ return true;
379
+ }
380
+ }
381
+ }
382
+
383
+ function isCloser(close, open, tags) {
384
+ for (var i = 0, l = tags.length; i < l; i++) {
385
+ if (tags[i].c == close && tags[i].o == open) {
386
+ return true;
387
+ }
388
+ }
389
+ }
390
+
391
+ function generate(tree, text, options) {
392
+ var code = 'var c = [cx];var b = "";var _ = this;' +
393
+ walk(tree) + 'return b;';
394
+ if (options.asString) {
395
+ return 'function(cx,p){' + code + ';};';
396
+ }
397
+
398
+ var template = new HoganTemplate(text);
399
+ template.r = new Function('cx', 'p', code);
400
+ return template;
401
+ }
402
+
403
+ function esc(s) {
404
+ return s.replace(rSlash, '\\\\')
405
+ .replace(rQuot, '\\\"')
406
+ .replace(rNewline, '\\n')
407
+ .replace(rCr, '\\r');
408
+ }
409
+
410
+ function chooseMethod(s) {
411
+ return (~s.indexOf('.')) ? 'd' : 'f';
412
+ }
413
+
414
+ function walk(tree) {
415
+ var code = '';
416
+ for (var i = 0, l = tree.length; i < l; i++) {
417
+ var tag = tree[i].tag;
418
+ if (tag == '#') {
419
+ code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n),
420
+ tree[i].i, tree[i].end);
421
+ } else if (tag == '^') {
422
+ code += invertedSection(tree[i].nodes, tree[i].n,
423
+ chooseMethod(tree[i].n));
424
+ } else if (tag == '<' || tag == '>') {
425
+ code += partial(tree[i].n);
426
+ } else if (tag == '{' || tag == '&') {
427
+ code += tripleStache(tree[i].n, chooseMethod(tree[i].n));
428
+ } else if (tag == '\n') {
429
+ code += text('\n');
430
+ } else if (tag == '_v') {
431
+ code += variable(tree[i].n, chooseMethod(tree[i].n));
432
+ } else if (tag === undefined) {
433
+ code += text(tree[i]);
434
+ }
435
+ }
436
+ return code;
437
+ }
438
+
439
+ function section(nodes, id, method, start, end) {
440
+ return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' +
441
+ 'c,p,0,' + start + ',' + end + ')){' +
442
+ 'b += _.rs(c,p,' +
443
+ 'function(c,p){ var b = "";' +
444
+ walk(nodes) +
445
+ 'return b;});c.pop();}' +
446
+ 'else{b += _.b; _.b = ""};';
447
+ }
448
+
449
+ function invertedSection(nodes, id, method) {
450
+ return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0)){' +
451
+ walk(nodes) +
452
+ '};';
453
+ }
454
+
455
+ function partial(id) {
456
+ return 'b += _.rp("' + esc(id) + '",c[c.length - 1],p);';
457
+ }
458
+
459
+ function tripleStache(id, method) {
460
+ return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));';
461
+ }
462
+
463
+ function variable(id, method) {
464
+ return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));';
465
+ }
466
+
467
+ function text(id) {
468
+ return 'b += "' + esc(id) + '";';
469
+ }
470
+
471
+ return ({
472
+ scan: scan,
473
+
474
+ parse: function(tokens, options) {
475
+ options = options || {};
476
+ return buildTree(tokens, '', [], options.sectionTags || []);
477
+ },
478
+
479
+ cache: {},
480
+
481
+ compile: function(text, options) {
482
+ // options
483
+ //
484
+ // asString: false (default)
485
+ //
486
+ // sectionTags: [{o: '_foo', c: 'foo'}]
487
+ // An array of object with o and c fields that indicate names for custom
488
+ // section tags. The example above allows parsing of {{_foo}}{{/foo}}.
489
+ //
490
+ options = options || {};
491
+
492
+ var t = this.cache[text];
493
+ if (t) {
494
+ return t;
495
+ }
496
+ t = generate(this.parse(scan(text), options), text, options);
497
+ return this.cache[text] = t;
498
+ }
499
+ });
500
+ })();
501
+
502
+ // Export the hogan constructor for Node.js and CommonJS.
503
+ if (typeof module !== 'undefined' && module.exports) {
504
+ module.exports = Hogan;
505
+ module.exports.Template = HoganTemplate;
506
+ } else if (typeof exports !== 'undefined') {
507
+ exports.Hogan = Hogan;
508
+ exports.HoganTemplate = HoganTemplate;
509
+ }