role_call 0.1.0 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ad375b91373f25bf7d1424ae82e46af3f9a689249e5d3cebd7c5703e172219f
4
- data.tar.gz: e9b5c8fcde350b7511fc21d7b49d3ca9471b8ed5c8681f6054afce87a88c514e
3
+ metadata.gz: 383223b658164ace5b6bae492ff85f5ad5cd07dad7ce04244be3c0dfd73f84b5
4
+ data.tar.gz: 6044c87799f8d888b4411addbf92e99f5e4ed5044619c5b1eec1b9339ddd09ce
5
5
  SHA512:
6
- metadata.gz: c9d2ef9d20f908256b2613763c659b0164066de3c30d823de59be0de6f2ad7ab1c1516ef100edbb85e657862616b74dcb7e2fc407ff443c4c6160bb1e244cf74
7
- data.tar.gz: d56eff26436385219c548f28112eb67327678357a7e79372d2b830f08d00d8c812af6ff303d76862b770d3a56b157e7bf724c2cc1f17d909265e8d72bbf8c1b5
6
+ metadata.gz: e6d50ed87e4601a23df929c75957d0b09580ceb1fcdf6455a06a2a5f7660e9a5af0ea72758cd573b89186db752b7366eeee5444a2b9a79f371a99c4b92d0ce60
7
+ data.tar.gz: 75d16aec5180cf8fc57ecbcc30cbcbcfca1f887314fa202b8719b5c6af7465ddfb75a416a27f94d0cbcb57bcd635bc762aaa387263c61fcb19d1b9ff943b9701
@@ -3,9 +3,13 @@
3
3
  require "active_support"
4
4
  require "active_support/core_ext/enumerable"
5
5
 
6
- require "spicerack"
6
+ require "spicery"
7
7
 
8
8
  require "role_call/version"
9
9
 
10
+ require "role_call/permission_base"
11
+ require "role_call/role_base"
12
+ require "role_call/actor"
13
+
10
14
  module RoleCall
