couch 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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