cancancan 1.15.0 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +38 -0
  3. data/.rubocop_todo.yml +48 -0
  4. data/.travis.yml +8 -2
  5. data/Appraisals +1 -0
  6. data/CHANGELOG.rdoc +5 -0
  7. data/Gemfile +1 -1
  8. data/README.md +58 -41
  9. data/Rakefile +7 -3
  10. data/cancancan.gemspec +13 -12
  11. data/gemfiles/activerecord_4.2.gemfile +1 -0
  12. data/lib/cancan.rb +2 -2
  13. data/lib/cancan/ability.rb +26 -24
  14. data/lib/cancan/controller_additions.rb +33 -23
  15. data/lib/cancan/controller_resource.rb +83 -56
  16. data/lib/cancan/exceptions.rb +1 -1
  17. data/lib/cancan/matchers.rb +2 -2
  18. data/lib/cancan/model_adapters/abstract_adapter.rb +8 -8
  19. data/lib/cancan/model_adapters/active_record_4_adapter.rb +48 -35
  20. data/lib/cancan/model_adapters/active_record_adapter.rb +18 -17
  21. data/lib/cancan/model_adapters/mongoid_adapter.rb +26 -21
  22. data/lib/cancan/model_adapters/sequel_adapter.rb +12 -12
  23. data/lib/cancan/model_additions.rb +0 -1
  24. data/lib/cancan/rule.rb +23 -17
  25. data/lib/cancan/version.rb +1 -1
  26. data/lib/generators/cancan/ability/ability_generator.rb +1 -1
  27. data/spec/cancan/ability_spec.rb +189 -180
  28. data/spec/cancan/controller_additions_spec.rb +77 -64
  29. data/spec/cancan/controller_resource_spec.rb +230 -228
  30. data/spec/cancan/exceptions_spec.rb +20 -20
  31. data/spec/cancan/inherited_resource_spec.rb +21 -21
  32. data/spec/cancan/matchers_spec.rb +12 -12
  33. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +38 -32
  34. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +155 -145
  35. data/spec/cancan/model_adapters/default_adapter_spec.rb +2 -2
  36. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +87 -88
  37. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +44 -47
  38. data/spec/cancan/rule_spec.rb +18 -18
  39. data/spec/spec_helper.rb +2 -2
  40. data/spec/support/ability.rb +0 -1
  41. metadata +60 -19
@@ -4,7 +4,7 @@ module Cancan
4
4
  source_root File.expand_path('../templates', __FILE__)
5
5
 
6
6
  def generate_ability
7
- copy_file "ability.rb", "app/models/ability.rb"
7
+ copy_file 'ability.rb', 'app/models/ability.rb'
8
8
  end
9
9
  end
10
10
  end
@@ -1,11 +1,11 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
3
  describe CanCan::Ability do
4
4
  before(:each) do
5
5
  (@ability = double).extend(CanCan::Ability)
6
6
  end
7
7
 
8
- it "is able to :read anything" do
8
+ it 'is able to :read anything' do
9
9
  @ability.can :read, :all
10
10
  expect(@ability.can?(:read, String)).to be(true)
11
11
  expect(@ability.can?(:read, 123)).to be(true)
@@ -15,15 +15,15 @@ describe CanCan::Ability do
15
15
  expect(@ability.can?(:foodfight, String)).to be(false)
16
16
  end
17
17
 
18
- it "passes true to `can?` when non false/nil is returned in block" do
18
+ it 'passes true to `can?` when non false/nil is returned in block' do
19
19
  @ability.can :read, :all
20
- @ability.can :read, Symbol do |sym|
21
- "foo" # TODO test that sym is nil when no instance is passed
20
+ @ability.can :read, Symbol do |_sym|
21
+ 'foo' # TODO: test that sym is nil when no instance is passed
22
22
  end
23
23
  expect(@ability.can?(:read, :some_symbol)).to be(true)
24
24
  end
25
25
 
26
- it "passes nil to a block when no instance is passed" do
26
+ it 'passes nil to a block when no instance is passed' do
27
27
  @ability.can :read, Symbol do |sym|
28
28
  expect(sym).to be_nil
29
29
  true
@@ -31,7 +31,7 @@ describe CanCan::Ability do
31
31
  expect(@ability.can?(:read, Symbol)).to be(true)
32
32
  end
33
33
 
34
- it "passes to previous rule, if block returns false or nil" do
34
+ it 'passes to previous rule, if block returns false or nil' do
35
35
  @ability.can :read, Symbol
36
36
  @ability.can :read, Integer do |i|
37
37
  i < 5
@@ -45,30 +45,30 @@ describe CanCan::Ability do
45
45
  expect(@ability.can?(:read, 6)).to be(false)
46
46
  end
47
47
 
48
- it "overrides earlier rules with later ones (even if a different exact subject)" do
48
+ it 'overrides earlier rules with later ones (even if a different exact subject)' do
49
49
  @ability.cannot :read, Numeric
50
50
  @ability.can :read, Integer
51
51
 
52
52
  expect(@ability.can?(:read, 6)).to be(true)
53
53
  end
54
54
 