11
15
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RoleCall
4
+ module Actor
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include ShortCircuIt
9
+
10
+ memoize :permissions
11
+ memoize :permission_classes
12
+ memoize :permissions_map
13
+ end
14
+
15
+ def permitted_to?(object)
16
+ permissions_map.key?(object.try(:key)) || permissions_map.key?(object) || permissions.include?(object)
17
+ end
18
+
19
+ def permissions
20
+ permission_classes.map(&:key).uniq
21
+ end
22
+
23
+ def roles
24
+ [ try(:role) ].compact
25
+ end
26
+
27
+ private
28
+
29
+ def permission_classes
30
+ Array.wrap(roles).map(&:permissions).flatten
31
+ end
32
+
33
+ def permissions_map
34
+ permission_classes.index_by(&:key)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "permissions/roles"
4
+
5
+ # A **Permission** are the "keys" that are accumulated across the **Roles** of an **Actor**.
6
+ module RoleCall
7
+ class PermissionBase < Spicerack::RootObject
8
+ include RoleCall::Permissions::Roles
9
+
10
+ def self.key
11
+ name.chomp("Permission").underscore.to_sym
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A **Permission** is granted to various **Roles** to authorize **Actors** to perform actions.
4
+ module RoleCall
5
+ module Permissions
6
+ module Roles
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :roles, instance_writer: false, default: []
11
+ end
12
+
13
+ class_methods do
14
+ def inherited(base)
15
+ base.roles = []
16
+ super
17
+ end
18
+
19
+ def granted_to(role)
20
+ roles << role
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "roles/permissions"
4
+
5
+ # A **Role** is authorized to take actions by virtue of having the appropriate **Permissions**.
6
+ module RoleCall
7
+ class RoleBase < Spicerack::RootObject
8
+ include RoleCall::Roles::Permissions
9
+ end
10
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A **Role** is a collection of granted **Permissions**.
4
+ module RoleCall
5
+ module Roles
6
+ module Permissions
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :permissions, instance_writer: false, default: []
11
+ delegate :unpermitted?, to: :class
12
+ end
13
+
14
+ class_methods do
15
+ def unpermitted?
16
+ permissions.blank?
17
+ end
18
+
19
+ def inherited(base)
20
+ base.permissions = permissions.dup
21
+ super
22
+ end
23
+
24
+ private
25
+
26
+ def grant(*permission_grants)
27
+ permission_grants = permission_grants.flatten.compact
28
+
29
+ ensure_valid_permissions(permission_grants)
30
+
31
+ permission_grants.each do |permission|
32
+ permissions << permission
33
+ track_permission(permission)
34
+ end
35
+ end
36
+
37
+ def track_permission(permission)
38
+ permission.granted_to(self)
39
+ end
40
+
41
+ def ensure_valid_permissions(permission_grants)
42
+ raise ArgumentError, "a permission is required" if permission_grants.empty?
43
+
44
+ invalid_permissions = permission_grants.reject { |permission| permission.respond_to?(:granted_to) }
45
+ raise ArgumentError, "invalid permissions: #{invalid_permissions.join(", ")}" if invalid_permissions.present?
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "custom_matchers/be_granted_to"
4
+ require_relative "custom_matchers/grant_permissions"
5
+ require_relative "custom_matchers/have_default_key"
6
+ require_relative "custom_matchers/have_key"
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSpec matcher that tests references of roles to permissions.
4
+ #
5
+ # class ExamplePermission < ApplicationPermission
6
+ # end
7
+ #
8
+ # class ExampleRole < ApplicationRole
9
+ # grants ExamplePermission
10
+ # end
11
+ #
12
+ # RSpec.describe ExamplePermission, type: :permission do
13
+ # it { is_expected.to be_granted_to ExampleRole }
14
+ # end
15
+
16
+ RSpec::Matchers.define :be_granted_to do |*roles|
17
+ match { expect(test_subject.roles).to include *Array.wrap(roles).flatten }
18
+ description { "include roles #{Array.wrap(roles).flatten}" }
19
+ failure_message do
20
+ "expected #{test_subject} to include roles #{Array.wrap(roles).flatten}; #{test_subject.roles}"
21
+ end
22
+ failure_message_when_negated do
23
+ "expected #{test_subject} not to include roles #{Array.wrap(roles).flatten}; #{test_subject.roles}"
24
+ end
25
+
26
+ def test_subject
27
+ subject.is_a?(Class) ? subject : subject.class
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSpec matcher that tests grants of permissions to roles.
4
+ #
5
+ # class ExamplePermission < ApplicationPermission
6
+ # end
7
+ #
8
+ # class ExampleRole < ApplicationRole
9
+ # grants ExamplePermission
10
+ # end
11
+ #
12
+ # RSpec.describe ExampleRole, type: :role do
13
+ # it { is_expected.to grant_permissions ExamplePermission }
14
+ # end
15
+
16
+ RSpec::Matchers.define :grant_permissions do |*permissions|
17
+ match { expect(test_subject.permissions).to include *Array.wrap(permissions).flatten }
18
+ description { "have permissions #{Array.wrap(permissions).flatten}" }
19
+ failure_message do
20
+ "expected #{test_subject} to have permissions #{Array.wrap(permissions).flatten}; #{test_subject.permissions}"
21
+ end
22
+ failure_message_when_negated do
23
+ "expected #{test_subject} not to have permissions #{Array.wrap(permissions).flatten}; #{test_subject.permissions}"
24
+ end
25
+
26
+ def test_subject
27
+ subject.is_a?(Class) ? subject : subject.class
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSpec matcher that tests the key of a permissions.
4
+ #
5
+ # class ExamplePermission < ApplicationPermission
6
+ # end
7
+ #
8
+ # RSpec.describe ExamplePermission, type: :permission do
9
+ # it { is_expected.to have_default_key }
10
+ # end
11
+ #
12
+
13
+ RSpec::Matchers.define :have_default_key do
14
+ match { expect(test_subject.key).to eq test_subject.name.chomp("Permission").underscore.to_sym }
15
+ description { "have default key" }
16
+ failure_message { "expected #{test_subject} to have default key but had `#{test_subject.key}' instead." }
17
+ failure_message_when_negated { "expected #{test_subject} not to have default key but did." }
18
+
19
+ def test_subject
20
+ subject.is_a?(Class) ? subject : subject.class
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSpec matcher that tests the key of a permissions.
4
+ #
5
+ # class ExamplePermission < ApplicationPermission
6
+ # def self.key
7
+ # :something_nonstandard
8
+ # end
9
+ # end
10
+ #
11
+ # RSpec.describe ExamplePermission, type: :permission do
12
+ # it { is_expected.to have_key :something_nonstandard }
13
+ # end
14
+ #
15
+
16
+ RSpec::Matchers.define :have_key do |expected_key|
17
+ match { expect(test_subject.key).to eq expected_key }
18
+ description { "have key #{expected_key}" }
19
+ failure_message do
20
+ "expected #{test_subject} to have key `#{expected_key}' but had `#{test_subject.key}' instead."
21
+ end
22
+ failure_message_when_negated { "expected #{test_subject} not to have key `#{expected_key}' but did." }
23
+
24
+ def test_subject
25
+ subject.is_a?(Class) ? subject : subject.class
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rspec/custom_matchers"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RoleCall
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
metadata CHANGED
@@ -1,36 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: role_call
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Garside
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-04 00:00:00.000000000 Z
11
+ date: 2020-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 5.2.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.2.1
27
27
  - !ruby/object:Gem::Dependency
