ianwhite-pickle 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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