shenandoah 0.1.3 → 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 (33) hide show
  1. data/.gitignore +1 -0
  2. data/ChangeLog.markdown +9 -0
  3. data/Rakefile +21 -2
  4. data/VERSION.yml +3 -2
  5. data/features/buildr.feature +29 -0
  6. data/features/example_projects/base/Rakefile +7 -0
  7. data/features/example_projects/base/lib/cells.js +105 -0
  8. data/features/example_projects/base/lib/life.js +30 -0
  9. data/features/example_projects/base/spec/cells.html +13 -0
  10. data/features/example_projects/base/spec/cells_spec.js +234 -0
  11. data/features/example_projects/base/spec/life.html +13 -0
  12. data/features/example_projects/base/spec/life_spec.js +28 -0
  13. data/features/plain-rake.feature +30 -0
  14. data/features/rails.feature +39 -0
  15. data/features/step_definitions/buildr_steps.rb +26 -0
  16. data/features/step_definitions/rails_steps.rb +38 -0
  17. data/features/step_definitions/rake_steps.rb +45 -0
  18. data/features/support/env.rb +48 -0
  19. data/lib/shenandoah/css/shenandoah.sass +138 -0
  20. data/lib/shenandoah/javascript/browser/index.js +18 -0
  21. data/lib/shenandoah/javascript/browser/multirunner-single.js +32 -0
  22. data/lib/shenandoah/javascript/browser/multirunner.js +87 -0
  23. data/lib/shenandoah/javascript/common/jquery.parsequery.js +19 -0
  24. data/lib/shenandoah/server.rb +81 -16
  25. data/lib/shenandoah/server/views/index.haml +18 -8
  26. data/lib/shenandoah/server/views/multirunner.haml +6 -0
  27. data/rails_generators/shen_spec/templates/fixture.html.erb +1 -1
  28. data/rails_generators/shenandoah/templates/application.html +1 -1
  29. data/spec/rails_generators/shen_spec_generator_spec.rb +2 -2
  30. data/spec/rails_generators/shenandoah_generator_spec.rb +3 -3
  31. data/spec/shenandoah/server_spec.rb +156 -15
  32. metadata +32 -3
  33. data/lib/shenandoah/css/screw.css +0 -90
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ rdoc
5
5
  pkg
6
6
  spec/tmp
7
7
  *.gemspec
