Simulate Overloading Method

Run Settings
LanguageRuby
Language Version
Run Command
require "set" require "./dio.rb" class B end class A < B end class D end class C < D end class M sig def fun() p [] end sig Integer def fun(p1) p [p1] end sig Integer, Integer def fun(p1, p2) p [p1, p2] end sig Integer, Integer, Integer def fun(p1, p2, p3) p "Integer# #{[p1, p2, p3].inspect}" end sig String, String, String, String def fun(p1, p2, p3, p4) p "String# #{[p1, p2, p3, p4].inspect}" end sig Array, Array, Array def fun(p1, p2, p3) p "Array# #{[p1, p2, p3].inspect}" end sig Hash, Hash def fun(p1, p2) fun(p1, p2, {}) end sig Hash, Hash, Hash def fun(p1, p2, p3) p "Hash# #{[p1, p2, p3].inspect}" end sig Set, Set, Set def fun(p1, p2, p3) p "Set# #{[p1, p2, p3].inspect}" end sig A, D def test(a, d) p "A & D" end sig B, C def test(b, c) p "B & C" end end M.new.fun() M.new.fun(1) M.new.fun(1, 2) M.new.fun(1, 2, 3) M.new.fun("A", "B", "C", "D") M.new.fun({}, {}) M.new.fun(Set.new, Set.new, Set.new) M.new.test(A.new, C.new) puts M.new.overloading_methods("fun8")
class Inconsistent < StandardError attr_reader :object def initialize(object) @object = object end end class ConflictDefinition < StandardError attr_reader :object def initialize(object) @object = object end end class DuplicateSignature < StandardError attr_reader :object def initialize(object) @object = object end end class AmbiguousMethodCall < StandardError attr_reader :object def initialize(object) @object = object end end class MethodDefinition attr_accessor :method_ref, :type, :name def initialize(method_ref, type, name) @method_ref = method_ref @type = type @name = name end def inspect "#{name}(#{type.join(", ")})" end end class Object def self.method_added(name, &block) if $flag @@expect = nil $flag = false return end return if !signature_declared? return if name.to_s.end_with?("__hook") @@poly_definition ||= {} @@poly_definition[name] ||= [] method = self.instance_method(name) if method.arity != @@expect.size raise Inconsistent.new(self), "Declaration is inconsistent with implementation type parameters" end raise ConflictDefinition.new(self), "Conflict definition" if @@poly_definition[name].find{ |definition| definition.type.size == method.arity && @@expect.zip(definition.type).all?{ |curr, prev| curr == prev } } @@poly_definition[name] << MethodDefinition.new(method, @@expect, name) self.define_method("#{name}__hook") do |*args, &block| definitions = @@poly_definition[name].select{ |definition| definition.type.size == args.size && definition .type .zip(args.map(&:class)) .all?{ |expect, actual| actual.ancestors.include?(expect) } } if definitions.empty? raise NoMethodError.new(self), "#{name}(#{args.map(&:class).join(", ")})" else definition_set = args.map(&:class).map.with_index{ |clazz, i| ancestors = clazz.ancestors min_type = definitions.min_by{ |definition| ancestors.index(definition.type[i]) }.type[i] Set.new(definitions.select{ |definition| definition.type[i] == min_type }) }.reduce(Set.new(definitions), :&) if definition_set.empty? raise AmbiguousMethodCall.new(self), "Ambiguous method call" end end definition_set.first.method_ref.bind(self).call(*args, &block) end $flag = true self.class_eval "alias #{name} #{name}__hook" end def self.sig(*expect) if signature_declared? raise DuplicateSignature.new(self), "DuplicateSignature" end @@expect = expect end def signature_declared? class_variable_defined?("@@expect") && !@@expect.nil? end def overloading_methods(name) @@poly_definition[name.to_sym]&.map(&:inspect) || [] end def static_methods @@poly_definition.keys end end
Editor Settings
Theme
Key bindings
Full width
Lines