Skip to content

Instantly share code, notes, and snippets.

@Mon-Ouie
Created July 30, 2012 09:59
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 Mon-Ouie/3205958 to your computer and use it in GitHub Desktop.
Save Mon-Ouie/3205958 to your computer and use it in GitHub Desktop.
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