8
+ .sass-cache
@@ -1,3 +1,12 @@
1
+ 0.2.0
2
+ =====
3
+
4
+ * Running multiple specs in-browser using iframes (issue #5)
5
+ * Use a single stylesheet for single specs, multirunner, and index page
6
+ * Allow override of the default runner stylesheet using a file at the root of spec_path; either shenandoah.sass or shenandoah.css
7
+ * Stop publishing the gem to rubyforge (but continue deploying rdoc there)
8
+ * Basic full-execution test coverage with cucumber features
9
+
1
10
  0.1.3
2
11
  =====
3
12
 
data/Rakefile CHANGED
@@ -18,6 +18,7 @@ begin
18
18
  gem.add_runtime_dependency('haml', '>= 2.0.9')
19
19
  gem.add_runtime_dependency('rake')
20
20
  gem.add_runtime_dependency('rails', '>= 2.1.0')
21
+ gem.add_runtime_dependency('compass')
21
22
 
22
23
  # Have to use rspec 1.2.4 for buildr compat
23
24
  gem.add_development_dependency('rspec', '= 1.2.4')
@@ -25,7 +26,7 @@ begin
25
26
  gem.add_development_dependency('hpricot', '>= 0.8.1')
26
27
  gem.add_development_dependency('rspec_hpricot_matchers', '>= 1.0.0')
27
28
  gem.add_development_dependency('braid', '>= 0.5.0')
28
-
29
+
29
30
  # These are the dependencies for the vendored buildr (used for testing)
30
31
  gem.add_development_dependency('rake', '= 0.8.4')
31
32
  gem.add_development_dependency('net-ssh', '= 2.0.11')
@@ -62,6 +63,20 @@ Spec::Rake::SpecTask.new(:rcov) do |spec|
62
63
  spec.rcov_opts = ['--exclude', "spec/*,/Library/Ruby/*"]
63
64
  end
64
65
 
66
+ begin
67
+ require 'cucumber'
68
+ require 'cucumber/rake/task'
69
+
70
+ Cucumber::Rake::Task.new(:features) do |t|
71
+ t.cucumber_opts = "features --format pretty"
72
+ end
73
+ rescue LoadError
74
+ desc 'Cucumber rake task not available'
75
+ task :features do
76
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
77
+ end
78
+ end
79
+
65
80
  task :default => :spec
66
81
 
67
82
  def version
@@ -88,6 +103,10 @@ end
88
103
 
89
104
  # Disable github release since I don't want to commit the gemspec
90
105
  Rake::Task[:release].prerequisites.delete 'github:release'
106
+ # Disable rubyforge releasing, but keep rdoc deployment task
107
+ Rake::Task[:release].prerequisites.delete 'rubyforge:release'
91
108
 
92
109
  task :build => [:gemspec]
93
- task :install => [:uninstall]
110
+ task :install => [:uninstall]
111
+
112
+ task :ci => [:features, :spec]
@@ -1,4 +1,5 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 1
4
- :patch: 3
3
+ :minor: 2
4
+ :build:
5
+ :patch: 0
@@ -0,0 +1,29 @@
1
+ Feature: Testing buildr projects
2
+
3
+ Scenario: Defined tasks
4
+ Given a buildr project
5
+ When I list the available buildr tasks
6
+ Then the task list should include life:shen:serve
7
+ And the task list should include life:shen:generate
8
+ And the task list should include life:shen:shell
9
+
10
+ Scenario: Running the server
11
+ Given a buildr project
12
+ When I execute `buildr life:shen:serve`
13
+ Then the server should be running
14
+
15
+ Scenario: Running all specs
16
+ Given a buildr project
17
+ When I execute `buildr test`
18
+ Then 49 specs should run
19
+
20
+ Scenario: Running one spec
21
+ Given a buildr project
22
+ When I execute `buildr test:life_spec`
23
+ Then 1 spec should run
24
+
25
+ Scenario: Generating a spec
26
+ Given a buildr project
27
+ When I execute `buildr life:shen:generate[pre_view]`
28
+ Then the file "src/spec/javascript/pre_view_spec.js" should exist
29
+ And the file "src/spec/javascript/pre_view.html" should exist
@@ -0,0 +1,7 @@
1
+ begin
2
+ dev_shen = File.expand_path('../../..', File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(dev_shen, 'lib'))
4
+ end
5
+
6
+ require 'shenandoah/tasks'
7
+ Shenandoah::Tasks.new
@@ -0,0 +1,105 @@
1
+ Cell = function (initialState) {
2
+ this.willSurvive = true;
3
+ this.age = (initialState && initialState.age) || 0;
4
+
5
+ this.alive = function () {
6
+ return this.age > 0;
7
+ };
8
+
9
+ this.advance = function () {
10
+ if (this.willSurvive) {
11
+ this.age += 1;
12
+ } else {
13
+ this.age = 0;
14
+ }
15
+ };
16
+ };
17
+
18
+ Cells = function () {
19
+ var matrix;
20
+
21
+ function buildMatrix(rows, columns) {
22
+ matrix = new Array(rows);
23
+ var i, j;
24
+ for (i = 0 ; i < rows ; i++) {
25
+ matrix[i] = new Array(columns);
26
+ for (j = 0 ; j < columns ; j++) {
27
+ matrix[i][j] = new Cell();
28
+ }
29
+ }
30
+ }
31
+
32
+ function initializeMatrix(args) {
33
+ if (args.length == 1) {
34
+ var input = args[0];
35
+ var rows = input.length; var cols = input[0].length;
36
+ buildMatrix(rows, cols);
37
+ var i, j, item;
38
+ for (i = 0 ; i < rows ; i++) {
39
+ for (j = 0 ; j < cols ; j++) {
40
+ item = input[i][j];
41
+ age = 0;
42
+ if (item) {
43
+ if (!isNaN(parseInt(item))) {
44
+ age = parseInt(item);
45
+ } else if (item === '+') {
46
+ age = 1;
47
+ } else if (item === '.') {
48
+ age = 0;
49
+ } else if (item.match) {
50
+ age = item.match(/\S/) ? 1 : 0;
51
+ } else {
52
+ age = 1;
53
+ }
54
+ }
55
+ matrix[i][j].age = age;
56
+ }
57
+ }
58
+ } else if (args.length == 2) {
59
+ buildMatrix(args[0], args[1]);
60
+ }
61
+ }
62
+
63
+ this.get = function (r, c) {
64
+ if (r < 0 || r >= this.rowCount()) {
65
+ return null;
66
+ }
67
+ return matrix[r][c];
68
+ };
69
+
70
+ this.getAdjacency = function (r, c) {
71
+ return new Adjacency({
72
+ nw: this.get(r - 1, c - 1), n: this.get(r - 1, c), ne: this.get(r - 1, c + 1),
73
+ w: this.get(r, c - 1), e: this.get(r, c + 1),
74
+ sw: this.get(r + 1, c - 1), s: this.get(r + 1, c), se: this.get(r + 1, c + 1),
75
+ });
76
+ };
77
+
78
+ this.rowCount = function () {
79
+ return matrix.length;
80
+ };
81
+
82
+ this.columnCount = function () {
83
+ return matrix[0].length;
84
+ };
85
+
86
+ initializeMatrix(arguments);
87
+ };
88
+
89
+ Adjacency = function (adjacentCells) {
90
+ var EDGES = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
91
+
92
+ var self = this;
93
+ var liveCount = 0;
94
+
95
+ jQuery.each(EDGES, function (i, v) {
96
+ self[v] = adjacentCells[v] || new Cell();
97
+ if (self[v].alive()) {
98
+ liveCount += 1;
99
+ }
100
+ });
101
+
102
+ this.liveCount = function () {
103
+ return liveCount;
104
+ }
105
+ };
@@ -0,0 +1,30 @@
1
+ Life = function (cells) {
2
+ var self = this;
3
+
4
+ this.cells = cells;
5
+
6
+ function willLive(r, c) {
7
+ var adj = self.cells.getAdjacency(r, c);
8
+ switch (adj.liveCount()) {
9
+ case 2: // no change
10
+ return self.cells.get(r, c).alive();
11
+ case 3: // always live
12
+ return true;
13
+ default: // alwaysDie
14
+ return false;
15
+ }
16
+ }
17
+
18
+ this.step = function () {
19
+ for (var r = 0 ; r < this.cells.rowCount() ; r++) {
20
+ for (var c = 0 ; c < this.cells.columnCount() ; c++) {
21
+ this.cells.get(r, c).willSurvive = willLive(r, c);
22
+ }
23
+ }
24
+ for (var r = 0 ; r < this.cells.rowCount() ; r++) {
25
+ for (var c = 0 ; c < this.cells.columnCount() ; c++) {
26
+ this.cells.get(r, c).advance();
27
+ }
28
+ }
29
+ };
30
+ }
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+
4
+ <head>
5
+ <title>cells.js | JavaScript Testing Results</title>
6
+ <link rel="stylesheet" href="/shenandoah.css" type="text/css" charset="utf-8" />
7
+ <script type="text/javascript" src="/shenandoah/browser-runner.js"></script>
8
+ </head>
9
+
10
+ <body>
11
+ <!-- Put any HTML fixture elements here. -->
12
+ </body>
13
+ </html>
@@ -0,0 +1,234 @@
1
+ require_main('cells.js');
2
+
3
+ Screw.Unit(function () {
4
+ describe('Cell', function () {
5
+ describe("initialization", function () {
6
+ it("defaults to a dead cell", function () {
7
+ expect((new Cell()).age).to(equal, 0);
8
+ });
9
+
10
+ it("accepts an initial age", function () {
11
+ expect((new Cell({ age: 3 })).age).to(equal, 3);
12
+ });
13
+ });
14
+
15
+ it("is alive if its age is positive", function () {
16
+ expect((new Cell({ age: 4 })).alive()).to(be_true);
17
+ });
18
+
19
+ it("is not alive if its age is zero", function () {
20
+ expect((new Cell({ age: 0 })).alive()).to(be_false);
21
+ });
22
+
23
+ describe("#advance", function () {
24
+ var cell;
25
+
26
+ before(function () {
27
+ cell = new Cell({ age: 5 });
28
+ })
29
+
30
+ it("increments the age if it will survive", function () {
31
+ cell.willSurvive = true;
32
+ cell.advance();
33
+ expect(cell.age).to(equal, 6);
34
+ });
35
+
36
+ it("resets the age if it will not survive", function () {
37
+ cell.willSurvive = false;
38
+ cell.advance();
39
+ expect(cell.age).to(equal, 0);
40
+ });
41
+ });
42
+ });
43
+
44
+ describe('Cells', function () {
45
+ describe("initialization", function () {
46
+ var board;
47
+ describe("from an array of arrays", function () {
48
+ before(function () {
49
+ board = new Cells([
50
+ [true, false, null],
51
+ [0, 1, 2],
52
+ [undefined, "", "s"]
53
+ ]);
54
+ });
55
+
56
+ it("has the right number of rows", function () {
57
+ expect(board.rowCount()).to(equal, 3);
58
+ });
59
+
60
+ it("has the right number of columns", function () {
61
+ expect(board.columnCount()).to(equal, 3);
62
+ });
63
+
64
+ it("treats true as set", function () {
65
+ expect(board.get(0, 0).age).to(equal, 1);
66
+ });
67
+
68
+ it("treats false as not set", function () {
69
+ expect(board.get(0, 1).age).to(equal, 0);
70
+ });
71
+
72
+ it("treats null as not set", function () {
73
+ expect(board.get(0, 2).age).to(equal, 0);
74
+ });
75
+
76
+ it("treats 0 as not set", function () {
77
+ expect(board.get(1, 0).age).to(equal, 0);
78
+ });
79
+
80
+ it("treats 1 as set", function () {
81
+ expect(board.get(1, 1).age).to(equal, 1);
82
+ });
83
+
84
+ it("treats other numbers as an age", function () {
85
+ expect(board.get(1, 2).age).to(equal, 2);
86
+ });
87
+
88
+ it("treats undefined as not set", function () {
89
+ expect(board.get(2, 0).age).to(equal, 0);
90
+ });
91
+
92
+ it("treats an empty string as not set", function () {
93
+ expect(board.get(2, 1).age).to(equal, 0);
94
+ });
95
+
96
+ it("treats a non-empty string as set", function () {
97
+ expect(board.get(2, 2).age).to(equal, 1);
98
+ });
99
+ });
100
+
101
+ describe("from an array of strings", function () {
102
+ before(function () {
103
+ board = new Cells([
104
+ ".++..",
105
+ "..+ .",
106
+ "4.+++"
107
+ ]);
108
+ });
109
+
110
+ it("finds the correct number of rows", function () {
111
+ expect(board.rowCount()).to(equal, 3);
112
+ });
113
+
114
+ it("finds the correct number of columns", function () {
115
+ expect(board.columnCount()).to(equal, 5);
116
+ });
117
+
118
+ it("treats + as set", function () {
119
+ expect(board.get(2, 3).age).to(equal, 1);
120
+ });
121
+
122
+ it("treats a digit as an age", function () {
123
+ expect(board.get(2, 0).age).to(equal, 4);
124
+ });
125
+
126
+ it("treats a . as not set", function () {
127
+ expect(board.get(0, 4).age).to(equal, 0);
128
+ });
129
+
130
+ it("treats a space as not set", function () {
131
+ expect(board.get(1, 3).age).to(equal, 0);
132
+ });
133
+ });
134
+
135
+ describe("from dimensions", function () {
136
+ before(function () {
137
+ board = new Cells(2, 3);
138
+ });
139
+
140
+ it("has the correct number of rows", function () {
141
+ expect(board.rowCount()).to(equal, 2);
142
+ });
143
+
144
+ it("has the correct number of columns", function () {
145
+ expect(board.columnCount()).to(equal, 3);
146
+ });
147
+
148
+ it("initializes the board with empty cells", function () {
149
+ expect(board.get(0, 0).age).to(equal, 0);
150
+ expect(board.get(0, 1).age).to(equal, 0);
151
+ expect(board.get(0, 2).age).to(equal, 0);
152
+ expect(board.get(1, 0).age).to(equal, 0);
153
+ expect(board.get(1, 1).age).to(equal, 0);
154
+ expect(board.get(1, 2).age).to(equal, 0);
155
+ });
156
+ });
157
+ });
158
+
159
+ describe("#get", function () {
160
+ var board;
161
+
162
+ before(function () {
163
+ board = new Cells(3, 2);
164
+ });
165
+
166
+ jQuery.each([
167
+ ['top', [-1, 1]],
168
+ ['right', [ 0, 3]],
169
+ ['bottom', [ 4, 0]],
170
+ ['left', [ 1, -1]]
171
+ ], function (i, v) {
172
+ it("returns null for off-board " + v[0], function () {
173
+ expect(board.get.apply(board, v[1])).to(equal, null);
174
+ });
175
+ });
176
+ });
177
+
178
+ describe("#getAdjacency", function () {
179
+ var board;
180
+
181
+ before(function () {
182
+ board = new Cells([
183
+ ".1..",
184
+ "...2",
185
+ ".543"
186
+ ]);
187
+ });
188
+
189
+ describe("for an interior cell", function () {
190
+ var actual;
191
+
192
+ before(function () {
193
+ actual = board.getAdjacency(1, 2);
194
+ });
195
+
196
+ jQuery.each([
197
+ ['nw', 1], ['n', 0], ['ne', 0],
198
+ [ 'w', 0], [ 'e', 2],
199
+ ['sw', 5], ['s', 4], ['se', 3]
200
+ ], function (i, v) {
201
+ it("has the right cell for " + v[0], function () {
202
+ expect(actual[v[0]].age).to(equal, v[1]);
203
+ });
204
+ });
205
+
206
+ it("has the correct adjacency count", function () {
207
+ expect(actual.liveCount()).to(equal, 5);
208
+ });
209
+ });
210
+
211
+ describe("for an edge cell", function () {
212
+ var actual;
213
+
214
+ before(function () {
215
+ actual = board.getAdjacency(2, 3);
216
+ });
217
+
218
+ jQuery.each([
219
+ ['nw', 0], ['n', 2], ['ne', 0],
220
+ [ 'w', 4], [ 'e', 0],
221
+ ['sw', 0], ['s', 0], ['se', 0]
222
+ ], function (i, v) {
223
+ it("has the right cell for " + v[0], function () {
224
+ expect(actual[v[0]].age).to(equal, v[1]);
225
+ });
226
+ });
227
+
228
+ it("has the correct adjacency count", function () {
229
+ expect(actual.liveCount()).to(equal, 2);
230
+ });
231
+ });
232
+ });
233
+ });
234
+ });