acts-as-approvable 0.6.7 → 0.6.8.1
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/.gitignore +2 -5
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Appraisals +14 -10
- data/CHANGELOG +16 -0
- data/Gemfile.lock +60 -20
- data/README.md +1 -2
- data/Rakefile +44 -16
- data/VERSION +1 -1
- data/acts-as-approvable.gemspec +21 -11
- data/features/create_approval.feature +26 -0
- data/features/step_definitions/cucumber_steps.rb +86 -0
- data/features/support/env.rb +14 -0
- data/features/support/large.txt +29943 -0
- data/features/support/second_large.txt +31798 -0
- data/features/update_approval.feature +34 -0
- data/gemfiles/Gemfile.ci +14 -0
- data/gemfiles/Gemfile.ci.lock +98 -0
- data/gemfiles/mysql2.gemfile +7 -0
- data/gemfiles/mysql2.gemfile.lock +92 -0
- data/gemfiles/rails2.gemfile +1 -0
- data/gemfiles/rails2.gemfile.lock +59 -17
- data/gemfiles/rails30.gemfile +1 -0
- data/gemfiles/rails30.gemfile.lock +54 -14
- data/gemfiles/rails31.gemfile +1 -0
- data/gemfiles/rails31.gemfile.lock +54 -14
- data/gemfiles/sqlite.gemfile +7 -0
- data/generators/acts_as_approvable/templates/create_approvals.rb +8 -7
- data/lib/acts-as-approvable.rb +2 -3
- data/lib/acts_as_approvable/approval.rb +3 -2
- data/lib/acts_as_approvable/model.rb +55 -0
- data/lib/acts_as_approvable/model/class_methods.rb +63 -0
- data/lib/acts_as_approvable/model/create_instance_methods.rb +83 -0
- data/lib/acts_as_approvable/model/instance_methods.rb +89 -0
- data/lib/acts_as_approvable/model/update_instance_methods.rb +61 -0
- data/lib/acts_as_approvable/railtie.rb +1 -1
- data/lib/generators/acts_as_approvable/templates/create_approvals.rb +8 -7
- data/spec/acts_as_approvable/approval_spec.rb +475 -0
- data/spec/acts_as_approvable/model/class_methods_spec.rb +219 -0
- data/spec/acts_as_approvable/model/create_instance_methods_spec.rb +149 -0
- data/spec/acts_as_approvable/model/instance_methods_spec.rb +328 -0
- data/spec/acts_as_approvable/model/update_instance_methods_spec.rb +111 -0
- data/spec/acts_as_approvable/model_spec.rb +90 -0
- data/spec/acts_as_approvable/ownership/class_methods_spec.rb +101 -0
- data/spec/acts_as_approvable/ownership/instance_methods_spec.rb +32 -0
- data/spec/acts_as_approvable/ownership_spec.rb +51 -0
- data/spec/acts_as_approvable_spec.rb +29 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/database.rb +46 -0
- data/spec/support/database.yml +12 -0
- data/spec/support/matchers.rb +87 -0
- data/spec/support/models.rb +60 -0
- data/{test → spec/support}/schema.rb +15 -9
- metadata +156 -53
- data/gemfiles/rails32.gemfile +0 -8
- data/gemfiles/rails32.gemfile.lock +0 -99
- data/lib/acts_as_approvable/acts_as_approvable.rb +0 -291
- data/test/acts_as_approvable_model_test.rb +0 -459
- data/test/acts_as_approvable_ownership_test.rb +0 -132
- data/test/acts_as_approvable_schema_test.rb +0 -13
- data/test/acts_as_approvable_test.rb +0 -8
- data/test/database.yml +0 -7
- data/test/support.rb +0 -19
- data/test/test_helper.rb +0 -62
data/gemfiles/rails32.gemfile
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/jlogsdon/Code/acts_as_approvable/acts_as_approvable
|
3
|
-
specs:
|
4
|
-
acts-as-approvable (0.6.7)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: http://rubygems.org/
|
8
|
-
specs:
|
9
|
-
actionpack (3.2.1)
|
10
|
-
activemodel (= 3.2.1)
|
11
|
-
activesupport (= 3.2.1)
|
12
|
-
builder (~> 3.0.0)
|
13
|
-
erubis (~> 2.7.0)
|
14
|
-
journey (~> 1.0.1)
|
15
|
-
rack (~> 1.4.0)
|
16
|
-
rack-cache (~> 1.1)
|
17
|
-
rack-test (~> 0.6.1)
|
18
|
-
sprockets (~> 2.1.2)
|
19
|
-
activemodel (3.2.1)
|
20
|
-
activesupport (= 3.2.1)
|
21
|
-
builder (~> 3.0.0)
|
22
|
-
activerecord (3.2.1)
|
23
|
-
activemodel (= 3.2.1)
|
24
|
-
activesupport (= 3.2.1)
|
25
|
-
arel (~> 3.0.0)
|
26
|
-
tzinfo (~> 0.3.29)
|
27
|
-
activesupport (3.2.1)
|
28
|
-
i18n (~> 0.6)
|
29
|
-
multi_json (~> 1.0)
|
30
|
-
appraisal (0.4.1)
|
31
|
-
bundler
|
32
|
-
rake
|
33
|
-
arel (3.0.0)
|
34
|
-
builder (3.0.0)
|
35
|
-
coderay (1.0.5)
|
36
|
-
erubis (2.7.0)
|
37
|
-
hike (1.2.1)
|
38
|
-
i18n (0.6.0)
|
39
|
-
journey (1.0.1)
|
40
|
-
json (1.6.5)
|
41
|
-
metaclass (0.0.1)
|
42
|
-
method_source (0.7.0)
|
43
|
-
mocha (0.10.4)
|
44
|
-
metaclass (~> 0.0.1)
|
45
|
-
multi_json (1.0.4)
|
46
|
-
pry (0.9.8)
|
47
|
-
coderay (~> 1.0.5)
|
48
|
-
method_source (~> 0.7)
|
49
|
-
slop (>= 2.4.3, < 3)
|
50
|
-
rack (1.4.1)
|
51
|
-
rack-cache (1.1)
|
52
|
-
rack (>= 0.4)
|
53
|
-
rack-ssl (1.3.2)
|
54
|
-
rack
|
55
|
-
rack-test (0.6.1)
|
56
|
-
rack (>= 1.0)
|
57
|
-
railties (3.2.1)
|
58
|
-
actionpack (= 3.2.1)
|
59
|
-
activesupport (= 3.2.1)
|
60
|
-
rack-ssl (~> 1.3.2)
|
61
|
-
rake (>= 0.8.7)
|
62
|
-
rdoc (~> 3.4)
|
63
|
-
thor (~> 0.14.6)
|
64
|
-
rake (0.9.2.2)
|
65
|
-
rdoc (3.12)
|
66
|
-
json (~> 1.4)
|
67
|
-
redcarpet (2.1.0)
|
68
|
-
shoulda (2.11.3)
|
69
|
-
simplecov (0.5.4)
|
70
|
-
multi_json (~> 1.0.3)
|
71
|
-
simplecov-html (~> 0.5.3)
|
72
|
-
simplecov-html (0.5.3)
|
73
|
-
slop (2.4.3)
|
74
|
-
sprockets (2.1.2)
|
75
|
-
hike (~> 1.2)
|
76
|
-
rack (~> 1.0)
|
77
|
-
tilt (~> 1.1, != 1.3.0)
|
78
|
-
sqlite3 (1.3.5)
|
79
|
-
thor (0.14.6)
|
80
|
-
tilt (1.3.3)
|
81
|
-
tzinfo (0.3.31)
|
82
|
-
yard (0.7.5)
|
83
|
-
|
84
|
-
PLATFORMS
|
85
|
-
ruby
|
86
|
-
|
87
|
-
DEPENDENCIES
|
88
|
-
activerecord (~> 3.2.0)
|
89
|
-
acts-as-approvable!
|
90
|
-
appraisal
|
91
|
-
mocha
|
92
|
-
pry
|
93
|
-
railties (~> 3.2.0)
|
94
|
-
rake
|
95
|
-
redcarpet
|
96
|
-
shoulda
|
97
|
-
simplecov
|
98
|
-
sqlite3
|
99
|
-
yard
|
@@ -1,291 +0,0 @@
|
|
1
|
-
module ActsAsApprovable
|
2
|
-
##
|
3
|
-
# The meat of {ActsAsApprovable}. This applies methods for the configured approval events
|
4
|
-
# and configures the required relationships.
|
5
|
-
module Model
|
6
|
-
def self.included(base)
|
7
|
-
base.send :extend, ClassMethods
|
8
|
-
end
|
9
|
-
|
10
|
-
##
|
11
|
-
# Class methods added to `ActiveRecord::Base`.
|
12
|
-
module ClassMethods
|
13
|
-
# Declare this in your model to require approval on new records or changes to fields.
|
14
|
-
#
|
15
|
-
# @param [Hash] options the options for this models approval workflow.
|
16
|
-
# @option options [Symbol,Array] :on The events to require approval on (`:create` or `:update`).
|
17
|
-
# @option options [String] :state_field The local field to store `:create` approval state.
|
18
|
-
# @option options [Array] :ignore A list of fields to ignore. By default we ignore `:created_at`, `:updated_at` and
|
19
|
-
# the field specified in `:state_field`.
|
20
|
-
# @option options [Array] :only A list of fields to explicitly require approval on. This list supercedes `:ignore`.
|
21
|
-
def acts_as_approvable(options = {})
|
22
|
-
include InstanceMethods
|
23
|
-
|
24
|
-
cattr_accessor :approvable_on
|
25
|
-
self.approvable_on = Array.wrap(options.delete(:on) { [:create, :update] })
|
26
|
-
|
27
|
-
cattr_accessor :approvable_field
|
28
|
-
self.approvable_field = options.delete(:state_field)
|
29
|
-
|
30
|
-
cattr_accessor :approvable_ignore
|
31
|
-
ignores = Array.wrap(options.delete(:ignore) { [] })
|
32
|
-
ignores.push('created_at', 'updated_at', self.approvable_field)
|
33
|
-
self.approvable_ignore = ignores.compact.uniq.map(&:to_s)
|
34
|
-
|
35
|
-
cattr_accessor :approvable_only
|
36
|
-
self.approvable_only = Array.wrap(options.delete(:only) { [] }).uniq.map(&:to_s)
|
37
|
-
|
38
|
-
cattr_accessor :approvals_active
|
39
|
-
self.approvals_active = true
|
40
|
-
|
41
|
-
has_many :approvals, :as => :item, :dependent => :destroy
|
42
|
-
|
43
|
-
if self.approvable_on.include?(:update)
|
44
|
-
include UpdateInstanceMethods
|
45
|
-
before_update :approvable_update, :if => :approvable_update?
|
46
|
-
end
|
47
|
-
|
48
|
-
if self.approvable_on.include?(:create)
|
49
|
-
include CreateInstanceMethods
|
50
|
-
before_create :approvable_create, :if => :approvable_create?
|
51
|
-
end
|
52
|
-
|
53
|
-
after_save :approvable_save, :if => :approvals_enabled?
|
54
|
-
end
|
55
|
-
|
56
|
-
##
|
57
|
-
# Enable the approval queue for this model.
|
58
|
-
def approvals_on
|
59
|
-
self.approvals_active = true
|
60
|
-
end
|
61
|
-
|
62
|
-
##
|
63
|
-
# Disable the approval queue for this model.
|
64
|
-
def approvals_off
|
65
|
-
self.approvals_active = false
|
66
|
-
end
|
67
|
-
|
68
|
-
##
|
69
|
-
# Execute a code block while the approval queue is temporarily disabled. The
|
70
|
-
# queue state will be returned to it's previous value, either on or off.
|
71
|
-
def without_approval(&block)
|
72
|
-
enable = self.approvals_active
|
73
|
-
approvals_off
|
74
|
-
yield(self)
|
75
|
-
ensure
|
76
|
-
approvals_on if enable
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
##
|
81
|
-
# Instance methods that apply to the `:create` event specifically.
|
82
|
-
module CreateInstanceMethods
|
83
|
-
##
|
84
|
-
# Retrieve approval record for the creation event.
|
85
|
-
#
|
86
|
-
# @return [Approval]
|
87
|
-
def approval
|
88
|
-
approvals.find_by_event('create')
|
89
|
-
end
|
90
|
-
|
91
|
-
##
|
92
|
-
# Get the approval state of the current record from either the local state
|
93
|
-
# field or, if no state field exists, the creation approval object.
|
94
|
-
#
|
95
|
-
# @return [String] one of `'pending'`, `'approved`' or `'rejected'`.
|
96
|
-
def approval_state
|
97
|
-
if self.class.approvable_field
|
98
|
-
send(self.class.approvable_field)
|
99
|
-
elsif approval.present?
|
100
|
-
approval.state
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
##
|
105
|
-
# Set the records local approval state.
|
106
|
-
#
|
107
|
-
# @param [String] state one of `'pending'`, `'approved`' or `'rejected'`.
|
108
|
-
def set_approval_state(state)
|
109
|
-
return unless self.class.approvable_field
|
110
|
-
send("#{self.class.approvable_field}=".to_sym, state)
|
111
|
-
end
|
112
|
-
|
113
|
-
##
|
114
|
-
# Returns true if the record is pending approval.
|
115
|
-
def pending?
|
116
|
-
approval_state == 'pending' or approval.try(:pending?)
|
117
|
-
end
|
118
|
-
|
119
|
-
##
|
120
|
-
# Returns true if the record has been approved.
|
121
|
-
def approved?
|
122
|
-
approval_state == 'approved' or approval.try(:approved?)
|
123
|
-
end
|
124
|
-
|
125
|
-
##
|
126
|
-
# Returns true if the record has been rejected.
|
127
|
-
def rejected?
|
128
|
-
approval_state == 'rejected' or approval.try(:rejected?)
|
129
|
-
end
|
130
|
-
|
131
|
-
##
|
132
|
-
# Approves the record through {Approval#approve!}
|
133
|
-
#
|
134
|
-
# @return [Boolean]
|
135
|
-
def approve!
|
136
|
-
return unless approvable_on?(:create) && approval.present?
|
137
|
-
approval.approve!
|
138
|
-
end
|
139
|
-
|
140
|
-
##
|
141
|
-
# Rejects the record through {Approval#reject!}
|
142
|
-
#
|
143
|
-
# @return [Boolean]
|
144
|
-
def reject!
|
145
|
-
return unless approvable_on?(:create) && approval.present?
|
146
|
-
approval.reject!
|
147
|
-
end
|
148
|
-
|
149
|
-
private
|
150
|
-
def approvable_create?
|
151
|
-
approvals_enabled? and approvable_on?(:create)
|
152
|
-
end
|
153
|
-
|
154
|
-
def approvable_create
|
155
|
-
@approval = approvals.build(:event => 'create', :state => 'pending')
|
156
|
-
set_approval_state('pending')
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
##
|
161
|
-
# Instance methods that apply to the :update event specifically.
|
162
|
-
module UpdateInstanceMethods
|
163
|
-
##
|
164
|
-
# Retrieve all approval records for `:update` events.
|
165
|
-
def update_approvals(all = true)
|
166
|
-
all ? approvals.find_all_by_event('update') : approvals.find_all_by_event_and_state('update', 0)
|
167
|
-
end
|
168
|
-
|
169
|
-
##
|
170
|
-
# Returns true if the record has any `#update_approvals` that are pending
|
171
|
-
# approval.
|
172
|
-
def pending_changes?
|
173
|
-
!update_approvals(false).empty?
|
174
|
-
end
|
175
|
-
|
176
|
-
##
|
177
|
-
# Returns true if any notable (eg. not ignored) fields have been changed.
|
178
|
-
def changed_notably?
|
179
|
-
notably_changed.any?
|
180
|
-
end
|
181
|
-
|
182
|
-
##
|
183
|
-
# Returns an array of any notable (eg. not ignored) fields that have not
|
184
|
-
# been changed.
|
185
|
-
#
|
186
|
-
# @return [Array] a list of changed fields.
|
187
|
-
def notably_changed
|
188
|
-
unless self.class.approvable_only.empty?
|
189
|
-
self.class.approvable_only.select { |field| changed.include?(field) }
|
190
|
-
else
|
191
|
-
changed - self.class.approvable_ignore
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
private
|
196
|
-
def approvable_update?
|
197
|
-
approvals_enabled? and approvable_on?(:update) and changed_notably?
|
198
|
-
end
|
199
|
-
|
200
|
-
def approvable_update
|
201
|
-
changed = {}
|
202
|
-
notably_changed.each do |attr|
|
203
|
-
original, changed_to = changes[attr]
|
204
|
-
|
205
|
-
write_attribute(attr.to_s, original)
|
206
|
-
changed[attr] = changed_to
|
207
|
-
end
|
208
|
-
|
209
|
-
@approval = approvals.build(:event => 'update', :state => 'pending', :object => changed)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
##
|
214
|
-
# Instance methods that apply to both `:update` and `:create` events.
|
215
|
-
module InstanceMethods
|
216
|
-
##
|
217
|
-
# Returns true if the approval queue is active at both the local and global
|
218
|
-
# level. Note that the global level supercedes the local level.
|
219
|
-
def approvals_enabled?
|
220
|
-
ActsAsApprovable.enabled? and self.class.approvals_active and approvals_on?
|
221
|
-
end
|
222
|
-
|
223
|
-
##
|
224
|
-
# Returns the inverse of `#approvals_enabled?`
|
225
|
-
def approvals_disabled?
|
226
|
-
!approvals_enabled?
|
227
|
-
end
|
228
|
-
|
229
|
-
def approvals_off
|
230
|
-
@approvals_disabled = true
|
231
|
-
end
|
232
|
-
|
233
|
-
def approvals_on
|
234
|
-
@approvals_disabled = false
|
235
|
-
end
|
236
|
-
|
237
|
-
def approvals_on?
|
238
|
-
not @approvals_disabled
|
239
|
-
end
|
240
|
-
|
241
|
-
##
|
242
|
-
# Returns true if the model is configured to use the approval queue on the
|
243
|
-
# given event (`:create` or `:update`).
|
244
|
-
def approvable_on?(event)
|
245
|
-
self.class.approvable_on.include?(event)
|
246
|
-
end
|
247
|
-
|
248
|
-
##
|
249
|
-
# A filter that is run before the record can be approved. Returning false
|
250
|
-
# stops the approval process from completing.
|
251
|
-
def before_approve(approval); end
|
252
|
-
|
253
|
-
##
|
254
|
-
# A filter that is run after the record has been approved.
|
255
|
-
def after_approve(approval); end
|
256
|
-
|
257
|
-
##
|
258
|
-
# A filter that is run before the record can be rejected. Returning false
|
259
|
-
# stops the rejection process from completing.
|
260
|
-
def before_reject(approval); end
|
261
|
-
|
262
|
-
##
|
263
|
-
# A filter that is run after the record has been rejected.
|
264
|
-
def after_reject(approval); end
|
265
|
-
|
266
|
-
##
|
267
|
-
# Execute a code block while the approval queue is temporarily disabled. The
|
268
|
-
# queue state will be returned to it's previous value, either on or off.
|
269
|
-
def without_approval(&block)
|
270
|
-
enable = approvals_on? # If we use #approvals_enabled? the global state might be incorrectly applied.
|
271
|
-
approvals_off
|
272
|
-
yield(self)
|
273
|
-
ensure
|
274
|
-
approvals_on if enable
|
275
|
-
end
|
276
|
-
|
277
|
-
def save_without_approval(*args)
|
278
|
-
without_approval { |i| save(*args) }
|
279
|
-
end
|
280
|
-
|
281
|
-
def save_without_approval!(*args)
|
282
|
-
without_approval { |i| save!(*args) }
|
283
|
-
end
|
284
|
-
|
285
|
-
private
|
286
|
-
def approvable_save
|
287
|
-
@approval.save if @approval.present? && @approval.new_record?
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
291
|
-
end
|
@@ -1,459 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class ActsAsApprovableModelTest < Test::Unit::TestCase
|
4
|
-
load_schema
|
5
|
-
|
6
|
-
def teardown
|
7
|
-
truncate
|
8
|
-
end
|
9
|
-
|
10
|
-
context 'A record with update only approval' do
|
11
|
-
context 'and ignored fields' do
|
12
|
-
setup { @project = Project.create }
|
13
|
-
|
14
|
-
should 'have no approvals' do
|
15
|
-
assert @project.approvals.empty?
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'which updates an ignored column' do
|
19
|
-
setup { @project.update_attribute(:title, 'Ignore Me') }
|
20
|
-
|
21
|
-
should 'not have an approval' do
|
22
|
-
assert @project.approvals.empty?
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context 'which updates an ignore column and a non-ignored column' do
|
27
|
-
setup { @project.update_attributes(:title => 'Ignore Me', :description => 'Must Review') }
|
28
|
-
|
29
|
-
should 'have one approval' do
|
30
|
-
assert_equal 1, @project.approvals.size
|
31
|
-
end
|
32
|
-
|
33
|
-
should 'not update the records ignored column' do
|
34
|
-
assert_equal nil, @project.description
|
35
|
-
end
|
36
|
-
|
37
|
-
should 'update the records non-ignored columns' do
|
38
|
-
assert_equal 'Ignore Me', @project.title
|
39
|
-
end
|
40
|
-
|
41
|
-
should 'have the description on the approval' do
|
42
|
-
assert @project.approvals.last.object.key?('description')
|
43
|
-
assert_equal 'Must Review', @project.approvals.last.object['description']
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
context 'that is altered using #without_approval' do
|
48
|
-
should 'not have an approval object' do
|
49
|
-
@project.without_approval { |i| i.update_attribute(:description, 'updated') }
|
50
|
-
assert @project.approvals.empty?
|
51
|
-
end
|
52
|
-
|
53
|
-
should 'correctly restore approval queue state' do
|
54
|
-
assert @project.approvals_on?
|
55
|
-
@project.approvals_off
|
56
|
-
assert !@project.approvals_on?
|
57
|
-
@project.without_approval { |i| i.update_attribute(:description, 'updated') }
|
58
|
-
assert !@project.approvals_on?
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context 'and "only" fields' do
|
64
|
-
setup { @game = Game.create }
|
65
|
-
|
66
|
-
should 'have no approvals' do
|
67
|
-
assert @game.approvals.empty?
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'which updates an only column' do
|
71
|
-
setup { @game.update_attribute(:title, 'review') }
|
72
|
-
|
73
|
-
should 'have an approval' do
|
74
|
-
assert_equal 1, @game.approvals.size
|
75
|
-
end
|
76
|
-
|
77
|
-
should 'have pending changes' do
|
78
|
-
assert @game.pending_changes?
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context 'which updates an only column and another column' do
|
83
|
-
setup { @game.update_attributes(:title => 'review', :description => 'no review') }
|
84
|
-
|
85
|
-
should 'have one approval' do
|
86
|
-
assert_equal 1, @game.approvals.size
|
87
|
-
end
|
88
|
-
|
89
|
-
should 'not update the records only column' do
|
90
|
-
assert_equal nil, @game.title
|
91
|
-
end
|
92
|
-
|
93
|
-
should 'update the records other fields' do
|
94
|
-
assert_equal 'no review', @game.description
|
95
|
-
end
|
96
|
-
|
97
|
-
should 'have the title on the approval' do
|
98
|
-
assert @game.approvals.last.object.key?('title')
|
99
|
-
assert_equal 'review', @game.approvals.last.object['title']
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
context 'that has approved, rejected and pending update approvals' do
|
104
|
-
setup do
|
105
|
-
@game.update_attributes(:title => 'review1')
|
106
|
-
@game.update_approvals.last.approve!(true)
|
107
|
-
|
108
|
-
@game.update_attributes(:title => 'review2')
|
109
|
-
@game.update_approvals.last.reject!
|
110
|
-
|
111
|
-
@game.update_attributes(:title => 'review3')
|
112
|
-
@game.update_attributes(:title => 'review4')
|
113
|
-
end
|
114
|
-
|
115
|
-
should 'have #pending_changes?' do
|
116
|
-
assert @game.pending_changes?
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
context 'that has approved and rejected, but no pending update approvals' do
|
121
|
-
setup do
|
122
|
-
@game.update_attributes(:title => 'review1')
|
123
|
-
@game.update_approvals.last.approve!(true)
|
124
|
-
|
125
|
-
@game.update_attributes(:title => 'review2')
|
126
|
-
@game.update_approvals.last.reject!
|
127
|
-
end
|
128
|
-
|
129
|
-
should 'have #pending_changes?' do
|
130
|
-
assert !@game.pending_changes?
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
context 'that is altered using #without_approval' do
|
135
|
-
setup { @game.without_approval { |i| i.update_attribute(:title, 'updated') } }
|
136
|
-
|
137
|
-
should 'not have an approval object' do
|
138
|
-
assert @game.approvals.empty?
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
context 'with approval queue disabled' do
|
143
|
-
context 'at the record level' do
|
144
|
-
setup do
|
145
|
-
@game.approvals_off
|
146
|
-
@game.update_attributes(:title => 'review')
|
147
|
-
end
|
148
|
-
|
149
|
-
teardown { @game.approvals_on }
|
150
|
-
|
151
|
-
should 'have approvals off' do
|
152
|
-
assert @game.approvals_disabled?
|
153
|
-
end
|
154
|
-
|
155
|
-
should 'not have an approval object' do
|
156
|
-
assert @game.approvals.empty?
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
context 'at the model level' do
|
161
|
-
setup do
|
162
|
-
Game.approvals_off
|
163
|
-
@game.update_attributes(:title => 'review')
|
164
|
-
end
|
165
|
-
|
166
|
-
teardown { Game.approvals_on }
|
167
|
-
|
168
|
-
should 'have approvals off' do
|
169
|
-
assert @game.approvals_disabled?
|
170
|
-
end
|
171
|
-
|
172
|
-
should 'not have an approval object' do
|
173
|
-
assert @game.approvals.empty?
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
context 'at the global level' do
|
178
|
-
setup do
|
179
|
-
ActsAsApprovable.disable
|
180
|
-
@game.update_attributes(:title => 'review')
|
181
|
-
end
|
182
|
-
|
183
|
-
teardown { ActsAsApprovable.enable }
|
184
|
-
|
185
|
-
should 'have approvals off' do
|
186
|
-
assert @game.approvals_disabled?
|
187
|
-
end
|
188
|
-
|
189
|
-
should 'not have an approval object' do
|
190
|
-
assert @game.approvals.empty?
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
context 'An approval record' do
|
198
|
-
setup do
|
199
|
-
@project = Project.create
|
200
|
-
@project.update_attribute(:description, 'review')
|
201
|
-
@approval = @project.approvals.last
|
202
|
-
end
|
203
|
-
|
204
|
-
should 'not be locked by default' do
|
205
|
-
assert @approval.unlocked?
|
206
|
-
assert !@approval.locked?
|
207
|
-
end
|
208
|
-
|
209
|
-
should 'be pending' do
|
210
|
-
assert @approval.pending?
|
211
|
-
assert !@approval.approved?
|
212
|
-
assert !@approval.rejected?
|
213
|
-
end
|
214
|
-
|
215
|
-
should 'check attributes in object' do
|
216
|
-
@approval.object['foo'] = 'bar'
|
217
|
-
@approval.approve!
|
218
|
-
assert_equal @approval.object['description'], @approval.item.description
|
219
|
-
end
|
220
|
-
|
221
|
-
context 'that is accepted' do
|
222
|
-
setup { @approval.approve! }
|
223
|
-
|
224
|
-
should 'be locked' do
|
225
|
-
assert @approval.locked?
|
226
|
-
assert !@approval.unlocked?
|
227
|
-
end
|
228
|
-
|
229
|
-
should 'be approved' do
|
230
|
-
assert @approval.approved?
|
231
|
-
assert !@approval.rejected?
|
232
|
-
assert !@approval.pending?
|
233
|
-
end
|
234
|
-
|
235
|
-
should 'update the target item' do
|
236
|
-
assert_equal @approval.object['description'], @approval.item.description
|
237
|
-
end
|
238
|
-
|
239
|
-
should 'raise an error if approved again' do
|
240
|
-
assert_raise(ActsAsApprovable::Error::Locked) { @approval.approve! }
|
241
|
-
end
|
242
|
-
|
243
|
-
should 'raise an error if rejected' do
|
244
|
-
assert_raise(ActsAsApprovable::Error::Locked) { @approval.reject! }
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
context 'that is rejected' do
|
249
|
-
setup { @approval.reject! }
|
250
|
-
|
251
|
-
should 'be locked' do
|
252
|
-
assert @approval.locked?
|
253
|
-
assert !@approval.unlocked?
|
254
|
-
end
|
255
|
-
|
256
|
-
should 'be rejected' do
|
257
|
-
assert @approval.rejected?
|
258
|
-
assert !@approval.approved?
|
259
|
-
assert !@approval.pending?
|
260
|
-
end
|
261
|
-
|
262
|
-
should 'not update the target item' do
|
263
|
-
assert_equal nil, @approval.item.description
|
264
|
-
end
|
265
|
-
|
266
|
-
should 'raise an error if approved' do
|
267
|
-
assert_raise(ActsAsApprovable::Error::Locked) { @approval.approve! }
|
268
|
-
end
|
269
|
-
|
270
|
-
should 'raise an error if rejected again' do
|
271
|
-
assert_raise(ActsAsApprovable::Error::Locked) { @approval.reject! }
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
context 'that is stale' do
|
276
|
-
setup { @approval.update_attributes(:created_at => 10.days.ago) }
|
277
|
-
|
278
|
-
should 'be stale' do
|
279
|
-
assert @approval.stale?
|
280
|
-
assert !@approval.fresh?
|
281
|
-
end
|
282
|
-
|
283
|
-
should 'raise an error if approved' do
|
284
|
-
assert_raise(ActsAsApprovable::Error::Stale) { @approval.approve! }
|
285
|
-
assert @approval.pending?
|
286
|
-
end
|
287
|
-
|
288
|
-
should 'not raise an error if rejected' do
|
289
|
-
assert_nothing_raised { @approval.reject! }
|
290
|
-
assert @approval.rejected?
|
291
|
-
end
|
292
|
-
|
293
|
-
should 'allow approval when forced' do
|
294
|
-
assert_nothing_raised { @approval.approve!(true) }
|
295
|
-
assert @approval.approved?
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
context 'A record with create only approval' do
|
301
|
-
setup { @user = User.create }
|
302
|
-
|
303
|
-
should 'be pending by default' do
|
304
|
-
assert @user.pending?
|
305
|
-
assert !@user.approved?
|
306
|
-
assert !@user.rejected?
|
307
|
-
end
|
308
|
-
|
309
|
-
should 'have an approval object' do
|
310
|
-
assert_equal 1, @user.approvals.size
|
311
|
-
end
|
312
|
-
|
313
|
-
should 'set the local state' do
|
314
|
-
assert_equal 'pending', @user.state
|
315
|
-
end
|
316
|
-
|
317
|
-
context 'when approved' do
|
318
|
-
setup do
|
319
|
-
@user.approve!
|
320
|
-
@user.reload
|
321
|
-
end
|
322
|
-
|
323
|
-
should 'be approved' do
|
324
|
-
assert @user.approved?
|
325
|
-
assert !@user.rejected?
|
326
|
-
assert !@user.pending?
|
327
|
-
end
|
328
|
-
|
329
|
-
should 'update the local state' do
|
330
|
-
assert_equal 'approved', @user.state
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
context 'when rejected' do
|
335
|
-
setup do
|
336
|
-
@user.reject!
|
337
|
-
@user.reload
|
338
|
-
end
|
339
|
-
|
340
|
-
should 'be rejected' do
|
341
|
-
assert @user.rejected?
|
342
|
-
assert !@user.approved?
|
343
|
-
assert !@user.pending?
|
344
|
-
end
|
345
|
-
|
346
|
-
should 'update the local state' do
|
347
|
-
assert_equal 'rejected', @user.state
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
context '.without_approval' do
|
352
|
-
should 'disable approvals for the given block' do
|
353
|
-
@user = User.without_approval { |m| m.create }
|
354
|
-
assert @user.approval.nil?
|
355
|
-
end
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
context 'A record with default settings' do
|
360
|
-
setup { @employee = Employee.create }
|
361
|
-
|
362
|
-
should 'be pending by default' do
|
363
|
-
assert @employee.pending?
|
364
|
-
assert !@employee.approved?
|
365
|
-
assert !@employee.rejected?
|
366
|
-
end
|
367
|
-
|
368
|
-
should 'get the state from the approval record' do
|
369
|
-
assert_equal @employee.approval_state, @employee.approval.state
|
370
|
-
end
|
371
|
-
|
372
|
-
context 'when updated' do
|
373
|
-
setup { @employee.update_attributes(:name => 'John Doe') }
|
374
|
-
|
375
|
-
should 'not update the attribute' do
|
376
|
-
assert_equal nil, @employee.name
|
377
|
-
end
|
378
|
-
|
379
|
-
should 'create an approval record' do
|
380
|
-
assert_equal 1, @employee.update_approvals.size
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
context 'when approving' do
|
385
|
-
setup { @approval = @employee.approval }
|
386
|
-
|
387
|
-
should 'call before_approve hook' do
|
388
|
-
@approval.item.expects(:before_approve).once
|
389
|
-
@approval.approve!
|
390
|
-
end
|
391
|
-
|
392
|
-
should 'call after_approve hook' do
|
393
|
-
@approval.item.expects(:after_approve).once
|
394
|
-
@approval.approve!
|
395
|
-
end
|
396
|
-
|
397
|
-
should 'halt if before_approve returns false' do
|
398
|
-
@approval.item.stubs(:before_approve).returns(false)
|
399
|
-
@approval.approve!
|
400
|
-
assert @approval.item.pending?
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
context 'when rejecting' do
|
405
|
-
setup { @approval = @employee.approval }
|
406
|
-
|
407
|
-
should 'call before_reject hook' do
|
408
|
-
@approval.item.expects(:before_reject).once
|
409
|
-
@approval.reject!
|
410
|
-
end
|
411
|
-
|
412
|
-
should 'call after_reject hook' do
|
413
|
-
@approval.item.expects(:after_reject).once
|
414
|
-
@approval.reject!
|
415
|
-
end
|
416
|
-
|
417
|
-
should 'halt if before_reject returns false' do
|
418
|
-
@approval.item.stubs(:before_reject).returns(false)
|
419
|
-
@approval.reject!
|
420
|
-
assert @approval.item.pending?
|
421
|
-
end
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
context '.options_for_state' do
|
426
|
-
should 'return an array' do
|
427
|
-
assert_kind_of Array, Approval.options_for_state
|
428
|
-
end
|
429
|
-
|
430
|
-
should 'contain our states' do
|
431
|
-
assert Approval.options_for_state.include?(['All', -1])
|
432
|
-
assert Approval.options_for_state.include?(['Pending', 0])
|
433
|
-
assert Approval.options_for_state.include?(['Approved', 1])
|
434
|
-
assert Approval.options_for_state.include?(['Rejected', 2])
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
|
-
context '.options_for_type' do
|
439
|
-
context 'without approval records' do
|
440
|
-
should 'be empty' do
|
441
|
-
assert Approval.options_for_type.empty?
|
442
|
-
end
|
443
|
-
end
|
444
|
-
|
445
|
-
context 'with approval records' do
|
446
|
-
setup do
|
447
|
-
Project.create.update_attributes(:description => 'review')
|
448
|
-
Game.create.update_attributes(:title => 'review')
|
449
|
-
User.create
|
450
|
-
end
|
451
|
-
|
452
|
-
should 'contain all types with approvals' do
|
453
|
-
assert Approval.options_for_type.include?('Project')
|
454
|
-
assert Approval.options_for_type.include?('Game')
|
455
|
-
assert Approval.options_for_type.include?('User')
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end
|