simon_says 0.2.0 → 0.3.0.alpha.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 +4 -4
- data/README.md +25 -12
- data/lib/simon_says/roleable.rb +35 -7
- data/lib/simon_says/version.rb +1 -1
- data/test/simon_says/roleable_test.rb +23 -4
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6bf629f417e1bd66bf820ee52c333aacfe0e25a
|
4
|
+
data.tar.gz: 340919dff4421094ec54d4b75e0446b54f522a10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2f679703c9bd5fb566ee181498131d069c6ad5e3de83957cb2e8a8a3777a6c194589a399a58e4272906c1e8e89f309101ad23103f1b5e515e7d747edc0c9055
|
7
|
+
data.tar.gz: 1aae317daf655c2dcbcf425ef2eeeff492212003a4256501f72c5278239aeb8f57b861051a407d8f35af5467e8f2f10466695e9a5eeaec887c3d050c02129ef4
|
data/README.md
CHANGED
@@ -12,7 +12,7 @@ Rails that works great with devise!
|
|
12
12
|
|
13
13
|
### Installation
|
14
14
|
|
15
|
-
SimonSays can be installed via your Gemfile
|
15
|
+
SimonSays can be installed via your Gemfile.
|
16
16
|
|
17
17
|
```ruby
|
18
18
|
gem 'simon_says'
|
@@ -22,21 +22,23 @@ gem 'simon_says'
|
|
22
22
|
|
23
23
|
SimonSays consists of two parts:
|
24
24
|
|
25
|
-
1. A [Roleable](#roleable)
|
26
|
-
on User models or on join through models.
|
27
|
-
2. An [Authorizer](#authorizer)
|
28
|
-
to controllers for finding and authorizing
|
25
|
+
1. A [Roleable](#roleable) module mixin which provides a way to define
|
26
|
+
roles on User models or on join through models.
|
27
|
+
2. An [Authorizer](#authorizer) module mixin which provides a
|
28
|
+
declarative API to controllers for finding and authorizing resources.
|
29
29
|
|
30
30
|
#### Roleable
|
31
31
|
|
32
32
|
First, we need to define some roles on a model. Roles are stored as an
|
33
33
|
integer and [bitmasking](https://en.wikipedia.org/wiki/Mask_(computing))
|
34
|
-
is used to determine the roles assigned for
|
34
|
+
is used to determine the roles assigned for given record. SimonSays
|
35
35
|
provides a generator for creating a new migration for this required
|
36
36
|
attribute:
|
37
37
|
|
38
38
|
```bash
|
39
|
+
rails g model User # if and only if this model does not yet exist
|
39
40
|
rails g active_record:simon_says User
|
41
|
+
rails db:migrate
|
40
42
|
```
|
41
43
|
|
42
44
|
Now we can define some roles in our User model. For example:
|
@@ -51,14 +53,16 @@ end
|
|
51
53
|
# > User.new.roles
|
52
54
|
# => []
|
53
55
|
|
54
|
-
# > u = User.
|
55
|
-
#
|
56
|
+
# > u = User.create(roles: %i[add edit])
|
57
|
+
# => #<User ...>
|
56
58
|
# > u.roles
|
57
59
|
# => [:add, :edit]
|
58
60
|
# > u.has_add?
|
59
61
|
# => true
|
60
62
|
# > u.has_delete?
|
61
63
|
# => false
|
64
|
+
# > u.update roles: %i[delete add edit]
|
65
|
+
# > u.save # save record with roles_mask of 7
|
62
66
|
```
|
63
67
|
|
64
68
|
The attribute name can be customized by using the `:as` option as seen
|
@@ -103,11 +107,20 @@ end
|
|
103
107
|
# => [:download, :edit, :delete]
|
104
108
|
```
|
105
109
|
|
106
|
-
|
107
|
-
|
108
|
-
|
110
|
+
`Roleable` also creates two scopes that can be used to find records that
|
111
|
+
have a given set roles. Using the default attribute name, the two scopes
|
112
|
+
generated would be `with_roles` and `with_all_roles`. Both methods
|
113
|
+
accept one or more role symbols as its arguments. The first scope,
|
114
|
+
`with_roles`, will find any record with one or more the supplied roles.
|
115
|
+
The second scope, `with_all_roles` will only find record that have all
|
116
|
+
of the supplied roles.
|
117
|
+
|
118
|
+
It is useful to note the various dynamically generated methods as well
|
119
|
+
the `ROLES` constant, which is used in the Permission example. Take a
|
120
|
+
look at the `Roleable`
|
109
121
|
[source code](https://github.com/SimplyBuilt/SimonSays/blob/master/lib/simon_says/roleable.rb)
|
110
|
-
to see how
|
122
|
+
to see how methods and scopes are dynamically generated with
|
123
|
+
`has_roles`.
|
111
124
|
|
112
125
|
#### Authorizer
|
113
126
|
|
data/lib/simon_says/roleable.rb
CHANGED
@@ -71,11 +71,11 @@ module SimonSays
|
|
71
71
|
args.compact!
|
72
72
|
args.map!(&:to_sym)
|
73
73
|
|
74
|
-
self
|
74
|
+
self.#{name}_mask = (args & #{const}).map { |i| 2 ** #{const}.index(i) }.sum
|
75
75
|
end
|
76
76
|
|
77
77
|
def #{name}
|
78
|
-
#{const}.reject { |i| ((#{name}_mask || 0) & 2 ** #{const}.index(i)).zero? }
|
78
|
+
#{const}.reject { |i| ((#{name}_mask || 0) & 2 ** #{const}.index(i)).zero? }.tap(&:freeze)
|
79
79
|
end
|
80
80
|
|
81
81
|
def has_#{name}?(*args)
|
@@ -93,12 +93,40 @@ module SimonSays
|
|
93
93
|
RUBY_EVAL
|
94
94
|
end
|
95
95
|
|
96
|
-
#
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
# Try to declare ActiveRecord scopes or Sequel subsets for finding
|
97
|
+
# records with a given set of roles
|
98
|
+
|
99
|
+
scope_method = respond_to?(:scope) ? :scope : respond_to?(:subset) ? :subset : nil
|
100
|
+
|
101
|
+
if scope_method
|
102
|
+
send scope_method, "with_#{name}", ->(*args) {
|
103
|
+
clause = "#{name}_mask & ?"
|
104
|
+
values = Roleable.roles2ints(roles, *args)
|
105
|
+
|
106
|
+
query = where(clause, values.shift)
|
107
|
+
query = query.or(where(clause, values.shift)) until values.empty?
|
108
|
+
query
|
109
|
+
}
|
110
|
+
|
111
|
+
send scope_method, "with_all_#{name}", ->(*args) {
|
112
|
+
clause = "#{name}_mask & ?"
|
113
|
+
values = Roleable.roles2ints(roles, *args)
|
114
|
+
|
115
|
+
query = where(clause, values.shift)
|
116
|
+
query = query.where(clause, values.shift) until values.empty?
|
117
|
+
query
|
118
|
+
}
|
119
|
+
end
|
101
120
|
end
|
102
121
|
end
|
122
|
+
|
123
|
+
def self.roles2ints(defined_roles, *args)
|
124
|
+
values = args.map do |arg|
|
125
|
+
index = defined_roles.index(arg)
|
126
|
+
index ? 2 ** index : nil
|
127
|
+
end
|
128
|
+
|
129
|
+
values.tap(&:flatten!)
|
130
|
+
end
|
103
131
|
end
|
104
132
|
end
|
data/lib/simon_says/version.rb
CHANGED
@@ -132,15 +132,34 @@ class RoleableTest < ActiveSupport::TestCase
|
|
132
132
|
test "named scope with_roles" do
|
133
133
|
assert_equal [2, 1], [
|
134
134
|
Membership.with_roles(:download).count,
|
135
|
-
Membership.with_roles(:delete).count
|
135
|
+
Membership.with_roles(:edit, :delete).count,
|
136
136
|
]
|
137
137
|
end
|
138
138
|
|
139
139
|
test "named scope with_access" do
|
140
|
-
assert_equal [2,
|
141
|
-
Admin.with_access(:marketing).count,
|
140
|
+
assert_equal [2, 3, 4], [
|
142
141
|
Admin.with_access(:content).count,
|
143
|
-
Admin.with_access(:
|
142
|
+
Admin.with_access(:content, :marketing).count,
|
143
|
+
Admin.with_access(:content, :marketing, :support).count
|
144
|
+
]
|
145
|
+
end
|
146
|
+
|
147
|
+
test "named scope with_all_roles" do
|
148
|
+
memberships(:mb1).update roles: %i[download fork edit]
|
149
|
+
memberships(:mb2).update roles: %i[download fork]
|
150
|
+
|
151
|
+
assert_equal [2, 0], [
|
152
|
+
Membership.with_all_roles(:download, :fork).count,
|
153
|
+
Membership.with_all_roles(:download, :fork, :edit, :delete).count
|
154
|
+
]
|
155
|
+
end
|
156
|
+
|
157
|
+
test "named scope with_all_access" do
|
158
|
+
Admin.create(access: %i[content marketing])
|
159
|
+
|
160
|
+
assert_equal [2, 1], [
|
161
|
+
Admin.with_all_access(:content, :marketing).count,
|
162
|
+
Admin.with_all_access(:content, :marketing, :support).count
|
144
163
|
]
|
145
164
|
end
|
146
165
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simon_says
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0.alpha.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Coyne
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2018-10-26 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -231,9 +231,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
231
231
|
version: '0'
|
232
232
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
233
233
|
requirements:
|
234
|
-
- - "
|
234
|
+
- - ">"
|
235
235
|
- !ruby/object:Gem::Version
|
236
|
-
version:
|
236
|
+
version: 1.3.1
|
237
237
|
requirements: []
|
238
238
|
rubyforge_project:
|
239
239
|
rubygems_version: 2.6.13
|