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