Class: RubyWarningFilter

Inherits:
IO
  • Object
show all
Defined in:
lib/ruby_warning_filter.rb

Overview

Filter IO from Ruby warnings that come out of external gems. There is no other way currently to filter out Ruby warnings other than hijacking stderr.

$VERBOSE = true
require "ruby_warning_filter"
$stderr = RubyWarningFilter.new($stderr)

Number of occurred non-filtered warnings can be read with ruby_warnings:

$stderr.ruby_warnings #=> 0
@foo # warning: instance variable @foo not initialized
$stderr.ruby_warnings #=> 1

The filter only overrides “write” method. This is OK since Ruby uses “write” internally when emitting warnings. Helper methods such as “puts”, “print”, “printf” will do native “write” bypassing the filter.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io, ignore_path: Gem.path) ⇒ RubyWarningFilter

Returns a new instance of RubyWarningFilter.



24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/ruby_warning_filter.rb', line 24

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
end

Instance Attribute Details

#ruby_warningsObject (readonly)

Returns the value of attribute ruby_warnings.



22
23
24
# File 'lib/ruby_warning_filter.rb', line 22

def ruby_warnings
  @ruby_warnings
end

Instance Method Details

#write(line) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ruby_warning_filter.rb', line 38

def write(line)
  if @ignored && (backtrace?(line) || line == "\n")
    # Ignore the whole backtrace after ignored warning.
    # Some warnings write newline separately for some reason.
    @ignored = true
    nil
  elsif @ignored && eval_redefined?(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)
    unless @ignored
      @ruby_warnings += 1
      super
    end
  else
    super
  end
end