mustache-trimmer-rails 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Joshua Peek
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ Mustache Trimmer Rails
2
+ ======================
3
+
4
+ Josh Peek’s [Mustache Trimmer](https://github.com/josh/mustache-trimmer)
5
+ packaged for the Rails asset pipeline.
6
+
7
+ Installation
8
+ ------------
9
+
10
+ gem install mustache-trimmer-rails
11
+
12
+ License
13
+ -------
14
+
15
+ Copyright (c) 2012 Joshua Peek.
16
+
17
+ Released under the MIT license. See `LICENSE` for details.
@@ -0,0 +1,27 @@
1
+ require 'mustache/js'
2
+ require 'sprockets'
3
+ require 'tilt'
4
+
5
+ module Sprockets
6
+ class MustacheJsTemplate < ::Tilt::Template
7
+ self.default_mime_type = 'application/javascript'
8
+
9
+ def self.engine_initialized?
10
+ defined? ::Mustache.to_javascript
11
+ end
12
+
13
+ def initialize_engine
14
+ require_template_library 'mustache/js'
15
+ end
16
+
17
+ def prepare
18
+ end
19
+
20
+ def evaluate(scope, locals, &block)
21
+ Mustache.to_javascript(data)
22
+ end
23
+ end
24
+ end
25
+
26
+ Sprockets::Engines
27
+ Sprockets.register_engine '.mustachejs', Sprockets::MustacheJsTemplate
@@ -0,0 +1,331 @@
1
+ require 'mustache'
2
+
3
+ class Mustache
4
+ class JavascriptGenerator
5
+ def initialize
6
+ @n = 0
7
+ @globals = []
8
+ @locals = []
9
+ @helpers = {}
10
+ @partials = {}
11
+ end
12
+
13
+ def helpers
14
+ out = ""
15
+
16
+ if @helpers[:fetch]
17
+ global :fetch
18
+ out << <<-JS
19
+ fetch = function fetch(stack, key) {
20
+ var i, v;
21
+ for (i = stack.length - 1; i >= 0; i -= 1) {
22
+ v = stack[i][key];
23
+ if (v) {
24
+ return v;
25
+ }
26
+ }
27
+ };
28
+ JS
29
+ end
30
+
31
+ if @helpers[:escape]
32
+ global :escape
33
+ out << <<-JS
34
+ escape = function escape(value) {
35
+ return ('' + value)
36
+ .replace(/&/g, '&amp;')
37
+ .replace(/</g, '&lt;')
38
+ .replace(/>/g, '&gt;')
39
+ .replace(/\x22/g, '&quot;');
40
+ };
41
+ JS
42
+ end
43
+
44
+ if @helpers[:isEmpty]
45
+ @helpers[:isArray] = @helpers[:isObject] = true
46
+ global :isEmpty
47
+ out << <<-JS
48
+ isEmpty = function isEmpty(obj) {
49
+ var key;
50
+
51
+ if (!obj) {
52
+ return true;
53
+ } else if (isArray(obj)) {
54
+ return obj.length === 0;
55
+ } else if (isObject(obj)) {
56
+ for (key in obj) {
57
+ if (obj.hasOwnProperty(key)) {
58
+ return false;
59
+ }
60
+ }
61
+ return true;
62
+ } else {
63
+ return false;
64
+ }
65
+ };
66
+ JS
67
+ end
68
+
69
+ if @helpers[:isArray]
70
+ global :isArray
71
+ out << <<-JS
72
+ isArray = Array.isArray || function (obj) {
73
+ return Object.prototype.toString.call(obj) === '[object Array]';
74
+ };
75
+ JS
76
+ end
77
+
78
+ if @helpers[:isObject]
79
+ global :isObject
80
+ out << <<-JS
81
+ isObject = function isObject(obj) {
82
+ return (obj && typeof obj === 'object');
83
+ };
84
+ JS
85
+ end
86
+
87
+ if @helpers[:isFunction]
88
+ global :isFunction
89
+ out << <<-JS
90
+ isFunction = function isFunction(obj) {
91
+ return !!(obj && obj.constructor && obj.call && obj.apply);
92
+ };
93
+ JS
94
+ end
95
+
96
+ if @helpers[:reduce]
97
+ global :reduce
98
+ out << <<-JS
99
+ reduce = Array.prototype.reduce || function (iterator, memo) {
100
+ var i;
101
+ for (i = 0; i < this.length; i++) {
102
+ memo = iterator(memo, this[i]);
103
+ }
104
+ return memo;
105
+ };
106
+ JS
107
+
108
+ global :traverse
109
+ out << <<-JS
110
+ traverse = function traverse(value, key) {
111
+ return value && value[key];
112
+ };
113
+ JS
114
+ end
115
+
116
+ out.gsub(" ", "")
117
+ end
118
+
119
+ def globals
120
+ if @globals.any?
121
+ "var #{@globals.join(', ')};\n"
122
+ else
123
+ ""
124
+ end
125
+ end
126
+
127
+ def locals
128
+ if @locals.last.any?
129
+ "var #{@locals.last.join(', ')};\n"
130
+ else
131
+ ""
132
+ end
133
+ end
134
+
135
+ def partials
136
+ @partials.values.join("\n")
137
+ end
138
+
139
+ def compile(exp)
140
+ main = global
141
+ body = global
142
+
143
+ compile_closure!(body, exp)
144
+
145
+ helpers = self.helpers
146
+
147
+ <<-JS.gsub(" ", "")
148
+ (function() {
149
+ #{globals.strip}
150
+ #{helpers.strip}
151
+ #{partials.strip}
152
+
153
+ #{main} = function #{main}(obj) {
154
+ var stack, out;
155
+ stack = [];
156
+ stack.push(obj);
157
+ out = [];
158
+ #{body}(stack, out);
159
+ return out.join("");
160
+ };
161
+
162
+ return #{main};
163
+ })()
164
+ JS
165
+ end
166
+
167
+ def compile!(exp)
168
+ case exp.first
169
+ when :multi
170
+ exp[1..-1].map { |e| compile!(e) }.join
171
+ when :static
172
+ str(exp[1])
173
+ when :mustache
174
+ send("on_#{exp[1]}", *exp[2..-1])
175
+ else
176
+ raise "Unhandled exp: #{exp.first}"
177
+ end
178
+ end
179
+
180
+ def on_section(name, content, raw, delims)
181
+ @helpers[:isEmpty] = true
182
+ @helpers[:isObject] = @helpers[:isArray] = @helpers[:isFunction] = true
183
+
184
+ f, v, i = global, local(:v), local(:i)
185
+
186
+ compile_closure!(f, content)
187
+
188
+ <<-JS
189
+ #{v} = #{compile!(name).strip};
190
+ if (!isEmpty(#{v})) {
191
+ if (isFunction(#{v})) {
192
+ out.push(#{v}.call(stack[stack.length - 1], function () {
193
+ var out = [];
194
+ #{f}(stack, out);
195
+ return out.join("");
196
+ }));
197
+ } else if (isArray(#{v})) {
198
+ for (#{i} = 0; #{i} < #{v}.length; #{i} += 1) {
199
+ stack.push(#{v}[#{i}]);
200
+ #{f}(stack, out);
201
+ stack.pop();
202
+ }
203
+ } else if (isObject(#{v})) {
204
+ stack.push(#{v});
205
+ #{f}(stack, out);
206
+ stack.pop();
207
+ } else {
208
+ #{f}(stack, out);
209
+ }
210
+ }
211
+ JS
212
+ end
213
+
214
+ def on_inverted_section(name, content, raw, _)
215
+ @helpers[:isEmpty] = true
216
+
217
+ f, v = global, local(:v)
218
+
219
+ compile_closure!(f, content)
220
+
221
+ <<-JS
222
+ #{v} = #{compile!(name).strip};
223
+ if (isEmpty(#{v})) {
224
+ #{f}(stack, out);
225
+ }
226
+ JS
227
+ end
228
+
229
+ def on_partial(name, indentation)
230
+ unless @partials[name]
231
+ @partials[name] = true # Stub for recursion
232
+
233
+ source = Mustache.partial(name).to_s.gsub(/^/, indentation)
234
+ template = Mustache.templateify(source)
235
+
236
+ compile_closure!(name, template.tokens)
237
+ end
238
+
239
+ "#{name}(stack, out);\n"
240
+ end
241
+
242
+ def compile_closure!(name, tokens)
243
+ @locals.push([])
244
+ code = compile!(tokens)
245
+ locals = self.locals
246
+ @locals.pop
247
+
248
+ @partials[name] = <<-JS
249
+ #{name} = function #{name}(stack, out) {
250
+ #{locals.strip}
251
+ #{code.strip}
252
+ };
253
+ JS
254
+
255
+ nil
256
+ end
257
+
258
+ def on_utag(name)
259
+ @helpers[:isFunction] = true
260
+ @helpers[:isEmpty] = true
261
+
262
+ v = local(:v)
263
+
264
+ <<-JS
265
+ #{v} = #{compile!(name).strip};
266
+ if (isFunction(#{v})) {
267
+ #{v} = #{v}.call(stack[stack.length - 1]);
268
+ }
269
+ if (!isEmpty(#{v})) {
270
+ out.push(#{v});
271
+ }
272
+ JS
273
+ end
274
+
275
+ def on_etag(name)
276
+ @helpers[:isFunction] = true
277
+ @helpers[:isEmpty] = @helpers[:escape] = true
278
+
279
+ v = local(:v)
280
+
281
+ <<-JS
282
+ #{v} = #{compile!(name).strip};
283
+ if (isFunction(#{v})) {
284
+ #{v} = #{v}.call(stack[stack.length - 1]);
285
+ }
286
+ if (!isEmpty(#{v})) {
287
+ out.push(escape(#{v}));
288
+ }
289
+ JS
290
+ end
291
+
292
+ def on_fetch(names)
293
+ @helpers[:fetch] = true
294
+
295
+ names = names.map { |n| n.to_s }
296
+
297
+ case names.length
298
+ when 0
299
+ "stack[stack.length-1]"
300
+ when 1
301
+ "fetch(stack, #{names.first.inspect})"
302
+ else
303
+ @helpers[:reduce] = true
304
+ initial, *rest = names
305
+ "reduce.call(#{rest.inspect}, traverse, fetch(stack, #{initial.inspect}))"
306
+ end
307
+ end
308
+
309
+ def str(s)
310
+ "out.push(#{s.inspect});\n"
311
+ end
312
+
313
+ def global(name = nil)
314
+ if name
315
+ @globals << name.to_sym
316
+ name
317
+ else
318
+ @n += 1
319
+ name = :"g#{@n}"
320
+ @globals << name
321
+ name
322
+ end
323
+ end
324
+
325
+ def local(name = nil)
326
+ raise "not in closure" unless @locals.last
327
+ @locals.last << name.to_sym
328
+ name
329
+ end
330
+ end
331
+ end
@@ -0,0 +1,9 @@
1
+ require 'mustache'
2
+ require 'mustache/javascript_generator'
3
+
4
+ class Mustache
5
+ def self.to_javascript(source)
6
+ template = templateify(source)
7
+ JavascriptGenerator.new.compile(template.tokens)
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mustache-trimmer-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joshua Peek
9
+ - Hugh Evans
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-10-09 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mustache
17
+ requirement: &70218250760820 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 0.99.4
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *70218250760820
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: &70218250760400 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *70218250760400
37
+ - !ruby/object:Gem::Dependency
38
+ name: therubyracer
39
+ requirement: &70218250759900 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *70218250759900
48
+ description: ! ' Ruby lib that compiles Mustache templates into pure Javascript
49
+
50
+ '
51
+ email: josh@joshpeek.com
52
+ executables: []
53
+ extensions: []
54
+ extra_rdoc_files: []
55
+ files:
56
+ - lib/mustache/javascript_generator.rb
57
+ - lib/mustache/js.rb
58
+ - lib/mustache-trimmer-rails.rb
59
+ - LICENSE
60
+ - README.md
61
+ homepage: https://github.com/icelab/mustache-trimmer-rails
62
+ licenses: []
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project: mustache-trimmer-rails
81
+ rubygems_version: 1.8.11
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Mustache JS compiler packaged for the Rails asset Pipeline
85
+ test_files: []
86
+ has_rdoc: