rubocop-socketry 0.6.0 → 0.6.1
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
- checksums.yaml.gz.sig +0 -0
- data/lib/rubocop/socketry/style/global_exception_variables.rb +77 -9
- data/lib/rubocop/socketry/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +1 -1
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 199a4f2c374f6e452459742724b7ba8ba9b0e9d9859ddf4ae12172a95e033bd9
|
|
4
|
+
data.tar.gz: ddc2c5a20e4b7181b1cdc0d07c53f85dc7acabb9ea4681616e3000292b45496f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f04815a61b6651a7c4325967a9d193ade2ecb85800cb3ef816afed0a0f51d5849ab8a3aeb758474b93a8927b7fd984826f983749a9ff4824a0cf5beba1d72d95
|
|
7
|
+
data.tar.gz: 6b255a3e77c44782ea801bc3de112411896f9395ab0b78191998b8a064528a29cbca77bc50be56223f68c1b2df2e1155332f3985fd6e62bc935f5850a7b91553
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -8,7 +8,7 @@ require "rubocop"
|
|
|
8
8
|
module RuboCop
|
|
9
9
|
module Socketry
|
|
10
10
|
module Style
|
|
11
|
-
# A RuboCop cop that warns against using global exception variables.
|
|
11
|
+
# A RuboCop cop that warns against using global exception variables in unsafe contexts.
|
|
12
12
|
#
|
|
13
13
|
# This cop discourages the use of:
|
|
14
14
|
# - `$!` (last exception)
|
|
@@ -17,26 +17,52 @@ module RuboCop
|
|
|
17
17
|
# - `$ERROR_POSITION` (English name for `$@`)
|
|
18
18
|
#
|
|
19
19
|
# These global variables are implicit and can make code harder to understand.
|
|
20
|
-
#
|
|
20
|
+
#
|
|
21
|
+
# However, this cop allows their use in safe contexts where the scope is well-defined:
|
|
22
|
+
# - Inside rescue blocks (well-defined scope)
|
|
23
|
+
# - In rescue modifiers (`expression rescue $!`)
|
|
24
|
+
# - In method parameter defaults (`def foo(error = $!)`, `def bar(error: $!)`)
|
|
25
|
+
#
|
|
26
|
+
# This cop specifically flags their use in unsafe contexts:
|
|
27
|
+
# - Inside ensure blocks (extremely unsafe - exception state is unpredictable)
|
|
28
|
+
# - Outside of exception handling contexts
|
|
21
29
|
#
|
|
22
30
|
# @example
|
|
23
|
-
# # bad
|
|
31
|
+
# # bad - unsafe in ensure block
|
|
24
32
|
# begin
|
|
25
33
|
# risky_operation
|
|
26
|
-
#
|
|
34
|
+
# ensure
|
|
35
|
+
# log($!.message) if $! # unsafe!
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# # bad - outside exception handling
|
|
39
|
+
# def process
|
|
27
40
|
# puts $!.message
|
|
28
|
-
# puts $@.first
|
|
29
41
|
# end
|
|
30
42
|
#
|
|
31
|
-
# # good
|
|
43
|
+
# # good - explicit exception handling
|
|
32
44
|
# begin
|
|
33
45
|
# risky_operation
|
|
34
46
|
# rescue => error
|
|
35
47
|
# puts error.message
|
|
36
|
-
# puts error.backtrace.first
|
|
37
48
|
# end
|
|
49
|
+
#
|
|
50
|
+
# # allowed - inside rescue block (well-defined scope)
|
|
51
|
+
# begin
|
|
52
|
+
# risky_operation
|
|
53
|
+
# rescue
|
|
54
|
+
# puts $!.message
|
|
55
|
+
# end
|
|
56
|
+
#
|
|
57
|
+
# # allowed - rescue modifier
|
|
58
|
+
# result = risky_operation rescue $!
|
|
59
|
+
#
|
|
60
|
+
# # allowed - parameter defaults
|
|
61
|
+
# def foo(error = $!)
|
|
62
|
+
# def bar(error: $!)
|
|
38
63
|
class GlobalExceptionVariables < RuboCop::Cop::Base
|
|
39
|
-
MSG = "Avoid using global exception variable `%<variable>s
|
|
64
|
+
MSG = "Avoid using global exception variable `%<variable>s` in %<context>s. Use explicit exception handling with `rescue => error` instead."
|
|
65
|
+
ENSURE_MSG = "Using global exception variable `%<variable>s` in an ensure block is extremely unsafe."
|
|
40
66
|
|
|
41
67
|
EXCEPTION_VARIABLES = %i[$! $@ $ERROR_INFO $ERROR_POSITION].freeze
|
|
42
68
|
|
|
@@ -45,11 +71,53 @@ module RuboCop
|
|
|
45
71
|
|
|
46
72
|
return unless EXCEPTION_VARIABLES.include?(variable_name)
|
|
47
73
|
|
|
74
|
+
# Allow in parameter defaults (explicitly opting in)
|
|
75
|
+
return if in_parameter_default?(node)
|
|
76
|
+
|
|
77
|
+
# Allow in rescue modifier (well-defined scope)
|
|
78
|
+
return if in_rescue_modifier?(node)
|
|
79
|
+
|
|
80
|
+
# Allow in rescue block (well-defined scope)
|
|
81
|
+
return if in_rescue_block?(node)
|
|
82
|
+
|
|
83
|
+
# Flag if in ensure block (extremely unsafe)
|
|
84
|
+
if in_ensure_block?(node)
|
|
85
|
+
add_offense(
|
|
86
|
+
node,
|
|
87
|
+
message: format(ENSURE_MSG, variable: variable_name)
|
|
88
|
+
)
|
|
89
|
+
return
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Flag in all other contexts
|
|
48
93
|
add_offense(
|
|
49
94
|
node,
|
|
50
|
-
message: format(MSG, variable: variable_name)
|
|
95
|
+
message: format(MSG, variable: variable_name, context: "this context")
|
|
51
96
|
)
|
|
52
97
|
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def in_parameter_default?(node)
|
|
102
|
+
node.each_ancestor(:args, :optarg, :kwoptarg).any?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def in_rescue_modifier?(node)
|
|
106
|
+
node.each_ancestor(:rescue).any? do |ancestor|
|
|
107
|
+
# A rescue modifier has no resbody children
|
|
108
|
+
# e.g., `expression rescue $!` is a rescue node with 2 children: expression and handler
|
|
109
|
+
# A regular rescue has resbody children
|
|
110
|
+
!ancestor.children.any?{|child| child.is_a?(RuboCop::AST::Node) && child.type == :resbody}
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def in_rescue_block?(node)
|
|
115
|
+
node.each_ancestor(:resbody).any?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def in_ensure_block?(node)
|
|
119
|
+
node.each_ancestor(:ensure).any?
|
|
120
|
+
end
|
|
53
121
|
end
|
|
54
122
|
end
|
|
55
123
|
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
metadata.gz.sig
CHANGED
|
Binary file
|