class Overloader::Core

Public Class Methods

define_overload(klass, proc) click to toggle source
# File lib/overloader/core.rb, line 5
def self.define_overload(klass, proc)
  new(klass, proc).define_overload
end
new(klass, proc) click to toggle source
# File lib/overloader/core.rb, line 9
def initialize(klass, proc)
  @klass = klass
  @proc = proc
end

Public Instance Methods

define_overload() click to toggle source
# File lib/overloader/core.rb, line 14
    def define_overload
      ast = RubyVM::AbstractSyntaxTree.of(@proc)
      methods = {}
      ast.find_nodes(:DEFN).each.with_index do |def_node, index|
        args = def_node.method_args
        body = def_node.method_body
        name = def_node.method_name
        args_source = args.to_source(absolute_path)
        args_source = "" if args_source == "(" # RubyVM::AST's bug?

        @klass.class_eval <<~RUBY
          def __#{name}_#{index}_checker_inner(#{args_source}) end
          def __#{name}_#{index}_checker(*args)
            __#{name}_#{index}_checker_inner(*args)
            #{type_check_code(def_node, name)}
          rescue ArgumentError
            false
          end
        RUBY

        @klass.class_eval <<~RUBY, absolute_path, def_node.first_lineno
          def __#{name}_#{index}(#{args_source})
          #{body.to_source(absolute_path)}
          end
        RUBY
        (methods[name] ||= []) << index
      end

      methods.each do |name, indexes|
        @klass.class_eval <<~RUBY
          def #{name}(*args, &block)
            #{indexes.map do |index|
              "return __#{name}_#{index}(*args, &block) if __#{name}_#{index}_checker(*args)"
            end.join("\n")}
            raise ArgumentError
          end
        RUBY
      end
    end
type_check_code(def_node, method_name) click to toggle source
# File lib/overloader/core.rb, line 54
def type_check_code(def_node, method_name)
  return 'true' unless defined?(::Overloader::Type)

  comment = def_node.comment(path: absolute_path)
  return 'true' unless comment

  type = comment.sub(/^\s*#/, '')

  "::Overloader::Type.callable?(#{type.dump}, self.class, #{method_name.inspect}, *args)"
end

Private Instance Methods

absolute_path() click to toggle source
# File lib/overloader/core.rb, line 65
        def absolute_path
  @proc.source_location[0]
end