action_policy 0.6.9 → 0.7.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: ae3b29268276a0c189e7a2ce8d83e9a68f0de8a1da555de29549d6d7712bb6da
4
- data.tar.gz: ff91808a4bf73e284ed2cc973de4e5d4eb76e9ffe18f4f987461e8fa531f9f5b
3
+ metadata.gz: 0e9a1595099a6b87f22ec08fbd6676cd73cea94672c8cc9276525e82e9ba8c1a
4
+ data.tar.gz: bc743bbc45679d6583d3549cad77fc37f4004d051ef54d4cf8baa252730b0621
5
5
  SHA512:
6
- metadata.gz: e914fd53642a316240ff3f4ef8e51076080bd98780fa5116678a1bc87d7ad135a34ba5ab8eff3e125d73b993044b026cb232605cf21b9ec4cb8dbbf5b2cc2f71
7
- data.tar.gz: 4be9b544ab2a48d7e3a4a94896b417159c17b69745980a460e1927e2d8aef35b946e5a980c16fd78f83138c413afe290d510a3942f7f2deae5c10f132b8934f2
6
+ metadata.gz: cf8db058edbeb5b198fb58f8ccab0d35e1f71aeb7891a6bab93bf6e04b9819fc321706bfbbe6437b58021325f01f62d5e891e812690a80f8464ef2c825ef8e47
7
+ data.tar.gz: 8aceb6e4a30d97e487b7bb29de4393c3c7f8598261c12f36dd66743d2a3c469bce61423c062e38b757d5265711d07172a743d04060dc336521f2dd10f80b7693
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.7.0 (2024-06-20)
6
+
7
+ - **Ruby 2.7+** is required.
8
+
9
+ - Support using callable objects as scopes. ([@killondark][])
10
+
5
11
  ## 0.6.9 (2024-04-19)
6
12
 
7
13
  - Add `.with_context` modifier to the `#have_authorized_scope` matcher. ([@killondark][])
@@ -9,7 +9,7 @@ module ActionPolicy
9
9
 
10
10
  # Returns policy instance for the record.
11
11
  def policy_for(record:, with: nil, namespace: authorization_namespace, context: nil, allow_nil: false, default: default_authorization_policy_class, strict_namespace: authorization_strict_namespace)
12
- context = context ? authorization_context.merge(context) : authorization_context
12
+ context = context ? build_authorization_context.merge(context) : authorization_context
13
13
 
