warning 0.9.0 → 1.2.0

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
- SHA1:
3
- metadata.gz: 70b1655bff238b444c9373002b6d1010812a9a71
4
- data.tar.gz: 2276292182d974e7fdb71802295ed1dc45771f82
2
+ SHA256:
3
+ metadata.gz: c2628e7956e2f0c2a7f55ef1d4397a1f1ff8339d48904b49fc16692934930464
4
+ data.tar.gz: 72b7fa93465fe52a2907ef2172d3c90694308af52bb2cd5b9117c6e7084419d1
5
5
  SHA512:
6
- metadata.gz: 6a512057f73e7f275e806a9e9442919e128c0edcf312e730b4787f9b9630c8f088bdfce0af7a7b7f9d6e3811aa94ae95211a4b13d205353e1853c20f2f5a0a4d
7
- data.tar.gz: 16e8d3da29e75c5c6f1dd70fede11564006ad30201923d8750aa0d383e77820fa4355c6fd6f6b44600bd276d9afd38706581c123c34898bbbf2534bb64cab5b3
6
+ metadata.gz: e8f95072982d387477121b90c13790876743d9a40a0a32c06a1ea72720b85c6d831c4dceff28445dd8be2a3ba6e915670b874a908e6b438cce40c83229f95a15
7
+ data.tar.gz: 3cf24b069bc071cdf425aad86fae1c0b37b3cf723ee8c365a09a183da7e3f737f7eb454f8b1fbc29be1a9651d01fd286e13562ea442c1ae57ca5fc2c045a7570
data/CHANGELOG CHANGED
@@ -1,3 +1,53 @@
1
+ === 1.2.0 (2021-02-16)
2
+
3
+ * Add support for :void_context as regexp argument to Warning.ignore (jeremyevans)
4
+
5
+ * Support :category keyword to Warning.warn on Ruby 3.0 (jeremyevans)
6
+
7
+ * Fix :taint warning handling on Ruby 3.0 (jeremyevans)
8
+
9
+ * Fix :ambiguous_slash warning handling on Ruby 3.0 (jeremyevans)
10
+
11
+ === 1.1.0 (2020-06-12)
12
+
13
+ * Allow Warning.process to be called with a hash of actions instead of a block (jeremyevans)
14
+
15
+ * Handle Warning.process blocks that return :default, :backtrace, or :raise specially (jeremyevans)
16
+
17
+ * Add support for :mismatched_indentations as regexp argument to Warning.ignore (qortex) (#7)
18
+
19
+ === 1.0.0 (2020-01-21)
20
+
21
+ * Add support for :taint as regexp argument to Warning.ignore (jeremyevans)
22
+
23
+ * Add support for :safe as regexp argument to Warning.ignore (jeremyevans)
24
+
25
+ * Add Warning.dedup for deduplicating warnings (jeremyevans)
26
+
27
+ * Add support for :keyword_separation as regexp argument to Warning.ignore (jeremyevans)
28
+
29
+ === 0.10.1 (2017-11-16)
30
+
31
+ * Correctly handle Warning.freeze (jeremyevans)
32
+
33
+ === 0.10.0 (2016-11-16)
34
+
35
+ * Add support for :arg_prefix and :shadow as regexp argument to Warning.ignore (jeremyevans)
36
+
37
+ * Add support for :useless_operator as regexp argument to Warning.ignore (jeremyevans)
38
+
39
+ * Add support for :missing_gvar as regexp argument to Warning.ignore (jeremyevans)
40
+
41
+ * Add support for :ambiguous_slash and :unused_var as regexp arguments to Warning.ignore (jeremyevans)
42
+
43
+ * Add support for :fixnum and :bignum as regexp arguments to Warning.ignore (jeremyevans)
44
+
45
+ * Add support for array of symbols as regexp argument to Warning.ignore (jeremyevans)
46
+
47
+ * Add support for :not_reached as regexp argument to Warning.ignore (jeremyevans)
48
+
49
+ * Add support for :missing_ivar and :method_redefined as regexp argument to Warning.ignore (jeremyevans)
50
+
1
51
  === 0.9.0 (2016-08-09)
2
52
 
3
53
  * Initial Public Release
data/MIT-LICENSE CHANGED
@@ -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
data/README.rdoc CHANGED
@@ -2,8 +2,9 @@
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, and add custom handling for all
6
- warnings in specific files/directories.
5
+ in specific files/directories, include backtraces with warnings,
6
+ treat warnings as errors, deduplicate warnings, and add
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
9
10
  not support custom processing of warnings.
@@ -23,7 +24,25 @@ warnings, it just adds methods that allow you to customize the processing.
23
24
 
24
25
  <tt>Warning.ignore</tt> takes a regexp and optionally a path prefix, and ignores
25
26
  any warning that matches the regular expression if it starts with the path
26
- prefix.
27
+ prefix. It can also take a symbol or an array of symbols, and will use an
28
+ appropriate regexp. The supported symbols are:
29
+
30
+ * :arg_prefix
31
+ * :ambiguous_slash
32
+ * :bignum
33
+ * :fixnum
34
+ * :keyword_separation
35
+ * :method_redefined
36
+ * :mismatched_indentations
37
+ * :missing_gvar
38
+ * :missing_ivar
39
+ * :not_reached
40
+ * :safe
41
+ * :shadow
42
+ * :taint
43
+ * :unused_var
44
+ * :useless_operator
45
+ * :void_context
27
46
 
28
47
  <tt>Warning.process</tt> takes an optional path prefix and a block, and if the
29
48
  warning string starts with the path prefix, it calls the block with the warning
@@ -31,15 +50,35 @@ string instead of performing the default behavior. You can call
31
50
  <tt>Warning.process</tt> multiple times and it will operate intelligently,
32
51
  choosing the longest path prefix that the string starts with.
33
52
 
34
- <tt>Warning.clear</tt> just clears the current ignored warnings and warning
35
- processors.
53
+ <tt>Warning.process</tt> blocks can return +:default+ to use the default
54
+ behavior, +:backtrace+ to use the default behavior and also print the backtrace
55
+ or +:raise+ to raise the warning string as a RuntimeError.
56
+
57
+ <tt>Warning.process</tt> can also accept a hash of actions instead of a block,
58
+ with keys being regexps (or symbols supported by <tt>Warning.ignore</tt>) and
59
+ values being callable objects (or +:default+, +:backtrace+, or +:raise+).
60
+
61
+ <tt>Warning.dedup</tt> deduplicates warnings, so that if a warning is received
62
+ that is the same as a warning that has already been processed, the warning is
63
+ ignored. Note that this should be used with care, since if the application
64
+ generates an arbitrary number of unique warnings, that can lead to unbounded
65
+ memory growth.
66
+
67
+ <tt>Warning.clear</tt> resets the library to its initial state, clearing the
68
+ current ignored warnings and warning processors, and turning off deduplication.
36
69
 
37
70
  By using path prefixes, it's fairly easy for a gem to set that specific warnings
38
71
  should be ignored inside the gem's directory.
39
72
 
40
73
  Note that path prefixes will not correctly handle warnings raised by
41
74
  <tt>Kernel#warn</tt>, unless the warning message given to <tt>Kernel#warn</tt>
42
- starts with the filename where the warning is used.
75
+ starts with the filename where the warning is used. The <tt>Kernel#warn</tt>
76
+ +:uplevel+ option will make sure the warning starts with the filename.
77
+
78
+ Note that many of the warnings this library can ignore are warnings caused
79
+ during compilation (i.e. when files are loaded via require). You should
80
+ require this library and setup the appropriate warning handling before
81
+ loading any code that could cause warnings.
43
82
 
44
83
  = Examples
45
84
 
@@ -49,6 +88,12 @@ starts with the filename where the warning is used.
49
88
  # Ignore all uninitialized instance variable warnings in current file
50
89
  Warning.ignore(/instance variable @\w+ not initialized/, __FILE__)
51
90
 
91
+ # Ignore all uninitialized instance variable warnings in current file
92
+ Warning.ignore(:missing_ivar, __FILE__)
93
+
94
+ # Ignore all Fixnum and Bignum warnings in current file
95
+ Warning.ignore([:fixnum, :bignum], __FILE__)
96
+
52
97
  # Write warning to LOGGER at level warning
53
98
  Warning.process do |warning|
54
99
  LOGGER.warning(warning)
@@ -59,6 +104,31 @@ starts with the filename where the warning is used.
59
104
  LOGGER.error(warning)
60
105
  end
61
106
 
107
+ # Write warnings in the current file to $stderr, but include backtrace
108
+ Warning.process(__FILE__) do |warning|
109
+ :backtrace
110
+ end
111
+
112
+ # Raise warnings in the current file as RuntimeErrors, with the warning
113
+ # string as the exception message
114
+ Warning.process(__FILE__) do |warning|
115
+ :raise
116
+ end
117
+
118
+ # Raise keyword argument separation warnings in the current file as
119
+ # RuntimeErrors, and write ambiguous slash warnings to $stderr, including
120
+ # the backtrace
121
+ Warning.process(__FILE__, keyword_separation: :raise,
122
+ ambiguous_slash: :backtrace)
123
+
124
+ # Deduplicate warnings
125
+ Warning.dedup
126
+
127
+ # Ignore all warnings in Gem dependencies
128
+ Gem.path.each do |path|
129
+ Warning.ignore(//, path)
130
+ end
131
+
62
132
  = License
63
133
 
64
134
  MIT
data/Rakefile CHANGED
@@ -15,11 +15,19 @@ end
15
15
  desc "Run test"
16
16
  Rake::TestTask.new do |t|
17
17
  t.libs.push "lib"
18
- t.test_files = FileList['test/test_*.rb']
18
+ t.test_files = FileList['test/test_warning.rb']
19
19
  t.verbose = true
20
20
  end
21
21
 
22
- task :default=>:test
22
+ desc "Run test"
23
+ Rake::TestTask.new(:test_freeze) do |t|
24
+ t.libs.push "lib"
25
+ t.test_files = FileList['test/test_freeze_warning.rb']
26
+ t.verbose = true
27
+ end
28
+
29
+ desc "Run all tests"
30
+ task :default=>[:test, :test_freeze]
23
31
 
24
32
  ### RDoc
25
33
 
data/lib/warning.rb CHANGED
@@ -2,23 +2,101 @@ require 'monitor'
2
2
 
3
3
  module Warning
4
4
  module Processor
5
- # Clear all current ignored warnings and warning processors.
5
+ # Map of symbols to regexps for warning messages to ignore.
6
+ IGNORE_MAP = {
7
+ ambiguous_slash: /: warning: ambiguous first argument; put parentheses or a space even after `\/' operator\n\z|: warning: ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `\/' operator\n\z/,
8
+ arg_prefix: /: warning: `[&\*]' interpreted as argument prefix\n\z/,
9
+ bignum: /: warning: constant ::Bignum is deprecated\n\z/,
10
+ fixnum: /: warning: constant ::Fixnum is deprecated\n\z/,
11
+ method_redefined: /: warning: method redefined; discarding old .+\n\z|: warning: previous definition of .+ was here\n\z/,
12
+ missing_gvar: /: warning: global variable `\$.+' not initialized\n\z/,
13
+ missing_ivar: /: warning: instance variable @.+ not initialized\n\z/,
14
+ not_reached: /: warning: statement not reached\n\z/,
15
+ shadow: /: warning: shadowing outer local variable - \w+\n\z/,
16
+ unused_var: /: warning: assigned but unused variable - \w+\n\z/,
17
+ useless_operator: /: warning: possibly useless use of [><!=]+ in void context\n\z/,
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
+ 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
+ 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/,
22
+ void_context: /possibly useless use of :: in void context/,
23
+ }
24
+
25
+ # Map of action symbols to procs that return the symbol
26
+ ACTION_PROC_MAP = {
27
+ default: proc{|_| :default},
28
+ backtrace: proc{|_| :backtrace},
29
+ raise: proc{|_| :raise},
30
+ }
31
+ private_constant :ACTION_PROC_MAP
32
+
33
+ # Clear all current ignored warnings, warning processors, and duplicate check cache.
34
+ # Also disables deduplicating warnings if that is currently enabled.
6
35
  def clear
7
36
  synchronize do
8
37
  @ignore.clear
9
38
  @process.clear
39
+ @dedup = false
10
40
  end
11
41
  end
42
+
43
+ # Deduplicate warnings, supress warning messages if the same warning message
44
+ # has already occurred. Note that this can lead to unbounded memory use
45
+ # if unique warnings are generated.
46
+ def dedup
47
+ @dedup = {}
48
+ end
49
+
50
+ def freeze
51
+ @ignore.freeze
52
+ @process.freeze
53
+ super
54
+ end
12
55
 
13
56
  # Ignore any warning messages matching the given regexp, if they
14
- # start with the given path. Examples:
57
+ # start with the given path.
58
+ # The regexp can also be one of the following symbols (or an array including them), which will
59
+ # use an appropriate regexp for the given warning:
60
+ #
61
+ # :arg_prefix :: Ignore warnings when using * or & as an argument prefix
62
+ # :ambiguous_slash :: Ignore warnings for things like <tt>method /regexp/</tt>
63
+ # :bignum :: Ignore warnings when referencing the ::Bignum constant.
64
+ # :fixnum :: Ignore warnings when referencing the ::Fixnum constant.
65
+ # :keyword_separation :: Ignore warnings related to keyword argument separation.
66
+ # :method_redefined :: Ignore warnings when defining a method in a class/module where a
67
+ # method of the same name was already defined in that class/module.
68
+ # :missing_gvar :: Ignore warnings for accesses to global variables
69
+ # that have not yet been initialized
70
+ # :missing_ivar :: Ignore warnings for accesses to instance variables
71
+ # that have not yet been initialized
72
+ # :not_reached :: Ignore statement not reached warnings.
73
+ # :safe :: Ignore warnings related to $SAFE and related C-API functions.
74
+ # :shadow :: Ignore warnings related to shadowing outer local variables.
75
+ # :taint :: Ignore warnings related to taint and related methods and C-API functions.
76
+ # :unused_var :: Ignore warnings for unused variables.
77
+ # :useless_operator :: Ignore warnings when using operators such as == and > when the
78
+ # result is not used.
79
+ # :void_context :: Ignore warnings for :: to reference constants when the result is not
80
+ # used (often used to trigger autoload).
81
+ #
82
+ # Examples:
15
83
  #
16
84
  # # Ignore all uninitialized instance variable warnings
17
85
  # Warning.ignore(/instance variable @\w+ not initialized/)
18
86
  #
19
87
  # # Ignore all uninitialized instance variable warnings in current file
20
88
  # Warning.ignore(/instance variable @\w+ not initialized/, __FILE__)
89
+ #
90
+ # # Ignore all uninitialized instance variable warnings in current file
91
+ # Warning.ignore(:missing_ivar, __FILE__)
92
+ #
93
+ # # Ignore all uninitialized instance variable and method redefined warnings in current file
94
+ # Warning.ignore([:missing_ivar, :method_redefined], __FILE__)
21
95
  def ignore(regexp, path='')
96
+ unless regexp = convert_regexp(regexp)
97
+ raise TypeError, "first argument to Warning.ignore should be Regexp, Symbol, or Array of Symbols, got #{regexp.inspect}"
98
+ end
99
+
22
100
  synchronize do
23
101
  @ignore << [path, regexp]
24
102
  end
@@ -37,7 +115,52 @@ module Warning
37
115
  # Warning.process(__FILE__) do |warning|
38
116
  # LOGGER.error(warning)
39
117
  # end
40
- def process(path='', &block)
118
+ #
119
+ # The block can return one of the following symbols:
120
+ #
121
+ # :default :: Take the default action (call super, printing to $stderr).
122
+ # :backtrace :: Take the default action (call super, printing to $stderr),
123
+ # and also print the backtrace.
124
+ # :raise :: Raise a RuntimeError with the warning as the message.
125
+ #
126
+ # If the block returns anything else, it is assumed the block completely handled
127
+ # the warning and takes no other action.
128
+ #
129
+ # Instead of passing a block, you can pass a hash of actions to take for specific
130
+ # warnings, using regexp as keys and a callable objects as values:
131
+ #
132
+ # Warning.process(__FILE__,
133
+ # /instance variable @\w+ not initialized/ => proc do |warning|
134
+ # LOGGER.warning(warning)
135
+ # end,
136
+ # /global variable `\$\w+' not initialized/ => proc do |warning|
137
+ # LOGGER.error(warning)
138
+ # end
139
+ # )
140
+ #
141
+ # Instead of passing a regexp as a key, you can pass a symbol that is recognized
142
+ # by Warning.ignore. Instead of passing a callable object as a value, you can
143
+ # pass a symbol, which will be treated as a callable object that returns that symbol:
144
+ #
145
+ # Warning.process(__FILE__, :missing_ivar=>:backtrace, :keyword_separation=>:raise)
146
+ def process(path='', actions=nil, &block)
147
+ if block
148
+ if actions
149
+ raise ArgumentError, "cannot pass both actions and block to Warning.process"
150
+ end
151
+ elsif actions
152
+ block = {}
153
+ actions.each do |regexp, value|
154
+ unless regexp = convert_regexp(regexp)
155
+ raise TypeError, "action provided to Warning.process should be Regexp, Symbol, or Array of Symbols, got #{regexp.inspect}"
156
+ end
157
+
158
+ block[regexp] = ACTION_PROC_MAP[value] || value
159
+ end
160
+ else
161
+ raise ArgumentError, "must pass either actions or block to Warning.process"
162
+ end
163
+
41
164
  synchronize do
42
165
  @process << [path, block]
43
166
  @process.sort_by!(&:first)
@@ -46,30 +169,89 @@ module Warning
46
169
  nil
47
170
  end
48
171
 
49
- # Handle ignored warnings and warning processors. If the warning is
50
- # not ignored and there is no warning processor setup for the warning
51
- # string, then use the default behavior of writing to $stderr.
52
- def warn(str)
53
- synchronize{@ignore.dup}.each do |path, regexp|
54
- if str.start_with?(path) && str =~ regexp
55
- return
172
+
173
+ if RUBY_VERSION >= '3.0'
174
+ method_args = ', category: nil'
175
+ super_ = "category ? super : super(str)"
176
+ else
177
+ super_ = "super"
178
+ end
179
+
180
+ class_eval(<<-END, __FILE__, __LINE__+1)
181
+ def warn(str#{method_args})
182
+ synchronize{@ignore.dup}.each do |path, regexp|
183
+ if str.start_with?(path) && str =~ regexp
184
+ return
185
+ end
56
186
  end
57
- end
58
187
 
59
- synchronize{@process.dup}.each do |path, block|
60
- if str.start_with?(path)
61
- block.call(str)
62
- return
188
+ if @dedup
189
+ if synchronize{@dedup[str]}
190
+ return
191
+ end
192
+
193
+ synchronize{@dedup[str] = true}
63
194
  end
195
+
196
+ action = catch(:action) do
197
+ synchronize{@process.dup}.each do |path, block|
198
+ if str.start_with?(path)
199
+ if block.is_a?(Hash)
200
+ block.each do |regexp, blk|
201
+ if str =~ regexp
202
+ throw :action, blk.call(str)
203
+ end
204
+ end
205
+ else
206
+ throw :action, block.call(str)
207
+ end
208
+ end
209
+ end
210
+
211
+ :default
212
+ end
213
+
214
+ case action
215
+ when :default
216
+ #{super_}
217
+ when :backtrace
218
+ #{super_}
219
+ $stderr.puts caller
220
+ when :raise
221
+ raise str
222
+ else
223
+ # nothing
224
+ end
225
+
226
+ nil
64
227
  end
228
+ END
65
229
 
66
- super
230
+ private
231
+
232
+ # Convert the given Regexp, Symbol, or Array of Symbols into a Regexp.
233
+ def convert_regexp(regexp)
234
+ case regexp
235
+ when Regexp
236
+ regexp
237
+ when Symbol
238
+ IGNORE_MAP.fetch(regexp)
239
+ when Array
240
+ Regexp.union(regexp.map{|re| IGNORE_MAP.fetch(re)})
241
+ else
242
+ # nothing
243
+ end
244
+ end
245
+
246
+ def synchronize(&block)
247
+ @monitor.synchronize(&block)
67
248
  end
68
249
  end
69
250
 
70
251
  @ignore = []
71
252
  @process = []
253
+ @dedup = false
254
+ @monitor = Monitor.new
72
255
 
73
- extend MonitorMixin
74
256
  extend Processor
75
257
  end
@@ -0,0 +1,4 @@
1
+ # Example that will trigger the "mismatched indentations" warning from Ruby
2
+ if 2 > 1
3
+ true
4
+ end
@@ -0,0 +1,69 @@
1
+ ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
2
+ require 'minitest/global_expectations/autorun'
3
+ require 'warning'
4
+
5
+ class WarningFreezeTest < Minitest::Test
6
+ module EnvUtil
7
+ def verbose_warning
8
+ class << (stderr = "")
9
+ alias write <<
10
+ end
11
+ stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
12
+ yield stderr
13
+ return $stderr
14
+ ensure
15
+ stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
16
+ end
17
+ module_function :verbose_warning
18
+
19
+ def with_default_internal(enc)
20
+ verbose, $VERBOSE = $VERBOSE, nil
21
+ origenc, Encoding.default_internal = Encoding.default_internal, enc
22
+ $VERBOSE = verbose
23
+ yield
24
+ ensure
25
+ verbose, $VERBOSE = $VERBOSE, nil
26
+ Encoding.default_internal = origenc
27
+ $VERBOSE = verbose
28
+ end
29
+ module_function :with_default_internal
30
+ end
31
+
32
+ def assert_warning(pat, msg = nil)
33
+ stderr = EnvUtil.verbose_warning {
34
+ EnvUtil.with_default_internal(pat.encoding) {
35
+ yield
36
+ }
37
+ }
38
+ msg = message(msg) {diff pat, stderr}
39
+ assert(pat === stderr, msg)
40
+ end
41
+
42
+ def test_warning_ignore
43
+ w = nil
44
+
45
+ Warning.ignore(/global variable `\$test_warning_ignore' not initialized/)
46
+ Warning.process do |warning|
47
+ w = [4, warning]
48
+ end
49
+ Warning.freeze
50
+
51
+ assert_raises RuntimeError do
52
+ Warning.ignore(/global variable `\$test_warning_ignore' not initialized/)
53
+ end
54
+ assert_raises RuntimeError do
55
+ Warning.process{|warning| w = [4, warning]}
56
+ end
57
+
58
+ assert_warning '' do
59
+ $test_warning_ignore
60
+ end
61
+ assert_nil w
62
+
63
+ assert_warning '' do
64
+ $test_warning_ignore2
65
+ end
66
+ assert_equal(4, w.first)
67
+ assert_match(/global variable `\$test_warning_ignore2' not initialized/, w.last)
68
+ end
69
+ end
data/test/test_warning.rb CHANGED
@@ -1,11 +1,17 @@
1
- require 'minitest/unit'
2
- require 'minitest/autorun'
1
+ ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
2
+ require 'minitest/global_expectations/autorun'
3
+ require 'warning'
4
+ require 'pathname'
3
5
 
4
6
  class WarningTest < Minitest::Test
5
7
  module EnvUtil
6
8
  def verbose_warning
9
+ stderr = ""
7
10
  class << (stderr = "")
8
11
  alias write <<
12
+ def puts(*a)
13
+ self << a.join("\n")
14
+ end
9
15
  end
10
16
  stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
11
17
  yield stderr
@@ -38,66 +44,344 @@ class WarningTest < Minitest::Test
38
44
  assert(pat === stderr, msg)
39
45
  end
40
46
 
41
- def test_warning_ignore
42
- obj = Object.new
47
+ def teardown
48
+ Warning.clear
49
+ end
43
50
 
44
- assert_warning /instance variable @ivar not initialized/ do
45
- assert_nil(obj.instance_variable_get(:@ivar))
51
+ def test_warning_dedup
52
+ gvar = ->{$test_warning_dedup}
53
+
54
+ assert_warning(/global variable `\$test_warning_dedup' not initialized/) do
55
+ gvar.call
56
+ end
57
+ assert_warning(/global variable `\$test_warning_dedup' not initialized/) do
58
+ gvar.call
46
59
  end
47
60
 
48
- require 'warning'
61
+ Warning.dedup
62
+
63
+ assert_warning(/global variable `\$test_warning_dedup' not initialized/) do
64
+ gvar.call
65
+ end
66
+ assert_warning('') do
67
+ gvar.call
68
+ end
69
+ end
49
70
 
50
- assert_warning /instance variable @ivar not initialized/ do
51
- assert_nil(obj.instance_variable_get(:@ivar))
71
+ def test_warning_ignore
72
+ assert_warning(/global variable `\$test_warning_ignore' not initialized/) do
73
+ assert_nil($test_warning_ignore)
52
74
  end
53
75
 
54
- Warning.ignore(/instance variable @ivar not initialized/)
76
+ Warning.ignore(/global variable `\$test_warning_ignore' not initialized/)
55
77
 
56
78
  assert_warning '' do
57
- assert_nil(obj.instance_variable_get(:@ivar))
79
+ assert_nil($test_warning_ignore)
58
80
  end
59
81
 
60
- assert_warning /instance variable @ivar2 not initialized/ do
61
- assert_nil(obj.instance_variable_get(:@ivar2))
82
+ assert_warning(/global variable `\$test_warning_ignore2' not initialized/) do
83
+ assert_nil($test_warning_ignore2)
62
84
  end
63
85
 
64
- Warning.ignore(/instance variable @ivar2 not initialized/, __FILE__)
86
+ Warning.ignore(/global variable `\$test_warning_ignore2' not initialized/, __FILE__)
65
87
 
66
88
  assert_warning '' do
67
- assert_nil(obj.instance_variable_get(:@ivar2))
89
+ assert_nil($test_warning_ignore2)
68
90
  end
69
91
 
70
- assert_warning /instance variable @ivar3 not initialized/ do
71
- assert_nil(obj.instance_variable_get(:@ivar3))
92
+ assert_warning(/global variable `\$test_warning_ignore3' not initialized/) do
93
+ assert_nil($test_warning_ignore3)
72
94
  end
73
95
 
74
- Warning.ignore(/instance variable @ivar3 not initialized/, __FILE__+'a')
96
+ Warning.ignore(/global variable `\$test_warning_ignore3' not initialized/, __FILE__ + 'a')
75
97
 
76
- assert_warning /instance variable @ivar3 not initialized/ do
77
- assert_nil(obj.instance_variable_get(:@ivar3))
98
+ assert_warning(/global variable `\$test_warning_ignore3' not initialized/) do
99
+ assert_nil($test_warning_ignore3)
78
100
  end
101
+ end
79
102
 
103
+ def test_warning_ignore_missing_ivar
80
104
  Warning.clear
81
105
 
82
- assert_warning /instance variable @ivar not initialized/ do
83
- assert_nil(obj.instance_variable_get(:@ivar))
106
+ unless RUBY_VERSION >= '3.0'
107
+ assert_warning(/instance variable @ivar not initialized/) do
108
+ assert_nil(instance_variable_get(:@ivar))
109
+ end
110
+ end
111
+
112
+ Warning.ignore(:missing_ivar, __FILE__)
113
+
114
+ assert_warning '' do
115
+ assert_nil(instance_variable_get(:@ivar))
116
+ end
117
+ end
118
+
119
+ def test_warning_ignore_missing_gvar
120
+ assert_warning(/global variable `\$gvar' not initialized/) do
121
+ $gvar
122
+ end
123
+
124
+ Warning.ignore(:missing_gvar, __FILE__)
125
+
126
+ assert_warning '' do
127
+ $gvar
128
+ end
129
+ end
130
+
131
+ def test_warning_ignore_method_redefined
132
+ def self.a; end
133
+
134
+ assert_warning(/method redefined; discarding old a.+previous definition of a was here/m) do
135
+ def self.a; end
136
+ end
137
+
138
+ Warning.ignore(:method_redefined, __FILE__)
139
+
140
+ assert_warning '' do
141
+ def self.a; end
142
+ end
143
+ end
144
+
145
+ def test_warning_ignore_not_reached
146
+ assert_warning(/: warning: statement not reached/) do
147
+ instance_eval('def self.b; return; 1 end', __FILE__)
148
+ end
149
+
150
+ Warning.ignore(:not_reached, __FILE__)
151
+
152
+ assert_warning '' do
153
+ instance_eval('def self.c; return; 1 end', __FILE__)
154
+ end
155
+ end
156
+
157
+ def test_warning_ignore_fixnum
158
+ assert_warning(/warning: constant ::Fixnum is deprecated/) do
159
+ ::Fixnum
160
+ end
161
+
162
+ Warning.ignore(:fixnum, __FILE__)
163
+
164
+ assert_warning '' do
165
+ ::Fixnum
166
+ end
167
+ end
168
+
169
+ def test_warning_ignore_bignum
170
+ assert_warning(/warning: constant ::Bignum is deprecated/) do
171
+ ::Bignum
172
+ end
173
+
174
+ Warning.ignore(:bignum, __FILE__)
175
+
176
+ assert_warning '' do
177
+ ::Bignum
178
+ end
179
+ end
180
+
181
+ def test_warning_ignore_void_context
182
+ assert_warning(/warning: possibly useless use of :: in void context/) do
183
+ instance_eval('::Object; nil', __FILE__, __LINE__)
184
+ end
185
+
186
+ Warning.ignore(:void_context, __FILE__)
187
+
188
+ assert_warning '' do
189
+ instance_eval('::Object; nil', __FILE__, __LINE__)
190
+ end
191
+ end
192
+
193
+ def test_warning_ignore_ambiguous_slash
194
+ def self.d(re); end
195
+ assert_warning(/warning: ambi/) do
196
+ instance_eval('d /a/', __FILE__)
197
+ end
198
+
199
+ Warning.ignore(:ambiguous_slash, __FILE__)
200
+
201
+ assert_warning '' do
202
+ instance_eval('d /a/', __FILE__)
203
+ end
204
+ end
205
+
206
+ def test_warning_ignore_unused_var
207
+ assert_warning(/warning: assigned but unused variable - \w+/) do
208
+ instance_eval('def self.e; b = 1; 2 end', __FILE__)
209
+ end
210
+
211
+ Warning.ignore(:unused_var, __FILE__)
212
+
213
+ assert_warning '' do
214
+ instance_eval('def self.f; b = 1; 2 end', __FILE__)
215
+ end
216
+ end
217
+
218
+ def test_warning_ignore_useless_operator
219
+ assert_warning(/warning: possibly useless use of == in void context/) do
220
+ instance_eval('1 == 2; true', __FILE__)
221
+ end
222
+
223
+ Warning.ignore(:useless_operator, __FILE__)
224
+
225
+ assert_warning '' do
226
+ instance_eval('1 == 2; true', __FILE__)
227
+ end
228
+ end
229
+
230
+ def test_warning_ignore_arg_prefix
231
+ assert_warning(/: warning: `\*' interpreted as argument prefix/) do
232
+ instance_eval('Array *[nil]', __FILE__)
233
+ end
234
+
235
+ assert_warning(/: warning: `&' interpreted as argument prefix/) do
236
+ instance_eval('tap &proc{}', __FILE__)
237
+ end
238
+ Warning.ignore(:arg_prefix, __FILE__)
239
+
240
+ assert_warning '' do
241
+ instance_eval('Array *[nil]', __FILE__)
242
+ instance_eval('tap &proc{}', __FILE__)
243
+ end
244
+ end
245
+
246
+ def test_warning_ignore_shadow
247
+ assert_warning(/warning: shadowing outer local variable - a/) do
248
+ instance_eval('lambda{|a| lambda{|a|}}', __FILE__)
249
+ end
250
+
251
+ Warning.ignore(:shadow, __FILE__)
252
+
253
+ assert_warning '' do
254
+ instance_eval('lambda{|a| lambda{|a|}}', __FILE__)
255
+ end
256
+ end if RUBY_VERSION < '2.6'
257
+
258
+ if RUBY_VERSION > '2.7' && RUBY_VERSION < '2.8'
259
+ def h2kw(**kw)
260
+ end
261
+ def kw2h(h, **kw)
262
+ end
263
+ def skw(h=1, a: 1)
264
+ end
265
+
266
+ def test_warning_ignore_keyword
267
+ assert_warning(/warning: Using the last argument as keyword parameters is deprecated; maybe \*\* should be added to the call.*The called method `h2kw' is defined here/m) do
268
+ h2kw({})
269
+ end
270
+ assert_warning(/warning: Passing the keyword argument as the last hash parameter is deprecated.*The called method `kw2h' is defined here/m) do
271
+ kw2h(a: 1)
272
+ end
273
+ assert_warning(/warning: Splitting the last argument into positional and keyword parameters is deprecated.*The called method `skw' is defined here/m) do
274
+ skw("b" => 1, a: 2)
275
+ end
276
+ assert_warning(/warning: Splitting the last argument into positional and keyword parameters is deprecated.*The called method `skw' is defined here/m) do
277
+ skw({"b" => 1, a: 2})
278
+ end
279
+
280
+ Warning.ignore(:keyword_separation, __FILE__)
281
+
282
+ assert_warning '' do
283
+ h2kw({})
284
+ kw2h(a: 1)
285
+ skw("b" => 1, a: 2)
286
+ skw({"b" => 1, a: 2})
287
+ end
288
+ end
289
+
290
+ def test_warning_ignore_safe
291
+ assert_warning(/\$SAFE will become a normal global variable in Ruby 3\.0/) do
292
+ $SAFE = 0
293
+ end
294
+
295
+ Warning.ignore(:safe, __FILE__)
296
+
297
+ assert_warning("") do
298
+ $SAFE = 0
299
+ end
300
+ end
301
+ end
302
+
303
+ if RUBY_VERSION > '2.7' && RUBY_VERSION < '3.2'
304
+
305
+ def test_warning_ignore_taint
306
+ o = Object.new
307
+
308
+ assert_warning(/Object#taint is deprecated and will be removed in Ruby 3\.2/) do
309
+ o.taint
310
+ end
311
+ assert_warning(/Object#untaint is deprecated and will be removed in Ruby 3\.2/) do
312
+ o.untaint
313
+ end
314
+ assert_warning(/Object#tainted\? is deprecated and will be removed in Ruby 3\.2/) do
315
+ o.tainted?
316
+ end
317
+ assert_warning(/Object#trust is deprecated and will be removed in Ruby 3\.2/) do
318
+ o.trust
319
+ end
320
+ assert_warning(/Object#untrust is deprecated and will be removed in Ruby 3\.2/) do
321
+ o.untrust
322
+ end
323
+ assert_warning(/Object#untrusted\? is deprecated and will be removed in Ruby 3\.2/) do
324
+ o.untrusted?
325
+ end
326
+
327
+ path = Pathname.new(__FILE__)
328
+ assert_warning(/Pathname#taint is deprecated and will be removed in Ruby 3\.2/) do
329
+ path.taint
330
+ end
331
+ assert_warning(/Pathname#untaint is deprecated and will be removed in Ruby 3\.2/) do
332
+ path.untaint
333
+ end
334
+
335
+ Warning.ignore(:taint, __FILE__)
336
+
337
+ assert_warning("") do
338
+ o.taint
339
+ o.untaint
340
+ o.tainted?
341
+ o.trust
342
+ o.untrust
343
+ o.untrusted?
344
+ p.taint
345
+ p.untaint
346
+ end
347
+ end
348
+ end
349
+
350
+ def test_warning_ignore_symbol_array
351
+ def self.c; end
352
+
353
+ assert_warning(/statement not reached.+method redefined; discarding old c.+previous definition of c was here/m) do
354
+ instance_eval('def self.c; return; 1 end', __FILE__)
355
+ end
356
+
357
+ Warning.ignore([:method_redefined, :not_reached], __FILE__)
358
+
359
+ assert_warning '' do
360
+ instance_eval('def self.c; return; 1 end', __FILE__)
361
+ end
362
+ end
363
+
364
+ def test_warning_ignore_mismatched_indentation
365
+ assert_warning(/warning: mismatched indentations/) do
366
+ load 'test/fixtures/mismatched_indentations.rb'
367
+ end
368
+
369
+ Warning.ignore(:mismatched_indentations, 'test/fixtures/mismatched_indentations.rb')
370
+
371
+ assert_warning '' do
372
+ load 'test/fixtures/mismatched_indentations.rb'
84
373
  end
85
- ensure
86
- Warning.clear
87
374
  end
88
375
 
89
376
  def test_warning_process
90
- obj = Object.new
91
377
  warn = nil
92
378
 
93
- require 'warning'
94
-
95
379
  Warning.process(__FILE__+'a') do |warning|
96
380
  warn = [0, warning]
97
381
  end
98
382
 
99
- assert_warning /instance variable @ivar not initialized/ do
100
- assert_nil(obj.instance_variable_get(:@ivar))
383
+ assert_warning(/global variable `\$test_warning_process' not initialized/) do
384
+ $test_warning_process
101
385
  end
102
386
  assert_nil(warn)
103
387
 
@@ -106,10 +390,10 @@ class WarningTest < Minitest::Test
106
390
  end
107
391
 
108
392
  assert_warning '' do
109
- assert_nil(obj.instance_variable_get(:@ivar2))
393
+ $test_warning_process2
110
394
  end
111
395
  assert_equal(1, warn.first)
112
- assert_match(/instance variable @ivar2 not initialized/, warn.last)
396
+ assert_match(/global variable `\$test_warning_process2' not initialized/, warn.last)
113
397
  warn = nil
114
398
 
115
399
  Warning.process(File.dirname(__FILE__)) do |warning|
@@ -117,10 +401,10 @@ class WarningTest < Minitest::Test
117
401
  end
118
402
 
119
403
  assert_warning '' do
120
- assert_nil(obj.instance_variable_get(:@ivar3))
404
+ $test_warning_process3
121
405
  end
122
406
  assert_equal(1, warn.first)
123
- assert_match(/instance variable @ivar3 not initialized/, warn.last)
407
+ assert_match(/global variable `\$test_warning_process3' not initialized/, warn.last)
124
408
  warn = nil
125
409
 
126
410
  Warning.process(__FILE__+':') do |warning|
@@ -128,16 +412,16 @@ class WarningTest < Minitest::Test
128
412
  end
129
413
 
130
414
  assert_warning '' do
131
- assert_nil(obj.instance_variable_get(:@ivar4))
415
+ $test_warning_process4
132
416
  end
133
417
  assert_equal(3, warn.first)
134
- assert_match(/instance variable @ivar4 not initialized/, warn.last)
418
+ assert_match(/global variable `\$test_warning_process4' not initialized/, warn.last)
135
419
  warn = nil
136
420
 
137
421
  Warning.clear
138
422
 
139
- assert_warning /instance variable @ivar5 not initialized/ do
140
- assert_nil(obj.instance_variable_get(:@ivar5))
423
+ assert_warning(/global variable `\$test_warning_process5' not initialized/) do
424
+ $test_warning_process5
141
425
  end
142
426
  assert_nil(warn)
143
427
 
@@ -146,11 +430,102 @@ class WarningTest < Minitest::Test
146
430
  end
147
431
 
148
432
  assert_warning '' do
149
- assert_nil(obj.instance_variable_get(:@ivar6))
433
+ $test_warning_process6
150
434
  end
151
435
  assert_equal(4, warn.first)
152
- assert_match(/instance variable @ivar6 not initialized/, warn.last)
153
- ensure
154
- Warning.clear
436
+ assert_match(/global variable `\$test_warning_process6' not initialized/, warn.last)
437
+ end
438
+
439
+ def test_warning_process_block_return_default
440
+ w = nil
441
+ Warning.process(__FILE__) do |warning|
442
+ w = warning
443
+ :default
444
+ end
445
+
446
+ assert_warning(/global variable `\$test_warning_process_block_return_default' not initialized/) do
447
+ $test_warning_process_block_return_default
448
+ end
449
+ assert_match(/global variable `\$test_warning_process_block_return_default' not initialized/, w)
450
+ end
451
+
452
+ def test_warning_process_block_return_backtrace
453
+ w = nil
454
+ Warning.process(__FILE__) do |warning|
455
+ w = warning
456
+ :backtrace
457
+ end
458
+
459
+ assert_warning(/global variable `\$test_warning_process_block_return_backtrace' not initialized.*#{__FILE__}/m) do
460
+ $test_warning_process_block_return_backtrace
461
+ end
462
+ assert_match(/global variable `\$test_warning_process_block_return_backtrace' not initialized/, w)
463
+ end
464
+
465
+ def test_warning_process_block_return_raise
466
+ w = nil
467
+ Warning.process(__FILE__) do |warning|
468
+ w = warning
469
+ :raise
470
+ end
471
+
472
+ assert_raises(RuntimeError) do
473
+ $test_warning_process_block_return_raise
474
+ end
475
+ assert_match(/global variable `\$test_warning_process_block_return_raise' not initialized/, w)
476
+ end
477
+
478
+ def test_warning_process_action
479
+ w = nil
480
+ Warning.process(__FILE__, :method_redefined=>:default, :missing_gvar=>:backtrace, :ambiguous_slash=>:raise)
481
+ Warning.process(__FILE__, :not_reached=>proc do |warning|
482
+ w = warning
483
+ :raise
484
+ end)
485
+
486
+ assert_warning(/warning: method redefined/) do
487
+ Class.new do
488
+ def a; end
489
+ def a; end
490
+ end
491
+ end
492
+
493
+ assert_warning(/global variable `\$test_warning_process_action' not initialized.*#{__FILE__}/m) do
494
+ $test_warning_process_action
495
+ end
496
+
497
+ Warning.process(__FILE__) do |warning|
498
+ w = warning
499
+ :raise
500
+ end
501
+
502
+ assert_raises(RuntimeError, /warning: ambi/) do
503
+ EnvUtil.verbose_warning{instance_eval('d /a/', __FILE__)}
504
+ end
505
+
506
+ assert_raises(RuntimeError, /warning: statement not reached/) do
507
+ EnvUtil.verbose_warning{instance_eval('def self.b; return; 1 end', __FILE__)}
508
+ end
509
+ assert_match(/warning: statement not reached/, w)
510
+ end
511
+
512
+ def test_warning_process_action_and_block
513
+ assert_raises(ArgumentError) do
514
+ Warning.process(__FILE__)
515
+ end
516
+ end
517
+
518
+ def test_warning_process_no_action_and_no_block
519
+ assert_raises(ArgumentError) do
520
+ Warning.process(__FILE__, :missing_ivar=>:default){}
521
+ end
522
+ end
523
+
524
+ if RUBY_VERSION >= '3.0'
525
+ def test_warning_warn_category_keyword
526
+ assert_warning('foo') do
527
+ Warning.warn("foo", category: :deprecated)
528
+ end
529
+ end
155
530
  end
156
531
  end
metadata CHANGED
@@ -1,20 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: warning
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 1.2.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: 2016-08-09 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest-global_expectations
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description: |
14
28
  ruby-warning adds custom processing for warnings, including the
15
29
  ability to ignore specific warning messages, ignore warnings
16
- in specific files/directories, and add custom handling for all
17
- 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.
18
33
  email: code@jeremyevans.net
19
34
  executables: []
20
35
  extensions: []
@@ -28,11 +43,17 @@ files:
28
43
  - README.rdoc
29
44
  - Rakefile
30
45
  - lib/warning.rb
46
+ - test/fixtures/mismatched_indentations.rb
47
+ - test/test_freeze_warning.rb
31
48
  - test/test_warning.rb
32
49
  homepage: https://github.com/jeremyevans/ruby-warning
33
50
  licenses:
34
51
  - MIT
35
- metadata: {}
52
+ metadata:
53
+ bug_tracker_uri: https://github.com/jeremyevans/ruby-warning/issues
54
+ changelog_uri: https://github.com/jeremyevans/ruby-warning/blob/master/CHANGELOG
55
+ documentation_uri: https://github.com/jeremyevans/ruby-warning/blob/master/README.rdoc
56
+ source_code_uri: https://github.com/jeremyevans/ruby-warning
36
57
  post_install_message:
37
58
  rdoc_options:
38
59
  - "--quiet"
@@ -48,15 +69,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
48
69
  requirements:
49
70
  - - ">="
50
71
  - !ruby/object:Gem::Version
51
- version: '2.4'
72
+ version: 2.4.0
52
73
  required_rubygems_version: !ruby/object:Gem::Requirement
53
74
  requirements:
54
75
  - - ">="
55
76
  - !ruby/object:Gem::Version
56
77
  version: '0'
57
78
  requirements: []
58
- rubyforge_project:
59
- rubygems_version: 2.5.1
79
+ rubygems_version: 3.2.3
60
80
  signing_key:
61
81
  specification_version: 4
62
82
  summary: Add custom processing for warnings