poirot 0.0.3 → 0.1.0

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.
@@ -2,13 +2,27 @@ module Poirot
2
2
  module AssetHelper
3
3
  def template_include_tag(*sources)
4
4
  sources.collect do |source|
5
- template = File.open(_poirot_resolve_partial_path(source), "rb")
6
- content_tag :script, template.read.html_safe, :type => "text/mustache", :id => "#{source.parameterize.dasherize}-template"
5
+ template = File.open(resolve_partial_path(source), "rb")
6
+ content_tag :script, template.read.html_safe, :type => "text/mustache", :id => "#{template_name(source).parameterize.dasherize}-template"
7
7
  end.join("\n").html_safe
8
8
  end
9
-
10
- def _poirot_resolve_partial_path(source)
11
- if source.to_s =~ /^\// # absolute path to a different view folder
9
+
10
+ private
11
+
12
+ def is_absolute_path?(source)
13
+ source.to_s =~ /^\//
14
+ end
15
+
16
+ def template_name(source)
17
+ if is_absolute_path?(source)
18
+ source.to_s.split('/').last
19
+ else
20
+ source
21
+ end
22
+ end
23
+
24
+ def resolve_partial_path(source)
25
+ if is_absolute_path?(source)
12
26
  segments = source.to_s.split('/')
13
27
  partial_name = "_#{segments.pop}.html.mustache"
14
28
  segments << partial_name
@@ -17,6 +31,5 @@ module Poirot
17
31
  Rails.root.join('app/views', controller_name, "_#{source}.html.mustache")
18
32
  end
19
33
  end
20
-
21
34
  end
22
35
  end
@@ -6,6 +6,7 @@ module Poirot
6
6
  view_class = begin
7
7
  view_path.classify.constantize
8
8
  rescue NameError => e
9
+ Rails.logger.info ">>> #{e}"
9
10
  Poirot::View
10
11
  end
11
12
  "#{view_class}.new(self, '#{template.source.gsub(/'/, "\\\\'")}').render.html_safe"
@@ -1,3 +1,3 @@
1
1
  module Poirot
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/poirot/view.rb CHANGED
@@ -3,18 +3,42 @@ module Poirot
3
3
 
4
4
  def initialize(view_context, template_source)
5
5
  @view_context = view_context
6
+ @params = view_context.params || {}
6
7
  self.template = template_source
7
8
  assign_variables!
8
9
  end
9
10
 
11
+ self.template_extension = 'html.mustache'
12
+
13
+ def self.inherited(view_class)
14
+ self.template_path = Rails.root.join('app', 'views', view_class.name.split('::').first.downcase)
15
+ end
16
+
10
17
  def respond_to?(method_sym, include_private = false)
11
- if view_context.respond_to?(method_sym)
18
+ if view_context.respond_to?(method_sym)
12
19
  true
13
20
  else
14
21
  super
15
22
  end
16
23
  end
17
24
 
25
+ def render_buffer(buffer)
26
+ self.render(buffer, context).html_safe
27
+ end
28
+
29
+ def include_partial(name)
30
+ path = ["app/views", controller_name]
31
+ path += name.split("/")
32
+ path.delete(nil)
33
+ path.last.replace("_#{path.last}.html.mustache")
34
+
35
+ filename = path.join("/")
36
+
37
+ Dir.chdir(Rails.root) do
38
+ render_buffer(File.read(filename))
39
+ end
40
+ end
41
+
18
42
  def method_missing(method_name, *args, &block)
19
43
  instance_var = instance_variable_get("@#{method_name}")
20
44
  if defined?(instance_var) && args.empty?
@@ -27,6 +51,7 @@ module Poirot
27
51
  private
28
52
 
29
53
  attr_reader :view_context
54
+ attr_reader :params
30
55
 
31
56
  def assign_variables!
32
57
  variables = view_context.instance_variable_names.select{|name| name =~ /^@[^_]/}
@@ -36,12 +61,14 @@ module Poirot
36
61
  self[name.tr('@','').to_sym] = instance_var
37
62
  end
38
63
 
39
- # get the locals from the view context, is there a better way?
40
- locals = view_context.send(:view_renderer).send(:_partial_renderer).instance_variable_get("@locals") || {}
64
+ if Rails.version >= "3.1"
65
+ # get the locals from the view context, is there a better way?
66
+ locals = view_context.send(:view_renderer).send(:_partial_renderer).instance_variable_get("@locals") || {}
41
67
 
42
- locals.each do |name, val|
43
- instance_variable_set("@#{name}", val)
44
- self[name] = val
68
+ locals.each do |name, val|
69
+ instance_variable_set("@#{name}", val)
70
+ self[name] = val
71
+ end
45
72
  end
46
73
  end
47
74
  end
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  var Mustache = function() {
8
+ var regexCache = {};
8
9
  var Renderer = function() {};
9
10
 
10
11
  Renderer.prototype = {
@@ -34,13 +35,22 @@ var Mustache = function() {
34
35
  }
35
36
  }
36
37
 
38
+ // get the pragmas together
37
39
  template = this.render_pragmas(template);
40
+
41
+ // render the template
38
42
  var html = this.render_section(template, context, partials);
39
- if(in_recursion) {
40
- return this.render_tags(html, context, partials, in_recursion);
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);
41
47
  }
42
48
 
43
- this.render_tags(html, context, partials, in_recursion);
49
+ if (in_recursion) {
50
+ return html;
51
+ } else {
52
+ this.sendLines(html);
53
+ }
44
54
  },
45
55
 
46
56
  /*
@@ -52,6 +62,15 @@ var Mustache = function() {
52
62
  }
53
63
  },
54
64
 
65
+ sendLines: function(text) {
66
+ if (text) {
67
+ var lines = text.split("\n");
68
+ for (var i = 0; i < lines.length; i++) {
69
+ this.send(lines[i]);
70
+ }
71
+ }
72
+ },
73
+
55
74
  /*
56
75
  Looks for %PRAGMAS
57
76
  */
@@ -62,11 +81,13 @@ var Mustache = function() {
62
81
  }
63
82
 
64
83
  var that = this;
65
- var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
66
- this.ctag, "g");
84
+ var regex = this.getCachedRegex("render_pragmas", function(otag, ctag) {
85
+ return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
86
+ });
87
+
67
88
  return template.replace(regex, function(match, pragma, options) {
68
89
  if(!that.pragmas_implemented[pragma]) {
69
- throw({message:
90
+ throw({message:
70
91
  "This implementation of mustache doesn't understand the '" +
71
92
  pragma + "' pragma"});
72
93
  }
@@ -99,45 +120,74 @@ var Mustache = function() {
99
120
  */
100
121
  render_section: function(template, context, partials) {
101
122
  if(!this.includes("#", template) && !this.includes("^", template)) {
102
- return template;
123
+ // did not render anything, there were no sections
124
+ return false;
103
125
  }
104
126
 
105
127
  var that = this;
106
- // CSW - Added "+?" so it finds the tighest bound, not the widest
107
- var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
108
- "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
109
- "\\s*", "mg");
128
+
129
+ var regex = this.getCachedRegex("render_section", function(otag, ctag) {
130
+ // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
131
+ return new RegExp(
132
+ "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
133
+
134
+ otag + // {{
135
+ "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3)
136
+ ctag + // }}
137
+
138
+ "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped
139
+
140
+ otag + // {{
141
+ "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag).
142
+ ctag + // }}
143
+
144
+ "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped.
145
+
146
+ "g");
147
+ });
148
+
110
149
 
111
150
  // for each {{#foo}}{{/foo}} section do...
112
- return template.replace(regex, function(match, type, name, content) {
113
- var value = that.find(name, context);
114
- if(type == "^") { // inverted section
115
- if(!value || that.is_array(value) && value.length === 0) {
151
+ return template.replace(regex, function(match, before, type, name, content, after) {
152
+ // before contains only tags, no sections
153
+ var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",
154
+
155
+ // after may contain both sections and tags, so use full rendering function
156
+ renderedAfter = after ? that.render(after, context, partials, true) : "",
157
+
158
+ // will be computed below
159
+ renderedContent,
160
+
161
+ value = that.find(name, context);
162
+
163
+ if (type === "^") { // inverted section
164
+ if (!value || that.is_array(value) && value.length === 0) {
116
165
  // false or empty list, render it
117
- return that.render(content, context, partials, true);
166
+ renderedContent = that.render(content, context, partials, true);
118
167
  } else {
119
- return "";
168
+ renderedContent = "";
120
169
  }
121
- } else if(type == "#") { // normal section
122
- if(that.is_array(value)) { // Enumerable, Let's loop!
123
- return that.map(value, function(row) {
124
- return that.render(content, that.create_context(row),
125
- partials, true);
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);
126
174
  }).join("");
127
- } else if(that.is_object(value)) { // Object, Use it as subcontext!
128
- return that.render(content, that.create_context(value),
175
+ } else if (that.is_object(value)) { // Object, Use it as subcontext!
176
+ renderedContent = that.render(content, that.create_context(value),
129
177
  partials, true);
130
- } else if(typeof value === "function") {
178
+ } else if (typeof value === "function") {
131
179
  // higher order section
132
- return value.call(context, content, function(text) {
180
+ renderedContent = value.call(context, content, function(text) {
133
181
  return that.render(text, context, partials, true);
134
182
  });
135
- } else if(value) { // boolean section
136
- return that.render(content, context, partials, true);
183
+ } else if (value) { // boolean section
184
+ renderedContent = that.render(content, context, partials, true);
137
185
  } else {
138
- return "";
186
+ renderedContent = "";
139
187
  }
140
188
  }
189
+
190
+ return renderedBefore + renderedContent + renderedAfter;
141
191
  });
142
192
  },
143
193
 
@@ -148,9 +198,12 @@ var Mustache = function() {
148
198
  // tit for tat
149
199
  var that = this;
150
200
 
201
+
202
+
151
203
  var new_regex = function() {
152
- return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
153
- that.ctag + "+", "g");
204
+ return that.getCachedRegex("render_tags", function(otag, ctag) {
205
+ return new RegExp(otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + ctag + "+", "g");
206
+ });
154
207
  };
155
208
 
156
209
  var regex = new_regex();
@@ -216,10 +269,20 @@ var Mustache = function() {
216
269
  }
217
270
 
218
271
  var value;
219
- if(is_kinda_truthy(context[name])) {
220
- value = context[name];
221
- } else if(is_kinda_truthy(this.context[name])) {
222
- value = this.context[name];
272
+
273
+ // check for dot notation eg. foo.bar
274
+ if(name.match(/([a-z_]+)\./ig)){
275
+ var childValue = this.walk_context(name, context);
276
+ if(is_kinda_truthy(childValue)) {
277
+ value = childValue;
278
+ }
279
+ }
280
+ else{
281
+ if(is_kinda_truthy(context[name])) {
282
+ value = context[name];
283
+ } else if(is_kinda_truthy(this.context[name])) {
284
+ value = this.context[name];
285
+ }
223
286
  }
224
287
 
225
288
  if(typeof value === "function") {
@@ -232,6 +295,22 @@ var Mustache = function() {
232
295
  return "";
233
296
  },
234
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
+
235
314
  // Utility methods
236
315
 
237
316
  /* includes tag */
@@ -247,7 +326,6 @@ var Mustache = function() {
247
326
  return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
248
327
  switch(s) {
249
328
  case "&": return "&amp;";
250
- case "\\": return "\\\\";
251
329
  case '"': return '&quot;';
252
330
  case "'": return '&#39;';
253
331
  case "<": return "&lt;";
@@ -301,12 +379,31 @@ var Mustache = function() {
301
379
  }
302
380
  return r;
303
381
  }
382
+ },
383
+
384
+ getCachedRegex: function(name, generator) {
385
+ var byOtag = regexCache[this.otag];
386
+ if (!byOtag) {
387
+ byOtag = regexCache[this.otag] = {};
388
+ }
389
+
390
+ var byCtag = byOtag[this.ctag];
391
+ if (!byCtag) {
392
+ byCtag = byOtag[this.ctag] = {};
393
+ }
394
+
395
+ var regex = byCtag[name];
396
+ if (!regex) {
397
+ regex = byCtag[name] = generator(this.otag, this.ctag);
398
+ }
399
+
400
+ return regex;
304
401
  }
305
402
  };
306
403
 
307
404
  return({
308
405
  name: "mustache.js",
309
- version: "0.3.1-dev",
406
+ version: "0.4.0-dev",
310
407
 
311
408
  /*
312
409
  Turns a template and view into HTML
@@ -316,7 +413,7 @@ var Mustache = function() {
316
413
  if(send_fun) {
317
414
  renderer.send = send_fun;
318
415
  }
319
- renderer.render(template, view, partials);
416
+ renderer.render(template, view || {}, partials);
320
417
  if(!send_fun) {
321
418
  return renderer.buffer.join("\n");
322
419
  }
@@ -1,7 +1,14 @@
1
1
  var poirot = (function ($) {
2
2
 
3
+ var viewFactory = function (template, partials) {
4
+ return function (data) {
5
+ return $(Mustache.to_html(template, data, partials))
6
+ }
7
+ }
8
+
3
9
  var poirot = {
4
- partials: {}
10
+ partials: {},
11
+ _viewFactory: viewFactory
5
12
  }
6
13
 
7
14
  $(document).ready(function () {
@@ -13,9 +20,7 @@ var poirot = (function ($) {
13
20
 
14
21
  poirot.partials[methodName] = template
15
22
 
16
- poirot[methodName] = function (presenter) {
17
- return $(Mustache.to_html(template, presenter, poirot.partials))
18
- }
23
+ poirot[methodName] = poirot._viewFactory(template, poirot.partials)
19
24
  })
20
25
  })
21
26
 
metadata CHANGED
@@ -1,57 +1,46 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: poirot
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 3
9
- version: 0.0.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Oliver Nightingale
13
9
  - Mark Evans
14
10
  autorequire:
15
11
  bindir: bin
16
12
  cert_chain: []
17
-
18
- date: 2011-08-15 00:00:00 +01:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2012-01-04 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: rails
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- requirements:
26
- - - ">"
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 3
30
- version: "3"
17
+ requirement: &70170133189960 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>'
21
+ - !ruby/object:Gem::Version
22
+ version: '3'
31
23
  type: :runtime
32
- version_requirements: *id001
33
- - !ruby/object:Gem::Dependency
34
- name: mustache
35
24
  prerelease: false
36
- requirement: &id002 !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- segments:
41
- - 0
42
- version: "0"
25
+ version_requirements: *70170133189960
26
+ - !ruby/object:Gem::Dependency
27
+ name: mustache
28
+ requirement: &70170133189380 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
43
34
  type: :runtime
44
- version_requirements: *id002
35
+ prerelease: false
36
+ version_requirements: *70170133189380
45
37
  description: mustaches are cool
46
- email:
38
+ email:
47
39
  - oliver.nightingale1@gmail.com
48
40
  executables: []
49
-
50
41
  extensions: []
51
-
52
42
  extra_rdoc_files: []
53
-
54
- files:
43
+ files:
55
44
  - .gitignore
56
45
  - Gemfile
57
46
  - Gemfile.lock
@@ -67,35 +56,28 @@ files:
67
56
  - vendor/assets/javascripts/poirot/index.js
68
57
  - vendor/assets/javascripts/poirot/mustache.js
69
58
  - vendor/assets/javascripts/poirot/poirot.js
70
- has_rdoc: true
71
59
  homepage: http://rubygems.org/gems/poirot
72
60
  licenses: []
73
-
74
61
  post_install_message:
75
62
  rdoc_options: []
76
-
77
- require_paths:
63
+ require_paths:
78
64
  - lib
79
- required_ruby_version: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- segments:
84
- - 0
85
- version: "0"
86
- required_rubygems_version: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- segments:
91
- - 0
92
- version: "0"
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
93
77
  requirements: []
94
-
95
78
  rubyforge_project: poirot
96
- rubygems_version: 1.3.6
79
+ rubygems_version: 1.8.11
97
80
  signing_key:
98
81
  specification_version: 3
99
82
  summary: mustaches
100
83
  test_files: []
101
-