module Abstriker::HookBase

Private Instance Methods

check_abstract_methods(klass) click to toggle source
# File lib/abstriker.rb, line 88
def check_abstract_methods(klass)
  return if Abstriker.disabled?

  unless klass.instance_variable_get("@__abstract_trace_point")
    tp = TracePoint.trace(:end, :c_return, :raise) do |t|
      if t.event == :raise
        tp.disable
        next
      end

      t_self = t.self

      target_outer_include = false
      if t.event == :c_return && t_self == klass && t.method_id == :include
        traverser = SexpTraverser.new(Abstriker.sexps[t.path])
        traverser.traverse do |n, parent|
          if n[0] == :@ident && n[1] == "include" && n[2][0] == t.lineno
            if parent[0] == :command || parent[0] == :fcall
              # include Mod
            elsif parent[0] == :command_call || parent[0] == :call
              if parent[1][0] == :var_ref && parent[1][1][0] == :@kw && parent[1][1][1] == "self"
                # self.include Mod
              else
                # unknown case
                target_outer_include = true
              end
            else
              target_outer_include = true
            end
          end
        end
      end

      target_end_event = t_self == klass && t.event == :end
      target_c_return_event = (t_self == Class || t_self == Module) && t.event == :c_return && t.method_id == :new
      if target_end_event || target_c_return_event || target_outer_include
        klass.ancestors.drop(1).each do |mod|
          Abstriker.abstract_methods[mod]&.each do |fmeth_name|
            meth = klass.instance_method(fmeth_name)
            if meth.owner == mod
              tp.disable
              klass.instance_variable_set("@__abstract_trace_point", nil)
              raise Abstriker::NotImplementedError.new(klass, meth)
            end
          end
        end
        tp.disable
        klass.instance_variable_set("@__abstract_trace_point", nil)
      end
    end
    klass.instance_variable_set("@__abstract_trace_point", tp)
  end
end
check_abstract_singleton_methods(klass) click to toggle source
# File lib/abstriker.rb, line 142
def check_abstract_singleton_methods(klass)
  return if Abstriker.disabled?

  unless klass.instance_variable_get("@__abstract_singleton_trace_point")

    tp = TracePoint.trace(:end, :c_return, :raise) do |t|
      if t.event == :raise
        tp.disable
        next
      end

      t_self = t.self

      target_outer_extend = false
      if t.event == :c_return && t_self == klass && t.method_id == :extend
        traverser = SexpTraverser.new(Abstriker.sexps[t.path])
        traverser.traverse do |n, parent|
          if n[0] == :@ident && n[1] == "extend" && n[2][0] == t.lineno
            if parent[0] == :command || parent[0] == :fcall
              # extend Mod
            elsif parent[0] == :command_call || parent[0] == :call
              if parent[1][0] == :var_ref && parent[1][1][0] == :@kw && parent[1][1][1] == "self"
                # self.extend Mod
              else
                # unknown case
                target_outer_extend = true
              end
            else
              target_outer_extend = true
            end
          end
        end
      end

      target_end_event = t_self == klass && t.event == :end
      target_c_return_event = (t_self == Class || t_self == Module) && t.event == :c_return && t.method_id == :new
      if target_end_event || target_c_return_event || target_outer_extend
        klass.singleton_class.ancestors.drop(1).each do |mod|
          Abstriker.abstract_methods[mod]&.each do |fmeth_name|
            meth = klass.singleton_class.instance_method(fmeth_name)
            if meth.owner == mod
              tp.disable
              klass.instance_variable_set("@__abstract_singleton_trace_point", nil)
              raise Abstriker::NotImplementedError.new(klass, meth)
            end
          end
        end
        tp.disable
        klass.instance_variable_set("@__abstract_singleton_trace_point", nil)
      end
    end
    klass.instance_variable_set("@__abstract_singleton_trace_point", tp)
  end
end