liquid_assets 0.1.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/liquid_assets.rb CHANGED
@@ -1,13 +1,16 @@
1
1
  require 'liquid_assets/version'
2
+ require 'liquid_assets/eval'
2
3
  require 'liquid_assets/config'
3
4
  require 'liquid_assets/template_handler'
4
- require 'liquid_assets/tilt_engine'
5
+
6
+ require 'liquid_assets/resolver'
7
+
5
8
  module LiquidAssets
6
9
 
7
10
  extend Config
8
11
 
9
12
  autoload :TinyLiquid, 'liquid_assets/tiny_liquid'
10
- autoload :TiltEngine, 'liquid_assets/tilt_engine'
13
+ autoload :PipelineTemplateEngine, 'liquid_assets/pipeline_template_engine'
11
14
 
12
15
  if defined? Rails
13
16
  require 'liquid_assets/engine'
@@ -1,76 +1,28 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'liquid_assets/version'
5
5
 
6
- Gem::Specification.new do |s|
7
- s.name = "liquid_assets"
8
- s.version = "0.1.0"
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "liquid_assets"
8
+ spec.version = LiquidAssets::VERSION
9
+ spec.authors = ["Nathan Stitt"]
10
+ spec.email = ["nathan@stitt.org"]
11
+ spec.description = %q{A rails engine that supports writing both server and client side templates in Liqud markup}
12
+ spec.summary = %q{Liquid formmated views and assets}
13
+ spec.homepage = "http://github.com/nathanstitt/liquid_assets"
14
+ spec.license = "MIT"
9
15
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Nathan Stitt"]
12
- s.date = "2013-03-14"
13
- s.description = "Allows you to use Liquid format templates in Rails, both as\nview templates and as compiled JavaScript via the asset_pipeline."
14
- s.email = "nathan@stitt.org"
15
- s.extra_rdoc_files = [
16
- "LICENSE.txt",
17
- "README.md"
18
- ]
19
- s.files = [
20
- ".document",
21
- "Gemfile",
22
- "Gemfile.lock",
23
- "LICENSE.txt",
24
- "README.md",
25
- "Rakefile",
26
- "VERSION",
27
- "lib/liquid_assets.rb",
28
- "lib/liquid_assets/config.rb",
29
- "lib/liquid_assets/engine.rb",
30
- "lib/liquid_assets/template_handler.rb",
31
- "lib/liquid_assets/tilt_engine.rb",
32
- "lib/liquid_assets/tiny_liquid.rb",
33
- "lib/liquid_assets/version.rb",
34
- "liquid_assets.gemspec",
35
- "test/helper.rb",
36
- "test/test_liquid_assets.rb",
37
- "vendor/assets/javascripts/liquid_assets.js",
38
- "vendor/tinyliquid.js"
39
- ]
40
- s.homepage = "http://github.com/nathanstitt/liquid_assets"
41
- s.licenses = ["MIT"]
42
- s.require_paths = ["lib"]
43
- s.rubygems_version = "1.8.23"
44
- s.summary = "Liquid formmated views and assets"
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
45
20
 
46
- if s.respond_to? :specification_version then
47
- s.specification_version = 3
21
+ spec.add_dependency 'liquid'
22
+ spec.add_dependency 'tilt'
23
+ spec.add_dependency 'execjs'
24
+ spec.add_dependency 'actionpack', '>=3.2'
48
25
 
