mongoid_ability 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +7 -0
  4. data/README.md +55 -23
  5. data/lib/cancancan/model_adapters/mongoid_adapter.rb +156 -0
  6. data/lib/cancancan/model_additions.rb +30 -0
  7. data/lib/mongoid_ability.rb +12 -12
  8. data/lib/mongoid_ability/ability.rb +67 -26
  9. data/lib/mongoid_ability/find_lock.rb +71 -0
  10. data/lib/mongoid_ability/lock.rb +25 -16
  11. data/lib/mongoid_ability/locks_decorator.rb +45 -0
  12. data/lib/mongoid_ability/owner.rb +23 -3
  13. data/lib/mongoid_ability/subject.rb +10 -22
  14. data/lib/mongoid_ability/version.rb +1 -1
  15. data/test/cancancan/model_adapters/mongoid_adapter_options_test.rb +102 -0
  16. data/test/cancancan/model_adapters/mongoid_adapter_test.rb +207 -0
  17. data/test/mongoid_ability/ability_basic_benchmark.rb +30 -0
  18. data/test/mongoid_ability/ability_basic_test.rb +44 -13
  19. data/test/mongoid_ability/ability_marshal_test.rb +17 -0
  20. data/test/mongoid_ability/ability_options_test.rb +93 -0
  21. data/test/mongoid_ability/ability_test.rb +87 -106
  22. data/test/mongoid_ability/find_lock_test.rb +67 -0
  23. data/test/mongoid_ability/lock_test.rb +32 -40
  24. data/test/mongoid_ability/owner_locks_test.rb +14 -21
  25. data/test/mongoid_ability/owner_test.rb +4 -14
  26. data/test/mongoid_ability/subject_test.rb +32 -58
  27. data/test/support/test_classes/my_lock.rb +8 -13
  28. data/test/support/test_classes/my_owner.rb +13 -15
  29. data/test/support/test_classes/my_role.rb +9 -11
  30. data/test/support/test_classes/my_subject.rb +16 -9
  31. data/test/test_helper.rb +12 -2
  32. metadata +18 -25
  33. data/lib/mongoid_ability/accessible_query_builder.rb +0 -64
  34. data/lib/mongoid_ability/resolve_default_locks.rb +0 -17
  35. data/lib/mongoid_ability/resolve_inherited_locks.rb +0 -35
  36. data/lib/mongoid_ability/resolve_locks.rb +0 -12
  37. data/lib/mongoid_ability/resolve_owner_locks.rb +0 -35
  38. data/lib/mongoid_ability/resolver.rb +0 -24
  39. data/lib/mongoid_ability/values_for_accessible_query.rb +0 -74
  40. data/test/mongoid_ability/ability_syntactic_sugar_test.rb +0 -32
  41. data/test/mongoid_ability/accessible_query_builder_test.rb +0 -119
  42. data/test/mongoid_ability/can_options_test.rb +0 -17
  43. data/test/mongoid_ability/resolve_default_locks_test.rb +0 -41
  44. data/test/mongoid_ability/resolve_inherited_locks_test.rb +0 -50
  45. data/test/mongoid_ability/resolve_owner_locks_test.rb +0 -56
  46. data/test/mongoid_ability/resolver_test.rb +0 -23
  47. data/test/mongoid_ability/subject_accessible_by_test.rb +0 -147
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+ require 'minitest/benchmark'
3
+
4
+ module MongoidAbility
5
+ describe 'basic ability Benchmark' do
6
+ let(:read_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
7
+ let(:owner) { MyRole.new(my_locks: [read_lock]) }
8
+ let(:ability) { Ability.new(owner) }
9
+
10
+ before(:all) { MySubject.default_lock MyLock, :read, true }
11
+
12
+ bench_performance_constant 'can?' do |n|
13
+ n.times do
14
+ ability.can?(:read, MySubject).must_equal false
15
+ end
16
+ end
17
+
18
+ bench_performance_constant 'cannot?' do |n|
19
+ n.times do
20
+ ability.cannot?(:read, MySubject).must_equal true
21
+ end
22
+ end
23
+
24
+ # bench_performance_constant 'accessible_by' do |n|
25
+ # n.times do
26
+ # MySubject.accessible_by(ability, :read).must_be_kind_of Mongoid::Criteria
27
+ # end
28
+ # end
29
+ end
30
+ end
@@ -2,27 +2,58 @@ require 'test_helper'
2
2
 
3
3
  module MongoidAbility
4
4
  describe 'basic ability test' do
5
- let(:read_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
6
- let(:owner) { MyRole.new(my_locks: [read_lock]) }
5
+ let(:owner) { MyRole.new }
7
6
  let(:ability) { Ability.new(owner) }
8
7
 
9
- let(:default_locks) { [MyLock.new(action: :read, outcome: true)] }
8
+ describe 'default' do
9
+ it { ability.can?(:read, MySubject).must_equal false }
10
+ it { ability.cannot?(:read, MySubject).must_equal true }
11
+ end
10
12
 
11
- it 'owner can?' do
12
- MySubject.stub :default_locks, default_locks do
13
- ability.can?(:read, MySubject).must_equal false
14
- end
13
+ describe 'class locks' do
14
+ before(:all) { MySubject.default_lock MyLock, :read, true }
15
+
16
+ it { ability.can?(:read, MySubject).must_equal true }
17
+ it { ability.cannot?(:read, MySubject).must_equal false }
15
18
  end
16
19
 
17
- it 'owner cannot?' do
18
- MySubject.stub :default_locks, default_locks do
19
- ability.cannot?(:read, MySubject).must_equal true
20
+ describe 'inherited locks' do
21
+ describe 'subject_type' do
22
+ let(:read_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
23
+ let(:my_role) { MyRole.new(my_locks: [read_lock]) }
24
+ let(:owner) { MyOwner.new(my_roles: [my_role]) }
25
+
26
+ it { ability.can?(:read, MySubject).must_equal true }
27
+ it { ability.cannot?(:read, MySubject).must_equal false }
28
+ end
29
+
30
+ describe 'subject_id' do
31
+ let(:my_subject) { MySubject.new }
32
+ let(:read_lock) { MyLock.new(subject: my_subject, action: :read, outcome: true) }
33
+ let(:my_role) { MyRole.new(my_locks: [read_lock]) }
34
+ let(:owner) { MyOwner.new(my_roles: [my_role]) }
35
+
36
+ it { ability.can?(:read, my_subject).must_equal true }
37
+ it { ability.cannot?(:read, my_subject).must_equal false }
20
38
  end
21
39
  end
22
40
 
23
- it 'is accessible by' do
24
- MySubject.stub :default_locks, default_locks do
25
- MySubject.accessible_by(ability, :read).must_be_kind_of Mongoid::Criteria
41
+ describe 'owner locks' do
42
+ describe 'subject_type' do
43
+ let(:read_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
44
+ let(:owner) { MyOwner.new(my_locks: [read_lock]) }
45
+
46
+ it { ability.can?(:read, MySubject).must_equal true }
47
+ it { ability.cannot?(:read, MySubject).must_equal false }
48
+ end
49
+
50
+ describe 'subject_id' do
51
+ let(:my_subject) { MySubject.new }
52
+ let(:read_lock) { MyLock.new(subject: my_subject, action: :read, outcome: true) }
53
+ let(:owner) { MyOwner.new(my_locks: [read_lock]) }
54
+
55
+ it { ability.can?(:read, my_subject).must_equal true }
56
+ it { ability.cannot?(:read, my_subject).must_equal false }
26
57
  end
27
58
  end
28
59
  end
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ module MongoidAbility
4
+ describe 'marshal' do
5
+ before(:all) { MySubject.default_lock MyLock, :read, true }
6
+
7
+ let(:read_lock) { MyLock.new(subject_type: MySubject1, action: :read, outcome: false) }
8
+ let(:owner) { MyRole.new(my_locks: [read_lock]) }
9
+ let(:ability) { Ability.new(owner) }
10
+
11
+ let(:ability_dump) { Marshal.dump(ability) }
12
+ let(:ability_load) { Marshal.load(ability_dump) }
13
+
14
+ it { ability_dump.must_be :present? }
15
+ it { ability_load.send(:rules).count.must_equal 2 }
16
+ end
17
+ end
@@ -0,0 +1,93 @@
1
+ require 'test_helper'
2
+
3
+ module MongoidAbility
4
+ describe 'options test' do
5
+ let(:owner) { MyOwner.new }
6
+ let(:ability) { Ability.new(owner) }
7
+ let(:subject1) { MySubject.new }
8
+
9
+ describe 'Boolean' do
10
+ let(:subject2) { MySubject.new(override: true) }
11
+
12
+ describe 'positive' do
13
+ before(:all) { MySubject.default_lock MyLock, :read, true, override: true }
14
+
15
+ it { ability.can?(:read, subject1).must_equal false }
16
+ it { ability.can?(:read, subject2).must_equal true }
17
+ end
18
+
19
+ describe 'negative' do
20
+ before(:all) do
21
+ MySubject.default_lock MyLock, :read, true
22
+ MySubject.default_lock MyLock, :read, false, override: true
23
+ end
24
+
25
+ it { ability.can?(:read, subject1).must_equal true }
26
+ it { ability.can?(:read, subject2).must_equal false }
27
+ end
28
+ end
29
+
30
+ describe 'String' do
31
+ let(:subject2) { MySubject.new(str_val: "Jan Tschichold") }
32
+
33
+ describe 'positive' do
34
+ before(:all) { MySubject.default_lock MyLock, :read, true, str_val: 'Jan Tschichold' }
35
+
36
+ it { ability.can?(:read, subject1).must_equal false }
37
+ it { ability.can?(:read, subject2).must_equal true }
38
+ end
39
+
40
+ describe 'negative' do
41
+ before(:all) do
42
+ MySubject.default_lock MyLock, :read, true
43
+ MySubject.default_lock MyLock, :read, false, str_val: 'Jan Tschichold'
44
+ end
45
+
46
+ it { ability.can?(:read, subject1).must_equal true }
47
+ it { ability.can?(:read, subject2).must_equal false }
48
+ end
49
+ end
50
+
51
+ describe 'Regexp' do
52
+ let(:subject2) { MySubject.new(str_val: "Jan Tschichold") }
53
+
54
+ describe 'positive' do
55
+ before(:all) { MySubject.default_lock MyLock, :read, true, str_val: /tschichold/i }
56
+
57
+ it { ability.can?(:read, subject1).must_equal false }
58
+ it { ability.can?(:read, subject2).must_equal true }
59
+ end
60
+
61
+ describe 'negative' do
62
+ before(:all) do
63
+ MySubject.default_lock MyLock, :read, true
64
+ MySubject.default_lock MyLock, :read, false, str_val: /tschichold/i
65
+ end
66
+
67
+ it { ability.can?(:read, subject1).must_equal true }
68
+ it { ability.can?(:read, subject2).must_equal false }
69
+ end
70
+ end
71
+
72
+ describe 'Array' do
73
+ let(:subject2) { MySubject.new(str_val: "John") }
74
+
75
+ describe 'positive' do
76
+ before(:all) { MySubject.default_lock MyLock, :read, true, str_val: %w(John Paul George Ringo) }
77
+
78
+ it { ability.can?(:read, subject1).must_equal false }
79
+ it { ability.can?(:read, subject2).must_equal true }
80
+ end
81
+
82
+ describe 'negative' do
83
+ before(:all) do
84
+ MySubject.default_lock MyLock, :read, true
85
+ MySubject.default_lock MyLock, :read, false, str_val: %w(John Paul George Ringo)
86
+ end
87
+
88
+ it { ability.can?(:read, subject1).must_equal true }
89
+ it { ability.can?(:read, subject2).must_equal false }
90
+ end
91
+ end
92
+ end
93
+ end
@@ -5,63 +5,44 @@ module MongoidAbility
5
5
  let(:owner) { MyOwner.new }
6
6
  let(:ability) { Ability.new(owner) }
7
7
 
8
- let(:my_subject_default_locks) { [] }
9
- let(:my_subject_1_default_locks) { [] }
10
- let(:my_subject_2_default_locks) { [] }
11
-
12
8
  it 'exposes owner' do
13
9
  ability.owner.must_equal owner
14
10
  end
15
11
 
16
12
  describe 'default locks' do
17
- # NOTE: we might need to use the .default_lock macro in case we propagate down directly
18
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: true)] }
13
+ before(:all) { MySubject.default_lock MyLock, :update, true }
14
+ after(:all) { [MySubject, MySubject1, MySubject2, MySubject11, MySubject21].each(&:reset_default_locks!) }
19
15
 
20
16
  it 'propagates from superclass to all subclasses' do
21
- MySubject.stub :default_locks, my_subject_default_locks do
22
- MySubject1.stub :default_locks, my_subject_1_default_locks do
23
- MySubject2.stub :default_locks, my_subject_2_default_locks do
24
- ability.can?(:update, MySubject).must_equal true
25
- ability.can?(:update, MySubject1).must_equal true
26
- ability.can?(:update, MySubject2).must_equal true
27
- end
28
- end
29
- end
17
+ ability.can?(:update, MySubject).must_equal true
18
+ ability.can?(:update, MySubject1).must_equal true
19
+ ability.can?(:update, MySubject2).must_equal true
30
20
  end
31
21
  end
32
22
 
33
23
  describe 'when defined for all superclasses' do
34
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
35
- let(:my_subject_1_default_locks) { [MyLock.new(subject_type: MySubject1, action: :read, outcome: true)] }
36
- let(:my_subject_2_default_locks) { [MyLock.new(subject_type: MySubject2, action: :read, outcome: false)] }
37
-
38
- it 'respects the definitions' do
39
- MySubject.stub :default_locks, my_subject_default_locks do
40
- MySubject1.stub :default_locks, my_subject_1_default_locks do
41
- MySubject2.stub :default_locks, my_subject_2_default_locks do
42
- ability.can?(:read, MySubject).must_equal false
43
- ability.can?(:read, MySubject1).must_equal true
44
- ability.can?(:read, MySubject2).must_equal false
45
- end
46
- end
47
- end
24
+ before(:all) do
25
+ MySubject.default_lock MyLock, :read, false
26
+ MySubject1.default_lock MyLock, :read, true
27
+ MySubject2.default_lock MyLock, :read, false
48
28
  end
29
+
30
+ it { ability.can?(:read, MySubject).must_equal false }
31
+ it { ability.can?(:read, MySubject1).must_equal true }
32
+ it { ability.can?(:read, MySubject2).must_equal false }
49
33
  end
50
34
 
51
35
  describe 'when defined for some superclasses' do
52
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
53
- let(:my_subject_2_default_locks) { [MyLock.new(subject_type: MySubject2, action: :read, outcome: true)] }
36
+ before(:all) do
37
+ MySubject.default_lock MyLock, :read, false
38
+ MySubject1.reset_default_locks!
39
+ MySubject2.default_lock MyLock, :read, true
40
+ end
54
41
 
55
42
  it 'propagates default locks to subclasses' do
56
- MySubject.stub :default_locks, my_subject_default_locks do
57
- MySubject1.stub :default_locks, my_subject_1_default_locks do
58
- MySubject2.stub :default_locks, my_subject_2_default_locks do
59
- ability.can?(:read, MySubject).must_equal false
60
- ability.can?(:read, MySubject1).must_equal false
61
- ability.can?(:read, MySubject2).must_equal true
62
- end
63
- end
64
- end
43
+ ability.can?(:read, MySubject).must_equal false
44
+ ability.can?(:read, MySubject1).must_equal false
45
+ ability.can?(:read, MySubject2).must_equal true
65
46
  end
66
47
  end
67
48
 
@@ -69,21 +50,10 @@ module MongoidAbility
69
50
 
70
51
  describe 'user locks' do
71
52
  describe 'when defined for superclass' do
72
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
53
+ let(:owner) { MyOwner.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: true)]) }
54
+ before(:all) { MySubject.default_lock MyLock, :read, false }
73
55
 
