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.
- data/.gitignore +1 -0
- data/ChangeLog.markdown +9 -0
- data/Rakefile +21 -2
- data/VERSION.yml +3 -2
- data/features/buildr.feature +29 -0
- data/features/example_projects/base/Rakefile +7 -0
- data/features/example_projects/base/lib/cells.js +105 -0
- data/features/example_projects/base/lib/life.js +30 -0
- data/features/example_projects/base/spec/cells.html +13 -0
- data/features/example_projects/base/spec/cells_spec.js +234 -0
- data/features/example_projects/base/spec/life.html +13 -0
- data/features/example_projects/base/spec/life_spec.js +28 -0
- data/features/plain-rake.feature +30 -0
- data/features/rails.feature +39 -0
- data/features/step_definitions/buildr_steps.rb +26 -0
- data/features/step_definitions/rails_steps.rb +38 -0
- data/features/step_definitions/rake_steps.rb +45 -0
- data/features/support/env.rb +48 -0
- data/lib/shenandoah/css/shenandoah.sass +138 -0
- data/lib/shenandoah/javascript/browser/index.js +18 -0
- data/lib/shenandoah/javascript/browser/multirunner-single.js +32 -0
- data/lib/shenandoah/javascript/browser/multirunner.js +87 -0
- data/lib/shenandoah/javascript/common/jquery.parsequery.js +19 -0
- data/lib/shenandoah/server.rb +81 -16
- data/lib/shenandoah/server/views/index.haml +18 -8
- data/lib/shenandoah/server/views/multirunner.haml +6 -0
- data/rails_generators/shen_spec/templates/fixture.html.erb +1 -1
- data/rails_generators/shenandoah/templates/application.html +1 -1
- data/spec/rails_generators/shen_spec_generator_spec.rb +2 -2
- data/spec/rails_generators/shenandoah_generator_spec.rb +3 -3
- data/spec/shenandoah/server_spec.rb +156 -15
- metadata +32 -3
- data/lib/shenandoah/css/screw.css +0 -90
data/.gitignore
CHANGED
data/ChangeLog.markdown
CHANGED
@@ -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]
|
data/VERSION.yml
CHANGED
@@ -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,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
|
+
});
|