28
- name: spicerack
28
+ name: spicery
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.17.3
33
+ version: 0.22.3.1
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
36
  version: '1.0'
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.17.3
43
+ version: 0.22.3.1
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '1.0'
@@ -58,20 +58,6 @@ dependencies:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
60
  version: 2.0.1
61
- - !ruby/object:Gem::Dependency
62
- name: faker
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '1.8'
68
- type: :development
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '1.8'
75
61
  - !ruby/object:Gem::Dependency
76
62
  name: pry-byebug
77
63
  requirement: !ruby/object:Gem::Requirement
@@ -101,54 +87,54 @@ dependencies:
101
87
  - !ruby/object:Gem::Version
102
88
  version: '10.0'
103
89
  - !ruby/object:Gem::Dependency
104
- name: rspec
90
+ name: simplecov
105
91
  requirement: !ruby/object:Gem::Requirement
106
92
  requirements:
107
93
  - - "~>"
108
94
  - !ruby/object:Gem::Version
109
- version: '3.0'
95
+ version: '0.16'
110
96
  type: :development
111
97
  prerelease: false
112
98
  version_requirements: !ruby/object:Gem::Requirement
113
99
  requirements:
114
100
  - - "~>"
115
101
  - !ruby/object:Gem::Version
116
- version: '3.0'
102
+ version: '0.16'
117
103
  - !ruby/object:Gem::Dependency
118
- name: simplecov
104
+ name: timecop
119
105
  requirement: !ruby/object:Gem::Requirement
120
106
  requirements:
121
- - - "~>"
107
+ - - ">="
122
108
  - !ruby/object:Gem::Version
123
- version: '0.16'
109
+ version: 0.9.1
124
110
  type: :development
125
111
  prerelease: false
126
112
  version_requirements: !ruby/object:Gem::Requirement
127
113
  requirements:
128
- - - "~>"
114
+ - - ">="
129
115
  - !ruby/object:Gem::Version
130
- version: '0.16'
116
+ version: 0.9.1
131
117
  - !ruby/object:Gem::Dependency
132
- name: timecop
118
+ name: shoulda-matchers
133
119
  requirement: !ruby/object:Gem::Requirement
134
120
  requirements:
