action_policy 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +203 -174
  3. data/README.md +5 -4
  4. data/lib/action_policy.rb +7 -1
  5. data/lib/action_policy/behaviour.rb +22 -16
  6. data/lib/action_policy/behaviours/policy_for.rb +10 -3
  7. data/lib/action_policy/behaviours/scoping.rb +2 -1
  8. data/lib/action_policy/behaviours/thread_memoized.rb +1 -3
  9. data/lib/action_policy/ext/module_namespace.rb +1 -6
  10. data/lib/action_policy/ext/policy_cache_key.rb +10 -30
  11. data/lib/action_policy/i18n.rb +1 -1
  12. data/lib/action_policy/lookup_chain.rb +29 -15
  13. data/lib/action_policy/policy/aliases.rb +7 -12
  14. data/lib/action_policy/policy/authorization.rb +8 -7
  15. data/lib/action_policy/policy/cache.rb +11 -17
  16. data/lib/action_policy/policy/core.rb +25 -12
  17. data/lib/action_policy/policy/defaults.rb +3 -9
  18. data/lib/action_policy/policy/execution_result.rb +3 -9
  19. data/lib/action_policy/policy/pre_check.rb +19 -58
  20. data/lib/action_policy/policy/reasons.rb +29 -19
  21. data/lib/action_policy/policy/scoping.rb +5 -6
  22. data/lib/action_policy/rails/controller.rb +6 -1
  23. data/lib/action_policy/rails/policy/instrumentation.rb +1 -1
  24. data/lib/action_policy/rspec/be_authorized_to.rb +5 -9
  25. data/lib/action_policy/rspec/dsl.rb +1 -1
  26. data/lib/action_policy/rspec/have_authorized_scope.rb +5 -7
  27. data/lib/action_policy/utils/pretty_print.rb +21 -24
  28. data/lib/action_policy/utils/suggest_message.rb +1 -3
  29. data/lib/action_policy/version.rb +1 -1
  30. data/lib/generators/action_policy/install/templates/{application_policy.rb → application_policy.rb.tt} +0 -0
  31. data/lib/generators/action_policy/policy/policy_generator.rb +4 -1
  32. data/lib/generators/action_policy/policy/templates/{policy.rb → policy.rb.tt} +0 -0
  33. data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
  34. data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
  35. metadata +29 -119
  36. data/.gitattributes +0 -2
  37. data/.github/ISSUE_TEMPLATE.md +0 -21
  38. data/.github/PULL_REQUEST_TEMPLATE.md +0 -29
  39. data/.github/bug_report_template.rb +0 -175
  40. data/.gitignore +0 -15
  41. data/.rubocop.yml +0 -54
  42. data/.tidelift.yml +0 -6
  43. data/.travis.yml +0 -31
  44. data/Gemfile +0 -22
  45. data/Rakefile +0 -27
  46. data/action_policy.gemspec +0 -44
  47. data/benchmarks/namespaced_lookup_cache.rb +0 -74
  48. data/benchmarks/pre_checks.rb +0 -73
  49. data/bin/console +0 -14
  50. data/bin/setup +0 -8
  51. data/docs/.nojekyll +0 -0
  52. data/docs/CNAME +0 -1
  53. data/docs/README.md +0 -79
  54. data/docs/_sidebar.md +0 -27
  55. data/docs/aliases.md +0 -122
  56. data/docs/assets/docsify-search.js +0 -364
  57. data/docs/assets/docsify.min.js +0 -3
  58. data/docs/assets/fonts/FiraCode-Medium.woff +0 -0
  59. data/docs/assets/fonts/FiraCode-Regular.woff +0 -0
  60. data/docs/assets/images/banner.png +0 -0
  61. data/docs/assets/images/cache.png +0 -0
  62. data/docs/assets/images/cache.svg +0 -70
  63. data/docs/assets/images/layer.png +0 -0
  64. data/docs/assets/images/layer.svg +0 -35
  65. data/docs/assets/prism-ruby.min.js +0 -1
  66. data/docs/assets/styles.css +0 -347
  67. data/docs/assets/vue.min.css +0 -1
  68. data/docs/authorization_context.md +0 -92
  69. data/docs/behaviour.md +0 -113
  70. data/docs/caching.md +0 -291
  71. data/docs/controller_action_aliases.md +0 -109
  72. data/docs/custom_lookup_chain.md +0 -48
  73. data/docs/custom_policy.md +0 -53
  74. data/docs/debugging.md +0 -55
  75. data/docs/decorators.md +0 -27
  76. data/docs/favicon.ico +0 -0
  77. data/docs/graphql.md +0 -302
  78. data/docs/i18n.md +0 -44
  79. data/docs/index.html +0 -43
  80. data/docs/instrumentation.md +0 -84
  81. data/docs/lookup_chain.md +0 -22
  82. data/docs/namespaces.md +0 -77
  83. data/docs/non_rails.md +0 -28
  84. data/docs/pre_checks.md +0 -57
  85. data/docs/pundit_migration.md +0 -80
  86. data/docs/quick_start.md +0 -118
  87. data/docs/rails.md +0 -120
  88. data/docs/reasons.md +0 -120
  89. data/docs/scoping.md +0 -255
  90. data/docs/testing.md +0 -390
  91. data/docs/writing_policies.md +0 -107
  92. data/gemfiles/jruby.gemfile +0 -8
  93. data/gemfiles/rails42.gemfile +0 -9
  94. data/gemfiles/rails6.gemfile +0 -8
  95. data/gemfiles/railsmaster.gemfile +0 -6
  96. data/lib/action_policy/ext/string_match.rb +0 -14
  97. data/lib/action_policy/ext/yield_self_then.rb +0 -25
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/action_policy.svg)](https://badge.fury.io/rb/action_policy)
2
- [![Build Status](https://travis-ci.org/palkan/action_policy.svg?branch=master)](https://travis-ci.org/palkan/action_policy)
2
+ ![Build](https://github.com/palkan/action_policy/workflows/Build/badge.svg)
3
+ ![JRuby Build](https://github.com/palkan/action_policy/workflows/JRuby%20Build/badge.svg)
3
4
  [![Documentation](https://img.shields.io/badge/docs-link-brightgreen.svg)](https://actionpolicy.evilmartians.io)
4
5
 
5
6
  # Action Policy
@@ -21,7 +22,6 @@ Composable. Extensible. Performant.
21
22
 
22
23
  - RailsConf, 2018 "Access Denied" talk ([video](https://www.youtube.com/watch?v=NVwx0DARDis), [slides](https://speakerdeck.com/palkan/railsconf-2018-access-denied-the-missing-guide-to-authorization-in-rails))
23
24
 
24
-
25
25
  ## Integrations
26
26
 
27
27
  - GraphQL Ruby ([`action_policy-graphql`](https://github.com/palkan/action_policy-graphql))
@@ -36,7 +36,9 @@ gem "action_policy", "~> 0.4.0"
36
36
 
37
37
  And then execute:
38
38
 
39
- $ bundle
39
+ ```sh
40
+ bundle install
41
+ ```
40
42
 
41
43
  ## Usage
42
44
 
@@ -89,7 +91,6 @@ end
89
91
 
90
92
  \* See [Non-Rails Usage](docs/non_rails.md) on how to add `authorize!` to any Ruby project.
91
93
 
92
-
93
94
  When authorization is successful (i.e., the corresponding rule returns `true`), nothing happens, but in case of authorization failure `ActionPolicy::Unauthorized` error is raised.
94
95
 
95
96
  There is also an `allowed_to?` method which returns `true` or `false`, and could be used, in views, for example:
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "ruby-next"
4
+
5
+ require "ruby-next/language/setup"
6
+ RubyNext::Language.setup_gem_load_path(transpile: true)
7
+
3
8
  # ActionPolicy is an authorization framework for Ruby/Rails applications.
4
9
  #
5
10
  # It provides a way to write access policies and helpers to check these policies
@@ -30,8 +35,9 @@ module ActionPolicy
30
35
  attr_accessor :cache_store
31
36
 
32
37
  # Find a policy class for a target
33
- def lookup(target, allow_nil: false, **options)
38
+ def lookup(target, allow_nil: false, default: nil, **options)
34
39
  LookupChain.call(target, **options) ||
40
+ default ||
35
41
  (allow_nil ? nil : raise(NotFound, target))
36
42
  end
37
43
  end
@@ -35,12 +35,7 @@ module ActionPolicy
35
35
  #
36
36
  # Raises `ActionPolicy::Unauthorized` if check failed.
37
37
  def authorize!(record = :__undef__, to:, **options)
38
- record = implicit_authorization_target! if record == :__undef__
39
- raise ArgumentError, "Record must be specified" if record.nil?
40
-
41
- options[:context] && (options[:context] = authorization_context.merge(options[:context]))
42
-
43
- policy = policy_for(record: record, **options)
38
+ policy = lookup_authorization_policy(record, **options)
44
39
 
45
40
  Authorizer.call(policy, authorization_rule_for(policy, to))
46
41
  end
@@ -49,14 +44,17 @@ module ActionPolicy
49
44
  #
50
45
  # Returns true of false.
51
46
  def allowed_to?(rule, record = :__undef__, **options)
52
- record = implicit_authorization_target! if record == :__undef__
53
- raise ArgumentError, "Record must be specified" if record.nil?
47
+ policy = lookup_authorization_policy(record, **options)
54
48
 
55
- options[:context] && (options[:context] = authorization_context.merge(options[:context]))
49
+ policy.apply(authorization_rule_for(policy, rule))
50
+ end
56
51
 
57
- policy = policy_for(record: record, **options)
52
+ # Returns the authorization result object after applying a specified rule to a record.
53
+ def allowance_to(rule, record = :__undef__, **options)
54
+ policy = lookup_authorization_policy(record, **options)
58
55
 
59
56
  policy.apply(authorization_rule_for(policy, rule))
57
+ policy.result
60
58
  end
61
59
 
62
60
  def authorization_context
@@ -75,6 +73,15 @@ module ActionPolicy
75
73
  policy.resolve_rule(rule)
76
74
  end
77
75
 
76
+ def lookup_authorization_policy(record, **options) # :nodoc:
77
+ record = implicit_authorization_target! if record == :__undef__
78
+ raise ArgumentError, "Record must be specified" if record.nil?
79
+
80
+ options[:context] && (options[:context] = authorization_context.merge(options[:context]))
81
+
82
+ policy_for(record: record, **options)
83
+ end
84
+
78
85
  module ClassMethods # :nodoc:
79
86
  # Configure authorization context.
80
87
  #
@@ -97,12 +104,11 @@ module ActionPolicy
97
104
  def authorization_targets
98
105
  return @authorization_targets if instance_variable_defined?(:@authorization_targets)
99
106
 
100
- @authorization_targets =
101
- if superclass.respond_to?(:authorization_targets)
102
- superclass.authorization_targets.dup
103
- else
104
- {}
105
- end
107
+ if superclass.respond_to?(:authorization_targets)
108
+ superclass.authorization_targets.dup
109
+ else
110
+ {}
111
+ end => @authorization_targets
106
112
  end
107
113
  end
108
114
  end
@@ -8,8 +8,11 @@ module ActionPolicy
8
8
  using ActionPolicy::Ext::PolicyCacheKey
9
9
 
10
10
  # Returns policy instance for the record.
11
- def policy_for(record:, with: nil, namespace: authorization_namespace, context: authorization_context, allow_nil: false)
12
- policy_class = with || ::ActionPolicy.lookup(record, namespace: namespace, context: context, allow_nil: allow_nil)
11
+ def policy_for(record:, with: nil, namespace: authorization_namespace, context: authorization_context, allow_nil: false, default: default_authorization_policy_class)
12
+ policy_class = with || ::ActionPolicy.lookup(
13
+ record,
14
+ **{namespace, context, allow_nil, default}
15
+ )
13
16
  policy_class&.new(record, **context)
14
17
  end
15
18
 
@@ -21,6 +24,10 @@ module ActionPolicy
21
24
  # override to provide specific authorization namespace
22
25
  end
23
26
 
27
+ def default_authorization_policy_class
28
+ # override to provide a policy class use when no policy found
29
+ end
30
+
24
31
  # Override this method to provide implicit authorization target
25
32
  # that would be used in case `record` is not specified in
26
33
  # `authorize!` and `allowed_to?` call.
@@ -46,7 +53,7 @@ module ActionPolicy
46
53
 
47
54
  def policy_for_cache_key(record:, with: nil, namespace: nil, context: authorization_context, **)
48
55
  record_key = record._policy_cache_key(use_object_id: true)
49
- context_key = context.values.map { |v| v._policy_cache_key(use_object_id: true) }.join(".")
56
+ context_key = context.values.map { _1._policy_cache_key(use_object_id: true) }.join(".")
50
57
 
51
58
  "#{namespace}/#{with}/#{context_key}/#{record_key}"
52
59
  end
@@ -17,8 +17,9 @@ module ActionPolicy
17
17
  policy ||= policy_for(record: implicit_authorization_target!, **options)
18
18
 
19
19
  type ||= authorization_scope_type_for(policy, target)
20
+ name = as
20
21
 
21
- Authorizer.scopify(target, policy, type: type, name: as, scope_options: scope_options)
22
+ Authorizer.scopify(target, policy, **{type, name, scope_options})
22
23
  end
23
24
 
24
25
  # For backward compatibility
@@ -7,9 +7,7 @@ module ActionPolicy
7
7
  class << self
8
8
  attr_writer :enabled
9
9
 
10
- def enabled?
11
- @enabled == true
12
- end
10
+ def enabled?() = @enabled == true
13
11
 
14
12
  def fetch(key)
15
13
  return yield unless enabled?
@@ -9,11 +9,6 @@ module ActionPolicy
9
9
  using ActionPolicy::Ext::StringConstantize
10
10
  end
11
11
 
12
- unless "".respond_to?(:match?)
13
- require "action_policy/ext/string_match"
14
- using ActionPolicy::Ext::StringMatch
15
- end
16
-
17
12
  module Ext
18
13
  def namespace
19
14
  return unless name&.match?(/[^^]::/)
@@ -23,7 +18,7 @@ module ActionPolicy
23
18
  end
24
19
 
25
20
  # See https://github.com/jruby/jruby/issues/5220
26
- ::Module.include(Ext) if RUBY_PLATFORM =~ /java/i
21
+ ::Module.include(Ext) if RUBY_PLATFORM.match?(/java/i)
27
22
 
28
23
  refine Module do
29
24
  include Ext
@@ -27,65 +27,45 @@ module ActionPolicy
27
27
  end
28
28
 
29
29
  refine NilClass do
30
- def _policy_cache_key(*)
31
- ""
32
- end
30
+ def _policy_cache_key(*) = ""
33
31
  end
34
32
 
35
33
  refine TrueClass do
36
- def _policy_cache_key(*)
37
- "t"
38
- end
34
+ def _policy_cache_key(*) = "t"
39
35
  end
40
36
 
41
37
  refine FalseClass do
42
- def _policy_cache_key(*)
43
- "f"
44
- end
38
+ def _policy_cache_key(*) = "f"
45
39
  end
46
40
 
47
41
  refine String do
48
- def _policy_cache_key(*)
49
- self
50
- end
42
+ def _policy_cache_key(*) = self
51
43
  end
52
44
 
53
45
  refine Symbol do
54
- def _policy_cache_key(*)
55
- to_s
56
- end
46
+ def _policy_cache_key(*) = to_s
57
47
  end
58
48
 
59
49
  if RUBY_PLATFORM.match?(/java/i)
60
50
  refine Integer do
61
- def _policy_cache_key(*)
62
- to_s
63
- end
51
+ def _policy_cache_key(*) = to_s
64
52
  end
65
53
 
66
54
  refine Float do
67
- def _policy_cache_key(*)
68
- to_s
69
- end
55
+ def _policy_cache_key(*) = to_s
70
56
  end
71
57
  else
72
58
  refine Numeric do
73
- def _policy_cache_key(*)
74
- to_s
75
- end
59
+ def _policy_cache_key(*) = to_s
76
60
  end
77
61
  end
78
62
 
79
63
  refine Time do
80
- def _policy_cache_key(*)
81
- to_s
82
- end
64
+ def _policy_cache_key(*) = to_s
83
65
  end
84
66
 
85
67
  refine Module do
86
- def _policy_cache_key(*)
87
- name
88
- end
68
+ def _policy_cache_key(*) = name
89
69
  end
90
70
  end
91
71
  end
@@ -21,7 +21,7 @@ module ActionPolicy
21
21
  private
22
22
 
23
23
  def candidates_for(policy_class, rule)
24
- policy_hierarchy = policy_class.ancestors.select { |klass| klass.respond_to?(:identifier) }
24
+ policy_hierarchy = policy_class.ancestors.select { _1.respond_to?(:identifier) }
25
25
  [
26
26
  *policy_hierarchy.map { |klass| :"policy.#{klass.identifier}.#{rule}" },
27
27
  :"policy.#{rule}",
@@ -24,14 +24,26 @@ module ActionPolicy
24
24
  class << self
25
25
  attr_reader :store
26
26
 
27
- def fetch(namespace, policy)
27
+ def put_if_absent(scope, namespace, policy)
28
+ local_store = store[scope][namespace]
29
+ return local_store[policy] if local_store[policy]
30
+ local_store[policy] ||= yield
31
+ end
32
+
33
+ def fetch(namespace, policy, strict:, &block)
28
34
  return yield unless LookupChain.namespace_cache_enabled?
29
- return store[namespace][policy] if store[namespace].key?(policy)
30
- store[namespace][policy] ||= yield
35
+
36
+ if strict
37
+ put_if_absent(:strict, namespace, policy, &block)
38
+ else
39
+ cached_policy = put_if_absent(:strict, namespace, policy, &block)
40
+ put_if_absent(:flexible, namespace, policy) { cached_policy }
41
+ end
31
42
  end
32
43
 
33
44
  def clear
34
- @store = Hash.new { |h, k| h[k] = {} }
45
+ hash = Hash.new { |h, k| h[k] = {} }
46
+ @store = {strict: hash, flexible: hash.clone}
35
47
  end
36
48
  end
37
49
 
@@ -53,23 +65,23 @@ module ActionPolicy
53
65
 
54
66
  private
55
67
 
56
- def lookup_within_namespace(policy_name, namespace)
68
+ def lookup_within_namespace(policy_name, namespace, strict: false)
57
69
  return unless namespace
58
- NamespaceCache.fetch(namespace.name, policy_name) do
70
+ NamespaceCache.fetch(namespace.name, policy_name, strict: strict) do
59
71
  mod = namespace
60
-
61
72
  loop do
62
73
  policy = "#{mod.name}::#{policy_name}".safe_constantize
63
-
64
74
  break policy unless policy.nil?
65
-
66
75
  mod = mod.namespace
67
-
68
- break if mod.nil?
76
+ break if mod.nil? || strict
69
77
  end
70
78
  end
71
79
  end
72
80
 
81
+ def objectify_policy(policy_name, strict: false)
82
+ policy_name.safe_constantize unless strict
83
+ end
84
+
73
85
  def policy_class_name_for(record)
74
86
  return record.policy_name.to_s if record.respond_to?(:policy_name)
75
87
 
@@ -112,19 +124,21 @@ module ActionPolicy
112
124
  }
113
125
 
114
126
  # Infer from passed symbol
115
- SYMBOL_LOOKUP = ->(record, namespace: nil, **) {
127
+ SYMBOL_LOOKUP = ->(record, namespace: nil, strict_namespace: false, **) {
116
128
  next unless record.is_a?(Symbol)
117
129
 
118
130
  policy_name = "#{record.camelize}Policy"
119
- lookup_within_namespace(policy_name, namespace) || policy_name.safe_constantize
131
+ lookup_within_namespace(policy_name, namespace, strict: strict_namespace) ||
132
+ objectify_policy(policy_name, strict: strict_namespace)
120
133
  }
121
134
 
122
135
  # (Optional) Infer using String#classify if available
123
- CLASSIFY_SYMBOL_LOOKUP = ->(record, namespace: nil, **) {
136
+ CLASSIFY_SYMBOL_LOOKUP = ->(record, namespace: nil, strict_namespace: false, **) {
124
137
  next unless record.is_a?(Symbol)
125
138
 
126
139
  policy_name = "#{record.to_s.classify}Policy"
127
- lookup_within_namespace(policy_name, namespace) || policy_name.safe_constantize
140
+ lookup_within_namespace(policy_name, namespace, strict: strict_namespace) ||
141
+ objectify_policy(policy_name, strict: strict_namespace)
128
142
  }
129
143
 
130
144
  self.chain = [
@@ -46,23 +46,18 @@ module ActionPolicy
46
46
  end
47
47
  end
48
48
 
49
- def lookup_alias(rule)
50
- rules_aliases[rule]
51
- end
49
+ def lookup_alias(rule) = rules_aliases[rule]
52
50
 
53
- def lookup_default_rule
54
- rules_aliases[DEFAULT]
55
- end
51
+ def lookup_default_rule() = rules_aliases[DEFAULT]
56
52
 
57
53
  def rules_aliases
58
54
  return @rules_aliases if instance_variable_defined?(:@rules_aliases)
59
55
 
60
- @rules_aliases =
61
- if superclass.respond_to?(:rules_aliases)
62
- superclass.rules_aliases.dup
63
- else
64
- {}
65
- end
56
+ if superclass.respond_to?(:rules_aliases)
57
+ superclass.rules_aliases.dup
58
+ else
59
+ {}
60
+ end => @rules_aliases
66
61
  end
67
62
 
68
63
  def method_added(name)
@@ -63,8 +63,10 @@ module ActionPolicy
63
63
 
64
64
  module ClassMethods # :nodoc:
65
65
  def authorize(*ids, allow_nil: false, optional: false)
66
+ allow_nil ||= optional
67
+
66
68
  ids.each do |id|
67
- authorization_targets[id] = {allow_nil: allow_nil || optional, optional: optional}
69
+ authorization_targets[id] = {allow_nil, optional}
68
70
  end
69
71
 
70
72
  attr_reader(*ids)
@@ -73,12 +75,11 @@ module ActionPolicy
73
75
  def authorization_targets
74
76
  return @authorization_targets if instance_variable_defined?(:@authorization_targets)
75
77
 
76
- @authorization_targets =
77
- if superclass.respond_to?(:authorization_targets)
78
- superclass.authorization_targets.dup
79
- else
80
- {}
81
- end
78
+ if superclass.respond_to?(:authorization_targets)
79
+ superclass.authorization_targets.dup
80
+ else
81
+ {}
82
+ end => @authorization_targets
82
83
  end
83
84
  end
84
85
  end
@@ -3,16 +3,13 @@
3
3
  require "action_policy/version"
4
4
 
5
5
  module ActionPolicy # :nodoc:
6
+ using RubyNext
7
+
6
8
  # By default cache namespace (or prefix) contains major and minor version of the gem
7
9
  CACHE_NAMESPACE = "acp:#{ActionPolicy::VERSION.split(".").take(2).join(".")}"
8
10
 
9
- require "action_policy/ext/yield_self_then"
10
11
  require "action_policy/ext/policy_cache_key"
11
12
 
12
- unless "".respond_to?(:then)
13
- require "action_policy/ext/yield_self_then"
14
- using ActionPolicy::Ext::YieldSelfThen
15
- end
16
13
  using ActionPolicy::Ext::PolicyCacheKey
17
14
 
18
15
  module Policy
@@ -26,15 +23,13 @@ module ActionPolicy # :nodoc:
26
23
  end
27
24
  end
28
25
 
29
- def cache_namespace
30
- ActionPolicy::CACHE_NAMESPACE
31
- end
26
+ def cache_namespace() = ActionPolicy::CACHE_NAMESPACE
32
27
 
33
28
  def cache_key(*parts)
34
29
  [
35
30
  cache_namespace,
36
31
  *parts
37
- ].map { |part| part._policy_cache_key }.join("/")
32
+ ].map { _1._policy_cache_key }.join("/")
38
33
  end
39
34
 
40
35
  def rule_cache_key(rule)
@@ -47,7 +42,7 @@ module ActionPolicy # :nodoc:
47
42
  end
48
43
 
49
44
  def context_cache_key
50
- authorization_context.map { |_k, v| v._policy_cache_key.to_s }.join("/")
45
+ authorization_context.map { _2._policy_cache_key.to_s }.join("/")
51
46
  end
52
47
 
53
48
  def apply_with_cache(rule)
@@ -79,7 +74,7 @@ module ActionPolicy # :nodoc:
79
74
  res = store.read(key)
80
75
  next res unless res.nil?
81
76
  res = yield
82
- store.write(key, res, **options)
77
+ store.write(key, res, options)
83
78
  res
84
79
  end
85
80
  end
@@ -94,12 +89,11 @@ module ActionPolicy # :nodoc:
94
89
  def cached_rules
95
90
  return @cached_rules if instance_variable_defined?(:@cached_rules)
96
91
 
97
- @cached_rules =
98
- if superclass.respond_to?(:cached_rules)
99
- superclass.cached_rules.dup
100
- else
101
- {}
102
- end
92
+ if superclass.respond_to?(:cached_rules)
93
+ superclass.cached_rules.dup
94
+ else
95
+ {}
96
+ end => @cached_rules
103
97
  end
104
98
  end
105
99
  end