mongoid_ability 1.0.0 → 2.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.
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