Created
October 11, 2012 21:37
-
-
Save bil-bas/3875647 to your computer and use it in GitHub Desktop.
Swarley's crazy type-checking method generator!
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
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