cucumber_factory 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
- == Example
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.6.0
1
+ 1.7.0
@@ -1,15 +1,15 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
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.6.0"
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-08-17}
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
+
@@ -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
- [ { :pattern => /^"([^\"]*)" is an? (.+?)( \(.+?\))?( with the .+?)?$/,
19
- :action => lambda { |name, raw_model, raw_variant, raw_attributes| Cucumber::Factory.parse_named_creation(self, name, raw_model, raw_variant, raw_attributes) } },
20
- { :pattern => /^there is an? (.+?)( \(.+?\))?( with the .+?)?$/,
21
- :action => lambda { |raw_model, raw_variant, raw_attributes| Cucumber::Factory.parse_creation(self, raw_model, raw_variant, raw_attributes) } } ]
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
- # # Emulate Cucumber step matching for specs
25
- # def parse(world, command)
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.present? && raw_attributes.strip.present?
47
- raw_attributes.scan(/(the|and|with| )+(.*?) ("([^\"]*)"|above)/).each do |fragment|
48
- value = nil
49
- attribute = fragment[1].downcase.gsub(" ", "_").to_sym
50
- value_type = fragment[2] # 'above' or a quoted string
51
- value = fragment[3]
52
- association = model_class.reflect_on_association(attribute) if model_class.respond_to?(:reflect_on_association)
53
- if association.present?
54
- if value_type == "above"
55
- # Don't use class.last, in sqlite that is not always the last inserted element
56
- value = association.klass.find(:last, :order => "id") or raise "There is no last #{attribute}"
57
- else
58
- value = world.instance_variable_get(variable_name_from_prose(value))
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
@@ -4,6 +4,11 @@ class CreateUsers < ActiveRecord::Migration
4
4
  create_table :users do |t|
5
5
  t.string :email
6
6
  t.string :name
7
+ t.boolean :deleted
8
+ t.boolean :locked
9
+ t.boolean :subscribed
10
+ t.boolean :scared
11
+ t.boolean :scared_by_spiders
7
12
  end
8
13
  end
9
14
 
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("movie").should == Movie
19
- Cucumber::Factory.model_class_from_prose("job offer").should == JobOffer
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("movie").should == :'@movie'
28
- Cucumber::Factory.variable_name_from_prose("Some Movie").should == :'@some_movie'
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("1973").should == :'@_1973'
33
- Cucumber::Factory.variable_name_from_prose("%$§").should == :'@_'
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
- @before_sunset = Movie.find_by_title!("Before Sunset")
119
- @before_sunset.prequel.title.should == "Before Sunrise"
120
- @before_sunset.reviewer.name.should == "Jane"
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
- - 6
7
+ - 7
8
8
  - 0
9
- version: 1.6.0
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-08-17 00:00:00 +02:00
17
+ date: 2010-09-04 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20