action_policy 0.6.9 → 0.7.1

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: ae3b29268276a0c189e7a2ce8d83e9a68f0de8a1da555de29549d6d7712bb6da
4
- data.tar.gz: ff91808a4bf73e284ed2cc973de4e5d4eb76e9ffe18f4f987461e8fa531f9f5b
3
+ metadata.gz: 9a2cec9201751bbc94bfa0875d8b4ed69500cdeea4ab4a1d9717a1786b3adba8
4
+ data.tar.gz: 4b0be37589400d6491bf4e7b5c7a6e2e46b5e71629f9c6b93d28c59f58b0d4ec
5
5
  SHA512:
6
- metadata.gz: e914fd53642a316240ff3f4ef8e51076080bd98780fa5116678a1bc87d7ad135a34ba5ab8eff3e125d73b993044b026cb232605cf21b9ec4cb8dbbf5b2cc2f71
7
- data.tar.gz: 4be9b544ab2a48d7e3a4a94896b417159c17b69745980a460e1927e2d8aef35b946e5a980c16fd78f83138c413afe290d510a3942f7f2deae5c10f132b8934f2
6
+ metadata.gz: 3751003181c14a8f2f71889525597d7b53cd2553cc52e955bbd668891f27ae34ec684fce36b1118b57c1527f78cdf6dca98b90b1dec7efc6cd20e59dc9f18fde
7
+ data.tar.gz: c6d0b96504ac2f70264b12df798cbbf4fc953b139666522e5dad8b6b3c5fd8702d522d21ed35c6023443b9ba9872720499931b3996e64e3d5652b600eb23e2a0
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.7.1 (2024-07-25)
6
+
7
+ - Support passing scope options to callable scope objects. ([@palkan][])
8
+
9
+ ## 0.7.0 (2024-06-20)
10
+
11
+ - **Ruby 2.7+** is required.
12
+
13
+ - Support using callable objects as scopes. ([@killondark][])
14
+
5
15
  ## 0.6.9 (2024-04-19)
6
16
 
7
17
  - 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, **opts) { callable.call(self, target, **opts) } 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.1"
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.1
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-07-25 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