55
- it "performs can(_, :all) before other checks when can(_, :all) is defined before" do
55
+ it 'performs can(_, :all) before other checks when can(_, :all) is defined before' do
56
56
  @ability.can :manage, :all
57
57
  @ability.can :edit, String do |_string|
58
- fail 'Performed a check for :edit before the check for :all'
58
+ raise 'Performed a check for :edit before the check for :all'
59
59
  end
60
60
  expect { @ability.can? :edit, 'a' }.to_not raise_exception
61
61
  end
62
62
 
63
- it "performs can(_, :all) before other checks when can(_, :all) is defined after" do
63
+ it 'performs can(_, :all) before other checks when can(_, :all) is defined after' do
64
64
  @ability.can :edit, String do |_string|
65
- fail 'Performed a check for :edit before the check for :all'
65
+ raise 'Performed a check for :edit before the check for :all'
66
66
  end
67
67
  @ability.can :manage, :all
68
68
  expect { @ability.can? :edit, 'a' }.to_not raise_exception
69
69
  end
70
70
 
71
- it "does not pass class with object if :all objects are accepted" do
71
+ it 'does not pass class with object if :all objects are accepted' do
72
72
  @ability.can :preview, :all do |object|
73
73
  expect(object).to eq(123)
74
74
  @block_called = true
@@ -77,43 +77,44 @@ describe CanCan::Ability do
77
77
  expect(@block_called).to be(true)
78
78
  end
79
79
 
80
- it "does not call block when only class is passed, only return true" do
80
+ it 'does not call block when only class is passed, only return true' do
81
81
  @block_called = false
82
- @ability.can :preview, :all do |object|
82
+ @ability.can :preview, :all do |_object|
83
83
  @block_called = true
84
84
  end
85
85
  expect(@ability.can?(:preview, Hash)).to be(true)
86
86
  expect(@block_called).to be(false)
87
87
  end
88
88
 
89
- it "passes only object for global manage actions" do
89
+ it 'passes only object for global manage actions' do
90
90
  @ability.can :manage, String do |object|
91
- expect(object).to eq("foo")
91
+ expect(object).to eq('foo')
92
92
  @block_called = true
93
93
  end
94
- expect(@ability.can?(:stuff, "foo")).to be(true)
94
+ expect(@ability.can?(:stuff, 'foo')).to be(true)
95
95
  expect(@block_called).to be(true)
96
96
  end
97
97
 
98
- it "makes alias for update or destroy actions to modify action" do
99
- @ability.alias_action :update, :destroy, :to => :modify
98
+ it 'makes alias for update or destroy actions to modify action' do
99
+ @ability.alias_action :update, :destroy, to: :modify
100
100
  @ability.can :modify, :all
101
101
  expect(@ability.can?(:update, 123)).to be(true)
102
102
  expect(@ability.can?(:destroy, 123)).to be(true)
103
103
  end
104
104
 
105
- it "allows deeply nested aliased actions" do
106
- @ability.alias_action :increment, :to => :sort
107
- @ability.alias_action :sort, :to => :modify
105
+ it 'allows deeply nested aliased actions' do
106
+ @ability.alias_action :increment, to: :sort
107
+ @ability.alias_action :sort, to: :modify
108
108
  @ability.can :modify, :all
109
109
  expect(@ability.can?(:increment, 123)).to be(true)
110
110
  end
111
111
 
112
- it "raises an Error if alias target is an exist action" do
113
- expect { @ability.alias_action :show, :to => :show }.to raise_error(CanCan::Error, "You can't specify target (show) as alias because it is real action name")
112
+ it 'raises an Error if alias target is an exist action' do
113
+ expect { @ability.alias_action :show, to: :show }
114
+ .to raise_error(CanCan::Error, "You can't specify target (show) as alias because it is real action name")
114
115
  end
115
116
 
116
- it "always calls block with arguments when passing no arguments to can" do
117
+ it 'always calls block with arguments when passing no arguments to can' do
117
118
  @ability.can do |action, object_class, object|
118
119
  expect(action).to eq(:foo)
119
120
  expect(object_class).to eq(123.class)
@@ -124,7 +125,7 @@ describe CanCan::Ability do
124
125
  expect(@block_called).to be(true)
125
126
  end
126
127
 
127
- it "passes nil to object when comparing class with can check" do
128
+ it 'passes nil to object when comparing class with can check' do
128
129
  @ability.can do |action, object_class, object|
129
130
  expect(action).to eq(:foo)
130
131
  expect(object_class).to eq(Hash)
@@ -135,247 +136,250 @@ describe CanCan::Ability do
135
136
  expect(@block_called).to be(true)
136
137
  end
137
138
 
138
- it "automatically makes alias for index and show into read calls" do
139
+ it 'automatically makes alias for index and show into read calls' do
139
140
  @ability.can :read, :all
140
141
  expect(@ability.can?(:index, 123)).to be(true)
141
142
  expect(@ability.can?(:show, 123)).to be(true)
142
143
  end
143
144
 
144
- it "automatically makes alias for new and edit into create and update respectively" do
145
+ it 'automatically makes alias for new and edit into create and update respectively' do
145
146
  @ability.can :create, :all
