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 +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/.rbnext/2.7/action_policy/behaviours/policy_for.rb +5 -3
- data/lib/.rbnext/2.7/action_policy/utils/pretty_print.rb +25 -29
- data/lib/.rbnext/3.0/action_policy/behaviours/policy_for.rb +70 -0
- data/lib/.rbnext/3.0/action_policy/behaviours/thread_memoized.rb +1 -1
- data/lib/.rbnext/3.0/action_policy/policy/core.rb +1 -1
- data/lib/.rbnext/3.0/action_policy/utils/pretty_print.rb +25 -29
- data/lib/.rbnext/3.1/action_policy/behaviours/policy_for.rb +5 -3
- data/lib/.rbnext/3.1/action_policy/policy/authorization.rb +1 -0
- data/lib/.rbnext/3.2/action_policy/behaviours/policy_for.rb +5 -3
- data/lib/.rbnext/3.2/action_policy/policy/core.rb +1 -1
- data/lib/action_policy/behaviours/memoized.rb +1 -1
- data/lib/action_policy/behaviours/policy_for.rb +5 -3
- data/lib/action_policy/behaviours/thread_memoized.rb +1 -1
- data/lib/action_policy/policy/authorization.rb +1 -0
- data/lib/action_policy/policy/core.rb +1 -1
- data/lib/action_policy/policy/scoping.rb +12 -1
- data/lib/action_policy/rails/controller.rb +1 -1
- data/lib/action_policy/utils/pretty_print.rb +25 -29
- data/lib/action_policy/version.rb +1 -1
- metadata +4 -4
- data/lib/.rbnext/1995.next/action_policy/utils/pretty_print.rb +0 -159
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e9a1595099a6b87f22ec08fbd6676cd73cea94672c8cc9276525e82e9ba8c1a
|
4
|
+
data.tar.gz: bc743bbc45679d6583d3549cad77fc37f4004d051ef54d4cf8baa252730b0621
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 ?
|
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
|
-
|
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 "
|
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 =
|
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
|
82
|
-
visit_node(ast.
|
82
|
+
def visit_and_node(ast)
|
83
|
+
visit_node(ast.left)
|
83
84
|
lines << indented("AND")
|
84
|
-
visit_node(ast.
|
85
|
+
visit_node(ast.right)
|
85
86
|
end
|
86
87
|
|
87
|
-
def
|
88
|
-
visit_node(ast.
|
88
|
+
def visit_or_node(ast)
|
89
|
+
visit_node(ast.left)
|
89
90
|
lines << indented("OR")
|
90
|
-
visit_node(ast.
|
91
|
+
visit_node(ast.right)
|
91
92
|
end
|
92
93
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
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?(::
|
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
|
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(
|
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
|
@@ -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 "
|
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 "
|
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 =
|
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
|
82
|
-
visit_node(ast.
|
82
|
+
def visit_and_node(ast)
|
83
|
+
visit_node(ast.left)
|
83
84
|
lines << indented("AND")
|
84
|
-
visit_node(ast.
|
85
|
+
visit_node(ast.right)
|
85
86
|
end
|
86
87
|
|
87
|
-
def
|
88
|
-
visit_node(ast.
|
88
|
+
def visit_or_node(ast)
|
89
|
+
visit_node(ast.left)
|
89
90
|
lines << indented("OR")
|
90
|
-
visit_node(ast.
|
91
|
+
visit_node(ast.right)
|
91
92
|
end
|
92
93
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
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?(::
|
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
|
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(
|
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 ?
|
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
|
-
|
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
|
@@ -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 ?
|
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
|
-
|
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 "
|
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
|
|
@@ -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 ?
|
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
|
-
|
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 "
|
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
|
@@ -7,8 +7,7 @@ begin
|
|
7
7
|
# Ignore parse warnings when patch
|
8
8
|
# Ruby version mismatches
|
9
9
|
$VERBOSE = nil
|
10
|
-
require "
|
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 =
|
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
|
82
|
-
visit_node(ast.
|
82
|
+
def visit_and_node(ast)
|
83
|
+
visit_node(ast.left)
|
83
84
|
lines << indented("AND")
|
84
|
-
visit_node(ast.
|
85
|
+
visit_node(ast.right)
|
85
86
|
end
|
86
87
|
|
87
|
-
def
|
88
|
-
visit_node(ast.
|
88
|
+
def visit_or_node(ast)
|
89
|
+
visit_node(ast.left)
|
89
90
|
lines << indented("OR")
|
90
|
-
visit_node(ast.
|
91
|
+
visit_node(ast.right)
|
91
92
|
end
|
92
93
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
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?(::
|
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
|
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(
|
135
|
+
Visitor.new(object).collect(ast)
|
140
136
|
end
|
141
137
|
else
|
142
138
|
def available?() = false
|
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.
|
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-
|
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.
|
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
|