pickle 0.2.12 → 0.3.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/History.txt +7 -0
- data/README.rdoc +46 -26
- data/VERSION +1 -1
- data/lib/pickle/adapter.rb +48 -23
- data/lib/pickle/adapters/active_record.rb +46 -0
- data/lib/pickle/adapters/data_mapper.rb +37 -0
- data/lib/pickle/config.rb +2 -2
- data/lib/pickle/email.rb +4 -4
- data/lib/pickle/session.rb +24 -9
- data/lib/pickle/world.rb +4 -0
- data/pickle.gemspec +3 -1
- data/spec/pickle/adapter_spec.rb +41 -61
- data/spec/pickle/config_spec.rb +27 -19
- data/spec/pickle/email_spec.rb +26 -23
- data/spec/pickle/session_spec.rb +80 -78
- data/spec/spec_helper.rb +2 -0
- metadata +6 -4
data/History.txt
CHANGED
data/README.rdoc
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
= pickle
|
2
2
|
|
3
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.
|
4
|
+
machinist factories/blueprints. You can also just use ActiveRecord as a factory but it's not as cool.
|
5
|
+
|
6
|
+
Pickle can make use of different ORMs for finding records. Currently ActiveRecord and DataMapper adapters are
|
7
|
+
provided. More adapters welcome!
|
5
8
|
|
6
9
|
References to the models are stored in the current world, not necessarily for the purpose of checking the db
|
7
10
|
(although you could use it for that), but for enabling easy reference to urls, and for
|
@@ -35,7 +38,7 @@ Install pickle either as a rails plugin, or a gem
|
|
35
38
|
|
36
39
|
# plugin
|
37
40
|
script/plugin install git://github.com/ianwhite/pickle.git
|
38
|
-
|
41
|
+
|
39
42
|
# or, plugin as submodule
|
40
43
|
git submodule add git://github.com/ianwhite/pickle.git vendor/plugins/pickle
|
41
44
|
|
@@ -48,7 +51,7 @@ It's tested against all stable branches of 2.x rails, and edge, with the latest
|
|
48
51
|
To run the specs do:
|
49
52
|
|
50
53
|
rake spec
|
51
|
-
|
54
|
+
|
52
55
|
To run the features (rails 2.3 only ATM):
|
53
56
|
|
54
57
|
rake cucumber
|
@@ -57,6 +60,8 @@ To run the features (rails 2.3 only ATM):
|
|
57
60
|
|
58
61
|
The following people have made Pickle better:
|
59
62
|
|
63
|
+
* {Daniel Neighman}[http://github.com/hassox]
|
64
|
+
* {Josh Bassett}[http://github.com/nullobject]
|
60
65
|
* {Nick Rutherford}[http://github.com/nruth]
|
61
66
|
* {Tobi Knaup}[http://github.com/guenter]
|
62
67
|
* {Michael MacDonald}[http://github.com/schlick]
|
@@ -77,9 +82,11 @@ If you want path steps and email steps then just add 'paths' and/or 'email'. Th
|
|
77
82
|
written to <tt>features/env/paths.rb</tt> and
|
78
83
|
<tt>features/step_definitions/email_steps.rb</tt> respectively.
|
79
84
|
|
80
|
-
=== Using with plain ole Active Record
|
85
|
+
=== Using with plain ole Active Record or DataMapper
|
86
|
+
|
87
|
+
Pickle comes with adapters for Active Record and DataMapper.
|
81
88
|
|
82
|
-
If you have an AR called 'Post', with required fields 'title', and 'body', then you can now write
|
89
|
+
If you have an AR/DM called 'Post', with required fields 'title', and 'body', then you can now write
|
83
90
|
steps like this
|
84
91
|
|
85
92
|
Given a post exists with title: "My Post", body: "My body"
|
@@ -98,7 +105,7 @@ you've written, you can just do stuff like
|
|
98
105
|
|
99
106
|
==== Machinst: require your blueprints and reset Shams
|
100
107
|
|
101
|
-
(The latest version of pickle supports {multiple blueprints}[http://github.com/notahat/machinist/commit/d6492e6927a8aa1819926e48b22377171fd20496], for
|
108
|
+
(The latest version of pickle supports {multiple blueprints}[http://github.com/notahat/machinist/commit/d6492e6927a8aa1819926e48b22377171fd20496], for
|
102
109
|
earlier versions of machinist use pickle <= 0.1.10)
|
103
110
|
|
104
111
|
In your <tt>features/support/env.rb</tt> add the following lines at the bottom
|
@@ -115,6 +122,19 @@ If that doesn't solve loading issues then require your factories.rb file directl
|
|
115
122
|
# example features/support/factory_girl.rb
|
116
123
|
require File.dirname(__FILE__) + '/../../spec/factories'
|
117
124
|
|
125
|
+
=== Using with an ORM other than ActiveRecord or DataMapper
|
126
|
+
|
127
|
+
Pickle can be used with any Modeling library provided there is an adapter written for it.
|
128
|
+
|
129
|
+
Adapters are very simple and exist a module or class with the name "PickleAdapter" available to the class. For example
|
130
|
+
|
131
|
+
User.const_get(:PickleAdapter) #=> should return a pickle adapter
|
132
|
+
|
133
|
+
The Active Record and DataMapper ones can be found at
|
134
|
+
ActiveRecord::Base::PickleAdapter and DataMapper::Resource::PickleAdapter respectively.
|
135
|
+
|
136
|
+
See how to implement one by looking at the ones provided in the pickle source in lib/pickle/adapters/*
|
137
|
+
|
118
138
|
=== Configuring Pickle
|
119
139
|
|
120
140
|
You can tell pickle to use another factory adapter (see Pickle::Adapter), or
|
@@ -129,7 +149,7 @@ In: <tt>features/support/pickle.rb</tt>
|
|
129
149
|
config.adapters = [:machinist, YourOwnAdapterClass]
|
130
150
|
config.map 'me', 'myself', 'my', 'I', :to => 'user: "me"'
|
131
151
|
end
|
132
|
-
|
152
|
+
|
133
153
|
Out of the box pickle looks for machinist, then factory-girl, then finally active-record 'factories'.
|
134
154
|
If you find that your steps aren't working with your factories, it's probably the case that your factory
|
135
155
|
setup is not being included in your cucumber environment (see comments above regarding machinist and factory-girl).
|
@@ -147,29 +167,29 @@ When you run <tt>script/generate pickle</tt> you get the following steps
|
|
147
167
|
Given a user exists
|
148
168
|
Given a user: "fred" exists
|
149
169
|
Given the user exists
|
150
|
-
|
170
|
+
|
151
171
|
"Given <b>a model</b> exists with <b>fields</b>", e.g.
|
152
172
|
|
153
173
|
Given a user exists with name: "Fred"
|
154
174
|
Given a user exists with name: "Fred", activated: false
|
155
|
-
|
175
|
+
|
156
176
|
You can refer to other models in the fields
|
157
177
|
|
158
178
|
Given a user exists
|
159
179
|
And a post exists with author: the user
|
160
|
-
|
180
|
+
|
161
181
|
Given a person: "fred" exists
|
162
182
|
And a person: "ethel" exists
|
163
183
|
And a fatherhood exists with parent: user "fred", child: user "ethel"
|
164
|
-
|
184
|
+
|
165
185
|
"Given <b>n models</b> exist", e.g.
|
166
|
-
|
186
|
+
|
167
187
|
Given 10 users exist
|
168
|
-
|
188
|
+
|
169
189
|
"Given <b>n models</b> exist with <b>fields</b>", examples:
|
170
190
|
|
171
191
|
Given 10 users exist with activated: false
|
172
|
-
|
192
|
+
|
173
193
|
"Given the following <b>models</b> exist:", examples:
|
174
194
|
|
175
195
|
Given the following users exist
|
@@ -188,21 +208,21 @@ You can refer to other models in the fields
|
|
188
208
|
"Then <b>a model</b> should exist with <b>fields</b>", e.g.
|
189
209
|
|
190
210
|
Then a user: "fred" should exist with name: "Fred" # we can label the found user for later use
|
191
|
-
|
211
|
+
|
192
212
|
You can use other models, booleans, numerics, and strings as fields
|
193
213
|
|
194
214
|
Then a person should exist with child: person "ethel"
|
195
215
|
Then a user should exist with activated: false
|
196
216
|
Then a user should exist with activated: true, email: "fred@gmail.com"
|
197
|
-
|
217
|
+
|
198
218
|
"Then <b>n models</b> should exist", e.g.
|
199
219
|
|
200
220
|
Then 10 events should exist
|
201
|
-
|
221
|
+
|
202
222
|
"Then <b>n models</b> should exist with <b>fields</b>", e.g.
|
203
223
|
|
204
224
|
Then 2 people should exist with father: person "fred"
|
205
|
-
|
225
|
+
|
206
226
|
"Then the following <b>models</b> exist". This allows the creation of multiple models
|
207
227
|
using a table syntax. Using a column with the singularized name of the model creates a referenceable model. E.g.
|
208
228
|
|
@@ -213,30 +233,30 @@ using a table syntax. Using a column with the singularized name of the model cre
|
|
213
233
|
Then the following users exist:
|
214
234
|
| user | name | activated |
|
215
235
|
| Fred | Freddy | false |
|
216
|
-
|
236
|
+
|
217
237
|
===== Asserting associations
|
218
238
|
|
219
239
|
One-to-one assocs: "Then <b>a model</b> should be <b>other model</b>'s <b>association</b>", e.g.
|
220
240
|
|
221
241
|
Then the person: "fred" should be person: "ethel"'s father
|
222
|
-
|
242
|
+
|
223
243
|
Many-to-one assocs: "Then <b>a model</b> should be [in|one of] <b>other model</b>'s <b>association</b>", e.g.
|
224
244
|
|
225
245
|
Then the person: "ethel" should be one of person: "fred"'s children
|
226
246
|
Then the comment should be in the post's comments
|
227
|
-
|
247
|
+
|
228
248
|
===== Asserting predicate methods
|
229
249
|
|
230
250
|
"Then <b>a model</b> should [be|have] [a|an] <b>predicate</b>", e.g.
|
231
|
-
|
251
|
+
|
232
252
|
Then the user should have a status # => user.status.should be_present
|
233
253
|
Then the user should have a stale password # => user.should have_stale_password
|
234
254
|
Then the car: "batmobile" should be fast # => car.should be_fast
|
235
|
-
|
255
|
+
|
236
256
|
"Then <b>a model</b> should not [be|have] [a|an] <b>predicate</b>", e.g.
|
237
257
|
|
238
258
|
Then person: "fred" should not be childless # => fred.should_not be_childless
|
239
|
-
|
259
|
+
|
240
260
|
=== Regexps for use in your own steps
|
241
261
|
|
242
262
|
By default you get some regexps available in the main namespace for use
|
@@ -263,7 +283,7 @@ Pickle::Parser::Matchers for the methods available)
|
|
263
283
|
post = model!(post)
|
264
284
|
forum = model!(forum)
|
265
285
|
forum.posts.should include(post)
|
266
|
-
end
|
286
|
+
end
|
267
287
|
|
268
288
|
*capture_fields*
|
269
289
|
|
@@ -276,4 +296,4 @@ can build up composite objects with ease
|
|
276
296
|
|
277
297
|
# example of use
|
278
298
|
Given a user exists
|
279
|
-
And a post exists with author: the user # this step will assign the above user as :author on the post
|
299
|
+
And a post exists with author: the user # this step will assign the above user as :author on the post
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/pickle/adapter.rb
CHANGED
@@ -4,7 +4,7 @@ module Pickle
|
|
4
4
|
# Abstract Factory adapter class, if you have a factory type setup, you
|
5
5
|
# can easily create an adaptor to make it work with Pickle.
|
6
6
|
#
|
7
|
-
# The factory adaptor must have a #factories class method that returns
|
7
|
+
# The factory adaptor must have a #factories class method that returns
|
8
8
|
# its instances, and each instance must respond to:
|
9
9
|
#
|
10
10
|
# #name : identifies the factory by name (default is attr_reader)
|
@@ -12,40 +12,65 @@ module Pickle
|
|
12
12
|
# #create(attrs = {}) : returns a newly created object
|
13
13
|
class Adapter
|
14
14
|
attr_reader :name, :klass
|
15
|
-
|
15
|
+
|
16
16
|
def create(attrs = {})
|
17
17
|
raise NotImplementedError, "create and return an object with the given attributes"
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
if respond_to?(:class_attribute)
|
21
21
|
class_attribute :model_classes
|
22
22
|
else
|
23
23
|
cattr_writer :model_classes
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
self.model_classes = nil
|
27
|
-
|
27
|
+
|
28
|
+
# Include this module into your adapter
|
29
|
+
# this will register the adapter with pickle and it will be picked up for you
|
30
|
+
# To create an adapter you should create an inner constant "PickleAdapter"
|
31
|
+
#
|
32
|
+
# e.g. ActiveRecord::Base::PickleAdapter
|
33
|
+
#
|
34
|
+
# @see pickle/adapters/active_record
|
35
|
+
# @see pickle/adapters/datamapper
|
36
|
+
module Base
|
37
|
+
def self.included(base)
|
38
|
+
adapters << base
|
39
|
+
end
|
40
|
+
|
41
|
+
# A collection of registered adapters
|
42
|
+
def self.adapters
|
43
|
+
@@adapters ||= []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
28
47
|
class << self
|
29
48
|
def factories
|
30
49
|
raise NotImplementedError, "return an array of factory adapter objects"
|
31
50
|
end
|
32
51
|
|
33
52
|
def model_classes
|
34
|
-
@@model_classes ||= ::
|
53
|
+
@@model_classes ||= self::Base.adapters.map{ |a| a.model_classes }.flatten
|
35
54
|
end
|
36
|
-
|
37
|
-
#
|
38
|
-
def
|
39
|
-
|
55
|
+
|
56
|
+
# Returns the column names for the given ORM model class.
|
57
|
+
def column_names(klass)
|
58
|
+
klass.const_get(:PickleAdapter).column_names(klass)
|
40
59
|
end
|
41
60
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
61
|
+
def get_model(klass, id)
|
62
|
+
klass.const_get(:PickleAdapter).get_model(klass, id)
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_first_model(klass, conditions)
|
66
|
+
klass.const_get(:PickleAdapter).find_first_model(klass, conditions)
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_all_models(klass, conditions)
|
70
|
+
klass.const_get(:PickleAdapter).find_all_models(klass, conditions)
|
46
71
|
end
|
47
72
|
end
|
48
|
-
|
73
|
+
|
49
74
|
# machinist adapter
|
50
75
|
class Machinist < Adapter
|
51
76
|
def self.factories
|
@@ -57,37 +82,37 @@ module Pickle
|
|
57
82
|
end
|
58
83
|
factories
|
59
84
|
end
|
60
|
-
|
85
|
+
|
61
86
|
def initialize(klass, blueprint)
|
62
87
|
@klass, @blueprint = klass, blueprint
|
63
88
|
@name = @klass.name.underscore.gsub('/','_')
|
64
89
|
@name = "#{@blueprint}_#{@name}" unless @blueprint == :master
|
65
90
|
end
|
66
|
-
|
91
|
+
|
67
92
|
def create(attrs = {})
|
68
93
|
@klass.send(:make, @blueprint, attrs)
|
69
94
|
end
|
70
95
|
end
|
71
|
-
|
96
|
+
|
72
97
|
# factory-girl adapter
|
73
98
|
class FactoryGirl < Adapter
|
74
99
|
def self.factories
|
75
100
|
(::Factory.factories.values rescue []).map {|factory| new(factory)}
|
76
101
|
end
|
77
|
-
|
102
|
+
|
78
103
|
def initialize(factory)
|
79
104
|
@klass, @name = factory.build_class, factory.factory_name.to_s
|
80
105
|
end
|
81
|
-
|
106
|
+
|
82
107
|
def create(attrs = {})
|
83
108
|
Factory.create(@name, attrs)
|
84
109
|
end
|
85
110
|
end
|
86
|
-
|
111
|
+
|
87
112
|
# fallback active record adapter
|
88
113
|
class ActiveRecord < Adapter
|
89
114
|
def self.factories
|
90
|
-
model_classes.map
|
115
|
+
::ActiveRecord::Base::PickleAdapter.model_classes.map{|k| new(k)}
|
91
116
|
end
|
92
117
|
|
93
118
|
def initialize(klass)
|
@@ -99,4 +124,4 @@ module Pickle
|
|
99
124
|
end
|
100
125
|
end
|
101
126
|
end
|
102
|
-
end
|
127
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
begin
|
2
|
+
require 'activerecord'
|
3
|
+
rescue LoadError
|
4
|
+
require 'active_record'
|
5
|
+
end
|
6
|
+
|
7
|
+
class ActiveRecord::Base
|
8
|
+
module PickleAdapter
|
9
|
+
include Pickle::Adapter::Base
|
10
|
+
|
11
|
+
# Do not consider these to be part of the class list
|
12
|
+
def self.except_classes
|
13
|
+
@@except_classes ||= [
|
14
|
+
"CGI::Session::ActiveRecordStore::Session",
|
15
|
+
"ActiveRecord::SessionStore::Session"
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Gets a list of the available models for this adapter
|
20
|
+
def self.model_classes
|
21
|
+
::ActiveRecord::Base.__send__(:subclasses).select do |klass|
|
22
|
+
!klass.abstract_class? && klass.table_exists? && !except_classes.include?(klass.name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# get a list of column names for a given class
|
27
|
+
def self.column_names(klass)
|
28
|
+
klass.column_names
|
29
|
+
end
|
30
|
+
|
31
|
+
# Get an instance by id of the model
|
32
|
+
def self.get_model(klass, id)
|
33
|
+
klass.find(id)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Find the first instance matching conditions
|
37
|
+
def self.find_first_model(klass, conditions)
|
38
|
+
klass.find(:first, :conditions => conditions)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Find all models matching conditions
|
42
|
+
def self.find_all_models(klass, conditions)
|
43
|
+
klass.find(:all, :conditions => conditions)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module DataMapper::Resource
|
4
|
+
module PickleAdapter
|
5
|
+
include Pickle::Adapter::Base
|
6
|
+
|
7
|
+
# Do not consider these to be part of the class list
|
8
|
+
def self.except_classes
|
9
|
+
@@except_classes ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets a list of the available models for this adapter
|
13
|
+
def self.model_classes
|
14
|
+
::DataMapper::Model.descendants.to_a.select{|k| !except_classes.include?(k.name)}
|
15
|
+
end
|
16
|
+
|
17
|
+
# get a list of column names for a given class
|
18
|
+
def self.column_names(klass)
|
19
|
+
klass.properties.map(&:name)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get an instance by id of the model
|
23
|
+
def self.get_model(klass, id)
|
24
|
+
klass.get(id)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Find the first instance matching conditions
|
28
|
+
def self.find_first_model(klass, conditions)
|
29
|
+
klass.first(conditions)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Find all models matching conditions
|
33
|
+
def self.find_all_models(klass, conditions)
|
34
|
+
klass.all(conditions)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/pickle/config.rb
CHANGED
@@ -28,7 +28,7 @@ module Pickle
|
|
28
28
|
|
29
29
|
def predicates
|
30
30
|
@predicates ||= Pickle::Adapter.model_classes.map do |k|
|
31
|
-
k.public_instance_methods.select{|m| m =~ /\?$/} +
|
31
|
+
k.public_instance_methods.select {|m| m =~ /\?$/} + Pickle::Adapter.column_names(k)
|
32
32
|
end.flatten.uniq
|
33
33
|
end
|
34
34
|
|
@@ -45,4 +45,4 @@ module Pickle
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end
|