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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45d8b27941b7424a315428ba04dd6dc98218896b54551f49f0cdde531c41b1af
4
- data.tar.gz: d602b39fd19660eb34908a17c0681fd884d7d2fb9b14395e1f2070ee54910ced
3
+ metadata.gz: 199a4f2c374f6e452459742724b7ba8ba9b0e9d9859ddf4ae12172a95e033bd9
4
+ data.tar.gz: ddc2c5a20e4b7181b1cdc0d07c53f85dc7acabb9ea4681616e3000292b45496f
5
5
  SHA512:
6
- metadata.gz: f3dbbc01b527507b658225ad95dcce305a1c33764636a88d3f83f7772a9c5264e7729d4d554335c4427c13f66b3a7535ef05e11842c0acddfa88d143a9cea83b
7
- data.tar.gz: a09b66c884a2258df7e9f53010af7fe638ac6454b4c36195406136b694116f9f5cb16465e7d67bdbddfd872b525f10dfc104cd8bcc659c323209b5a4f759c2fe
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
- # Instead, use explicit exception handling with rescue blocks and local variables.
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
- # rescue
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`. Use explicit exception handling with `rescue => error` instead."
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
@@ -5,6 +5,6 @@
5
5
 
6
6
  module RuboCop
7
7
  module Socketry
8
- VERSION = "0.6.0"
8
+ VERSION = "0.6.1"
9
9
  end
10
10
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-socketry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file