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,670 @@
1
+ // JSLitmus.js
2
+ //
3
+ // History:
4
+ // 2008-10-27: Initial release
5
+ // 2008-11-09: Account for iteration loop overhead
6
+ // 2008-11-13: Added OS detection
7
+ // 2009-02-25: Create tinyURL automatically, shift-click runs tests in reverse
8
+ //
9
+ // Copyright (c) 2008-2009, Robert Kieffer
10
+ // All Rights Reserved
11
+ //
12
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ // of this software and associated documentation files (the
14
+ // Software), to deal in the Software without restriction, including
15
+ // without limitation the rights to use, copy, modify, merge, publish,
16
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
17
+ // persons to whom the Software is furnished to do so, subject to the
18
+ // following conditions:
19
+ //
20
+ // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
21
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
23
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
24
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
26
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+
28
+ (function() {
29
+ // Private methods and state
30
+
31
+ // Get platform info but don't go crazy trying to recognize everything
32
+ // that's out there. This is just for the major platforms and OSes.
33
+ var platform = 'unknown platform', ua = navigator.userAgent;
34
+
35
+ // Detect OS
36
+ var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
37
+ var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
38
+ if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
39
+
40
+ // Detect browser
41
+ var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
42
+
43
+ // Detect version
44
+ var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
45
+ var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
46
+ var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
47
+
48
+ /**
49
+ * A smattering of methods that are needed to implement the JSLitmus testbed.
50
+ */
51
+ var jsl = {
52
+ /**
53
+ * Enhanced version of escape()
54
+ */
55
+ escape: function(s) {
56
+ s = s.replace(/,/g, '\\,');
57
+ s = escape(s);
58
+ s = s.replace(/\+/g, '%2b');
59
+ s = s.replace(/ /g, '+');
60
+ return s;
61
+ },
62
+
63
+ /**
64
+ * Get an element by ID.
65
+ */
66
+ $: function(id) {
67
+ return document.getElementById(id);
68
+ },
69
+
70
+ /**
71
+ * Null function
72
+ */
73
+ F: function() {},
74
+
75
+ /**
76
+ * Set the status shown in the UI
77
+ */
78
+ status: function(msg) {
79
+ var el = jsl.$('jsl_status');
80
+ if (el) el.innerHTML = msg || '';
81
+ },
82
+
83
+ /**
84
+ * Convert a number to an abbreviated string like, "15K" or "10M"
85
+ */
86
+ toLabel: function(n) {
87
+ if (n == Infinity) {
88
+ return 'Infinity';
89
+ } else if (n > 1e9) {
90
+ n = Math.round(n/1e8);
91
+ return n/10 + 'B';
92
+ } else if (n > 1e6) {
93
+ n = Math.round(n/1e5);
94
+ return n/10 + 'M';
95
+ } else if (n > 1e3) {
96
+ n = Math.round(n/1e2);
97
+ return n/10 + 'K';
98
+ }
99
+ return n;
100
+ },
101
+
102
+ /**
103
+ * Copy properties from src to dst
104
+ */
105
+ extend: function(dst, src) {
106
+ for (var k in src) dst[k] = src[k]; return dst;
107
+ },
108
+
109
+ /**
110
+ * Like Array.join(), but for the key-value pairs in an object
111
+ */
112
+ join: function(o, delimit1, delimit2) {
113
+ if (o.join) return o.join(delimit1); // If it's an array
114
+ var pairs = [];
115
+ for (var k in o) pairs.push(k + delimit1 + o[k]);
116
+ return pairs.join(delimit2);
117
+ },
118
+
119
+ /**
120
+ * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
121
+ */
122
+ indexOf: function(arr, o) {
123
+ if (arr.indexOf) return arr.indexOf(o);
124
+ for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
125
+ return -1;
126
+ }
127
+ };
128
+
129
+ /**
130
+ * Test manages a single test (created with
131
+ * JSLitmus.test())
132
+ *
133
+ * @private
134
+ */
135
+ var Test = function (name, f) {
136
+ if (!f) throw new Error('Undefined test function');
137
+ if (!/function[^\(]*\(([^,\)]*)/.test(f.toString())) {
138
+ throw new Error('"' + name + '" test: Test is not a valid Function object');
139
+ }
140
+ this.loopArg = RegExp.$1;
141
+ this.name = name;
142
+ this.f = f;
143
+ };
144
+
145
+ jsl.extend(Test, /** @lends Test */ {
146
+ /** Calibration tests for establishing iteration loop overhead */
147
+ CALIBRATIONS: [
148
+ new Test('calibrating loop', function(count) {while (count--);}),
149
+ new Test('calibrating function', jsl.F)
150
+ ],
151
+
152
+ /**
153
+ * Run calibration tests. Returns true if calibrations are not yet
154
+ * complete (in which case calling code should run the tests yet again).
155
+ * onCalibrated - Callback to invoke when calibrations have finished
156
+ */
157
+ calibrate: function(onCalibrated) {
158
+ for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
159
+ var cal = Test.CALIBRATIONS[i];
160
+ if (cal.running) return true;
161
+ if (!cal.count) {
162
+ cal.isCalibration = true;
163
+ cal.onStop = onCalibrated;
164
+ //cal.MIN_TIME = .1; // Do calibrations quickly
165
+ cal.run(2e4);
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+ });
172
+
173
+ jsl.extend(Test.prototype, {/** @lends Test.prototype */
174
+ /** Initial number of iterations */
175
+ INIT_COUNT: 10,
176
+ /** Max iterations allowed (i.e. used to detect bad looping functions) */
177
+ MAX_COUNT: 1e9,
178
+ /** Minimum time a test should take to get valid results (secs) */
179
+ MIN_TIME: .5,
180
+
181
+ /** Callback invoked when test state changes */
182
+ onChange: jsl.F,
183
+
184
+ /** Callback invoked when test is finished */
185
+ onStop: jsl.F,
186
+
187
+ /**
188
+ * Reset test state
189
+ */
190
+ reset: function() {
191
+ delete this.count;
192
+ delete this.time;
193
+ delete this.running;
194
+ delete this.error;
195
+ },
196
+
197
+ /**
198
+ * Run the test (in a timeout). We use a timeout to make sure the browser
199
+ * has a chance to finish rendering any UI changes we've made, like
200
+ * updating the status message.
201
+ */
202
+ run: function(count) {
203
+ count = count || this.INIT_COUNT;
204
+ jsl.status(this.name + ' x ' + count);
205
+ this.running = true;
206
+ var me = this;
207
+ setTimeout(function() {me._run(count);}, 200);
208
+ },
209
+
210
+ /**
211
+ * The nuts and bolts code that actually runs a test
212
+ */
213
+ _run: function(count) {
214
+ var me = this;
215
+
216
+ // Make sure calibration tests have run
217
+ if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
218
+ this.error = null;
219
+
220
+ try {
221
+ var start, f = this.f, now, i = count;
222
+
223
+ // Start the timer
224
+ start = new Date();
225
+
226
+ // Now for the money shot. If this is a looping function ...
227
+ if (this.loopArg) {
228
+ // ... let it do the iteration itself
229
+ f(count);
230
+ } else {
231
+ // ... otherwise do the iteration for it
232
+ while (i--) f();
233
+ }
234
+
235
+ // Get time test took (in secs)
236
+ this.time = Math.max(1,new Date() - start)/1000;
237
+
238
+ // Store iteration count and per-operation time taken
239
+ this.count = count;
240
+ this.period = this.time/count;
241
+
242
+ // Do we need to do another run?
243
+ this.running = this.time <= this.MIN_TIME;
244
+
245
+ // ... if so, compute how many times we should iterate
246
+ if (this.running) {
247
+ // Bump the count to the nearest power of 2
248
+ var x = this.MIN_TIME/this.time;
249
+ var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
250
+ count *= pow;
251
+ if (count > this.MAX_COUNT) {
252
+ throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
253
+ }
254
+ }
255
+ } catch (e) {
256
+ // Exceptions are caught and displayed in the test UI
257
+ this.reset();
258
+ this.error = e;
259
+ }
260
+
261
+ // Figure out what to do next
262
+ if (this.running) {
263
+ me.run(count);
264
+ } else {
265
+ jsl.status('');
266
+ me.onStop(me);
267
+ }
268
+
269
+ // Finish up
270
+ this.onChange(this);
271
+ },
272
+
273
+ /**
274
+ * Get the number of operations per second for this test.
275
+ *
276
+ * @param normalize if true, iteration loop overhead taken into account
277
+ */
278
+ getHz: function(/**Boolean*/ normalize) {
279
+ var p = this.period;
280
+
281
+ // Adjust period based on the calibration test time
282
+ if (normalize && !this.isCalibration) {
283
+ var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
284
+
285
+ // If the period is within 20% of the calibration time, then zero the
286
+ // it out
287
+ p = p < cal.period*1.2 ? 0 : p - cal.period;
288
+ }
289
+
290
+ return Math.round(1/p);
291
+ },
292
+
293
+ /**
294
+ * Get a friendly string describing the test
295
+ */
296
+ toString: function() {
297
+ return this.name + ' - ' + this.time/this.count + ' secs';
298
+ }
299
+ });
300
+
301
+ // CSS we need for the UI
302
+ var STYLESHEET = '<style> \
303
+ #jslitmus {font-family:sans-serif; font-size: 12px;} \
304
+ #jslitmus a {text-decoration: none;} \
305
+ #jslitmus a:hover {text-decoration: underline;} \
306
+ #jsl_status { \
307
+ margin-top: 10px; \
308
+ font-size: 10px; \
309
+ color: #888; \
310
+ } \
311
+ A IMG {border:none} \
312
+ #test_results { \
313
+ margin-top: 10px; \
314
+ font-size: 12px; \
315
+ font-family: sans-serif; \
316
+ border-collapse: collapse; \
317
+ border-spacing: 0px; \
318
+ } \
319
+ #test_results th, #test_results td { \
320
+ border: solid 1px #ccc; \
321
+ vertical-align: top; \
322
+ padding: 3px; \
323
+ } \
324
+ #test_results th { \
325
+ vertical-align: bottom; \
326
+ background-color: #ccc; \
327
+ padding: 1px; \
328
+ font-size: 10px; \
329
+ } \
330
+ #test_results #test_platform { \
331
+ color: #444; \
332
+ text-align:center; \
333
+ } \
334
+ #test_results .test_row { \
335
+ color: #006; \
336
+ cursor: pointer; \
337
+ } \
338
+ #test_results .test_nonlooping { \
339
+ border-left-style: dotted; \
340
+ border-left-width: 2px; \
341
+ } \
342
+ #test_results .test_looping { \
343
+ border-left-style: solid; \
344
+ border-left-width: 2px; \
345
+ } \
346
+ #test_results .test_name {white-space: nowrap;} \
347
+ #test_results .test_pending { \
348
+ } \
349
+ #test_results .test_running { \
350
+ font-style: italic; \
351
+ } \
352
+ #test_results .test_done {} \
353
+ #test_results .test_done { \
354
+ text-align: right; \
355
+ font-family: monospace; \
356
+ } \
357
+ #test_results .test_error {color: #600;} \
358
+ #test_results .test_error .error_head {font-weight:bold;} \
359
+ #test_results .test_error .error_body {font-size:85%;} \
360
+ #test_results .test_row:hover td { \
361
+ background-color: #ffc; \
362
+ text-decoration: underline; \
363
+ } \
364
+ #chart { \
365
+ margin: 10px 0px; \
366
+ width: 250px; \
367
+ } \
368
+ #chart img { \
369
+ border: solid 1px #ccc; \
370
+ margin-bottom: 5px; \
371
+ } \
372
+ #chart #tiny_url { \
373
+ height: 40px; \
374
+ width: 250px; \
375
+ } \
376
+ #jslitmus_credit { \
377
+ font-size: 10px; \
378
+ color: #888; \
379
+ margin-top: 8px; \
380
+ } \
381
+ </style>';
382
+
383
+ // HTML markup for the UI
384
+ var MARKUP = '<div id="jslitmus"> \
385
+ <button onclick="JSLitmus.runAll(event)">Run Tests</button> \
386
+ <button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
387
+ <br \> \
388
+ <br \> \
389
+ <input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
390
+ <table id="test_results"> \
391
+ <colgroup> \
392
+ <col /> \
393
+ <col width="100" /> \
394
+ </colgroup> \
395
+ <tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
396
+ <tr><th>Test</th><th>Ops/sec</th></tr> \
397
+ <tr id="test_row_template" class="test_row" style="display:none"> \
398
+ <td class="test_name"></td> \
399
+ <td class="test_result">Ready</td> \
400
+ </tr> \
401
+ </table> \
402
+ <div id="jsl_status"></div> \
403
+ <div id="chart" style="display:none"> \
404
+ <a id="chart_link" target="_blank"><img id="chart_image"></a> \
405
+ TinyURL (for chart): \
406
+ <iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
407
+ </div> \
408
+ <a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
409
+ </div>';
410
+
411
+ /**
412
+ * The public API for creating and running tests
413
+ */
414
+ window.JSLitmus = {
415
+ /** The list of all tests that have been registered with JSLitmus.test */
416
+ _tests: [],
417
+ /** The queue of tests that need to be run */
418
+ _queue: [],
419
+
420
+ /**
421
+ * The parsed query parameters the current page URL. This is provided as a
422
+ * convenience for test functions - it's not used by JSLitmus proper
423
+ */
424
+ params: {},
425
+
426
+ /**
427
+ * Initialize
428
+ */
429
+ _init: function() {
430
+ // Parse query params into JSLitmus.params[] hash
431
+ var match = (location + '').match(/([^?#]*)(#.*)?$/);
432
+ if (match) {
433
+ var pairs = match[1].split('&');
434
+ for (var i = 0; i < pairs.length; i++) {
435
+ var pair = pairs[i].split('=');
436
+ if (pair.length > 1) {
437
+ var key = pair.shift();
438
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
439
+ this.params[key] = value;
440
+ }
441
+ }
442
+ }
443
+
444
+ // Write out the stylesheet. We have to do this here because IE
445
+ // doesn't honor sheets written after the document has loaded.
446
+ document.write(STYLESHEET);
447
+
448
+ // Setup the rest of the UI once the document is loaded
449
+ if (window.addEventListener) {
450
+ window.addEventListener('load', this._setup, false);
451
+ } else if (document.addEventListener) {
452
+ document.addEventListener('load', this._setup, false);
453
+ } else if (window.attachEvent) {
454
+ window.attachEvent('onload', this._setup);
455
+ }
456
+
457
+ return this;
458
+ },
459
+
460
+ /**
461
+ * Set up the UI
462
+ */
463
+ _setup: function() {
464
+ var el = jsl.$('jslitmus_container');
465
+ if (!el) document.body.appendChild(el = document.createElement('div'));
466
+
467
+ el.innerHTML = MARKUP;
468
+
469
+ // Render the UI for all our tests
470
+ for (var i=0; i < JSLitmus._tests.length; i++)
471
+ JSLitmus.renderTest(JSLitmus._tests[i]);
472
+ },
473
+
474
+ /**
475
+ * (Re)render all the test results
476
+ */
477
+ renderAll: function() {
478
+ for (var i = 0; i < JSLitmus._tests.length; i++)
479
+ JSLitmus.renderTest(JSLitmus._tests[i]);
480
+ JSLitmus.renderChart();
481
+ },
482
+
483
+ /**
484
+ * (Re)render the chart graphics
485
+ */
486
+ renderChart: function() {
487
+ var url = JSLitmus.chartUrl();
488
+ jsl.$('chart_link').href = url;
489
+ jsl.$('chart_image').src = url;
490
+ jsl.$('chart').style.display = '';
491
+
492
+ // Update the tiny URL
493
+ jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
494
+ },
495
+
496
+ /**
497
+ * (Re)render the results for a specific test
498
+ */
499
+ renderTest: function(test) {
500
+ // Make a new row if needed
501
+ if (!test._row) {
502
+ var trow = jsl.$('test_row_template');
503
+ if (!trow) return;
504
+
505
+ test._row = trow.cloneNode(true);
506
+ test._row.style.display = '';
507
+ test._row.id = '';
508
+ test._row.onclick = function() {JSLitmus._queueTest(test);};
509
+ test._row.title = 'Run ' + test.name + ' test';
510
+ trow.parentNode.appendChild(test._row);
511
+ test._row.cells[0].innerHTML = test.name;
512
+ }
513
+
514
+ var cell = test._row.cells[1];
515
+ var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
516
+
517
+ if (test.error) {
518
+ cns.push('test_error');
519
+ cell.innerHTML =
520
+ '<div class="error_head">' + test.error + '</div>' +
521
+ '<ul class="error_body"><li>' +
522
+ jsl.join(test.error, ': ', '</li><li>') +
523
+ '</li></ul>';
524
+ } else {
525
+ if (test.running) {
526
+ cns.push('test_running');
527
+ cell.innerHTML = 'running';
528
+ } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
529
+ cns.push('test_pending');
530
+ cell.innerHTML = 'pending';
531
+ } else if (test.count) {
532
+ cns.push('test_done');
533
+ var hz = test.getHz(jsl.$('test_normalize').checked);
534
+ cell.innerHTML = hz != Infinity ? hz : '&infin;';
535
+ } else {
536
+ cell.innerHTML = 'ready';
537
+ }
538
+ }
539
+ cell.className = cns.join(' ');
540
+ },
541
+
542
+ /**
543
+ * Create a new test
544
+ */
545
+ test: function(name, f) {
546
+ // Create the Test object
547
+ var test = new Test(name, f);
548
+ JSLitmus._tests.push(test);
549
+
550
+ // Re-render if the test state changes
551
+ test.onChange = JSLitmus.renderTest;
552
+
553
+ // Run the next test if this one finished
554
+ test.onStop = function(test) {
555
+ if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
556
+ JSLitmus.currentTest = null;
557
+ JSLitmus._nextTest();
558
+ };
559
+
560
+ // Render the new test
561
+ this.renderTest(test);
562
+ },
563
+
564
+ /**
565
+ * Add all tests to the run queue
566
+ */
567
+ runAll: function(e) {
568
+ e = e || window.event;
569
+ var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
570
+ for (var i = 0; i < len; i++) {
571
+ JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
572
+ }
573
+ },
574
+
575
+ /**
576
+ * Remove all tests from the run queue. The current test has to finish on
577
+ * it's own though
578
+ */
579
+ stop: function() {
580
+ while (JSLitmus._queue.length) {
581
+ var test = JSLitmus._queue.shift();
582
+ JSLitmus.renderTest(test);
583
+ }
584
+ },
585
+
586
+ /**
587
+ * Run the next test in the run queue
588
+ */
589
+ _nextTest: function() {
590
+ if (!JSLitmus.currentTest) {
591
+ var test = JSLitmus._queue.shift();
592
+ if (test) {
593
+ jsl.$('stop_button').disabled = false;
594
+ JSLitmus.currentTest = test;
595
+ test.run();
596
+ JSLitmus.renderTest(test);
597
+ if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
598
+ } else {
599
+ jsl.$('stop_button').disabled = true;
600
+ JSLitmus.renderChart();
601
+ }
602
+ }
603
+ },
604
+
605
+ /**
606
+ * Add a test to the run queue
607
+ */
608
+ _queueTest: function(test) {
609
+ if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
610
+ JSLitmus._queue.push(test);
611
+ JSLitmus.renderTest(test);
612
+ JSLitmus._nextTest();
613
+ },
614
+
615
+ /**
616
+ * Generate a Google Chart URL that shows the data for all tests
617
+ */
618
+ chartUrl: function() {
619
+ var n = JSLitmus._tests.length, markers = [], data = [];
620
+ var d, min = 0, max = -1e10;
621
+ var normalize = jsl.$('test_normalize').checked;
622
+
623
+ // Gather test data
624
+ for (var i=0; i < JSLitmus._tests.length; i++) {
625
+ var test = JSLitmus._tests[i];
626
+ if (test.count) {
627
+ var hz = test.getHz(normalize);
628
+ var v = hz != Infinity ? hz : 0;
629
+ data.push(v);
630
+ markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
631
+ markers.length + ',10');
632
+ max = Math.max(v, max);
633
+ }
634
+ }
635
+ if (markers.length <= 0) return null;
636
+
637
+ // Build chart title
638
+ var title = document.getElementsByTagName('title');
639
+ title = (title && title.length) ? title[0].innerHTML : null;
640
+ var chart_title = [];
641
+ if (title) chart_title.push(title);
642
+ chart_title.push('Ops/sec (' + platform + ')');
643
+
644
+ // Build labels
645
+ var labels = [jsl.toLabel(min), jsl.toLabel(max)];
646
+
647
+ var w = 250, bw = 15;
648
+ var bs = 5;
649
+ var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
650
+
651
+ var params = {
652
+ chtt: escape(chart_title.join('|')),
653
+ chts: '000000,10',
654
+ cht: 'bhg', // chart type
655
+ chd: 't:' + data.join(','), // data set
656
+ chds: min + ',' + max, // max/min of data
657
+ chxt: 'x', // label axes
658
+ chxl: '0:|' + labels.join('|'), // labels
659
+ chsp: '0,1',
660
+ chm: markers.join('|'), // test names
661
+ chbh: [bw, 0, bs].join(','), // bar widths
662
+ // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
663
+ chs: w + 'x' + h
664
+ };
665
+ return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
666
+ }
667
+ };
668
+
669
+ JSLitmus._init();
670
+ })();