mustachejs-rails 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mustachejs-rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Simon COURTOIS
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # mustachejs-rails
2
+
3
+ Use mustache.js with Rails 3.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'mustachejs-rails'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install mustachejs-rails
18
+
19
+ ## Usage
20
+
21
+ Add the following line to your `app/assets/javascripts/application.js` file:
22
+
23
+ //= require mustache
24
+
25
+ That's it !
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,6 @@
1
+ module Mustachejs
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Mustachejs
2
+ module Rails
3
+ VERSION = "0.7.1"
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ require 'mustachejs/rails/version'
2
+ require 'mustachejs/rails/engine'
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mustachejs/rails/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "mustachejs-rails"
8
+ gem.version = Mustachejs::Rails::VERSION
9
+ gem.authors = ["Simon COURTOIS"]
10
+ gem.email = ["scourtois@cubyx.fr"]
11
+ gem.description = "This gem provides mustache.js for your Rails 3 application."
12
+ gem.summary = "Use mustache.js with Rails 3"
13
+ gem.homepage = "http://github.com/simonc/mustachejs-rails"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,626 @@
1
+ /*!
2
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
3
+ * http://github.com/janl/mustache.js
4
+ */
5
+
6
+ /*global define: false*/
7
+
8
+ var Mustache;
9
+
10
+ (function (exports) {
11
+ if (typeof module !== "undefined" && module.exports) {
12
+ module.exports = exports; // CommonJS
13
+ } else if (typeof define === "function") {
14
+ define(exports); // AMD
15
+ } else {
16
+ Mustache = exports; // <script>
17
+ }
18
+ }((function () {
19
+
20
+ var exports = {};
21
+
22
+ exports.name = "mustache.js";
23
+ exports.version = "0.7.1";
24
+ exports.tags = ["{{", "}}"];
25
+
26
+ exports.Scanner = Scanner;
27
+ exports.Context = Context;
28
+ exports.Writer = Writer;
29
+
30
+ var whiteRe = /\s*/;
31
+ var spaceRe = /\s+/;
32
+ var nonSpaceRe = /\S/;
33
+ var eqRe = /\s*=/;
34
+ var curlyRe = /\s*\}/;
35
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
36
+
37
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
38
+ // See https://github.com/janl/mustache.js/issues/189
39
+ function testRe(re, string) {
40
+ return RegExp.prototype.test.call(re, string);
41
+ }
42
+
43
+ function isWhitespace(string) {
44
+ return !testRe(nonSpaceRe, string);
45
+ }
46
+
47
+ var isArray = Array.isArray || function (obj) {
48
+ return Object.prototype.toString.call(obj) === "[object Array]";
49
+ };
50
+
51
+ function escapeRe(string) {
52
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
53
+ }
54
+
55
+ var entityMap = {
56
+ "&": "&amp;",
57
+ "<": "&lt;",
58
+ ">": "&gt;",
59
+ '"': '&quot;',
60
+ "'": '&#39;',
61
+ "/": '&#x2F;'
62
+ };
63
+
64
+ function escapeHtml(string) {
65
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
66
+ return entityMap[s];
67
+ });
68
+ }
69
+
70
+ // Export the escaping function so that the user may override it.
71
+ // See https://github.com/janl/mustache.js/issues/244
72
+ exports.escape = escapeHtml;
73
+
74
+ function Scanner(string) {
75
+ this.string = string;
76
+ this.tail = string;
77
+ this.pos = 0;
78
+ }
79
+
80
+ /**
81
+ * Returns `true` if the tail is empty (end of string).
82
+ */
83
+ Scanner.prototype.eos = function () {
84
+ return this.tail === "";
85
+ };
86
+
87
+ /**
88
+ * Tries to match the given regular expression at the current position.
89
+ * Returns the matched text if it can match, the empty string otherwise.
90
+ */
91
+ Scanner.prototype.scan = function (re) {
92
+ var match = this.tail.match(re);
93
+
94
+ if (match && match.index === 0) {
95
+ this.tail = this.tail.substring(match[0].length);
96
+ this.pos += match[0].length;
97
+ return match[0];
98
+ }
99
+
100
+ return "";
101
+ };
102
+
103
+ /**
104
+ * Skips all text until the given regular expression can be matched. Returns
105
+ * the skipped string, which is the entire tail if no match can be made.
106
+ */
107
+ Scanner.prototype.scanUntil = function (re) {
108
+ var match, pos = this.tail.search(re);
109
+
110
+ switch (pos) {
111
+ case -1:
112
+ match = this.tail;
113
+ this.pos += this.tail.length;
114
+ this.tail = "";
115
+ break;
116
+ case 0:
117
+ match = "";
118
+ break;
119
+ default:
120
+ match = this.tail.substring(0, pos);
121
+ this.tail = this.tail.substring(pos);
122
+ this.pos += pos;
123
+ }
124
+
125
+ return match;
126
+ };
127
+
128
+ function Context(view, parent) {
129
+ this.view = view;
130
+ this.parent = parent;
131
+ this.clearCache();
132
+ }
133
+
134
+ Context.make = function (view) {
135
+ return (view instanceof Context) ? view : new Context(view);
136
+ };
137
+
138
+ Context.prototype.clearCache = function () {
139
+ this._cache = {};
140
+ };
141
+
142
+ Context.prototype.push = function (view) {
143
+ return new Context(view, this);
144
+ };
145
+
146
+ Context.prototype.lookup = function (name) {
147
+ var value = this._cache[name];
148
+
149
+ if (!value) {
150
+ if (name === ".") {
151
+ value = this.view;
152
+ } else {
153
+ var context = this;
154
+
155
+ while (context) {
156
+ if (name.indexOf(".") > 0) {
157
+ var names = name.split("."), i = 0;
158
+
159
+ value = context.view;
160
+
161
+ while (value && i < names.length) {
162
+ value = value[names[i++]];
163
+ }
164
+ } else {
165
+ value = context.view[name];
166
+ }
167
+
168
+ if (value != null) {
169
+ break;
170
+ }
171
+
172
+ context = context.parent;
173
+ }
174
+ }
175
+
176
+ this._cache[name] = value;
177
+ }
178
+
179
+ if (typeof value === "function") {
180
+ value = value.call(this.view);
181
+ }
182
+
183
+ return value;
184
+ };
185
+
186
+ function Writer() {
187
+ this.clearCache();
188
+ }
189
+
190
+ Writer.prototype.clearCache = function () {
191
+ this._cache = {};
192
+ this._partialCache = {};
193
+ };
194
+
195
+ Writer.prototype.compile = function (template, tags) {
196
+ var fn = this._cache[template];
197
+
198
+ if (!fn) {
199
+ var tokens = exports.parse(template, tags);
200
+ fn = this._cache[template] = this.compileTokens(tokens, template);
201
+ }
202
+
203
+ return fn;
204
+ };
205
+
206
+ Writer.prototype.compilePartial = function (name, template, tags) {
207
+ var fn = this.compile(template, tags);
208
+ this._partialCache[name] = fn;
209
+ return fn;
210
+ };
211
+
212
+ Writer.prototype.compileTokens = function (tokens, template) {
213
+ var fn = compileTokens(tokens);
214
+ var self = this;
215
+
216
+ return function (view, partials) {
217
+ if (partials) {
218
+ if (typeof partials === "function") {
219
+ self._loadPartial = partials;
220
+ } else {
221
+ for (var name in partials) {
222
+ self.compilePartial(name, partials[name]);
223
+ }
224
+ }
225
+ }
226
+
227
+ return fn(self, Context.make(view), template);
228
+ };
229
+ };
230
+
231
+ Writer.prototype.render = function (template, view, partials) {
232
+ return this.compile(template)(view, partials);
233
+ };
234
+
235
+ Writer.prototype._section = function (name, context, text, callback) {
236
+ var value = context.lookup(name);
237
+
238
+ switch (typeof value) {
239
+ case "object":
240
+ if (isArray(value)) {
241
+ var buffer = "";
242
+
243
+ for (var i = 0, len = value.length; i < len; ++i) {
244
+ buffer += callback(this, context.push(value[i]));
245
+ }
246
+
247
+ return buffer;
248
+ }
249
+
250
+ return value ? callback(this, context.push(value)) : "";
251
+ case "function":
252
+ var self = this;
253
+ var scopedRender = function (template) {
254
+ return self.render(template, context);
255
+ };
256
+
257
+ var result = value.call(context.view, text, scopedRender);
258
+ return result != null ? result : "";
259
+ default:
260
+ if (value) {
261
+ return callback(this, context);
262
+ }
263
+ }
264
+
265
+ return "";
266
+ };
267
+
268
+ Writer.prototype._inverted = function (name, context, callback) {
269
+ var value = context.lookup(name);
270
+
271
+ // Use JavaScript's definition of falsy. Include empty arrays.
272
+ // See https://github.com/janl/mustache.js/issues/186
273
+ if (!value || (isArray(value) && value.length === 0)) {
274
+ return callback(this, context);
275
+ }
276
+
277
+ return "";
278
+ };
279
+
280
+ Writer.prototype._partial = function (name, context) {
281
+ if (!(name in this._partialCache) && this._loadPartial) {
282
+ this.compilePartial(name, this._loadPartial(name));
283
+ }
284
+
285
+ var fn = this._partialCache[name];
286
+
287
+ return fn ? fn(context) : "";
288
+ };
289
+
290
+ Writer.prototype._name = function (name, context) {
291
+ var value = context.lookup(name);
292
+
293
+ if (typeof value === "function") {
294
+ value = value.call(context.view);
295
+ }
296
+
297
+ return (value == null) ? "" : String(value);
298
+ };
299
+
300
+ Writer.prototype._escaped = function (name, context) {
301
+ return exports.escape(this._name(name, context));
302
+ };
303
+
304
+ /**
305
+ * Calculates the bounds of the section represented by the given `token` in
306
+ * the original template by drilling down into nested sections to find the
307
+ * last token that is part of that section. Returns an array of [start, end].
308
+ */
309
+ function sectionBounds(token) {
310
+ var start = token[3];
311
+ var end = start;
312
+
313
+ var tokens;
314
+ while ((tokens = token[4]) && tokens.length) {
315
+ token = tokens[tokens.length - 1];
316
+ end = token[3];
317
+ }
318
+
319
+ return [start, end];
320
+ }
321
+
322
+ /**
323
+ * Low-level function that compiles the given `tokens` into a function
324
+ * that accepts three arguments: a Writer, a Context, and the template.
325
+ */
326
+ function compileTokens(tokens) {
327
+ var subRenders = {};
328
+
329
+ function subRender(i, tokens, template) {
330
+ if (!subRenders[i]) {
331
+ var fn = compileTokens(tokens);
332
+ subRenders[i] = function (writer, context) {
333
+ return fn(writer, context, template);
334
+ };
335
+ }
336
+
337
+ return subRenders[i];
338
+ }
339
+
340
+ return function (writer, context, template) {
341
+ var buffer = "";
342
+ var token, sectionText;
343
+
344
+ for (var i = 0, len = tokens.length; i < len; ++i) {
345
+ token = tokens[i];
346
+
347
+ switch (token[0]) {
348
+ case "#":
349
+ sectionText = template.slice.apply(template, sectionBounds(token));
350
+ buffer += writer._section(token[1], context, sectionText, subRender(i, token[4], template));
351
+ break;
352
+ case "^":
353
+ buffer += writer._inverted(token[1], context, subRender(i, token[4], template));
354
+ break;
355
+ case ">":
356
+ buffer += writer._partial(token[1], context);
357
+ break;
358
+ case "&":
359
+ buffer += writer._name(token[1], context);
360
+ break;
361
+ case "name":
362
+ buffer += writer._escaped(token[1], context);
363
+ break;
364
+ case "text":
365
+ buffer += token[1];
366
+ break;
367
+ }
368
+ }
369
+
370
+ return buffer;
371
+ };
372
+ }
373
+
374
+ /**
375
+ * Forms the given array of `tokens` into a nested tree structure where
376
+ * tokens that represent a section have a fifth item: an array that contains
377
+ * all tokens in that section.
378
+ */
379
+ function nestTokens(tokens) {
380
+ var tree = [];
381
+ var collector = tree;
382
+ var sections = [];
383
+ var token, section;
384
+
385
+ for (var i = 0; i < tokens.length; ++i) {
386
+ token = tokens[i];
387
+
388
+ switch (token[0]) {
389
+ case "#":
390
+ case "^":
391
+ token[4] = [];
392
+ sections.push(token);
393
+ collector.push(token);
394
+ collector = token[4];
395
+ break;
396
+ case "/":
397
+ if (sections.length === 0) {
398
+ throw new Error("Unopened section: " + token[1]);
399
+ }
400
+
401
+ section = sections.pop();
402
+
403
+ if (section[1] !== token[1]) {
404
+ throw new Error("Unclosed section: " + section[1]);
405
+ }
406
+
407
+ if (sections.length > 0) {
408
+ collector = sections[sections.length - 1][4];
409
+ } else {
410
+ collector = tree;
411
+ }
412
+ break;
413
+ default:
414
+ collector.push(token);
415
+ }
416
+ }
417
+
418
+ // Make sure there were no open sections when we're done.
419
+ section = sections.pop();
420
+
421
+ if (section) {
422
+ throw new Error("Unclosed section: " + section[1]);
423
+ }
424
+
425
+ return tree;
426
+ }
427
+
428
+ /**
429
+ * Combines the values of consecutive text tokens in the given `tokens` array
430
+ * to a single token.
431
+ */
432
+ function squashTokens(tokens) {
433
+ var token, lastToken, squashedTokens = [];
434
+
435
+ for (var i = 0; i < tokens.length; ++i) {
436
+ token = tokens[i];
437
+
438
+ if (lastToken && lastToken[0] === "text" && token[0] === "text") {
439
+ lastToken[1] += token[1];
440
+ lastToken[3] = token[3];
441
+ } else {
442
+ lastToken = token;
443
+ squashedTokens.push(token);
444
+ }
445
+ }
446
+
447
+ return squashedTokens;
448
+ }
449
+
450
+ function escapeTags(tags) {
451
+ if (tags.length !== 2) {
452
+ throw new Error("Invalid tags: " + tags.join(" "));
453
+ }
454
+
455
+ return [
456
+ new RegExp(escapeRe(tags[0]) + "\\s*"),
457
+ new RegExp("\\s*" + escapeRe(tags[1]))
458
+ ];
459
+ }
460
+
461
+ /**
462
+ * Breaks up the given `template` string into a tree of token objects. If
463
+ * `tags` is given here it must be an array with two string values: the
464
+ * opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
465
+ * course, the default is to use mustaches (i.e. Mustache.tags).
466
+ */
467
+ exports.parse = function (template, tags) {
468
+ template = template || '';
469
+ tags = tags || exports.tags;
470
+
471
+ var tagRes = escapeTags(tags);
472
+ var scanner = new Scanner(template);
473
+
474
+ var tokens = [], // Buffer to hold the tokens
475
+ spaces = [], // Indices of whitespace tokens on the current line
476
+ hasTag = false, // Is there a {{tag}} on the current line?
477
+ nonSpace = false; // Is there a non-space char on the current line?
478
+
479
+ // Strips all whitespace tokens array for the current line
480
+ // if there was a {{#tag}} on it and otherwise only space.
481
+ function stripSpace() {
482
+ if (hasTag && !nonSpace) {
483
+ while (spaces.length) {
484
+ tokens.splice(spaces.pop(), 1);
485
+ }
486
+ } else {
487
+ spaces = [];
488
+ }
489
+
490
+ hasTag = false;
491
+ nonSpace = false;
492
+ }
493
+
494
+ var start, type, value, chr;
495
+
496
+ while (!scanner.eos()) {
497
+ start = scanner.pos;
498
+ value = scanner.scanUntil(tagRes[0]);
499
+
500
+ if (value) {
501
+ for (var i = 0, len = value.length; i < len; ++i) {
502
+ chr = value.charAt(i);
503
+
504
+ if (isWhitespace(chr)) {
505
+ spaces.push(tokens.length);
506
+ } else {
507
+ nonSpace = true;
508
+ }
509
+
510
+ tokens.push(["text", chr, start, start + 1]);
511
+ start += 1;
512
+
513
+ if (chr === "\n") {
514
+ stripSpace(); // Check for whitespace on the current line.
515
+ }
516
+ }
517
+ }
518
+
519
+ start = scanner.pos;
520
+
521
+ // Match the opening tag.
522
+ if (!scanner.scan(tagRes[0])) {
523
+ break;
524
+ }
525
+
526
+ hasTag = true;
527
+ type = scanner.scan(tagRe) || "name";
528
+
529
+ // Skip any whitespace between tag and value.
530
+ scanner.scan(whiteRe);
531
+
532
+ // Extract the tag value.
533
+ if (type === "=") {
534
+ value = scanner.scanUntil(eqRe);
535
+ scanner.scan(eqRe);
536
+ scanner.scanUntil(tagRes[1]);
537
+ } else if (type === "{") {
538
+ var closeRe = new RegExp("\\s*" + escapeRe("}" + tags[1]));
539
+ value = scanner.scanUntil(closeRe);
540
+ scanner.scan(curlyRe);
541
+ scanner.scanUntil(tagRes[1]);
542
+ type = "&";
543
+ } else {
544
+ value = scanner.scanUntil(tagRes[1]);
545
+ }
546
+
547
+ // Match the closing tag.
548
+ if (!scanner.scan(tagRes[1])) {
549
+ throw new Error("Unclosed tag at " + scanner.pos);
550
+ }
551
+
552
+ tokens.push([type, value, start, scanner.pos]);
553
+
554
+ if (type === "name" || type === "{" || type === "&") {
555
+ nonSpace = true;
556
+ }
557
+
558
+ // Set the tags for the next time around.
559
+ if (type === "=") {
560
+ tags = value.split(spaceRe);
561
+ tagRes = escapeTags(tags);
562
+ }
563
+ }
564
+
565
+ tokens = squashTokens(tokens);
566
+
567
+ return nestTokens(tokens);
568
+ };
569
+
570
+ // The high-level clearCache, compile, compilePartial, and render functions
571
+ // use this default writer.
572
+ var _writer = new Writer();
573
+
574
+ /**
575
+ * Clears all cached templates and partials in the default writer.
576
+ */
577
+ exports.clearCache = function () {
578
+ return _writer.clearCache();
579
+ };
580
+
581
+ /**
582
+ * Compiles the given `template` to a reusable function using the default
583
+ * writer.
584
+ */
585
+ exports.compile = function (template, tags) {
586
+ return _writer.compile(template, tags);
587
+ };
588
+
589
+ /**
590
+ * Compiles the partial with the given `name` and `template` to a reusable
591
+ * function using the default writer.
592
+ */
593
+ exports.compilePartial = function (name, template, tags) {
594
+ return _writer.compilePartial(name, template, tags);
595
+ };
596
+
597
+ /**
598
+ * Compiles the given array of tokens (the output of a parse) to a reusable
599
+ * function using the default writer.
600
+ */
601
+ exports.compileTokens = function (tokens, template) {
602
+ return _writer.compileTokens(tokens, template);
603
+ };
604
+
605
+ /**
606
+ * Renders the `template` with the given `view` and `partials` using the
607
+ * default writer.
608
+ */
609
+ exports.render = function (template, view, partials) {
610
+ return _writer.render(template, view, partials);
611
+ };
612
+
613
+ // This is here for backwards compatibility with 0.4.x.
614
+ exports.to_html = function (template, view, partials, send) {
615
+ var result = exports.render(template, view, partials);
616
+
617
+ if (typeof send === "function") {
618
+ send(result);
619
+ } else {
620
+ return result;
621
+ }
622
+ };
623
+
624
+ return exports;
625
+
626
+ }())));
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mustachejs-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Simon COURTOIS
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-15 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: This gem provides mustache.js for your Rails 3 application.
15
+ email:
16
+ - scourtois@cubyx.fr
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - lib/mustachejs-rails.rb
27
+ - lib/mustachejs/rails/engine.rb
28
+ - lib/mustachejs/rails/version.rb
29
+ - mustachejs-rails.gemspec
30
+ - vendor/assets/javascripts/mustache.js
31
+ homepage: http://github.com/simonc/mustachejs-rails
32
+ licenses: []
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ segments:
44
+ - 0
45
+ hash: -2278858652052863131
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ segments:
53
+ - 0
54
+ hash: -2278858652052863131
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.23
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: Use mustache.js with Rails 3
61
+ test_files: []