Skip to content

Instantly share code, notes, and snippets.

@ne-sachirou
Created April 30, 2015 06:49
Show Gist options
  • Save ne-sachirou/7b90e19fb3c8d9ada703 to your computer and use it in GitHub Desktop.
Save ne-sachirou/7b90e19fb3c8d9ada703 to your computer and use it in GitHub Desktop.
Ruby Enumerableを(パターン)マッチで分岐
class Matcher
def initialize enum
@enum = enum
@patterns = []
@else = nil
end
def with pattern, &b
@patterns << [pattern, b, []]
end
def else_ &b
@else = [b, []]
end
def _exec
@enum.each do |item|
is_matched = false
@patterns.each do |pattern, b, pool|
if pattern.call item
pool << item
is_matched = true
break
end
end
@else[1] << item unless is_matched && @else
end
@patterns.each{|pattern, b, pool| b.call pool }
@else[0].call(@else[1]) if @else
end
class LazyEnum
include Enumerable
def initialize pull
@pull = pull
end
def each
while true
yield @pull.call
end
rescue StopIteration
end
end
class Lazy < Matcher
def _exec
gen_enum = lambda do |pool|
LazyEnum.new ->{
begin
while pool.length == 0
item = @enum.next
is_matched = false
@patterns.each do |pattern, b, pool|
if pattern.call item
pool << item
is_matched = true
break
end
end
@else[1] << item if !is_matched && @else
end
rescue StopIteration
raise
end
pool.shift
}
end
@patterns.each do |pattern, b, pool|
b.call gen_enum.call(pool)
end
@else[0].call gen_enum.call(@else[1]) if @else
end
end
end
module Enumerable
def case &b
matcher = Matcher.new self
matcher.instance_eval &b
matcher._exec
end
end
class Enumerator::Lazy
def case &b
matcher = Matcher::Lazy.new self
matcher.instance_eval &b
matcher._exec
end
end
class Array
def case &b
to_enum.case &b
end
end
threads = []
(1..42).case do
with ->(i){ i % 3 == 1 } do |e|
threads << Thread.new do
e.each{|i| puts "r1 #{i}" }
end
end
with ->(i){ i % 3 == 2 } do |e|
threads << Thread.new do
e.each{|i| puts "r2 #{i}" }
end
end
else_ do |e|
threads << Thread.new do
e.each{|i| puts "r0 #{i}" }
end
end
end
threads.each &:join
puts
threads = []
(1..42).lazy.case do
with ->(i){ i % 3 == 1 } do |e|
threads << Thread.new do
e.each{|i| puts "lz r1 #{i}" }
end
end
with ->(i){ i % 3 == 2 } do |e|
threads << Thread.new do
e.each{|i| puts "lz r2 #{i}" }
end
end
else_ do |e|
threads << Thread.new do
e.each{|i| puts "lz r0 #{i}" }
end
end
end
threads.each &:join
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment