ii_policy 1.1.0 → 2.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62f7efd3ac2e7db1c4c9532e987e3ed592083cec2e00f5cca700c5c5a5bab4e6
4
- data.tar.gz: e6df72f0fae98ff640ff6f87bc8bf3a1297c4470c64c45e5449b9ab439c96bdc
3
+ metadata.gz: c7b1c0f55a4109c53a364e8350cfd853609f69b4748779b5eecf15ea79d63e98
4
+ data.tar.gz: dd71c867fba51c0b26aff0cf4746eda351e74437117475951ce6c0cacc81da8d
5
5
  SHA512:
6
- metadata.gz: 928646d051e6296eff7dcb3330f8080c36fba6949ffd706165e598f8849d1cf5d6084a4eaf15daab013f289783087a1406c3417c6fb096c963ffd858e4f0c8dc
7
- data.tar.gz: e21fbbf89718aa908b42acd332b85178cfe7ab8ca9c5b11525b1c0454f6475df77820e4604bc3c275f46359ac32ac9d800107444973b95bc785593d72a6d37a2
6
+ metadata.gz: 7e8cb50a214fdbc7a130c526ebdd4f24839d2539ab8be1a6a38cbc1b6d855ffcfd70aa058ddfd758af3d48d4e8a932eb494249e2ba975f5fe1beb7f6a7bf9423
7
+ data.tar.gz: 1f267e1d1ecd857bfd440934a047afad89667cc221cf5d89afba1d65971011e0f946fc9754b53c1c372f8e7e9afb3bf18f355946863ec5fe118c8959f3b2dada
@@ -4,27 +4,41 @@ on: [push, pull_request]
4
4
 
5
5
  jobs:
6
6
  test:
7
- runs-on: ubuntu-18.04
7
+ runs-on: ubuntu-20.04
8
8
  strategy:
9
9
  fail-fast: false
10
10
  matrix:
11
- ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0]
12
- gemfile: ['rails50', 'rails51', 'rails52', 'rails60', 'rails61']
11
+ ruby: [2.3, 2.4, 2.5, 2.6, 2.7, '3.0', 3.1]
12
+ gemfile: ['rails50', 'rails51', 'rails52', 'rails60', 'rails61', 'rails70']
13
13
  exclude:
14
14
  - ruby: 2.3
15
15
  gemfile: rails60
16
16
  - ruby: 2.3
17
17
  gemfile: rails61
18
+ - ruby: 2.3
19
+ gemfile: rails70
18
20
  - ruby: 2.4
19
21
  gemfile: rails60
20
22
  - ruby: 2.4
21
23
  gemfile: rails61
24
+ - ruby: 2.4
25
+ gemfile: rails70
26
+ - ruby: 2.5
27
+ gemfile: rails70
28
+ - ruby: 2.6
29
+ gemfile: rails70
22
30
  - ruby: 3.0
23
31
  gemfile: rails50
24
32
  - ruby: 3.0
25
33
  gemfile: rails51
26
34
  - ruby: 3.0
27
35
  gemfile: rails52
36
+ - ruby: 3.1
37
+ gemfile: rails50
38
+ - ruby: 3.1
39
+ gemfile: rails51
40
+ - ruby: 3.1
41
+ gemfile: rails52
28
42
 
29
43
  name: ruby ${{ matrix.ruby }}, ${{ matrix.gemfile }}
30
44
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.2.0
4
+
5
+ * Use coactive 0.3.
6
+
7
+ ## 2.1.0
8
+
9
+ * Add traversal config.
10
+ * Add callbacks for `call_all`.
11
+ * Add calling instrumentation.
12
+ * Clear class cache when reloaded.
13
+ * Bump coactive version to 0.2.
14
+
15
+ ## 2.0.0
16
+
17
+ * Replace chain feature with coactive.
18
+
3
19
  ## 1.1.0
4
20
 
5
21
  * Support method and block for `chain`.
data/README.md CHANGED
@@ -175,9 +175,9 @@ class ItemPolicy < IIPolicy::Base
175
175
  end
176
176
  ```
177
177
 
178
- #### Policy chain
178
+ #### Coactors
179
179
 
180
- You can chain shared policies to base policy by using `chain` as follows:
180
+ You can define multiple coactors by using `coact` as follows:
181
181
 
182
182
  ```ruby
183
183
  # shared policy
@@ -189,7 +189,7 @@ end
189
189
 
190
190
  # base policy
191
191
  class ItemPolicy < IIPolicy::Base
192
- chain SharedPolicy
192
+ coact SharedPolicy
193
193
 
194
194
  def show?
195
195
  @item.status != 'deleted'
@@ -203,22 +203,7 @@ policy.allowed(:show?)
203
203
 
204
204
  In this example, `policy.allowed(:show?)` is evaluated by `SharedPolicy#show? && ItemPolicy#show?`.
205
205
 
206
- You can also use method or block to find policy class dynamically:
207
-
208
- ```ruby
209
- class ItemPolicy < IIPolicy::Base
210
- chain -> { SharedPolicy }
211
- end
212
-
213
- class ItemPolicy < IIPolicy::Base
214
- chain :chain_policy
215
-
216
- def chain_policy
217
- SharedPolicy
218
- end
219
- end
220
- ```
221
-
206
+ See [coactive](https://github.com/kanety/coactive) for more `coact` examples:
222
207
 
223
208
  ### Lookup for policy
224
209
 
@@ -277,7 +262,9 @@ IIPolicy::LogSubscriber.attach_to :ii_policy
277
262
  This subscriber will write logs in debug mode as the following example:
278
263
 
279
264
  ```
280
- Called ItemPolicy#index? for Item#1 and return true (Duration: 0.1ms, Allocations: 9)
265
+ Calling ItemPolicy#index? with #<IIPolicy::Context ...>
266
+ ...
267
+ Called ItemPolicy#index? and return true (Duration: 0.1ms, Allocations: 9)
281
268
  ```
282
269
 
283
270
  ## Contributing
data/bin/console CHANGED
@@ -10,5 +10,5 @@ require "ii_policy"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- # require "irb"
14
- # IRB.start
13
+ require "irb"
14
+ IRB.start
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem "rails", "~> 6.0.0"
4
+ gem "psych", "~> 3.3.0"
4
5
 
5
6
  gemspec path: "../"
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "rails", "~> 7.0.1"
4
+
5
+ gemspec path: "../"
data/ii_policy.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_dependency "activesupport", ">= 5.0"
21
+ spec.add_dependency "coactive", ">= 0.3"
21
22
 
22
23
  spec.add_development_dependency "rails", ">= 5.0"
23
24
  spec.add_development_dependency "sqlite3"
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'context'
4
3
  require_relative 'core'
5
4
  require_relative 'callbacks'
6
5
  require_relative 'instrumentation'
7
6
  require_relative 'lookup'
8
- require_relative 'chain'
7
+ require_relative 'context'
8
+ require_relative 'contextualizer'
9
+ require_relative 'coactors'
9
10
 
10
11
  module IIPolicy
11
12
  class Base
@@ -13,6 +14,7 @@ module IIPolicy
13
14
  include Callbacks
14
15
  include Instrumentation
15
16
  include Lookup
16
- include Chain
17
+ include Contextualizer
18
+ include Coactors
17
19
  end
18
20
  end
@@ -6,16 +6,35 @@ module IIPolicy
6
6
  include ActiveSupport::Callbacks
7
7
 
8
8
  included do
9
+ define_callbacks :all
9
10
  define_callbacks :call
10
11
  end
11
12
 
13
+ def call_all(action)
14
+ run_callbacks :all do
15
+ super
16
+ end
17
+ end
18
+
12
19
  def call(action)
13
- run_callbacks(:call) do
20
+ run_callbacks :call do
14
21
  super
15
22
  end
16
23
  end
17
24
 
18
25
  class_methods do
26
+ def before_all(*args, &block)
27
+ set_callback(:all, :before, *args, &block)
28
+ end
29
+
30
+ def after_all(*args, &block)
31
+ set_callback(:all, :after, *args, &block)
32
+ end
33
+
34
+ def around_all(*args, &block)
35
+ set_callback(:all, :around, *args, &block)
36
+ end
37
+
19
38
  def before_call(*args, &block)
20
39
  set_callback(:call, :before, *args, &block)
21
40
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IIPolicy
4
+ module Coactors
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include Coactive::Base
9
+
10
+ configure_coactive do |config|
11
+ config.load_paths = ['app/policies']
12
+ config.class_suffix = 'Policy'
13
+ config.use_cache = true
14
+ config.lookup_superclass_until = ['ActiveRecord::Base', 'ActiveModel::Base']
15
+ end
16
+
17
+ class << self
18
+ alias_method :chain, :coact
19
+ end
20
+ end
21
+ end
22
+ end
@@ -5,7 +5,8 @@ module IIPolicy
5
5
  class_attribute :data
6
6
 
7
7
  self.data = {
8
- lookup_cache: true
8
+ lookup_cache: true,
9
+ traversal: :postorder
9
10
  }
10
11
 
11
12
  data.keys.each do |key|
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IIPolicy
4
- class Context < OpenStruct
4
+ class Context < Coactive::Context
5
5
  end
6
6
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IIPolicy
4
+ module Contextualizer
5
+ extend ActiveSupport::Concern
6
+ include Coactive::Contextualizer
7
+
8
+ def call(action)
9
+ contextualize do
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
@@ -20,7 +20,7 @@ module IIPolicy
20
20
 
21
21
  def authorize(item, context = {})
22
22
  instance = policy(item, context)
23
- raise IIPolicy::AuthorizationError.new('Not Authorized') unless instance.call("#{action_name}?")
23
+ raise IIPolicy::AuthorizationError.new('Not Authorized') unless instance.allowed("#{action_name}?")
24
24
  instance
25
25
  end
26
26
  end
@@ -3,19 +3,35 @@
3
3
  module IIPolicy
4
4
  module Core
5
5
  extend ActiveSupport::Concern
6
+ include Coactive::Initializer
6
7
 
7
8
  included do
8
- attr_reader :context, :user, :item, :_result
9
+ self.context_class = IIPolicy::Context
10
+ context :user, :item
11
+ attr_reader :_result
9
12
  end
10
13
 
11
- def initialize(context = {})
12
- @context = if context.is_a?(IIPolicy::Context)
13
- context
14
- else
15
- IIPolicy::Context.new(context)
14
+ def initialize(args = {})
15
+ super
16
+ end
17
+
18
+ def call_all(action)
19
+ planned = case IIPolicy.config.traversal
20
+ when :preorder
21
+ [self] + coactors
22
+ when :postorder
23
+ coactors + [self]
24
+ when :inorder
25
+ planned = coactors.in_groups(2, false)
26
+ planned[0] + [self] + planned[1]
16
27
  end
17
- @item = @context.item
18
- @user = @context.user
28
+
29
+ planned.each do |policy|
30
+ result = policy == self ? call(action) : policy.new(@context).call_all(action)
31
+ return false unless result
32
+ end
33
+
34
+ return true
19
35
  end
20
36
 
21
37
  def call(action)
@@ -27,12 +43,11 @@ module IIPolicy
27
43
  end
28
44
 
29
45
  def allowed(action)
30
- call(action)
46
+ call_all(action)
31
47
  end
32
48
 
33
49
  def policy(item)
34
- context = @context.dup
35
- context.item = item
50
+ context = self.class.context_class.new(@context.to_h.dup.merge(item: item))
36
51
  self.class.lookup(item).new(context)
37
52
  end
38
53
  end
@@ -4,6 +4,11 @@ module IIPolicy
4
4
  module Instrumentation
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ def call_all(action)
8
+ ActiveSupport::Notifications.instrument 'calling.ii_policy', policy: self, action: action
9
+ super
10
+ end
11
+
7
12
  def call(action)
8
13
  ActiveSupport::Notifications.instrument 'call.ii_policy', policy: self, action: action do
9
14
  super
@@ -2,15 +2,24 @@
2
2
 
3
3
  module IIPolicy
4
4
  class LogSubscriber < ActiveSupport::LogSubscriber
5
+ def calling(event)
6
+ debug do
7
+ policy = event.payload[:policy]
8
+ action = event.payload[:action]
9
+ "Calling #{policy.class}##{action} with #{policy.context}"
10
+ end
11
+ end
12
+
5
13
  def call(event)
6
14
  debug do
7
15
  policy = event.payload[:policy]
8
16
  action = event.payload[:action]
9
- item = " for #{policy.item.class}##{policy.item.id}" if policy.item
10
- "Called #{policy.class}##{action}#{item} and return #{policy._result} (#{additional_log(event)})"
17
+ "Called #{policy.class}##{action} and return #{policy._result} (#{additional_log(event)})"
11
18
  end
12
19
  end
13
20
 
21
+ private
22
+
14
23
  def additional_log(event)
15
24
  additions = ["Duration: %.1fms" % event.duration]
16
25
  additions << "Allocations: %d" % event.allocations if event.respond_to?(:allocations)
@@ -9,5 +9,9 @@ module IIPolicy
9
9
  ActiveSupport.on_load :action_view do
10
10
  ActionView::Base.send :include, IIPolicy::Helper
11
11
  end
12
+
13
+ ActiveSupport::Reloader.to_prepare do
14
+ IIPolicy::Lookup.cache.clear
15
+ end
12
16
  end
13
17
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IIPolicy
4
- VERSION = '1.1.0'
4
+ VERSION = '2.2.0'
5
5
  end
data/lib/ii_policy.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'active_support'
2
+ require 'coactive'
2
3
 
3
4
  require 'ii_policy/version'
4
5
  require 'ii_policy/config'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ii_policy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoshikazu Kaneta
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-19 00:00:00.000000000 Z
11
+ date: 2022-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coactive
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rails
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -116,13 +130,15 @@ files:
116
130
  - gemfiles/rails52.gemfile
117
131
  - gemfiles/rails60.gemfile
118
132
  - gemfiles/rails61.gemfile
133
+ - gemfiles/rails70.gemfile
119
134
  - ii_policy.gemspec
120
135
  - lib/ii_policy.rb
121
136
  - lib/ii_policy/base.rb
122
137
  - lib/ii_policy/callbacks.rb
123
- - lib/ii_policy/chain.rb
138
+ - lib/ii_policy/coactors.rb
124
139
  - lib/ii_policy/config.rb
125
140
  - lib/ii_policy/context.rb
141
+ - lib/ii_policy/contextualizer.rb
126
142
  - lib/ii_policy/controller.rb
127
143
  - lib/ii_policy/core.rb
128
144
  - lib/ii_policy/errors.rb
@@ -150,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
166
  - !ruby/object:Gem::Version
151
167
  version: '0'
152
168
  requirements: []
153
- rubygems_version: 3.1.2
169
+ rubygems_version: 3.3.3
154
170
  signing_key:
155
171
  specification_version: 4
156
172
  summary: A base policy to support management of authorization logic
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IIPolicy
4
- module Chain
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- class_attribute :_chains
9
- self._chains = []
10
- end
11
-
12
- def call(action)
13
- lookup.each do |policy|
14
- return false unless policy.new(@context).call(action)
15
- end
16
- super
17
- end
18
-
19
- def lookup
20
- self.class._chains.map do |policy|
21
- if policy.is_a?(Symbol) && respond_to?(policy, true)
22
- send(policy)
23
- elsif policy.is_a?(Proc)
24
- instance_exec(&policy)
25
- else
26
- policy
27
- end
28
- end.flatten.compact
29
- end
30
-
31
- class_methods do
32
- def chain(*policies, &block)
33
- self._chains = _chains + policies
34
- self._chains << block if block
35
- end
36
- end
37
- end
38
- end