shenandoah 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ });