rspectacles 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3b75957f7c35b3b3ce7cf3689fccf1b2283905eb
4
+ data.tar.gz: b073ea404ac798f4c113c111a45dd6c2faef3da8
5
+ SHA512:
6
+ metadata.gz: a352c263f686deef03c0521799ccdf969db839fd98b7c208f14fccf981f99f35d9c57396ce8d77938591ea7db50b3403a2e585874dd2a6cd3a1d2281ef372f42
7
+ data.tar.gz: 8b6972c2c68a783be7e7246cecc04397d4afc88f423a051321c769f3c29f2cf82a34928d4729e5d661c77505f5be2f81f17f8c74e8159a2a3c1207c69b1d1da5
data/.gitignore CHANGED
@@ -1 +1,3 @@
1
1
  pkg/*
2
+ .ruby-gemset
3
+ .ruby-version
data/Gemfile.lock CHANGED
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspectacles (0.0.1)
4
+ rspectacles (0.0.4)
5
5
  em-hiredis (~> 0.2.1)
6
6
  rake
7
+ redis
7
8
  sinatra (~> 1.4.3)
8
9
  thin (>= 1.5.0)
9
10
 
@@ -20,6 +21,7 @@ GEM
20
21
  rack-protection (1.5.0)
21
22
  rack
22
23
  rake (10.1.0)
24
+ redis (3.0.4)
23
25
  rspec (2.12.0)
24
26
  rspec-core (~> 2.12.0)
25
27
  rspec-expectations (~> 2.12.0)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 Michael Wheeler
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -2,14 +2,9 @@ require 'rubygems'
2
2
  require 'sinatra/base'
3
3
  require 'json'
4
4
  require 'em-hiredis'
5
+ require 'redis'
5
6
  require 'uri'
6
7
  require 'thin'
7
- require 'pry'
8
-
9
- # Helpers
10
- # require './lib/render_partial'
11
- # require './db/config'
12
-
13
8
 
14
9
  module RSpectacles
15
10
  class App < Sinatra::Base
@@ -28,6 +23,7 @@ module RSpectacles
28
23
 
29
24
  uri = URI.parse 'redis://127.0.0.1:6379/'
30
25
  $emredis = nil
26
+ $redis = Redis.new host: uri.host, port: uri.port
31
27
 
32
28
  # Routes
33
29
  get '/' do
@@ -38,10 +34,13 @@ module RSpectacles
38
34
  stream :keep_open do |out|
39
35
  connections << out
40
36
  out.callback { connections.delete(out) }
41
- dump_last_run out
42
37
  end
43
38
  end
44
39
 
40
+ get '/last' do
41
+ $redis.lrange('redis-rspec-last-run', 0, -1).to_json
42
+ end
43
+
45
44
  def dump_last_run(out)
46
45
  $emredis.lrange('redis-rspec-last-run', 0, -1) do |list|
47
46
  list.each { |msg| out << "data: #{msg}\n\n" }
@@ -15,10 +15,25 @@ form {
15
15
  position: fixed;
16
16
  top: 0;
17
17
  left: 0;
18
- padding: 20px;
19
18
  background: rgba(255, 255, 255, 0.5);
20
19
  width: 100%
21
20
  z-index: 100;
22
21
  overflow: auto;
23
- max-width: 300px;
22
+ max-width: 350px;
24
23
  }
24
+
25
+ ul {
26
+ border: 1px solid #eee;
27
+ list-style-type: none;
28
+ margin: 0;
29
+ padding: 15px;
30
+ font-size: 12px;
31
+ }
32
+
33
+ li {
34
+ margin: 0;
35
+ padding: 0;
36
+ }
37
+
38
+ .failed { color: red; }
39
+ .passed { color: green; }
@@ -1,7 +1,8 @@
1
- /*global define: true */
2
- define(['jquery', 'pathtree'], function ($, PathTree) {
1
+ /*global define: true d3: true */
2
+ define(['jquery', 'pathtree', 'mustache'], function ($, PathTree, Mustache) {
3
3
  'use strict';
4
4
 
5
+
5
6
  function chart(options) {
6
7
  var svg, partition, arc, me
7
8
  , tmpl = $('#template').html()
@@ -59,11 +60,12 @@ define(['jquery', 'pathtree'], function ($, PathTree) {
59
60
  , duration: ''
60
61
  , time_or_count: options.isCount ? 'Examples' : 'Seconds'
61
62
  }, data)
63
+ , map
62
64
  ;
63
65
 
64
66
  !options.isCount && (mappedData.value = mappedData.value.toFixed(3));
65
67
 
66
- $('.example-wrapper').html(Plates.bind(tmpl, mappedData));
68
+ $('.example-wrapper').html(Mustache.render(tmpl, mappedData));
67
69
  }
68
70
 
69
71
  function getValue() {
@@ -81,7 +83,7 @@ define(['jquery', 'pathtree'], function ($, PathTree) {
81
83
  .each(stash);
82
84
 
83
85
  path.enter().append("path")
84
- .attr("display", function (d) { return d.depth ? null : "none"; }) // hide inner ring
86
+ .attr("display", function (d) { return d.depth ? null : "none"; })
85
87
  .attr("d", arc)
86
88
  .style("stroke", function (d) { return '#fff'; })
87
89
  .style("fill", function (d) {
@@ -5,17 +5,29 @@ define(['riffle'], function (riffle) {
5
5
  return function streams(uri) {
6
6
  var stream = riffle.stream
7
7
  , me
8
- , events
8
+ , serverEvents
9
+ , ajaxEvents
9
10
  , matching
11
+ , toArray
10
12
  , toJson
13
+ , each
11
14
  , stringEvents
15
+ , allEvents
12
16
  , eventToString
13
17
  ;
14
18
 
15
- events = stream(function (o, i) {
19
+ serverEvents = stream(function (o, i) {
16
20
  new EventSource(uri).addEventListener('message', o);
17
21
  }).invoke();
18
22
 
23
+ function ajaxStream(url, args) {
24
+ return stream(function (o) {
25
+ $.get(url, args, function (d) {
26
+ o(JSON.parse(d));
27
+ });
28
+ });
29
+ }
30
+
19
31
  eventToString = stream(function (o, i) {
20
32
  o(i.data);
21
33
  });
@@ -30,6 +42,10 @@ define(['riffle'], function (riffle) {
30
42
  o(JSON.parse(i));
31
43
  });
32
44
 
45
+ each = stream(function (o, i) {
46
+ i.forEach(function (item) { o(item); });
47
+ });
48
+
33
49
  function batched(delay, maxSize) {
34
50
  var batch = []
35
51
  ;
@@ -37,7 +53,7 @@ define(['riffle'], function (riffle) {
37
53
  delay = delay || 100;
38
54
 
39
55
  return stream(function (o, i) {
40
- batch.push(i);
56
+ batch = batch.concat(i);
41
57
 
42
58
  function clear() {
43
59
  batch.length > 0 && o(batch);
@@ -52,13 +68,15 @@ define(['riffle'], function (riffle) {
52
68
  });
53
69
  }
54
70
 
55
- stringEvents = eventToString.input(events);
71
+ stringEvents = eventToString.input(serverEvents);
72
+ ajaxEvents = each.input(ajaxStream('/last').invoke());
73
+ allEvents = stream().input(stringEvents, ajaxEvents);
56
74
 
57
75
  return me = {
58
76
  message: matching(/^message:/).input(stringEvents)
59
77
  , start: matching(/^status:start/).input(stringEvents)
60
78
  , stop: matching(/^status:stop/).input(stringEvents)
61
- , example: batched().input(toJson.input(matching(/^\{/).input(stringEvents)))
79
+ , example: batched().input(toJson.input(matching(/^\{/).input(allEvents)))
62
80
  };
63
81
  };
64
82
  });
@@ -0,0 +1,536 @@
1
+ /*!
2
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
3
+ * http://github.com/janl/mustache.js
4
+ */
5
+
6
+ /*global define: false*/
7
+
8
+ (function (root, factory) {
9
+ if (typeof exports === "object" && exports) {
10
+ factory(exports); // CommonJS
11
+ } else {
12
+ var mustache = {};
13
+ factory(mustache);
14
+ if (typeof define === "function" && define.amd) {
15
+ define(mustache); // AMD
16
+ } else {
17
+ root.Mustache = mustache; // <script>
18
+ }
19
+ }
20
+ }(this, function (mustache) {
21
+
22
+ var whiteRe = /\s*/;
23
+ var spaceRe = /\s+/;
24
+ var nonSpaceRe = /\S/;
25
+ var eqRe = /\s*=/;
26
+ var curlyRe = /\s*\}/;
27
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
28
+
29
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
30
+ // See https://github.com/janl/mustache.js/issues/189
31
+ var RegExp_test = RegExp.prototype.test;
32
+ function testRegExp(re, string) {
33
+ return RegExp_test.call(re, string);
34
+ }
35
+
36
+ function isWhitespace(string) {
37
+ return !testRegExp(nonSpaceRe, string);
38
+ }
39
+
40
+ var Object_toString = Object.prototype.toString;
41
+ var isArray = Array.isArray || function (obj) {
42
+ return Object_toString.call(obj) === '[object Array]';
43
+ };
44
+
45
+ function escapeRegExp(string) {
46
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
47
+ }
48
+
49
+ var entityMap = {
50
+ "&": "&amp;",
51
+ "<": "&lt;",
52
+ ">": "&gt;",
53
+ '"': '&quot;',
54
+ "'": '&#39;',
55
+ "/": '&#x2F;'
56
+ };
57
+
58
+ function escapeHtml(string) {
59
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
60
+ return entityMap[s];
61
+ });
62
+ }
63
+
64
+ function Scanner(string) {
65
+ this.string = string;
66
+ this.tail = string;
67
+ this.pos = 0;
68
+ }
69
+
70
+ /**
71
+ * Returns `true` if the tail is empty (end of string).
72
+ */
73
+ Scanner.prototype.eos = function () {
74
+ return this.tail === "";
75
+ };
76
+
77
+ /**
78
+ * Tries to match the given regular expression at the current position.
79
+ * Returns the matched text if it can match, the empty string otherwise.
80
+ */
81
+ Scanner.prototype.scan = function (re) {
82
+ var match = this.tail.match(re);
83
+
84
+ if (match && match.index === 0) {
85
+ this.tail = this.tail.substring(match[0].length);
86
+ this.pos += match[0].length;
87
+ return match[0];
88
+ }
89
+
90
+ return "";
91
+ };
92
+
93
+ /**
94
+ * Skips all text until the given regular expression can be matched. Returns
95
+ * the skipped string, which is the entire tail if no match can be made.
96
+ */
97
+ Scanner.prototype.scanUntil = function (re) {
98
+ var match, pos = this.tail.search(re);
99
+
100
+ switch (pos) {
101
+ case -1:
102
+ match = this.tail;
103
+ this.pos += this.tail.length;
104
+ this.tail = "";
105
+ break;
106
+ case 0:
107
+ match = "";
108
+ break;
109
+ default:
110
+ match = this.tail.substring(0, pos);
111
+ this.tail = this.tail.substring(pos);
112
+ this.pos += pos;
113
+ }
114
+
115
+ return match;
116
+ };
117
+
118
+ function Context(view, parent) {
119
+ this.view = view || {};
120
+ this.parent = parent;
121
+ this._cache = {};
122
+ }
123
+
124
+ Context.make = function (view) {
125
+ return (view instanceof Context) ? view : new Context(view);
126
+ };
127
+
128
+ Context.prototype.push = function (view) {
129
+ return new Context(view, this);
130
+ };
131
+
132
+ Context.prototype.lookup = function (name) {
133
+ var value = this._cache[name];
134
+
135
+ if (!value) {
136
+ if (name == '.') {
137
+ value = this.view;
138
+ } else {
139
+ var context = this;
140
+
141
+ while (context) {
142
+ if (name.indexOf('.') > 0) {
143
+ value = context.view;
144
+ var names = name.split('.'), i = 0;
145
+ while (value && i < names.length) {
146
+ value = value[names[i++]];
147
+ }
148
+ } else {
149
+ value = context.view[name];
150
+ }
151
+
152
+ if (value != null) break;
153
+
154
+ context = context.parent;
155
+ }
156
+ }
157
+
158
+ this._cache[name] = value;
159
+ }
160
+
161
+ if (typeof value === 'function') value = value.call(this.view);
162
+
163
+ return value;
164
+ };
165
+
166
+ function Writer() {
167
+ this.clearCache();
168
+ }
169
+
170
+ Writer.prototype.clearCache = function () {
171
+ this._cache = {};
172
+ this._partialCache = {};
173
+ };
174
+
175
+ Writer.prototype.compile = function (template, tags) {
176
+ var fn = this._cache[template];
177
+
178
+ if (!fn) {
179
+ var tokens = mustache.parse(template, tags);
180
+ fn = this._cache[template] = this.compileTokens(tokens, template);
181
+ }
182
+
183
+ return fn;
184
+ };
185
+
186
+ Writer.prototype.compilePartial = function (name, template, tags) {
187
+ var fn = this.compile(template, tags);
188
+ this._partialCache[name] = fn;
189
+ return fn;
190
+ };
191
+
192
+ Writer.prototype.getPartial = function (name) {
193
+ if (!(name in this._partialCache) && this._loadPartial) {
194
+ this.compilePartial(name, this._loadPartial(name));
195
+ }
196
+
197
+ return this._partialCache[name];
198
+ };
199
+
200
+ Writer.prototype.compileTokens = function (tokens, template) {
201
+ var self = this;
202
+ return function (view, partials) {
203
+ if (partials) {
204
+ if (typeof partials === 'function') {
205
+ self._loadPartial = partials;
206
+ } else {
207
+ for (var name in partials) {
208
+ self.compilePartial(name, partials[name]);
209
+ }
210
+ }
211
+ }
212
+
213
+ return renderTokens(tokens, self, Context.make(view), template);
214
+ };
215
+ };
216
+
217
+ Writer.prototype.render = function (template, view, partials) {
218
+ return this.compile(template)(view, partials);
219
+ };
220
+
221
+ /**
222
+ * Low-level function that renders the given `tokens` using the given `writer`
223
+ * and `context`. The `template` string is only needed for templates that use
224
+ * higher-order sections to extract the portion of the original template that
225
+ * was contained in that section.
226
+ */
227
+ function renderTokens(tokens, writer, context, template) {
228
+ var buffer = '';
229
+
230
+ var token, tokenValue, value;
231
+ for (var i = 0, len = tokens.length; i < len; ++i) {
232
+ token = tokens[i];
233
+ tokenValue = token[1];
234
+
235
+ switch (token[0]) {
236
+ case '#':
237
+ value = context.lookup(tokenValue);
238
+
239
+ if (typeof value === 'object') {
240
+ if (isArray(value)) {
241
+ for (var j = 0, jlen = value.length; j < jlen; ++j) {
242
+ buffer += renderTokens(token[4], writer, context.push(value[j]), template);
243
+ }
244
+ } else if (value) {
245
+ buffer += renderTokens(token[4], writer, context.push(value), template);
246
+ }
247
+ } else if (typeof value === 'function') {
248
+ var text = template == null ? null : template.slice(token[3], token[5]);
249
+ value = value.call(context.view, text, function (template) {
250
+ return writer.render(template, context);
251
+ });
252
+ if (value != null) buffer += value;
253
+ } else if (value) {
254
+ buffer += renderTokens(token[4], writer, context, template);
255
+ }
256
+
257
+ break;
258
+ case '^':
259
+ value = context.lookup(tokenValue);
260
+
261
+ // Use JavaScript's definition of falsy. Include empty arrays.
262
+ // See https://github.com/janl/mustache.js/issues/186
263
+ if (!value || (isArray(value) && value.length === 0)) {
264
+ buffer += renderTokens(token[4], writer, context, template);
265
+ }
266
+
267
+ break;
268
+ case '>':
269
+ value = writer.getPartial(tokenValue);
270
+ if (typeof value === 'function') buffer += value(context);
271
+ break;
272
+ case '&':
273
+ value = context.lookup(tokenValue);
274
+ if (value != null) buffer += value;
275
+ break;
276
+ case 'name':
277
+ value = context.lookup(tokenValue);
278
+ if (value != null) buffer += mustache.escape(value);
279
+ break;
280
+ case 'text':
281
+ buffer += tokenValue;
282
+ break;
283
+ }
284
+ }
285
+
286
+ return buffer;
287
+ }
288
+
289
+ /**
290
+ * Forms the given array of `tokens` into a nested tree structure where
291
+ * tokens that represent a section have two additional items: 1) an array of
292
+ * all tokens that appear in that section and 2) the index in the original
293
+ * template that represents the end of that section.
294
+ */
295
+ function nestTokens(tokens) {
296
+ var tree = [];
297
+ var collector = tree;
298
+ var sections = [];
299
+
300
+ var token;
301
+ for (var i = 0, len = tokens.length; i < len; ++i) {
302
+ token = tokens[i];
303
+ switch (token[0]) {
304
+ case '#':
305
+ case '^':
306
+ sections.push(token);
307
+ collector.push(token);
308
+ collector = token[4] = [];
309
+ break;
310
+ case '/':
311
+ var section = sections.pop();
312
+ section[5] = token[2];
313
+ collector = sections.length > 0 ? sections[sections.length - 1][4] : tree;
314
+ break;
315
+ default:
316
+ collector.push(token);
317
+ }
318
+ }
319
+
320
+ return tree;
321
+ }
322
+
323
+ /**
324
+ * Combines the values of consecutive text tokens in the given `tokens` array
325
+ * to a single token.
326
+ */
327
+ function squashTokens(tokens) {
328
+ var squashedTokens = [];
329
+
330
+ var token, lastToken;
331
+ for (var i = 0, len = tokens.length; i < len; ++i) {
332
+ token = tokens[i];
333
+ if (token) {
334
+ if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
335
+ lastToken[1] += token[1];
336
+ lastToken[3] = token[3];
337
+ } else {
338
+ lastToken = token;
339
+ squashedTokens.push(token);
340
+ }
341
+ }
342
+ }
343
+
344
+ return squashedTokens;
345
+ }
346
+
347
+ function escapeTags(tags) {
348
+ return [
349
+ new RegExp(escapeRegExp(tags[0]) + "\\s*"),
350
+ new RegExp("\\s*" + escapeRegExp(tags[1]))
351
+ ];
352
+ }
353
+
354
+ /**
355
+ * Breaks up the given `template` string into a tree of token objects. If
356
+ * `tags` is given here it must be an array with two string values: the
357
+ * opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
358
+ * course, the default is to use mustaches (i.e. Mustache.tags).
359
+ */
360
+ function parseTemplate(template, tags) {
361
+ template = template || '';
362
+ tags = tags || mustache.tags;
363
+
364
+ if (typeof tags === 'string') tags = tags.split(spaceRe);
365
+ if (tags.length !== 2) throw new Error('Invalid tags: ' + tags.join(', '));
366
+
367
+ var tagRes = escapeTags(tags);
368
+ var scanner = new Scanner(template);
369
+
370
+ var sections = []; // Stack to hold section tokens
371
+ var tokens = []; // Buffer to hold the tokens
372
+ var spaces = []; // Indices of whitespace tokens on the current line
373
+ var hasTag = false; // Is there a {{tag}} on the current line?
374
+ var nonSpace = false; // Is there a non-space char on the current line?
375
+
376
+ // Strips all whitespace tokens array for the current line
377
+ // if there was a {{#tag}} on it and otherwise only space.
378
+ function stripSpace() {
379
+ if (hasTag && !nonSpace) {
380
+ while (spaces.length) {
381
+ delete tokens[spaces.pop()];
382
+ }
383
+ } else {
384
+ spaces = [];
385
+ }
386
+
387
+ hasTag = false;
388
+ nonSpace = false;
389
+ }
390
+
391
+ var start, type, value, chr, token;
392
+ while (!scanner.eos()) {
393
+ start = scanner.pos;
394
+
395
+ // Match any text between tags.
396
+ value = scanner.scanUntil(tagRes[0]);
397
+ if (value) {
398
+ for (var i = 0, len = value.length; i < len; ++i) {
399
+ chr = value.charAt(i);
400
+
401
+ if (isWhitespace(chr)) {
402
+ spaces.push(tokens.length);
403
+ } else {
404
+ nonSpace = true;
405
+ }
406
+
407
+ tokens.push(['text', chr, start, start + 1]);
408
+ start += 1;
409
+
410
+ // Check for whitespace on the current line.
411
+ if (chr == '\n') stripSpace();
412
+ }
413
+ }
414
+
415
+ // Match the opening tag.
416
+ if (!scanner.scan(tagRes[0])) break;
417
+ hasTag = true;
418
+
419
+ // Get the tag type.
420
+ type = scanner.scan(tagRe) || 'name';
421
+ scanner.scan(whiteRe);
422
+
423
+ // Get the tag value.
424
+ if (type === '=') {
425
+ value = scanner.scanUntil(eqRe);
426
+ scanner.scan(eqRe);
427
+ scanner.scanUntil(tagRes[1]);
428
+ } else if (type === '{') {
429
+ value = scanner.scanUntil(new RegExp('\\s*' + escapeRegExp('}' + tags[1])));
430
+ scanner.scan(curlyRe);
431
+ scanner.scanUntil(tagRes[1]);
432
+ type = '&';
433
+ } else {
434
+ value = scanner.scanUntil(tagRes[1]);
435
+ }
436
+
437
+ // Match the closing tag.
438
+ if (!scanner.scan(tagRes[1])) throw new Error('Unclosed tag at ' + scanner.pos);
439
+
440
+ token = [type, value, start, scanner.pos];
441
+ tokens.push(token);
442
+
443
+ if (type === '#' || type === '^') {
444
+ sections.push(token);
445
+ } else if (type === '/') {
446
+ // Check section nesting.
447
+ if (sections.length === 0) throw new Error('Unopened section "' + value + '" at ' + start);
448
+ var openSection = sections.pop();
449
+ if (openSection[1] !== value) throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
450
+ } else if (type === 'name' || type === '{' || type === '&') {
451
+ nonSpace = true;
452
+ } else if (type === '=') {
453
+ // Set the tags for the next time around.
454
+ tags = value.split(spaceRe);
455
+ if (tags.length !== 2) throw new Error('Invalid tags at ' + start + ': ' + tags.join(', '));
456
+ tagRes = escapeTags(tags);
457
+ }
458
+ }
459
+
460
+ // Make sure there are no open sections when we're done.
461
+ var openSection = sections.pop();
462
+ if (openSection) throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
463
+
464
+ tokens = squashTokens(tokens);
465
+
466
+ return nestTokens(tokens);
467
+ }
468
+
469
+ mustache.name = "mustache.js";
470
+ mustache.version = "0.7.2";
471
+ mustache.tags = ["{{", "}}"];
472
+
473
+ mustache.Scanner = Scanner;
474
+ mustache.Context = Context;
475
+ mustache.Writer = Writer;
476
+
477
+ mustache.parse = parseTemplate;
478
+
479
+ // Export the escaping function so that the user may override it.
480
+ // See https://github.com/janl/mustache.js/issues/244
481
+ mustache.escape = escapeHtml;
482
+
483
+ // All Mustache.* functions use this writer.
484
+ var defaultWriter = new Writer();
485
+
486
+ /**
487
+ * Clears all cached templates and partials in the default writer.
488
+ */
489
+ mustache.clearCache = function () {
490
+ return defaultWriter.clearCache();
491
+ };
492
+
493
+ /**
494
+ * Compiles the given `template` to a reusable function using the default
495
+ * writer.
496
+ */
497
+ mustache.compile = function (template, tags) {
498
+ return defaultWriter.compile(template, tags);
499
+ };
500
+
501
+ /**
502
+ * Compiles the partial with the given `name` and `template` to a reusable
503
+ * function using the default writer.
504
+ */
505
+ mustache.compilePartial = function (name, template, tags) {
506
+ return defaultWriter.compilePartial(name, template, tags);
507
+ };
508
+
509
+ /**
510
+ * Compiles the given array of tokens (the output of a parse) to a reusable
511
+ * function using the default writer.
512
+ */
513
+ mustache.compileTokens = function (tokens, template) {
514
+ return defaultWriter.compileTokens(tokens, template);
515
+ };
516
+
517
+ /**
518
+ * Renders the `template` with the given `view` and `partials` using the
519
+ * default writer.
520
+ */
521
+ mustache.render = function (template, view, partials) {
522
+ return defaultWriter.render(template, view, partials);
523
+ };
524
+
525
+ // This is here for backwards compatibility with 0.4.x.
526
+ mustache.to_html = function (template, view, partials, send) {
527
+ var result = mustache.render(template, view, partials);
528
+
529
+ if (typeof send === "function") {
530
+ send(result);
531
+ } else {
532
+ return result;
533
+ }
534
+ };
535
+
536
+ }));
@@ -42,7 +42,11 @@ define(['jquery'], function ($) {
42
42
 
43
43
  data.forEach(function (node) {
44
44
  var path = node.file_path.split('/');
45
- path.shift();
45
+
46
+ ['.', 'spec'].forEach(function (v) {
47
+ if (path[0] === v) { path.shift(); }
48
+ });
49
+
46
50
  createNodes(path, node, that.nodes);
47
51
  });
48
52
  };
@@ -11,19 +11,27 @@
11
11
  <label><input type="radio" name="mode" value="count"> Count</label>
12
12
  </form>
13
13
 
14
- <div class='example-wrapper' id='template'>
14
+ <div class='example-wrapper'>
15
+ </div>
16
+
17
+ <script id='template' type='text/x-template'>
15
18
  <ul class='example-details'>
16
- <li id='name'></li>
17
- <li>Line Number: <span id='line_number'></span></li>
18
- <li>Status: <span id='status'></span></li>
19
+ <li class='{{ status }}'><span id='status'>{{ status }}</span></li>
20
+ <li><strong>Description:</strong></li>
21
+ <li class='name'>{{ name }}</li>
22
+ <li><strong>File:</strong></li>
23
+ <li>{{ file_path }}:<span id='line_number'>{{ line_number }}</span></li>
19
24
  <li>
20
- <span id='value'></span> <span id='time_or_count'></span>
25
+ <span id='value'>{{ value }}</span> <span id='time_or_count'> {{ time_or_count }}</span>
21
26
  </li>
22
27
  </ul>
23
- </div>
28
+ </script>
24
29
 
25
30
  <script type='text/javascript' src='<%= url '/js/d3.js' %>'></script>
26
31
  <script type='text/javascript' src='<%= url '/js/plates.js' %>'></script>
27
32
  <script type='text/javascript' data-main='<%= url 'js/script' %>' src='<%= url '/js/require.js' %>'></script>
33
+ <script>
34
+ require.config({ urlArgs: (new Date().getTime())});
35
+ </script>
28
36
  </body>
29
37
  </html>
@@ -1,3 +1,3 @@
1
1
  module RSpectacles
2
- VERSION='0.0.2'
2
+ VERSION='0.0.4'
3
3
  end
data/rspectacles.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = RSpectacles::VERSION
8
8
  s.authors = ['Michael Wheeler']
9
9
  s.email = ['mwheeler@g2crowd.com']
10
- s.homepage = 'https://github.com/wheeyls/rspectacles'
10
+ s.homepage = 'https://github.com/G2Labs-net/rspectacles'
11
11
  s.summary = %q{Visualize rspec test running in the browser}
12
12
  s.description = %q{Visualize rspec test running in the browser}
13
13
 
@@ -23,5 +23,6 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency 'rake'
24
24
  s.add_dependency 'thin', '>= 1.5.0'
25
25
  s.add_dependency 'sinatra', '~> 1.4.3'
26
+ s.add_dependency 'redis'
26
27
  s.add_dependency 'em-hiredis', '~> 0.2.1'
27
28
  end
metadata CHANGED
@@ -1,68 +1,60 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspectacles
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.4
6
5
  platform: ruby
7
6
  authors:
8
7
  - Michael Wheeler
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-09-03 00:00:00.000000000 Z
11
+ date: 2013-09-04 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: thin
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: 1.5.0
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: 1.5.0
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: sinatra
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
@@ -70,15 +62,27 @@ dependencies:
70
62
  type: :runtime
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
77
68
  version: 1.4.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: redis
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
78
83
  - !ruby/object:Gem::Dependency
79
84
  name: em-hiredis
80
85
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
86
  requirements:
83
87
  - - ~>
84
88
  - !ruby/object:Gem::Version
@@ -86,7 +90,6 @@ dependencies:
86
90
  type: :runtime
87
91
  prerelease: false
88
92
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
93
  requirements:
91
94
  - - ~>
92
95
  - !ruby/object:Gem::Version
@@ -102,6 +105,7 @@ files:
102
105
  - .gitignore
103
106
  - Gemfile
104
107
  - Gemfile.lock
108
+ - LICENSE
105
109
  - Rakefile
106
110
  - bin/rspectacles
107
111
  - lib/rspectacles.rb
@@ -111,6 +115,7 @@ files:
111
115
  - lib/rspectacles/app/public/js/d3.js
112
116
  - lib/rspectacles/app/public/js/exampleStream.js
113
117
  - lib/rspectacles/app/public/js/jquery.js
118
+ - lib/rspectacles/app/public/js/mustache.js
114
119
  - lib/rspectacles/app/public/js/pathtree.js
115
120
  - lib/rspectacles/app/public/js/plates.js
116
121
  - lib/rspectacles/app/public/js/require.js
@@ -124,29 +129,28 @@ files:
124
129
  - spec/javascripts/resources/qunit.js
125
130
  - spec/javascripts/test.html
126
131
  - spec/javascripts/tests/pathtree_spec.js
127
- homepage: https://github.com/wheeyls/rspectacles
132
+ homepage: https://github.com/G2Labs-net/rspectacles
128
133
  licenses: []
134
+ metadata: {}
129
135
  post_install_message:
130
136
  rdoc_options: []
131
137
  require_paths:
132
138
  - lib
133
139
  required_ruby_version: !ruby/object:Gem::Requirement
134
- none: false
135
140
  requirements:
136
- - - ! '>='
141
+ - - '>='
137
142
  - !ruby/object:Gem::Version
138
143
  version: '0'
139
144
  required_rubygems_version: !ruby/object:Gem::Requirement
140
- none: false
141
145
  requirements:
142
- - - ! '>='
146
+ - - '>='
143
147
  - !ruby/object:Gem::Version
144
148
  version: '0'
145
149
  requirements: []
146
150
  rubyforge_project: rspectacles
147
- rubygems_version: 1.8.24
151
+ rubygems_version: 2.0.2
148
152
  signing_key:
149
- specification_version: 3
153
+ specification_version: 4
150
154
  summary: Visualize rspec test running in the browser
151
155
  test_files:
152
156
  - spec/javascripts/resources/qunit.css