def mydef(n, **k, &b)
raise LocalJumpError, 'no block given' unless block_given?
raise ArgumentError, 'arity not matched' unless b.arity == k.size
define_singleton_method n do |*xs|
a, ts = [], k.values
c = -> x do
x.is_a?(t = ts.shift)?(a << x):(raise TypeError, "expect #{t}, got #{x}")
ts.empty? ? b.(*a) : c
end
xs.inject(c) { |r, x| r = r.(x) }
end
end
mydef(:add, a: Integer, b: Integer) { |a, b| a + b }
p add(3, 5)
p add(3).(5)
p add.(3).(5)
# add(0.1, 0.2)
module T
@@__t = { :' reserved types ' => [] }
def typed(*ts)
@@__t[:' reserved types '] = ts
end
def method_added(name)
unless @@__t.include?(name)
@@__t[name] = @@__t[:' reserved types ']
return if @@__t[name].empty?
@@__t[:' reserved types '] = []
old = instance_method(name)
define_method name do |*xs|
a, ts, b = [], @@__t[name].clone, old.bind(self)
c = -> x do
if x.is_a?(t = ts.shift)
a << x
else
raise TypeError, "expect #{t}, got #{x.inspect}"
end
ts.empty? ? b.(*a) : c
end
xs.inject(c) { |r, x| r = r.(x) }
end
end
end
end
class A
extend T
def add a, b
a + b
end
typed Integer, Integer
def mul a, b
a * b
end
end
a = A.new
p a.add(3, 5)
p a.add('3', '5')
p a.mul(3, 5)
# a.mul('3', 5)