neverfails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +2 -0
- data/HISTORY.md +8 -0
- data/MIT-LICENSE +20 -0
- data/README.md +287 -0
- data/TODO.md +9 -0
- data/fails_steps.rb +49 -0
- data/lib/neverfails.rb +60 -0
- data/neverfails.gemspec +21 -0
- metadata +103 -0
data/Gemfile
ADDED
data/HISTORY.md
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
Behavior-driven development (BDD) consists of [five steps](http://cukes.info/):
|
2
|
+
|
3
|
+
1. Describe behavior in plain text
|
4
|
+
2. Write a step definition
|
5
|
+
3. Run and watch it fail
|
6
|
+
4. Write code to make the step pass
|
7
|
+
5. Run again and see the step pass
|
8
|
+
|
9
|
+
Neverfails is a proof of concept to reduce this list to **two steps**:
|
10
|
+
|
11
|
+
1. Describe behaviour in plain text
|
12
|
+
2. Run and watch it pass
|
13
|
+
|
14
|
+
With neverfails, step definitions do not simply check whether the existing code satifies the required behaviour or not. They also **write the code** to make them pass.
|
15
|
+
|
16
|
+
Neverfails involves an ambitious idea: code generation based on specifications. This idea does not depend on a specific platform or programming language. In principle, it could be implemented with any framework. The current claudiob/neverfails@rails branch uses Rails as a web framework and Ruby as the programming language. The master claudiob/neverfails@master branch, on the other hand, is investigating the same approach using Python and Django.
|
17
|
+
|
18
|
+
Behavior-driven development in Rails
|
19
|
+
====================================
|
20
|
+
|
21
|
+
Before approaching neverfails, it is important to understand how Behaviour-Driven Development (BDD) typically takes place within a Rails project.
|
22
|
+
|
23
|
+
Step 1 (Describe behavior in plain text)
|
24
|
+
----------------------------------------
|
25
|
+
|
26
|
+
Say we want to create a web store for a *grocery* store, with a distinct page for each product. The *apples* page, for instance, will list the types and quantities of apples currently in store, showing "No apples left" if there are none left in the market. This scenario can be described as:
|
27
|
+
|
28
|
+
``` cucumber
|
29
|
+
Feature: Apples
|
30
|
+
Scenario: No apples left
|
31
|
+
Given there are no apples
|
32
|
+
When I browse the list of apples
|
33
|
+
Then I should see the text "No apples left"
|
34
|
+
```
|
35
|
+
|
36
|
+
Having described behavior in plain text, we create a blank Rails project and make use of [cucumber](https://github.com/gabrielfalcao/lettuce) and [capybara](https://github.com/jnicklas/capybara) to run the steps.
|
37
|
+
|
38
|
+
The following commands set up a new `grocery` Rails project with a basic SQLite database, and a bundle installation with cucumber and capybara:
|
39
|
+
|
40
|
+
``` bash
|
41
|
+
rails new grocery -JT
|
42
|
+
cd grocery
|
43
|
+
rm public/index.html
|
44
|
+
rm public/images/rails.png
|
45
|
+
echo -e '\ngem "cucumber"' >> Gemfile
|
46
|
+
echo -e '\ngem "cucumber-rails"' >> Gemfile
|
47
|
+
bundle install
|
48
|
+
rails g cucumber:install
|
49
|
+
echo "require 'cucumber/rails'
|
50
|
+
Capybara.default_selector = :css
|
51
|
+
ActionController::Base.allow_rescue = false" >| features/support/env.rb
|
52
|
+
sed -i '' -e's/<<: \*test/<<: *development/' config/database.yml
|
53
|
+
rake db:create
|
54
|
+
echo -e "Feature: Apples
|
55
|
+
Scenario: No apples left
|
56
|
+
Given there are no apples
|
57
|
+
When I browse the list of apples
|
58
|
+
Then I should see the text \"No apples left\"
|
59
|
+
" > features/apples.feature
|
60
|
+
```
|
61
|
+
|
62
|
+
Step 2 (Write step definitions)
|
63
|
+
-------------------------------
|
64
|
+
|
65
|
+
To make Rails aware of what the actions in the scenario actually mean, we can either write new step definitions, or import some library that translates common actions into Python commands. One such popular library for Web applications is [capybara](https://github.com/jnicklas/capybara).
|
66
|
+
|
67
|
+
For the sake of the `grocery` example, we define the three steps of the `No apples left` scenario as follows:
|
68
|
+
|
69
|
+
* *Given there are no apples*: this step passes if a model called 'Apple' exist and if there are no instances of this model in the database
|
70
|
+
* *When I browse the list of apples*: this step passes if a page exists listing apples and if I can open that page in a browser
|
71
|
+
* *Then I should see the text "No apples left"*: this step passes if I see the text "No apples left" in that page
|
72
|
+
|
73
|
+
The file `fails_steps.rb` in this package contains these definition in Ruby and capybara code.
|
74
|
+
|
75
|
+
Step 3 (Run and watch it fail)
|
76
|
+
------------------------------
|
77
|
+
|
78
|
+
The following commands copy the content of this file in the project and run the steps again:
|
79
|
+
|
80
|
+
``` bash
|
81
|
+
echo -e "# MODELS
|
82
|
+
|
83
|
+
Given /^there are no (\\S+?)\$/ do |objects|
|
84
|
+
model_name = objects.classify
|
85
|
+
Given \"there is a model called #{model_name}\"
|
86
|
+
Given \"there are no instances of that model\"
|
87
|
+
end
|
88
|
+
|
89
|
+
Given /^(?:|there is )a model called (.+?)\$/ do |model_name|
|
90
|
+
assert ActiveRecord::Base.connection.tables.include?(model_name.tableize),
|
91
|
+
\"No model found called #{model_name}\"
|
92
|
+
@last_model = model_name.constantize
|
93
|
+
end
|
94
|
+
|
95
|
+
Given /^(?:|there are )no instances of that model\$/ do
|
96
|
+
@last_model.delete_all
|
97
|
+
end
|
98
|
+
|
99
|
+
# NAVIGATION
|
100
|
+
|
101
|
+
When /^I browse the list of (.+?)\$/ do |models|
|
102
|
+
Given \"there is a page listing #{models}\"
|
103
|
+
When \"I navigate to that page\"
|
104
|
+
end
|
105
|
+
|
106
|
+
Given /^there is a page listing (.+?)\$/ do |models|
|
107
|
+
Given \"there is a page with URL /#{models}\"
|
108
|
+
end
|
109
|
+
|
110
|
+
Given /^there is a page with URL (.+?)\$/ do |url|
|
111
|
+
assert Rails.application.routes.routes.collect(&:conditions).
|
112
|
+
collect{|route| route[:path_info] =~ url }.any?,
|
113
|
+
\"No URL pattern found matching #{url}\"
|
114
|
+
\$last_url = url
|
115
|
+
end
|
116
|
+
|
117
|
+
When /^I navigate to that page\$/ do
|
118
|
+
visit \$last_url
|
119
|
+
end
|
120
|
+
|
121
|
+
# CONTENT
|
122
|
+
|
123
|
+
Then /^I should see the text \"([^\"]*)\"\$/ do |text|
|
124
|
+
begin
|
125
|
+
page.should have_content(text)
|
126
|
+
rescue Test::Unit::AssertionFailedError => e
|
127
|
+
raise e.class, \"The text \\\"#{text}\\\" was not found in the current page\"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
" > features/step_definitions/fails_steps.rb
|
131
|
+
cucumber RAILS_ENV=development
|
132
|
+
```
|
133
|
+
|
134
|
+
The result is the following, indicating that the *first* step has failed:
|
135
|
+
|
136
|
+
```
|
137
|
+
No model found called Apple. (Test::Unit::AssertionFailedError)
|
138
|
+
```
|
139
|
+
|
140
|
+
Step 4 (Write code to make the three steps pass)
|
141
|
+
-------------------------------------------------
|
142
|
+
|
143
|
+
To make the first step pass, we need to create an Apple model and store it in the database:
|
144
|
+
|
145
|
+
``` bash
|
146
|
+
rails g model apple
|
147
|
+
rake db:migrate
|
148
|
+
cucumber RAILS_ENV=development
|
149
|
+
```
|
150
|
+
|
151
|
+
The result is now the following, indicating that the *second* step has failed:
|
152
|
+
|
153
|
+
```
|
154
|
+
No URL pattern found matching /apples. (Test::Unit::AssertionFailedError)
|
155
|
+
```
|
156
|
+
|
157
|
+
To make the second step pass, we need to create a URL pattern matching "apples/" that points to a blank HTML page:
|
158
|
+
|
159
|
+
``` bash
|
160
|
+
rails g controller Apples index
|
161
|
+
sed -i '' '
|
162
|
+
/get "apples\/index"/ a\
|
163
|
+
match "/apples" => "apples#index"
|
164
|
+
' config/routes.rb
|
165
|
+
cucumber RAILS_ENV=development
|
166
|
+
```
|
167
|
+
|
168
|
+
The result is now the following, indicating that the *third* step has failed:
|
169
|
+
|
170
|
+
```
|
171
|
+
The text "No apples" left was not found in the current page (Test::Unit::AssertionFailedError)
|
172
|
+
```
|
173
|
+
|
174
|
+
To make the third step pass, we need to add the text "No apples left" to the page that lists apples:
|
175
|
+
|
176
|
+
``` bash
|
177
|
+
echo "No apples left" >| app/views/apples/index.html.erb
|
178
|
+
cucumber RAILS_ENV=development
|
179
|
+
```
|
180
|
+
|
181
|
+
Step 5 (Run again and see the step pass)
|
182
|
+
----------------------------------------
|
183
|
+
|
184
|
+
Finally, the three steps pass and running them again returns the message:
|
185
|
+
|
186
|
+
``` cucumber
|
187
|
+
Feature: Apples
|
188
|
+
Scenario: No apples left
|
189
|
+
Given there are no apples
|
190
|
+
When I browse the list of apples
|
191
|
+
Then I should see the text "No apples left"
|
192
|
+
|
193
|
+
1 feature (1 passed)
|
194
|
+
3 steps (3 passed)
|
195
|
+
```
|
196
|
+
|
197
|
+
Neverfails does all of this, so you don't have to (TO COMPLETE)
|
198
|
+
===============================================================
|
199
|
+
|
200
|
+
The `grocery` example shows that Behaviour-Driven Development is time-consuming even for very small applications, with an empty model and a view showing one sentence.
|
201
|
+
Time is spent watching the tests fail and writing snippets of code that are common to every web application (creating a model, filling view with text and so on).
|
202
|
+
|
203
|
+
Neverfails reduces this time by automatically creating the missing snippets of code when a step fails.
|
204
|
+
|
205
|
+
|
206
|
+
Step 1 (Describe behavior in plain text)
|
207
|
+
----------------------------------------
|
208
|
+
|
209
|
+
Continuing with the grocery example, say we want to add this new scenario:
|
210
|
+
|
211
|
+
``` cucumber
|
212
|
+
Feature: Bananas
|
213
|
+
Scenario: No bananas left
|
214
|
+
Given there are no bananas
|
215
|
+
When I browse the list of bananas
|
216
|
+
Then I should see the text "No bananas left"
|
217
|
+
```
|
218
|
+
|
219
|
+
The following commands add the previous scenario to the grocery project and include neverfails to the project:
|
220
|
+
|
221
|
+
``` bash
|
222
|
+
echo -e "Feature: Bananas\n\tScenario: No bananas left\n\t\tGiven there are no bananas\n\t\tWhen I browse the list of bananas\n\t\tThen I should see the text \"No bananas left\"" > features/bananas.feature
|
223
|
+
echo -e '\ngem "neverfails"' >> Gemfile
|
224
|
+
bundle install
|
225
|
+
echo -e "\nrequire 'neverfails'" >> features/support/env.rb
|
226
|
+
echo -e "\nRails.configuration.cache_classes = false" >> features/support/env.rb
|
227
|
+
```
|
228
|
+
|
229
|
+
Step 2 (Run and watch it pass)
|
230
|
+
------------------------------
|
231
|
+
|
232
|
+
Both the `apples` and the `bananas` scenario can be run with the command:
|
233
|
+
|
234
|
+
``` bash
|
235
|
+
cucumber features/
|
236
|
+
```
|
237
|
+
|
238
|
+
The `apples` scenario passes since we already wrote all its required. The `bananas` scenario, though, passes as well:
|
239
|
+
|
240
|
+
``` cucumber
|
241
|
+
Feature: Apples
|
242
|
+
Scenario: No apples left
|
243
|
+
Given there are no apples
|
244
|
+
When I browse the list of apples
|
245
|
+
Then I should see the text "No apples left"
|
246
|
+
|
247
|
+
Feature: Bananas
|
248
|
+
Scenario: No bananas left
|
249
|
+
Given there are no bananas
|
250
|
+
Creating tables ...
|
251
|
+
Creating table bananas_banana
|
252
|
+
Installing custom SQL ...
|
253
|
+
Installing indexes ...
|
254
|
+
When I browse the list of bananas
|
255
|
+
Then I should see the text "No bananas left"
|
256
|
+
|
257
|
+
2 features (2 passed)
|
258
|
+
2 scenarios (2 passed)
|
259
|
+
6 steps (6 passed)
|
260
|
+
```
|
261
|
+
|
262
|
+
How neverfails works
|
263
|
+
====================
|
264
|
+
|
265
|
+
With neverfails, all the steps are parsed by cucumber as normal. However, if a step fails, neverfails *does not* raise an AssertionError but runs the code to make the step pass, then runs the step again.
|
266
|
+
|
267
|
+
So far, neverfails is only able to recognize the three kinds of step included in the `grocery` sample project: creating a model, creating a view, adding text to that view. This is why I call neverfails a proof of concept. If other people find this project interesting (or if I get more time to work on this), then neverfails will grow up to the point where people with no programming experience will be able to create complex web applications by describing what they wish for.
|
268
|
+
|
269
|
+
|
270
|
+
Installing neverfails
|
271
|
+
=====================
|
272
|
+
|
273
|
+
To follow the example described above, you need [rails](https://github.com/rails/rails) and [bundler](http://gembundler.com) installed on your machine.
|
274
|
+
The following commands will install these packages, given you already have Ruby installed with [rubygems](http://rubygems.org) enabled:
|
275
|
+
|
276
|
+
``` bash
|
277
|
+
gem install rails
|
278
|
+
gem install bundler
|
279
|
+
```
|
280
|
+
|
281
|
+
The actual neverfails gem can either be downloaded from GitHub or installed by adding the following to the Rails project's Gemfile:
|
282
|
+
|
283
|
+
gem 'neverfails'
|
284
|
+
|
285
|
+
and the running:
|
286
|
+
|
287
|
+
bundle install
|
data/TODO.md
ADDED
data/fails_steps.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# MODELS
|
2
|
+
|
3
|
+
Given /^there are no (\S+?)$/ do |objects|
|
4
|
+
model_name = objects.classify
|
5
|
+
Given "there is a model called #{model_name}"
|
6
|
+
Given "there are no instances of that model"
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^(?:|there is )a model called (.+?)$/ do |model_name|
|
10
|
+
assert ActiveRecord::Base.connection.tables.include?(model_name.tableize),
|
11
|
+
"No model found called #{model_name}"
|
12
|
+
@last_model = model_name.constantize
|
13
|
+
end
|
14
|
+
|
15
|
+
Given /^(?:|there are )no instances of that model$/ do
|
16
|
+
@last_model.delete_all
|
17
|
+
end
|
18
|
+
|
19
|
+
# NAVIGATION
|
20
|
+
|
21
|
+
When /^I browse the list of (.+?)$/ do |models|
|
22
|
+
Given "there is a page listing #{models}"
|
23
|
+
When "I navigate to that page"
|
24
|
+
end
|
25
|
+
|
26
|
+
Given /^there is a page listing (.+?)$/ do |models|
|
27
|
+
Given "there is a page with URL /#{models}/index"
|
28
|
+
end
|
29
|
+
|
30
|
+
Given /^there is a page with URL (.+?)$/ do |url|
|
31
|
+
assert Rails.application.routes.routes.collect(&:conditions).
|
32
|
+
collect{|route| route[:path_info] =~ url }.any?,
|
33
|
+
"No URL pattern found matching #{url}"
|
34
|
+
$last_url = url
|
35
|
+
end
|
36
|
+
|
37
|
+
When /^I navigate to that page$/ do
|
38
|
+
visit $last_url
|
39
|
+
end
|
40
|
+
|
41
|
+
# CONTENT
|
42
|
+
|
43
|
+
Then /^I should see the text "([^"]*)"$/ do |text|
|
44
|
+
begin
|
45
|
+
assert_contain text
|
46
|
+
rescue Test::Unit::AssertionFailedError => e
|
47
|
+
raise e.class, "The text \"#{text}\" was not found in the current page"
|
48
|
+
end
|
49
|
+
end
|
data/lib/neverfails.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
class StepMatch
|
5
|
+
def invoke_with_neverfails(multiline_arg)
|
6
|
+
begin
|
7
|
+
invoke_without_neverfails(multiline_arg)
|
8
|
+
rescue Exception => e # NOTE: Test::Unit::AssertionFailedError
|
9
|
+
match1 = /No model found called (.+?)\.$/.match(e.message)
|
10
|
+
match2 = /No URL pattern found matching \/(.+?)\.$/.match(e.message)
|
11
|
+
match3 = /The text "(.+?)" was not found in the current page$/.match(e.message)
|
12
|
+
if match1
|
13
|
+
create_missing_model match1[1]
|
14
|
+
elsif match2
|
15
|
+
create_missing_page_listing match2[1]
|
16
|
+
elsif match3
|
17
|
+
create_missing_text match3[1]
|
18
|
+
else
|
19
|
+
raise
|
20
|
+
end
|
21
|
+
return invoke_without_neverfails(multiline_arg) # Try again
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
alias_method_chain :invoke, :neverfails
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_missing_model(singular_name)
|
31
|
+
# Generate the model and the migration
|
32
|
+
Rails::Generators.invoke("model", [singular_name, "--orm=active_record", "--migration"])
|
33
|
+
# Run the migration
|
34
|
+
ActiveRecord::Migrator.migrate "db/migrate/"
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_missing_page_listing(objects)
|
38
|
+
# Generate the controller
|
39
|
+
require 'ruby-debug'
|
40
|
+
debugger
|
41
|
+
Rails::Generators.invoke("controller", [objects.classify, "index"])
|
42
|
+
# Add an extra route match "/models" => "model#index"
|
43
|
+
singular = objects.singularize
|
44
|
+
@@missing_view_file = "app/views/#{singular}/index.html.erb"
|
45
|
+
routes_file = 'config/routes.rb'
|
46
|
+
old_routes = File.read(routes_file)
|
47
|
+
File.open(routes_file, "w") do |file|
|
48
|
+
file.puts old_routes.gsub(/get "#{singular}\/index"/,
|
49
|
+
"get \"#{singular}/index\"\nmatch \"/#{objects}\" => \"#{singular}#index\"")
|
50
|
+
end
|
51
|
+
# Reload routes
|
52
|
+
::Rails.application.reload_routes!
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_missing_text(text)
|
56
|
+
File.open(@@missing_view_file, "w") do |file|
|
57
|
+
file.puts "#{text}\n"
|
58
|
+
end
|
59
|
+
Capybara.current_session.visit $last_url
|
60
|
+
end
|
data/neverfails.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'neverfails'
|
6
|
+
s.version = '0.0.1'
|
7
|
+
s.authors = ["Claudio B."]
|
8
|
+
s.email = ["claudiob@gmail.com"]
|
9
|
+
s.homepage = "https://github.com/claudiob/neverfails/tree/rails"
|
10
|
+
s.summary = %q{Cucumber plugin that generates code to make failing steps pass}
|
11
|
+
s.description = %q{With neverfails, step definitions do not simply check whether the existing code satifies the required behaviour or not. They also write the code to make them pass.}
|
12
|
+
s.licenses = ["MIT"]
|
13
|
+
|
14
|
+
s.add_dependency 'cucumber'
|
15
|
+
s.add_dependency 'cucumber-rails'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_path = "lib"
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: neverfails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Claudio B.
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-08-07 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: cucumber
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: cucumber-rails
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
description: With neverfails, step definitions do not simply check whether the existing code satifies the required behaviour or not. They also write the code to make them pass.
|
50
|
+
email:
|
51
|
+
- claudiob@gmail.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- Gemfile
|
61
|
+
- HISTORY.md
|
62
|
+
- MIT-LICENSE
|
63
|
+
- README.md
|
64
|
+
- TODO.md
|
65
|
+
- fails_steps.rb
|
66
|
+
- lib/neverfails.rb
|
67
|
+
- neverfails.gemspec
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: https://github.com/claudiob/neverfails/tree/rails
|
70
|
+
licenses:
|
71
|
+
- MIT
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.3.7
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Cucumber plugin that generates code to make failing steps pass
|
102
|
+
test_files: []
|
103
|
+
|