action_policy 0.6.0 → 0.6.3

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: 0fe2b2b40f6a3bd85c312495209382b1ee72950072257e676be008e2ef8d77c5
4
- data.tar.gz: f0c9b0cb38bc130cdb8c7f3f4cfba3adcc326f25c6435fe75723e8c0d3ba3fe9
3
+ metadata.gz: 611389adf65ee131b0b5b272885fe0ba6a7066330a1e9b97d7f0b9cb8dd47530
4
+ data.tar.gz: f2f29bf49216ef6406b408935250fc845619d14657d8956d7a20a6344b8a3032
5
5
  SHA512:
6
- metadata.gz: f49f02d335942aa0a100e681f7570c1b6d042e68d1ed9d02012ec84b9f354b5c0a1d7a42ba15fbd3c84c84536e444af95057a09ef00cdc6ae3c2f5d0b24dd3a6
7
- data.tar.gz: 2eced066c406feb11e8cdf99113fa8d27f8fe73ff015bcc1d2958c0a657540d195b25a8328dee02206b8539e55d16278f531dcde6b9567fef95ec1bead92cda0
6
+ metadata.gz: 86baaf070430319da764d5287542f418a32f9b28870518bddeb6c25ad3875ea14482993c2d0d185750e1dea36ad45263182f285f893b9a44a95f29dcd734f653
7
+ data.tar.gz: 6fbb1736b962bd2b80d24ffe2ada43ced3bf4324f5d4790d6ca39f7f1c5a654bffcde93caca846c6ce49ce5a1d68a299fd050edda595cdc114bd552de83ac1d5
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.6.3 (2022-08-16)
6
+
7
+ - Fix regression for [#179](https://github.com/palkan/action_policy/issues/179). ([@palkan][])
8
+
9
+ ## 0.6.2 (2022-08-12)
10
+
11
+ - Allow omitting authorization record if `with` is provided. ([@palkan][])
12
+
13
+ ## 0.6.1 (2022-05-23)
14
+
15
+ - Fix policy lookup when a namespaced record is passed and the strict mode is used. ([@palkan][])
16
+ - Expose `#authorized_scope` as helper. ([@palkan][])
17
+ - [Fixes [#207](https://github.com/palkan/action_policy/issues/207)] refinement#include deprecation warning on Ruby 3.1
18
+
5
19
  ## 0.6.0 (2021-09-02)
6
20
 
7
21
  - Drop Ruby 2.5 support.
@@ -23,7 +23,7 @@ module ActionPolicy
23
23
  end
24
24
 
25
25
  refine Object do
26
- include ObjectExt
26
+ ::RubyNext::Core.import_methods(ObjectExt, binding)
27
27
  end
28
28
 
29
29
  refine NilClass do
@@ -86,7 +86,7 @@ module ActionPolicy
86
86
  @result = self.class.result_class.new(self.class, rule)
87
87
 
88
88
  catch :policy_fulfilled do
89
- result.load __apply__(rule)
89
+ result.load __apply__(resolve_rule(rule))
90
90
  end
91
91
 
92
92
  result.value
@@ -139,7 +139,7 @@ module ActionPolicy
139
139
  #
140
140
  # By default, rule name is equal to activity name.
141
141
  #
142
- # Raises ActionPolicy::UknownRule when rule is not found in policy.
142
+ # Raises ActionPolicy::UnknownRule when rule is not found in policy.
143
143
  def resolve_rule(activity)
144
144
  raise UnknownRule.new(self, activity) unless
145
145
  respond_to?(activity)
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_policy/testing"
4
+
5
+ module ActionPolicy
6
+ module RSpec
7
+ # Policy rule alias matcher `be_an_alias_of`.
8
+ #
9
+ # Verifies that for given policy a policy rule has an alias.
10
+ #
11
+ # Example:
12
+ #
13
+ # # in policy specs
14
+ # subject(:policy) { described_class.new(record, user: user) }
15
+ #
16
+ # let(:user) { build_stubbed(:user) }
17
+ # let(:record) { build_stubbed(:post) }
18
+ #
19
+ # describe "#show?" do
20
+ # it "is an alias of :index? policy rule" do
21
+ # expect(:show?).to be_an_alias_of(policy, :index?)
22
+ # end
23
+ # end
24
+ #
25
+ # # negated version
26
+ # describe "#show?" do
27
+ # it "is not an alias of :index? policy rule" do
28
+ # expect(:show?).to_not be_an_alias_of(policy, :index?)
29
+ # end
30
+ # end
31
+ #
32
+ class BeAnAliasOf < ::RSpec::Matchers::BuiltIn::BaseMatcher
33
+ attr_reader :policy, :rule, :actual
34
+
35
+ def initialize(policy, rule)
36
+ @policy = policy
37
+ @rule = rule
38
+ end
39
+
40
+ def match(_expected, actual)
41
+ policy.resolve_rule(actual) == rule
42
+ end
43
+
44
+ def does_not_match?(actual)
45
+ @actual = actual
46
+ policy.resolve_rule(actual) != rule
47
+ end
48
+
49
+ def supports_block_expectations?() ; false; end
50
+
51
+ def failure_message
52
+ "expected #{policy}##{actual} " \
53
+ "to be an alias of #{policy}##{rule}"
54
+ end
55
+
56
+ def failure_message_when_negated
57
+ "expected #{policy}##{actual} " \
58
+ "to not be an alias of #{policy}##{rule}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ RSpec.configure do |config|
65
+ config.include(Module.new do
66
+ def be_an_alias_of(policy, rule)
67
+ ActionPolicy::RSpec::BeAnAliasOf.new(policy, rule)
68
+ end
69
+ end)
70
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionPolicy
4
+ module Ext
5
+ # Add Module#namespace method
6
+ module ModuleNamespace # :nodoc: all
7
+ unless "".respond_to?(:safe_constantize)
8
+ require "action_policy/ext/string_constantize"
9
+ using ActionPolicy::Ext::StringConstantize
10
+ end
11
+
12
+ module Ext
13
+ def namespace
14
+ return unless name&.match?(/[^^]::/)
15
+
16
+ name.sub(/::[^:]+$/, "").safe_constantize
17
+ end
18
+ end
19
+
20
+ # See https://github.com/jruby/jruby/issues/5220
21
+ ::Module.include(Ext) if RUBY_PLATFORM.match?(/java/i)
22
+
23
+ refine Module do
24
+ if RUBY_VERSION <= "2.7.0"
25
+ include Ext
26
+ else
27
+ ::RubyNext::Core.import_methods(Ext, binding)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionPolicy
4
+ module Ext
5
+ # Adds #_policy_cache_key method to Object,
6
+ # which just call #policy_cache_key or #cache_key
7
+ # or #object_id (if `use_object_id` parameter is set to true).
8
+ #
9
+ # For other core classes returns string representation.
10
+ #
11
+ # Raises ArgumentError otherwise.
12
+ module PolicyCacheKey # :nodoc: all
13
+ module ObjectExt
14
+ def _policy_cache_key(use_object_id: false)
15
+ return policy_cache_key if respond_to?(:policy_cache_key)
16
+ return cache_key_with_version if respond_to?(:cache_key_with_version)
17
+ return cache_key if respond_to?(:cache_key)
18
+
19
+ return object_id.to_s if use_object_id == true
20
+
21
+ raise ArgumentError, "object is not cacheable"
22
+ end
23
+ end
24
+
25
+ refine Object do
26
+ ::RubyNext::Core.import_methods(ObjectExt, binding)
27
+ end
28
+
29
+ refine NilClass do
30
+ def _policy_cache_key(*) = ""
31
+ end
32
+
33
+ refine TrueClass do
34
+ def _policy_cache_key(*) = "t"
35
+ end
36
+
37
+ refine FalseClass do
38
+ def _policy_cache_key(*) = "f"
39
+ end
40
+
41
+ refine String do
42
+ def _policy_cache_key(*) = self
43
+ end
44
+
45
+ refine Symbol do
46
+ def _policy_cache_key(*) = to_s
47
+ end
48
+
49
+ if RUBY_PLATFORM.match?(/java/i)
50
+ refine Integer do
51
+ def _policy_cache_key(*) = to_s
52
+ end
53
+
54
+ refine Float do
55
+ def _policy_cache_key(*) = to_s
56
+ end
57
+ else
58
+ refine Numeric do
59
+ def _policy_cache_key(*) = to_s
60
+ end
61
+ end
62
+
63
+ refine Time do
64
+ def _policy_cache_key(*) = to_s
65
+ end
66
+
67
+ refine Module do
68
+ def _policy_cache_key(*) = name
69
+ end
70
+ end
71
+ end
72
+ end
@@ -58,10 +58,11 @@ module ActionPolicy
58
58
  end
59
59
 
60
60
  def authorization_context
61
- return @__authorization_context if
62
- instance_variable_defined?(:@__authorization_context)
61
+ @_authorization_context ||= build_authorization_context
62
+ end
63
63
 
64
- @__authorization_context = self.class.authorization_targets
64
+ private def build_authorization_context
65
+ self.class.authorization_targets
65
66
  .each_with_object({}) do |(key, meth), obj|
66
67
  obj[key] = send(meth)
67
68
  end
@@ -73,11 +74,19 @@ module ActionPolicy
73
74
  policy.resolve_rule(rule)
74
75
  end
75
76
 
76
- def lookup_authorization_policy(record, **options) # :nodoc:
77
- record = implicit_authorization_target! if :__undef__ == record # rubocop:disable Style/YodaCondition See https://github.com/palkan/action_policy/pull/180
78
- Kernel.raise ArgumentError, "Record must be specified" if record.nil?
77
+ def lookup_authorization_policy(record, with: nil, **options) # :nodoc:
78
+ if :__undef__ == record # rubocop:disable Style/YodaCondition
79
+ record =
80
+ if with
81
+ implicit_authorization_target
82
+ else
83
+ implicit_authorization_target!
84
+ end
85
+ end
86
+
87
+ Kernel.raise ArgumentError, "Record or policy must be specified" if record.nil? && with.nil?
79
88
 
80
- policy_for(record: record, **options)
89
+ policy_for(record: record, with: with, **options)
81
90
  end
82
91
 
83
92
  module ClassMethods # :nodoc:
@@ -21,7 +21,11 @@ module ActionPolicy
21
21
  ::Module.include(Ext) if RUBY_PLATFORM.match?(/java/i)
22
22
 
23
23
  refine Module do
24
- include Ext
24
+ if RUBY_VERSION <= "2.7.0"
25
+ include Ext
26
+ else
27
+ import_methods Ext
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -23,7 +23,7 @@ module ActionPolicy
23
23
  end
24
24
 
25
25
  refine Object do
26
- include ObjectExt
26
+ import_methods ObjectExt
27
27
  end
28
28
 
29
29
  refine NilClass do
@@ -67,12 +67,20 @@ module ActionPolicy
67
67
  def lookup_within_namespace(policy_name, namespace, strict: false)
68
68
  NamespaceCache.fetch(namespace&.name || "Kernel", policy_name, strict: strict) do
69
69
  mod = namespace
70
+ policy_class = nil
71
+
70
72
  loop do
71
- policy = [mod&.name, policy_name].compact.join("::").safe_constantize
72
- break policy if policy || mod.nil? || strict
73
+ policy_class = [mod&.name, policy_name].compact.join("::").safe_constantize
74
+ break policy_class if policy_class || mod.nil?
73
75
 
74
76
  mod = mod.namespace
75
77
  end
78
+
79
+ next policy_class if !strict || namespace.nil? || policy_class.nil?
80
+
81
+ # If we're in the strict mode and the namespace boundary is provided,
82
+ # we must check that the found policy satisfies it
83
+ policy_class if policy_class.name.start_with?("#{namespace.name}::")
76
84
  end
77
85
  end
78
86
 
@@ -66,7 +66,7 @@ module ActionPolicy
66
66
  allow_nil ||= optional
67
67
 
68
68
  ids.each do |id|
69
- authorization_targets[id] = {allow_nil, optional}
69
+ authorization_targets[id] = {allow_nil:, optional:}
70
70
  end
71
71
 
72
72
  attr_reader(*ids)
@@ -86,7 +86,7 @@ module ActionPolicy
86
86
  @result = self.class.result_class.new(self.class, rule)
87
87
 
88
88
  catch :policy_fulfilled do
89
- result.load __apply__(rule)
89
+ result.load __apply__(resolve_rule(rule))
90
90
  end
91
91
 
92
92
  result.value
@@ -139,7 +139,7 @@ module ActionPolicy
139
139
  #
140
140
  # By default, rule name is equal to activity name.
141
141
  #
142
- # Raises ActionPolicy::UknownRule when rule is not found in policy.
142
+ # Raises ActionPolicy::UnknownRule when rule is not found in policy.
143
143
  def resolve_rule(activity)
144
144
  raise UnknownRule.new(self, activity) unless
145
145
  respond_to?(activity)
@@ -23,7 +23,10 @@ module ActionPolicy
23
23
  include ActionPolicy::Behaviours::Namespaced
24
24
 
25
25
  included do
26
- helper_method :allowed_to? if respond_to?(:helper_method)
26
+ if respond_to?(:helper_method)
27
+ helper_method :allowed_to?
28
+ helper_method :authorized_scope
29
+ end
27
30
 
28
31
  attr_writer :authorize_count
29
32
  attr_reader :verify_authorized_skipped
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_policy/testing"
4
+
5
+ module ActionPolicy
6
+ module RSpec
7
+ # Policy rule alias matcher `be_an_alias_of`.
8
+ #
9
+ # Verifies that for given policy a policy rule has an alias.
10
+ #
11
+ # Example:
12
+ #
13
+ # # in policy specs
14
+ # subject(:policy) { described_class.new(record, user: user) }
15
+ #
16
+ # let(:user) { build_stubbed(:user) }
17
+ # let(:record) { build_stubbed(:post) }
18
+ #
19
+ # describe "#show?" do
20
+ # it "is an alias of :index? policy rule" do
21
+ # expect(:show?).to be_an_alias_of(policy, :index?)
22
+ # end
23
+ # end
24
+ #
25
+ # # negated version
26
+ # describe "#show?" do
27
+ # it "is not an alias of :index? policy rule" do
28
+ # expect(:show?).to_not be_an_alias_of(policy, :index?)
29
+ # end
30
+ # end
31
+ #
32
+ class BeAnAliasOf < ::RSpec::Matchers::BuiltIn::BaseMatcher
33
+ attr_reader :policy, :rule, :actual
34
+
35
+ def initialize(policy, rule)
36
+ @policy = policy
37
+ @rule = rule
38
+ end
39
+
40
+ def match(_expected, actual)
41
+ policy.resolve_rule(actual) == rule
42
+ end
43
+
44
+ def does_not_match?(actual)
45
+ @actual = actual
46
+ policy.resolve_rule(actual) != rule
47
+ end
48
+
49
+ def supports_block_expectations?() = false
50
+
51
+ def failure_message
52
+ "expected #{policy}##{actual} " \
53
+ "to be an alias of #{policy}##{rule}"
54
+ end
55
+
56
+ def failure_message_when_negated
57
+ "expected #{policy}##{actual} " \
58
+ "to not be an alias of #{policy}##{rule}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ RSpec.configure do |config|
65
+ config.include(Module.new do
66
+ def be_an_alias_of(policy, rule)
67
+ ActionPolicy::RSpec::BeAnAliasOf.new(policy, rule)
68
+ end
69
+ end)
70
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "action_policy/rspec/be_an_alias_of"
3
4
  require "action_policy/rspec/be_authorized_to"
4
5
  require "action_policy/rspec/have_authorized_scope"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionPolicy
4
- VERSION = "0.6.0"
4
+ VERSION = "0.6.3"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_policy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-02 00:00:00.000000000 Z
11
+ date: 2022-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.11.0
19
+ version: 0.14.0
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
- version: 0.11.0
26
+ version: 0.14.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ammeter
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -133,9 +133,6 @@ files:
133
133
  - LICENSE.txt
134
134
  - README.md
135
135
  - config/rubocop-rspec.yml
136
- - lib/.rbnext/1995.next/action_policy/behaviours/policy_for.rb
137
- - lib/.rbnext/1995.next/action_policy/behaviours/scoping.rb
138
- - lib/.rbnext/1995.next/action_policy/policy/authorization.rb
139
136
  - lib/.rbnext/1995.next/action_policy/utils/pretty_print.rb
140
137
  - lib/.rbnext/2.7/action_policy/behaviours/policy_for.rb
141
138
  - lib/.rbnext/2.7/action_policy/i18n.rb
@@ -153,10 +150,16 @@ files:
153
150
  - lib/.rbnext/3.0/action_policy/policy/execution_result.rb
154
151
  - lib/.rbnext/3.0/action_policy/policy/pre_check.rb
155
152
  - lib/.rbnext/3.0/action_policy/policy/reasons.rb
153
+ - lib/.rbnext/3.0/action_policy/rspec/be_an_alias_of.rb
156
154
  - lib/.rbnext/3.0/action_policy/rspec/be_authorized_to.rb
157
155
  - lib/.rbnext/3.0/action_policy/rspec/have_authorized_scope.rb
158
156
  - lib/.rbnext/3.0/action_policy/utils/pretty_print.rb
159
157
  - lib/.rbnext/3.0/action_policy/utils/suggest_message.rb
158
+ - lib/.rbnext/3.1/action_policy/behaviours/policy_for.rb
159
+ - lib/.rbnext/3.1/action_policy/behaviours/scoping.rb
160
+ - lib/.rbnext/3.1/action_policy/ext/module_namespace.rb
161
+ - lib/.rbnext/3.1/action_policy/ext/policy_cache_key.rb
162
+ - lib/.rbnext/3.1/action_policy/policy/authorization.rb
160
163
  - lib/action_policy.rb
161
164
  - lib/action_policy/authorizer.rb
162
165
  - lib/action_policy/base.rb
@@ -194,6 +197,7 @@ files:
194
197
  - lib/action_policy/rails/scope_matchers/active_record.rb
195
198
  - lib/action_policy/railtie.rb
196
199
  - lib/action_policy/rspec.rb
200
+ - lib/action_policy/rspec/be_an_alias_of.rb
197
201
  - lib/action_policy/rspec/be_authorized_to.rb
198
202
  - lib/action_policy/rspec/dsl.rb
199
203
  - lib/action_policy/rspec/have_authorized_scope.rb
@@ -237,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
237
241
  - !ruby/object:Gem::Version
238
242
  version: '0'
239
243
  requirements: []
240
- rubygems_version: 3.2.15
244
+ rubygems_version: 3.3.11
241
245
  signing_key:
242
246
  specification_version: 4
243
247
  summary: Authorization framework for Ruby/Rails application