Skip to content

Instantly share code, notes, and snippets.

@bil-bas
Created October 11, 2012 21:37
Show Gist options
  • Save bil-bas/3875647 to your computer and use it in GitHub Desktop.
Save bil-bas/3875647 to your computer and use it in GitHub Desktop.
Swarley's crazy type-checking method generator!
class Class
def define(method_name, argument_types = {}, &block)
raise ArgumentError, "Block required" unless block_given?
raise ArgumentError, "Expected argument Hash" unless argument_types.is_a? Hash
raise ArgumentError, "Expected argument names to be Symbols" unless argument_types.each_key.all? {|x| x.is_a? Symbol }
raise ArgumentError, "Expected argument types to be Classes" unless argument_types.each_value.all? {|x| x.is_a? Class }
wrapper_class = Struct.new *argument_types.keys
# Redirect all other methods to the class, so methods get called there not on the bearer of arguments.
wrapper_class.send :define_method, :method_missing do |*args, &block|
@_target.send *args, &block
end
define_method method_name do |*args|
raise ArgumentError "Expected #{argument_types.size} arguments" unless args.size == argument_types.size
argument_types.zip(args) do |(name, type), value|
raise TypeError, "Expected argument #{name} to be a #{type.name} in #{method_name}" unless value.is_a? type
end
# Create a new wrapper with methods which act as fake arguments within the block.
wrapper = wrapper_class.new(*args)
wrapper.instance_variable_set :@_target, self # So it can redirect to calling object.
wrapper.instance_eval &block
end
end
end
class Bleh
define :factorial, i: Integer do
i < 1 ? 1 : i * factorial(i - 1)
end
end
puts Bleh.new.factorial 5
# => 120
puts Bleh.new.factorial 5.4
=begin
swarley_method_type.rb:19:in `block (2 levels) in define': Expected argument i to be a Integer in factorial (TypeError)
from swarley_method_type.rb:18:in `each'
from swarley_method_type.rb:18:in `zip'
from swarley_method_type.rb:18:in `block in define'
from swarley_method_type.rb:39:in `<main>'
=end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment