ii_policy 1.1.0 → 2.2.0

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
  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