jim 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/HISTORY +28 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +2 -1
  4. data/jim.gemspec +67 -9
  5. data/lib/jim/bundler.rb +14 -11
  6. data/lib/jim/cli.rb +51 -9
  7. data/lib/jim/index.rb +3 -7
  8. data/lib/jim/installer.rb +140 -22
  9. data/lib/jim/templates/commands +21 -6
  10. data/lib/jim/version_parser.rb +2 -3
  11. data/lib/jim.rb +19 -2
  12. data/test/fixtures/jimfile +3 -3
  13. data/test/fixtures/sammy-0.5.0/HISTORY.md +135 -0
  14. data/test/fixtures/sammy-0.5.0/LICENSE +22 -0
  15. data/test/fixtures/sammy-0.5.0/README.md +81 -0
  16. data/test/fixtures/sammy-0.5.0/Rakefile +174 -0
  17. data/test/fixtures/sammy-0.5.0/examples/backend/README.md +23 -0
  18. data/test/fixtures/sammy-0.5.0/examples/backend/Rakefile +15 -0
  19. data/test/fixtures/sammy-0.5.0/examples/backend/app.rb +17 -0
  20. data/test/fixtures/sammy-0.5.0/examples/backend/app.ru +3 -0
  21. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/app.js +106 -0
  22. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.cloudkit.js +840 -0
  23. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.js +19 -0
  24. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/sammy.js +1013 -0
  25. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/index.html.erb +11 -0
  26. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task.html.erb +4 -0
  27. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task_details.html.erb +4 -0
  28. data/test/fixtures/sammy-0.5.0/examples/backend/views/app.sass +63 -0
  29. data/test/fixtures/sammy-0.5.0/examples/backend/views/index.haml +18 -0
  30. data/test/fixtures/sammy-0.5.0/examples/form_handling/files/form.html +12 -0
  31. data/test/fixtures/sammy-0.5.0/examples/form_handling/index.html +65 -0
  32. data/test/fixtures/sammy-0.5.0/examples/hello_world/index.html +50 -0
  33. data/test/fixtures/sammy-0.5.0/examples/location_override/README.md +15 -0
  34. data/test/fixtures/sammy-0.5.0/examples/location_override/data.html +110 -0
  35. data/test/fixtures/sammy-0.5.0/examples/location_override/index.html +79 -0
  36. data/test/fixtures/sammy-0.5.0/examples/location_override/test.html +121 -0
  37. data/test/fixtures/sammy-0.5.0/lib/min/sammy-0.5.0.min.js +5 -0
  38. data/test/fixtures/sammy-0.5.0/lib/min/sammy-lastest.min.js +5 -0
  39. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.cache.js +117 -0
  40. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.haml.js +539 -0
  41. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.json.js +362 -0
  42. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.mustache.js +415 -0
  43. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.nested_params.js +118 -0
  44. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.storage.js +515 -0
  45. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.template.js +117 -0
  46. data/test/fixtures/sammy-0.5.0/lib/sammy.js +1367 -0
  47. data/test/fixtures/sammy-0.5.0/test/fixtures/partial +1 -0
  48. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.html +1 -0
  49. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.noengine +1 -0
  50. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.template +1 -0
  51. data/test/fixtures/sammy-0.5.0/test/index.html +84 -0
  52. data/test/fixtures/sammy-0.5.0/test/test_sammy_application.js +953 -0
  53. data/test/fixtures/sammy-0.5.0/test/test_sammy_event_context.js +252 -0
  54. data/test/fixtures/sammy-0.5.0/test/test_sammy_location_proxy.js +91 -0
  55. data/test/fixtures/sammy-0.5.0/test/test_sammy_plugins.js +296 -0
  56. data/test/fixtures/sammy-0.5.0/test/test_sammy_storage.js +175 -0
  57. data/test/fixtures/sammy-0.5.0/test/test_server +27 -0
  58. data/test/fixtures/sammy-0.5.0/vendor/jquery-1.4.1.js +6078 -0
  59. data/test/fixtures/sammy-0.5.0/vendor/jquery-1.4.1.min.js +152 -0
  60. data/test/fixtures/sammy-0.5.0/vendor/jsdoc/doc.haml +58 -0
  61. data/test/fixtures/sammy-0.5.0/vendor/jsdoc/jsdoc.rb +143 -0
  62. data/test/fixtures/sammy-0.5.0/vendor/jslitmus.js +670 -0
  63. data/test/fixtures/sammy-0.5.0/vendor/qunit/qunit.css +119 -0
  64. data/test/fixtures/sammy-0.5.0/vendor/qunit/qunit.js +1043 -0
  65. data/test/fixtures/sammy-0.5.0/vendor/qunit-spec.js +127 -0
  66. data/test/helper.rb +23 -3
  67. data/test/test_jim_bundler.rb +9 -8
  68. data/test/test_jim_cli.rb +21 -12
  69. data/test/test_jim_installer.rb +152 -35
  70. data/test/test_jim_version_parser.rb +4 -0
  71. metadata +117 -27
  72. data/.document +0 -5
@@ -0,0 +1,117 @@
1
+ // name: sammy.cache
2
+ // version: 0.5.0
3
+ // ** deprecated
4
+ (function($) {
5
+
6
+ Sammy = Sammy || {};
7
+
8
+ // A simple cache strategy that stores key/values in memory.
9
+ Sammy.MemoryCacheProxy = function(initial) {
10
+ this._cache = initial || {};
11
+ };
12
+
13
+ $.extend(Sammy.MemoryCacheProxy.prototype, {
14
+ exists: function(name) {
15
+ return (typeof this._cache[name] != "undefined");
16
+ },
17
+ set: function(name, value) {
18
+ return this._cache[name] = value;
19
+ },
20
+ get: function(name) {
21
+ return this._cache[name];
22
+ },
23
+ clear: function(name) {
24
+ delete this._cache[name];
25
+ }
26
+ });
27
+
28
+ // A simple cache strategy that stores key/values <tt>$element.data()</tt> with a <tt>cache.</tt> prefix
29
+ Sammy.DataCacheProxy = function(initial, $element) {
30
+ initial = initial || {};
31
+ this.$element = $element;
32
+ $.each(initial, function(key, value) {
33
+ $element.data('cache.' + key, value);
34
+ });
35
+ };
36
+
37
+ $.extend(Sammy.DataCacheProxy.prototype, {
38
+ exists: function(name) {
39
+ return (typeof this.$element.data('cache.' + name) != "undefined");
40
+ },
41
+ set: function(name, value) {
42
+ return this.$element.data('cache.' + name, value);
43
+ },
44
+ get: function(name) {
45
+ return this.$element.data('cache.' + name);
46
+ },
47
+ clear: function(name) {
48
+ this.$element.removeData('cache.' + name);
49
+ }
50
+ });
51
+
52
+ // Sammy.Cache provides helpers for caching data within the lifecycle of a
53
+ // Sammy app. The plugin provides two main methods on <tt>Sammy.Application<tt>,
54
+ // <tt>cache</tt> and <tt>clearCache</tt>. Each app has its own cache store so that
55
+ // you dont have to worry about collisions. There are currently two different 'cache proxies'
56
+ // that share the same API but store the data in different ways.
57
+ //
58
+ // === Arguments
59
+ //
60
+ // +proxy+:: decides which caching proxy to use, either 'memory'(default) or 'data'
61
+ //
62
+ Sammy.Cache = function(app, proxy) {
63
+
64
+ app.log('**WARNING:** This version of Sammy.Cache has been deprecated in favor of using the version in Sammy.Storage and will be removed in 1.0')
65
+
66
+ if (proxy == 'data') {
67
+ this.cache_proxy = new Sammy.DataCacheProxy({}, this.$element());
68
+ } else {
69
+ this.cache_proxy = new Sammy.MemoryCacheProxy({});
70
+ }
71
+
72
+ app.cache_partials = true;
73
+
74
+ $.extend(app, {
75
+ // cache is the main method for interacting with the cache store. The same
76
+ // method is used for both setting and getting the value. The API is similar
77
+ // to jQuery.fn.attr()
78
+ //
79
+ // === Examples
80
+ //
81
+ // // setting a value
82
+ // cache('key', 'value');
83
+ //
84
+ // // getting a value
85
+ // cache('key'); //=> 'value'
86
+ //
87
+ // // setting a value with a callback
88
+ // cache('key', function() {
89
+ // // this is the app
90
+ // return app.element_selector;
91
+ // });
92
+ //
93
+ cache: function(name, value) {
94
+ if (typeof value == 'undefined') {
95
+ return this.cache_proxy.get(name);
96
+ } else if ($.isFunction(value) && !this.cache_proxy.exists(name)) {
97
+ return this.cache_proxy.set(name, value.apply(this));
98
+ } else {
99
+ return this.cache_proxy.set(name, value)
100
+ }
101
+ },
102
+
103
+ // clears the cached value for <tt>name</tt>
104
+ clearCache: function(name) {
105
+ return this.cache_proxy.clear(name);
106
+ }
107
+ });
108
+
109
+ app.helpers({
110
+ // a helper shortcut for use in <tt>Sammy.EventContext</tt>
111
+ cache: function(name, value) {
112
+ return this.app.cache(name, value);
113
+ }
114
+ });
115
+ };
116
+
117
+ })(jQuery);
@@ -0,0 +1,539 @@
1
+ (function($) {
2
+
3
+ /*
4
+ port of http://github.com/creationix/haml-js
5
+ by Tim Caswell <tim@creationix.com>
6
+ */
7
+
8
+ var matchers, self_close_tags, embedder;
9
+
10
+ function html_escape(text) {
11
+ if (typeof text !== 'string') {
12
+ text = text + "";
13
+ }
14
+ return text.
15
+ replace(/&/g, "&amp;").
16
+ replace(/</g, "&lt;").
17
+ replace(/>/g, "&gt;").
18
+ replace(/\"/g, "&quot;");
19
+ }
20
+
21
+ function render_attribs(attribs) {
22
+ var key, value, result = [];
23
+ for (key in attribs) {
24
+ if (key !== 'content' && attribs.hasOwnProperty(key)) {
25
+ switch (attribs[key]) {
26
+ case 'undefined':
27
+ case 'false':
28
+ case 'null':
29
+ case '""':
30
+ break;
31
+ default:
32
+ try {
33
+ value = JSON.parse("[" + attribs[key] +"]")[0];
34
+ if (value === true) {
35
+ value = key;
36
+ }
37
+ result.push(" " + key + '=\\"' + html_escape(value) + '\\"');
38
+ } catch (e) {
39
+ result.push(" " + key + '=\\"" + html_escape(' + attribs[key] + ') + "\\"');
40
+ }
41
+ }
42
+ }
43
+ }
44
+ return result.join("");
45
+ }
46
+
47
+ // Parse the attribute block using a state machine
48
+ function parse_attribs(line) {
49
+ var attributes = {},
50
+ l = line.length,
51
+ i, c,
52
+ count = 1,
53
+ quote = false,
54
+ skip = false,
55
+ open, close, joiner, seperator,
56
+ pair = {
57
+ start: 1,
58
+ middle: null,
59
+ end: null
60
+ };
61
+
62
+ if (!(l > 0 && (line.charAt(0) === '{' || line.charAt(0) === '('))) {
63
+ return {
64
+ content: line[0] === ' ' ? line.substr(1, l) : line
65
+ };
66
+ }
67
+ open = line.charAt(0);
68
+ close = (open === '{') ? '}' : ')';
69
+ joiner = (open === '{') ? ':' : '=';
70
+ seperator = (open === '{') ? ',' : ' ';
71
+
72
+ function process_pair() {
73
+ var key = line.substr(pair.start, pair.middle - pair.start).trim(),
74
+ value = line.substr(pair.middle + 1, pair.end - pair.middle - 1).trim();
75
+ attributes[key] = value;
76
+ pair = {
77
+ start: null,
78
+ middle: null,
79
+ end: null
80
+ };
81
+ }
82
+
83
+ for (i = 1; count > 0; i += 1) {
84
+
85
+ // If we reach the end of the line, then there is a problem
86
+ if (i > l) {
87
+ throw "Malformed attribute block";
88
+ }
89
+
90
+ c = line.charAt(i);
91
+ if (skip) {
92
+ skip = false;
93
+ } else {
94
+ if (quote) {
95
+ if (c === '\\') {
96
+ skip = true;
97
+ }
98
+ if (c === quote) {
99
+ quote = false;
100
+ }
101
+ } else {
102
+ if (c === '"' || c === "'") {
103
+ quote = c;
104
+ }
105
+
106
+ if (count === 1) {
107
+ if (c === joiner) {
108
+ pair.middle = i;
109
+ }
110
+ if (c === seperator || c === close) {
111
+ pair.end = i;
112
+ process_pair();
113
+ if (c === seperator) {
114
+ pair.start = i + 1;
115
+ }
116
+ }
117
+ }
118
+
119
+ if (c === open) {
120
+ count += 1;
121
+ }
122
+ if (c === close) {
123
+ count -= 1;
124
+ }
125
+ }
126
+ }
127
+ }
128
+ attributes.content = line.substr(i, line.length);
129
+ return attributes;
130
+ }
131
+
132
+ // Split interpolated strings into an array of literals and code fragments.
133
+ function parse_interpol(value) {
134
+ var items = [],
135
+ pos = 0,
136
+ next = 0,
137
+ match;
138
+ while (true) {
139
+ // Match up to embedded string
140
+ next = value.substr(pos).search(embedder);
141
+ if (next < 0) {
142
+ if (pos < value.length) {
143
+ items.push(JSON.stringify(value.substr(pos)));
144
+ }
145
+ break;
146
+ }
147
+ items.push(JSON.stringify(value.substr(pos, next)));
148
+ pos += next;
149
+
150
+ // Match embedded string
151
+ match = value.substr(pos).match(embedder);
152
+ next = match[0].length;
153
+ if (next < 0) { break; }
154
+ items.push(match[1] || match[2]);
155
+ pos += next;
156
+ }
157
+ return items.join(" + ");
158
+ }
159
+
160
+ // Used to find embedded code in interpolated strings.
161
+ embedder = /\#\{([^}]*)\}/;
162
+
163
+ self_close_tags = ["meta", "img", "link", "br", "hr", "input", "area", "base"];
164
+
165
+ // All matchers' regexps should capture leading whitespace in first capture
166
+ // and trailing content in last capture
167
+ matchers = [
168
+ // html tags
169
+ {
170
+ regexp: /^(\s*)((?:[.#%][a-z_\-][a-z0-9_\-]*)+)(.*)$/i,
171
+ process: function () {
172
+ var tag, classes, ids, attribs, content;
173
+ tag = this.matches[2];
174
+ classes = tag.match(/\.([a-z_\-][a-z0-9_\-]*)/gi);
175
+ ids = tag.match(/\#([a-z_\-][a-z0-9_\-]*)/gi);
176
+ tag = tag.match(/\%([a-z_\-][a-z0-9_\-]*)/gi);
177
+
178
+ // Default to <div> tag
179
+ tag = tag ? tag[0].substr(1, tag[0].length) : 'div';
180
+
181
+ attribs = this.matches[3];
182
+ if (attribs) {
183
+ attribs = parse_attribs(attribs);
184
+ if (attribs.content) {
185
+ this.contents.unshift(attribs.content.trim());
186
+ delete(attribs.content);
187
+ }
188
+ } else {
189
+ attribs = {};
190
+ }
191
+
192
+ if (classes) {
193
+ classes = classes.map(function (klass) {
194
+ return klass.substr(1, klass.length);
195
+ }).join(' ');
196
+ if (attribs['class']) {
197
+ try {
198
+ attribs['class'] = JSON.stringify(classes + " " + JSON.parse(attribs['class']));
199
+ } catch (e) {
200
+ attribs['class'] = JSON.stringify(classes + " ") + " + " + attribs['class'];
201
+ }
202
+ } else {
203
+ attribs['class'] = JSON.stringify(classes);
204
+ }
205
+ }
206
+ if (ids) {
207
+ ids = ids.map(function (id) {
208
+ return id.substr(1, id.length);
209
+ }).join(' ');
210
+ if (attribs.id) {
211
+ attribs.id = JSON.stringify(ids + " ") + attribs.id;
212
+ } else {
213
+ attribs.id = JSON.stringify(ids);
214
+ }
215
+ }
216
+
217
+ attribs = render_attribs(attribs);
218
+
219
+ content = this.render_contents();
220
+ if (content === '""') {
221
+ content = '';
222
+ }
223
+
224
+ if (self_close_tags.indexOf(tag) == -1) {
225
+ return '"<' + tag + attribs + '>"' +
226
+ (content.length > 0 ? ' + \n' + content : "") +
227
+ ' + \n"</' + tag + '>"';
228
+ } else {
229
+ return '"<' + tag + attribs + ' />"';
230
+ }
231
+ }
232
+ },
233
+
234
+ // each loops
235
+ {
236
+ regexp: /^(\s*)(?::for|:each)\s+(?:([a-z_][a-z_\-]*),\s*)?([a-z_][a-z_\-]*)\s+in\s+(.*)(\s*)$/i,
237
+ process: function () {
238
+ var ivar = this.matches[2] || '__key__', // index
239
+ vvar = this.matches[3], // value
240
+ avar = this.matches[4], // array
241
+ rvar = '__result__'; // results
242
+
243
+ if (this.matches[5]) {
244
+ this.contents.unshift(this.matches[5]);
245
+ }
246
+ return '(function () { ' +
247
+ 'var ' + rvar + ' = [], ' + ivar + ', ' + vvar + '; ' +
248
+ 'for (' + ivar + ' in ' + avar + ') { ' +
249
+ 'if (' + avar + '.hasOwnProperty(' + ivar + ')) { ' +
250
+ vvar + ' = ' + avar + '[' + ivar + ']; ' +
251
+ rvar + '.push(\n' + (this.render_contents() || "''") + '\n); ' +
252
+ '} } return ' + rvar + '.join(""); }).call(this)';
253
+ }
254
+ },
255
+
256
+ // if statements
257
+ {
258
+ regexp: /^(\s*):if\s+(.*)\s*$/i,
259
+ process: function () {
260
+ var condition = this.matches[2];
261
+ return '(function () { ' +
262
+ 'if (' + condition + ') { ' +
263
+ 'return (\n' + (this.render_contents() || '') + '\n);' +
264
+ '} else { return ""; } }).call(this)';
265
+ }
266
+ },
267
+
268
+ // declarations
269
+ {
270
+ regexp: /^()!!!(?:\s*(.*))\s*$/,
271
+ process: function () {
272
+ var line = '';
273
+ switch ((this.matches[2] || '').toLowerCase()) {
274
+ case '':
275
+ // XHTML 1.0 Transitional
276
+ line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
277
+ break;
278
+ case 'strict':
279
+ case '1.0':
280
+ // XHTML 1.0 Strict
281
+ line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
282
+ break;
283
+ case 'frameset':
284
+ // XHTML 1.0 Frameset
285
+ line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';
286
+ break;
287
+ case '5':
288
+ // XHTML 5
289
+ line = '<!DOCTYPE html>';
290
+ break;
291
+ case '1.1':
292
+ // XHTML 1.1
293
+ line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
294
+ break;
295
+ case 'basic':
296
+ // XHTML Basic 1.1
297
+ line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">';
298
+ break;
299
+ case 'mobile':
300
+ // XHTML Mobile 1.2
301
+ line = '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">';
302
+ break;
303
+ case 'xml':
304
+ // XML
305
+ line = "<?xml version='1.0' encoding='utf-8' ?>";
306
+ break;
307
+ case 'xml iso-8859-1':
308
+ // XML iso-8859-1
309
+ line = "<?xml version='1.0' encoding='iso-8859-1' ?>";
310
+ break;
311
+ }
312
+ return JSON.stringify(line + "\n");
313
+ }
314
+ },
315
+
316
+ // script blocks
317
+ {
318
+ regexp: /^(\s*):(?:java)?script\s*$/,
319
+ process: function () {
320
+ return parse_interpol('\n<script type="text/javascript">\n' +
321
+ '//<![CDATA[\n ' +
322
+ this.contents.join("\n ") +
323
+ "\n//]]>\n</script>\n");
324
+ }
325
+ },
326
+
327
+ // css blocks
328
+ {
329
+ regexp: /^(\s*):css\s*$/,
330
+ process: function () {
331
+ return JSON.stringify('\n<style type="text/css">\n ' +
332
+ this.contents.join("\n ") +
333
+ "\n</style>\n");
334
+ }
335
+ },
336
+
337
+ ];
338
+
339
+ function compile(lines) {
340
+ var block = false,
341
+ output = [];
342
+
343
+ // If lines is a string, turn it into an array
344
+ if (typeof lines === 'string') {
345
+ lines = lines.trim().split("\n");
346
+ }
347
+
348
+ lines.forEach(function(line) {
349
+ var match, found = false;
350
+
351
+ // Collect all text as raw until outdent
352
+ if (block) {
353
+ match = block.check_indent(line);
354
+ if (match) {
355
+ block.contents.push(match[1] || "");
356
+ return;
357
+ } else {
358
+ output.push(block.process());
359
+ block = false;
360
+ }
361
+ }
362
+
363
+ matchers.forEach(function (matcher) {
364
+ if (!found) {
365
+ match = matcher.regexp(line);
366
+ if (match) {
367
+ block = {
368
+ contents: [],
369
+ matches: match,
370
+ check_indent: new RegExp("^(?:\\s*|" + match[1] + " (.*))$"),
371
+ process: matcher.process,
372
+ render_contents: function () {
373
+ return compile(this. contents);
374
+ }
375
+ };
376
+ found = true;
377
+ }
378
+ }
379
+ });
380
+
381
+ // Match plain text
382
+ if (!found) {
383
+ output.push(function () {
384
+ // Escaped plain text
385
+ if (line[0] === '\\') {
386
+ return JSON.stringify(line.substr(1, line.length) + "\n");
387
+ }
388
+
389
+ // Plain variable data
390
+ if (line[0] === '=') {
391
+ line = line.substr(1, line.length).trim();
392
+ try {
393
+ return JSON.stringify(JSON.parse(line) +"\n");
394
+ } catch (e) {
395
+ return line + ' +\n"\\n"';
396
+ }
397
+ }
398
+
399
+ // HTML escape variable data
400
+ if (line.substr(0, 2) === "&=") {
401
+ line = line.substr(2, line.length).trim();
402
+ try {
403
+ return JSON.stringify(html_escape(JSON.parse(line)) +"\n");
404
+ } catch (e2) {
405
+ return 'html_escape(' + line + ') +\n"\\n"';
406
+ }
407
+ }
408
+
409
+ // Plain text
410
+ return JSON.stringify(line + "\n");
411
+ }());
412
+ }
413
+
414
+ });
415
+ if (block) {
416
+ output.push(block.process());
417
+ }
418
+ return output.join(' + \n');
419
+ };
420
+
421
+ function optimize(js) {
422
+ var new_js = [], buffer = [], part, end;
423
+
424
+ function flush() {
425
+ if (buffer.length > 0) {
426
+ new_js.push(JSON.stringify(buffer.join("")) + end);
427
+ buffer = [];
428
+ }
429
+ }
430
+ js.split("\n").forEach(function (line) {
431
+ part = line.match(/^(\".*\")(\s*\+\s*)?$/);
432
+ if (!part) {
433
+ flush();
434
+ new_js.push(line);
435
+ return;
436
+ }
437
+ end = part[2] || "";
438
+ part = part[1];
439
+ try {
440
+ buffer.push(JSON.parse(part));
441
+ } catch (e) {
442
+ flush();
443
+ new_js.push(line);
444
+ }
445
+ });
446
+ flush();
447
+ return new_js.join("\n");
448
+ };
449
+
450
+ function execute(js, self, locals) {
451
+ return (function () {
452
+ with(locals || {}) {
453
+ try {
454
+ return eval("(" + js + ")");
455
+ } catch (e) {
456
+ return "\n<pre class='error'>" + html_escape(e.stack) + "</pre>\n";
457
+ }
458
+
459
+ }
460
+ }).call(self);
461
+ };
462
+
463
+
464
+ Sammy = Sammy || {};
465
+
466
+ // <tt>Sammy.Haml</tt> provides a quick way of using haml style templates in your app.
467
+ // The plugin itself includes the haml-js library created by Tim Caswell at
468
+ // at http://github.com/creationix/haml-js
469
+ //
470
+ // Haml is an alternative HTML syntax that is really great for describing
471
+ // the structure of HTML documents.
472
+ //
473
+ // By default using Sammy.Haml in your app adds the <tt>haml()</tt> method to the EventContext
474
+ // prototype. However, just like <tt>Sammy.Template</tt> you can change the default name of the method
475
+ // by passing a second argument (e.g. you could use the hml() as the method alias so that all the template
476
+ // files could be in the form file.hml instead of file.haml)
477
+ //
478
+ // === Example
479
+ //
480
+ // The template (mytemplate.haml):
481
+ //
482
+ // %h1&= title
483
+ //
484
+ // Hey, #{name}! Welcome to Haml!
485
+ //
486
+ // The app:
487
+ //
488
+ // var $.app = $.sammy(function() {
489
+ // // include the plugin
490
+ // this.use(Sammy.Haml);
491
+ //
492
+ // this.get('#/hello/:name', function() {
493
+ // // set local vars
494
+ // this.title = 'Hello!'
495
+ // this.name = this.params.name;
496
+ // // render the template and pass it through mustache
497
+ // this.partial('mytemplate.haml');
498
+ // });
499
+ //
500
+ // });
501
+ //
502
+ // If I go to #/hello/AQ in the browser, Sammy will render this to the <tt>body</tt>:
503
+ //
504
+ // <h1>Hello!</h1>
505
+ //
506
+ // Hey, AQ! Welcome to HAML!
507
+ //
508
+ // Note: You dont have to include the haml.js file on top of the plugin as the plugin
509
+ // includes the full source.
510
+ //
511
+ Sammy.Haml = function(app, method_alias) {
512
+ app.use(Sammy.JSON);
513
+
514
+ var haml_cache = {};
515
+ // *Helper*:: Uses haml-js to parse a template and interpolate and work with the passed data
516
+ //
517
+ // === Arguments
518
+ //
519
+ // +template+:: A String template.
520
+ // +data+:: An Object containing the replacement values for the template.
521
+ // data is extended with the <tt>EventContext</tt> allowing you to call its methods within the template.
522
+ //
523
+ var haml = function(template, data, name) {
524
+ // use name for caching
525
+ if (typeof name == 'undefined') name = template;
526
+ var code = haml_cache[name];
527
+ if (!code) {
528
+ code = haml_cache[name] = optimize(compile(template));
529
+ }
530
+ return execute(code, {}, $.extend({}, this, data));
531
+ };
532
+
533
+ // set the default method name/extension
534
+ if (!method_alias) method_alias = 'haml';
535
+ app.helper(method_alias, haml);
536
+
537
+ };
538
+
539
+ })(jQuery);