Skip to content

Instantly share code, notes, and snippets.

@bit-dragon
Last active December 11, 2015 04:58
Show Gist options
  • Save bit-dragon/4548551 to your computer and use it in GitHub Desktop.
Save bit-dragon/4548551 to your computer and use it in GitHub Desktop.
Meta-programming examples
# Memoization
# Example number one
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
class Discounter
def initialize
@memory = {}
end
def discount(*skus)
if @memory.has_key?(skus)
@memory[skus]
else
@memory[skus] = expensive_discount_calculation(*skus)
end
end
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
d = Discounter.new
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple 2
# Subclassing
#
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
class Discounter
def discount(*skus)
expensive_discount_calculation(*skus)
end
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
class MemoDiscounter < Discounter
def initialize
@memory = {}
end
def discount(*skus)
if @memory.has_key?(skus)
@memory[skus]
else
@memory[skus] = super
end
end
end
d = MemoDiscounter.new
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple 3
# Subclass with generator
#
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
class Discounter
def discount(*skus)
expensive_discount_calculation(*skus)
end
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
def memoize(cls, method)
Class.new (cls) do
memory = {}
define_method(method) do |*args|
if memory.has_key?(args)
memory[args]
else
memory[args] = super(*args)
end
end
end
end
d = memoize(Discounter, :discount)
d = d.new
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple 4
# using a ghost class
#
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
class Discounter
def discount(*skus)
expensive_discount_calculation(*skus)
end
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
d = Discounter.new
def d.discount(*skus)
@memory ||= {}
if @memory.has_key?(skus)
@memory[skus]
else
@memory[skus] = super
end
end
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple
# ghost with generator
#
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
class Discounter
def discount(*skus)
expensive_discount_calculation(*skus)
end
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
def memoize(obj, method)
ghost = class << obj; self; end
ghost.class_eval do
memory ||= {}
define_method(method) do |*args|
if memory.has_key?(args)
memory[args]
else
# Fixed this part from the video
# Super needs to expecify the args
memory[args] = super(*args)
end
end
end
end
d = Discounter.new
memoize(d, :discount)
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple 6
# Rewrite the method
#
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
class Discounter
def discount(*skus)
expensive_discount_calculation(*skus)
end
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
class Discounter
alias_method :_origial_discount_, :discount
def discount(*skus)
@memory ||= {}
if @memory.has_key?(skus)
@memory[skus]
else
@memory[skus] = _origial_discount_(*skus)
end
end
end
d = Discounter.new
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple 7
# Rewrite using module
#
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
module Memoize
def remember(name)
original = "origina #{name}"
alias_method original, name
memory = {}
define_method(name) do |*args|
if memory.has_key?(args)
memory[args]
else
memory[args] = send original, *args
end
end
end
end
class Discounter
extend Memoize
def discount(*skus)
expensive_discount_calculation(*skus)
end
remember :discount
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
d = Discounter.new
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple 8
# Rewrite using bind
#
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
module Memoize
def remember(name)
original_method = instance_method(name)
memory = {}
define_method(name) do |*args|
if memory.has_key?(args)
memory[args]
else
bound_method = original_method.bind(self)
memory[args] = bound_method.call(*args)
end
end
end
end
class Discounter
extend Memoize
def discount(*skus)
expensive_discount_calculation(*skus)
end
remember :discount
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
d = Discounter.new
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
# Exmaple 9
# using a DSL
#
# Original class
#class Discounter
# def discount(*skus)
# expensive_discount_calculation(*skus)
# end
#
# private
#
# def expensive_discount_calculation(*skus)
# puts "Expensive calculation for #{skus.inspect}"
# skus.inject { |m,n| m + n }
# end
#end
module Memoize
def remember(name, &block)
define_method(name, &block)
original_method = instance_method(name)
memory = {}
define_method(name) do |*args|
if memory.has_key?(args)
memory[args]
else
bound_method = original_method.bind(self)
memory[args] = bound_method.call(*args)
end
end
end
end
class Discounter
extend Memoize
remember :discount do |*skus|
expensive_discount_calculation(*skus)
end
private
def expensive_discount_calculation(*skus)
puts "Expensive calculation for #{skus.inspect}"
skus.inject { |m,n| m + n }
end
end
d = Discounter.new
puts d.discount(1, 2, 3)
# => Expensive calculation for [1, 2, 3]
# => 6
puts d.discount(1, 2, 3)
# => 6
puts d.discount(2, 3, 4)
# => Expensive calculation for [2, 3, 4]
# => 9
puts d.discount(2, 3, 4)
# => 9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment