rspectacles 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,200 @@
1
+ (function (definition) {
2
+ // AMD
3
+ if (typeof define === "function") {
4
+ define(definition);
5
+ // CommonJS
6
+ } else if (typeof exports === "object") {
7
+ definition(this, exports);
8
+ // Browser
9
+ } else {
10
+ definition(this);
11
+ }
12
+ }(function (require, exports, module) {
13
+ "use strict";
14
+ var old,
15
+ _;
16
+
17
+ exports = exports || window;
18
+
19
+ if (!window.setTimeout) {
20
+ return;
21
+ }
22
+
23
+ function stream(userSuppliedStreamFn) {
24
+ var chain = {};
25
+
26
+ function defaultStreamFn(output) {
27
+ var inputs = _.argumentsToArray(arguments);
28
+ inputs.shift();
29
+ if (inputs.length === 0) {
30
+ window.setTimeout(function () {
31
+ output();
32
+ }, 0);
33
+ }
34
+ _.each(inputs, function invokeOutput(input) {
35
+ if (!_.isUndefined(input)) {
36
+ window.setTimeout(function delayedInvokeOutput() {
37
+ output(input);
38
+ }, 0);
39
+ }
40
+ });
41
+ }
42
+
43
+ (function () {
44
+ var outputFns = [], streamFn;
45
+ function outputAllFns() {
46
+ var outputs = _.argumentsToArray(arguments);
47
+ _.each(outputFns, function applyFunction(f) {
48
+ _.applyArgsToFn(f, outputs);
49
+ });
50
+ }
51
+ streamFn = _.isFunction(userSuppliedStreamFn) ? userSuppliedStreamFn : defaultStreamFn;
52
+ chain.invoke = function invoke() {
53
+ var outputs = _.argumentsToArray(arguments);
54
+ outputs.unshift(outputAllFns);
55
+ _.applyArgsToFn(streamFn, outputs);
56
+ return chain;
57
+ };
58
+ chain.onOutput = function onOutput(f) {
59
+ if (!_.isFunction(f)) {
60
+ throw new Error('onOutput expecting callback function');
61
+ }
62
+ outputFns.push(f);
63
+ return chain;
64
+ };
65
+ chain.offOutput = function offOutput(f) {
66
+ if (!_.isFunction(f)) {
67
+ throw new Error('offOutput expecting callback function');
68
+ }
69
+ outputFns = _.reject(outputFns, function isSameAsReferenceInScope(x) {
70
+ return x === f;
71
+ });
72
+ return chain;
73
+ };
74
+ }());
75
+
76
+ (function () {
77
+ var callbacks = [],
78
+ inputStreams = [];
79
+ function wait(streams, idx) {
80
+ var unbindStreams = inputStreams[idx];
81
+ function invokeWithOneArg(x) {
82
+ var outputs = [];
83
+ outputs.length = idx + 1;
84
+ outputs[idx] = x;
85
+ chain.invoke.apply(window, _.isUndefined(x) ? [] : outputs);
86
+ }
87
+ if (unbindStreams) {
88
+ _.each(unbindStreams, function unbindInputs(s) {
89
+ s.offOutput(callbacks[idx]);
90
+ });
91
+ delete callbacks[idx];
92
+ delete inputStreams[idx];
93
+ }
94
+ _.each(streams, function registerOnOutput(stream) {
95
+ stream.onOutput(invokeWithOneArg);
96
+ });
97
+ callbacks[idx] = invokeWithOneArg;
98
+ inputStreams[idx] = streams;
99
+ }
100
+ chain.input = function input() {
101
+ var i, removeStreamIndexes = [];
102
+ _.each(arguments, function bindInputs(inputs, inIdx) {
103
+ if (stream.isStream(inputs)) {
104
+ inputs = [inputs];
105
+ }
106
+ if (_.isArray(inputs)) {
107
+ inputs = _.reject(inputs, function isNotStream(obj) {
108
+ return !stream.isStream(obj);
109
+ });
110
+ wait(inputs, inIdx);
111
+ }
112
+ });
113
+ for (i = arguments.length; i < inputStreams.length; i += 1) {
114
+ removeStreamIndexes.push(i);
115
+ }
116
+ _.each(removeStreamIndexes, function (idx) {
117
+ _.each(inputStreams[idx], function (stream) { stream.offOutput(callbacks[idx]); });
118
+ delete callbacks[idx];
119
+ delete inputStreams[idx];
120
+ });
121
+ return chain;
122
+ };
123
+ }());
124
+ return chain;
125
+ }
126
+
127
+ stream.isStream = function isStream(x) {
128
+ return !!(x && x.invoke && x.onOutput && x.offOutput && x.input);
129
+ };
130
+
131
+ old = exports.stream;
132
+ stream.noConflict = function noConflict() {
133
+ exports.stream = old;
134
+ return stream;
135
+ };
136
+ exports.stream = stream;
137
+
138
+ _ = {
139
+ breaker: {},
140
+ arrayProto: Array.prototype,
141
+ objProto: Object.prototype,
142
+ isArray: Array.isArray || function isArray(obj) {
143
+ return _.objProto.toString.call(obj) === '[object Array]';
144
+ },
145
+ isFunction: function isFunction(obj) {
146
+ return _.objProto.toString.call(obj) === '[object Function]';
147
+ },
148
+ isUndefined: function isUndefined(obj) {
149
+ return obj === void 0;
150
+ },
151
+ argumentsToArray: function argumentsToArray(args) {
152
+ return _.arrayProto.slice.call(args);
153
+ },
154
+ applyArgsToFn: function applyArgsToFn(fn, args) {
155
+ try {
156
+ fn.apply(window, args);
157
+ } catch (e) {
158
+ if (console && console.exception) {
159
+ console.exception(e);
160
+ }
161
+ }
162
+ },
163
+ each: function each(obj, iterator, context) {
164
+ var i, l, key;
165
+ if (obj === null) {
166
+ return;
167
+ }
168
+ if (_.arrayProto.forEach && obj.forEach === _.arrayProto.forEach) {
169
+ obj.forEach(iterator, context);
170
+ } else if (obj.length === +obj.length) {
171
+ for (i = 0, l = obj.length; i < l; i += 1) {
172
+ if (obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj) === _.breaker) {
173
+ return;
174
+ }
175
+ }
176
+ } else {
177
+ for (key in obj) {
178
+ if (obj.hasOwnProperty(key)) {
179
+ if (iterator.call(context, obj[key], key, obj) === _.breaker) {
180
+ return;
181
+ }
182
+ }
183
+ }
184
+ }
185
+ },
186
+ reject: function reject(obj, iterator, context) {
187
+ var results = [];
188
+ if (obj === null) {
189
+ return results;
190
+ }
191
+ _.each(obj, function exclude(value, index, list) {
192
+ if (!iterator.call(context, value, index, list)) {
193
+ results[results.length] = value;
194
+ }
195
+ });
196
+ return results;
197
+ }
198
+ };
199
+
200
+ }));
@@ -0,0 +1,26 @@
1
+ /*global require: true */
2
+ require(['chart', 'exampleStream'], function (chart, examples) {
3
+ 'use strict';
4
+
5
+ var
6
+ bodyEl = document.querySelector('body')
7
+ , uri = bodyEl.dataset.streamUrl
8
+ , streams = examples(uri)
9
+ , c = chart()
10
+ ;
11
+
12
+ streams.start.onOutput(function (data) {
13
+ c.reset();
14
+ });
15
+
16
+ streams.message.onOutput(function (data) {
17
+ console.log('message logged', data);
18
+ });
19
+
20
+ streams.example.onOutput(function (data) {
21
+ c.push(data);
22
+ });
23
+
24
+ c.render();
25
+ window.c = c;
26
+ });
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <title>RSpectacles</title>
6
+ <link rel='stylesheet' href='<%= url 'css/style.css' %>' />
7
+ </head>
8
+ <body data-stream-url=<%= url '/stream' %>>
9
+ <form>
10
+ <label><input type="radio" name="mode" value="size" checked> Time</label>
11
+ <label><input type="radio" name="mode" value="count"> Count</label>
12
+ </form>
13
+
14
+ <div class='example-wrapper' id='template'>
15
+ <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>
20
+ <span id='value'></span> <span id='time_or_count'></span>
21
+ </li>
22
+ </ul>
23
+ </div>
24
+
25
+ <script type='text/javascript' src='<%= url '/js/d3.js' %>'></script>
26
+ <script type='text/javascript' src='<%= url '/js/plates.js' %>'></script>
27
+ <script type='text/javascript' data-main='<%= url 'js/script' %>' src='<%= url '/js/require.js' %>'></script>
28
+ </body>
29
+ </html>
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'json'
4
+ require 'em-hiredis'
5
+ require 'uri'
6
+ require 'thin'
7
+ require 'pry'
8
+
9
+ # Helpers
10
+ # require './lib/render_partial'
11
+ # require './db/config'
12
+
13
+
14
+ module RSpectacles
15
+ class App < Sinatra::Base
16
+ connections = []
17
+ dir = File.dirname(File.expand_path(__FILE__))
18
+ set :app_file, __FILE__
19
+ set :root, dir
20
+ set :views, "#{dir}/app/views"
21
+ set :static, true
22
+
23
+ if respond_to? :public_folder
24
+ set :public_folder, "#{dir}/app/public"
25
+ else
26
+ set :public, "#{dir}/app/public"
27
+ end
28
+
29
+ uri = URI.parse 'redis://127.0.0.1:6379/'
30
+ $emredis = nil
31
+
32
+ # Routes
33
+ get '/' do
34
+ erb :index
35
+ end
36
+
37
+ get '/stream', :provides => 'text/event-stream' do
38
+ stream :keep_open do |out|
39
+ connections << out
40
+ out.callback { connections.delete(out) }
41
+ dump_last_run out
42
+ end
43
+ end
44
+
45
+ def dump_last_run(out)
46
+ $emredis.lrange('redis-rspec-last-run', 0, -1) do |list|
47
+ list.each { |msg| out << "data: #{msg}\n\n" }
48
+ end
49
+ end
50
+
51
+ EM.next_tick do
52
+ $emredis = EM::Hiredis.connect(uri)
53
+
54
+ $emredis.pubsub.subscribe 'redis-rspec-examples' do |message|
55
+ connections.each { |out| out << "data: #{message}\n\n" }
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,84 @@
1
+ require 'rspec/core/formatters/base_formatter'
2
+ require 'ostruct'
3
+ require 'redis'
4
+
5
+ module RSpectacles
6
+ class RedisFormatter < RSpec::Core::Formatters::BaseFormatter
7
+ attr_accessor :redis
8
+
9
+ class << self
10
+ def config
11
+ OpenStruct.new({
12
+ channel_name: 'redis-rspec-examples',
13
+ last_run_key: 'redis-rspec-last-run',
14
+ port: 6379,
15
+ host: '127.0.0.1',
16
+ password: ''
17
+ })
18
+ end
19
+ end
20
+
21
+ def initialize(output)
22
+ self.redis = Redis.new host: config.host, port: config.port
23
+ end
24
+
25
+ def message(message)
26
+ log "message:#{message}"
27
+ end
28
+
29
+ def start(example_count)
30
+ log 'status:start'
31
+ redis.del config.last_run_key
32
+ end
33
+
34
+ def stop
35
+ log 'status:stop'
36
+ end
37
+
38
+ def example_started(example)
39
+ end
40
+
41
+ def example_passed(example)
42
+ log_formatted example
43
+ end
44
+
45
+ def example_pending(example)
46
+ log_formatted example
47
+ end
48
+
49
+ def example_failed(example)
50
+ log_formatted example
51
+ end
52
+
53
+ def close
54
+ end
55
+
56
+ private
57
+
58
+ def config
59
+ self.class.config
60
+ end
61
+
62
+ def log(message)
63
+ redis.publish config.channel_name, message
64
+ redis.lpush config.last_run_key, message
65
+ end
66
+
67
+ def log_formatted(example)
68
+ message = format_example(example)
69
+ redis.publish config.channel_name, message
70
+ redis.lpush config.last_run_key, message
71
+ end
72
+
73
+ def format_example(example)
74
+ {
75
+ :description => example.description,
76
+ :full_description => example.full_description,
77
+ :status => example.execution_result[:status],
78
+ :duration => example.execution_result[:run_time],
79
+ :file_path => example.metadata[:file_path],
80
+ :line_number => example.metadata[:line_number]
81
+ }.to_json
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ module RSpectacles
2
+ VERSION='0.0.1'
3
+ end
@@ -0,0 +1 @@
1
+ require 'rspectacles/app.rb'
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'rspectacles/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'rspectacles'
7
+ s.version = RSpectacles::VERSION
8
+ s.authors = ['Michael Wheeler']
9
+ s.email = ['mwheeler@g2crowd.com']
10
+ s.homepage = 'https://github.com/wheeyls/rspectacles'
11
+ s.summary = %q{Visualize rspec test running in the browser}
12
+ s.description = %q{Visualize rspec test running in the browser}
13
+
14
+ s.rubyforge_project = 'rspectacles'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency 'rspec'
23
+ s.add_dependency 'rake'
24
+ s.add_dependency 'thin', '>= 1.5.0'
25
+ s.add_dependency 'sinatra', '~> 1.4.3'
26
+ s.add_dependency 'em-hiredis', '~> 0.2.1'
27
+ end
@@ -0,0 +1,244 @@
1
+ /**
2
+ * QUnit v1.12.0 - A JavaScript Unit Testing Framework
3
+ *
4
+ * http://qunitjs.com
5
+ *
6
+ * Copyright 2012 jQuery Foundation and other contributors
7
+ * Released under the MIT license.
8
+ * http://jquery.org/license
9
+ */
10
+
11
+ /** Font Family and Sizes */
12
+
13
+ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
14
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
15
+ }
16
+
17
+ #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
18
+ #qunit-tests { font-size: smaller; }
19
+
20
+
21
+ /** Resets */
22
+
23
+ #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
+
29
+ /** Header */
30
+
31
+ #qunit-header {
32
+ padding: 0.5em 0 0.5em 1em;
33
+
34
+ color: #8699a4;
35
+ background-color: #0d3349;
36
+
37
+ font-size: 1.5em;
38
+ line-height: 1em;
39
+ font-weight: normal;
40
+
41
+ border-radius: 5px 5px 0 0;
42
+ -moz-border-radius: 5px 5px 0 0;
43
+ -webkit-border-top-right-radius: 5px;
44
+ -webkit-border-top-left-radius: 5px;
45
+ }
46
+
47
+ #qunit-header a {
48
+ text-decoration: none;
49
+ color: #c2ccd1;
50
+ }
51
+
52
+ #qunit-header a:hover,
53
+ #qunit-header a:focus {
54
+ color: #fff;
55
+ }
56
+
57
+ #qunit-testrunner-toolbar label {
58
+ display: inline-block;
59
+ padding: 0 .5em 0 .1em;
60
+ }
61
+
62
+ #qunit-banner {
63
+ height: 5px;
64
+ }
65
+
66
+ #qunit-testrunner-toolbar {
67
+ padding: 0.5em 0 0.5em 2em;
68
+ color: #5E740B;
69
+ background-color: #eee;
70
+ overflow: hidden;
71
+ }
72
+
73
+ #qunit-userAgent {
74
+ padding: 0.5em 0 0.5em 2.5em;
75
+ background-color: #2b81af;
76
+ color: #fff;
77
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
78
+ }
79
+
80
+ #qunit-modulefilter-container {
81
+ float: right;
82
+ }
83
+
84
+ /** Tests: Pass/Fail */
85
+
86
+ #qunit-tests {
87
+ list-style-position: inside;
88
+ }
89
+
90
+ #qunit-tests li {
91
+ padding: 0.4em 0.5em 0.4em 2.5em;
92
+ border-bottom: 1px solid #fff;
93
+ list-style-position: inside;
94
+ }
95
+
96
+ #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
97
+ display: none;
98
+ }
99
+
100
+ #qunit-tests li strong {
101
+ cursor: pointer;
102
+ }
103
+
104
+ #qunit-tests li a {
105
+ padding: 0.5em;
106
+ color: #c2ccd1;
107
+ text-decoration: none;
108
+ }
109
+ #qunit-tests li a:hover,
110
+ #qunit-tests li a:focus {
111
+ color: #000;
112
+ }
113
+
114
+ #qunit-tests li .runtime {
115
+ float: right;
116
+ font-size: smaller;
117
+ }
118
+
119
+ .qunit-assert-list {
120
+ margin-top: 0.5em;
121
+ padding: 0.5em;
122
+
123
+ background-color: #fff;
124
+
125
+ border-radius: 5px;
126
+ -moz-border-radius: 5px;
127
+ -webkit-border-radius: 5px;
128
+ }
129
+
130
+ .qunit-collapsed {
131
+ display: none;
132
+ }
133
+
134
+ #qunit-tests table {
135
+ border-collapse: collapse;
136
+ margin-top: .2em;
137
+ }
138
+
139
+ #qunit-tests th {
140
+ text-align: right;
141
+ vertical-align: top;
142
+ padding: 0 .5em 0 0;
143
+ }
144
+
145
+ #qunit-tests td {
146
+ vertical-align: top;
147
+ }
148
+
149
+ #qunit-tests pre {
150
+ margin: 0;
151
+ white-space: pre-wrap;
152
+ word-wrap: break-word;
153
+ }
154
+
155
+ #qunit-tests del {
156
+ background-color: #e0f2be;
157
+ color: #374e0c;
158
+ text-decoration: none;
159
+ }
160
+
161
+ #qunit-tests ins {
162
+ background-color: #ffcaca;
163
+ color: #500;
164
+ text-decoration: none;
165
+ }
166
+
167
+ /*** Test Counts */
168
+
169
+ #qunit-tests b.counts { color: black; }
170
+ #qunit-tests b.passed { color: #5E740B; }
171
+ #qunit-tests b.failed { color: #710909; }
172
+
173
+ #qunit-tests li li {
174
+ padding: 5px;
175
+ background-color: #fff;
176
+ border-bottom: none;
177
+ list-style-position: inside;
178
+ }
179
+
180
+ /*** Passing Styles */
181
+
182
+ #qunit-tests li li.pass {
183
+ color: #3c510c;
184
+ background-color: #fff;
185
+ border-left: 10px solid #C6E746;
186
+ }
187
+
188
+ #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
189
+ #qunit-tests .pass .test-name { color: #366097; }
190
+
191
+ #qunit-tests .pass .test-actual,
192
+ #qunit-tests .pass .test-expected { color: #999999; }
193
+
194
+ #qunit-banner.qunit-pass { background-color: #C6E746; }
195
+
196
+ /*** Failing Styles */
197
+
198
+ #qunit-tests li li.fail {
199
+ color: #710909;
200
+ background-color: #fff;
201
+ border-left: 10px solid #EE5757;
202
+ white-space: pre;
203
+ }
204
+
205
+ #qunit-tests > li:last-child {
206
+ border-radius: 0 0 5px 5px;
207
+ -moz-border-radius: 0 0 5px 5px;
208
+ -webkit-border-bottom-right-radius: 5px;
209
+ -webkit-border-bottom-left-radius: 5px;
210
+ }
211
+
212
+ #qunit-tests .fail { color: #000000; background-color: #EE5757; }
213
+ #qunit-tests .fail .test-name,
214
+ #qunit-tests .fail .module-name { color: #000000; }
215
+
216
+ #qunit-tests .fail .test-actual { color: #EE5757; }
217
+ #qunit-tests .fail .test-expected { color: green; }
218
+
219
+ #qunit-banner.qunit-fail { background-color: #EE5757; }
220
+
221
+
222
+ /** Result */
223
+
224
+ #qunit-testresult {
225
+ padding: 0.5em 0.5em 0.5em 2.5em;
226
+
227
+ color: #2b81af;
228
+ background-color: #D2E0E6;
229
+
230
+ border-bottom: 1px solid white;
231
+ }
232
+ #qunit-testresult .module-name {
233
+ font-weight: bold;
234
+ }
235
+
236
+ /** Fixture */
237
+
238
+ #qunit-fixture {
239
+ position: absolute;
240
+ top: -10000px;
241
+ left: -10000px;
242
+ width: 1000px;
243
+ height: 1000px;
244
+ }