class TTY::Logger::DataFilter

Constants

DOT
FILTERED

Attributes

compiled_filters[R]
filters[R]
mask[R]

Public Class Methods

new(filters = [], mask: nil) click to toggle source

Create a data filter instance with filters.

@example

TTY::Logger::DataFilter.new(%w[foo], mask: "<SECRET>")

@param [String] mask

the mask to replace object with. Defaults to `"[FILTERED]"`

@api private

# File lib/tty/logger/data_filter.rb, line 20
def initialize(filters = [], mask: nil)
  @mask = mask || FILTERED
  @filters = filters
  @compiled_filters = compile(filters)
end

Public Instance Methods

filter(obj) click to toggle source

Filter object for keys matching provided filters.

@example

data_filter = TTY::Logger::DataFilter.new(%w[foo])
data_filter.filter({"foo" => "bar"})
# => {"foo" => "[FILTERED]"}

@param [Object] obj

the object to filter

@api public

# File lib/tty/logger/data_filter.rb, line 37
def filter(obj)
  return obj if filters.empty?

  obj.each_with_object({}) do |(k, v), acc|
    acc[k] = filter_val(k, v)
  end
end

Private Instance Methods

compile(filters) click to toggle source
# File lib/tty/logger/data_filter.rb, line 47
def compile(filters)
  compiled = {
    regexps: [],
    nested_regexps: [],
    blocks: []
  }
  strings = []
  nested_strings = []

  filters.each do |filter|
    case filter
    when Proc
      compiled[:blocks] << filter
    when Regexp
      if filter.to_s.include?(DOT)
        compiled[:nested_regexps] << filter
      else
        compiled[:regexps] << filter
      end
    else
      exp = Regexp.escape(filter)
      if exp.include?(DOT)
        nested_strings << exp
      else
        strings << exp
      end
    end
  end

  if !strings.empty?
    compiled[:regexps] << /^(#{strings.join("|")})$/
  end

  if !nested_strings.empty?
    compiled[:nested_regexps] << /^(#{nested_strings.join("|")})$/
  end

  compiled
end
filter_arr(key, obj, composite) click to toggle source
# File lib/tty/logger/data_filter.rb, line 111
def filter_arr(key, obj, composite)
  obj.reduce([]) do |acc, v|
    acc << filter_val(key, v, composite)
  end
end
filter_obj(_key, obj, composite) click to toggle source
# File lib/tty/logger/data_filter.rb, line 105
def filter_obj(_key, obj, composite)
  obj.each_with_object({}) do |(k, v), acc|
    acc[k] = filter_val(k, v, composite)
  end
end
filter_val(key, val, composite = []) click to toggle source
# File lib/tty/logger/data_filter.rb, line 87
def filter_val(key, val, composite = [])
  return mask if filtered?(key, composite)

  case val
  when Hash then filter_obj(key, val, composite << key)
  when Array then filter_arr(key, val, composite)
  else val
  end
end
filtered?(key, composite) click to toggle source
# File lib/tty/logger/data_filter.rb, line 97
def filtered?(key, composite)
  composite_key = composite + [key]
  joined_key = composite_key.join(DOT)
  @compiled_filters[:regexps].any? { |reg| !!reg.match(key.to_s) } ||
    @compiled_filters[:nested_regexps].any? { |reg| !!reg.match(joined_key) } ||
    @compiled_filters[:blocks].any? { |block| block.(composite_key.dup) }
end