Instantly share code, notes, and snippets.

# britishtea/example.rb Last active Dec 31, 2015

What would you like to do?
Simple pattern matching in Ruby that won't win any beauty contests.
 require 'function' # A fibonacci function. fib = Function.new fib[0] = 0 fib[1] = 1 fib[Integer] = ->(i) { fib[i - 2] + fib[i - 1] } p fib[0] # => 0 p fib[20] # => 6765 fib["a"] rescue p \$! # => # # An implementation of map. map = Function.new map[[], Function] = [] map[Array, Function] = ->(arr, f) { [f[arr[0]]] + map[arr[1..-1], f] } p map[[0,1,2,5,20], fib] p map[[0,1,2,5,20], fib] # => [0, 1, 1, 5, 6765] # Let's do some guarding. It ain't pretty. fizzbuzz = Function.new fizzbuzz[->(i) { i % 3 == 0 && i % 5 == 0 }] = "fizzbuzz" fizzbuzz[->(i) { i % 3 == 0 }] = "fizz" fizzbuzz[->(i) { i % 5 == 0 }] = "buzz" fizzbuzz[:_] = ->(i) { i } p map[1.upto(15).to_a, fizzbuzz] # => [1, 2, "fizz", 4, "buzz", "fizz", 7, 8, "fizz", "buzz", 11, "fizz", 13, 14, "fizzbuzz"]
 # A simple function with pattern matching. class Function WILDCARD = :_ TypeError = Class.new TypeError def initialize(&block) @patterns = Hash.new end # Public: Defines behaviour for a pattern. def []=(*pattern, value) @patterns[pattern] = value end # Public: Calls the function. # # Raises a Function::TypeError when no matching pattern was found. def [](*args) key, value = find_exact_match(args) || find_pattern_match(args) if key.nil? raise TypeError, "No matching pattern for #{args.inspect[1..-2]}." end if value.is_a? Proc return value.call(*args) else return value end end alias_method :call, :[] def to_proc proc { |*args| self[*args] } end private # A set of values that are equal (#==) to another set of values. # Example: [1,2,3] and [1,2,3] def find_exact_match(arguments) @patterns.find { |pattern, _| arguments == pattern } end # A set of values that are threequal (#===) to another set of values. Note # that :_ is treated as a wildcard. # Example: [Integer, Integer, :_] and [1,2,3]. def find_pattern_match(arguments) @patterns.find do |pattern, _| pattern.zip(arguments).all? do |one, two| [ one == WILDCARD, # This is a wildcard. one === two, # This executes Procs, we've got guards! :D one == two ].any? end end end end