146
147
  @ability.can :update, :all
147
148
  expect(@ability.can?(:new, 123)).to be(true)
148
149
  expect(@ability.can?(:edit, 123)).to be(true)
149
150
  end
150
151
 
151
- it "does not respond to prepare (now using initialize)" do
152
+ it 'does not respond to prepare (now using initialize)' do
152
153
  expect(@ability).to_not respond_to(:prepare)
153
154
  end
154
155
 
155
- it "offers cannot? method which is simply invert of can?" do
156
+ it 'offers cannot? method which is simply invert of can?' do
156
157
  expect(@ability.cannot?(:tie, String)).to be(true)
157
158
  end
158
159
 
159
- it "is able to specify multiple actions and match any" do
160
+ it 'is able to specify multiple actions and match any' do
160
161
  @ability.can [:read, :update], :all
161
162
  expect(@ability.can?(:read, 123)).to be(true)
162
163
  expect(@ability.can?(:update, 123)).to be(true)
163
164
  expect(@ability.can?(:count, 123)).to be(false)
164
165
  end
165
166
 
166
- it "is able to specify multiple classes and match any" do
167
+ it 'is able to specify multiple classes and match any' do
167
168
  @ability.can :update, [String, Range]
168
- expect(@ability.can?(:update, "foo")).to be(true)
169
+ expect(@ability.can?(:update, 'foo')).to be(true)
169
170
  expect(@ability.can?(:update, 1..3)).to be(true)
170
171
  expect(@ability.can?(:update, 123)).to be(false)
171
172
  end
172
173
 
173
- it "checks if there is a permission for any of given subjects" do
174
+ it 'checks if there is a permission for any of given subjects' do
174
175
  @ability.can :update, [String, Range]
175
- expect(@ability.can?(:update, {:any => ["foo", 1..3]})).to be(true)
176
- expect(@ability.can?(:update, {:any => [1..3, "foo"]})).to be(true)
177
- expect(@ability.can?(:update, {:any => [123, "foo"]})).to be(true)
178
- expect(@ability.can?(:update, {:any => [123, 1.0]})).to be(false)
176
+ expect(@ability.can?(:update, any: ['foo', 1..3])).to be(true)
177
+ expect(@ability.can?(:update, any: [1..3, 'foo'])).to be(true)
178
+ expect(@ability.can?(:update, any: [123, 'foo'])).to be(true)
179
+ expect(@ability.can?(:update, any: [123, 1.0])).to be(false)
179
180
  end
180
181
 
181
- it "lists all permissions" do
182
+ it 'lists all permissions' do
182
183
  @ability.can :manage, :all
183
184
  @ability.can :learn, Range
184
185
  @ability.cannot :read, String
185
186
  @ability.cannot :read, Hash
186
187
  @ability.cannot :preview, Array
187
188
 
188
- expected_list = {:can => {:manage => ["all"],
189
- :learn => ["Range"]
190
- },
191
- :cannot => {:read => ["String", "Hash"],
192
- :index => ["String", "Hash"],
193
- :show => ["String", "Hash"],
194
- :preview => ["Array"]
195
- }
196
- }
189
+ expected_list = { can: { manage: ['all'],
190
+ learn: ['Range'] },
191
+ cannot: { read: %w(String Hash),
192
+ index: %w(String Hash),
193
+ show: %w(String Hash),
194
+ preview: ['Array'] } }
197
195
 
198
196
  expect(@ability.permissions).to eq(expected_list)
199
197
  end
200
198
 
201
- it "supports custom objects in the rule" do
199
+ it 'supports custom objects in the rule' do
202
200
  @ability.can :read, :stats
203
201
  expect(@ability.can?(:read, :stats)).to be(true)
204
202
  expect(@ability.can?(:update, :stats)).to be(false)
205
203
  expect(@ability.can?(:read, :nonstats)).to be(false)
206
- expect(@ability.can?(:read, {:any => [:stats, :nonstats]})).to be(true)
207
- expect(@ability.can?(:read, {:any => [:nonstats, :neitherstats]})).to be(false)
204
+ expect(@ability.can?(:read, any: [:stats, :nonstats])).to be(true)
205
+ expect(@ability.can?(:read, any: [:nonstats, :neitherstats])).to be(false)
208
206
  end
209
207
 
210
- it "checks ancestors of class" do
208
+ it 'checks ancestors of class' do
211
209
  @ability.can :read, Numeric
212
210
  expect(@ability.can?(:read, Integer)).to be(true)
213
211
  expect(@ability.can?(:read, 1.23)).to be(true)
214
- expect(@ability.can?(:read, "foo")).to be(false)
215
- expect(@ability.can?(:read, {:any => [Integer, String]})).to be(true)
212
+ expect(@ability.can?(:read, 'foo')).to be(false)
213
+ expect(@ability.can?(:read, any: [Integer, String])).to be(true)
216
214
  end
217
215
 
218
216
  it "supports 'cannot' method to define what user cannot do" do
219
217
  @ability.can :read, :all
220
218
  @ability.cannot :read, Integer
