accessly 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 815f41738a2e4a9ff10656b7328cfcbce68ceb41
4
- data.tar.gz: 9920d928acb62e3a3f823f28a2322cd0a8dba174
3
+ metadata.gz: 96505b522e737820634c4c02ab4c861880008a70
4
+ data.tar.gz: eee707f0a8667c4e9f383e827197f64db141412f
5
5
  SHA512:
6
- metadata.gz: 120ca23c06d76c839e22860b01483c182e32ecb6ce1f67e8377fddeb46871d70ecb6acc85a474acb3061ecc6fc7e2bc9411b0ecba71fc20811d20429c126862b
7
- data.tar.gz: ed13d76b6ee3b35bed3f3ba0b10c330511b1f0e602e25651b4b530ce153f229a1cb81d4dfe7cdaca6cecf2fadd332390fbfda99dabf304093bf8027dc57d209e
6
+ metadata.gz: 504dd75a1ce9ae60c89dd3e335de18cb7ef46e45bc2a39d67e07407d94eec0daffbeedcf70ac8a045cdb26c5be2c584c3e756cbbca46757ac9826281b3ad00dd
7
+ data.tar.gz: 511e3129de53be6bb92c8519db2dd9fc29b392851337dfb38d0104116eb7d56cd0d85f4957465bfcb15b6817e1a602225b5a42e88df56d06aecaafc65ba81ae5
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- accessly (1.0.0)
4
+ accessly (1.0.2)
5
5
  activerecord (~> 5.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -64,6 +64,18 @@ class ApplicationFeaturePolicy < Accessly::Policy::Base
64
64
  end
65
65
  ```
66
66
 
67
+ #### ACTIONS
68
+
69
+ Accessly policies rely on a definition of `actions` and/or `actions_on_objects` for effective use. This example uses `actions` which represent a "permission" that can be granted to an actor for later validation within your app's business logic.
70
+
71
+ - `actions` map a symbol to an integer value.
72
+ - An `action` value should be a unique integer within each policy.
73
+ - removing/editing `actions` and values can have negative consequences if the underlying data is not migrated
74
+
75
+ Defined policy `actions` become part of the policy API. (see examples below)
76
+
77
+ #### Policy API Example
78
+
67
79
  With this policy we can `grant` permissions to a user
68
80
 
69
81
  ```ruby
@@ -107,6 +119,18 @@ class UserPolicy < Accessly::Policy::Base
107
119
  end
108
120
  ```
109
121
 
122
+ #### ACTIONS ON OBJECTS
123
+
124
+ Accessly policies rely on a definition of `actions` and/or `actions_on_objects` for effective use. This example uses `actions_on_objects` which associate a "permission" with an object in your system. The "object" is typically an ActiveRecord object.
125
+
126
+ - `actions_on_objects` map a symbol to an integer value.
127
+ - An `actions_on_objects` value should be a unique integer within each policy.
128
+ - removing/editing `actions_on_objects` and values can have negative consequences if the underlying data is not migrated
129
+
130
+ Defined policy `actions_on_objects` become part of the policy API. (see examples below)
131
+
132
+ #### Policy API Example
133
+
110
134
  We differentiate permissions by a `namespace` which by default is the name of your policy class. However,
111
135
  it may be necessary to override the default behavior represented in the above example.
112
136
 
@@ -1,6 +1,10 @@
1
1
  module Accessly
2
2
  module Policy
3
3
  class Base
4
+ # Module that will hold our meta-programmed action methods just above
5
+ # the policy class in the inheritance hierarchy; allowing for them to
6
+ # be overridden in the policy.
7
+ ACTIONS_MODULE = :Actions
4
8
 
5
9
  attr_reader :actor
6
10
 
@@ -8,17 +12,82 @@ module Accessly
8
12
  @actor = actor
9
13
  end
10
14
 
15
+ # Meta-programs action methods from actions supplied.
16
+ # Used in policies as a DSL to declare actions.
17
+ #
18
+ # This defines the actions on the `actions_module` so that they are
19
+ # positioned higher in the inheritance tree than methods defined on the
20
+ # class itself. This will allow us to define methods that override these
21
+ # base methods and call `super`.
22
+ #
23
+ # @param actions [Hash] the actions to define on the policy
24
+ #
25
+ # @example Define Actions
26
+ #
27
+ # # This example causes the following methods to be defined:
28
+ # # some_action? : Returns true if the actor has the some_action
29
+ # # permission, false otherwise
30
+ # # flip_the_flop? : Returns true if the actor has the flip_the_flop
31
+ # # permission, false otherwise
32
+ # # create? : Returns true if the actor has the create permission, false
33
+ # # otherwise
34
+ # actions(
35
+ # some_action: 1,
36
+ # flip_the_flop: 2,
37
+ # create: 3
38
+ # )
39
+ #
40
+ # @return [Hash] actions
11
41
  def self.actions(actions)
12
42
  _actions.merge!(actions)
13
43
  actions.each do |action, action_id|
14
- _define_action_methods(action, action_id)
44
+ actions_module.module_eval do
45
+ define_method(:"#{action}?") do |*args|
46
+ _can_do_action?(action, action_id, args.first)
47
+ end
48
+ end
15
49
  end
16
50
  end
17
51
 
52
+ # Meta-programs action_on_objects methods from the actions supplied.
53
+ # Used in policies as a DSL to declare actions on objects.
54
+ # It is different from actions in that it will also define a method
55
+ # for listing all objects authorized with this action for the given
56
+ # actor and that these actions will always be associated not only with
57
+ # an actor, but with an object of the action.
58
+ #
59
+ # @param actions_on_objects [Hash] the actions on objects to define
60
+ # on the policy
61
+ #
62
+ # @example Define Actions On Objects
63
+ #
64
+ # # This example causes the following methods to be defined:
65
+ # # edit : Returns an ActiveRecord::Relation of the objects on which
66
+ # # the actor has the edit permission
67
+ # # edit?(object) : Returns true if the actor has the edit permission
68
+ # # on the given object, false otherwise
69
+ # # show : Returns an ActiveRecord::Relation of the objects on which
70
+ # # the actor has the show permission
71
+ # # show?(object) : Returns true if the actor has the show permission
72
+ # # on the given object, false otherwise
73
+ # actions_on_objects(
74
+ # edit: 1,
75
+ # show: 2
76
+ # )
77
+ #
78
+ # @return [Hash] actions_on_objects
18
79
  def self.actions_on_objects(actions_on_objects)
19
80
  _actions_on_objects.merge!(actions_on_objects)
20
81
  actions_on_objects.each do |action, action_id|
21
- _define_action_methods(action, action_id)
82
+ actions_module.module_eval do
83
+ define_method(:"#{action}?") do |*args|
84
+ _can_do_action?(action, action_id, args.first)
85
+ end
86
+
87
+ define_method(action) do |*args|
88
+ _list_for_action(action, action_id)
89
+ end
90
+ end
22
91
  end
23
92
  end
24
93
 
@@ -102,85 +171,31 @@ module Accessly
102
171
 
103
172
  private
104
173
 
105
- def _get_action_id(action, object_id = nil)
106
- if object_id.nil?
107
- _get_general_action_id!(action)
174
+ # Accessor for the actions module that will hold our meta-programmed
175
+ # methods.
176
+ # We put these methods in this module so that they are positioned
177
+ # above the policy in the inheritance chain. We can then override
178
+ # the methods in our policy as needed and call super to access the
179
+ # previous definition.
180
+ #
181
+ # @return [ACTIONS_MODULE] the module for holding actions currently
182
+ # defined on this class.
183
+ def self.actions_module
184
+ if const_defined?(ACTIONS_MODULE, _search_ancestors = false)
185
+ mod = const_get(ACTIONS_MODULE)
108
186
  else
109
- _get_action_on_object_id!(action)
187
+ mod = const_set(ACTIONS_MODULE, Module.new)
188
+ include mod
110
189
  end
111
- end
112
190
 
113
- # Determines whether the caller is trying to call an action method
114
- # in the format `action_name?`. If so, this calls that method with
115
- # the given arguments.
116
- def method_missing(method_name, *args)
117
- action_method_name = _resolve_action_method_name(method_name)
118
- if action_method_name.nil?
119
- super
120
- else
121
- send(action_method_name, *args)
122
- end
191
+ mod
123
192
  end
124
193
 
125
- # Parses an action name from a given method name of the format
126
- # `action_name?` or `action_name and returns the action method
127
- # or the list method name. If the method name does not follow
128
- # one of those formats, this assumes the caller is not calling
129
- # an action or list method and returns nil.
130
- def _resolve_action_method_name(method_name)
131
- action_method_match = /\A(\w+)(\??)\z/.match(method_name)
132
-
133
- return nil if action_method_match.nil? || action_method_match[1].nil?
134
-
135
- action_name = action_method_match[1].to_sym
136
- is_predicate = action_method_match[2] == "?"
137
-
138
- if !_action_defined?(action_name)
139
- nil
140
- elsif is_predicate
141
- _action_method_name(action_name)
194
+ def _get_action_id(action, object_id = nil)
195
+ if object_id.nil?
196
+ _get_general_action_id!(action)
142
197
  else
143
- _action_list_method_name(action_name)
144
- end
145
- end
146
-
147
- # The implementation for action methods follow the naming format
148
- # `_resolve_action_name`. This is to allow child Policies to override
149
- # the action method and still be able to call `super` when they
150
- # need to call the base implementation of the action method.
151
- def self._action_method_name(action_name)
152
- "_resolve_#{action_name}"
153
- end
154
-
155
- def _action_method_name(action_name)
156
- self.class._action_method_name(action_name)
157
- end
158
-
159
- # The implementation for list methods follow the naming format
160
- # `_list_action_name`. This is to allow child Policies to override
161
- # the list method and still be able to call `super` when they
162
- # need to call the base implementation of the lsit method.
163
- def self._action_list_method_name(action_name)
164
- "_list_#{action_name}"
165
- end
166
-
167
- def _action_list_method_name(action_name)
168
- self.class._action_list_method_name(action_name)
169
- end
170
-
171
- # Defines the action method on the Policy class for the given
172
- # action name.
173
- def self._define_action_methods(action, action_id)
174
- unless method_defined?(_action_method_name(action))
175
- define_method(_action_method_name(action)) do |*args|
176
- _can_do_action?(action, action_id, args.first)
177
- end
178
- end
179
-
180
- unless method_defined?(_action_list_method_name(action))
181
- define_method(_action_list_method_name(action)) do |*args|
182
- _list_for_action(action, action_id)
183
- end
198
+ _get_action_on_object_id!(action)
184
199
  end
185
200
  end
186
201
 
@@ -1,3 +1,3 @@
1
1
  module Accessly
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: accessly
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Milam
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2018-06-15 00:00:00.000000000 Z
13
+ date: 2018-10-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord