requires_approval 1.0.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.
@@ -0,0 +1,90 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "requires_approval"
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dan Langevin"]
12
+ s.date = "2012-08-05"
13
+ s.description = "Gem to handle versioning and things that require approval"
14
+ s.email = "dan.langevin@lifebooker.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "Guardfile",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "lib/errors.rb",
30
+ "lib/requires_approval.rb",
31
+ "requires_approval.gemspec",
32
+ "spec/lib/requires_approval_spec.rb",
33
+ "spec/spec_helper.rb",
34
+ "spec/support/BLANK"
35
+ ]
36
+ s.homepage = "http://github.com/LifebookerInc/requires_approval"
37
+ s.licenses = ["MIT"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = "1.8.11"
40
+ s.summary = "Gem to handle versioning and things that require approval"
41
+
42
+ if s.respond_to? :specification_version then
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<activerecord>, ["~> 3.0.9"])
47
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3.0.9"])
48
+ s.add_development_dependency(%q<bundler>, [">= 0"])
49
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
50
+ s.add_development_dependency(%q<guard-bundler>, [">= 0"])
51
+ s.add_development_dependency(%q<guard-spork>, [">= 0"])
52
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
53
+ s.add_development_dependency(%q<mocha>, [">= 0"])
54
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
55
+ s.add_development_dependency(%q<rspec>, [">= 0"])
56
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
57
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
58
+ s.add_development_dependency(%q<yard>, [">= 0"])
59
+ else
60
+ s.add_dependency(%q<activerecord>, ["~> 3.0.9"])
61
+ s.add_dependency(%q<activesupport>, ["~> 3.0.9"])
62
+ s.add_dependency(%q<bundler>, [">= 0"])
63
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
64
+ s.add_dependency(%q<guard-bundler>, [">= 0"])
65
+ s.add_dependency(%q<guard-spork>, [">= 0"])
66
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
67
+ s.add_dependency(%q<mocha>, [">= 0"])
68
+ s.add_dependency(%q<rdoc>, [">= 0"])
69
+ s.add_dependency(%q<rspec>, [">= 0"])
70
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
71
+ s.add_dependency(%q<sqlite3>, [">= 0"])
72
+ s.add_dependency(%q<yard>, [">= 0"])
73
+ end
74
+ else
75
+ s.add_dependency(%q<activerecord>, ["~> 3.0.9"])
76
+ s.add_dependency(%q<activesupport>, ["~> 3.0.9"])
77
+ s.add_dependency(%q<bundler>, [">= 0"])
78
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
79
+ s.add_dependency(%q<guard-bundler>, [">= 0"])
80
+ s.add_dependency(%q<guard-spork>, [">= 0"])
81
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
82
+ s.add_dependency(%q<mocha>, [">= 0"])
83
+ s.add_dependency(%q<rdoc>, [">= 0"])
84
+ s.add_dependency(%q<rspec>, [">= 0"])
85
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
86
+ s.add_dependency(%q<sqlite3>, [">= 0"])
87
+ s.add_dependency(%q<yard>, [">= 0"])
88
+ end
89
+ end
90
+
@@ -0,0 +1,423 @@
1
+ require 'spec_helper'
2
+
3
+ describe RequiresApproval do
4
+
5
+ before(:all) do
6
+
7
+ ActiveRecord::Base.establish_connection({
8
+ "adapter" => "sqlite3",
9
+ "database" => File.join(File.dirname(__FILE__), "..", "support", "db.sqlite")
10
+ })
11
+
12
+ ActiveRecord::Base.connection.create_table(:users, :force => true) do |t|
13
+ t.string(:first_name)
14
+ t.string(:last_name)
15
+ t.date(:birthday)
16
+ t.timestamps
17
+ end
18
+
19
+ class User < ActiveRecord::Base
20
+ requires_approval_for(:first_name, :last_name)
21
+ end
22
+
23
+ User.prepare_tables_for_requires_approval
24
+
25
+ end
26
+
27
+
28
+ context "setup" do
29
+
30
+ context "database" do
31
+
32
+ it "should create a versions table" do
33
+ User.connection.tables.should include "user_versions"
34
+ end
35
+
36
+ it "should add an is_active column to the parent table" do
37
+ User.column_names.should include "is_frozen"
38
+ col = User.columns.select{|c| c.name == "is_frozen"}.first
39
+ col.type.should be :boolean
40
+ col.default.should be true
41
+ end
42
+
43
+ it "should add an is_deleted column to the parent table" do
44
+ User.column_names.should include "is_deleted"
45
+ col = User.columns.select{|c| c.name == "is_deleted"}.first
46
+ col.type.should be :boolean
47
+ col.default.should be false
48
+ end
49
+
50
+ end
51
+
52
+ context "version class" do
53
+
54
+ it "should create an ActiveRecord class for its versions" do
55
+ defined?(User::Version).should eql "constant"
56
+ User::Version.table_name.should eql("user_versions")
57
+ end
58
+
59
+ it "should provide a getter for its versions class" do
60
+ User.versions_class.should be User::Version
61
+ end
62
+
63
+ end
64
+
65
+ context "options" do
66
+
67
+ before(:all) do
68
+ conn = ActiveRecord::Base.connection
69
+
70
+ conn.create_table(:posts, :force => true) do |t|
71
+ t.string(:title)
72
+ t.string(:body)
73
+ t.date(:published_at)
74
+ t.timestamps
75
+ end
76
+
77
+ class Post < ActiveRecord::Base
78
+ requires_approval_for(:title, :body, {
79
+ :versions_table_name => "blah_blah",
80
+ :versions_foreign_key => "test_id",
81
+ :versions_class_name => "SuperVersion"
82
+ })
83
+ end
84
+ Post.prepare_tables_for_requires_approval
85
+
86
+ end
87
+
88
+ it "should create a custom-named subclass" do
89
+ defined?(Post::SuperVersion).should_not be_nil
90
+ end
91
+
92
+ it "should allow for custom table names" do
93
+ Post::SuperVersion.table_name.should eql("blah_blah")
94
+ end
95
+
96
+ it "should allow for a custom foreign key" do
97
+ assn = Post.reflect_on_association(:versions)
98
+ assn.options[:foreign_key].should eql("test_id")
99
+
100
+ assn = Post.reflect_on_association(:latest_unapproved_version)
101
+ assn.options[:foreign_key].should eql("test_id")
102
+
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+
109
+ context "scopes" do
110
+
111
+ before(:each) do
112
+ User.delete_all
113
+ end
114
+
115
+ it "should add an unapproved scope that finds records
116
+ that have pending changes" do
117
+
118
+ user = User.create!(
119
+ :first_name => "Dan",
120
+ :last_name => "Langevin",
121
+ :birthday => Date.today
122
+ )
123
+ # has unapproved changes
124
+ User.unapproved.should include user
125
+
126
+ # approve them and it should not match the scope
127
+ user.approve_all_attributes
128
+ User.unapproved.should_not include user
129
+
130
+ end
131
+
132
+ end
133
+
134
+ context "saving" do
135
+
136
+ it "should create a new version as blank with is_frozen true, is_deleted
137
+ false, and the requires approval attributes saved in the versions
138
+ table" do
139
+ user = User.create(
140
+ :first_name => "Dan",
141
+ :last_name => "Langevin",
142
+ :birthday => Date.today
143
+ )
144
+ user.is_frozen.should be true
145
+ user.is_deleted.should be false
146
+ user.versions.length.should eql 1
147
+
148
+ # requires_approval attributes should not be set on the parent record
149
+ user.first_name.should be nil
150
+ user.last_name.should be nil
151
+
152
+ # regular attributes should be set
153
+ user.birthday.should_not be nil
154
+
155
+ # requires_approval attributes should be set on the version record
156
+ user.versions.last.first_name.should eql "Dan"
157
+ user.versions.last.last_name.should eql "Langevin"
158
+
159
+ end
160
+
161
+ it "should update the latest_unapproved_version
162
+ when a field that requires approval has changed" do
163
+
164
+ user = User.create(
165
+ :first_name => "Dan",
166
+ :last_name => "Langevin"
167
+ )
168
+ version = user.latest_unapproved_version
169
+ version.first_name.should eql("Dan")
170
+ version.last_name.should eql("Langevin")
171
+
172
+ user.update_attribute(:first_name, "Blah")
173
+
174
+ version = user.latest_unapproved_version(true)
175
+ version.reload.first_name.should eql("Blah")
176
+ end
177
+
178
+ it "should initialize a new latest_unapproved_version with
179
+ the attributes of the previously approved version" do
180
+
181
+ user = User.create(
182
+ :first_name => "Dan",
183
+ :last_name => "Langevin"
184
+ )
185
+ user.approve_all_attributes
186
+
187
+ user.first_name = "Other"
188
+ user.save
189
+
190
+ user.reload
191
+
192
+ user.latest_unapproved_version.last_name.should eql("Langevin")
193
+ user.approve_all_attributes
194
+
195
+ user.first_name.should eql("Other")
196
+ user.last_name.should eql("Langevin")
197
+
198
+ end
199
+
200
+ end
201
+
202
+ context ".validates_approved_field" do
203
+
204
+ it "should delegate to the requires_approval field" do
205
+ User.class_eval do
206
+ validates_approved_field :first_name,
207
+ :presence => true
208
+ end
209
+
210
+ user = User.new
211
+ user.should_not be_valid
212
+ errors = user.errors[:"latest_unapproved_version.first_name"]
213
+ errors.should include "can't be blank"
214
+
215
+ end
216
+
217
+ end
218
+
219
+ context "#approve_all_attributes" do
220
+
221
+ it "should flag the latest_unapproved_version as approved, set is_frozen
222
+ to false and update all attributes" do
223
+
224
+ user = User.create(
225
+ :first_name => "Dan",
226
+ :last_name => "Langevin"
227
+ )
228
+ user.approve_all_attributes
229
+
230
+ user.first_name.should eql("Dan")
231
+ user.last_name.should eql("Langevin")
232
+ user.is_frozen.should be false
233
+
234
+ user.latest_unapproved_version.should be nil
235
+ end
236
+
237
+ end
238
+
239
+ context "#approve_attributes" do
240
+
241
+ it "should flag the selected values as approved and create a
242
+ new latest_unapproved_version to hold changes that were not
243
+ approved" do
244
+
245
+ user = User.create(
246
+ :first_name => "Dan",
247
+ :last_name => "Langevin"
248
+ )
249
+ user.approve_all_attributes
250
+
251
+ user.update_attributes(
252
+ :first_name => "New First",
253
+ :last_name => "New Last"
254
+ )
255
+
256
+ user.approve_attributes(:first_name)
257
+
258
+ user.first_name.should eql("New First")
259
+ # last name was not approved, should still be nil
260
+ user.last_name.should eql "Langevin"
261
+ user.is_frozen.should be false
262
+
263
+ user.pending_changes.should eql({
264
+ "last_name" => {"was" => "Langevin", "became" => "New Last"}
265
+ })
266
+
267
+ # should create an approved version
268
+ user.versions.where(:is_approved => true).count.should be > 0
269
+
270
+ end
271
+
272
+ it "should throw an error if you try to approve fields that do not require approval
273
+ or do not exist" do
274
+
275
+ user = User.create(
276
+ :first_name => "Dan",
277
+ :last_name => "Langevin",
278
+ :birthday => Date.today
279
+ )
280
+ user.approve_attributes(:first_name, :last_name)
281
+ user.update_attributes({
282
+ :first_name => "New Name",
283
+ :last_name => "New Last Name"
284
+ })
285
+
286
+ # doesn't exist
287
+ lambda{user.approve_attributes(:x)}.should raise_error(RequiresApproval::InvalidFieldsError)
288
+ # doesn't require approval
289
+ lambda{user.approve_attributes(:birthday)}.should raise_error(RequiresApproval::InvalidFieldsError)
290
+
291
+ end
292
+
293
+ it "should throw an error if you try to approve only some of the fields that require approval
294
+ in a newly created object" do
295
+
296
+ user = User.create(
297
+ :first_name => "Dan",
298
+ :last_name => "Langevin",
299
+ :birthday => Date.today
300
+ )
301
+ lambda{user.approve_attributes(:first_name)}.should raise_error(
302
+ RequiresApproval::PartialApprovalForNewObject
303
+ )
304
+
305
+ end
306
+
307
+ end
308
+
309
+ context "#deny_attributes" do
310
+
311
+ it "should remove the denied attributes from the
312
+ pending_changes hash" do
313
+
314
+ user = User.create(
315
+ :first_name => "Dan",
316
+ :last_name => "Langevin"
317
+ )
318
+ user.approve_all_attributes
319
+
320
+ user.update_attributes(
321
+ :first_name => "Test",
322
+ :last_name => "User"
323
+ )
324
+
325
+ user.deny_attributes(:first_name)
326
+ user.first_name.should eql("Dan")
327
+ user.pending_changes.should eql({
328
+ "last_name" => {"was" => "Langevin", "became" => "User"}
329
+ })
330
+
331
+
332
+ end
333
+
334
+ it "should remove the unapproved version all together when all
335
+ attributes are denied" do
336
+
337
+ user = User.create(
338
+ :first_name => "Dan",
339
+ :last_name => "Langevin"
340
+ )
341
+ user.approve_all_attributes
342
+
343
+ user.update_attributes(
344
+ :first_name => "ABC",
345
+ :last_name => "DEFG"
346
+ )
347
+ user.deny_attributes(:first_name, :last_name)
348
+ user.latest_unapproved_version.should be nil
349
+
350
+ end
351
+
352
+ it "should throw an error if you try to deny
353
+ fields that do not require approval or do not exist" do
354
+
355
+ u = User.create(
356
+ :first_name => "Dan",
357
+ :last_name => "Langevin",
358
+ :birthday => Date.today
359
+ )
360
+ u.approve_all_attributes
361
+
362
+ u.update_attributes(:first_name => "A", :last_name => "B")
363
+
364
+ # doesn't exist
365
+ lambda{u.deny_attributes(:x)}.should raise_error(RequiresApproval::InvalidFieldsError)
366
+ # doesn't require approval
367
+ lambda{u.deny_attributes(:birthday)}.should raise_error(RequiresApproval::InvalidFieldsError)
368
+
369
+ end
370
+
371
+ it "should throw an error if you try to deny fields on a never-approved object" do
372
+
373
+ u = User.create(
374
+ :first_name => "Dan",
375
+ :last_name => "Langevin",
376
+ :birthday => Date.today
377
+ )
378
+
379
+ lambda{u.deny_attributes(:first_name, :last_name)}.should raise_error(
380
+ RequiresApproval::DenyingNeverApprovedError
381
+ )
382
+ end
383
+
384
+ end
385
+
386
+ context "#has_approved_version?" do
387
+
388
+ it "should return true if a version has ever been approved" do
389
+ user = User.create(:first_name => "Dan", :last_name => "Langevin")
390
+ user.approve_all_attributes
391
+ user.has_approved_version?.should be true
392
+ end
393
+
394
+ it "should return false if no version has ever been approved" do
395
+ user = User.create(:first_name => "Dan", :last_name => "Langevin")
396
+ user.has_approved_version?.should be false
397
+ end
398
+
399
+ end
400
+
401
+ context "#has_pending_changes?" do
402
+
403
+ let(:user) do
404
+ User.new
405
+ end
406
+
407
+ it "should return true if the provider has no outstanding changes" do
408
+ user.stubs(:pending_changes => {})
409
+ user.has_pending_changes?.should be false
410
+ end
411
+
412
+ it "should return false if the provider has outstanding changes" do
413
+ user.stubs(:pending_changes => {
414
+ "last_name" => {"was" => "L", "became" => "T"}
415
+ })
416
+ user.has_pending_changes?.should be true
417
+ end
418
+
419
+ end
420
+
421
+
422
+
423
+ end