221
- expect(@ability.can?(:read, "foo")).to be(true)
219
+ expect(@ability.can?(:read, 'foo')).to be(true)
222
220
  expect(@ability.can?(:read, 123)).to be(false)
223
- expect(@ability.can?(:read, {:any => ["foo", "bar"]})).to be(true)
224
- expect(@ability.can?(:read, {:any => [123, "foo"]})).to be(false)
225
- expect(@ability.can?(:read, {:any => [123, 456]})).to be(false)
221
+ expect(@ability.can?(:read, any: %w(foo bar))).to be(true)
222
+ expect(@ability.can?(:read, any: [123, 'foo'])).to be(false)
223
+ expect(@ability.can?(:read, any: [123, 456])).to be(false)
226
224
  end
227
225
 
228
- it "passes to previous rule, if block returns false or nil" do
226
+ it 'passes to previous rule, if block returns false or nil' do
229
227
  @ability.can :read, :all
230
228
  @ability.cannot :read, Integer do |int|
231
- int > 10 ? nil : ( int > 5 )
229
+ int > 10 ? nil : (int > 5)
232
230
  end
233
231
 
234
- expect(@ability.can?(:read, "foo")).to be(true)
232
+ expect(@ability.can?(:read, 'foo')).to be(true)
235
233
  expect(@ability.can?(:read, 3)).to be(true)
236
234
  expect(@ability.can?(:read, 8)).to be(false)
237
235
  expect(@ability.can?(:read, 123)).to be(true)
238
- expect(@ability.can?(:read, {:any => [123, 8]})).to be(true)
239
- expect(@ability.can?(:read, {:any => [8, 9]})).to be(false)
236
+ expect(@ability.can?(:read, any: [123, 8])).to be(true)
237
+ expect(@ability.can?(:read, any: [8, 9])).to be(false)
240
238
  end
241
239
 
242
- it "always returns `false` for single cannot definition" do
240
+ it 'always returns `false` for single cannot definition' do
243
241
  @ability.cannot :read, Integer do |int|
244
- int > 10 ? nil : ( int > 5 )
242
+ int > 10 ? nil : (int > 5)
245
243
  end
246
- expect(@ability.can?(:read, "foo")).to be(false)
244
+ expect(@ability.can?(:read, 'foo')).to be(false)
247
245
  expect(@ability.can?(:read, 3)).to be(false)
248
246
  expect(@ability.can?(:read, 8)).to be(false)
249
247
  expect(@ability.can?(:read, 123)).to be(false)
250
248
  end
251
249
 
252
- it "passes to previous cannot definition, if block returns false or nil" do
250
+ it 'passes to previous cannot definition, if block returns false or nil' do
253
251
  @ability.cannot :read, :all
254
252
  @ability.can :read, Integer do |int|
255
- int > 10 ? nil : ( int > 5 )
253
+ int > 10 ? nil : (int > 5)
256
254
  end
257
- expect(@ability.can?(:read, "foo")).to be(false)
255
+ expect(@ability.can?(:read, 'foo')).to be(false)
258
256
  expect(@ability.can?(:read, 3)).to be(false)
259
257
  expect(@ability.can?(:read, 10)).to be(true)
260
258
  expect(@ability.can?(:read, 123)).to be(false)
261
259
  end
262
260
 
263
- it "appends aliased actions" do
264
- @ability.alias_action :update, :to => :modify
265
- @ability.alias_action :destroy, :to => :modify
261
+ it 'appends aliased actions' do
262
+ @ability.alias_action :update, to: :modify
263
+ @ability.alias_action :destroy, to: :modify
266
264
  expect(@ability.aliased_actions[:modify]).to eq([:update, :destroy])
267
265
  end
268
266
 
269
- it "clears aliased actions" do
270
- @ability.alias_action :update, :to => :modify
267
+ it 'clears aliased actions' do
268
+ @ability.alias_action :update, to: :modify
271
269
  @ability.clear_aliased_actions
272
270
  expect(@ability.aliased_actions[:modify]).to be_nil
273
271
  end
274
272
 
275
- it "passes additional arguments to block from can?" do
273
+ it 'passes additional arguments to block from can?' do
276
274
  @ability.can :read, Integer do |int, x|
277
275
  int > x
278
276
  end
279
277
 
280
278
  expect(@ability.can?(:read, 2, 1)).to be(true)
281
279
  expect(@ability.can?(:read, 2, 3)).to be(false)
282
- expect(@ability.can?(:read, {:any => [4, 5]}, 3)).to be(true)
283
- expect(@ability.can?(:read, {:any => [2, 3]}, 3)).to be(false)
280
+ expect(@ability.can?(:read, { any: [4, 5] }, 3)).to be(true)
281
+ expect(@ability.can?(:read, { any: [2, 3] }, 3)).to be(false)
284
282
  end
285
283
 
286
- it "uses conditions as third parameter and determine abilities from it" do
287
- @ability.can :read, Range, :begin => 1, :end => 3
284
+ it 'uses conditions as third parameter and determine abilities from it' do
285
+ @ability.can :read, Range, begin: 1, end: 3
288
286
 
289
287
  expect(@ability.can?(:read, 1..3)).to be(true)
290
288
  expect(@ability.can?(:read, 1..4)).to be(false)
291
289
  expect(@ability.can?(:read, Range)).to be(true)
292
- expect(@ability.can?(:read, {:any => [1..3, 1..4]})).to be(true)
293
- expect(@ability.can?(:read, {:any => [1..4, 2..4]})).to be(false)
290
+ expect(@ability.can?(:read, any: [1..3, 1..4])).to be(true)
291
+ expect(@ability.can?(:read, any: [1..4, 2..4])).to be(false)
294
292
  end
295
293
 
296
- it "allows an array of options in conditions hash" do
297
- @ability.can :read, Range, :begin => [1, 3, 5]
294
+ it 'allows an array of options in conditions hash' do
295
+ @ability.can :read, Range, begin: [1, 3, 5]
298
296
 
299
297
  expect(@ability.can?(:read, 1..3)).to be(true)
300
298
  expect(@ability.can?(:read, 2..4)).to be(false)
301
299
  expect(@ability.can?(:read, 3..5)).to be(true)
302
- expect(@ability.can?(:read, {:any => [2..4, 3..5]})).to be(true)
303
- expect(@ability.can?(:read, {:any => [2..4, 2..5]})).to be(false)
300
+ expect(@ability.can?(:read, any: [2..4, 3..5])).to be(true)
301
+ expect(@ability.can?(:read, any: [2..4, 2..5])).to be(false)
304
302
  end
305
303
 
306
- it "allows a range of options in conditions hash" do
307
- @ability.can :read, Range, :begin => 1..3
304
+ it 'allows a range of options in conditions hash' do
305
+ @ability.can :read, Range, begin: 1..3
308
306
  expect(@ability.can?(:read, 1..10)).to be(true)
309
307
  expect(@ability.can?(:read, 3..30)).to be(true)
310
308
  expect(@ability.can?(:read, 4..40)).to be(false)
311
309
  end
312
310
 
313
- it "allows a range of time in conditions hash" do
314
- @ability.can :read, Range, :begin => 1.day.from_now..3.days.from_now
311
+ it 'allows a range of time in conditions hash' do
312
+ @ability.can :read, Range, begin: 1.day.from_now..3.days.from_now
315
313
  expect(@ability.can?(:read, 1.day.from_now..10.days.from_now)).to be(true)
316
314
  expect(@ability.can?(:read, 2.days.from_now..20.days.from_now)).to be(true)
317
315
  expect(@ability.can?(:read, 4.days.from_now..40.days.from_now)).to be(false)
318
316
  end
319
317
 
320
- it "allows nested hashes in conditions hash" do
321
- @ability.can :read, Range, :begin => { :to_i => 5 }
318
+ it 'allows nested hashes in conditions hash' do
319
+ @ability.can :read, Range, begin: { to_i: 5 }
322
320
  expect(@ability.can?(:read, 5..7)).to be(true)
323
321
  expect(@ability.can?(:read, 6..8)).to be(false)
324
322
  end
325
323
 
326
324
  it "matches any element passed in to nesting if it's an array (for has_many associations)" do
327
- @ability.can :read, Range, :to_a => { :to_i => 3 }
325
+ @ability.can :read, Range, to_a: { to_i: 3 }
328
326
  expect(@ability.can?(:read, 1..5)).to be(true)
329
327
  expect(@ability.can?(:read, 4..6)).to be(false)
330
328
  end
331
329
 
332
- it "accepts a set as a condition value" do
333
- expect(object_with_foo_2 = double(:foo => 2)).to receive(:foo)
334
- expect(object_with_foo_3 = double(:foo => 3)).to receive(:foo)
335
- @ability.can :read, Object, :foo => [1, 2, 5].to_set
330
+ it 'accepts a set as a condition value' do
331
+ expect(object_with_foo_2 = double(foo: 2)).to receive(:foo)
332
+ expect(object_with_foo_3 = double(foo: 3)).to receive(:foo)
333
+ @ability.can :read, Object, foo: [1, 2, 5].to_set
336
334
  expect(@ability.can?(:read, object_with_foo_2)).to be(true)
337
335
  expect(@ability.can?(:read, object_with_foo_3)).to be(false)
338
336
  end
339
337
 
340
- it "does not match subjects return nil for methods that must match nested a nested conditions hash" do
341
- expect(object_with_foo = double(:foo => :bar)).to receive(:foo)
342
- @ability.can :read, Array, :first => { :foo => :bar }
338
+ it 'does not match subjects return nil for methods that must match nested a nested conditions hash' do
339
+ expect(object_with_foo = double(foo: :bar)).to receive(:foo)
340
+ @ability.can :read, Array, first: { foo: :bar }
343
341
  expect(@ability.can?(:read, [object_with_foo])).to be(true)
344
342
  expect(@ability.can?(:read, [])).to be(false)
345
343
  end
346
344
 
