Fun With Ruby Metaprogramming
def foo
'bar'
end
#=> :foo
def fibonacci(n)
return 1 if n <= 1
fib(n-1) + fib(n-2)
end
def fib(n)
# ...
end
#=> :fib
def fib(n)
# ...
end
memoize :fib
memoize def fib(n)
# ...
end
class Calculator
extend Memoization
memoize def fib(n)
# ...
end
end
calc = Calculator.new
calc.fib(1000)
module Memoization
def memoize(name)
#
end
end
def memoize(name)
@@cache ||= {}
@@cache[name] = {}
# ...
end
def memoize(name)
@@cache ||= {}
@@cache[name] = {}
fn = instance_method(name)
# ...
end
def memoize(name)
# ...
instance_eval do
define_method(name) do |*args|
# ...
end
end
end
define_method(name) do |*args|
if @@cache[name].include?(args)
# return from @@cache
else
# calculate and update @@cache
end
end
if @@cache[name].include?(args)
@@cache[name][args]
else
@@cache[name][args] = fn.bind(self).call(args)
end
class Calculator
extend Memoization
memoize def fib(n)
# ...
end
end
static def fib(n)
# ...
end
Calculator.fib(100)
def static(name)
fn = instance_method(name)
define_singleton_method(name) do |*args|
fn.bind(self.new).call(args)
end
end
memoized static def fib(n)
# ...
end
Calculator.fib(100)
def factorial(n)
n <= 1 ? n : n * factorial(n-1)
end
def factorial(n, acc=1)
return acc if n <= 1
factorial(n-1, acc*n)
end
class Calculator
extend TailCallOptimization
tail_recursive def factorial(n, acc=1)
# ...
end
end
module TailCallOptimization
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
end
module TailCallOptimization
def tail_recursive(name)
fn = instance_method(name)
undef_method name
# recompile method with TCO
end
end
def tail_recursive(name)
# ...
RubyVM::InstructionSequence.new(<<-EOS).eval
class #{to_s}
#{fn.source}
end
EOS
end
# Raises error if result is not a Fixnum
typecheck Fixnum, def foo
# ...
end
# Please don't
public static void def main()
# ...
end