Skip to content

Instantly share code, notes, and snippets.

@duckinator
Forked from jneen/variant.rb
Last active August 29, 2015 14:10
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 duckinator/bad02061c7d0e65192f9 to your computer and use it in GitHub Desktop.
Save duckinator/bad02061c7d0e65192f9 to your computer and use it in GitHub Desktop.
class Variant
attr_accessor :variant_tag
def self.variants(hsh)
hsh.map do |tag, args|
variant(tag, args)
end
end
def self.variant(tag, args)
args = [args] unless args.is_a?(Array)
@@variants ||= {}
@@variants[tag] = args
arg_definitions = @@variants[tag].map do |arg_name|
"tmp.#{arg_name} = %s"
end.join("\n ")
code = <<-EOF
def #{tag.to_s}(#{args.join(', ')})
attr_accessor *#{args.inspect}
tag = #{tag.inspect}
tmp = self.new
tmp.variant_tag = tag
#{format(arg_definitions, *args)}
tmp
end
EOF
self.class.class_eval code
tag
end
def cases(hsh)
hsh.each do |k, v|
if variant_tag == k
args = @@variants[k].map{|x| send(x)}
return v.call(*args)
end
end
end
end
class Order < Variant
variants delivery: [:address],
digital: [:email],
pickup: [:store_id]
end
def test(order)
puts order.cases(
delivery: ->(address) { "delivering to #{address}" },
digital: ->(email) { "emailing to #{email}" },
pickup: ->(store_id) {
"picking up from store ##{store_id}"
},
)
end
# n constructors
test Order.delivery('123 Main St') #=> delivering to 123 Main St
test Order.digital('customer@example.com') #=> emailing to customer@example.com
test Order.pickup(456) #=> picking up from store #456
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment