warning 1.0.0 → 1.1.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: 0fd71447749bdaad9176ecb3eb6302104bcaf5401516719beed80594d2fa234a
4
- data.tar.gz: 18eee8db50ef702428bcfd5690c3f92d013b4b8013dd6cd28e554ff808cccbd6
3
+ metadata.gz: 719af8cdb41da57d07edb0fa0eac81d2bb017d5d816cadf98e600cc75e63f4aa
4
+ data.tar.gz: 169550daf070386f36072d01c9c36303c631b6f598cf358e0f16e786f1d4ac68
5
5
  SHA512:
6
- metadata.gz: 8038062c8d96ec8eb800be734041654d3dd24a1a5ddda523c5c44f465f7cbdf3fdbaa3537e4d360ad9673effb4a54e27de544325235b0fe343ec13f6ee3ec948
7
- data.tar.gz: 26324dfc9591fda0a4627d515c3b18738e55f3213c0ff76b15f7493616980c54cf3cf3b945985d460d230db69b57ccd687f2b4ac5f367feec1b1efeae72319f0
6
+ metadata.gz: 5ddf24399c73e0b2b747189d02972c3616482ac90c3c9e89b16b8594a1e2c6cf005b3b81bab905de6f30d3fd1882d806c8746fd317f59e6915408f80f054ee8f
7
+ data.tar.gz: a5f1d714b59737dd6e67ab000687783acff87c3fe5cfd85bac2828c91556a7de5637d082e82d0a34198b53580a324c69639da93e07c0436e4f648e0031c7ff00
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ === 1.1.0 (2020-06-12)
2
+
3
+ * Allow Warning.process to be called with a hash of actions instead of a block (jeremyevans)
4
+
5
+ * Handle Warning.process blocks that return :default, :backtrace, or :raise specially (jeremyevans)
6
+
7
+ * Add support for :mismatched_indentations as regexp argument to Warning.ignore (qortex) (#7)
8
+
1
9
  === 1.0.0 (2020-01-21)
2
10
 
3
11
  * Add support for :taint as regexp argument to Warning.ignore (jeremyevans)
@@ -1,4 +1,4 @@
1
- Copyright (c) 2016 Jeremy Evans
1
+ Copyright (c) 2016-2020 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
@@ -2,7 +2,8 @@
2
2
 
3
3
  ruby-warning adds custom processing for warnings, including the
4
4
  ability to ignore specific warning messages, ignore warnings
5
- in specific files/directories, deduplicate warnings, and add
5
+ in specific files/directories, include backtraces with warnings,
6
+ treat warnings as errors, deduplicate warnings, and add
6
7
  custom handling for all warnings in specific files/directories.
7
8
 
8
9
  ruby-warning requires ruby 2.4+, as previous versions of ruby do
@@ -32,6 +33,7 @@ appropriate regexp. The supported symbols are:
32
33
  * :fixnum
33
34
  * :keyword_separation
34
35
  * :method_redefined
36
+ * :mismatched_indentations
35
37
  * :missing_gvar
36
38
  * :missing_ivar
37
39
  * :not_reached
@@ -47,6 +49,14 @@ string instead of performing the default behavior. You can call
47
49
  <tt>Warning.process</tt> multiple times and it will operate intelligently,
48
50
  choosing the longest path prefix that the string starts with.
49
51
 
52
+ <tt>Warning.process</tt> blocks can return +:default+ to use the default
53
+ behavior, +:backtrace+ to use the default behavior and also print the backtrace
54
+ or +:raise+ to raise the warning string as a RuntimeError.
55
+
56
+ <tt>Warning.process</tt> can also accept a hash of actions instead of a block,
57
+ with keys being regexps (or symbols supported by <tt>Warning.ignore</tt>) and
58
+ values being callable objects (or +:default+, +:backtrace+, or +:raise+).
59
+
50
60
  <tt>Warning.dedup</tt> deduplicates warnings, so that if a warning is received
51
61
  that is the same as a warning that has already been processed, the warning is
52
62
  ignored. Note that this should be used with care, since if the application
@@ -93,6 +103,23 @@ loading any code that could cause warnings.
93
103
  LOGGER.error(warning)
94
104
  end
95
105
 
106
+ # Write warnings in the current file to $stderr, but include backtrace
107
+ Warning.process(__FILE__) do |warning|
108
+ :backtrace
109
+ end
110
+
111
+ # Raise warnings in the current file as RuntimeErrors, with the warning
112
+ # string as the exception message
113
+ Warning.process(__FILE__) do |warning|
114
+ :raise
115
+ end
116
+
117
+ # Raise keyword argument separation warnings in the current file as
118
+ # RuntimeErrors, and write ambiguous slash warnings to $stderr, including
119
+ # the backtrace
120
+ Warning.process(__FILE__, keyword_separation: :raise,
121
+ ambiguous_slash: :backtrace)
122
+
96
123
  # Deduplicate warnings
97
124
  Warning.dedup
98
125
 
@@ -18,8 +18,17 @@ module Warning
18
18
  keyword_separation: /: warning: (?:Using the last argument (?:for `.+' )?as keyword parameters is deprecated; maybe \*\* should be added to the call|Passing the keyword argument (?:for `.+' )?as the last hash parameter is deprecated|Splitting the last argument (?:for `.+' )?into positional and keyword parameters is deprecated|The called method (?:`.+' )?is defined here)\n\z/,
19
19
  safe: /: warning: (?:rb_safe_level_2_warning|rb_safe_level|rb_set_safe_level_force|rb_set_safe_level|rb_secure|rb_insecure_operation|rb_check_safe_obj|\$SAFE) will (?:be removed|become a normal global variable) in Ruby 3\.0\n\z/,
20
20
  taint: /: warning: (?:rb_error_untrusted|rb_check_trusted|Pathname#taint|Pathname#untaint|rb_env_path_tainted|Object#tainted\?|Object#taint|Object#untaint|Object#untrusted\?|Object#untrust|Object#trust|rb_obj_infect|rb_tainted_str_new|rb_tainted_str_new_cstr) is deprecated and will be removed in Ruby 3\.2\.\n\z/,
21
+ mismatched_indentations: /: warning: mismatched indentations at '.+' with '.+' at \d+\n\z/,
21
22
  }
22
23
 
24
+ # Map of action symbols to procs that return the symbol
25
+ ACTION_PROC_MAP = {
26
+ default: proc{|_| :default},
27
+ backtrace: proc{|_| :backtrace},
28
+ raise: proc{|_| :raise},
29
+ }
30
+ private_constant :ACTION_PROC_MAP
31
+
23
32
  # Clear all current ignored warnings, warning processors, and duplicate check cache.
24
33
  # Also disables deduplicating warnings if that is currently enabled.
25
34
  def clear
@@ -81,14 +90,7 @@ module Warning
81
90
  # # Ignore all uninitialized instance variable and method redefined warnings in current file
82
91
  # Warning.ignore([:missing_ivar, :method_redefined], __FILE__)
83
92
  def ignore(regexp, path='')
84
- case regexp
85
- when Regexp
86
- # already regexp
87
- when Symbol
88
- regexp = IGNORE_MAP.fetch(regexp)
89
- when Array
90
- regexp = Regexp.union(regexp.map{|re| IGNORE_MAP.fetch(re)})
91
- else
93
+ unless regexp = convert_regexp(regexp)
92
94
  raise TypeError, "first argument to Warning.ignore should be Regexp, Symbol, or Array of Symbols, got #{regexp.inspect}"
93
95
  end
94
96
 
@@ -110,7 +112,52 @@ module Warning
110
112
  # Warning.process(__FILE__) do |warning|
111
113
  # LOGGER.error(warning)
112
114
  # end
113
- def process(path='', &block)
115
+ #
116
+ # The block can return one of the following symbols:
117
+ #
118
+ # :default :: Take the default action (call super, printing to $stderr).
119
+ # :backtrace :: Take the default action (call super, printing to $stderr),
120
+ # and also print the backtrace.
121
+ # :raise :: Raise a RuntimeError with the warning as the message.
122
+ #
123
+ # If the block returns anything else, it is assumed the block completely handled
124
+ # the warning and takes no other action.
125
+ #
126
+ # Instead of passing a block, you can pass a hash of actions to take for specific
127
+ # warnings, using regexp as keys and a callable objects as values:
128
+ #
129
+ # Warning.ignore(__FILE__,
130
+ # /instance variable @\w+ not initialized/ => proc do |warning|
131
+ # LOGGER.warning(warning)
132
+ # end,
133
+ # /global variable `\$\w+' not initialized/ => proc do |warning|
134
+ # LOGGER.error(warning)
135
+ # end
136
+ # )
137
+ #
138
+ # Instead of passing a regexp as a key, you can pass a symbol that is recognized
139
+ # by Warning.ignore. Instead of passing a callable object as a value, you can
140
+ # pass a symbol, which will be treated as a callable object that returns that symbol:
141
+ #
142
+ # Warning.process(__FILE__, :missing_ivar=>:backtrace, :keyword_separation=>:raise)
143
+ def process(path='', actions=nil, &block)
144
+ if block
145
+ if actions
146
+ raise ArgumentError, "cannot pass both actions and block to Warning.process"
147
+ end
148
+ elsif actions
149
+ block = {}
150
+ actions.each do |regexp, value|
151
+ unless regexp = convert_regexp(regexp)
152
+ raise TypeError, "action provided to Warning.process should be Regexp, Symbol, or Array of Symbols, got #{regexp.inspect}"
153
+ end
154
+
155
+ block[regexp] = ACTION_PROC_MAP[value] || value
156
+ end
157
+ else
158
+ raise ArgumentError, "must pass either actions or block to Warning.process"
159
+ end
160
+
114
161
  synchronize do
115
162
  @process << [path, block]
116
163
  @process.sort_by!(&:first)
@@ -138,18 +185,55 @@ module Warning
138
185
  synchronize{@dedup[str] = true}
139
186
  end
140
187
 
141
- synchronize{@process.dup}.each do |path, block|
142
- if str.start_with?(path)
143
- block.call(str)
144
- return
188
+ action = catch(:action) do
189
+ synchronize{@process.dup}.each do |path, block|
190
+ if str.start_with?(path)
191
+ if block.is_a?(Hash)
192
+ block.each do |regexp, blk|
193
+ if str =~ regexp
194
+ throw :action, blk.call(str)
195
+ end
196
+ end
197
+ else
198
+ throw :action, block.call(str)
199
+ end
200
+ end
145
201
  end
202
+
203
+ :default
146
204
  end
147
205
 
148
- super
206
+ case action
207
+ when :default
208
+ super
209
+ when :backtrace
210
+ super
211
+ $stderr.puts caller
212
+ when :raise
213
+ raise str
214
+ else
215
+ # nothing
216
+ end
217
+
218
+ nil
149
219
  end
150
220
 
151
221
  private
152
222
 
223
+ # Convert the given Regexp, Symbol, or Array of Symbols into a Regexp.
224
+ def convert_regexp(regexp)
225
+ case regexp
226
+ when Regexp
227
+ regexp
228
+ when Symbol
229
+ IGNORE_MAP.fetch(regexp)
230
+ when Array
231
+ Regexp.union(regexp.map{|re| IGNORE_MAP.fetch(re)})
232
+ else
233
+ # nothing
234
+ end
235
+ end
236
+
153
237
  def synchronize(&block)
154
238
  @monitor.synchronize(&block)
155
239
  end
@@ -0,0 +1,4 @@
1
+ # Example that will trigger the "mismatched indentations" warning from Ruby
2
+ if 2 > 1
3
+ true
4
+ end
@@ -6,8 +6,12 @@ require 'pathname'
6
6
  class WarningTest < Minitest::Test
7
7
  module EnvUtil
8
8
  def verbose_warning
9
+ stderr = ""
9
10
  class << (stderr = "")
10
11
  alias write <<
12
+ def puts(*a)
13
+ self << a.join("\n")
14
+ end
11
15
  end
12
16
  stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
13
17
  yield stderr
@@ -351,6 +355,18 @@ class WarningTest < Minitest::Test
351
355
  end
352
356
  end
353
357
 
358
+ def test_warning_ignore_mismatched_indentation
359
+ assert_warning(/warning: mismatched indentations/) do
360
+ load 'test/fixtures/mismatched_indentations.rb'
361
+ end
362
+
363
+ Warning.ignore(:mismatched_indentations, 'test/fixtures/mismatched_indentations.rb')
364
+
365
+ assert_warning '' do
366
+ load 'test/fixtures/mismatched_indentations.rb'
367
+ end
368
+ end
369
+
354
370
  def test_warning_process
355
371
  obj = Object.new
356
372
  warn = nil
@@ -414,4 +430,86 @@ class WarningTest < Minitest::Test
414
430
  assert_equal(4, warn.first)
415
431
  assert_match(/instance variable @ivar6 not initialized/, warn.last)
416
432
  end
433
+
434
+ def test_warning_process_block_return_default
435
+ w = nil
436
+ Warning.process(__FILE__) do |warning|
437
+ w = warning
438
+ :default
439
+ end
440
+
441
+ assert_warning(/instance variable @ivar not initialized/) do
442
+ ivar
443
+ end
444
+ assert_match(/instance variable @ivar not initialized/, w)
445
+ end
446
+
447
+ def test_warning_process_block_return_backtrace
448
+ w = nil
449
+ Warning.process(__FILE__) do |warning|
450
+ w = warning
451
+ :backtrace
452
+ end
453
+
454
+ assert_warning(/instance variable @ivar not initialized.*#{__FILE__}/m) do
455
+ ivar
456
+ end
457
+ assert_match(/instance variable @ivar not initialized/, w)
458
+ end
459
+
460
+ def test_warning_process_block_return_raise
461
+ w = nil
462
+ Warning.process(__FILE__) do |warning|
463
+ w = warning
464
+ :raise
465
+ end
466
+
467
+ assert_raises(RuntimeError, /instance variable @ivar not initialized/) do
468
+ EnvUtil.verbose_warning{ivar}
469
+ end
470
+ assert_match(/instance variable @ivar not initialized/, w)
471
+ end
472
+
473
+ def test_warning_process_action
474
+ w = nil
475
+ Warning.process(__FILE__, :missing_ivar=>:default, :missing_gvar=>:backtrace, :ambiguous_slash=>:raise)
476
+ Warning.process(__FILE__, :not_reached=>proc do |warning|
477
+ w = warning
478
+ :raise
479
+ end)
480
+
481
+ assert_warning(/instance variable @ivar not initialized/) do
482
+ ivar
483
+ end
484
+
485
+ assert_warning(/global variable `\$gvar' not initialized.*#{__FILE__}/m) do
486
+ $gvar
487
+ end
488
+
489
+ Warning.process(__FILE__) do |warning|
490
+ w = warning
491
+ :raise
492
+ end
493
+
494
+ assert_raises(RuntimeError, /warning: ambiguous first argument; put parentheses or a space even after `\/' operator/) do
495
+ EnvUtil.verbose_warning{instance_eval('d /a/', __FILE__)}
496
+ end
497
+
498
+ assert_raises(RuntimeError, /warning: statement not reached/) do
499
+ EnvUtil.verbose_warning{instance_eval('def self.b; return; 1 end', __FILE__)}
500
+ end
501
+ assert_match(/warning: statement not reached/, w)
502
+ end
503
+
504
+ def test_warning_process_action_and_block
505
+ assert_raises(ArgumentError) do
506
+ Warning.process(__FILE__)
507
+ end
508
+ end
509
+
510
+ def test_warning_process_no_action_and_no_block
511
+ assert_raises(ArgumentError) do
512
+ Warning.process(__FILE__, :missing_ivar=>:default){}
513
+ end
514
+ end
417
515
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: warning
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-21 00:00:00.000000000 Z
11
+ date: 2020-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest-global_expectations
@@ -27,8 +27,9 @@ dependencies:
27
27
  description: |
28
28
  ruby-warning adds custom processing for warnings, including the
29
29
  ability to ignore specific warning messages, ignore warnings
30
- in specific files/directories, and add custom handling for all
31
- warnings in specific files/directories.
30
+ in specific files/directories, include backtraces with warnings,
31
+ treat warnings as errors, deduplicate warnings, and add
32
+ custom handling for all warnings in specific files/directories.
32
33
  email: code@jeremyevans.net
33
34
  executables: []
34
35
  extensions: []
@@ -42,6 +43,7 @@ files:
42
43
  - README.rdoc
43
44
  - Rakefile
44
45
  - lib/warning.rb
46
+ - test/fixtures/mismatched_indentations.rb
45
47
  - test/test_freeze_warning.rb
46
48
  - test/test_warning.rb
47
49
  homepage: https://github.com/jeremyevans/ruby-warning