Created
July 3, 2021 18:59
-
-
Save JoshCheek/df6154555387f966ef1808262e38f72e to your computer and use it in GitHub Desktop.
Using `method_added` to detect the next method
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://twitter.com/dorianmariefr/status/1411306589739433984 | |
# We'll ignore everything except required args, to keep it simpler | |
private def with_types(*ordtypes) | |
mod = is_a?(Module) ? self : Object # to handle edge-case of `main` | |
mod.module_eval { @next_types = ordtypes } | |
end | |
class Module | |
def method_added(name) | |
return unless @next_types | |
ordtypes = @next_types | |
remove_instance_variable :@next_types | |
meth = instance_method(name) | |
params = meth.parameters | |
ordtypes.size == params.size or raise TypeError, "#{ordtypes.inspect} does not match signature: #{params.inspect}" | |
define_method name do |*ords| | |
ords.size == ordtypes.size or raise ArgumentError, "wrong # of args, expected #{ordtypes.inspect}, got #{ords.inspect}" | |
ords.zip(ordtypes).each_with_index do |(ord, type), i| | |
type === ord or raise TypeError, "arg #{i} of `#{name}': #{type.inspect}, does not match #{ord.inspect}" | |
end | |
meth.bind(self).call(*ords) | |
end | |
end | |
end | |
# Provided example | |
with_types Integer, Integer | |
def add(a, b) | |
a + b | |
end | |
add 1, 2 # => 3 | |
add 'a', 'b' rescue $! # => #<TypeError: arg 0 of `add': Integer, does not match "a"> | |
# With mismatched signature | |
with_types Integer, Integer | |
def add2(arg) arg end rescue $! # => #<TypeError: [Integer, Integer] does not match signature: [[:req, :arg]]> | |
# On a class | |
class String | |
with_types String | |
def add(rhs) | |
self + rhs | |
end | |
end | |
"a".add "b" # => "ab" | |
"a".add 5 rescue $! # => #<TypeError: arg 0 of `add': String, does not match 5> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment