diff --git a/.travis.yml b/.travis.yml index cec065e..c9af5c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,8 @@ language: ruby rvm: - - "2.0.0" - - "2.1" - - "2.2" - - "2.3" - "2.4" - "2.5" + - "2.6" - ruby-head matrix: allow_failures: diff --git a/Readme.md b/Readme.md index 89d29ef..d6f2680 100644 --- a/Readme.md +++ b/Readme.md @@ -9,7 +9,7 @@ With the help of this gem you can filter out all those useless messages and only Add to your Gemfile: ```ruby -gem "ruby_warning_filter", "~> 1.0.0" +gem "ruby_warning_filter", "~> 1.1.0" ``` Put the following code somewhere before your project is loaded. In a Rails application, a good place would be at the end of "config/boot.rb". @@ -28,4 +28,4 @@ The filter works by proxying all writes to stderr. It has been running for a whi [![Build Status](https://travis-ci.org/semaperepelitsa/ruby_warning_filter.svg?branch=master)](https://travis-ci.org/semaperepelitsa/ruby_warning_filter) -The gem is tested against Ruby versions 2.5 down to 2.0. +The gem is tested against Ruby 2.6, 2.5, 2.4. diff --git a/lib/ruby_warning_filter.rb b/lib/ruby_warning_filter.rb index 08e0d0f..b69954f 100644 --- a/lib/ruby_warning_filter.rb +++ b/lib/ruby_warning_filter.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require "delegate" require "set" @@ -20,67 +21,51 @@ # class RubyWarningFilter < DelegateClass(IO) attr_reader :ruby_warnings + BACKTRACE = "\tfrom" + RUBY_WARNING = %r{(^
|\.bundle|:\d+|:in `\S+'): warning:} + EVAL_REDEFINED = /\(eval\):\d+: warning: previous definition of .+ was here/ + + # Variables used in tag attributes (Slim) always cause a warning. + # TODO: Report this. + IGNORED_TEMPLATE_WARNING = %r{\.slim:\d+: warning: possibly useless use of a variable in void context$} + + # The source of this warning cannot be located so we have to ignore it completely + # See example: https://github.com/deivid-rodriguez/pry-byebug/issues/221 + IGNORED_EVAL_WARNING = %r{^
(:\d+)?: warning: .+ in eval may not return location in binding; use Binding#source_location instead$} def initialize(io, ignore_path: Gem.path) super(io) @ruby_warnings = 0 @ignored = false - @ignore_path = ignore_path.to_set # Gem path can contain symlinks. # Some warnings use real path instead of symlinks so we need to ignore both. - ignore_path.each do |a| - @ignore_path << File.realpath(a) if File.exist?(a) - end + ignore_full_path = ignore_path + ignore_path.select{ |a| File.exist?(a) }.map{ |a| File.realpath(a) } + @ignore_regexp = Regexp.new("^(#{Regexp.union(ignore_full_path).source})") end def write(line) - if @ignored && (backtrace?(line) || line == "\n") + if @ignored && (line == "\n" || line.start_with?(BACKTRACE)) # Ignore the whole backtrace after ignored warning. # Some warnings write newline separately for some reason. @ignored = true nil - elsif @ignored && eval_redefined?(line) + elsif @ignored && EVAL_REDEFINED.match?(line) # Some gems use eval to redefine methods and the second warning with the source does not have file path, so we need to ignore that explicitly. @ignored = false nil - elsif ruby_warning?(line) - @ignored = ignored_warning?(line) + elsif RUBY_WARNING.match?(line) + @ignored = IGNORED_TEMPLATE_WARNING.match?(line) || + IGNORED_EVAL_WARNING.match?(line) || + @ignore_regexp.match?(line) unless @ignored @ruby_warnings += 1 super end else + @ignored = false super end end - - private - - def ruby_warning?(line) - line =~ %r{:(\d+|in `\S+'): warning:} - end - - def ignored_warning?(line) - external_warning?(line) || ignored_template_warning?(line) - end - - def external_warning?(line) - @ignore_path.any?{ |path| line.start_with?(path) } - end - - # Variables used in tag attributes (Slim) always cause a warning. - # TODO: Report this. - def ignored_template_warning?(line) - line =~ %r{\.slim:\d+: warning: possibly useless use of a variable in void context$} - end - - def backtrace?(line) - line.start_with?("\tfrom") - end - - def eval_redefined?(line) - line =~ /\(eval\):\d+: warning: previous definition of .+ was here/ - end end diff --git a/ruby_warning_filter.gemspec b/ruby_warning_filter.gemspec index 37ca1a2..dceee22 100644 --- a/ruby_warning_filter.gemspec +++ b/ruby_warning_filter.gemspec @@ -1,10 +1,11 @@ Gem::Specification.new do |gem| gem.name = "ruby_warning_filter" - gem.version = "1.0.1" + gem.version = "1.1.0" gem.summary = "Hassle-free Ruby warnings" gem.license = "MIT" - gem.author = "Semyon Perepelitsa" + gem.author = "Simon Perepelitsa" gem.email = "sema@sema.in" + gem.required_ruby_version = '>= 2.4.0' gem.homepage = "https://github.com/semaperepelitsa/ruby_warning_filter" diff --git a/test/bench.rb b/test/bench.rb index 0c9f5af..c3721c4 100644 --- a/test/bench.rb +++ b/test/bench.rb @@ -10,20 +10,22 @@ def write_errors(io) io.write("/path/to/gems/file.rb:297: warning: instance variable @object not initialized\n") end - 10.times do |i| + 7.times do |i| io.write("\tfrom /something/foo/bar:#{i}:in `
'") + io.write("\n") end - 10.times do + 7.times do io.write("(eval):1: warning: previous definition of foo was here") + io.write("\n") end end # Sample results in Ruby 2.3.1: # -# plain File 80.673k (± 2.5%) i/s - 410.454k in 5.091134s -# RubyWarningFilter 11.934k (± 4.7%) i/s - 59.721k in 5.017126s +# plain File 81.435k (± 2.5%) i/s - 411.632k in 5.057905s +# RubyWarningFilter 41.323k (± 2.5%) i/s - 210.236k in 5.090913s Benchmark.ips do |x| x.report "plain File" do write_errors(file) @@ -33,5 +35,3 @@ def write_errors(io) write_errors(filter) end end - - diff --git a/test/ruby_warnings_filter_test.rb b/test/ruby_warnings_filter_test.rb index 943d720..71fbb0b 100644 --- a/test/ruby_warnings_filter_test.rb +++ b/test/ruby_warnings_filter_test.rb @@ -15,7 +15,8 @@ def setup def test_no_effect assert_equal 0, @err.ruby_warnings @err.puts "hello" - assert_equal "hello\n", @err.string + @err.print "world", "\n" + assert_equal "hello\nworld\n", @err.string assert_equal 0, @err.ruby_warnings end @@ -27,12 +28,17 @@ def test_ruby_warning @err.write "#{@gems_dir}/unicode_utils-1.4.0/lib/unicode_utils/sid.rb:11: warning: shadowing outer local variable - al\n" @err.write "/path/to/ruby/2.2.0/gems/unicode_utils-1.4.0/lib/unicode_utils/sid.rb:11: warning: shadowing outer local variable - al\n" + @err.write "/path/to/ruby/2.2.0/gems/fast_blank-1.0.0/lib/fast_blank.bundle: warning: method redefined; discarding old blank?" # This warning actually writes newline separately. @err.write "/path/to/ruby/2.2.0/gems/dragonfly-1.0.6/lib/dragonfly/utils.rb:41:in `uri_unescape': warning: URI.unescape is obsolete" @err.write "\n" - assert_equal "/path/to/script/middleware_test.rb:58: warning: assigned but unused variable - status\n", + # warn "custom warning" + @err.write "custom warning" + @err.write "\n" + + assert_equal "/path/to/script/middleware_test.rb:58: warning: assigned but unused variable - status\ncustom warning\n", @err.string assert_equal 1, @err.ruby_warnings end @@ -87,4 +93,11 @@ def test_template_warning @err.string assert_equal 1, @err.ruby_warnings end + + def test_eval_warning + @err.write "
:1: warning: __FILE__ in eval may not return location in binding; use Binding#source_location instead\n" + @err.write "
: warning: __LINE__ in eval may not return location in binding; use Binding#source_location instead\n" + assert_equal "", @err.string + assert_equal 0, @err.ruby_warnings + end end