49
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
- s.add_runtime_dependency(%q<liquid>, [">= 0"])
51
- s.add_runtime_dependency(%q<tilt>, [">= 0"])
52
- s.add_runtime_dependency(%q<sprockets>, [">= 0"])
53
- s.add_runtime_dependency(%q<execjs>, [">= 0"])
54
- s.add_development_dependency(%q<rdoc>, [">= 0"])
55
- s.add_development_dependency(%q<bundler>, [">= 0"])
56
- s.add_development_dependency(%q<jeweler>, [">= 0"])
57
- else
58
- s.add_dependency(%q<liquid>, [">= 0"])
59
- s.add_dependency(%q<tilt>, [">= 0"])
60
- s.add_dependency(%q<sprockets>, [">= 0"])
61
- s.add_dependency(%q<execjs>, [">= 0"])
62
- s.add_dependency(%q<rdoc>, [">= 0"])
63
- s.add_dependency(%q<bundler>, [">= 0"])
64
- s.add_dependency(%q<jeweler>, [">= 0"])
65
- end
66
- else
67
- s.add_dependency(%q<liquid>, [">= 0"])
68
- s.add_dependency(%q<tilt>, [">= 0"])
69
- s.add_dependency(%q<sprockets>, [">= 0"])
70
- s.add_dependency(%q<execjs>, [">= 0"])
71
- s.add_dependency(%q<rdoc>, [">= 0"])
72
- s.add_dependency(%q<bundler>, [">= 0"])
73
- s.add_dependency(%q<jeweler>, [">= 0"])
74
- end
26
+ spec.add_development_dependency "bundler", "~> 1.3"
27
+ spec.add_development_dependency "rake"
75
28
  end
76
-
data/test/helper.rb CHANGED
@@ -15,7 +15,7 @@ require 'liquid_assets'
15
15
 
16
16
  module LiquidAssets::Config
17
17
  def reset!
18
- %w(env path_prefix template_namespace filters ).each do |option|
18
+ %w(env path_prefix namespace filters ).each do |option|
19
19
  send "#{option}=", nil
20
20
  end
21
21
  end
@@ -9,18 +9,17 @@ class TestLiquidAssets < Test::Unit::TestCase
9
9
  end
10
10
 
11
11
  def test_mime_type
12
- assert_equal 'application/javascript', LiquidAssets::TiltEngine.default_mime_type
12
+ assert_equal 'application/javascript', LiquidAssets::PipelineTemplateEngine.default_mime_type
13
13
  end
14
14
 
15
15
  def test_tilt_engine_rendering
16
16
  scope = make_scope '/myapp/app/assets/javascripts', 'path/to/template.mustache'
17
17
 
18
- template = LiquidAssets::TiltEngine.new(scope.s_path) { "This is {{me}}" }
18
+ template = LiquidAssets::PipelineTemplateEngine.new(scope.s_path) { "This is {{me}}" }
19
+
20
+ tmpl="LQT.Templates[\"path/to/template\"] = function(locals,filters){\n var $_tmpbuf, $_html = LQT._FNS.html, $_err = LQT._FNS.err,\n $_rethrow=LQT._FNS.rethrow, $_merge=LQT._FNS.merge,\n $_range=LQT._FNS.range, $_array=LQT._FNS.array;\n /* == Template Begin == */\nvar $_buf = '';\nvar $_line_num = 0;\n/* == define cycles == */\nvar $_cycle_next = function (n) {\nn.i++;\nif (n.i >= n.length) n.i = 0;\n}\n$_buf+=('This is ');\n$_line_num = 1;\n$_tmpbuf = locals.me;\n$_buf+=($_tmpbuf===null||typeof($_tmpbuf)===\"undefined\"?\"\":$_tmpbuf);\n return $_buf;\n }\n;"
21
+ assert_equal tmpl, template.render(scope, {})
19
22
 
20
- assert_equal <<-END_EXPECTED, template.render(scope, {})
21
- this.LQT || (this.LQT = {});
22
- this.LQT[\"path/to/template\"] = function(locals,filters){\nvar $_tmpbuf, $_html = LQT._FNS.html, $_err = LQT._FNS.err, $_rethrow=LQT._FNS.rethrow, $_merge=LQT._FNS.merge, $_range=LQT._FNS.range, $_array=LQT._FNS.array;\n/* == Template Begin == */\nvar $_buf = '';\nvar $_line_num = 0;\n/* == define cycles == */\nvar $_cycle_next = function (n) {\nn.i++;\nif (n.i >= n.length) n.i = 0;\n}\n$_buf+=('This is ');\n$_line_num = 1;\n$_tmpbuf = locals.me;\n$_buf+=($_tmpbuf===null||typeof($_tmpbuf)===\"undefined\"?\"\":$_tmpbuf);\nreturn $_buf;\n};
23
- END_EXPECTED
24
23
  end
25
24
 
26
25
  def test_template_rendering
@@ -30,4 +29,48 @@ class TestLiquidAssets < Test::Unit::TestCase
30
29
  assert_equal 'foo=bar', template
31
30
  end
32
31
 
32
+
33
+ def test_resolver
34
+ LiquidAssets::Config.content_provider = lambda do | path |
35
+ 'good' == path ? 'Hello {{bob|upcase}}' : false
36
+ end
37
+
38
+ details = {:formats=>[:liquid], :locale=>[:en], :handlers=>[] }
39
+ resolver = LiquidAssets::Resolver.instance
40
+
41
+ assert_empty resolver.find_all('bad','',false, details )
42
+ assert_not_empty resolver.find_all('good','',false, details )
43
+ end
44
+
45
+ def test_resolver_caches
46
+ times_called = 0
47
+ LiquidAssets::Config.content_provider = lambda do | path |
48
+ times_called += 1
49
+ 'foo/bar/good' == path ? 'Hello {{bob|upcase}}' : false
50
+ end
51
+
52
+ details = {:formats=>[:liquid], :locale=>[:en], :handlers=>[] }
53
+ resolver = LiquidAssets::Resolver.instance
54
+ key = 'dumb-key'
55
+ (0...3).each do
56
+ resolver.find_all('foo/bar/good',nil ,false, details, key )
57
+ end
58
+ assert_equal 1, times_called
59
+
60
+ times_called = 0
61
+
62
+ resolver.clear_cache_for( 'bad' ) # shouldn't clear cache for 'good'
63
+
64
+ resolver.find_all('foo/bar/good',nil,false, details, key )
65
+
66
+ assert_equal 0, times_called
67
+
68
+ resolver.clear_cache_for( 'foo/bar/good' )
69
+
70
+ resolver.find_all('foo/bar/good',nil,false, details, key )
71
+
72
+ assert_equal 1, times_called
73
+
74
+
75
+ end
33
76
  end
@@ -0,0 +1,228 @@
1
+ (function( namespace, document, undefined) {
2
+
3
+ namespace = namespace.<%= LiquidAssets::Config.namespace%> || (namespace.<%=LiquidAssets::Config.namespace%>={});
4
+ namespace.Templates || ( namespace.Templates={} );
5
+
6
+ namespace.Globals || ( namespace.Globals = {} );
7
+ var server_globals = <%= LiquidAssets::Config.globals.to_json.html_safe %>;
8
+ for ( var key in server_globals ){
9
+ namespace.Globals[ key ] = server_globals[key];
10
+ }
11
+
12
+ namespace.Render = function( name, data ){
13
+ if (data == null) {
14
+ data = {};
15
+ }
16
+ for ( var key in namespace.Globals )
17
+ if (! data.hasOwnProperty(key) )
18
+ data[key] = namespace.Globals[key];
19
+
20
+ return namespace.Templates[name]( data, namespace.Filters );
21
+ };
22
+
23
+ namespace.RenderPartial = function( name, data ){
24
+ var path, parts = name.split('/');
25
+ if ( parts.length > 1 )
26
+ path = parts.slice( 0, parts.length-1) +'/_'+parts[ parts.length-1 ];
27
+ else
28
+ path = '_' + parts[ parts.length-1 ];
29
+ return namespace.Render( path, data );
30
+ };
31
+
32
+ namespace._FNS = {
33
+ html: function (html) {
34
+ return html.replace(/\\/g, '\\\\')
35
+ .replace(/'/g, '\\\'')
36
+ .replace(/"/g, '\\\"')
37
+ .replace(/\r/g, '\\r')
38
+ .replace(/\n/g, '\\n');
39
+ },
40
+ err: function (msg) {
41
+ var html = '<pre style="font-family:Courier; font-weight:bold; \
42
+ font-size:14px; color:red; padding:4px 20px 4px 20px; border:1px solid #CCC; \
43
+ background-color:#FFF5F0; line-height:1.6em; white-space:pre-wrap; \
44
+ white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; \
45
+ word-wrap:break-word; z-index:9999">' + msg + '</pre>';
46
+ return html;
47
+ },
48
+ rethrow: function (err, filename) {
49
+ var msg = 'An error occurred while rendering\n' +
50
+ 'Line: ' + $_line_num + (filename ? ' File: ' + filename : '') +
51
+ '\n ' + err;
52
+ $_buf += $_err(msg);
53
+ },
54
+ merge: function () {
55
+ var ret = {};
56
+ for (var i in arguments) {
57
+ var obj = arguments[i];
58
+ for (var j in obj) {
59
+ ret[j] = obj[j];
60
+ }
61
+ }
62
+ return ret;
63
+ },
64
+ range: function (s, e) {
65
+ s = parseInt(s);
66
+ e = parseInt(e);
67
+ var r = [];
68
+ if (isNaN(s) || isNaN(e)) return r;
69
+ for (; s <= e; s++) {
70
+ r.push(s);
71
+ }
72
+ return r;
73
+ },
74
+ 'array': function (data) {
75
+ if (Array.isArray(data)) return data;
76
+ var ret = [];
77
+ for (var i in data) {
78
+ if (i !== 'size') {
79
+ ret.push(data[i]);
80
+ }
81
+ }
82
+ return ret;
83
+ }
84
+ };
85
+
86
+ var toNumber = function(input) {
87
+ return Number(input);
88
+ };
89
+
90
+ var toString = function(input) {
91
+ if (!input) {
92
+ return '';
93
+ }
94
+ if (_.isString(input)) {
95
+ return input;
96
+ } else if (typeof input.toString === "function") {
97
+ return input.toString();
98
+ } else {
99
+ return Object.prototype.toString.call(input);
100
+ }
101
+ };
102
+
103
+ namespace.Filters = {
104
+ size: function(input) {
105
+ return input.length;
106
+ },
107
+ downcase: function(input) {
108
+ return toString(input).toLowerCase();
109
+ },
110
+ upcase: function(input) {
111
+ return toString(input).toUpperCase();
112
+ },
113
+ append: function(input, other) {
114
+ return [toString(input), toString(other)].join();
115
+ },
116
+ prepend: function(input, other) {
117
+ return [toString(other), toString(input)].join();
118
+ },
119
+ empty: function(input) {
120
+ if (!input) {
121
+ return true;
122
+ }
123
+ if (input.length == null) {
124
+ return false;
125
+ }
126
+ return true;
127
+ },
128
+ truncate: function(input, length, truncateString) {
129
+ var l;
130
+
131
+ if (length == null) {
132
+ length = 50;
133
+ }
134
+ if (truncateString == null) {
135
+ truncateString = '...';
136
+ }
137
+ input = toString(input);
138
+ truncateString = toString(truncateString);
139
+ if (input == null) {
140
+ return '';
141
+ }
142
+ if (!input.slice) {
143
+ return '';
144
+ }
145
+ length = toNumber(length);
146
+ l = length - truncateString.length;
147
+ if (l < 0) {
148
+ l = 0;
149
+ }
150
+ if (input.length > length) {
151
+ return input.slice(0, +l + 1 || 9e9) + truncateString;
152
+ } else {
153
+ return input;
154
+ }
155
+ },
156
+ truncatewords: function(input, words, truncateString) {
157
+ var l, wordlist;
158
+
159
+ if (words == null) {
160
+ words = 15;
161
+ }
162
+ if (truncateString == null) {
163
+ truncateString = '...';
164
+ }
165
+ input = toString(input);
166
+ if (input == null) {
167
+ return '';
168
+ }
169
+ if (!input.slice) {
170
+ return '';
171
+ }
172
+ wordlist = input.split(" ");
173
+ words = toNumber(words);
174
+ l = words - 1;
175
+ if (l < 0) {
176
+ l = 0;
177
+ }
178
+ if (wordlist.length > l) {
179
+ return wordlist.slice(0, +l + 1 || 9e9).join(" ") + truncateString;
180
+ } else {
181
+ return input;
182
+ }
183
+ },
184
+ split: function(input, pattern) {
185
+ input = toString(input);
186
+ if (!input) {
187
+ return null;
188
+ }
189
+ return input.split(pattern);
190
+ },
191
+ join: function(input, glue) {
192
+ if (glue == null) {
193
+ glue = ' ';
194
+ }
195
+ return _(input).flatten().join(glue);
196
+ },
197
+ first: function(array) {
198
+ if (array.length > 0) {
199
+ return array[0];
200
+ } else {
201
+ return null;
202
+ }
203
+ },
204
+ last: function(array) {
205
+ if (array.length > 0) {
206
+ return array[array.length - 1];
207
+ } else {
208
+ return null;
209
+ }
210
+ },
211
+ plus: function(input, operand) {
212
+ return toNumber(input) + toNumber(operand);
213
+ },
214
+ minus: function(input, operand) {
215
+ return toNumber(input) - toNumber(operand);
216
+ },
217
+ times: function(input, operand) {
218
+ return toNumber(input) * toNumber(operand);
219
+ },
220
+ dividedBy: function(input, operand) {
221
+ return toNumber(input) / toNumber(operand);
222
+ },
223
+ modulo: function(input, operand) {
224
+ return toNumber(input) % toNumber(operand);
225
+ }
226
+ };
227
+
228
+ }(window, document));
data/vendor/tinyliquid.js CHANGED
@@ -2139,11 +2139,14 @@ exports.tags = function (text, start, context) {
2139
2139
  setLineNumber();
2140
2140
  var include_parts = inc_tag.name.split('/');
2141
2141
  include_parts[ include_parts.length-1] = '_' + include_parts[ include_parts.length - 1 ];
2142
- var partial_function = context.partials_namespace + '[\'' + include_parts.join('/') + '\']';
2143
- script += 'if ( ' + partial_function + '){' +
2144
- ' $_buf+=' + partial_function + '(' + (inc_tag.with ? inc_tag.with : 'locals') + ',filters);' +
2145
- '} else {' +
2146
- ' $_buf+=\'No such template ' + include_parts.join('/') + '\';' +
2142
+ var partial_function = context.namespace + '.Templates[\'' + include_parts.join('/') + '\']';
2143
+ script += 'if ( ' + partial_function + '){';
2144
+ if ( inc_tag.with )
2145
+ script+=' $_buf+=' + partial_function + '({\'' + inc_tag.with + '\': locals.' + (inc_tag.with) + '},filters);';
2146
+ else
2147
+ script+=' $_buf+=' + partial_function + '(locals,filters);';
2148
+ script+='} else {' +
2149
+ ' $_buf+=\'Partial not found: ' + include_parts.join('/') + '\';' +
2147
2150
  '}';
2148
2151
  // script += '/* === include "' + inc_tag.name + '"' +
2149
2152
  // (inc_tag.with ? ' with "' + inc_tag.with + '"' : '') +
@@ -2224,7 +2227,7 @@ exports.parse = function (text, options) {
2224
2227
  };
2225
2228
 
2226
2229
  // 初始化编译环境
2227
- context.partials_namespace = options.partials_namespace;
2230
+ context.namespace = options.namespace;
2228
2231
  context.customTags = options.tags; // 自定义的标记解析
2229
2232
  context.loop = 0; // { 嵌套层数
2230
2233
  context.loopName = []; // 当前嵌套标记名称