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 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