couch 0.1.1 → 0.1.2

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.
@@ -1,3 +1,3 @@
1
- [submodule "lib/couch/generators/application/templates/lib/mustache"]
2
- path = lib/couch/generators/application/templates/lib/mustache
1
+ [submodule "vendor/mustache.js"]
2
+ path = vendor/mustache.js
3
3
  url = git://github.com/janl/mustache.js.git
@@ -31,13 +31,13 @@ Building standalone CouchDB applications according to correct principles affords
31
31
  == What comes next
32
32
 
33
33
  At the moment, Couch supports generating a scaffold application, pushing to a CouchDB server and pulling from a CouchDB.
34
+ Couch injects the !code and !json makros introduced by CouchApp.
34
35
 
35
36
  The next big steps are:
36
37
 
37
- * support +code+ and +json+ makros to manage shared pieces of code
38
- * add the powerful mustache.js Template engine (http://github.com/janl/mustache.js)
39
- * add more code generators to rapidly get you started
40
-
38
+ * make use of mustache.js in generators
39
+ * build a lightweight JavaScript library to assist client side JavaScript work
40
+ * enhance generators to build a full flavored scaffold with all CRUD operations
41
41
 
42
42
  == I need your help!
43
43
 
data/Rakefile CHANGED
@@ -2,6 +2,25 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require File.join(File.dirname(__FILE__), 'lib', 'couch', 'version')
4
4
 
5
+ namespace :vendor do
6
+ desc "Update vendor"
7
+ task :update do
8
+ `git submodule update`
9
+ end
10
+
11
+ desc "vendor mustache"
12
+ task :mustache do
13
+ dir = File.expand_path('..', __FILE__)
14
+ source = File.join(dir, 'vendor/mustache.js/mustache.js')
15
+ target = File.join(dir, 'lib/couch/generators/application/templates/lib/')
16
+ FileUtils.cp source, target
17
+ end
18
+ end
19
+
20
+ desc "Vendor all"
21
+ task :vendor => ["vendor:update", "vendor:mustache"]
22
+
23
+
5
24
  begin
6
25
  require 'jeweler'
7
26
  Jeweler::Tasks.new do |gem|
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{couch}
8
- s.version = "0.1.1"
8
+ s.version = "0.1.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Johannes J. Schmidt"]
@@ -47,6 +47,7 @@ Gem::Specification.new do |s|
47
47
  "lib/couch/generators/application/templates/_id.js",
48
48
  "lib/couch/generators/application/templates/couchrc",
49
49
  "lib/couch/generators/application/templates/gitignore",
50
+ "lib/couch/generators/application/templates/lib/mustache.js",
50
51
  "lib/couch/generators/application/templates/validate_doc_update.js",
51
52
  "lib/couch/generators/base.rb",
52
53
  "lib/couch/generators/list/USAGE",
@@ -34,7 +34,7 @@ module Couch::Generators
34
34
  def create_lib_files
35
35
  empty_directory "lib"
36
36
  inside "lib" do
37
- copy_file "mustache/mustache.js", "mustache.js"
37
+ copy_file "mustache.js"
38
38
  end
39
39
  end
40
40
 
