cucumber_factory 1.6.0 → 1.7.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/README.rdoc +10 -1
- data/VERSION +1 -1
- data/cucumber_factory.gemspec +5 -4
- data/lib/cucumber/factory.rb +46 -42
- data/spec/app_root/db/migrate/002_create_users.rb +5 -0
- data/spec/factory_spec.rb +6 -6
- data/spec/steps_spec.rb +66 -3
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Cucumber Factory allows you to create ActiveRecord objects directly from your {Cucumber}[http://cukes.info/] features. No step definitions required.
|
4
4
|
|
5
|
-
==
|
5
|
+
== Examples
|
6
6
|
|
7
7
|
The following will call {Movie.make}[http://github.com/notahat/machinist], {Factory.create(:movie)}[http://github.com/thoughtbot/factory_girl], Movie.create! or Movie.new, depending on what's available:
|
8
8
|
Given there is a movie
|
@@ -21,6 +21,15 @@ You can also refer to the last created object of a kind by saying "above":
|
|
21
21
|
Given there is a movie with the title "Before Sunrise"
|
22
22
|
And "Before Sunset" is a movie with the prequel above
|
23
23
|
|
24
|
+
Boolean attributes can be set by appending "which", "that" or "who" at the end:
|
25
|
+
Given there is a movie which is awesome
|
26
|
+
And there is a movie with the name "Sunshine" that is not a comedy
|
27
|
+
And there is a director who is popular
|
28
|
+
|
29
|
+
Instead of "and" you can also use "but" and commas to join sentences:
|
30
|
+
Given there is a movie which is awesome, popular and successful but not science fiction
|
31
|
+
And there is a director with the income "500000" but with the account balance "-30000"
|
32
|
+
|
24
33
|
== Factory support
|
25
34
|
|
26
35
|
{Machinist blueprints}[http://github.com/notahat/machinist] and {factory_girl factories}[http://github.com/thoughtbot/factory_girl] will be used when available.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.7.0
|
data/cucumber_factory.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cucumber_factory}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.7.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Henning Koch"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-09-04}
|
13
13
|
s.description = %q{Cucumber Factory allows you to create ActiveRecord models from your Cucumber features without writing step definitions for each model.}
|
14
14
|
s.email = %q{github@makandra.de}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -97,3 +97,4 @@ Gem::Specification.new do |s|
|
|
97
97
|
else
|
98
98
|
end
|
99
99
|
end
|
100
|
+
|
data/lib/cucumber/factory.rb
CHANGED
@@ -2,6 +2,8 @@ module Cucumber
|
|
2
2
|
module Factory
|
3
3
|
class << self
|
4
4
|
|
5
|
+
ATTRIBUTES_PATTERN = '( with the .+?)?( (?:which|who|that) is .+?)?'
|
6
|
+
|
5
7
|
# List of Cucumber step definitions created by #add_steps
|
6
8
|
attr_reader :step_definitions
|
7
9
|
|
@@ -13,60 +15,64 @@ module Cucumber
|
|
13
15
|
end)
|
14
16
|
end
|
15
17
|
end
|
16
|
-
|
18
|
+
|
17
19
|
def steps
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
# we cannot use vararg blocks here in Ruby 1.8, as explained by Aslak: http://www.ruby-forum.com/topic/182927
|
21
|
+
[ { :pattern => /^"([^\"]*)" is an? (.+?)( \(.+?\))?#{ATTRIBUTES_PATTERN}?$/,
|
22
|
+
:action => lambda { |a1, a2, a3, a4, a5| Cucumber::Factory.parse_named_creation(self, a1, a2, a3, a4, a5) } },
|
23
|
+
{ :pattern => /^there is an? (.+?)( \(.+?\))?#{ATTRIBUTES_PATTERN}$/,
|
24
|
+
:action => lambda { |a1, a2, a3, a4| Cucumber::Factory.parse_creation(self, a1, a2, a3, a4) } } ]
|
22
25
|
end
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
# command = command.sub(/^When |Given |Then /, "")
|
27
|
-
# steps.each do |step|
|
28
|
-
# match = step[:pattern].match(command)
|
29
|
-
# if match
|
30
|
-
# step[:action].bind(world).call(*match.captures)
|
31
|
-
# return
|
32
|
-
# end
|
33
|
-
# end
|
34
|
-
# raise "No step definition for: #{command}"
|
35
|
-
# end
|
36
|
-
|
37
|
-
def parse_named_creation(world, name, raw_model, raw_variant, raw_attributes)
|
38
|
-
record = parse_creation(world, raw_model, raw_variant, raw_attributes)
|
27
|
+
def parse_named_creation(world, name, raw_model, raw_variant, raw_attributes, raw_boolean_attributes)
|
28
|
+
record = parse_creation(world, raw_model, raw_variant, raw_attributes, raw_boolean_attributes)
|
39
29
|
variable = variable_name_from_prose(name)
|
40
30
|
world.instance_variable_set variable, record
|
41
31
|
end
|
42
32
|
|
43
|
-
def parse_creation(world, raw_model, raw_variant, raw_attributes)
|
33
|
+
def parse_creation(world, raw_model, raw_variant, raw_attributes, raw_boolean_attributes)
|
44
34
|
model_class = model_class_from_prose(raw_model)
|
45
35
|
attributes = {}
|
46
|
-
if raw_attributes.
|
47
|
-
raw_attributes.scan(/(the|and|with| )+(.*?) ("([^\"]*)"|above)/).each do |fragment|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
else
|
61
|
-
value = world.Transform(value)
|
62
|
-
end
|
63
|
-
attributes[attribute] = value
|
36
|
+
if raw_attributes.try(:strip).present?
|
37
|
+
raw_attributes.scan(/(?:the|and|with|but|,| )+(.*?) ("([^\"]*)"|above)/).each do |fragment|
|
38
|
+
attribute = attribute_name_from_prose(fragment[0])
|
39
|
+
value_type = fragment[1] # 'above' or a quoted string
|
40
|
+
value = fragment[2] # the value string without quotes
|
41
|
+
attributes[attribute] = attribute_value(world, model_class, attribute, value_type, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
if raw_boolean_attributes.try(:strip).present?
|
45
|
+
raw_boolean_attributes.scan(/(?:which|who|that|is| )*(not )?(.+?)(?: and | but |,|$)+/).each do |fragment|
|
46
|
+
flag = !fragment[0] # if not ain't there, this is true
|
47
|
+
attribute = attribute_name_from_prose(fragment[1])
|
48
|
+
attributes[attribute] = flag
|
64
49
|
end
|
65
50
|
end
|
66
51
|
variant = raw_variant.present? && /\((.*?)\)/.match(raw_variant)[1].downcase.gsub(" ", "_")
|
67
52
|
create_record(model_class, variant, attributes)
|
68
53
|
end
|
69
|
-
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def attribute_value(world, model_class, attribute, value_type, value)
|
58
|
+
association = model_class.respond_to?(:reflect_on_association) ? model_class.reflect_on_association(attribute) : nil
|
59
|
+
if association.present?
|
60
|
+
if value_type == "above"
|
61
|
+
# Don't use class.last, in sqlite that is not always the last inserted element
|
62
|
+
value = association.klass.find(:last, :order => "id") or raise "There is no last #{attribute}"
|
63
|
+
else
|
64
|
+
value = world.instance_variable_get(variable_name_from_prose(value))
|
65
|
+
end
|
66
|
+
else
|
67
|
+
value = world.Transform(value)
|
68
|
+
end
|
69
|
+
value
|
70
|
+
end
|
71
|
+
|
72
|
+
def attribute_name_from_prose(prose)
|
73
|
+
prose.downcase.gsub(" ", "_").to_sym
|
74
|
+
end
|
75
|
+
|
70
76
|
def model_class_from_prose(prose)
|
71
77
|
# don't use \w which depends on the system locale
|
72
78
|
prose.gsub(/[^A-Za-z0-9_]+/, "_").camelize.constantize
|
@@ -80,8 +86,6 @@ module Cucumber
|
|
80
86
|
:"@#{name}"
|
81
87
|
end
|
82
88
|
|
83
|
-
private
|
84
|
-
|
85
89
|
def factory_girl_factory_name(model_class)
|
86
90
|
model_class.to_s.underscore.to_sym
|
87
91
|
end
|
data/spec/factory_spec.rb
CHANGED
@@ -15,8 +15,8 @@ describe Cucumber::Factory do
|
|
15
15
|
describe 'model_class_from_prose' do
|
16
16
|
|
17
17
|
it "should return the class matching a natural language expression" do
|
18
|
-
Cucumber::Factory.model_class_from_prose
|
19
|
-
Cucumber::Factory.model_class_from_prose
|
18
|
+
Cucumber::Factory.send(:model_class_from_prose, "movie").should == Movie
|
19
|
+
Cucumber::Factory.send(:model_class_from_prose, "job offer").should == JobOffer
|
20
20
|
end
|
21
21
|
|
22
22
|
end
|
@@ -24,13 +24,13 @@ describe Cucumber::Factory do
|
|
24
24
|
describe 'variable_name_from_prose' do
|
25
25
|
|
26
26
|
it "should translate natural language to instance variable names" do
|
27
|
-
Cucumber::Factory.variable_name_from_prose
|
28
|
-
Cucumber::Factory.variable_name_from_prose
|
27
|
+
Cucumber::Factory.send(:variable_name_from_prose, "movie").should == :'@movie'
|
28
|
+
Cucumber::Factory.send(:variable_name_from_prose, "Some Movie").should == :'@some_movie'
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should make sure the generated instance variable names are legal" do
|
32
|
-
Cucumber::Factory.variable_name_from_prose
|
33
|
-
Cucumber::Factory.variable_name_from_prose
|
32
|
+
Cucumber::Factory.send(:variable_name_from_prose, "1973").should == :'@_1973'
|
33
|
+
Cucumber::Factory.send(:variable_name_from_prose, "%$§").should == :'@_'
|
34
34
|
end
|
35
35
|
|
36
36
|
end
|
data/spec/steps_spec.rb
CHANGED
@@ -71,6 +71,13 @@ describe 'steps provided by cucumber_factory' do
|
|
71
71
|
@step_mother.invoke('there is a movie with the title "Sunshine" and the year "2007"')
|
72
72
|
end
|
73
73
|
|
74
|
+
it "should allow to join attribute lists with 'and's, commas and 'but's" do
|
75
|
+
movie = Movie.new
|
76
|
+
Movie.stub(:new => movie)
|
77
|
+
movie.should_receive(:"attributes=").with({ :title => "Sunshine", :year => "2007", :box_office_result => "32000000" }, false)
|
78
|
+
@step_mother.invoke('there is a movie with the title "Sunshine", the year "2007" but with the box office result "32000000"')
|
79
|
+
end
|
80
|
+
|
74
81
|
it "should apply Cucumber transforms to attribute values" do
|
75
82
|
movie = Movie.new
|
76
83
|
Movie.stub(:new => movie)
|
@@ -115,9 +122,65 @@ describe 'steps provided by cucumber_factory' do
|
|
115
122
|
@step_mother.invoke('there is a user with the name "Jane"')
|
116
123
|
@step_mother.invoke('there is a movie with the title "Before Sunrise"')
|
117
124
|
@step_mother.invoke('there is a movie with the title "Before Sunset" and the reviewer above and the prequel above')
|
118
|
-
|
119
|
-
|
120
|
-
|
125
|
+
before_sunset = Movie.find_by_title!("Before Sunset")
|
126
|
+
before_sunset.prequel.title.should == "Before Sunrise"
|
127
|
+
before_sunset.reviewer.name.should == "Jane"
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should allow to set positive boolean attributes with 'who' after the attribute list" do
|
131
|
+
user = User.new
|
132
|
+
User.stub(:new => user)
|
133
|
+
user.should_receive(:attributes=).with({ :name => 'Jane', :deleted => true }, false)
|
134
|
+
@step_mother.invoke('there is a user with the name "Jane" who is deleted')
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should allow to set positive boolean attributes with 'which' after the attribute list" do
|
138
|
+
user = User.new
|
139
|
+
User.stub(:new => user)
|
140
|
+
user.should_receive(:attributes=).with({ :name => 'Jane', :deleted => true }, false)
|
141
|
+
@step_mother.invoke('there is a user with the name "Jane" which is deleted')
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should allow to set positive boolean attributes with 'that' after the attribute list" do
|
145
|
+
user = User.new
|
146
|
+
User.stub(:new => user)
|
147
|
+
user.should_receive(:attributes=).with({ :name => 'Jane', :deleted => true }, false)
|
148
|
+
@step_mother.invoke('there is a user with the name "Jane" that is deleted')
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should allow to set boolean attributes without regular attributes preceding them" do
|
152
|
+
user = User.new
|
153
|
+
User.stub(:new => user)
|
154
|
+
user.should_receive(:attributes=).with({ :deleted => true }, false)
|
155
|
+
@step_mother.invoke('there is a user who is deleted')
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should allow to set negative boolean attribute" do
|
159
|
+
user = User.new
|
160
|
+
User.stub(:new => user)
|
161
|
+
user.should_receive(:attributes=).with({ :deleted => false }, false)
|
162
|
+
@step_mother.invoke('there is a user who is not deleted')
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should allow to set multiple boolean attributes" do
|
166
|
+
user = User.new
|
167
|
+
User.stub(:new => user)
|
168
|
+
user.should_receive(:attributes=).with({ :locked => true, :deleted => false, :subscribed => true }, false)
|
169
|
+
@step_mother.invoke('there is a user who is locked and not deleted and subscribed')
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should allow to set boolean attributes that are named from multiple words" do
|
173
|
+
user = User.new
|
174
|
+
User.stub(:new => user)
|
175
|
+
user.should_receive(:attributes=).with({ :locked => true, :scared => false, :scared_by_spiders => true, :deleted => true }, false)
|
176
|
+
@step_mother.invoke('there is a user who is locked and not scared and scared by spiders and deleted')
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should allow to join boolean attribute lists with 'and's, commas and 'but's" do
|
180
|
+
user = User.new
|
181
|
+
User.stub(:new => user)
|
182
|
+
user.should_receive(:attributes=).with({ :locked => true, :scared => true, :scared_by_spiders => true, :deleted => true }, false)
|
183
|
+
@step_mother.invoke('there is a user who is locked, scared, but scared by spiders and deleted')
|
121
184
|
end
|
122
185
|
|
123
186
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
-
|
7
|
+
- 7
|
8
8
|
- 0
|
9
|
-
version: 1.
|
9
|
+
version: 1.7.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Henning Koch
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-09-04 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|