ianwhite-pickle 0.1.1

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/History.txt ADDED
@@ -0,0 +1,11 @@
1
+ == 0.1.1
2
+
3
+ * 1 major enhancement:
4
+ * made pickle a github gem
5
+
6
+ * 1 minor enhancement:
7
+ * Added intentions for pickle in README.textile
8
+
9
+ == Prior to gems
10
+
11
+ * Initial release: everything is subject to sweeping change
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Ian White - ian.w.white@ardes.com
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.textile ADDED
@@ -0,0 +1,67 @@
1
+ h1. Pickle [Experimental: In development]
2
+
3
+ Stick this in vendor/plugins to have cucumber steps that create your models easily from factory_girl/machinist
4
+
5
+ References to the models are stored, not for the purpose of checking the db (although you could use it for
6
+ that), but for enabling easy reference to urls, and for building complex givens which require a bunch of
7
+ models collaborating
8
+
9
+ h2. Example
10
+
11
+ If you have a user model, which has admin? and moderator? predicate methods
12
+ and let's say you have an :admin, :user, and :moderator factory, you can do this in a Scenario:
13
+
14
+ And an admin exists
15
+ And a moderator exists
16
+
17
+ # the following is just to show how refs work, obviously you'd not want to test this
18
+ Then the moderator should be a moderator
19
+ And the admin should be an admin
20
+ And the moderator should not be an admin
21
+
22
+ h2. Usage
23
+
24
+ script/generate pickle
25
+
26
+ h2. API
27
+
28
+ h3. Regexps for us in your own steps
29
+
30
+ If you want to use pickle expressions in your own steps, make sure you
31
+ require pickle in that file
32
+
33
+ require 'pickle'
34
+
35
+ For matching english versions of model names you get
36
+
37
+ #match_model, #capture_model
38
+
39
+ Given /^#{capture_model} exists$/ do |model_name|
40
+ model(model_name).should_not == nil
41
+ end
42
+
43
+ Then /^I should be at the (.*?) page$/ |page|
44
+ if page =~ /#{match_model}'s/
45
+ url_for(model(page.sub("'s",''))
46
+ else
47
+ # ...
48
+ end
49
+ end
50
+
51
+ For matching a field string, you get
52
+
53
+ #match_fields, #capture_fields
54
+
55
+ Given /^#{capture_model} exists with #{capture_fields}$/ do |model_name, fields|
56
+ create_model(model_name, fields)
57
+ end
58
+
59
+ Take a look at features/step_definitions/pickle_steps.rb for more examples
60
+
61
+ h3. Creating and tracking models
62
+
63
+ #create_model(<model_name>[, <field string>])
64
+
65
+ #find_model(<model_name>[, <field string>])
66
+
67
+ #model(<model_model>) # refers to a model that has already been created/found (ie. referred to in a scenario)
data/Todo.txt ADDED
@@ -0,0 +1,5 @@
1
+ * make a gem release with version number
2
+
3
+ * create a generator for the pickle steps
4
+
5
+ * add machinist, and fallback to no factory pattern if none available
@@ -0,0 +1,18 @@
1
+ module Pickle
2
+ module Injector
3
+ def self.inject(session, options = {})
4
+ target = options[:into] || ActionController::Integration::Session
5
+ session_name = session.name.underscore.gsub('/','_')
6
+
7
+ target.class_eval <<-end_eval, __FILE__, __LINE__
8
+ def #{session_name}
9
+ @#{session_name} ||= #{session.name}.new
10
+ end
11
+ end_eval
12
+
13
+ delegate_methods = session.instance_methods - Object.instance_methods
14
+ delegate_methods << {:to => session_name}
15
+ target.delegate *delegate_methods
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,82 @@
1
+ module Pickle
2
+ module Parser
3
+ module Match
4
+ Ordinal = '(?:\d+(?:st|nd|rd|th))'
5
+ Index = "(?:first|last|#{Ordinal})"
6
+ Prefix = '(?:1 |a |an |another |the |that )'
7
+ Quoted = '(?:[^\\"]|\\.)*'
8
+ Name = '(?::? "' + Quoted + '")'
9
+
10
+ # model matching - depends on Parse::Config, so load before this if non standard config requried
11
+ ModelMapping = "(?:#{Pickle::Config.mappings.map(&:first).map{|s| "(?:#{s})"}.join('|')})"
12
+ ModelName = "(?:#{Pickle::Config.names.map{|n| n.to_s.gsub('_','[_ ]').gsub('/','[:\/ ]')}.join('|')})"
13
+ IndexedModel = "(?:(?:#{Index} )?#{ModelName})"
14
+ NamedModel = "(?:#{ModelName}#{Name}?)"
15
+ Model = "(?:#{ModelMapping}|#{Prefix}?(?:#{IndexedModel}|#{NamedModel}))"
16
+ Field = '(?:\w+: (?:' + Model + '|"' + Quoted + '"))'
17
+ Fields = "(?:#{Field}, )*#{Field}"
18
+
19
+ end
20
+
21
+ # these are expressions which capture a sub expression
22
+ module Capture
23
+ Ordinal = '(?:(\d+)(?:st|nd|rd|th))'
24
+ Name = '(?::? "(' + Match::Quoted + ')")'
25
+ Field = '(?:(\w+): "(' + Match::Quoted + ')")'
26
+ end
27
+
28
+ # given a string like 'foo: "bar", bar: "baz"' returns {"foo" => "bar", "bar" => "baz"}
29
+ def parse_fields(fields)
30
+ if fields.blank?
31
+ {}
32
+ elsif fields =~ /^#{Match::Fields}$/
33
+ fields.scan(/(#{Match::Field})(?:,|$)/).inject({}) do |m, match|
34
+ m.merge(parse_field(match[0]))
35
+ end
36
+ else
37
+ raise ArgumentError, "The fields string is not in the correct format.\n\n'#{fields}' did not match: #{Match::Fields}"
38
+ end
39
+ end
40
+
41
+ # given a string like 'foo: "bar"' returns {key => value}
42
+ def parse_field(field)
43
+ if field =~ /^#{Capture::Field}$/
44
+ { $1 => $2 }
45
+ else
46
+ raise ArgumentError, "The field argument is not in the correct format.\n\n'#{field}' did not match: #{Match::Field}"
47
+ end
48
+ end
49
+
50
+ # returns really underscored name
51
+ def canonical(str)
52
+ str.to_s.gsub(' ','_').underscore
53
+ end
54
+
55
+ def parse_index(index)
56
+ case index
57
+ when '', /last/ then -1
58
+ when /#{Capture::Ordinal}/ then $1.to_i - 1
59
+ when /first/ then 0
60
+ end
61
+ end
62
+
63
+ private
64
+ # return [factory, name or integer index]
65
+ def parse_model(name)
66
+ apply_mappings!(name)
67
+ if /(#{Match::ModelName})#{Capture::Name}$/ =~ name
68
+ [canonical($1), canonical($2)]
69
+ elsif /(#{Match::Index}) (#{Match::ModelName})$/ =~ name
70
+ [canonical($2), parse_index($1)]
71
+ else
72
+ /(#{Match::ModelName})#{Capture::Name}?$/ =~ name && [canonical($1), canonical($2)]
73
+ end
74
+ end
75
+
76
+ def apply_mappings!(string)
77
+ Pickle::Config.mappings.each do |(search, replace)|
78
+ string.sub! /^(?:#{search})$/, replace
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,106 @@
1
+ module Pickle
2
+ class Session
3
+ include Parser
4
+
5
+ def create_model(a_model_name, fields = nil)
6
+ factory, name = *parse_model(a_model_name)
7
+ raise ArgumentError, "Can't create a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
8
+ record = Factory(factory, parse_fields(fields))
9
+ store_model(factory, name, record)
10
+ end
11
+
12
+ def find_model(a_model_name, fields)
13
+ model, name = *parse_model(a_model_name)
14
+ raise ArgumentError, "Can't find a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
15
+ model_class = model.classify.constantize
16
+ if record = model_class.find(:first, :conditions => convert_models_to_attributes(model_class, parse_fields(fields)))
17
+ store_model(model, name, record)
18
+ else
19
+ raise ActiveRecord::RecordNotFound, "Couldn't find #{model} with #{fields}"
20
+ end
21
+ end
22
+
23
+ # return the original model stored by create_model or find_model
24
+ def original_model(a_model_name)
25
+ factory, name_or_index = *parse_model(a_model_name)
26
+
27
+ if name_or_index.blank?
28
+ models_by_factory(factory).last
29
+ elsif name_or_index.is_a?(Integer)
30
+ models_by_factory(factory)[name_or_index]
31
+ else
32
+ models_by_name(factory)[name_or_index] or raise "model: #{a_model_name} does not refer to known model in this scenario"
33
+ end
34
+ end
35
+
36
+ # predicate version which raises no errors
37
+ def original_model?(a_model_name)
38
+ (original_model(a_model_name) rescue nil) ? true : false
39
+ end
40
+
41
+ # return a newly selected model
42
+ def model(a_model_name)
43
+ if model = original_model(a_model_name)
44
+ model.class.find(model.id) or raise ActiveRecord::RecordNotFound, "model: #{a_model_name} could not be found in the database"
45
+ end
46
+ end
47
+
48
+ # predicate version which raises no errors
49
+ def model?(a_model_name)
50
+ (model(a_model_name) rescue nil) ? true : false
51
+ end
52
+
53
+ # return all original models of specified type
54
+ def original_models(factory)
55
+ models_by_factory(factory)
56
+ end
57
+
58
+ # return all models of specified type (freshly selected from the database)
59
+ def models(factory)
60
+ original_models(factory).map do |model|
61
+ model.class.find(model.id)
62
+ end
63
+ end
64
+
65
+ def parse_field_with_model(field)
66
+ if field =~ /^(\w+): (#{Match::Model})$/
67
+ {$1 => model($2)}
68
+ else
69
+ parse_field_without_model(field)
70
+ end
71
+ end
72
+ alias_method_chain :parse_field, :model
73
+
74
+ private
75
+ def convert_models_to_attributes(ar_class, attrs)
76
+ attrs.each do |key, val|
77
+ if val.is_a?(ActiveRecord::Base) && ar_class.column_names.include?("#{key}_id")
78
+ attrs["#{key}_id"] = val.id
79
+ attrs["#{key}_type"] = val.class.name if ar_class.column_names.include?("#{key}_type")
80
+ attrs.delete(key)
81
+ end
82
+ end
83
+ end
84
+
85
+ def models_by_name(factory)
86
+ @models_by_name ||= {}
87
+ @models_by_name[factory] ||= {}
88
+ end
89
+
90
+ def models_by_factory(factory)
91
+ @models_by_factory ||= {}
92
+ @models_by_factory[factory] ||= []
93
+ end
94
+
95
+ # if the factory name != the model name, store under both names
96
+ def store_model(factory, name, record)
97
+ store_record(canonical(record.class.name), name, record) if canonical(record.class.name) != factory
98
+ store_record(factory, name, record)
99
+ end
100
+
101
+ def store_record(factory, name, record)
102
+ models_by_name(factory)[name] = record
103
+ models_by_factory(factory) << record
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,27 @@
1
+ # inject the pickle session into integration session
2
+ Pickle::Injector.inject Pickle::Session, :into => ActionController::Integration::Session
3
+
4
+ # make some Regexp shortcuts for use in steps
5
+ MatchModel = Pickle::Parser::Match::Model
6
+ MatchFields = Pickle::Parser::Match::Fields
7
+
8
+ # start with some obvious steps
9
+ Given(/^(#{MatchModel}) exists$/) do |name|
10
+ create_model(name)
11
+ end
12
+
13
+ Given(/^(#{MatchModel}) exists with (#{MatchFields})$/) do |name, fields|
14
+ create_model(name, fields)
15
+ end
16
+
17
+ Then(/^(#{MatchModel}) should exist with (#{MatchFields})$/) do |name, fields|
18
+ find_model(name, fields).should_not == nil
19
+ end
20
+
21
+ Then(/^(#{MatchModel}) should be (?:an? )?"(.*?)"$/) do |name, predicate|
22
+ model(name).should send("be_#{predicate.gsub(' ','_')}")
23
+ end
24
+
25
+ Then(/^(#{MatchModel}) should not be (?:an? )?"(.*?)"$/) do |name, predicate|
26
+ model(name).should_not send("be_#{predicate.gsub(' ','_')}")
27
+ end
data/lib/pickle.rb ADDED
@@ -0,0 +1,47 @@
1
+ # Pickle == cucumber + factory
2
+ #
3
+ # = Usage
4
+ # # in features/steps/_env.rb
5
+ # require 'pickle/steps'
6
+ #
7
+ # If you need to configure pickle, do it like this
8
+ #
9
+ # Pickle::Config.map 'I|me|my', :to => 'user: "me"'
10
+ # require 'pickle/steps'
11
+ module Pickle
12
+ module Version
13
+ Major = 0
14
+ Minor = 1
15
+ Tiny = 1
16
+
17
+ String = [Major, Minor, Tiny].join('.')
18
+ end
19
+
20
+ module Config
21
+ class << self
22
+ attr_writer :model_names, :factory_names, :names, :mappings
23
+
24
+ def model_names
25
+ @model_names ||= Dir["#{RAILS_ROOT}/app/models/**/*.rb"].reject{|f| f =~ /observer.rb$/}.map{|f| f.sub("#{RAILS_ROOT}/app/models/",'').sub(".rb",'')}
26
+ end
27
+
28
+ def factory_names
29
+ require 'factory_girl'
30
+ @factory_names ||= Factory.factories.keys.map(&:to_s)
31
+ end
32
+
33
+ def names
34
+ @names ||= (model_names | factory_names)
35
+ end
36
+
37
+ def mappings
38
+ @mappings ||= []
39
+ end
40
+
41
+ def map(search, options)
42
+ raise ArgumentError, "Usage: map 'search', :to => 'replace'" unless search.is_a?(String) && options[:to].is_a?(String)
43
+ self.mappings << [search, options[:to]]
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,46 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Config do
4
+ before do
5
+ # zero pickle config before each example
6
+ [:names, :model_names, :factory_names, :mappings].each do |config_var|
7
+ instance_variable_set "@orig_#{config_var}", Pickle::Config.send(config_var)
8
+ Pickle::Config.send("#{config_var}=", nil)
9
+ end
10
+ end
11
+
12
+ after do
13
+ # restore pickle config back after each example
14
+ [:model_names, :factory_names, :names, :mappings].each do |config_var|
15
+ Pickle::Config.send "#{config_var}=", instance_variable_get("@orig_#{config_var}")
16
+ end
17
+ end
18
+
19
+ it ":factory_names should default to stringified keys of Factory.factories" do
20
+ Factory.factories.should_receive(:keys).and_return([:one, :two])
21
+ Pickle::Config.factory_names.should == ['one', 'two']
22
+ end
23
+
24
+ it ":model_names should default to directory listing of app/models excluding observers" do
25
+ models_path = "#{RAILS_ROOT}/app/models"
26
+ Dir.should_receive(:[]).with("#{models_path}/**/*.rb").and_return([
27
+ "#{models_path}/one.rb",
28
+ "#{models_path}/one/a.rb",
29
+ "#{models_path}/one/b.rb",
30
+ "#{models_path}/one/b/i.rb",
31
+ "#{models_path}/one_observer.rb",
32
+ "#{models_path}/two.rb"
33
+ ])
34
+ Pickle::Config.model_names.should == ['one', 'one/a', 'one/b', 'one/b/i', 'two']
35
+ end
36
+
37
+ it ":names should default to set (Array) :factory and :model names" do
38
+ Pickle::Config.factory_names = ['one', 'two']
39
+ Pickle::Config.model_names = ['two', 'one/a', 'one/b']
40
+ Pickle::Config.names.sort.should == ['one', 'one/a', 'one/b', 'two']
41
+ end
42
+
43
+ it ":mappings should default to []" do
44
+ Pickle::Config.mappings.should == []
45
+ end
46
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Injector do
4
+ describe ".inject Pickle::Session, :into => <a class>" do
5
+ before do
6
+ @class = Class.new
7
+ Pickle::Injector.inject Pickle::Session, :into => @class
8
+ @object = @class.new
9
+ end
10
+
11
+ it "object should respond_to Pickle:Session methods" do
12
+ @object.should respond_to(:model)
13
+ @object.should respond_to(:create_model)
14
+ @object.should respond_to(:find_model)
15
+ end
16
+
17
+ it "object.model (a pickle method) should call object.pickle_session.model" do
18
+ @object.pickle_session.should_receive(:model).with('a user')
19
+ @object.model('a user')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,164 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Parser do
4
+ include Pickle::Parser
5
+
6
+ describe "Match atoms" do
7
+ def self.atom_should_match(atom, strings)
8
+ Array(strings).each do |string|
9
+ it "#{atom} should match '#{string}'" do
10
+ string.should match(/^#{eval "Pickle::Parser::#{atom}"}$/)
11
+ end
12
+ end
13
+ end
14
+
15
+ def self.atom_should_not_match(atom, strings)
16
+ Array(strings).each do |string|
17
+ it "#{atom} should NOT match '#{string}'" do
18
+ string.should_not match(/^#{eval "Pickle::Parser::#{atom}"}$/)
19
+ end
20
+ end
21
+ end
22
+
23
+ atom_should_match 'Match::Ordinal', ['1st', '2nd', '23rd', '104th']
24
+ atom_should_not_match 'Match::Ordinal', ['1', '2']
25
+
26
+ atom_should_match 'Match::Index', ['first', 'last', '23rd', '104th']
27
+ atom_should_not_match 'Match::Index', ['1', '2', 'foo']
28
+
29
+ atom_should_match 'Match::Name', [': "gday"', ': "gday mate"']
30
+ atom_should_not_match 'Match::Name', [': "gday""', ': gday']
31
+
32
+ atom_should_match 'Match::Field', ['foo: "this is the life"', 'bar_man: "and so is this"']
33
+ atom_should_not_match 'Match::Field', ['foo bar: "this aint workin"']
34
+
35
+ atom_should_match 'Match::Fields', ['foo: "bar"', 'foo: "bar", baz: "bah"']
36
+ atom_should_not_match 'Match::Fields', ['foo bar: "baz"', 'email: "a", password: "b", and password_confirmation: "c"']
37
+
38
+ atom_should_match 'Match::Model', ['a user', '1st fast car', 'the 23rd fast_car', 'an event:create', 'the 2nd event/create', 'that event create: "zing"']
39
+ atom_should_not_match 'Match::Model', ['a giraffe', 'a 1st faster car: "jim"', 'an event created']
40
+
41
+ atom_should_match 'Match::ModelName', ['user', 'fast car', 'fast_car', 'event:create', 'event/create', 'event create']
42
+ atom_should_not_match 'Match::ModelName', ['users', 'faster car', 'event created']
43
+ end
44
+
45
+ describe 'misc regexps' do
46
+ describe '/^(#{Pickle::Parser::Match::Model}) exists/' do
47
+ before do
48
+ @regexp = /^(#{Pickle::Parser::Match::Model}) exists$/
49
+ end
50
+
51
+ it "should match 'a user exists'" do
52
+ 'a user exists'.should match(@regexp)
53
+ end
54
+
55
+ it "should caputure 'a user' from 'a user exists'" do
56
+ 'a user exists'.match(@regexp)[1].should == 'a user'
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#parse_field' do
62
+ it "should return {'a' => 'b'} for 'a: \"b\"'" do
63
+ parse_field('a: "b"').should == {'a' => 'b'}
64
+ end
65
+
66
+ it "should raise error for invalid field 'a : b'" do
67
+ lambda { parse_field('a : b') }.should raise_error(ArgumentError)
68
+ end
69
+ end
70
+
71
+ describe '#parse_fields' do
72
+ it 'should return {} for blank argument' do
73
+ parse_fields(nil).should == {}
74
+ parse_fields('').should == {}
75
+ end
76
+
77
+ it 'should raise error for invalid argument' do
78
+ lambda { parse_fields('foo foo') }.should raise_error(ArgumentError)
79
+ end
80
+
81
+ it '(\'foo: "bar"\') should == { "foo" => "bar"}' do
82
+ parse_fields('foo: "bar"').should == { "foo" => "bar"}
83
+ end
84
+
85
+ it '(\'foo: "bar", bar_man: "wonga wonga", gump: "123"\') should == {"foo" => "bar", "bar_man" => "wonga wonga", "gump" => "123"}' do
86
+ parse_fields('foo: "bar", bar_man: "wonga wonga", gump: "123"').should == {"foo" => "bar", "bar_man" => "wonga wonga", "gump" => "123"}
87
+ end
88
+ end
89
+
90
+ describe '#parse_model' do
91
+ it '("a user") should == ["user", ""]' do
92
+ parse_model("a user").should == ["user", ""]
93
+ end
94
+
95
+ it '("the user") should == ["user", ""]' do
96
+ parse_model("the user").should == ["user", ""]
97
+ end
98
+
99
+ it '("1 fast car") should == ["fast_car", ""]' do
100
+ parse_model("1 fast car").should == ["fast_car", ""]
101
+ end
102
+
103
+ it '(\'an user: "jim jones"\') should == ["user", "jim_jones"]' do
104
+ parse_model('an user: "jim jones"').should == ["user", "jim_jones"]
105
+ end
106
+
107
+ it '(\'that fast car: "herbie"\') should == ["fast_car", "herbie"]' do
108
+ parse_model('that fast car: "herbie"').should == ["fast_car", "herbie"]
109
+ end
110
+
111
+ it '(\'the 12th user\') should == ["user", 11]' do
112
+ parse_model('the 12th user').should == ["user", 11]
113
+ end
114
+
115
+ it '(\'the last user\') should == ["user", -1]' do
116
+ parse_model('the last user').should == ["user", -1]
117
+ end
118
+
119
+ it '("the first user") should == ["user", 0]' do
120
+ parse_model('the first user').should == ["user", 0]
121
+ end
122
+
123
+ it '("the 1st user") should == ["user", 0]' do
124
+ parse_model('the 1st user').should == ["user", 0]
125
+ end
126
+ end
127
+
128
+ describe "#parse_index" do
129
+ it '("1st") should == 0' do
130
+ parse_index("1st").should == 0
131
+ end
132
+
133
+ it '("24th") should == 23' do
134
+ parse_index("24th").should == 23
135
+ end
136
+ it '("first") should == 0' do
137
+ parse_index("first").should == 0
138
+ end
139
+
140
+ it '("last") should == -1' do
141
+ parse_index("last").should == -1
142
+ end
143
+ end
144
+
145
+ describe "customised mappings" do
146
+ describe 'Pickle::Config.map "I|myself", :to => \'user: "me"\'' do
147
+ it "'I' should match /\#{Pickle::Parser::Match::Model}/" do
148
+ 'I'.should match(/#{Pickle::Parser::Match::Model}/)
149
+ end
150
+
151
+ it "'myself' should match /\#{Pickle::Parser::Match::Model}/" do
152
+ 'myself'.should match(/#{Pickle::Parser::Match::Model}/)
153
+ end
154
+
155
+ it "parse_the_model_name('I') should == ['user', 'me']" do
156
+ parse_model('I').should == ["user", "me"]
157
+ end
158
+
159
+ it "parse_the_model_name('myself') should == ['user', 'me']" do
160
+ parse_model('I').should == ["user", "me"]
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,281 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Session do
4
+ before do
5
+ @session = Pickle::Session.new
6
+ end
7
+
8
+ describe "after storing a single user", :shared => true do
9
+ it "original_models('user') should be array containing the original user" do
10
+ @session.original_models('user').should == [@user]
11
+ end
12
+
13
+ describe "the original user should be retrievable with" do
14
+ it "original_model('the user')" do
15
+ @session.original_model('the user').should == @user
16
+ end
17
+
18
+ it "original_model('1st user')" do
19
+ @session.original_model('1st user').should == @user
20
+ end
21
+
22
+ it "original_model('last user')" do
23
+ @session.original_model('last user').should == @user
24
+ end
25
+ end
26
+
27
+ describe "(found from db)" do
28
+ before do
29
+ @user.stub!(:id).and_return(100)
30
+ @user.class.should_receive(:find).with(100).and_return(@user_from_db = @user.dup)
31
+ end
32
+
33
+ it "models('user') should be array containing user" do
34
+ @session.models('user').should == [@user_from_db]
35
+ end
36
+
37
+ describe "user should be retrievable with" do
38
+ it "model('the user')" do
39
+ @session.model('the user').should == @user_from_db
40
+ end
41
+
42
+ it "model('1st user')" do
43
+ @session.model('1st user').should == @user_from_db
44
+ end
45
+
46
+ it "model('last user')" do
47
+ @session.model('last user').should == @user_from_db
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#create_model" do
54
+ before do
55
+ @user = mock_model(User)
56
+ Factory.stub!(:create).and_return(@user)
57
+ end
58
+
59
+ describe "('a user')" do
60
+ def do_create_model
61
+ @session.create_model('a user')
62
+ end
63
+
64
+ it "should call Factory.create('user', {})" do
65
+ Factory.should_receive(:create).with('user', {}).and_return(@user)
66
+ do_create_model
67
+ end
68
+
69
+ describe "after create," do
70
+ before { do_create_model }
71
+
72
+ it_should_behave_like "after storing a single user"
73
+ end
74
+ end
75
+
76
+ describe "('1 user', 'foo: \"bar\", baz: \"bing bong\"')" do
77
+ def do_create_model
78
+ @session.create_model('1 user', 'foo: "bar", baz: "bing bong"')
79
+ end
80
+
81
+ it "should call Factory.create('user', {'foo' => 'bar', 'baz' => 'bing bong'})" do
82
+ Factory.should_receive(:create).with('user', {'foo' => 'bar', 'baz' => 'bing bong'}).and_return(@user)
83
+ do_create_model
84
+ end
85
+
86
+ describe "after create," do
87
+ before { do_create_model }
88
+
89
+ it_should_behave_like "after storing a single user"
90
+ end
91
+ end
92
+
93
+ describe "('an user: \"fred\")" do
94
+ def do_create_model
95
+ @session.create_model('an user: "fred"')
96
+ end
97
+
98
+ it "should call Factory.create('user', {})" do
99
+ Factory.should_receive(:create).with('user', {}).and_return(@user)
100
+ do_create_model
101
+ end
102
+
103
+ describe "after create," do
104
+ before { do_create_model }
105
+
106
+ it_should_behave_like "after storing a single user"
107
+
108
+ it "original_model('the user: \"fred\"') should retrieve the user" do
109
+ @session.original_model('the user: "fred"').should == @user
110
+ end
111
+
112
+ it "original_model?('the user: \"shirl\"') should be false" do
113
+ @session.original_model?('the user: "shirl"').should == false
114
+ end
115
+
116
+ it "model?('the user: \"shirl\"') should be false" do
117
+ @session.model?('the user: "shirl"').should == false
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ describe '#find_model' do
124
+ before do
125
+ @user = mock_model(User)
126
+ User.stub!(:find).and_return(@user)
127
+ end
128
+
129
+ def do_find_model
130
+ @session.find_model('a user', 'hair: "pink"')
131
+ end
132
+
133
+ it "should call User.find :first, :conditions => {'hair' => 'pink'}" do
134
+ User.should_receive(:find).with(:first, :conditions => {'hair' => 'pink'}).and_return(@user)
135
+ do_find_model
136
+ end
137
+
138
+ it "should raise RecordNotFound when no record returned" do
139
+ User.should_receive(:find).and_return(nil)
140
+ lambda { do_find_model }.should raise_error(ActiveRecord::RecordNotFound)
141
+ end
142
+
143
+ describe "after find," do
144
+ before { do_find_model }
145
+
146
+ it_should_behave_like "after storing a single user"
147
+ end
148
+ end
149
+
150
+ describe 'creating \'a super admin: "fred"\', then \'a user: "shirl"\', \'then 1 super_admin\'' do
151
+ before do
152
+ @user = @fred = mock_model(User)
153
+ @shirl = mock_model(User)
154
+ @noname = mock_model(User)
155
+ Factory.stub!(:create).and_return(@fred, @shirl, @noname)
156
+ end
157
+
158
+ def do_create_users
159
+ @session.create_model('a super admin: "fred"')
160
+ @session.create_model('a user: "shirl"')
161
+ @session.create_model('1 super_admin')
162
+ end
163
+
164
+ it "should call Factory.create with <'super_admin'>, <'user'>, <'super_admin'>" do
165
+ Factory.should_receive(:create).with('super_admin', {}).twice
166
+ Factory.should_receive(:create).with('user', {}).once
167
+ do_create_users
168
+ end
169
+
170
+ describe "after create," do
171
+ before do
172
+ do_create_users
173
+ end
174
+
175
+ it "original_models('user') should == [@fred, @shirl, @noname]" do
176
+ @session.original_models('user').should == [@fred, @shirl, @noname]
177
+ end
178
+
179
+ it "original_models('super_admin') should == [@fred, @noname]" do
180
+ @session.original_models('super_admin').should == [@fred, @noname]
181
+ end
182
+
183
+ describe "#original_model" do
184
+ it "'that user' should be @noname (the last user created - as super_admins are users)" do
185
+ @session.original_model('that user').should == @noname
186
+ end
187
+
188
+ it "'the super admin' should be @noname (the last super admin created)" do
189
+ @session.original_model('that super admin').should == @noname
190
+ end
191
+
192
+ it "'the 1st super admin' should be @fred" do
193
+ @session.original_model('the 1st super admin').should == @fred
194
+ end
195
+
196
+ it "'the first user' should be @fred" do
197
+ @session.original_model('the first user').should == @fred
198
+ end
199
+
200
+ it "'the 2nd user' should be @shirl" do
201
+ @session.original_model('the 2nd user').should == @shirl
202
+ end
203
+
204
+ it "'the last user' should be @noname" do
205
+ @session.original_model('the last user').should == @noname
206
+ end
207
+
208
+ it "'the user: \"fred\" should be @fred" do
209
+ @session.original_model('the user: "fred"').should == @fred
210
+ end
211
+
212
+ it "'the user: \"shirl\" should be @shirl" do
213
+ @session.original_model('the user: "shirl"').should == @shirl
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ describe "when 'the user: \"me\"' exists (and there is a mapping from 'I|myself' => 'user: \"me\")" do
220
+ before do
221
+ @user = mock_model(User)
222
+ User.stub!(:find).and_return(@user)
223
+ Factory.stub!(:create).and_return(@user)
224
+ @session.create_model('the user: "me"')
225
+ end
226
+
227
+ it 'model("I") should return the user' do
228
+ @session.model('I').should == @user
229
+ end
230
+
231
+ it 'model("myself") should return the user' do
232
+ @session.model('myself').should == @user
233
+ end
234
+
235
+ it "#parse_fields 'author: user \"JIM\"' should raise Error, as model deos not refer" do
236
+ lambda { @session.parse_fields('author: user "JIM"') }.should raise_error
237
+ end
238
+
239
+ it "#parse_fields 'author: the user' should return {\"author\" => <user>}" do
240
+ @session.parse_fields('author: the user').should == {"author" => @user}
241
+ end
242
+
243
+ it "#parse_fields 'author: myself' should return {\"author\" => <user>}" do
244
+ @session.parse_fields('author: myself').should == {"author" => @user}
245
+ end
246
+
247
+ it "#parse_fields 'author: the user, approver: I, rating: \"5\"' should return {'author' => <user>, 'approver' => <user>, 'rating' => '5'}" do
248
+ @session.parse_fields('author: the user, approver: I, rating: "5"').should == {'author' => @user, 'approver' => @user, 'rating' => '5'}
249
+ end
250
+
251
+ it "#parse_fields 'author: user: \"me\", approver: \"\"' should return {'author' => <user>, 'approver' => \"\"}" do
252
+ @session.parse_fields('author: user: "me", approver: ""').should == {'author' => @user, 'approver' => ""}
253
+ end
254
+ end
255
+
256
+ describe "convert_models_to_attributes(ar_class, :user => <a user>)" do
257
+ before do
258
+ @user = mock_model(User)
259
+ end
260
+
261
+ describe "(when ar_class has column 'user_id')" do
262
+ before do
263
+ @ar_class = mock('ActiveRecord', :column_names => ['user_id'])
264
+ end
265
+
266
+ it "should return {'user_id' => <the user.id>}" do
267
+ @session.send(:convert_models_to_attributes, @ar_class, :user => @user).should == {'user_id' => @user.id}
268
+ end
269
+ end
270
+
271
+ describe "(when ar_class has columns 'user_id', 'user_type')" do
272
+ before do
273
+ @ar_class = mock('ActiveRecord', :column_names => ['user_id', 'user_type'])
274
+ end
275
+
276
+ it "should return {'user_id' => <the user.id>, 'user_type' => <the user.type>}" do
277
+ @session.send(:convert_models_to_attributes, @ar_class, :user => @user).should == {'user_id' => @user.id, 'user_type' => @user.class.name}
278
+ end
279
+ end
280
+ end
281
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ianwhite-pickle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Ian White
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-27 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Easy model creation and reference in your cucumber features
17
+ email: ian.w.white@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/pickle/injector.rb
26
+ - lib/pickle/parser.rb
27
+ - lib/pickle/session.rb
28
+ - lib/pickle/steps.rb
29
+ - lib/pickle.rb
30
+ - License.txt
31
+ - README.textile
32
+ - Todo.txt
33
+ - History.txt
34
+ - spec/lib/pickle_config_spec.rb
35
+ - spec/lib/pickle_injector_spec.rb
36
+ - spec/lib/pickle_parser_spec.rb
37
+ - spec/lib/pickle_session_spec.rb
38
+ has_rdoc: true
39
+ homepage: http://github.com/ianwhite/pickle/tree
40
+ post_install_message:
41
+ rdoc_options:
42
+ - --title
43
+ - Pickle
44
+ - --line-numbers
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: Easy model creation and reference in your cucumber features
66
+ test_files:
67
+ - spec/lib/pickle_config_spec.rb
68
+ - spec/lib/pickle_injector_spec.rb
69
+ - spec/lib/pickle_parser_spec.rb
70
+ - spec/lib/pickle_session_spec.rb