Skip to content

Instantly share code, notes, and snippets.

@hube
Last active August 29, 2015 13:58
Show Gist options
  • Save hube/10000871 to your computer and use it in GitHub Desktop.
Save hube/10000871 to your computer and use it in GitHub Desktop.
Demonstrates metaprogramming and reflection features in Ruby
# An example of duck typing using reflection
def greet(names)
if names.respond_to? :each
names.each do |name|
puts "Hello #{name}!"
end
else
puts "Hello #{names}!"
end
end
greet ['Alice', 'Bob']
greet 'Eve'
class NoMethods
def method_missing(symbol, *args)
puts "called #{symbol}(#{args.join(', ')})"
if symbol == :greet
puts "Hello #{args.join(', ')}"
else
super
end
end
def respond_to?(symbol)
symbol == :greet ? true : super
end
end
n = NoMethods.new
n.greet
n.greet "Alice"
n.greet "Alice", "Bob", "Eve"
n.farewell "Alice"
class MathExpr
UNARY_EXPR = [
[:value, ->(v) { v }],
[:squared, ->(expr) { expr.() ** 2 }],
]
BINARY_EXPR = [
[:add, ->(lhs, rhs) { lhs.() + rhs.() }],
[:subtract, ->(lhs, rhs) { lhs.() - rhs.() }],
]
def self.define_expression(name, f, arity)
singleton_class.instance_exec do
define_method name do |*args|
->() { f.(*(args[0..arity])) }
end
end
end
UNARY_EXPR.each do |expr|
define_expression(*expr, 1)
end
BINARY_EXPR.each do |expr|
define_expression(*expr, 2)
end
end
one = MathExpr.value(1)
five = MathExpr.value(5)
add_one_five = MathExpr.add(one, five)
add_one_five.()
add_one_five_squared = MathExpr.squared(add_one_five)
add_one_five_squared.()
module MemoizedAttributes
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def attr_memoized(*args)
args.each do |attr|
define_method attr do |index|
arr = instance_variable_get(:"@#{attr}")
if arr.nil?
arr = instance_variable_set(:"@#{attr}", [])
end
arr[index] ||= super(index)
end
end
define_method :reset_memos do |*attrs|
attrs = args if attrs.empty?
attrs.each do |attr|
instance_variable_set(:"@#{attr}", [])
end
end
end
end
end
class Fibonacci
module Calculations
def fib(n)
n <= 1 ? 1 : fib(n - 1) + fib(n - 2)
end
def memo_fib(n)
n <= 1 ? 1 : memo_fib(n - 1) + memo_fib(n - 2)
end
end
include Calculations
include MemoizedAttributes
attr_memoized :memo_fib
end
Fibonacci.ancestors
require 'benchmark'
f = Fibonacci.new
Benchmark.bmbm do |x|
[:fib, :memo_fib].each do |method|
x.report(method) do
10.times { f.send(method, 30) }
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment