class NilPasser

Attributes

method_name[RW]
obj[RW]
orig_proc[RW]

Public Class Methods

clone(klass, method_name) click to toggle source
# File lib/nil_passer.rb, line 18
def self.clone(klass, method_name)
  begin
    # ensure that the method is not recursively redefined
    klass.class_variable_get("@@old_#{method_name}".to_sym)
  rescue NameError
    klass.instance_method(method_name).clone
  end
end
new(obj, method_name=nil, accepts_args=true) click to toggle source
# File lib/nil_passer.rb, line 33
def initialize(obj, method_name=nil, accepts_args=true)
  if obj.is_a? Class
    self.initialize_class    obj, method_name, accepts_args
  else
    self.initialize_instance obj, method_name, accepts_args
  end
end
teardown(nil_passers) click to toggle source
# File lib/nil_passer.rb, line 27
def self.teardown(nil_passers)
  nil_passers.each do |nil_passer|
    nil_passer.teardown
  end
end
test(a_caller, block) click to toggle source
# File lib/nil_passer.rb, line 8
def self.test(a_caller, block)
  if (block&.arity == 1) && a_caller.first&.start_with?(@@rails_path)
    begin
      block.call nil
    rescue Exception => e
      @@rails_logger.tagged("no-nil") { @@rails_logger.info "found a block that can't handle nil at #{block.source_location}, error: #{e.inspect}" }
    end
  end
end

Public Instance Methods

call(*args, &block) click to toggle source
# File lib/nil_passer.rb, line 102
def call(*args, &block)
  NilPasser.test caller, block
  @orig_proc.call(*args, &block)
end
initialize_class(klass, method_name=nil, accepts_args=true) click to toggle source
# File lib/nil_passer.rb, line 52
def initialize_class(klass, method_name=nil, accepts_args=true)
  if method_name
    obj.class.class_variable_set(to_old method_name, NilPasser.clone(obj, method_name))
    if accepts_args
      # I don't know how to send this to klass without eval
      eval [ "class #{klass}",
             "  def #{method_name}(*args, &block)",
             "    NilPasser.test caller, block",
             "    #{to_old method_name}.bind(self)&.call(*args, &block)",
             "  end",
             "end"
      ].join("\n")
    else
      eval [ "class #{klass}",
             "  def #{method_name}(&block)",
             "    NilPasser.test caller, block",
             "    #{to_old method_name}.bind(self)&.call(&block)",
             "  end",
             "end"
      ].join("\n")
    end
  else
    obj.methods.map do |method|
      NilPasser.new(obj, method)
    end
  end
end
initialize_instance(inst, method_name=nil, accepts_args=true) click to toggle source
# File lib/nil_passer.rb, line 80
def initialize_instance(inst, method_name=nil, accepts_args=true)
  if method_name
    begin
      @obj         = inst
      @method_name = method_name
      @orig_proc   = inst.method(method_name).to_proc
    rescue NameError => e
      raise ArgumentError, "The provided method must be a valid method of the provided object, got: #{e}"
    end
  else
    (inst.methods - Object.methods).map do |method|
      NilPasser.new(obj, method)
    end
  end
end
setup() click to toggle source
# File lib/nil_passer.rb, line 96
def setup
  @orig_proc = self.obj.method(@method_name).to_proc.clone
  @obj.send(:define_singleton_method, @method_name, self.method(:call).to_proc)
  self
end
teardown() click to toggle source
# File lib/nil_passer.rb, line 107
def teardown
  @obj.send(:define_singleton_method, @method_name, @orig_proc)
end
to_old(x) click to toggle source

stuff -> @@old_stuff

# File lib/nil_passer.rb, line 42
def to_old(x)
  # need to convert method-only symbols into symbols acceptible for class variables
  clean_x = x.to_s.gsub(/[^0-9a-zA-Z_]/) do |y|
    y.codepoints.map do |z|
      z.to_s
    end.join('_')
  end
  "@@old_#{clean_x}".to_sym
end