347
- it "matches strings but not substrings specified in a conditions hash" do
348
- @ability.can :read, String, :presence => "declassified"
349
- expect(@ability.can?(:read, "declassified")).to be(true)
350
- expect(@ability.can?(:read, "classified")).to be(false)
345
+ it 'matches strings but not substrings specified in a conditions hash' do
346
+ @ability.can :read, String, presence: 'declassified'
347
+ expect(@ability.can?(:read, 'declassified')).to be(true)
348
+ expect(@ability.can?(:read, 'classified')).to be(false)
351
349
  end
352
350
 
353
- it "does not stop at cannot definition when comparing class" do
351
+ it 'does not stop at cannot definition when comparing class' do
354
352
  @ability.can :read, Range
355
- @ability.cannot :read, Range, :begin => 1
353
+ @ability.cannot :read, Range, begin: 1
356
354
  expect(@ability.can?(:read, 2..5)).to be(true)
357
355
  expect(@ability.can?(:read, 1..5)).to be(false)
358
356
  expect(@ability.can?(:read, Range)).to be(true)
359
357
  end
360
358
 
361
- it "stops at cannot definition when no hash is present" do
359
+ it 'stops at cannot definition when no hash is present' do
362
360
  @ability.can :read, :all
363
361
  @ability.cannot :read, Range
364
362
  expect(@ability.can?(:read, 1..5)).to be(false)
365
363
  expect(@ability.can?(:read, Range)).to be(false)
366
364
  end
367
365
 
368
- it "allows to check ability for Module" do
369
- module B; end
370
- class A; include B; end
366
+ it 'allows to check ability for Module' do
367
+ module B
368
+ end
369
+ class A
370
+ include B
371
+ end
371
372
  @ability.can :read, B
372
373
  expect(@ability.can?(:read, A)).to be(true)
373
374
  expect(@ability.can?(:read, A.new)).to be(true)
374
375
  end
375
376
 
376
- it "passes nil to a block for ability on Module when no instance is passed" do
377
- module B; end
378
- class A; include B; end
377
+ it 'passes nil to a block for ability on Module when no instance is passed' do
378
+ module B
379
+ end
380
+ class A
381
+ include B
382
+ end
379
383
  @ability.can :read, B do |sym|
380
384
  expect(sym).to be_nil
381
385
  true
@@ -384,147 +388,152 @@ describe CanCan::Ability do
384
388
  expect(@ability.can?(:read, A)).to be(true)
385
389
  end
386
390
 
387
- it "checks permissions through association when passing a hash of subjects" do
388
- @ability.can :read, Range, :string => {:length => 3}
391
+ it 'checks permissions through association when passing a hash of subjects' do
392
+ @ability.can :read, Range, string: { length: 3 }
389
393
 
390
- expect(@ability.can?(:read, "foo" => Range)).to be(true)
391
- expect(@ability.can?(:read, "foobar" => Range)).to be(false)
394
+ expect(@ability.can?(:read, 'foo' => Range)).to be(true)
395
+ expect(@ability.can?(:read, 'foobar' => Range)).to be(false)
392
396
  expect(@ability.can?(:read, 123 => Range)).to be(true)
393
- expect(@ability.can?(:read, {:any => [{"foo" => Range}, {"foobar" => Range}]})).to be(true)
394
- expect(@ability.can?(:read, {:any => [{"food" => Range}, {"foobar" => Range}]})).to be(false)
397
+ expect(@ability.can?(:read, any: [{ 'foo' => Range }, { 'foobar' => Range }])).to be(true)
398
+ expect(@ability.can?(:read, any: [{ 'food' => Range }, { 'foobar' => Range }])).to be(false)
395
399
  end
396
400
 
397
- it "checks permissions correctly when passing a hash of subjects with multiple definitions" do
398
- @ability.can :read, Range, :string => {:length => 4}
399
- @ability.can [:create, :read], Range, :string => {:upcase => 'FOO'}
401
+ it 'checks permissions correctly when passing a hash of subjects with multiple definitions' do
402
+ @ability.can :read, Range, string: { length: 4 }
403
+ @ability.can [:create, :read], Range, string: { upcase: 'FOO' }
400
404
 
401
- expect(@ability.can?(:read, "foo" => Range)).to be(true)
402
- expect(@ability.can?(:read, "foobar" => Range)).to be(false)
405
+ expect(@ability.can?(:read, 'foo' => Range)).to be(true)
406
+ expect(@ability.can?(:read, 'foobar' => Range)).to be(false)
403
407
  expect(@ability.can?(:read, 1234 => Range)).to be(true)
404
- expect(@ability.can?(:read, {:any => [{"foo" => Range}, {"foobar" => Range}]})).to be(true)
405
- expect(@ability.can?(:read, {:any => [{"foo.bar" => Range}, {"foobar" => Range}]})).to be(false)
408
+ expect(@ability.can?(:read, any: [{ 'foo' => Range }, { 'foobar' => Range }])).to be(true)
409
+ expect(@ability.can?(:read, any: [{ 'foo.bar' => Range }, { 'foobar' => Range }])).to be(false)
406
410
  end
407
411
 
408
- it "allows to check ability on Hash-like object" do
409
- class Container < Hash; end
412
+ it 'allows to check ability on Hash-like object' do
413
+ class Container < Hash
414
+ end
410
415
  @ability.can :read, Container
