Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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
Add Comment
Please, Sign In to add comment