@@ -0,0 +1,305 @@
1
+ /*
2
+ Shameless port of http://github.com/defunkt/mustache
3
+ by Jan Lehnardt <jan@apache.org>,
4
+ Alexander Lang <alex@upstream-berlin.com>,
5
+ Sebastian Cohnen <sebastian.cohnen@googlemail.com>
6
+
7
+ Thanks @defunkt for the awesome code.
8
+
9
+ See http://github.com/defunkt/mustache for more info.
10
+ */
11
+
12
+ var Mustache = function() {
13
+ var Renderer = function() {};
14
+
15
+ Renderer.prototype = {
16
+ otag: "{{",
17
+ ctag: "}}",
18
+ pragmas: {},
19
+ buffer: [],
20
+ pragmas_parsed: false,
21
+ pragmas_implemented: {
22
+ "IMPLICIT-ITERATOR": true
23
+ },
24
+
25
+ render: function(template, context, partials, in_recursion) {
26
+ // fail fast
27
+ if(template.indexOf(this.otag) == -1) {
28
+ if(in_recursion) {
29
+ return template;
30
+ } else {
31
+ this.send(template);
32
+ return;
33
+ }
34
+ }
35
+
36
+ if(!in_recursion) {
37
+ this.buffer = [];
38
+ }
39
+
40
+ if(!this.pragmas_parsed) {
41
+ template = this.render_pragmas(template);
42
+ }
43
+ var html = this.render_section(template, context, partials);
44
+ if(in_recursion) {
45
+ return this.render_tags(html, context, partials, in_recursion);
46
+ }
47
+
48
+ this.render_tags(html, context, partials, in_recursion);
49
+ },
50
+
51
+ /*
52
+ Sends parsed lines
53
+ */
54
+ send: function(line) {
55
+ if(line != "") {
56
+ this.buffer.push(line);
57
+ }
58
+ },
59
+
60
+ /*
61
+ Looks for %PRAGMAS
62
+ */
63
+ render_pragmas: function(template) {
64
+ this.pragmas_parsed = true;
65
+ // no pragmas
66
+ if(template.indexOf(this.otag + "%") == -1) {
67
+ return template;
68
+ }
69
+
70
+ var that = this;
71
+ var regex = new RegExp(this.otag + "%([\\w_-]+) ?([\\w]+=[\\w]+)?"
72
+ + this.ctag);
73
+ return template.replace(regex, function(match, pragma, options) {
74
+ if(!that.pragmas_implemented[pragma]) {
75
+ throw({message: "This implementation of mustache doesn't understand the '"
76
+ + pragma + "' pragma"});
77
+ }
78
+ that.pragmas[pragma] = {};
79
+ if(options) {
80
+ var opts = options.split("=");
81
+ that.pragmas[pragma][opts[0]] = opts[1];
82
+ }
83
+ return "";
84
+ // ignore unknown pragmas silently
85
+ });
86
+ },
87
+
88
+ /*
89
+ Tries to find a partial in the global scope and render it
90
+ */
91
+ render_partial: function(name, context, partials) {
92
+ if(typeof(context[name]) != "object") {
93
+ throw({message: "subcontext for '" + name + "' is not an object"});
94
+ }
95
+ if(!partials || !partials[name]) {
96
+ throw({message: "unknown_partial '" + name + "'"});
97
+ }
98
+ return this.render(partials[name], context[name], partials, true);
99
+ },
100
+
101
+ /*
102
+ Renders boolean and enumerable sections
103
+ */
104
+ render_section: function(template, context, partials) {
105
+ if(template.indexOf(this.otag + "#") == -1) {
106
+ return template;
107
+ }
108
+ var that = this;
109
+ // CSW - Added "+?" so it finds the tighest bound, not the widest
110
+ var regex = new RegExp(this.otag + "\\#(.+)" + this.ctag +
111
+ "\\s*([\\s\\S]+?)" + this.otag + "\\/\\1" + this.ctag + "\\s*", "mg");
112
+
113
+ // for each {{#foo}}{{/foo}} section do...
114
+ return template.replace(regex, function(match, name, content) {
115
+ var value = that.find(name, context);
116
+ if(that.is_array(value)) { // Enumerable, Let's loop!
117
+ return that.map(value, function(row) {
118
+ return that.render(content, that.merge(context,
119
+ that.create_context(row)), partials, true);
120
+ }).join("");
121
+ } else if(value) { // boolean section
122
+ return that.render(content, context, partials, true);
123
+ } else {
124
+ return "";
125
+ }
126
+ });
127
+ },
128
+
129
+ /*
130
+ Replace {{foo}} and friends with values from our view
131
+ */
132
+ render_tags: function(template, context, partials, in_recursion) {
133
+ // tit for tat
134
+ var that = this;
135
+
136
+ var new_regex = function() {
137
+ return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\/#]+?)\\1?" +
138
+ that.ctag + "+", "g");
139
+ };
140
+
141
+ var regex = new_regex();
142
+ var lines = template.split("\n");
143
+ for (var i=0; i < lines.length; i++) {
144
+ lines[i] = lines[i].replace(regex, function(match, operator, name) {
145
+ switch(operator) {
146
+ case "!": // ignore comments
147
+ return match;
148
+ case "=": // set new delimiters, rebuild the replace regexp
149
+ that.set_delimiters(name);
150
+ regex = new_regex();
151
+ return "";
152
+ case ">": // render partial
153
+ return that.render_partial(name, context, partials);
154
+ case "{": // the triple mustache is unescaped
155
+ return that.find(name, context);
156
+ default: // escape the value
157
+ return that.escape(that.find(name, context));
158
+ }
159
+ }, this);
160
+ if(!in_recursion) {
161
+ this.send(lines[i]);
162
+ }
163
+ }
164
+
165
+ if(in_recursion) {
166
+ return lines.join("\n");
167
+ }
168
+ },
169
+
170
+ set_delimiters: function(delimiters) {
171
+ var dels = delimiters.split(" ");
172
+ this.otag = this.escape_regex(dels[0]);
173
+ this.ctag = this.escape_regex(dels[1]);
174
+ },
175
+
176
+ escape_regex: function(text) {
177
+ // thank you Simon Willison
178
+ if(!arguments.callee.sRE) {
179
+ var specials = [
180
+ '/', '.', '*', '+', '?', '|',
181
+ '(', ')', '[', ']', '{', '}', '\\'
182
+ ];
183
+ arguments.callee.sRE = new RegExp(
184
+ '(\\' + specials.join('|\\') + ')', 'g'
185
+ );
186
+ }
187
+ return text.replace(arguments.callee.sRE, '\\$1');
188
+ },
189
+
190
+ /*
191
+ find `name` in current `context`. That is find me a value
192
+ from the view object
193
+ */
194
+ find: function(name, context) {
195
+ name = this.trim(name);
196
+ if(typeof context[name] === "function") {
197
+ return context[name].apply(context);
198
+ }
199
+ if(context[name] !== undefined) {
200
+ return context[name];
201
+ }
202
+ // silently ignore unkown variables
203
+ return "";
204
+ },
205
+
206
+ // Utility methods
207
+
208
+ /*
209
+ Does away with nasty characters
210
+ */
211
+ escape: function(s) {
212
+ return ((s == null) ? "" : s).toString().replace(/[&"<>\\]/g, function(s) {
213
+ switch(s) {
214
+ case "&": return "&amp;";
215
+ case "\\": return "\\\\";;
216
+ case '"': return '\"';;
217
+ case "<": return "&lt;";
218
+ case ">": return "&gt;";
219
+ default: return s;
220
+ }
221
+ });
222
+ },
223
+
224
+ /*
225
+ Merges all properties of object `b` into object `a`.
226
+ `b.property` overwrites a.property`
227
+ */
228
+ merge: function(a, b) {
229
+ var _new = {};
230
+ for(var name in a) {
231
+ if(a.hasOwnProperty(name)) {
232
+ _new[name] = a[name];
233
+ }
234
+ };
235
+ for(var name in b) {
236
+ if(b.hasOwnProperty(name)) {
237
+ _new[name] = b[name];
238
+ }
239
+ };
240
+ return _new;
241
+ },
242
+
243
+ // by @langalex, support for arrays of strings
244
+ create_context: function(_context) {
245
+ if(this.is_object(_context)) {
246
+ return _context;
247
+ } else if(this.pragmas["IMPLICIT-ITERATOR"]) {
248
+ var iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator || ".";
249
+ var ctx = {};
250
+ ctx[iterator] = _context
251
+ return ctx;
252
+ }
253
+ },
254
+
255
+ is_object: function(a) {
256
+ return a && typeof a == "object";
257
+ },
258
+
259
+ is_array: function(a) {
260
+ return Object.prototype.toString.call(a) === '[object Array]';
261
+ },
262
+
263
+ /*
264
+ Gets rid of leading and trailing whitespace
265
+ */
266
+ trim: function(s) {
267
+ return s.replace(/^\s*|\s*$/g, "");
268
+ },
269
+
270
+ /*
271
+ Why, why, why? Because IE. Cry, cry cry.
272
+ */
273
+ map: function(array, fn) {
274
+ if (typeof array.map == "function") {
275
+ return array.map(fn)
276
+ } else {
277
+ var r = [];
278
+ var l = array.length;
279
+ for(i=0;i<l;i++) {
280
+ r.push(fn(array[i]));
281
+ }
282
+ return r;
283
+ }
284
+ }
285
+ };
286
+
287
+ return({
288
+ name: "mustache.js",
289
+ version: "0.2.3-dev",
290
+
291
+ /*
292
+ Turns a template and view into HTML
293
+ */
294
+ to_html: function(template, view, partials, send_fun) {
295
+ var renderer = new Renderer();
296
+ if(send_fun) {
297
+ renderer.send = send_fun;
298
+ }
299
+ renderer.render(template, view, partials);
300
+ if(!send_fun) {
301
+ return renderer.buffer.join("\n");
302
+ }
303
+ }
304
+ });
305
+ }();
@@ -1,3 +1,3 @@
1
1
  module Couch
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 1
9
- version: 0.1.1
8
+ - 2
9
+ version: 0.1.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Johannes J. Schmidt
@@ -112,6 +112,7 @@ files:
112
112
  - lib/couch/generators/application/templates/_id.js
113
113
  - lib/couch/generators/application/templates/couchrc
114
114
  - lib/couch/generators/application/templates/gitignore
115
+ - lib/couch/generators/application/templates/lib/mustache.js
115
116
  - lib/couch/generators/application/templates/validate_doc_update.js
116
117
  - lib/couch/generators/base.rb
117
118
  - lib/couch/generators/list/USAGE