411
416
  expect(@ability.can?(:read, Container.new)).to be(true)
412
417
  end
413
418
 
414
419
  it "has initial attributes based on hash conditions of 'new' action" do
415
- @ability.can :manage, Range, :foo => "foo", :hash => {:skip => "hashes"}
416
- @ability.can :create, Range, :bar => 123, :array => %w[skip arrays]
417
- @ability.can :new, Range, :baz => "baz", :range => 1..3
418
- @ability.cannot :new, Range, :ignore => "me"
419
- expect(@ability.attributes_for(:new, Range)).to eq({:foo => "foo", :bar => 123, :baz => "baz"})
420
+ @ability.can :manage, Range, foo: 'foo', hash: { skip: 'hashes' }
421
+ @ability.can :create, Range, bar: 123, array: %w(skip arrays)
422
+ @ability.can :new, Range, baz: 'baz', range: 1..3
423
+ @ability.cannot :new, Range, ignore: 'me'
424
+ expect(@ability.attributes_for(:new, Range)).to eq(foo: 'foo', bar: 123, baz: 'baz')
420
425
  end
421
426
 
422
- it "raises access denied exception if ability us unauthorized to perform a certain action" do
427
+ it 'raises access denied exception if ability us unauthorized to perform a certain action' do
423
428
  begin
424
- @ability.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!"
429
+ @ability.authorize! :read, :foo, 1, 2, 3, message: 'Access denied!'
425
430
  rescue CanCan::AccessDenied => e
426
- expect(e.message).to eq("Access denied!")
431
+ expect(e.message).to eq('Access denied!')
427
432
  expect(e.action).to eq(:read)
428
433
  expect(e.subject).to eq(:foo)
429
434
  else
430
- fail "Expected CanCan::AccessDenied exception to be raised"
435
+ raise 'Expected CanCan::AccessDenied exception to be raised'
431
436
  end
432
437
  end
433
438
 
434
- it "does not raise access denied exception if ability is authorized to perform an action and return subject" do
439
+ it 'does not raise access denied exception if ability is authorized to perform an action and return subject' do
435
440
  @ability.can :read, :foo
436
- expect {
441
+ expect do
437
442
  expect(@ability.authorize!(:read, :foo)).to eq(:foo)
438
- }.to_not raise_error
443
+ end.to_not raise_error
439
444
  end
440
445
 
441
- it "knows when block is used in conditions" do
446
+ it 'knows when block is used in conditions' do
442
447
  @ability.can :read, :foo
443
448
  expect(@ability).to_not have_block(:read, :foo)
444
- @ability.can :read, :foo do |foo|
449
+ @ability.can :read, :foo do |_foo|
445
450
  false
446
451
  end
447
452
  expect(@ability).to have_block(:read, :foo)
448
453
  end
449
454
 
450
- it "knows when raw sql is used in conditions" do
455
+ it 'knows when raw sql is used in conditions' do
451
456
  @ability.can :read, :foo
452
457
  expect(@ability).to_not have_raw_sql(:read, :foo)
453
458
  @ability.can :read, :foo, 'false'
454
459
  expect(@ability).to have_raw_sql(:read, :foo)
455
460
  end
456
461
 
457
- it "raises access denied exception with default message if not specified" do
462
+ it 'raises access denied exception with default message if not specified' do
458
463
  begin
459
464
  @ability.authorize! :read, :foo
460
465
  rescue CanCan::AccessDenied => e
461
- e.default_message = "Access denied!"
462
- expect(e.message).to eq("Access denied!")
466
+ e.default_message = 'Access denied!'
467
+ expect(e.message).to eq('Access denied!')
463
468
  else
464
- fail "Expected CanCan::AccessDenied exception to be raised"
469
+ raise 'Expected CanCan::AccessDenied exception to be raised'
465
470
  end
466
471
  end
467
472
 
468
- it "determines model adapterO class by asking AbstractAdapter" do
469
- adapter_class, model_class = double, double
473
+ it 'determines model adapterO class by asking AbstractAdapter' do
474
+ adapter_class = double
475
+ model_class = double
470
476
  allow(CanCan::ModelAdapters::AbstractAdapter).to receive(:adapter_class).with(model_class) { adapter_class }
471
477
  allow(adapter_class).to receive(:new).with(model_class, []) { :adapter_instance }
472
478
  expect(@ability.model_adapter(model_class, :read)).to eq(:adapter_instance)
473
479
  end
474
480
 
475
481
  it "raises an error when attempting to use a block with a hash condition since it's not likely what they want" do
476
- expect {
477
- @ability.can :read, Array, :published => true do
482
+ expect do
483
+ @ability.can :read, Array, published: true do
478
484
  false
479
485
  end
480
- }.to raise_error(CanCan::Error, "You are not able to supply a block with a hash of conditions in read Array ability. Use either one.")
486
+ end.to raise_error(CanCan::Error,
487
+ 'You are not able to supply a block with a hash of conditions in read Array ability. '\
488
+ 'Use either one.')
481
489
  end
482
490
 
483
- describe "unauthorized message" do
491
+ describe 'unauthorized message' do
484
492
  after(:each) do