74
- before do
75
- owner.my_locks = [MyLock.new(subject_type: MySubject, action: :read, outcome: true)]
76
- end
77
-
78
- it 'applies the superclass lock' do
79
- MySubject.stub :default_locks, my_subject_default_locks do
80
- MySubject1.stub :default_locks, my_subject_1_default_locks do
81
- MySubject2.stub :default_locks, my_subject_2_default_locks do
82
- ability.can?(:read, MySubject2).must_equal true
83
- end
84
- end
85
- end
86
- end
56
+ it { ability.can?(:read, MySubject2).must_equal true }
87
57
  end
88
58
  end
89
59
 
@@ -91,42 +61,28 @@ module MongoidAbility
91
61
 
92
62
  describe 'inherited owner locks' do
93
63
  describe 'when multiple inherited owners' do
94
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
95
-
96
- before do
97
- owner.my_roles = [
64
+ let(:owner) do
65
+ MyOwner.new(my_roles: [
98
66
  MyRole.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: true)]),
99
- MyRole.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: false)])
100
- ]
67
+ MyRole.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: false)]),
68
+ ])
101
69
  end
102
70
 
103
- it 'prefers positive outcome' do
104
- MySubject.stub :default_locks, my_subject_default_locks do
105
- MySubject1.stub :default_locks, my_subject_1_default_locks do
106
- MySubject2.stub :default_locks, my_subject_2_default_locks do
107
- ability.can?(:read, MySubject).must_equal true
108
- end
109
- end
110
- end
111
- end
71
+ before(:all) { MySubject.default_lock MyLock, :read, false }
72
+
73
+ it { ability.can?(:read, MySubject).must_equal true }
112
74
  end