14
14
  policy_class = with || ::ActionPolicy.lookup(
15
15
  record,
@@ -18,8 +18,10 @@ module ActionPolicy
18
18
  policy_class&.new(record, **context)
19
19
  end
20
20
 
21
- def authorization_context
22
- Kernel.raise NotImplementedError, "Please, define `authorization_context` method!"
21
+ def authorization_context ; @authorization_context ||= build_authorization_context; end
22
+
23
+ def build_authorization_context
24
+ Kernel.raise NotImplementedError, "Please, define `build_authorization_context` method!"
23
25
  end
24
26
 
25
27
  def authorization_namespace
@@ -7,8 +7,7 @@ begin
7
7
  # Ignore parse warnings when patch
8
8
  # Ruby version mismatches
9
9
  $VERBOSE = nil
10
- require "parser/current"
11
- require "unparser"
10
+ require "prism"
12
11
  rescue LoadError
13
12
  # do nothing
14
13
  ensure
@@ -42,7 +41,7 @@ module ActionPolicy
42
41
  FALSE = "\e[31mfalse\e[0m"
43
42
 
44
43
  class Visitor
45
- attr_reader :lines, :object
44
+ attr_reader :lines, :object, :source
46
45
  attr_accessor :indent
47
46
 
48
47
  def initialize(object)
@@ -52,6 +51,8 @@ module ActionPolicy
52
51
  def collect(ast)
53
52
  @lines = []
54
53
  @indent = 0
54
+ @source = ast.source.source
55
+ ast = ast.value.child_nodes[0].child_nodes[0].body
55
56
 
56
57
  visit_node(ast)
57
58
 
@@ -67,7 +68,7 @@ module ActionPolicy
67
68
  end
68
69
 
69
70
  def expression_with_result(sexp)
70
- expression = Unparser.unparse(sexp)
71
+ expression = source[sexp.location.start_offset...sexp.location.end_offset]
71
72
  "#{expression} #=> #{PrettyPrint.colorize(eval_exp(expression))}"
72
73
  end
73
74
 
@@ -78,36 +79,33 @@ module ActionPolicy
78
79
  "Failed: #{e.message}"
79
80
  end
80
81
 
81
- def visit_and(ast)
82
- visit_node(ast.children[0])
82
+ def visit_and_node(ast)
83
+ visit_node(ast.left)
83
84
  lines << indented("AND")
84
- visit_node(ast.children[1])
85
+ visit_node(ast.right)
85
86
  end
86
87
 
87
- def visit_or(ast)
88
- visit_node(ast.children[0])
88
+ def visit_or_node(ast)
89
+ visit_node(ast.left)
89
90
  lines << indented("OR")
90
- visit_node(ast.children[1])
91
+ visit_node(ast.right)
91
92
  end
92
93
 
93
- def visit_begin(ast)
94
- # Parens
95
- if ast.children.size == 1
96
- lines << indented("(")
97
- self.indent += 2
98
- visit_node(ast.children[0])
94
+ def visit_statements_node(ast)
95
+ ast.child_nodes.each do |node|
96
+ visit_node(node)
97
+ # restore indent after each expression
99
98
  self.indent -= 2
100
- lines << indented(")")
101
- else
102
- # Multiple expressions
103
- ast.children.each do |node|
104
- visit_node(node)
105
- # restore indent after each expression
106
- self.indent -= 2
107
- end
108
99
  end
109
100
  end
110
101
 
102
+ def visit_parentheses_node(ast)
103
+ lines << indented("(")
104
+ self.indent += 2
105
+ visit_node(ast.child_nodes[0])
106
+ lines << indented(")")
107
+ end
108
+
111
109
  def visit_missing(ast)
112
110
  lines << indented(expression_with_result(ast))
113
111
  end
@@ -128,15 +126,13 @@ module ActionPolicy
128
126
  class << self
129
127
  attr_accessor :ignore_expressions
130
128
 
131
- if defined?(::Unparser) && defined?(::MethodSource)
129
+ if defined?(::Prism) && defined?(::MethodSource)
132
130
  def available?() ; true; end
133
131
 
134
132
  def print_method(object, method_name)
135
- ast = object.method(method_name).source.then(&Unparser.method(:parse))
136
- # outer node is a method definition itself
137
- body = ast.children[2]
133
+ ast = Prism.parse(object.method(method_name).source)
138
134
 
139
- Visitor.new(object).collect(body)
135
+ Visitor.new(object).collect(ast)
140
136
  end
141
137
  else
142
138
  def available?() ; false; end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionPolicy
4
+ module Behaviours
5
+ # Adds `policy_for` method
6
+ module PolicyFor
7
+ require "action_policy/ext/policy_cache_key"
8
+ using ActionPolicy::Ext::PolicyCacheKey
9
+
10
+ # Returns policy instance for the record.
11
+ def policy_for(record:, with: nil, namespace: authorization_namespace, context: nil, allow_nil: false, default: default_authorization_policy_class, strict_namespace: authorization_strict_namespace)
12
+ context = context ? build_authorization_context.merge(context) : authorization_context
13
+
14
+ policy_class = with || ::ActionPolicy.lookup(
15
+ record,
16
+ namespace: namespace, context: context, allow_nil: allow_nil, default: default, strict_namespace: strict_namespace
17
+ )
18
+ policy_class&.new(record, **context)
19
+ end
20
+
21
+ def authorization_context ; @authorization_context ||= build_authorization_context; end
22
+
23
+ def build_authorization_context
24
+ Kernel.raise NotImplementedError, "Please, define `build_authorization_context` method!"
25
+ end
26
+
27
+ def authorization_namespace
28
+ # override to provide specific authorization namespace
29
+ end
30
+
31
+ def default_authorization_policy_class
32
+ # override to provide a policy class use when no policy found
33
+ end
34
+
35
+ def authorization_strict_namespace
36
+ # override to provide strict namespace lookup option
37
+ end
38
+
39
+ # Override this method to provide implicit authorization target
40
+ # that would be used in case `record` is not specified in
41
+ # `authorize!` and `allowed_to?` call.
42
+ #
43
+ # It is also used to infer a policy for scoping (in `authorized_scope` method).
44
+ def implicit_authorization_target
45
+ # no-op
46
+ end
47
+
48
+ # Return implicit authorization target or raises an exception if it's nil
49
+ def implicit_authorization_target!
50
+ implicit_authorization_target || Kernel.raise(
51
+ NotFound,
52
+ [
53
+ self,
54
+ "Couldn't find implicit authorization target " \
55
+ "for #{self.class}. " \
56
+ "Please, provide policy class explicitly using `with` option or " \
57
+ "define the `implicit_authorization_target` method."
58
+ ]
59
+ )
60
+ end
61
+
62
+ def policy_for_cache_key(record:, with: nil, namespace: nil, context: authorization_context, **__kwrest__)
63
+ record_key = record._policy_cache_key(use_object_id: true)
64
+ context_key = context.values.map { _1._policy_cache_key(use_object_id: true) }.join(".")
65
+
66
+ "#{namespace}/#{with}/#{context_key}/#{record_key}"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -45,7 +45,7 @@ module ActionPolicy
45
45
 
46
46
  module InstanceMethods # :nodoc:
47
47
  def policy_for(record:, **opts)
48
- __policy_thread_memoize__(record, **opts) { super(record: record, **opts) }
48
+ __policy_thread_memoize__(record, **opts) { super }
49
49
  end
50
50
  end
51
51
 
@@ -147,7 +147,7 @@ module ActionPolicy
147
147
  end
148
148
 
149
149
  # Return annotated source code for the rule
150
- # NOTE: require "method_source" and "unparser" gems to be installed.
150
+ # NOTE: require "method_source" and "prism" gems to be installed.
151
151
  # Otherwise returns empty string.
152
152
  def inspect_rule(rule) ; PrettyPrint.print_method(self, rule); end
153
153
 
@@ -7,8 +7,7 @@ begin
7
7
  # Ignore parse warnings when patch
8
8
  # Ruby version mismatches
9
9
  $VERBOSE = nil
10
- require "parser/current"
11
- require "unparser"
10
+ require "prism"
12
11
  rescue LoadError
13
12
  # do nothing
14
13
  ensure
@@ -42,7 +41,7 @@ module ActionPolicy
42
41
  FALSE = "\e[31mfalse\e[0m"
43
42
 
44
43
  class Visitor
45
- attr_reader :lines, :object
44
+ attr_reader :lines, :object, :source
46
45
  attr_accessor :indent
47
46
 
48
47
  def initialize(object)
@@ -52,6 +51,8 @@ module ActionPolicy
52
51
  def collect(ast)
53
52
  @lines = []
54
53
  @indent = 0
54
+ @source = ast.source.source
55
+ ast = ast.value.child_nodes[0].child_nodes[0].body
55
56
 
56
57
  visit_node(ast)
57
58
 
@@ -67,7 +68,7 @@ module ActionPolicy
67
68
  end
68
69
 
69
70
  def expression_with_result(sexp)
70
- expression = Unparser.unparse(sexp)
71
+ expression = source[sexp.location.start_offset...sexp.location.end_offset]
71
72
  "#{expression} #=> #{PrettyPrint.colorize(eval_exp(expression))}"
72
73
  end
73
74
 
@@ -78,36 +79,33 @@ module ActionPolicy
78
79
  "Failed: #{e.message}"
79
80
  end
80
81
 
81
- def visit_and(ast)
82
- visit_node(ast.children[0])
82
+ def visit_and_node(ast)
83
+ visit_node(ast.left)
83
84
  lines << indented("AND")
84
- visit_node(ast.children[1])
85
+ visit_node(ast.right)
85
86
  end
86
87
 
87
- def visit_or(ast)
88
- visit_node(ast.children[0])
88
+ def visit_or_node(ast)
89
+ visit_node(ast.left)
89
90
  lines << indented("OR")
90
- visit_node(ast.children[1])
91
+ visit_node(ast.right)
91
92
  end
92
93
 
93
- def visit_begin(ast)
94
- # Parens
95
- if ast.children.size == 1
96
- lines << indented("(")
97
- self.indent += 2
98
- visit_node(ast.children[0])
94
+ def visit_statements_node(ast)
95
+ ast.child_nodes.each do |node|
96
+ visit_node(node)
97
+ # restore indent after each expression
99
98
  self.indent -= 2
100
- lines << indented(")")
101
- else
102
- # Multiple expressions
103
- ast.children.each do |node|
104
- visit_node(node)
105
- # restore indent after each expression
106
- self.indent -= 2
107
- end
108
99
  end
109
100
  end
110
101
 
102
+ def visit_parentheses_node(ast)
103
+ lines << indented("(")
104
+ self.indent += 2
105
+ visit_node(ast.child_nodes[0])
106
+ lines << indented(")")
107
+ end
108
+
111
109
  def visit_missing(ast)
112
110
  lines << indented(expression_with_result(ast))
113
111
  end
@@ -128,15 +126,13 @@ module ActionPolicy
128
126
  class << self
129
127
  attr_accessor :ignore_expressions
130
128
 
131
- if defined?(::Unparser) && defined?(::MethodSource)
129
+ if defined?(::Prism) && defined?(::MethodSource)
132
130
  def available?() ; true; end
133
131
 
134
132
  def print_method(object, method_name)
135
- ast = object.method(method_name).source.then(&Unparser.method(:parse))
136
- # outer node is a method definition itself
137
- body = ast.children[2]
133
+ ast = Prism.parse(object.method(method_name).source)
138
134
 
139
- Visitor.new(object).collect(body)
135
+ Visitor.new(object).collect(ast)
140
136
  end
141
137
  else
142
138
  def available?() ; false; end
@@ -9,7 +9,7 @@ module ActionPolicy
9
9
 
10
10
  # Returns policy instance for the record.
11
11
  def policy_for(record:, with: nil, namespace: authorization_namespace, context: nil, allow_nil: false, default: default_authorization_policy_class, strict_namespace: authorization_strict_namespace)
12
- context = context ? authorization_context.merge(context) : authorization_context
12
+ context = context ? build_authorization_context.merge(context) : authorization_context
13
13
 
14
14
  policy_class = with || ::ActionPolicy.lookup(
15
15
  record,
@@ -18,8 +18,10 @@ module ActionPolicy
18
18
  policy_class&.new(record, **context)
19
19
  end
20
20
 
21
- def authorization_context
22
- Kernel.raise NotImplementedError, "Please, define `authorization_context` method!"
21
+ def authorization_context = @authorization_context ||= build_authorization_context
22
+
23
+ def build_authorization_context
24
+ Kernel.raise NotImplementedError, "Please, define `build_authorization_context` method!"
23
25
  end
24
26
 
25
27
  def authorization_namespace
@@ -42,6 +42,7 @@ module ActionPolicy
42
42
  end
43
43
 
44
44
  attr_reader :authorization_context
45
+ alias_method :build_authorization_context, :authorization_context
45
46
 
46
47
  def initialize(record = nil, **params)
47
48
  super(record)
@@ -9,7 +9,7 @@ module ActionPolicy
9
9
 
10
10
  # Returns policy instance for the record.
11
11
  def policy_for(record:, with: nil, namespace: authorization_namespace, context: nil, allow_nil: false, default: default_authorization_policy_class, strict_namespace: authorization_strict_namespace)
12
- context = context ? authorization_context.merge(context) : authorization_context
12
+ context = context ? build_authorization_context.merge(context) : authorization_context
13
13
 
14
14
  policy_class = with || ::ActionPolicy.lookup(
15
15
  record,
@@ -18,8 +18,10 @@ module ActionPolicy
18
18
  policy_class&.new(record, **context)
19
19
  end
20
20
 
21
- def authorization_context
22
- Kernel.raise NotImplementedError, "Please, define `authorization_context` method!"
21
+ def authorization_context = @authorization_context ||= build_authorization_context
22
+
23
+ def build_authorization_context
24
+ Kernel.raise NotImplementedError, "Please, define `build_authorization_context` method!"
23
25
  end
24
26
 
25
27
  def authorization_namespace
@@ -147,7 +147,7 @@ module ActionPolicy
147
147
  end
148
148
 
149
149
  # Return annotated source code for the rule
150
- # NOTE: require "method_source" and "unparser" gems to be installed.
150
+ # NOTE: require "method_source" and "prism" gems to be installed.
151
151
  # Otherwise returns empty string.
152
152
  def inspect_rule(rule) = PrettyPrint.print_method(self, rule)
153
153
 
@@ -29,7 +29,7 @@ module ActionPolicy
29
29
 
30
30
  module InstanceMethods # :nodoc:
31
31
  def policy_for(record:, **opts)
32
- __policy_memoize__(record, **opts) { super(record: record, **opts) }
32
+ __policy_memoize__(record, **opts) { super }
33
33
  end
34
34
  end
35
35
 
@@ -9,7 +9,7 @@ module ActionPolicy
9
9
 
10
10
  # Returns policy instance for the record.
11
11
  def policy_for(record:, with: nil, namespace: authorization_namespace, context: nil, allow_nil: false, default: default_authorization_policy_class, strict_namespace: authorization_strict_namespace)
12
- context = context ? authorization_context.merge(context) : authorization_context
12
+ context = context ? build_authorization_context.merge(context) : authorization_context
13
13
 
14
14
  policy_class = with || ::ActionPolicy.lookup(
15
15
  record,
@@ -18,8 +18,10 @@ module ActionPolicy
18
18
  policy_class&.new(record, **context)
19
19
  end
20
20
 
21
- def authorization_context
22
- Kernel.raise NotImplementedError, "Please, define `authorization_context` method!"
21
+ def authorization_context = @authorization_context ||= build_authorization_context
22
+
23
+ def build_authorization_context
24
+ Kernel.raise NotImplementedError, "Please, define `build_authorization_context` method!"
23
25
  end
24
26
 
25
27
  def authorization_namespace
@@ -45,7 +45,7 @@ module ActionPolicy
45
45
 
46
46
  module InstanceMethods # :nodoc:
47
47
  def policy_for(record:, **opts)
48
- __policy_thread_memoize__(record, **opts) { super(record: record, **opts) }
48
+ __policy_thread_memoize__(record, **opts) { super }
49
49
  end
50
50
  end
51
51
 
@@ -42,6 +42,7 @@ module ActionPolicy
42
42
  end
43
43
 
44
44
  attr_reader :authorization_context
45
+ alias_method :build_authorization_context, :authorization_context
45
46
 
46
47
  def initialize(record = nil, **params)
47
48
  super(record)
@@ -147,7 +147,7 @@ module ActionPolicy
147
147
  end
148
148
 
149
149
  # Return annotated source code for the rule
150
- # NOTE: require "method_source" and "unparser" gems to be installed.
150
+ # NOTE: require "method_source" and "prism" gems to be installed.
151
151
  # Otherwise returns empty string.
152
152
  def inspect_rule(rule) = PrettyPrint.print_method(self, rule)
153
153
 
@@ -113,8 +113,11 @@ module ActionPolicy
113
113
 
114
114
  module ClassMethods # :nodoc:
115
115
  # Register a new scoping method for the `type`
116
- def scope_for(type, name = :default, &block)
116
+ def scope_for(type, name = :default, callable = nil, &block)
117
+ name, callable = prepare_args(name, callable)
118
+
117
119
  mid = :"__scoping__#{type}__#{name}"
120
+ block = ->(target) { callable.call(self, target) } if callable
118
121
 
119
122
  define_method(mid, &block)
120
123
 
@@ -154,6 +157,14 @@ module ActionPolicy
154
157
  []
155
158
  end
156
159
  end
160
+
161
+ private
162
+
163
+ def prepare_args(name, callable)
164
+ return [name, callable] if name && callable
165
+ return [name, nil] if name.is_a?(Symbol) || name.is_a?(String)
166
+ [:default, name]
167
+ end
157
168
  end
158
169
  end
159
170
  end
@@ -48,7 +48,7 @@ module ActionPolicy
48
48
  def authorize!(record = :__undef__, to: nil, **options)
49
49
  to ||= :"#{action_name}?"
50
50
 
51
- super(record, to: to, **options)
51
+ super
52
52
 
53
53
  self.authorize_count += 1
54
54
  end
@@ -7,8 +7,7 @@ begin
7
7
  # Ignore parse warnings when patch
8
8
  # Ruby version mismatches
9
9
  $VERBOSE = nil
10
- require "parser/current"
11
- require "unparser"
10
+ require "prism"
12
11
  rescue LoadError
13
12
  # do nothing
14
13
  ensure
@@ -42,7 +41,7 @@ module ActionPolicy
42
41
  FALSE = "\e[31mfalse\e[0m"
43
42
 
44
43
  class Visitor
45
- attr_reader :lines, :object
44
+ attr_reader :lines, :object, :source
46
45
  attr_accessor :indent
47
46
 
48
47
  def initialize(object)
@@ -52,6 +51,8 @@ module ActionPolicy
52
51
  def collect(ast)
53
52
  @lines = []
54
53
  @indent = 0
54
+ @source = ast.source.source
55
+ ast = ast.value.child_nodes[0].child_nodes[0].body
55
56
 
56
57
  visit_node(ast)
57
58
 
@@ -67,7 +68,7 @@ module ActionPolicy
67
68
  end
68
69
 
69
70
  def expression_with_result(sexp)
70
- expression = Unparser.unparse(sexp)
71
+ expression = source[sexp.location.start_offset...sexp.location.end_offset]
71
72
  "#{expression} #=> #{PrettyPrint.colorize(eval_exp(expression))}"
72
73
  end
73
74
 
@@ -78,36 +79,33 @@ module ActionPolicy
78
79
  "Failed: #{e.message}"
79
80
  end
80
81
 
81
- def visit_and(ast)
82
- visit_node(ast.children[0])
82
+ def visit_and_node(ast)
83
+ visit_node(ast.left)
83
84
  lines << indented("AND")
84
- visit_node(ast.children[1])
85
+ visit_node(ast.right)
85
86
  end
86
87
 
87
- def visit_or(ast)
88
- visit_node(ast.children[0])
88
+ def visit_or_node(ast)
89
+ visit_node(ast.left)
89
90
  lines << indented("OR")
90
- visit_node(ast.children[1])
91
+ visit_node(ast.right)
91
92
  end
92
93
 
93
- def visit_begin(ast)
94
- # Parens
95
- if ast.children.size == 1
96
- lines << indented("(")
97
- self.indent += 2
98
- visit_node(ast.children[0])
94
+ def visit_statements_node(ast)
95
+ ast.child_nodes.each do |node|
96
+ visit_node(node)
97
+ # restore indent after each expression
99
98
  self.indent -= 2
100
- lines << indented(")")
101
- else
102
- # Multiple expressions
103
- ast.children.each do |node|
104
- visit_node(node)
105
- # restore indent after each expression
106
- self.indent -= 2
107
- end
108
99
  end
109
100
  end
110
101
 
102
+ def visit_parentheses_node(ast)
103
+ lines << indented("(")
104
+ self.indent += 2
105
+ visit_node(ast.child_nodes[0])
106
+ lines << indented(")")
107
+ end
108
+
111
109
  def visit_missing(ast)
112
110
  lines << indented(expression_with_result(ast))
113
111
  end
@@ -128,15 +126,13 @@ module ActionPolicy
128
126
  class << self
129
127
  attr_accessor :ignore_expressions
130
128
 
131
- if defined?(::Unparser) && defined?(::MethodSource)
129
+ if defined?(::Prism) && defined?(::MethodSource)
132
130
  def available?() = true
133
131
 
134
132
  def print_method(object, method_name)
135
- ast = object.method(method_name).source.then(&Unparser.:parse)
136
- # outer node is a method definition itself
137
- body = ast.children[2]
133
+ ast = Prism.parse(object.method(method_name).source)
138
134
 
139
- Visitor.new(object).collect(body)
135
+ Visitor.new(object).collect(ast)
140
136
  end
141
137
  else
142
138
  def available?() = false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionPolicy
4
- VERSION = "0.6.9"
4
+ VERSION = "0.7.0"
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.9
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-19 00:00:00.000000000 Z
11
+ date: 2024-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next-core
@@ -133,7 +133,6 @@ files:
133
133
  - LICENSE.txt
134
134
  - README.md
135
135
  - config/rubocop-rspec.yml
136
- - lib/.rbnext/1995.next/action_policy/utils/pretty_print.rb
137
136
  - lib/.rbnext/2.7/action_policy/behaviours/policy_for.rb
138
137
  - lib/.rbnext/2.7/action_policy/i18n.rb
139
138
  - lib/.rbnext/2.7/action_policy/policy/cache.rb
@@ -143,6 +142,7 @@ files:
143
142
  - lib/.rbnext/2.7/action_policy/rspec/be_authorized_to.rb
144
143
  - lib/.rbnext/2.7/action_policy/rspec/have_authorized_scope.rb
145
144
  - lib/.rbnext/2.7/action_policy/utils/pretty_print.rb
145
+ - lib/.rbnext/3.0/action_policy/behaviours/policy_for.rb
146
146
  - lib/.rbnext/3.0/action_policy/behaviours/thread_memoized.rb
147
147
  - lib/.rbnext/3.0/action_policy/ext/policy_cache_key.rb
148
148
  - lib/.rbnext/3.0/action_policy/policy/aliases.rb
@@ -242,7 +242,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
242
242
  requirements:
243
243
  - - ">="
244
244
  - !ruby/object:Gem::Version
245
- version: 2.6.0
245
+ version: 2.7.0
246
246
  required_rubygems_version: !ruby/object:Gem::Requirement
247
247
  requirements:
248
248
  - - ">="
@@ -1,159 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- old_verbose = $VERBOSE
4
-
5
- begin
6
- require "method_source"
7
- # Ignore parse warnings when patch
8
- # Ruby version mismatches
9
- $VERBOSE = nil
10
- require "parser/current"
11
- require "unparser"
12
- rescue LoadError
13
- # do nothing
14
- ensure
15
- $VERBOSE = old_verbose
16
- end
17
-
18
- module ActionPolicy
19
- using RubyNext
20
-
21
- # Takes the object and a method name,
22
- # and returns the "annotated" source code for the method:
23
- # code is split into parts by logical operators and each
24
- # part is evaluated separately.
25
- #
26
- # Example:
27
- #
28
- # class MyClass
29
- # def access?
30
- # admin? && access_feed?
31
- # end
32
- # end
33
- #
34
- # puts PrettyPrint.format_method(MyClass.new, :access?)
35
- #
36
- # #=> MyClass#access?
37
- # #=> ↳ admin? #=> false
38
- # #=> AND
39
- # #=> access_feed? #=> true
40
- module PrettyPrint
41
- TRUE = "\e[32mtrue\e[0m"
42
- FALSE = "\e[31mfalse\e[0m"
43
-
44
- class Visitor
45
- attr_reader :lines, :object
46
- attr_accessor :indent
47
-
48
- def initialize(object)
49
- @object = object
50
- end
51
-
52
- def collect(ast)
53
- @lines = []
54
- @indent = 0
55
-
56
- visit_node(ast)
57
-
58
- lines.join("\n")
59
- end
60
-
61
- def visit_node(ast)
62
- if respond_to?("visit_#{ast.type}")
63
- send("visit_#{ast.type}", ast)
64
- else
65
- visit_missing ast
66
- end
67
- end
68
-
69
- def expression_with_result(sexp)
70
- expression = Unparser.unparse(sexp)
71
- "#{expression} #=> #{PrettyPrint.colorize(eval_exp(expression))}"
72
- end
73
-
74
- def eval_exp(exp)
75
- return "<skipped>" if ignore_exp?(exp)
76
- object.instance_eval(exp)
77
- rescue => e
78
- "Failed: #{e.message}"
79
- end
80
-
81
- def visit_and(ast)
82
- visit_node(ast.children[0])
83
- lines << indented("AND")
84
- visit_node(ast.children[1])
85
- end
86
-
87
- def visit_or(ast)
88
- visit_node(ast.children[0])
89
- lines << indented("OR")
90
- visit_node(ast.children[1])
91
- end
92
-
93
- def visit_begin(ast)
94
- # Parens
95
- if ast.children.size == 1
96
- lines << indented("(")
97
- self.indent += 2
98
- visit_node(ast.children[0])
99
- self.indent -= 2
100
- lines << indented(")")
101
- else
102
- # Multiple expressions
103
- ast.children.each do |node|
104
- visit_node(node)
105
- # restore indent after each expression
106
- self.indent -= 2
107
- end
108
- end
109
- end
110
-
111
- def visit_missing(ast)
112
- lines << indented(expression_with_result(ast))
113
- end
114
-
115
- def indented(str)
116
- "#{indent.zero? ? "↳ " : ""}#{" " * indent}#{str}".tap do
117
- # increase indent after the first expression
118
- self.indent += 2 if indent.zero?
119
- end
120
- end
121
-
122
- # Some lines should not be evaled
123
- def ignore_exp?(exp)
124
- PrettyPrint.ignore_expressions.any? { exp.match?(_1) }
125
- end
126
- end
127
-
128
- class << self
129
- attr_accessor :ignore_expressions
130
-
131
- if defined?(::Unparser) && defined?(::MethodSource)
132
- def available?() = true
133
-
134
- def print_method(object, method_name)
135
- ast = object.method(method_name).source.then(&Unparser.method(:parse))
136
- # outer node is a method definition itself
137
- body = ast.children[2]
138
-
139
- Visitor.new(object).collect(body)
140
- end
141
- else
142
- def available?() = false
143
-
144
- def print_method(_, _) = ""
145
- end
146
-
147
- def colorize(val)
148
- return val unless $stdout.isatty
149
- return TRUE if val.eql?(true) # rubocop:disable Lint/DeprecatedConstants
150
- return FALSE if val.eql?(false) # rubocop:disable Lint/DeprecatedConstants
151
- val
152
- end
153
- end
154
-
155
- self.ignore_expressions = [
156
- /^\s*binding\.(pry|irb)\s*$/s
157
- ]
158
- end
159
- end