I am writing a small tool for validating method arguments in Ruby. Ideally, the functionality would be like this:
class Test
extend ArgValidator
def say(word)
puts word
end
validate_args(:say) do
raise(ArgumentError) if not word.is_a?(String)
end
end
Test.new.say(3) # => ArgumentError
That is, the ArgValidator
module provides a validate_args
method that takes an instance method name and a block. Calling validate_args(<meth>)
causes the validation code (supplied in the block) to be run before the method body. The validation block is executed against the bindings of the method body. There are two features of the above code that I am specifically striving for:
- the target method body has no knowledge of the validation code (it is decorated)
- the validation block should have access to the same bindings as the method body, without needing to hardcode a duplicated method signature
My current approach is to have validate_args
decorate the target method with the validation code. By using Method#parameters
, I can get signature information from the target method and come very close to dynamically replicating the bindings of the method body itself. Unfortunately, #parameters
provides no information about default argument values.
Is there any way to achieve my goal?