113
75
 
114
76
  describe 'when defined for superclass' do
115
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
116
-
117
- before do
118
- owner.my_roles = [MyRole.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: true)])]
77
+ let(:owner) do
78
+ MyOwner.new(my_roles: [
79
+ MyRole.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: true)])
80
+ ])
119
81
  end
120
82
 
121
- it 'applies the superclass lock' do
122
- MySubject.stub :default_locks, my_subject_default_locks do
123
- MySubject1.stub :default_locks, my_subject_1_default_locks do
124
- MySubject2.stub :default_locks, my_subject_2_default_locks do
125
- ability.can?(:read, MySubject2).must_equal true
126
- end
127
- end
128
- end
129
- end
83
+ before(:all) { MySubject.default_lock MyLock, :read, false }
84
+
85
+ it { ability.can?(:read, MySubject2).must_equal true }
130
86
  end
131
87
  end
132
88
 
@@ -134,40 +90,65 @@ module MongoidAbility
134
90
 
135
91
  describe 'combined locks' do
136
92
  describe 'user and role locks' do
137
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
93
+ let(:role_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
94
+ let(:owner_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
138
95
 
139
- before do
140
- owner.my_locks = [MyLock.new(subject_type: MySubject, action: :read, outcome: false)]
141
- owner.my_roles = [MyRole.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: true)])]
142
- end
96
+ let(:role) { MyRole.new(my_locks: [role_lock]) }
97
+ let(:owner) { MyOwner.new(my_locks: [owner_lock], my_roles: [role]) }
143
98
 
144
- it 'prefers user locks' do
145
- MySubject.stub :default_locks, my_subject_default_locks do
146
- MySubject1.stub :default_locks, my_subject_1_default_locks do
147
- MySubject2.stub :default_locks, my_subject_2_default_locks do
148
- ability.can?(:read, MySubject).must_equal false
149
- end
150
- end
151
- end
152
- end
99
+ before(:all) { MySubject.default_lock MyLock, :read, false }
100
+
101
+ it { ability.can?(:read, MySubject).must_equal false }
153
102
  end
154
103
 
155
104
  describe 'roles and default locks' do
156
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
105
+ describe 'negative positive' do
106
+ before(:all) { MySubject.default_lock MyLock, :read, false }
107
+
108
+ let(:lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
109
+ let(:role) { MyRole.new(my_locks: [lock]) }
110
+ let(:owner) { MyOwner.new(my_roles: [role]) }
111
+
112
+ it { ability.can?(:read, MySubject).must_equal true }
157
113
 
158
- before do
159
- owner.my_roles = [MyRole.new(my_locks: [MyLock.new(subject_type: MySubject, action: :read, outcome: true)])]
114
+ describe 'subclass' do
115
+ let(:lock) { MyLock.new(subject_type: MySubject1, action: :read, outcome: true) }
116
+
117
+ it { ability.can?(:read, MySubject).must_equal false }
118
+ it { ability.can?(:read, MySubject1).must_equal true }
119
+ end
160
120
  end
161
121
 
162
- it 'prefers role locks' do
163
- MySubject.stub :default_locks, my_subject_default_locks do
164
- MySubject1.stub :default_locks, my_subject_1_default_locks do
165
- MySubject2.stub :default_locks, my_subject_2_default_locks do
166
- ability.can?(:read, MySubject).must_equal true
167
- end
168
- end
122
+ describe 'positive negative' do
123
+ before(:all) { MySubject.default_lock MyLock, :read, true }
124
+
125
+ let(:lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
126
+ let(:role) { MyRole.new(my_locks: [lock]) }
127
+ let(:owner) { MyOwner.new(my_roles: [role]) }
128
+
129
+ it { ability.can?(:read, MySubject).must_equal false }
130
+
131
+ describe 'subclass' do
132
+ let(:lock) { MyLock.new(subject_type: MySubject1, action: :read, outcome: false) }
133
+
134
+ it { ability.can?(:read, MySubject).must_equal true }
135
+ it { ability.can?(:read, MySubject1).must_equal false }
169
136
  end
170
137
  end
138
+
139
+ describe 'positive negative positive' do
140
+ before(:all) do
141
+ MySubject.default_lock MyLock, :read, true
142
+ MySubject1.default_lock MyLock, :read, false
143
+ end
144
+
145
+ let(:lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
146
+ let(:role) { MyRole.new(my_locks: [lock]) }
147
+ let(:owner) { MyOwner.new(my_roles: [role]) }
148
+
149
+ it { ability.can?(:read, MySubject).must_equal true }
150
+ it { ability.can?(:read, MySubject1).must_equal false }
151
+ end
171
152
  end
172
153
  end
173
154
  end