2010-04-19 20:22:54 +02:00
|
|
|
|
2010-05-23 22:20:53 +02:00
|
|
|
class ::Regexp
|
|
|
|
class NegRegexp
|
|
|
|
def initialize r
|
|
|
|
@rx = r
|
|
|
|
end
|
|
|
|
def match l
|
|
|
|
! @rx.match( l)
|
|
|
|
end
|
|
|
|
def =~ l
|
|
|
|
! @rx =~ l
|
|
|
|
end
|
|
|
|
def -@
|
|
|
|
@rx
|
|
|
|
end
|
2010-05-20 14:48:42 +02:00
|
|
|
end
|
2010-05-23 22:20:53 +02:00
|
|
|
|
2010-05-20 14:48:42 +02:00
|
|
|
def -@
|
2010-05-23 22:20:53 +02:00
|
|
|
NegRegexp.new self
|
2010-05-20 14:48:42 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-05-23 22:20:53 +02:00
|
|
|
class ::Object
|
|
|
|
def functional meth = nil
|
|
|
|
Functional.new self, meth
|
2010-05-20 14:48:42 +02:00
|
|
|
end
|
2010-05-25 19:02:49 +02:00
|
|
|
alias to_fun functional
|
2010-05-20 14:48:42 +02:00
|
|
|
end
|
|
|
|
|
2010-04-19 20:22:54 +02:00
|
|
|
class Functional
|
|
|
|
include Enumerable
|
|
|
|
|
2010-05-20 17:07:23 +02:00
|
|
|
class Base
|
|
|
|
attr_reader :exe
|
|
|
|
attr_accessor :next
|
|
|
|
def initialize &e
|
|
|
|
@exe = e
|
|
|
|
end
|
|
|
|
|
|
|
|
def call *a
|
|
|
|
@next.call *a
|
|
|
|
end
|
|
|
|
|
|
|
|
def end
|
|
|
|
@next.end
|
|
|
|
end
|
2010-05-23 22:20:53 +02:00
|
|
|
|
|
|
|
def to_proc
|
|
|
|
method( :call).to_proc
|
|
|
|
end
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
|
|
|
|
2010-05-20 17:07:23 +02:00
|
|
|
class Collect <Base
|
|
|
|
def call *a
|
|
|
|
@next.call *@exe.call( *a)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Select <Base
|
|
|
|
def call *a
|
|
|
|
@next.call *a if @exe.call *a
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class DeleteIf <Base
|
|
|
|
def call *a
|
|
|
|
@next.call *a unless @exe.call *a
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Compact <Base
|
|
|
|
def call *a
|
|
|
|
@next.call *a unless a.empty? || [nil] == a
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class BottomUp <Base
|
|
|
|
def initialize start, *a, &e
|
|
|
|
@next.call *a, &e
|
|
|
|
@buffer, @start = nil, start
|
|
|
|
end
|
|
|
|
|
|
|
|
def call a
|
|
|
|
if @exe.call a
|
|
|
|
@next.call @buffer+a
|
|
|
|
@buffer = @start.dup
|
|
|
|
else
|
|
|
|
@buffer += a
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def end
|
|
|
|
@next.call @buffer
|
|
|
|
@next.end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class TopDown <Base
|
|
|
|
def initialize start, *a, &e
|
|
|
|
@next.call *a, &e
|
|
|
|
@buffer, @start = nil, start
|
|
|
|
end
|
|
|
|
|
|
|
|
def call a
|
|
|
|
if @exe.call a
|
|
|
|
@next.call @buffer
|
|
|
|
@buffer = @start.dup+a
|
|
|
|
else
|
|
|
|
@buffer += a
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def end
|
|
|
|
@next.call @buffer
|
|
|
|
@next.end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Each <Base
|
|
|
|
def end
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class P <Each
|
|
|
|
def initialize *a
|
|
|
|
super *a, &Kernel.method( :p)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Inject <Base
|
|
|
|
attr_reader :it
|
|
|
|
def initialize start, *a, &e
|
|
|
|
super *a, &e
|
|
|
|
@it = start
|
|
|
|
end
|
|
|
|
def call *a
|
|
|
|
@it = @exe.call @it, *a
|
|
|
|
end
|
|
|
|
def end
|
|
|
|
@it
|
|
|
|
end
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
|
|
|
|
2010-05-20 17:07:23 +02:00
|
|
|
class To_a <Inject
|
|
|
|
def initialize *a, &e
|
|
|
|
super [], *a, &e
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-05-23 22:20:53 +02:00
|
|
|
class Map <Collect
|
|
|
|
def call *a
|
2010-05-25 19:02:49 +02:00
|
|
|
@exe.call *a, &@next
|
2010-05-23 22:20:53 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-06-23 16:40:01 +02:00
|
|
|
class Flatten <Base
|
|
|
|
def call a
|
|
|
|
Array === a ? a.each( &method( :call)) : @next.call( a)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-05-23 22:20:53 +02:00
|
|
|
class Reduce <Base
|
2010-05-25 19:02:49 +02:00
|
|
|
def initialize iv, *a, &e
|
|
|
|
super *a, &e
|
2010-05-23 22:20:53 +02:00
|
|
|
@buf = {}
|
|
|
|
@buf.default = iv
|
|
|
|
end
|
|
|
|
|
|
|
|
def call *a
|
2010-05-25 19:02:49 +02:00
|
|
|
@buf[ a[0]] = @exe.call @buf[ a[0]], *a[1..-1]
|
|
|
|
end
|
|
|
|
|
|
|
|
def end
|
|
|
|
@buf.each {|i| @next.call *i}
|
|
|
|
@next.end
|
2010-05-23 22:20:53 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-05-20 17:07:23 +02:00
|
|
|
attr_accessor :next, :stack, :obj, :func, :args
|
|
|
|
|
2010-04-19 20:22:54 +02:00
|
|
|
def initialize obj = nil, func = nil, *args
|
2010-05-20 17:07:23 +02:00
|
|
|
@next, @stack, @obj, @func, @args = self, self, obj, func, args
|
|
|
|
end
|
|
|
|
|
|
|
|
def push a
|
|
|
|
@stack = @stack.next = a
|
|
|
|
self
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def collect &exe
|
2010-05-20 17:07:23 +02:00
|
|
|
push Collect.new( &exe)
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
|
|
|
|
2010-05-25 19:02:49 +02:00
|
|
|
def map &exe
|
2010-05-23 22:20:53 +02:00
|
|
|
push Map.new( &exe)
|
2010-04-19 21:22:30 +02:00
|
|
|
end
|
|
|
|
|
2010-05-25 19:02:49 +02:00
|
|
|
def reduce iv, &exe
|
|
|
|
push Reduce.new( iv, &exe)
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
2010-04-19 21:08:49 +02:00
|
|
|
|
2010-04-19 20:22:54 +02:00
|
|
|
def select &exe
|
2010-05-20 17:07:23 +02:00
|
|
|
push Select.new( &exe)
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
|
|
|
|
2010-05-20 17:07:23 +02:00
|
|
|
def grep re
|
|
|
|
push Select.new( &re.method( :match))
|
2010-05-20 14:48:42 +02:00
|
|
|
end
|
|
|
|
|
2010-04-19 20:22:54 +02:00
|
|
|
def delete_if &exe
|
2010-05-20 17:07:23 +02:00
|
|
|
push DeleteIf.new( &exe)
|
2010-04-20 16:50:59 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def compact
|
2010-05-20 17:07:23 +02:00
|
|
|
push Compact.new
|
|
|
|
end
|
|
|
|
|
|
|
|
def updown init, &exe
|
|
|
|
push UpDown.new( init, &exe)
|
2010-04-20 16:50:59 +02:00
|
|
|
end
|
|
|
|
|
2010-05-20 17:07:23 +02:00
|
|
|
def topdown init, &exe
|
|
|
|
push TopDown.new( init, &exe)
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
|
|
|
|
2010-06-23 16:40:01 +02:00
|
|
|
def flatten
|
|
|
|
push Flatten.new
|
|
|
|
end
|
|
|
|
|
2010-04-19 21:22:30 +02:00
|
|
|
def each &exe
|
2010-05-20 21:28:39 +02:00
|
|
|
return self unless exe
|
2010-05-20 17:07:23 +02:00
|
|
|
push Each.new
|
|
|
|
push exe
|
|
|
|
run
|
|
|
|
end
|
|
|
|
|
2010-05-20 21:28:39 +02:00
|
|
|
def join deli
|
|
|
|
push Inject.new('') {|i,j|i+deli+j}
|
|
|
|
run
|
|
|
|
end
|
|
|
|
|
2010-05-20 17:07:23 +02:00
|
|
|
def run
|
2010-05-23 22:20:53 +02:00
|
|
|
@obj.send @func||:each, *@args, &@next #.method(:call)
|
2010-05-20 17:07:23 +02:00
|
|
|
@next.end
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
2010-04-20 18:54:35 +02:00
|
|
|
|
|
|
|
def p
|
2010-05-25 19:02:49 +02:00
|
|
|
each {|*a|Kernel.p a}
|
2010-04-20 18:54:35 +02:00
|
|
|
end
|
2010-04-19 20:22:54 +02:00
|
|
|
end
|
2010-05-20 21:28:39 +02:00
|
|
|
|
|
|
|
begin
|
|
|
|
require 'tokyocabinet'
|
|
|
|
|
|
|
|
class Functional
|
|
|
|
class Map <Base
|
|
|
|
class Emit < TokyoCabinet::BDB
|
|
|
|
alias emit putdup
|
|
|
|
alias call emit
|
|
|
|
end
|
|
|
|
|
|
|
|
def call *a
|
2010-05-23 22:20:53 +02:00
|
|
|
@exe.call( *a).each &@next
|
2010-05-20 21:28:39 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def map name, &e
|
|
|
|
push Map.new( name, &e)
|
|
|
|
end
|
|
|
|
|
|
|
|
def Reduce name, &e
|
|
|
|
push Reduce.new( name, &e)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
rescue MissingSourceFile
|
|
|
|
# TokyoCabinet not installed?
|
2010-05-23 22:20:53 +02:00
|
|
|
end if false
|