Skip to content

Instantly share code, notes, and snippets.

@booch
Created January 14, 2014 03:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save booch/8412360 to your computer and use it in GitHub Desktop.
Save booch/8412360 to your computer and use it in GitHub Desktop.
What if we could check type signatures in Ruby? A proof of concept.
# Allow multiple classes to be declared via A|B instead of [A, B].
class Class
def |(*other_classes)
SetOfClasses.new(self, other_classes)
end
end
require 'set'
class SetOfClasses
attr_reader :classes
def initialize(*classes)
@classes = Set.new(classes.flatten)
end
def |(*other_classes)
SetOfClasses.new([self, *other_classes])
end
def none?(&block)
classes.none?(&block)
end
end
class Class
def signature(*arg_types)
@method_signature = arg_types
end
def method_added(method_name)
puts 'method_added'
if @method_signature
method_signature = @method_signature
@method_signature = nil
original_method_name = "#{method_name}_without_type_checking"
self.send(:alias_method, "#{original_method_name}", "#{method_name}")
define_method("#{method_name}".to_sym) do |*args, &block|
check_method_signature(method_signature, args)
self.send(original_method_name, *args, &block)
end
end
end
end
class Object
def check_method_signature(arg_types, args)
puts "Checking signature: #{arg_types}: #{args}"
arg_types.each_with_index do |arg_type, index|
var = args[index]
if arg_type.kind_of?(SetOfClasses)
if arg_type.none?{|type| var.kind_of?(type)}
raise ArgumentError.new("Argument '#{var}' must be one of the types #{arg_type}")
end
elsif arg_type.kind_of?(Class)
unless var.kind_of?(arg_type)
raise ArgumentError.new("Argument '#{var}' must be of type #{arg_type}")
end
else
raise ArgumentError.new("Arguments to signature() must be classes.")
end
end
end
end
class Xyz
signature(Integer|Fixnum, String, Symbol)
def xyz(a, b, c)
puts 'xyz:'
puts a.inspect
puts b.inspect
puts c.inspect
end
end
Xyz.new.xyz(1,'b',:c) # Should work.
Xyz.new.xyz('1','b',:c) # Should raise an exception.
@booch
Copy link
Author

booch commented Jan 14, 2014

No idea how this ended up with 4-space tabbing.

@adkron
Copy link

adkron commented Jan 14, 2014

This is kind of cool, but kind of makes me sick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment