mrflip-pickle 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,147 @@
1
+ == 0.1.13 - 16 June 2009
2
+
3
+ * 2 minor enhancements
4
+ * model! and created_model! raise an error if pickle name can't be found
5
+ * path_to_pickle uses the above to give back a better error message
6
+
7
+
8
+ == 0.1.12 - 7 Apr 2009
9
+
10
+ * 2 minor enhancements
11
+ * rationalised Rakefile
12
+ * update World extensions for latest cucumber changes
13
+
14
+
15
+ == 0.1.11 - 22 Feb 2009
16
+
17
+ * 2 minor enhancements
18
+ * Pickle now supports multiple machinist blueprints
19
+ * Fix confusing adapter/adaptor comment generator comment
20
+
21
+
22
+ == 0.1.10 - 13 Feb 2009
23
+
24
+ * 2 minor enhancements
25
+ * Made pickle paths generator compatible with latest cucumber
26
+ * Simplified and Rakefile, including auto push api docs to gh-pages on ci build
27
+
28
+
29
+ == 0.1.9 - 29 Jan 2009
30
+
31
+ * 1 minor enhancement
32
+ * Pickle::Adapter.model_classes excludes those without tables
33
+
34
+
35
+ == 0.1.8 - 29 Jan 2009
36
+
37
+ * API change
38
+ * pickle_path becomes path_to_pickle, to avoid named route clashes
39
+
40
+ * 2 minor enhancements
41
+ * Updated features for cucumber 0.2 compat
42
+ * Made paths allow for optional possesives
43
+
44
+
45
+ == 0,1,7
46
+
47
+ * 2 API changes
48
+ * script/generate pickle path[s] now amends the features/support/paths.rb file
49
+ instead of creating pge_to_path and path_steps.
50
+
51
+ * pickle_email_steps is renamed email_steps
52
+
53
+
54
+ == 0.1.6
55
+
56
+ * 1 API change
57
+ * to use pickle env.rb should contain "require 'pickle/world'". You should remove all trace of
58
+ pickle from features/support/env.rb and re run script/generate pickle
59
+
60
+ * 2 major enhancements
61
+
62
+ * generate email steps with `script/generate pickle email`
63
+ email steps allow you to do things like this:
64
+
65
+ Then 2 emails should be delivered
66
+ And the first email should be delivered to fred@gmail.com
67
+ And the 2nd email should be delivered to the user: "ethel"
68
+
69
+ Then 1 email should be delivered with subject: "Activate your account"
70
+ And the email should link to the user's page
71
+
72
+ take a look at features/step_definitions/pickle_email_steps.rb
73
+
74
+ * generate path steps with `script/generate pickle path`
75
+ path steps allow you to do things like this
76
+
77
+ When I go to the comment's page
78
+ Then I should be at the user's new comment page
79
+
80
+ take a look at features/step_definitions/pickle_path_steps.rb, and modify page_to_path to suit your needs
81
+
82
+ * 4 minor enhancements
83
+ * Improved documentation
84
+ * abstract models no longer kill pickle
85
+ * Actually test that the generators work
86
+ * Made Pickle::Session a plain ole mixin, as a separate class was unnecessary
87
+ * Pickle uses the cucumber World API
88
+
89
+
90
+ == 0.1.5
91
+
92
+ * API change
93
+ * CaptureModel, etc are now 'capture_model' methods
94
+
95
+ * 3 major enhancements
96
+ * Steps for asserting that <n> models exist, matching certain criteria
97
+ * Steps for asserting associations added to generated pickle steps
98
+ 'Then the user should be in the post's commenters'
99
+ 'Then the forum: "awesome" should be the 2nd post's forum'
100
+ * configuration can now occur any time before a step is defined, which makes
101
+ for much more intuitive env.rb
102
+
103
+ * 2 minor enhancement
104
+ * predicate matching is less prone to step conflicts because we preload a
105
+ big list of all the predicate and column methods
106
+ * field values now handle booleans and numerics
107
+
108
+
109
+ == 0.1.4
110
+
111
+ * 1 major enhancement
112
+ * You can create multiple models with ease, for eg.
113
+ 'Given 10 users exist with role: "admin"'
114
+
115
+ * 1 minor enhancement
116
+ * You can do Pickle.configure (just like Webrat.configure)
117
+
118
+
119
+ == 0.1.3 - Bugfix release
120
+
121
+ * 1 minor enhancement
122
+ * make generated steps compatible with Rails 2.1
123
+
124
+
125
+ == 0.1.2
126
+
127
+ * 2 major enhancements
128
+ * create your pickle steps with script/generate pickle
129
+ * Adapter based architecture, supports Machinist, FactoryGirl, and vanilla ActiveRecord
130
+
131
+ * 1 minor enhancement
132
+ * model_names now defaults to subclasses of AR::Base
133
+ * #original_model => #created_model
134
+
135
+
136
+ == 0.1.1
137
+
138
+ * 1 major enhancement:
139
+ * made pickle a github gem
140
+
141
+ * 1 minor enhancement:
142
+ * Added intentions for pickle in README.textile
143
+
144
+
145
+ == Prior to gems
146
+
147
+ * Initial release: everything is subject to sweeping change
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2009 Ian White - ian.w.white@gmail.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.
@@ -0,0 +1,202 @@
1
+ = pickle
2
+
3
+ Pickle gives you cucumber steps that create your models easily from factory-girl or
4
+ machinist factories/blueprints. You can also just use ActiveRecord but it's not as cool.
5
+
6
+ References to the models are stored, not necessarily for the purpose of checking the db
7
+ (although you could use it for that), but for enabling easy reference to urls, and for
8
+ building complex givens which require a bunch of models collaborating
9
+
10
+ == CI
11
+
12
+ It's tested against all stable branches of 2.x rails, and edge, with the latest versions of rspec, cucumber, factory_girl, machinist.
13
+
14
+ == Install
15
+
16
+ Install pickle either as a rails plugin, or a gem
17
+
18
+ # plugin
19
+ script/plugin install git://github.com/ianwhite/pickle.git
20
+
21
+ # or, plugin as submodule
22
+ git submodule add git://github.com/ianwhite/pickle.git vendor/plugins/pickle
23
+
24
+ # or, gem
25
+ sudo gem install ianwhite-pickle
26
+
27
+ == Get Started
28
+
29
+ (you'd better install cucumber)
30
+
31
+ script/generate pickle [paths] [email]
32
+
33
+ Now have a look at <tt>features/step_definitions/pickle_steps.rb</tt>
34
+
35
+ If you want path steps and email steps then just add 'paths' and/or 'email'. The code/steps will be
36
+ written to <tt>features/env/paths.rb</tt> and
37
+ <tt>features/step_definitions/email_steps.rb</tt> respectively.
38
+
39
+ === Using with plain ole Active Record
40
+
41
+ If you have an AR called 'Post', with required fields 'title', and 'body', then you can now write
42
+ steps like this
43
+
44
+ Given a post exists with title: "My Post", body: "My body"
45
+
46
+ === Using with factory-girl or machinist
47
+
48
+ But you're using Machinist or FactoryGirl right?! To leverage all of the factories/blueprints
49
+ you've written, you can just do stuff like
50
+
51
+ Given a user exists
52
+ And another user exists with role: "admin"
53
+
54
+ # later
55
+ Then a user should exist with name: "Fred"
56
+ And that user should be activated # this uses rspec predicate matchers
57
+
58
+ ==== Machinst: require your blueprints and reset Shams
59
+
60
+ (The latest version of pickle supports {multiple blueprints}[http://github.com/notahat/machinist/commit/d6492e6927a8aa1819926e48b22377171fd20496], for
61
+ earlier versions of machinist use pickle <= 0.1.10)
62
+
63
+ In your <tt>features/support/env.rb</tt> add the following lines at the bottom
64
+
65
+ require "#{Rails.root}/spec/blueprints" # or wherever they live
66
+ Before { Sham.reset } # reset Shams in between scenarios
67
+
68
+ === Configuring Pickle
69
+
70
+ You can tell pickle to use another factory adapter (see Pickle::Adapter), or
71
+ create mappings from english expressions to pickle model names. You can also
72
+ override many of the options on the Pickle::Config object if you so choose
73
+
74
+ require 'pickle/world'
75
+
76
+ Pickle.configure do |config|
77
+ config.adapters = [:machinist, YourOwnAdapterClass]
78
+ config.map 'me', 'myself', 'my', 'I', :to => 'user: "me"'
79
+ end
80
+
81
+ == API
82
+
83
+ === Steps
84
+
85
+ When you run <tt>script/generate pickle</tt> you get the following steps
86
+
87
+ ==== Given steps
88
+
89
+ "Given <b>a model</b> exists", e.g.
90
+
91
+ Given a user exists
92
+ Given a user: "fred" exists
93
+ Given the user exists
94
+
95
+ "Given <b>a model</b> exists with <b>fields</b>", e.g.
96
+
97
+ Given a user exists with name: "Fred"
98
+ Given a user exists with name: "Fred", activated: false
99
+
100
+ You can refer to other models in the fields
101
+
102
+ Given a user exists
103
+ And a post exists with author: the user
104
+
105
+ Given a person: "fred" exists
106
+ And a person: "ethel" exists
107
+ And a fatherhood exists with parent: user "fred", child: user "ethel"
108
+
109
+ "Given <b>n</b> models exist", e.g.
110
+
111
+ Given 10 users exist
112
+
113
+ "Given <b>n</b> <b>models</b> exist with <b>fields</b>", examples:
114
+
115
+ Given 10 users exist with activated: false
116
+
117
+ ==== Then steps
118
+
119
+ ===== Asserting existence of models
120
+
121
+ "Then <b>a model</b> should exist", e.g.
122
+
123
+ Then a user should exist
124
+
125
+ "Then <b>a model</b> should exist with <b>fields</b>", e.g.
126
+
127
+ Then a user: "fred" should exist with name: "Fred" # we can label the found user for later use
128
+
129
+ You can use other models, booleans, numerics, and strings as fields
130
+
131
+ Then a person should exist with child: person "ethel"
132
+ Then a user should exist with activated: false
133
+ Then a user should exist with activated: true, email: "fred@gmail.com"
134
+
135
+ "Then <b>n</b> <b>models</b> should exist", e.g.
136
+
137
+ Then 10 events should exist
138
+
139
+ "Then <b>n</b> <b>models</b> should exist with <b>fields</b>", e.g.
140
+
141
+ Then 2 people should exist with father: person "fred"
142
+
143
+ ===== Asserting associations
144
+
145
+ One-to-one assocs: "Then <b>a model</b> should be <b>other model</b>'s <b>association</b>", e.g.
146
+
147
+ Then the person: "fred" should be person: "ethel"'s father
148
+
149
+ Many-to-one assocs: "Then <b>a model</b> should be [in|one of] <b>other model</b>'s <b>association</b>", e.g.
150
+
151
+ Then the person: "ethel" should be one of person: "fred"'s children
152
+ Then the comment should be in the post's comments
153
+
154
+ ===== Asserting predicate methods
155
+
156
+ "Then <b>a model</b> should [be|have] [a|an] <b>predicate</b>", e.g.
157
+
158
+ Then the user should have a status # => user.status?.should == true
159
+ Then the car: "batmobile" should be fast # => car.fast?.should == true
160
+
161
+ "Then <b>a model</b> should [be|have] [a|an] <b>predicate</b>", e.g.
162
+
163
+ Then person: "fred" should not be childless # => fred.childless?.should == false
164
+
165
+ === Regexps for use in your own steps
166
+
167
+ By default you get some regexps available in the main namespace for use
168
+ in creating your own steps: `capture_model`, `capture_fields`, and others (see lib/pickle.rb)
169
+
170
+ (You can use any of the regexps that Pickle uses by using the Pickle.parser namespace, see
171
+ Pickle::Parser::Matchers for the methods available)
172
+
173
+ *capture_model*
174
+
175
+ Given /^#{capture_model} exists$/ do |model_name|
176
+ model(model_name).should_not == nil
177
+ end
178
+
179
+ Then /^I should be at the (.*?) page$/ |page|
180
+ if page =~ /#{capture_model}'s/
181
+ url_for(model($1))
182
+ else
183
+ # ...
184
+ end
185
+ end
186
+
187
+ Then /^#{capture_model} should be one of #{capture_model}'s posts$/ do |post, forum|
188
+ model(forum).posts.should include(post)
189
+ end
190
+
191
+ *capture_fields*
192
+
193
+ This is useful for setting attributes, and knows about pickle model names so that you
194
+ can build up composite objects with ease
195
+
196
+ Given /^#{capture_model} exists with #{capture_fields}$/ do |model_name, fields|
197
+ create_model(model_name, fields)
198
+ end
199
+
200
+ # example of use
201
+ Given a user exists
202
+ And a post exists with author: the user # this step will assign the above user as :author on the post
@@ -0,0 +1,4 @@
1
+ * Add email_for (same concept as path_to)
2
+ * fix problem with save_and_open_emails
3
+ * Translations
4
+ * Investigate using Treetop for pre-parsing
@@ -0,0 +1,26 @@
1
+ require 'active_support'
2
+ require 'pickle/version'
3
+ require 'pickle/adapter'
4
+ require 'pickle/config'
5
+ require 'pickle/parser'
6
+ require 'pickle/session'
7
+ require 'pickle/session/parser'
8
+
9
+ # make the parser aware of models in the session (for fields refering to models)
10
+ Pickle::Parser.send :include, Pickle::Session::Parser
11
+
12
+ module Pickle
13
+ class << self
14
+ def config
15
+ @config ||= Config.new
16
+ end
17
+
18
+ def configure(&block)
19
+ config.configure(&block)
20
+ end
21
+
22
+ def parser(options = {})
23
+ @parser ||= Parser.new({:config => config}.merge(options))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,87 @@
1
+ module Pickle
2
+ # Abstract Factory adapter class, if you have a factory type setup, you
3
+ # can easily create an adaptor to make it work with Pickle.
4
+ #
5
+ # The factory adaptor must have a #factories class method that returns
6
+ # its instances, and each instance must respond to:
7
+ #
8
+ # #name : identifies the factory by name (default is attr_reader)
9
+ # #klass : returns the associated model class for this factory (default is attr_reader)
10
+ # #create(attrs = {}) : returns a newly created object
11
+ class Adapter
12
+ attr_reader :name, :klass
13
+
14
+ def self.factories
15
+ raise NotImplementedError, "return an array of factory adapter objects"
16
+ end
17
+
18
+ def create(attrs = {})
19
+ raise NotImplementedError, "create and return an object with the given attributes"
20
+ end
21
+
22
+ cattr_writer :model_classes
23
+ self.model_classes = nil
24
+
25
+ def self.model_classes
26
+ # remove abstract, framework, and non-table classes
27
+ @@model_classes ||= ::ActiveRecord::Base.send(:subclasses).reject do |klass|
28
+ klass.abstract_class? || !klass.table_exists? ||
29
+ (defined?(CGI::Session::ActiveRecordStore::Session) && klass == CGI::Session::ActiveRecordStore::Session) ||
30
+ (defined?(::ActiveRecord::SessionStore::Session) && klass == ::ActiveRecord::SessionStore::Session)
31
+ end
32
+ end
33
+
34
+ # machinist adapter
35
+ class Machinist < Adapter
36
+ def self.factories
37
+ factories = []
38
+ model_classes.each do |klass|
39
+ if blueprints = klass.instance_variable_get('@blueprints')
40
+ blueprints.keys.each {|blueprint| factories << new(klass, blueprint)}
41
+ end
42
+ end
43
+ factories
44
+ end
45
+
46
+ def initialize(klass, blueprint)
47
+ @klass, @blueprint = klass, blueprint
48
+ @name = @klass.name.underscore.gsub('/','_')
49
+ @name = "#{@blueprint}_#{@name}" unless @blueprint == :master
50
+ end
51
+
52
+ def create(attrs = {})
53
+ @klass.send(:make, @blueprint, attrs)
54
+ end
55
+ end
56
+
57
+ # factory-girl adapter
58
+ class FactoryGirl < Adapter
59
+ def self.factories
60
+ (::Factory.factories.values rescue []).map {|factory| new(factory)}
61
+ end
62
+
63
+ def initialize(factory)
64
+ @klass, @name = factory.build_class, factory.factory_name.to_s
65
+ end
66
+
67
+ def create(attrs = {})
68
+ Factory.create(@name, attrs)
69
+ end
70
+ end
71
+
72
+ # fallback active record adapter
73
+ class ActiveRecord < Adapter
74
+ def self.factories
75
+ model_classes.map {|klass| new(klass) }
76
+ end
77
+
78
+ def initialize(klass)
79
+ @klass, @name = klass, klass.name.underscore.gsub('/','_')
80
+ end
81
+
82
+ def create(attrs = {})
83
+ @klass.send(:create!, attrs)
84
+ end
85
+ end
86
+ end
87
+ end