Created
July 30, 2012 09:59
-
-
Save Mon-Ouie/3205958 to your computer and use it in GitHub Desktop.
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 Module | |
class Overloader | |
EVERYTHING = Object.new | |
class << (ANYTHING = Object.new) | |
def ===(object); true; end | |
end | |
def initialize | |
@functions = {} | |
end | |
def run_for(object, *args, &block_arg) | |
args << block_arg if block_arg | |
@functions.each do |args_expr, block| | |
i, match = 0, true | |
args_expr.each do |expr| | |
if expr === args[i] | |
i += 1 | |
elsif expr == EVERYTHING | |
i = args.size | |
else | |
match = false | |
end | |
end | |
next if i < args.size unless i == (args.size - 1) and block_arg | |
next unless match | |
return object.instance_exec(*args, &block) | |
end | |
raise ArgumentError, "Given arguments aren't valid." | |
end | |
def when_given(*args, &block) | |
@functions[args] = block | |
end | |
def method_missing(symbol, *args, &block) | |
meth = symbol.to_s | |
case meth | |
when /^(\w+)_or_(\w+)$/ | |
begin | |
objects = [$1, $2].map { |i| self.send(i) } | |
rescue NoMethodError | |
super | |
end | |
o = Object.new | |
meta_class = (class << o; self; end) | |
meta_class.class_eval do | |
define_method(:===) do |other| | |
objects.any? { |e| e === other } | |
end | |
end | |
o | |
when /^an?_(\w+)$/ | |
begin | |
Object.const_get($1.capitalize) | |
rescue NameError | |
super | |
end | |
else | |
super | |
end | |
end | |
def anything | |
ANYTHING | |
end | |
def everything | |
EVERYTHING | |
end | |
def nothing | |
nil | |
end | |
end | |
def overload(method, &block) | |
overloader = Overloader.new | |
overloader.instance_eval(&block) | |
define_method(method) do |*args, &block| | |
overloader.run_for(self, *args, &block) | |
end | |
end | |
end | |
module Kernel | |
overload :foo do | |
when_given(a_string, an_integer) do |string, num| | |
puts string * num | |
end | |
when_given(a_string_or_an_integer) do |obj| | |
p obj | |
end | |
end | |
end | |
foo "a", 3 | |
foo 42 | |
foo "abc" | |
foo 1.5 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment