jim 0.1.2 → 0.2.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.
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);