485
493
  I18n.backend = nil
486
494
  end
487
495
 
488
- it "uses action/subject in i18n" do
489
- I18n.backend.store_translations :en, :unauthorized => {:update => {:array => "foo"}}
490
- expect(@ability.unauthorized_message(:update, Array)).to eq("foo")
491
- expect(@ability.unauthorized_message(:update, [1, 2, 3])).to eq("foo")
496
+ it 'uses action/subject in i18n' do
497
+ I18n.backend.store_translations :en, unauthorized: { update: { array: 'foo' } }
498
+ expect(@ability.unauthorized_message(:update, Array)).to eq('foo')
499
+ expect(@ability.unauthorized_message(:update, [1, 2, 3])).to eq('foo')
492
500
  expect(@ability.unauthorized_message(:update, :missing)).to be_nil
493
501
  end
494
502
 
495
- it "uses symbol as subject directly" do
496
- I18n.backend.store_translations :en, :unauthorized => {:has => {:cheezburger => "Nom nom nom. I eated it."}}
497
- expect(@ability.unauthorized_message(:has, :cheezburger)).to eq("Nom nom nom. I eated it.")
503
+ it 'uses symbol as subject directly' do
504
+ I18n.backend.store_translations :en, unauthorized: { has: { cheezburger: 'Nom nom nom. I eated it.' } }
505
+ expect(@ability.unauthorized_message(:has, :cheezburger)).to eq('Nom nom nom. I eated it.')
498
506
  end
499
507
 
500
508
  it "falls back to 'manage' and 'all'" do
501
- I18n.backend.store_translations :en, :unauthorized => {
502
- :manage => {:all => "manage all", :array => "manage array"},
503
- :update => {:all => "update all", :array => "update array"}
509
+ I18n.backend.store_translations :en, unauthorized: {
510
+ manage: { all: 'manage all', array: 'manage array' },
511
+ update: { all: 'update all', array: 'update array' }
504
512
  }
505
- expect(@ability.unauthorized_message(:update, Array)).to eq("update array")
506
- expect(@ability.unauthorized_message(:update, Hash)).to eq("update all")
507
- expect(@ability.unauthorized_message(:foo, Array)).to eq("manage array")
508
- expect(@ability.unauthorized_message(:foo, Hash)).to eq("manage all")
513
+ expect(@ability.unauthorized_message(:update, Array)).to eq('update array')
514
+ expect(@ability.unauthorized_message(:update, Hash)).to eq('update all')
515
+ expect(@ability.unauthorized_message(:foo, Array)).to eq('manage array')
516
+ expect(@ability.unauthorized_message(:foo, Hash)).to eq('manage all')
509
517
  end
510
518
 
511
- it "follows aliased actions" do
512
- I18n.backend.store_translations :en, :unauthorized => {:modify => {:array => "modify array"}}
513
- @ability.alias_action :update, :to => :modify
514
- expect(@ability.unauthorized_message(:update, Array)).to eq("modify array")
515
- expect(@ability.unauthorized_message(:edit, Array)).to eq("modify array")
519
+ it 'follows aliased actions' do
520
+ I18n.backend.store_translations :en, unauthorized: { modify: { array: 'modify array' } }
521
+ @ability.alias_action :update, to: :modify
522
+ expect(@ability.unauthorized_message(:update, Array)).to eq('modify array')
523
+ expect(@ability.unauthorized_message(:edit, Array)).to eq('modify array')
516
524
  end
517
525
 
518
- it "has variables for action and subject" do
519
- I18n.backend.store_translations :en, :unauthorized => {:manage => {:all => "%{action} %{subject}"}} # old syntax for now in case testing with old I18n
520
- expect(@ability.unauthorized_message(:update, Array)).to eq("update array")
521
- expect(@ability.unauthorized_message(:update, ArgumentError)).to eq("update argument error")
522
- expect(@ability.unauthorized_message(:edit, 1..3)).to eq("edit range")
526
+ it 'has variables for action and subject' do
527
+ # old syntax for now in case testing with old I18n
528
+ I18n.backend.store_translations :en, unauthorized: { manage: { all: '%{action} %{subject}' } }
529
+ expect(@ability.unauthorized_message(:update, Array)).to eq('update array')
530
+ expect(@ability.unauthorized_message(:update, ArgumentError)).to eq('update argument error')
531
+ expect(@ability.unauthorized_message(:edit, 1..3)).to eq('edit range')
523
532
  end
524
533
  end
525
534
 
526
- describe "#merge" do
527
- it "adds the rules from the given ability" do
535
+ describe '#merge' do
536
+ it 'adds the rules from the given ability' do
528
537
  @ability.can :use, :tools
529
538
  (another_ability = double).extend(CanCan::Ability)
530
539
  another_ability.can :use, :search
@@ -534,7 +543,7 @@ describe CanCan::Ability do
534
543
  expect(@ability.send(:rules).size).to eq(2)
535
544
  end
536
545
 
537
- it "can add an empty ability" do
546
+ it 'can add an empty ability' do
538
547
  (another_ability = double).extend(CanCan::Ability)
539
548
 
540
549
  @ability.merge(another_ability)