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