require "cgi" require "rbconfig" require "thread" Thread.abort_on_exception = true $DEBUG = ($DEBUG or ENV["RUBYDEBUG"] or false) #tekens = '\w\~\@\#\$\%\^\&\*\-\+' tekens = '^\s\r\n\`\!\(\)\[\]\{\}\<\>\,\.\/\?\\\|\=\;\:\"' #tekens11 = '\w' tekens11 = tekens + "'" tekens21 = tekens + "'" tekens22 = tekens tekens23 = tekens + "'" tekens31 = '\w\s\r\n' RegExpStringWord = "([#{tekens11}]+)" ; RegExpWord = Regexp.new(RegExpStringWord) RegExpStringWord2 = "([#{tekens21}]([#{tekens22}]*[#{tekens23}])?)" ; RegExpWord2 = Regexp.new(RegExpStringWord2) RegExpStringText = "([#{tekens31}]+)" ; RegExpText = Regexp.new(RegExpStringText) RegExpStringFile = '(\w[\w\.\-]*)' ; RegExpFile = Regexp.new(RegExpStringFile) RegExpStringEmail = '([\w\-\.]+@[\w\-\.]+)' ; RegExpEmail = Regexp.new(RegExpStringEmail) RegExpStringURL = '(\w+:\/\/[\w\.\-]+(:\d*)?\/[\w\.\-\/\#\?\=\%]*)' ; RegExpURL = Regexp.new(RegExpStringURL) RegExpStringPrint = '([\w \t\r\n\`\~\!\@\#\$\%\^\&\*\(\)\-\+\=\[\]\{\}\;\:\'\"\,\.\/\<\>\?\\\|]+)' ; RegExpPrint = Regexp.new(RegExpStringPrint) RegExpStringDiff = '(^[\-\+]([^\-\+].*)?)' ; RegExpDiff = Regexp.new(RegExpStringDiff) module Enumerable def deep_dup Marshal::load(Marshal::dump(dup)) end def deep_clone Marshal::load(Marshal::dump(clone)) end end class Thread def self.background(*args) new(*args) do |*args| Thread.pass yield(*args) end end end class Object alias deep_dup :dup alias deep_clone :clone def to_fs to_s end def ids id end end class Numeric def to_fs to_f end end class Integer def oct n = self res = [] while n > 8 n, x = n.divmod(8) res << x end res << n res.reverse.join("") end end class String def chomp!(dummy=nil) self.gsub!(/[\r\n]*\z/, "") end def chomp(dummy=nil) self.gsub(/[\r\n]*\z/, "") end def lf self.gsub(/\r*\n/, "\n").gsub(/\n\z/, "") + "\n" end def crlf self.gsub(/\r*\n/, "\r\n").gsub(/\r\n\z/, "") + "\r\n" end def strip self.stripbefore.stripafter end def stripbefore self.gsub(/\A[[:blank:]\r\n]*/, "") end def stripafter self.gsub(/[[:blank:]\r\n]*\z/, "") end def compress self.gsub(/[[:blank:]\r\n]+/, " ").strip end def compressspaces self.gsub(/[[:blank:]]+/, " ") end def compressperline res = self.split(/\n/) res.collect!{|line| line.compress} res.delete_if{|line| line.empty?} res.join("\n") end def numeric? d, a, n = [self].to_par not n.empty? end def exec(input=nil, output=true) res = [] IO.popen(self, "w+") do |f| f.puts input unless input.nil? f.close_write res = f.readlines if output end res.join("") end def eval Kernel::eval(self) end def speak require "drb" DRb.start_service DRbObject.new(nil, "druby://localhost:3100").speak(self) end def splitblocks(*delimiters) begindelimiters = [] enddelimiters = [] delimiters.each do |k, v| begindelimiters << k.downcase enddelimiters << v.downcase end bd = begindelimiters.collect {|s| Regexp.escape(s)} ed = enddelimiters.collect {|s| Regexp.escape(s)} be = bd.join("|") ee = ed.join("|") res = [] type = 0 tmp = "" bs = "" es = "" self.split(/(#{ee}|#{be})/i).each do |s| if type == 0 if begindelimiters.include?(s.downcase) i = begindelimiters.index(s.downcase) type = i+1 tmp = s bs = s.downcase es = enddelimiters[i] else res << [0, s] unless s.empty? end else if s.downcase == es res << [type, tmp + s] type = 0 tmp = "" bs = "" es = "" else if s.downcase == bs res << [0, tmp] tmp = s else tmp = tmp + s end end end end res << [0, tmp] unless tmp.empty? return res end def splitwords(tokens=[]) tokens = [tokens] unless tokens.kind_of?(Array) res = [] self.splitblocks(["'", "'"], ['"', '"']).each do |type, s| case type when 0 tokens.each do |token| token2 = token token2 = Regexp.escape(token2) if token2.kind_of?(String) s.gsub!(/#{token2}/, " #{token} ") end s.split().each do |w| res << w end when 1, 2 res << s[1..-2] end end return res end def uncomment res = [] self.splitblocks(["'", "'"], ['"', '"'], ["#", "\n"]).each do |type, s| case type when 0, 1, 2 then res << s when 3 then res << "\n" end end res.join("") end def noquotes self.sub(/\A['"]/, "").sub(/['"]\z/, "") end def to_html(eolconversion=true) s = CGI.escapeHTML(self) s.gsub!(/\"/, "\"") s.gsub!(/\'/, "\´") if eolconversion s.gsub!(/\n/ , "
") end s end def from_html(eolconversion=true) s = self s.gsub!(/"/ , "\"") s.gsub!(/´/, "\'") s = CGI.unescapeHTML(self) if eolconversion s.gsub!(/
/, "\n") end s end def to_fs if numeric? to_f else to_s end end end class Array def chomp! self.collect!{|s| s.chomp} end def chomp self.collect{|s| s.chomp} end def compress self.collect{|s| s.compress} end def uncomment self.join("\0").uncomment.split("\0") end def strip self.collect{|s| s.strip} end def sum res = 0 self.each do |n| res += n end res end def product res = 1 self.each do |n| res *= n end res end def joinwords(sep=" ", quote='"') self.collect do |s| s = quote + s + quote if s =~ /[[:blank:]]/ s end.join(sep) end def domino(tabellen, kolom=nil, onlymatchinglines=false) links = self res = [] res = self.dup unless onlymatchinglines tabellen.each do |rechts| tmp = [] links.each do |l| if kolom.nil? or l.length == kolom rechts.each do |r| tmp << l + r[1..-1] if l[-1] == r[0] end end end links = tmp res.concat(tmp) end res = res.sort.uniq end def dominoloop(tabellen) lres = [] res = self.dup kolom = 2 while lres.length != res.length do lres = res.dup res = res.domino(tabellen, kolom) res.each do |line| line << "*" if (line.length != line.uniq.length and line[-1] != "*") end $stderr.print "#{100*(res.length)/(lres.length)}% " kolom += 1 end $stderr.puts "" return res end def buildtree self.dominoloop([self]) end def subset(fields, values, results, exact=true, emptyline=nil, joinwith=nil) fields = [fields] unless fields.kind_of? Array values = [values] unless values.kind_of? Array results = [results] unless results.kind_of? Array emptyline = emptyline.downcase unless emptyline.nil? res = self.dup res.delete_if {true} self.each do |l| ok = true case l.class.to_s when "String" c = l.splitwords correction = 1 joinwith = " " if joinwith.nil? when "Array" c = l correction = 0 end #catch :stop do values2 = values.dup fields.each do |f| v = values2.shift v = v.downcase unless v.nil? if emptyline.nil? or (not v == emptyline) if exact unless (v.nil? or c[f-correction].downcase == v) ok = false #throw :stop end else unless (v.nil? or c[f-correction].downcase.include?(v)) ok = false #throw :stop end end end end #end if ok res2 = [] results.each do |n| res2 << c[n-1] end res2 = res2.join(joinwith) unless joinwith.nil? res << res2 end end return res end def format(format) res = [] [format.length, self.length].min.times do |n| case format[n].chr when "i" then res << self[n].to_i when "s" then res << self[n].to_s when "x" then res << self[n] end end res end def to_i collect{|c| c.to_i} end def to_par dash = self.dup alpha = self.dup numeric = self.dup dash.delete_if do |s| not (s =~ /\A-/) or (s =~ /\A-?[[:digit:]\.]+\z/) or (s =~ /^-+$/) end alpha.delete_if do |s| ((s =~ /\A-/) or (s =~ /\A-?[[:digit:]\.]+\z/)) and not ((s =~ /^\.+$/) or (s =~ /^-+$/)) end numeric.delete_if do |s| not (s =~ /\A-?[[:digit:]\.]+\z/) or (s =~ /^\.+$/) end raise "Oops!" if dash.length + alpha.length + numeric.length != length return dash, alpha, numeric end def self.file(file) res = new File.open(file) do |f| f.readlines.uncomment.chomp.each do |line| res << line end end res end def numsort sort do |a, b| a2 = a.to_fs b2 = b.to_fs if a2.class != b2.class a2 = a b2 = b end a2 <=> b2 end end def to_fs collect{|s| s.to_fs} end def chaos res = self.dup (length^2).times do a = rand(length) b = rand(length) res[a], res[b] = res[b], res[a] end res end def any if empty? nil else self[rand(self.length)] end end def minmax min, value, max = self [min, [value, max].min].max end def ids collect{|e| e.ids} end end class Hash def save(file, append=false) org = {} org = Hash.file(file) if (append and File.file?(file)) self.sort.each do |k, v| org[k] = v end File.open(file, "w") do |f| org.sort.each do |k, v| f.puts "%s\t= %s" % [k, v] end end end def subset(fields, values, results=nil, exact=true, emptyline=nil, joinwith=nil) fields = [fields] unless fields.kind_of? Array values = [values] unless values.kind_of? Array results = [results] unless results.kind_of? Array emptyline = emptyline.downcase unless emptyline.nil? res = self.dup res.delete_if {true} self.each do |k, l| ok = true case l.class.to_s when "String" c = l.splitwords correction = 1 joinwith = " " if joinwith.nil? when "Array" c = l correction = 0 end #catch :stop do values2 = values.dup fields.each do |f| v = values2.shift v = v.downcase unless v.nil? if emptyline.nil? or (not v == emptyline) if exact unless (v.nil? or c[f-correction].downcase == v) ok = false #throw :stop end else unless (v.nil? or c[f-correction].downcase.include?(v)) ok = false #throw :stop end end end end #end if ok res2 = [] if results == [nil] res2 = c else results.each do |n| res2 << c[n-correction] end end res2 = res2.join(joinwith) unless joinwith.nil? res[k] = res2 end end return res end def to_i collect{|k, v| v.to_i} end def self.file(file) res = new File.open(file) do |f| #f.readlines.chomp.each do |line| while line = f.gets do line.chomp! unless line.empty? k, v = line.split(/\s*=\s*/, 2) res[k] = v end end end res end def ids collect{|k, v| [k, v].ids} end end def id2ref(id) ObjectSpace._id2ref(id) end def after(seconds, *args) if not seconds.nil? and not seconds.zero? Thread.new(*args) do |*args2| sleep seconds yield(*args2) end end end def every(seconds, *args) if not seconds.nil? and not seconds.zero? Thread.new(*args) do |*args2| loop do sleep seconds yield(*args2) end end end end def evtimeout(seconds) begin timeout(seconds) do yield end rescue TimeoutError end end def evtimeoutretry(seconds) ok = false while not ok evtimeout(seconds) do yield ok = true end end end def trap(signal) Kernel::trap(signal) do yield end # Seems pointless, but it's for catching ^C under Windows... every(1) {} if windows? end def linux? not windows? and not cygwin? end def windows? not (target_os.downcase =~ /32/).nil? end def cygwin? not (target_os.downcase =~ /cyg/).nil? end def target_os Config::CONFIG["target_os"] or "" end def user ENV["USER"] or ENV["USERNAME"] end def home (ENV["HOME"] or ENV["USERPROFILE"] or (File.directory?("h:/") ? "h:" : "c:")).gsub(/\\/, "/") end def temp (ENV["TMPDIR"] or ENV["TMP"] or ENV["TEMP"] or "/tmp").gsub(/\\/, "/") end def stdtmp $stderr = $stdout = File.new("#{temp}/ruby.#{Process.pid}.log", "a") unless ARGV.include?("--rwd-exit") end $nobm = false def nobm $nobm = true end def bm(label="") if $nobm if block_given? return yield else return nil end end label = label.to_s res = nil $bm_mutex = ($bm_mutex or Mutex.new) $bm_mutex.synchronize do if $bm.nil? require "ev/bm" $bm = {} at_exit do format1 = "%10s %10s %10s %10s %10s %10s %10s" format2 = "%10s %10.6f %10.6f %10.6f %10.6f %10.6f %10d" $stderr.puts format1 % ["LABEL", "USERCPU", "SYSCPU", "CUSERCPU", "CSYSCPU", "ELAPSED", "TIMES"] $bm.sort{|a, b| [a[1], a[0]] <=> [b[1], b[0]]}.each do |k, v| $stderr.puts format2 % [k, *v] end end end $bm[label] = [0.0]*5 + [0] unless $bm.include?(label) end if block_given? bm = Benchmark.measure{res = yield} bma = bm.to_a # [dummy label, user CPU time, system CPU time, childrens user CPU time, childrens system CPU time, elapsed real time] $bm_mutex.synchronize do 0.upto(4) do |n| $bm[label][n] += bma[n+1] end $bm[label][5] += 1 end end res end def trace res =nil set_trace_func lambda { |event, file, line, id, binding, classname| $stderr.printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname } if block_given? res = yield notrace end res end def notrace set_trace_func nil end def lambda_cached(&block) hash = {} lambda do |*args| res = hash[args] if res.nil? res = block.call(*args) hash[args] = res end res end end