135
- - - ">="
121
+ - - '='
136
122
  - !ruby/object:Gem::Version
137
- version: 0.9.1
123
+ version: 4.0.1
138
124
  type: :development
139
125
  prerelease: false
140
126
  version_requirements: !ruby/object:Gem::Requirement
141
127
  requirements:
142
- - - ">="
128
+ - - '='
143
129
  - !ruby/object:Gem::Version
144
- version: 0.9.1
130
+ version: 4.0.1
145
131
  - !ruby/object:Gem::Dependency
146
132
  name: rspice
147
133
  requirement: !ruby/object:Gem::Requirement
148
134
  requirements:
149
135
  - - ">="
150
136
  - !ruby/object:Gem::Version
151
- version: 0.17.3
137
+ version: 0.22.3.1
152
138
  - - "<"
153
139
  - !ruby/object:Gem::Version
154
140
  version: '1.0'
@@ -158,7 +144,7 @@ dependencies:
158
144
  requirements:
159
145
  - - ">="
160
146
  - !ruby/object:Gem::Version
161
- version: 0.17.3
147
+ version: 0.22.3.1
162
148
  - - "<"
163
149
  - !ruby/object:Gem::Version
164
150
  version: '1.0'
@@ -168,7 +154,7 @@ dependencies:
168
154
  requirements:
169
155
  - - ">="
170
156
  - !ruby/object:Gem::Version
171
- version: 0.17.3
157
+ version: 0.22.3.1
172
158
  - - "<"
173
159
  - !ruby/object:Gem::Version
174
160
  version: '1.0'
@@ -178,24 +164,10 @@ dependencies:
178
164
  requirements:
179
165
  - - ">="
180
166
  - !ruby/object:Gem::Version
181
- version: 0.17.3
167
+ version: 0.22.3.1
182
168
  - - "<"
183
169
  - !ruby/object:Gem::Version
184
170
  version: '1.0'
185
- - !ruby/object:Gem::Dependency
186
- name: shoulda-matchers
187
- requirement: !ruby/object:Gem::Requirement
188
- requirements:
189
- - - '='
190
- - !ruby/object:Gem::Version
191
- version: 4.0.1
192
- type: :development
193
- prerelease: false
194
- version_requirements: !ruby/object:Gem::Requirement
195
- requirements:
196
- - - '='
197
- - !ruby/object:Gem::Version
198
- version: 4.0.1
199
171
  description: Describe the roles and permissions of your system with clear, testable,
200
172
  self-documenting code
201
173
  email:
@@ -207,8 +179,19 @@ files:
207
179
  - LICENSE.txt
208
180
  - README.md
209
181
  - lib/role_call.rb
182
+ - lib/role_call/actor.rb
183
+ - lib/role_call/permission_base.rb
184
+ - lib/role_call/permissions/roles.rb
185
+ - lib/role_call/role_base.rb
186
+ - lib/role_call/roles/permissions.rb
187
+ - lib/role_call/rspec/custom_matchers.rb
188
+ - lib/role_call/rspec/custom_matchers/be_granted_to.rb
189
+ - lib/role_call/rspec/custom_matchers/grant_permissions.rb
190
+ - lib/role_call/rspec/custom_matchers/have_default_key.rb
191
+ - lib/role_call/rspec/custom_matchers/have_key.rb
192
+ - lib/role_call/spec_helper.rb
210
193
  - lib/role_call/version.rb
211
- homepage: https://www.freshly.com/
194
+ homepage: https://github.com/Freshly/role_call
212
195
  licenses:
213
196
  - MIT
214
197
  metadata: {}
@@ -227,8 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
210
  - !ruby/object:Gem::Version
228
211
  version: '0'
229
212
  requirements: []
230
- rubyforge_project:
231
- rubygems_version: 2.7.6
213
+ rubygems_version: 3.0.3
232
214
  signing_key:
233
215
  specification_version: 4
234
216
  summary: A simple and extensible approach to role-based access control management