rspectacles 0.3.1 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a11e46720615db03ab64f004c98feef3d72ca01
4
- data.tar.gz: bddfb9c9be4d000a0bf98c4159a8daa196999eff
3
+ metadata.gz: 7ad15310a5b2e9712ce803911cd98521cb89bf16
4
+ data.tar.gz: 7ac51e01e5634330dc9c5ff6f109ebc522d7fb83
5
5
  SHA512:
6
- metadata.gz: 3f64c551d1430a41e95aa4253d4110636ad904705f128521982b83fdaed38320992802bdbfbd221389972c7b1c61f3b75dfa69a32cd16856d74f5af23c2c9160
7
- data.tar.gz: 646ea8a1b97d395603222c6820ba36502a72b033fcbd5e7709818ea65f57726b8c831df876a2d38f26a803532f6e7cc1933283bdcf907ae7141cbc80111e7816
6
+ metadata.gz: 739fc4b1b8328491e6e97854718b607fad6e6c4ca3f6256689ad8cc39ff0ba1e70b1ce3358eb6edcaa769635e3286da4c60ecad63fcf309a1a67263005be8bd7
7
+ data.tar.gz: 106d48147ffc87cf7e8416920cf7e7b1529694810c50ec0e3100320edd323be292eeb69f5c44ddad3ba6a0d6bcff5addfdcdb860f4bfb43f9b2c5b4580b1323b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspectacles (0.3.1)
4
+ rspectacles (0.4.0)
5
5
  httparty
6
6
  pg
7
7
  puma
data/README.md CHANGED
@@ -54,33 +54,30 @@ Then run your specs and watch the magic happen!
54
54
 
55
55
  ## Web Server
56
56
 
57
- The server can be run in standalone mode:
57
+ The server uses ActiveRecord and Postgres to store the examples.
58
58
 
59
- rspectacles
59
+ Run migrations:
60
+
61
+ # set ENV['DATABASE_URL'] to point to your database, or else database.yml defaults will be used
62
+ rake db:create
63
+ rake db:migrate
60
64
 
61
- Or mounted directly on your app:
65
+ Start the server:
62
66
 
63
- # routes.rb
64
- mount RSpectacles::App => '/rspectacles'
67
+ puma
65
68
 
66
69
  ## Configuration
67
- If you need to change any settings, the best method is to create a yaml file
68
- with your settings, and set the ```RSPECTACLES_CONFIG``` environment variable so
69
- that both the server and formatter can locate the file.
70
-
71
- For instance:
72
-
73
- ```sh
74
- export RSPECTACLES_CONFIG='/path/to/config/rspectacles.yml'
75
- ```
76
-
77
- And in ```rspectacles.yml```:
78
- ```yaml
79
- sinatra_port: 4567
80
- batch_size: 500
81
- rspectacles_url: 'http://127.0.0.1:4567/'
82
- last_run_primary_key: 'redis-rspec-last-run'
83
- ```
70
+
71
+ Configuration settings can all be set through environment variables:
72
+
73
+ # server settings
74
+ RSPECTACLES_PORT = 4567
75
+
76
+ # client settings
77
+ RSPECTACLES_URL = nil
78
+ RSPECTACLES_RUN_KEY = 'rspec-current-run'
79
+ RSPECTACLES_BATCH_SIZE = 1000
80
+ RSPECTACLES_TIMEOUT = 15
84
81
 
85
82
  ## Contributing
86
83
 
data/bin/console ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle exec irb -r rspectacles/app
@@ -0,0 +1,20 @@
1
+ require 'rspectacles/app/models/example'
2
+ require 'rspectacles/app/models/run'
3
+
4
+ class CreateRuns < ActiveRecord::Migration[5.1]
5
+ def change
6
+ create_table :runs do |t|
7
+ t.integer :total_time
8
+ t.string :rspec_run, null: false
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :runs, :rspec_run, unique: true
14
+ add_reference :examples, :run
15
+
16
+ Example.all.distinct.pluck(:rspec_run).each do |run|
17
+ Run.where(rspec_run: run).first_or_create
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ class AssociateRuns < ActiveRecord::Migration[5.1]
2
+ def up
3
+ add_column :examples, :duration, :numeric, null: false, default: 0
4
+ remove_column :runs, :total_time
5
+
6
+ Run.all.find_each do |r|
7
+ r.update_attributes id: r.rspec_run
8
+ end
9
+
10
+ count = Example.all.size
11
+ Example.all.find_each do |e|
12
+ e.update_column :duration, e.properties['duration'].to_f
13
+
14
+ count -= 1
15
+ puts count
16
+ end
17
+ end
18
+
19
+ def down
20
+ remove_column :examples, :duration
21
+ add_column :runs, :total_time, :integer
22
+ end
23
+ end
data/db/schema.rb CHANGED
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20170907205819) do
13
+ ActiveRecord::Schema.define(version: 20170912175547) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -18,7 +18,17 @@ ActiveRecord::Schema.define(version: 20170907205819) do
18
18
  create_table "examples", force: :cascade do |t|
19
19
  t.string "rspec_run", null: false
20
20
  t.text "properties"
21
+ t.bigint "run_id"
22
+ t.decimal "duration", default: "0.0", null: false
21
23
  t.index ["rspec_run"], name: "index_examples_on_rspec_run"
24
+ t.index ["run_id"], name: "index_examples_on_run_id"
25
+ end
26
+
27
+ create_table "runs", force: :cascade do |t|
28
+ t.string "rspec_run", null: false
29
+ t.datetime "created_at", null: false
30
+ t.datetime "updated_at", null: false
31
+ t.index ["rspec_run"], name: "index_runs_on_rspec_run", unique: true
22
32
  end
23
33
 
24
34
  end
@@ -39,7 +39,7 @@ module RSpectacles
39
39
  end
40
40
 
41
41
  def post_results(messages)
42
- HTTParty.post(full_uri, timeout: 5,
42
+ HTTParty.post(full_uri, timeout: config.timeout,
43
43
  body: { examples: messages }.to_json,
44
44
  headers: { 'Content-Type' => 'application/json' })
45
45
  rescue Net::ReadTimeout
@@ -1,4 +1,5 @@
1
1
  class Example < ActiveRecord::Base
2
+ belongs_to :run, primary_key: :rspec_run, foreign_key: :rspec_run
2
3
  serialize :properties, Hash
3
4
 
4
5
  def as_json(*_)
@@ -0,0 +1,11 @@
1
+ class Run < ActiveRecord::Base
2
+ has_many :examples, primary_key: :rspec_run, foreign_key: :rspec_run
3
+
4
+ def total_count
5
+ @total_count ||= examples.size
6
+ end
7
+
8
+ def runtime
9
+ @runtime ||= examples.sum(:duration)
10
+ end
11
+ end
@@ -1,3 +1,11 @@
1
+ table {
2
+ }
3
+
4
+ th, td {
5
+ text-align: left;
6
+ padding: 8px 16px;
7
+ }
8
+
1
9
  ul {
2
10
  border: 1px solid #eee;
3
11
  list-style-type: none;
@@ -1,5 +1,5 @@
1
1
  /*global define: true d3: true */
2
- define(['jquery', 'pathtree', 'mustache'], function ($, PathTree, Mustache) {
2
+ define(['jquery', 'pathtree', 'details', 'mustache'], function ($, PathTree, details) {
3
3
  'use strict';
4
4
 
5
5
 
@@ -62,31 +62,6 @@ define(['jquery', 'pathtree', 'mustache'], function ($, PathTree, Mustache) {
62
62
  return pad(min) + ':' + pad(sec);
63
63
  }
64
64
 
65
- function showDetails() {
66
- var data = showDetails.current
67
- , mappedData = $.extend({
68
- name: ''
69
- , line_number: ''
70
- , status: ''
71
- , duration: ''
72
- , time_or_count: options.isCount ? 'Examples' : 'ms'
73
- , minutes: ''
74
- , value: null
75
- }, data)
76
- , map
77
- ;
78
-
79
- if (mappedData.value) {
80
- if (!options.isCount) {
81
- mappedData.minutes = secToMin(mappedData.value);
82
- mappedData.value = parseInt(mappedData.value * 1000);
83
- }
84
- }
85
-
86
- $('.example-wrapper').html(Mustache.render(tmpl, mappedData));
87
- }
88
- showDetails.current = {};
89
-
90
65
  function getValue() {
91
66
  return options.isCount ?
92
67
  function () { return 1; } :
@@ -106,7 +81,7 @@ define(['jquery', 'pathtree', 'mustache'], function ($, PathTree, Mustache) {
106
81
  .attr("d", arc)
107
82
  .each(stash)
108
83
  .style("fill", getColor)
109
- .call(showDetails);
84
+ .call(details.update);
110
85
  }
111
86
 
112
87
  function onEnter(path) {
@@ -117,11 +92,8 @@ define(['jquery', 'pathtree', 'mustache'], function ($, PathTree, Mustache) {
117
92
  .style("fill", getColor)
118
93
  .style("fill-rule", "evenodd")
119
94
  .each(stash)
120
- .on('mouseover', function (d) {
121
- showDetails.current = d;
122
- showDetails();
123
- })
124
- .call(showDetails);
95
+ .on('mouseover', details.update)
96
+ .call(details.update);
125
97
  }
126
98
 
127
99
  function onExit(path) {
@@ -0,0 +1,51 @@
1
+ define(['jquery', 'mustache'], function ($, Mustache) {
2
+ var me
3
+ , defaults
4
+ , current = {}
5
+ , tmpl = $('#template').html()
6
+ , isCount = false
7
+ ;
8
+
9
+ defaults = function () {
10
+ return {
11
+ name: ''
12
+ , line_number: ''
13
+ , status: ''
14
+ , duration: ''
15
+ , time_or_count: isCount ? 'Examples' : 'ms'
16
+ , minutes: ''
17
+ , value: null
18
+ };
19
+ };
20
+
21
+ function secToMin(time) {
22
+ var pad = function (val) { return ('00' + val).slice(-2); }
23
+ , min = parseInt(time / 60)
24
+ , sec = parseInt(time % 60)
25
+ ;
26
+
27
+ return pad(min) + ':' + pad(sec);
28
+ }
29
+
30
+ function render() {
31
+ if (current.value) {
32
+ if (!isCount) {
33
+ current.minutes = secToMin(current.value);
34
+ current.value = parseInt(current.value * 1000);
35
+ }
36
+ }
37
+
38
+ $('.example-wrapper').html(Mustache.render(tmpl, current));
39
+ }
40
+
41
+ return {
42
+ update: function (d) {
43
+ current = $.extend({}, defaults(), d);
44
+ render();
45
+ }
46
+
47
+ , isCount: function (value) {
48
+ isCount = value;
49
+ }
50
+ };
51
+ });
@@ -22,28 +22,32 @@ define(['riffle'], function (riffle) {
22
22
 
23
23
  function batched(delay, maxSize) {
24
24
  var batch = []
25
+ , timer
25
26
  ;
26
27
 
27
28
  delay = delay || 100;
29
+ maxSize = maxSize || 100;
28
30
 
29
- return stream(function (o, i) {
30
- batch = batch.concat(i);
31
-
32
- function clear() {
33
- batch.length > 0 && o(batch);
34
- batch = [];
31
+ function clear(o) {
32
+ if (batch.length > 0) {
33
+ o(batch.splice(0, maxSize));
35
34
  }
36
35
 
37
- if (maxSize && batch.length > maxSize) {
38
- clear();
39
- } else {
40
- setTimeout(clear, delay);
36
+ if (batch.length < 1) {
37
+ clearInterval(timer);
38
+ timer = null;
41
39
  }
40
+ }
41
+
42
+ return stream(function (o, i) {
43
+ batch = batch.concat(i);
44
+
45
+ if (!timer) { timer = setInterval(function () { clear(o); }, delay); }
42
46
  });
43
47
  }
44
48
 
45
49
  jsonEvents = each.input(ajaxStream(ajaxUri).invoke());
46
50
 
47
- return { example: batched().input(jsonEvents) };
51
+ return { example: batched(10, 1000).input(jsonEvents) };
48
52
  };
49
53
  });
@@ -0,0 +1,24 @@
1
+ define(function () {
2
+ return function () {
3
+ var isCount = false;
4
+ var me;
5
+
6
+ d3.selectAll("input").on("change", function () {
7
+ var newCount = this.value === 'count';
8
+
9
+ if (newCount !== isCount) {
10
+ isCount = newCount;
11
+ me.onChange(isCount);
12
+ }
13
+ });
14
+
15
+ return me = {
16
+ isCount: function () {
17
+ return isCount;
18
+ },
19
+
20
+ onChange: function () {
21
+ }
22
+ }
23
+ }
24
+ });
@@ -1,5 +1,5 @@
1
1
  /*global require: true */
2
- require(['chart', 'exampleStream'], function (chart, examples) {
2
+ require(['zoomable', 'exampleStream'], function (chart, examples) {
3
3
  'use strict';
4
4
 
5
5
  var
@@ -0,0 +1,131 @@
1
+ define(['jquery', 'pathtree', 'details', 'form'], function ($, PathTree, details, countForm) {
2
+ return function (options) {
3
+ var width = 960,
4
+ height = 700,
5
+ radius = (Math.min(width, height) / 2) - 10,
6
+ form = countForm(),
7
+ me;
8
+
9
+ function arcTween(a) {
10
+ var i = d3.interpolate({ x: a.x0, dx: a.dx0 }, a);
11
+ return function tweener(t) {
12
+ var b = i(t);
13
+ a.x0 = b.x;
14
+ a.dx0 = b.dx;
15
+ return arc(b);
16
+ };
17
+ }
18
+
19
+ var x = d3.scale.linear()
20
+ .range([0, 2 * Math.PI]);
21
+
22
+ var y = d3.scale.sqrt()
23
+ .range([0, radius]);
24
+
25
+ var color = d3.scale.category20c();
26
+
27
+ var partition = d3.layout.partition()
28
+ .sort(function(a, b) { return d3.ascending(a.name, b.name); })
29
+ .value(function(d) { return d.size; });
30
+
31
+ var arc = d3.svg.arc()
32
+ .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
33
+ .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
34
+ .innerRadius(function(d) { return Math.max(0, y(d.y)); })
35
+ .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
36
+
37
+ var svg = d3.select("body").append("svg")
38
+ .attr("width", width)
39
+ .attr("height", height)
40
+ .append("g")
41
+ .attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")");
42
+
43
+ function getValue() {
44
+ return form.isCount() ?
45
+ function () { return 1; } :
46
+ function (d) { return d.size; };
47
+ }
48
+
49
+ function getColor(d) {
50
+ if (d.status && d.status === 'failed') {
51
+ return '#f00';
52
+ } else {
53
+ return color(((d.children ? d : d.parent) || {}).name);
54
+ }
55
+ }
56
+
57
+ function stash(d) {
58
+ d.x0 = d.x;
59
+ d.dx0 = d.dx;
60
+ }
61
+
62
+
63
+ function onUpdate(path) {
64
+ path
65
+ .attr("d", arc)
66
+ .each(stash)
67
+ .style("fill", getColor);
68
+ }
69
+
70
+ var render = function () {
71
+ var path = svg.datum(me.tree.nodes).selectAll("path")
72
+ .data(partition.value(getValue()).nodes);
73
+
74
+ onUpdate(path);
75
+ path
76
+ .enter().append("path")
77
+ .on('mouseover', details.update)
78
+ .attr("d", arc)
79
+ .style("fill", getColor)
80
+ .style("stroke", function (d) { return 'rgba(255,255,255,0.3)'; })
81
+ .style("fill-rule", "evenodd")
82
+ .on("click", click);
83
+
84
+ form.onChange = function (isCount) {
85
+ details.isCount(isCount);
86
+
87
+ path
88
+ .data(partition.value(getValue()).nodes)
89
+ .transition()
90
+ .duration(1500)
91
+ .attrTween("d", arcTween);
92
+ };
93
+
94
+ render = function () {
95
+ path.datum(me.tree.nodes)
96
+ .data(partition.value(getValue()).nodes);
97
+ };
98
+ };
99
+
100
+ function click(d) {
101
+ svg.transition()
102
+ .duration(750)
103
+ .tween("scale", function() {
104
+ var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
105
+ yd = d3.interpolate(y.domain(), [d.y, 1]),
106
+ yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
107
+ return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); };
108
+ })
109
+ .selectAll("path")
110
+ .attrTween("d", function(d) { return function() { return arc(d); }; });
111
+ }
112
+
113
+ d3.select(self.frameElement).style("height", height + "px");
114
+
115
+ return me = {
116
+ tree: new PathTree(),
117
+
118
+ render: render,
119
+
120
+ reset: function () {
121
+ me.tree = new PathTree();
122
+ me.render();
123
+ },
124
+
125
+ push: function (data) {
126
+ me.tree.add(data);
127
+ me.render();
128
+ }
129
+ };
130
+ }
131
+ });
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <title>RSpectacles</title>
6
+ <link rel='stylesheet' href='<%= versioned_stylesheet 'style' %>' />
7
+ </head>
8
+ <body>
9
+ <table>
10
+ <tr>
11
+ <th>Run</th>
12
+ <th>Examples</th>
13
+ <th>Time</th>
14
+ <th>Created At</th>
15
+ </tr>
16
+ <% @runs.each do |run| %>
17
+ <tr>
18
+ <td>
19
+ <a href='/watch/<%= run.rspec_run %>'>Run #<%= run.rspec_run %></a>
20
+ </td>
21
+ <td>
22
+ <%= run.examples.size %>
23
+ </td>
24
+ <td>
25
+ <% mm, ss = run.runtime.divmod(60) %>
26
+ <%= mm.to_i %>:<%= ss.to_i.to_s.rjust(2, '0') %>
27
+ </td>
28
+ <td>
29
+ <%= run.created_at.strftime('%Y-%m-%d %H:%M:%S') %>
30
+ </td>
31
+ </tr>
32
+ <% end %>
33
+ </table>
34
+ </body>
@@ -4,6 +4,7 @@ require 'json'
4
4
  require 'sinatra/activerecord'
5
5
  require 'rspectacles/config.rb'
6
6
  require 'rspectacles/app/models/example'
7
+ require 'rspectacles/app/models/run'
7
8
  require 'puma'
8
9
 
9
10
  module RSpectacles
@@ -27,6 +28,11 @@ module RSpectacles
27
28
  end
28
29
 
29
30
  # Routes
31
+ get '/' do
32
+ @runs = Run.all.limit(25).order(created_at: :desc)
33
+ erb :runs
34
+ end
35
+
30
36
  get '/watch/:key' do
31
37
  erb :index
32
38
  end
@@ -43,11 +49,14 @@ module RSpectacles
43
49
  post '/examples' do
44
50
  payload = JSON.parse(request.body.read)
45
51
 
52
+ run = Run.where(rspec_run: payload['examples'].first['rspec_run']).first_or_create
46
53
  data = payload['examples'].map do |args|
47
- { rspec_run: args['rspec_run'], properties: args }
54
+ { rspec_run: args['rspec_run'], duration: args['duration'].to_f, properties: args }
48
55
  end
49
56
 
50
- { errors: Example.create(data).count { |i| !i.persisted? } }.to_json
57
+ examples = Example.create(data)
58
+
59
+ { errors: examples.count { |i| !i.persisted? } }.to_json
51
60
  end
52
61
  end
53
62
  end
@@ -11,8 +11,9 @@ module RSpectacles
11
11
  def defaults
12
12
  {
13
13
  sinatra_port: ENV['RSPECTACLES_PORT'] || ENV['PORT'] || 4567,
14
- batch_size: (ENV['RSPECTACLES_BATCH_SIZE'] || 100).to_i,
15
- last_run_primary_key: ENV['RSPECTACLES_LAST_RUN_KEY'] || ENV['CIRCLE_BUILD_NUM'] || 'rspec-last-run',
14
+ batch_size: (ENV['RSPECTACLES_BATCH_SIZE'] || 1000).to_i,
15
+ last_run_primary_key: ENV['RSPECTACLES_RUN_KEY'] || ENV['CIRCLE_BUILD_NUM'] || 'rspec-current-run',
16
+ timeout: (ENV['RSPECTACLES_TIMEOUT'] || 15).to_i,
16
17
  rspectacles_url: ENV['RSPECTACLES_URL']
17
18
  }
18
19
  end
@@ -1,3 +1,3 @@
1
1
  module RSpectacles
2
- VERSION = '0.3.1'
2
+ VERSION = '0.4.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspectacles
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Wheeler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-08 00:00:00.000000000 Z
11
+ date: 2017-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -126,7 +126,7 @@ description: Visualize rspec test running in the browser
126
126
  email:
127
127
  - mwheeler@g2crowd.com
128
128
  executables:
129
- - rspectacles
129
+ - console
130
130
  extensions: []
131
131
  extra_rdoc_files: []
132
132
  files:
@@ -138,9 +138,11 @@ files:
138
138
  - Procfile
139
139
  - README.md
140
140
  - Rakefile
141
- - bin/rspectacles
141
+ - bin/console
142
142
  - config.ru
143
143
  - db/migrate/20170907205819_create_examples_table.rb
144
+ - db/migrate/20170912153508_create_runs.rb
145
+ - db/migrate/20170912175547_associate_runs.rb
144
146
  - db/schema.rb
145
147
  - lib/rspectacles.rb
146
148
  - lib/rspectacles/adapter/batched_logger.rb
@@ -148,10 +150,13 @@ files:
148
150
  - lib/rspectacles/app.rb
149
151
  - lib/rspectacles/app/helpers.rb
150
152
  - lib/rspectacles/app/models/example.rb
153
+ - lib/rspectacles/app/models/run.rb
151
154
  - lib/rspectacles/app/public/css/style.css
152
155
  - lib/rspectacles/app/public/js/chart.js
153
156
  - lib/rspectacles/app/public/js/d3.js
157
+ - lib/rspectacles/app/public/js/details.js
154
158
  - lib/rspectacles/app/public/js/exampleStream.js
159
+ - lib/rspectacles/app/public/js/form.js
155
160
  - lib/rspectacles/app/public/js/jquery.js
156
161
  - lib/rspectacles/app/public/js/mustache.js
157
162
  - lib/rspectacles/app/public/js/pathtree.js
@@ -159,7 +164,9 @@ files:
159
164
  - lib/rspectacles/app/public/js/require.js
160
165
  - lib/rspectacles/app/public/js/riffle.js
161
166
  - lib/rspectacles/app/public/js/script.js
167
+ - lib/rspectacles/app/public/js/zoomable.js
162
168
  - lib/rspectacles/app/views/index.erb
169
+ - lib/rspectacles/app/views/runs.erb
163
170
  - lib/rspectacles/config.rb
164
171
  - lib/rspectacles/config/database.yml
165
172
  - lib/rspectacles/formatter/base.rb
data/bin/rspectacles DELETED
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- begin
4
- require 'rspectacles/app.rb'
5
- rescue LoadError => e
6
- require 'rubygems'
7
- path = File.expand_path '../../lib', __FILE__
8
- $:.unshift(path) if File.directory?(path) && !$:.include?(path)
9
- require 'rspectacles/app.rb'
10
- end
11
-
12
- Thin::Server.start RSpectacles::App, '0.0.0.0', RSpectacles.config.sinatra_port