diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base64.rb | 2 | ||||
-rw-r--r-- | lib/cgi-lib.rb | 56 | ||||
-rw-r--r-- | lib/complex.rb | 490 | ||||
-rw-r--r-- | lib/find.rb | 47 | ||||
-rw-r--r-- | lib/getopts.rb | 173 | ||||
-rw-r--r-- | lib/jcode.rb | 174 | ||||
-rw-r--r-- | lib/mailread.rb | 19 | ||||
-rw-r--r-- | lib/mathn.rb | 307 | ||||
-rw-r--r-- | lib/observer.rb | 40 | ||||
-rw-r--r-- | lib/parsearg.rb | 103 | ||||
-rw-r--r-- | lib/rational.rb | 361 | ||||
-rw-r--r-- | lib/safe.rb | 78 | ||||
-rw-r--r-- | lib/thread.rb | 153 | ||||
-rw-r--r-- | lib/tk.rb | 557 | ||||
-rw-r--r-- | lib/tkcanvas.rb | 47 | ||||
-rw-r--r-- | lib/tkcore.rb | 521 | ||||
-rw-r--r-- | lib/tkentry.rb | 2 | ||||
-rw-r--r-- | lib/tkscrollbox.rb | 27 | ||||
-rw-r--r-- | lib/tktext.rb | 18 | ||||
-rw-r--r-- | lib/tkthcore.rb | 546 |
20 files changed, 3036 insertions, 685 deletions
diff --git a/lib/base64.rb b/lib/base64.rb index a6bf1adf92..9bb6487bee 100644 --- a/lib/base64.rb +++ b/lib/base64.rb @@ -46,7 +46,7 @@ def j2e(str) end def decode_b(str) - str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/) { + str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) { decode64($1) } str.gsub!(/\n/, ' ') diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb new file mode 100644 index 0000000000..afadbff3b6 --- /dev/null +++ b/lib/cgi-lib.rb @@ -0,0 +1,56 @@ +#!/usr/local/bin/ruby +# +# Get CGI String +# +# EXAMPLE: +# require "cgi-lib.rb" +# foo = CGI.new +# foo['field'] <== value of 'field' +# foo.keys <== array of fields +# foo.inputs <== hash of { <field> => <value> } + +class CGI + attr("inputs") + + def initialize + str = if ENV['REQUEST_METHOD'] == "GET" + ENV['QUERY_STRING'] + elsif ENV['REQUEST_METHOD'] == "POST" + $stdin.read ENV['CONTENT_LENGTH'].to_i + else + "" + end + arr = str.split(/&/) + @inputs = {} + arr.each do |x| + x.gsub!(/\+/, ' ') + key, val = x.split(/=/, 2) + val = "" unless val + + key.gsub!(/%(..)/) { [$1.hex].pack("c") } + val.gsub!(/%(..)/) { [$1.hex].pack("c") } + + @inputs[key] += "\0" if @inputs[key] + @inputs[key] += val + end + end + + def keys + @inputs.keys + end + + def [](key) + @inputs[key] + end + + def CGI.message(msg, title = "") + print "Content-type: text/html\n\n" + print "<html><head><title>" + print title + print "</title></head><body>\n" + print msg + print "</body></html>\n" + TRUE + end + +end diff --git a/lib/complex.rb b/lib/complex.rb new file mode 100644 index 0000000000..aa5d219d2f --- /dev/null +++ b/lib/complex.rb @@ -0,0 +1,490 @@ +# +# complex.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:19 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# Usage: +# class Complex < Numeric +# +# Complex(x, y) --> x + yi +# y.im --> 0 + yi +# +# Complex::polar +# +# Complex::+ +# Complex::- +# Complex::* +# Complex::/ +# Complex::** +# Complex::% +# Complex::divmod +# Complex::abs +# Complex::abs2 +# Complex::arg +# Complex::polar +# Complex::conjugate +# Complex::<=> +# Complex::== +# Complex::to_i +# Complex::to_f +# Complex::to_r +# Complex::to_s +# +# Complex::I +# +# Numeric::im +# +# Math.sqrt +# Math.exp +# Math.cos +# Math.sin +# Math.tan +# Math.log +# Math.log10 +# Math.atan2 +# +# + +def Complex(a, b = 0) + if a.kind_of?(Complex) and b == 0 + a + elsif b == 0 and defined? Complex::Unify + a + else + Complex.new(a, b) + end +end + +class Complex < Numeric + + def Complex.generic?(other) + other.kind_of?(Integer) or + other.kind_of?(Float) or + (defined?(Rational) and other.kind_of?(Rational)) + end + + def Complex.polar(r, theta) + Complex(r*Math.cos(theta), r*Math.sin(theta)) + end + + def initialize(a, b = 0) + @real = a + @image = b + end + + def + (other) + if other.kind_of?(Complex) + re = @real + other.real + im = @image + other.image + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real + other, @image) + else + x , y = a.coerce(self) + x + y + end + end + + def - (other) + if other.kind_of?(Complex) + re = @real - other.real + im = @image - other.image + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real - other, @image) + else + x , y = a.coerce(self) + x - y + end + end + + def * (other) + if other.kind_of?(Complex) + re = @real*other.real - @image*other.image + im = @real*other.image + @image*other.real + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real * other, @image * other) + else + x , y = a.coerce(self) + x * y + end + end + + def / (other) + if other.kind_of?(Complex) + self * other.conjugate / other.abs2 + elsif Complex.generic?(other) + Complex(@real / other, @image / other) + else + x , y = a.coerce(self) + x / y + end + end + + def ** (other) + if other == 0 + return Complex(1) + end + if other.kind_of?(Complex) + r, theta = polar + ore = other.real + oim = other.image + nr = Math.exp!(ore*Math.log!(r) - oim * theta) + ntheta = theta*ore + oim*Math.log!(r) + Complex.polar(nr, ntheta) + elsif other.kind_of?(Integer) + if other > 0 + x = self + z = x + n = other - 1 + while n != 0 + while (div, mod = n.divmod(2) + mod == 0) + x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image) + n = div + end + z *= x + n -= 1 + end + z + else + if defined? Rational + (Rational(1) / self) ** -other + else + self ** Float(other) + end + end + elsif Complex.generic?(other) + r, theta = polar + Complex.polar(r.power!(other), theta * other) + else + x , y = a.coerce(self) + x / y + end + end + + def % (other) + if other.kind_of?(Complex) + Complex(@real % other.real, @image % other.image) + elsif Complex.generic?(other) + Complex(@real % other, @image % other) + else + x , y = a.coerce(self) + x % y + end + end + + def divmod(other) + if other.kind_of?(Complex) + rdiv, rmod = @real.divmod(other.real) + idiv, imod = @image.divmod(other.image) + return Complex(rdiv, idiv), Complex(rmod, rdiv) + elsif Complex.generic?(other) + Complex(@real.divmod(other), @image.divmod(other)) + else + x , y = a.coerce(self) + x.divmod(y) + end + end + + def abs + Math.sqrt!((@real*@real + @image*@image).to_f) + end + + def abs2 + @real*@real + @image*@image + end + + def arg + Math.atan2(@image.to_f, @real.to_f) + end + + def polar + return abs, arg + end + + def conjugate + Complex(@real, -@image) + end + + def <=> (other) + self.abs <=> other.abs + end + + def == (other) + if other.kind_of?(Complex) + @real == other.real and @image == other.image + elsif Complex.generic?(other) + @real == other and @image == 0 + else + x , y = a.coerce(self) + x == y + end + end + + def coerce(other) + if Complex.generic?(other) + return Complex.new(other), self + else + super + end + end + + def to_i + Complex(@real.to_i, @image.to_i) + end + + def to_f + Complex(@real.to_f, @image.to_f) + end + + def to_r + Complex(@real.to_r, @image.to_r) + end + + def denominator + @real.denominator.lcm(@image.denominator) + end + + def numerator + cd = denominator + Complex(@real.numerator*(cd/@real.denominator), + @image.numerator*(cd/@image.denominator)) + end + + def to_s + if @real != 0 + if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 + if @image >= 0 + @real.to_s+"+("+@image.to_s+")i" + else + @real.to_s+"-("+(-@image).to_s+")i" + end + else + if @image >= 0 + @real.to_s+"+"+@image.to_s+"i" + else + @real.to_s+"-"+(-@image).to_s+"i" + end + end + else + if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 + "("+@image.to_s+")i" + else + @image.to_s+"i" + end + end + end + + def hash + @real ^ @image + end + + I = Complex(0,1) + + attr :real + attr :image + +end + +class Numeric + def im + Complex(0, self) + end + + def real + self + end + + def image + 0 + end + + def arg + if self >= 0 + return 0 + else + return Math.atan2(1,1)*4 + end + end + + def polar + return abs, arg + end + + def conjugate + self + end +end + +class Fixnum + if not defined? Rational + alias power! ** + end + + def ** (other) + if self < 0 + Complex.new(self) ** other + else + if defined? Rational + if other >= 0 + self.power!(other) + else + Rational.new!(self,1)**other + end + else + self.power!(other) + end + end + end +end + +class Bignum + if not defined? Rational + alias power! ** + end +end + +class Float + alias power! ** +end + +module Math + alias sqrt! sqrt + alias exp! exp + alias cos! cos + alias sin! sin + alias tan! tan + alias log! log + alias log10! log10 + alias atan2! atan2 + + def sqrt(z) + if Complex.generic?(z) + if z >= 0 + sqrt!(z) + else + Complex(0,sqrt!(-z)) + end + else + z**Rational(1,2) + end + end + + def exp(z) + if Complex.generic?(z) + exp!(z) + else + Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image)) + end + end + + def cosh!(x) + (exp!(x) + exp!(-x))/2.0 + end + + def sinh!(x) + (exp!(x) - exp!(-x))/2.0 + end + + def cos(z) + if Complex.generic?(z) + cos!(z) + else + Complex(cos!(z.real)*cosh!(z.image), + sin!(z.real)*sinh!(z.image)) + end + end + + def sin(z) + if Complex.generic?(z) + sin!(z) + else + Complex(sin!(z.real)*cosh!(z.image), + -cos!(z.real)*sinh!(z.image)) + end + end + + def tan(z) + if Complex.generic?(z) + tan!(z) + else + sin(z)/cos(z) + end + end + + def log(z) + if Complex.generic?(z) and z >= 0 + log!(z) + else + r, theta = z.polar + Complex(log!(r.abs), theta) + end + end + + def log10(z) + if Complex.generic?(z) + log10!(z) + else + log(z)/log!(10) + end + end + + def atan2(x, y) + if Complex.generic?(x) and Complex.generic?(y) + atan2!(x, y) + else + fail "Not yet implemented." + end + end + + def atanh!(x) + log((1.0 + x.to_f) / ( 1.0 - x.to_f)) / 2.0 + end + + def atan(z) + if Complex.generic?(z) + atan2!(z, 1) + elsif z.image == 0 + atan2(z.real,1) + else + a = z.real + b = z.image + + c = (a*a + b*b - 1.0) + d = (a*a + b*b + 1.0) + + Complex(atan2!((c + sqrt(c*c + 4.0*a*a)), 2.0*a), + atanh!((-d + sqrt(d*d - 4.0*b*b))/(2.0*b))) + end + end + + module_function :sqrt + module_function :sqrt! + module_function :exp! + module_function :exp + module_function :cosh! + module_function :cos! + module_function :cos + module_function :sinh! + module_function :sin! + module_function :sin + module_function :tan! + module_function :tan + module_function :log! + module_function :log + module_function :log10! + module_function :log + module_function :atan2! + module_function :atan2 +# module_function :atan! + module_function :atan + module_function :atanh! + +end + + diff --git a/lib/find.rb b/lib/find.rb index 340461c653..5ecc54329c 100644 --- a/lib/find.rb +++ b/lib/find.rb @@ -8,31 +8,32 @@ # module Find - extend Find - - def findpath(path, ary) - ary.push(path) - d = Dir.open(path) - for f in d - continue if f =~ /^\.\.?$/ - f = path + "/" + f - if File.directory? f - findpath(f, ary) - else - ary.push(f) - end + def find(*path) + while file = path.shift + catch(:prune) { + yield file + if File.directory? file and not File.symlink? file then + d = Dir.open(file) + begin + for f in d + next if f =~ /^\.\.?$/ + if file == "/" then + f = "/" + f + else + f = file + "/" + f + end + path.unshift f + end + ensure + d.close + end + end + } end end - private :findpath - def find(*path) - ary = [] - for p in path - findpath(p, ary) - for f in ary - yield f - end - end + def prune + throw :prune end - module_function :find + module_function :find, :prune end diff --git a/lib/getopts.rb b/lib/getopts.rb index 37fd3dc69d..d25437515d 100644 --- a/lib/getopts.rb +++ b/lib/getopts.rb @@ -1,117 +1,142 @@ +#!/usr/local/bin/ruby # -# getopts.rb - get options +# getopts.rb - # $Release Version: $ -# $Revision: 1.2 $ -# $Date: 1994/02/15 05:17:15 $ -# by Yasuo OHBA(STAFS Development Room) +# $Revision: 1.1 $ +# $Date: 1996/11/10 05:01:15 $ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- -# オプションの解析をし, $OPT_?? に値をセットします. -# 指定のないオプションが指定された時は nil を返します. -# 正常終了した場合は, セットされたオプションの数を返します. # -# getopts(single_opts, *opts) -# -# ex. sample [options] filename -# options ... -# -f -x --version --geometry 100x200 -d unix:0.0 -# ↓ -# getopts("fx", "version", "geometry:", "d:") -# -# 第一引数: -# -f や -x (= -fx) の様な一文字のオプションの指定をします. -# ここで引数がないときは nil の指定が必要です. -# 第二引数以降: -# ロングネームのオプションや, 引数の伴うオプションの指定をします. -# --version や, --geometry 300x400 や, -d host:0.0 等です. -# 引数を伴う指定は ":" を必ず付けてください. -# -# オプションの指定があった場合, 変数 $OPT_?? に non-nil もしくは, そのオ -# プションの引数がセットされます. -# -f -> $OPT_f = TRUE -# --geometry 300x400 -> $OPT_geometry = 300x400 -# -# - もしくは -- は, それ以降, 全てオプションの解析をしません. +# # -$RCS_ID="$Header: /var/ohba/RCS/getopts.rb,v 1.2 1994/02/15 05:17:15 ohba Exp ohba $" +$RCS_ID="$Header: /home/jammy/current/ruby/RCS/getopts.rb,v 1.1 1996/11/10 05:01:15 jammy Exp $" + +def isSingle(lopt) + if lopt.index(":") + if lopt.split(":")[0].length == 1 + return TRUE + end + end + return nil +end + +def getOptionName(lopt) + return lopt.split(":")[0] +end + +def getDefaultOption(lopt) + od = lopt.split(":")[1] + if od + return od + end + return nil +end + +def setOption(name, value) + eval("$OPT_" + name + " = " + 'value') +end + +def setDefaultOption(lopt) + d = getDefaultOption(lopt) + if d + setOption(getOptionName(lopt), d) + end +end + +def setNewArgv(newargv) + ARGV.clear + for na in newargv + ARGV << na + end +end -def getopts(single_opts, *opts) - if (opts) + +def getopts(single_opts, *options) + if options single_colon = "" long_opts = [] sc = 0 - for option in opts - if (option.length <= 2) - single_colon[sc, 0] = option[0, 1] + for o in options + setDefaultOption(o) + if isSingle(o) + single_colon[sc, 0] = getOptionName(o) sc += 1 else - long_opts.push(option) + long_opts.push(o) end end end - + opts = {} count = 0 - while ($ARGV.length != 0) + newargv = [] + while ARGV.length != 0 compare = nil - case $ARGV[0] + case ARGV[0] when /^--?$/ - $ARGV.shift + ARGV.shift + newargv += ARGV break when /^--.*/ - compare = $ARGV[0][2, ($ARGV[0].length - 2)] - if (long_opts != "") - for option in long_opts - if (option[(option.length - 1), 1] == ":" && - option[0, (option.length - 1)] == compare) - if ($ARGV.length <= 1) + compare = ARGV[0][2, (ARGV[0].length - 2)] + if long_opts != "" + for lo in long_opts + if lo.index(":") && getOptionName(lo) == compare + if ARGV.length <= 1 return nil - end - eval("$OPT_" + compare + " = " + '$ARGV[1]') - opts[compare] = TRUE - $ARGV.shift + end + setOption(compare, ARGV[1]) + opts[compare] = TRUE + ARGV.shift count += 1 break - elsif (option == compare) - eval("$OPT_" + compare + " = TRUE") - opts[compare] = TRUE + elsif lo == compare + setOption(compare, TRUE) + opts[compare] = TRUE count += 1 - break - end - end + break + end + end + end + if compare.length <= 1 + return nil end when /^-.*/ - for index in 1..($ARGV[0].length - 1) - compare = $ARGV[0][index, 1] - if (single_opts && compare =~ "[" + single_opts + "]") - eval("$OPT_" + compare + " = TRUE") - opts[compare] = TRUE + for idx in 1..(ARGV[0].length - 1) + compare = ARGV[0][idx, 1] + if single_opts && compare =~ "[" + single_opts + "]" + setOption(compare, TRUE) + opts[compare] = TRUE count += 1 - elsif (single_colon != "" && compare =~ "[" + single_colon + "]") - if ($ARGV[0][index..-1].length > 1) - eval("$OPT_" + compare + " = " + '$ARGV[0][(index + 1)..-1]') - opts[compare] = TRUE + elsif single_colon != "" && compare =~ "[" + single_colon + "]" + if ARGV[0][idx..-1].length > 1 + setOption(compare, ARGV[0][(idx + 1)..-1]) + opts[compare] = TRUE count += 1 - elsif ($ARGV.length <= 1) + elsif ARGV.length <= 1 return nil else - eval("$OPT_" + compare + " = " + '$ARGV[1]') - opts[compare] = TRUE - $ARGV.shift - count = count + 1 + setOption(compare, ARGV[1]) + opts[compare] = TRUE + ARGV.shift + count += 1 end break end end else - break + compare = ARGV[0] + opts[compare] = TRUE + newargv << ARGV[0] end - - $ARGV.shift - if (!opts.includes(compare)) + + ARGV.shift + if !opts.has_key?(compare) return nil end end + setNewArgv(newargv) return count end diff --git a/lib/jcode.rb b/lib/jcode.rb new file mode 100644 index 0000000000..5b2289932f --- /dev/null +++ b/lib/jcode.rb @@ -0,0 +1,174 @@ +# jcode.rb - ruby code to handle japanese (EUC/SJIS) string + +class String + printf STDERR, "feel free for some warnings:\n" if $VERBOSE + + alias original_succ succ + private :original_succ + + def succ + if self[-2] && self[-2] & 0x80 != 0 + s = self.dup + s[-1] += 1 + return s + else + original_succ + end + end + + def upto(to) + return if self > to + + curr = self + tail = self[-2..-1] + if tail.length == 2 and tail =~ /^.$/ then + if self[0..-2] == to[0..-2] + for c in self[-1] .. to[-1] + yield self[0..-2]+c.chr + end + end + else + loop do + yield curr + return if curr == to + curr = curr.succ + return if curr.length > to.length + end + end + return nil + end + + def _expand_ch + a = [] + self.scan(/(.|\n)-(.|\n)|(.|\n)/) do |r| + if $3 + a.push $3 + elsif $1.length != $2.length + next + elsif $1.length == 1 + $1[0].upto($2[0]) { |c| a.push c.chr } + else + $1.upto($2) { |c| a.push c } + end + end + a + end + + def tr!(from, to) + return self.delete!(from) if to.length == 0 + + if from =~ /^\^/ + comp=TRUE + from = $' + end + afrom = from._expand_ch + ato = to._expand_ch + i = 0 + if comp + self.gsub!(/(.|\n)/) do |c| + unless afrom.include?(c) + ato[-1] + else + c + end + end + else + self.gsub!(/(.|\n)/) do |c| + if i = afrom.index(c) + if i < ato.size then ato[i] else ato[-1] end + else + c + end + end + end + end + + def tr(from, to) + self.dup.tr!(from, to) + end + + def delete!(del) + if del =~ /^\^/ + comp=TRUE + del = $' + end + adel = del._expand_ch + if comp + self.gsub!(/(.|\n)/) do |c| + next unless adel.include?(c) + c + end + else + self.gsub!(/(.|\n)/) do |c| + next if adel.include?(c) + c + end + end + end + + def delete(del) + self.dup.delete!(del) + end + + def squeeze!(del=nil) + if del + if del =~ /^\^/ + comp=TRUE + del = $' + end + adel = del._expand_ch + if comp + self.gsub!(/(.|\n)\1+/) do + next unless adel.include?($1) + $& + end + else + for c in adel + cq = Regexp.quote(c) + self.gsub!(/#{cq}(#{cq})+/, cq) + end + end + self + else + self.gsub!(/(.|\n)\1+/, '\1') + end + end + + def squeeze(del=nil) + self.dup.squeeze!(del) + end + + def tr_s!(from, to) + return self.delete!(from) if to.length == 0 + if from =~ /^\^/ + comp=TRUE + from = $' + end + afrom = from._expand_ch + ato = to._expand_ch + i = 0 + c = nil + last = nil + self.gsub!(/(.|\n)/) do |c| + if comp + unless afrom.include?(c) + ato[-1] + else + c + end + elsif i = afrom.index(c) + c = if i < ato.size then ato[i] else ato[-1] end + next if c == last + last = c + else + last = nil + c + end + end + end + + def tr_s(from, to) + self.dup.tr_s!(from,to) + end + +end diff --git a/lib/mailread.rb b/lib/mailread.rb index 4b04445beb..d9feffbb7a 100644 --- a/lib/mailread.rb +++ b/lib/mailread.rb @@ -1,9 +1,8 @@ class Mail - def Mail.new(f) - if !f.is_kind_of?(IO) + unless f.kind_of?(IO) f = open(f, "r") - me = super + me = super(f) f.close else me = super @@ -16,17 +15,18 @@ class Mail @body = [] while f.gets() $_.chop! - continue if /^From / # skip From-line + next if /^From / # skip From-line break if /^$/ # end of header + if /^(\S+):\s*(.*)/ - @header[attr = $1.capitalize] = $2 + @header[attr = $1.capitalize!] = $2 elsif attr - sub(/^\s*/, '') + sub!(/^\s*/, '') @header[attr] += "\n" + $_ end end - - return if ! $_ + + return unless $_ while f.gets() break if /^From / @@ -42,4 +42,7 @@ class Mail return @body end + def [](field) + @header[field] + end end diff --git a/lib/mathn.rb b/lib/mathn.rb new file mode 100644 index 0000000000..359cb45769 --- /dev/null +++ b/lib/mathn.rb @@ -0,0 +1,307 @@ +# +# mathn.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:24 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# +# +# + +require "rational.rb" +require "complex.rb" + +class Integer + + def gcd2(int) + a = self.abs + b = int.abs + a, b = b, a if a < b + + pd_a = a.prime_division + pd_b = b.prime_division + + gcd = 1 + for pair in pd_a + as = pd_b.assoc(pair[0]) + if as + gcd *= as[0] ** [as[1], pair[1]].min + end + end + return gcd + end + + def Integer.from_prime_division(pd) + value = 1 + for prime, index in pd + value *= prime**index + end + value + end + + def prime_division + ps = Prime.new + value = self + pv = [] + for prime in ps + count = 0 + while (value1, mod = value.divmod(prime) + mod) == 0 + value = value1 + count += 1 + end + if count != 0 + pv.push [prime, count] + end + break if prime * prime >= value + end + if value > 1 + pv.push [value, 1] + end + return pv + end +end + +class Prime + include Enumerable + + def initialize + @seed = 1 + @primes = [] + @counts = [] + end + + def succ + i = -1 + size = @primes.size + while i < size + if i == -1 + @seed += 1 + i += 1 + else + while @seed > @counts[i] + @counts[i] += @primes[i] + end + if @seed != @counts[i] + i += 1 + else + i = -1 + end + end + end + @primes.push @seed + @counts.push @seed + @seed + return @seed + end + + def each + loop do + yield succ + end + end +end + +class Fixnum + alias divmod! divmod + alias / rdiv + def divmod(other) + a = self.div(other) + b = self % other + return a,b + end +end + +class Bignum + alias divmod! divmod + alias / rdiv +end + +class Rational + Unify = TRUE + + alias power! ** + + def ** (other) + if other.kind_of?(Rational) + if self < 0 + return Complex(self, 0) ** other + elsif other == 0 + return Rational(1,1) + elsif self == 0 + return Rational(0,1) + elsif self == 1 + return Rational(1,1) + end + + npd = @numerator.prime_division + dpd = @denominator.prime_division + if other < 0 + other = -other + npd, dpd = dpd, npd + end + + for elm in npd + elm[1] = elm[1] * other + if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 + return Float(self) ** other + end + elm[1] = elm[1].to_i + end + + for elm in dpd + elm[1] = elm[1] * other + if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 + return Float(self) ** other + end + elm[1] = elm[1].to_i + end + + num = Integer.from_prime_division(npd) + den = Integer.from_prime_division(dpd) + + Rational(num,den) + + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end + + def power2(other) + if other.kind_of?(Rational) + if self < 0 + return Complex(self, 0) ** other + elsif other == 0 + return Rational(1,1) + elsif self == 0 + return Rational(0,1) + elsif self == 1 + return Rational(1,1) + end + + dem = nil + x = self.denominator.to_f.to_i + neard = self.denominator.to_f ** (1.0/other.denominator.to_f) + loop do + if (neard**other.denominator == self.denominator) + dem = neaed + break + end + end + nearn = self.numerator.to_f ** (1.0/other.denominator.to_f) + Rational(num,den) + + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end +end + +module Math + def sqrt(a) + if a.kind_of?(Complex) + abs = sqrt(a.real*a.real + a.image*a.image) +# if not abs.kind_of?(Rational) +# return a**Rational(1,2) +# end + x = sqrt((a.real + abs)/Rational(2)) + y = sqrt((-a.real + abs)/Rational(2)) +# if !(x.kind_of?(Rational) and y.kind_of?(Rational)) +# return a**Rational(1,2) +# end + if a.image >= 0 + Complex(x, y) + else + Complex(x, -y) + end + elsif a >= 0 + rsqrt(a) + else + Complex(0,rsqrt(-a)) + end + end + + def rsqrt(a) + if a.kind_of?(Float) + sqrt!(a) + elsif a.kind_of?(Rational) + rsqrt(a.numerator)/rsqrt(a.denominator) + else + src = a + max = 2 ** 32 + byte_a = [src & 0xffffffff] + # ruby's bug + while (src >= max) and (src >>= 32) + byte_a.unshift src & 0xffffffff + end + + answer = 0 + main = 0 + side = 0 + for elm in byte_a + main = (main << 32) + elm + side <<= 16 + if answer != 0 + if main * 4 < side * side + applo = main.div(side) + else + applo = ((sqrt!(side * side + 4 * main) - side)/2.0).to_i + 1 + end + else + applo = sqrt!(main).to_i + 1 + end + + while (x = (side + applo) * applo) > main + applo -= 1 + end + main -= x + answer = (answer << 16) + applo + side += applo * 2 + end + if main == 0 + answer + else + sqrt!(a) + end + end + end + + module_function :sqrt + module_function :rsqrt +end + +class Complex + Unify = TRUE +end + diff --git a/lib/observer.rb b/lib/observer.rb new file mode 100644 index 0000000000..9a753939a2 --- /dev/null +++ b/lib/observer.rb @@ -0,0 +1,40 @@ +# Observable Mixin +# +# Observers must respond to update + +module Observable + def add_observer(observer) + @observer_peers = [] unless @observer_peers + unless defined? observer.update + raise NameError, "observer needs to respond to `update'" + end + @observer_peers.push observer + end + def delete_observer(observer) + @observer_peers.delete observer if @observer_peers + end + def delete_observers + @observer_peers.clear if @observer_peers + end + def count_observers + if @observer_peers + @observer_peers.size + else + 0 + end + end + def changed(state=TRUE) + @observer_state = state + end + def changed? + @observer_state + end + def notify_observers(*arg) + if @observer_state + for i in @observer_peers + i.update(*arg) + end + @observer_state = FALSE + end + end +end diff --git a/lib/parsearg.rb b/lib/parsearg.rb index e7e2b7a7f3..569ed260f7 100644 --- a/lib/parsearg.rb +++ b/lib/parsearg.rb @@ -1,68 +1,83 @@ +#!/usr/local/bin/ruby # -# parseargs.rb - parse arguments +# parsearg.rb - parse arguments # $Release Version: $ # $Revision: 1.3 $ -# $Date: 1994/02/15 05:16:21 $ -# by Yasuo OHBA(STAFS Development Room) +# $Date: 1996/11/12 06:48:51 $ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- -# 引数の解析をし, $OPT_?? に値をセットします. -# 正常終了した場合は, セットされたオプションの数を返します. # -# parseArgs(argc, single_opts, *opts) -# -# ex. sample [options] filename -# options ... -# -f -x --version --geometry 100x200 -d unix:0.0 -# ↓ -# parseArgs(1, nil, "fx", "version", "geometry:", "d:") -# -# 第一引数: -# オプション以外の最低引数の数 -# 第二引数: -# オプションの必要性…必ず必要なら %TRUE そうでなければ %FALSE. -# 第三引数: -# -f や -x (= -fx) の様な一文字のオプションの指定をします. -# ここで引数がないときは nil の指定が必要です. -# 第四引数以降: -# ロングネームのオプションや, 引数の伴うオプションの指定をします. -# --version や, --geometry 300x400 や, -d host:0.0 等です. -# 引数を伴う指定は ":" を必ず付けてください. -# -# オプションの指定があった場合, 変数 $OPT_?? に non-nil もしくは, そのオ -# プションの引数がセットされます. -# -f -> $OPT_f = %TRUE -# --geometry 300x400 -> $OPT_geometry = 300x400 -# -# usage を使いたい場合は, $USAGE に usage() を指定します. -# def usage() -# … -# end -# $USAGE = 'usage' -# usage は, --help が指定された時, 間違った指定をした時に表示します. -# -# - もしくは -- は, それ以降, 全てオプションの解析をしません. +# # -$RCS_ID="$Header: /var/ohba/RCS/parseargs.rb,v 1.3 1994/02/15 05:16:21 ohba Exp ohba $" +$RCS_ID="$Header: /home/jammy/current/ruby/RCS/parsearg.rb,v 1.3 1996/11/12 06:48:51 jammy Exp $" load("getopts.rb") def printUsageAndExit() if $USAGE - apply($USAGE) + eval($USAGE) end exit() end +def setParenthesis(ex, opt, c) + if opt != "" + ex = sprintf("%s$OPT_%s%s", ex, opt, c) + else + ex = sprintf("%s%s", ex, c) + end + return ex +end + +def setOrAnd(ex, opt, c) + if opt != "" + ex = sprintf("%s$OPT_%s %s%s ", ex, opt, c, c) + else + ex = sprintf("%s %s%s ", ex, c, c) + end + return ex +end + +def setExpression(ex, opt, op) + if !op + ex = sprintf("%s$OPT_%s", ex, opt) + return ex + end + case op.chr + when "(", ")" + ex = setParenthesis(ex, opt, op.chr) + when "|", "&" + ex = setOrAnd(ex, opt, op.chr) + else + return nil + end + return ex +end + def parseArgs(argc, nopt, single_opts, *opts) - if ((noOptions = getopts(single_opts, *opts)) == nil) + if (noOptions = getopts(single_opts, *opts)) == nil printUsageAndExit() end - if (nopt && noOptions == 0) - printUsageAndExit() + if nopt + ex = nil + pos = 0 + for o in nopt.split(/[()|&]/) + pos += o.length + ex = setExpression(ex, o, nopt[pos]) + pos += 1 + end + begin + if !eval(ex) + printUsageAndExit() + end + rescue + print "Format Error!! : \"" + nopt + "\"\t[parseArgs]\n" + exit! -1 + end end - if ($ARGV.length < argc) + if ARGV.length < argc printUsageAndExit() end return noOptions diff --git a/lib/rational.rb b/lib/rational.rb new file mode 100644 index 0000000000..d4112c2956 --- /dev/null +++ b/lib/rational.rb @@ -0,0 +1,361 @@ +# +# rational.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:14 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# Usage: +# class Rational < Numeric +# (include Compareable) +# +# Rational(a, b) --> a/b +# +# Rational::+ +# Rational::- +# Rational::* +# Rational::/ +# Rational::** +# Rational::% +# Rational::divmod +# Rational::abs +# Rational::<=> +# Rational::to_i +# Rational::to_f +# Rational::to_s +# +# Integer::gcd +# Integer::lcm +# Integer::gcdlcm +# Integer::to_r +# +# Fixnum::** +# Bignum::** +# +# + +def Rational(a, b = 1) + if a.kind_of?(Rational) && b == 1 + a + else + Rational.reduce(a, b) + end +end + +class Rational < Numeric + def Rational.reduce(num, den = 1) + if den < 0 + num = -num + den = -den + end + gcd = num.gcd(den) + num = num.div(gcd) + den = den.div(gcd) + if den == 1 && defined?(Unify) + num + else + new!(num, den) + end + end + + def Rational.new!(num, den = 1) + new(num, den) + end + + def initialize(num, den) + if den < 0 + num = -num + den = -den + end + if num.kind_of?(Integer) and den.kind_of?(Integer) + @numerator = num + @denominator = den + else + @numerator = num.to_i + @denoninator = den.to_i + end + end + + def + (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + num_a = a.numerator * @denominator + Rational(num + num_a, @denominator * a.denominator) + elsif a.kind_of?(Integer) + self + Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) + a + else + x , y = a.coerce(self) + x + y + end + end + + def - (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + num_a = a.numerator * @denominator + Rational(num - num_a, @denominator*a.denominator) + elsif a.kind_of?(Integer) + self - Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) - a + else + x , y = a.coerce(self) + x - y + end + end + + def * (a) + if a.kind_of?(Rational) + num = @numerator * a.numerator + den = @denominator * a.denominator + Rational(num, den) + elsif a.kind_of?(Integer) + self * Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) * a + else + x , y = a.coerce(self) + x * y + end + end + + def / (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + den = @denominator * a.numerator + Rational(num, den) + elsif a.kind_of?(Integer) + self / Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) / a + else + x , y = a.coerce(self) + x / y + end + end + + def ** (other) + if other.kind_of?(Rational) + Float(self) ** other + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end + + def % (other) + value = (self / other).to_i + return self - other * value + end + + def divmod(other) + value = (self / other).to_i + return value, self - other * value + end + + def abs + if @numerator > 0 + Rational.new!(@numerator, @denominator) + else + Rational.new!(-@numerator, @denominator) + end + end + + def <=> (other) + if other.kind_of?(Rational) + num = @numerator * other.denominator + num_a = other.numerator * @denominator + v = num - num_a + if v > 0 + return 1 + elsif v < 0 + return -1 + else + return 0 + end + elsif other.kind_of?(Integer) + return self <=> Rational.new!(other, 1) + elsif other.kind_of?(Float) + return Float(self) <=> other + else + x , y = other.coerce(self) + return x <=> y + end + end + + def coerce(other) + if other.kind_of?(Float) + return other, self.to_f + elsif other.kind_of?(Integer) + return Rational.new!(other, 1), self + else + super + end + end + + def to_i + Integer(@numerator.div(@denominator)) + end + + def to_f + @numerator.to_f/@denominator.to_f + end + + def to_s + if @denominator == 1 + @numerator.to_s + else + @numerator.to_s+"/"+@denominator.to_s + end + end + + def to_r + self + end + + def hash + @numerator ^ @denominator + end + + attr :numerator + attr :denominator + + private :initialize +end + +class Integer + def numerator + self + end + + def denomerator + 1 + end + + def to_r + Rational(self, 1) + end + + def gcd(int) + a = self.abs + b = int.abs + + a, b = b, a if a < b + + while b != 0 + void, a = a.divmod(b) + a, b = b, a + end + return a + end + + def lcm(int) + a = self.abs + b = int.abs + gcd = a.gcd(b) + (a.div(gcd)) * b + end + + def gcdlcm(int) + a = self.abs + b = int.abs + gcd = a.gcd(b) + return gcd, (a.div(gcd)) * b + end + +end + +class Fixnum + alias div! /; + def div(other) + if other.kind_of?(Fixnum) + self.div!(other) + elsif other.kind_of?(Bignum) + x, y = other.coerce(self) + x.div!(y) + else + x, y = other.coerce(self) + x / y + end + end + +# alias divmod! divmod + + if not defined? Complex + alias power! **; + end + +# def rdiv(other) +# if other.kind_of?(Fixnum) +# Rational(self, other) +# elsif +# x, y = other.coerce(self) +# if defined?(x.div()) +# x.div(y) +# else +# x / y +# end +# end + # end + + def rdiv(other) + Rational.new!(self,1) / other + end + + def rpower (other) + if other >= 0 + self.power!(other) + else + Rational.new!(self,1)**other + end + end + + if not defined? Complex + alias ** rpower + end +end + +class Bignum + alias div! /; + alias div /; + alias divmod! divmod + + if not defined? power! + alias power! ** + end + + def rdiv(other) + Rational.new!(self,1) / other + end + + def rpower (other) + if other >= 0 + self.power!(other) + else + Rational.new!(self, 1)**other + end + end + + if not defined? Complex + alias ** rpower + end + +end + diff --git a/lib/safe.rb b/lib/safe.rb new file mode 100644 index 0000000000..7c95555495 --- /dev/null +++ b/lib/safe.rb @@ -0,0 +1,78 @@ +# this is a safe-mode for ruby, which is still incomplete. + +unless defined? SecurityError + class SecurityError<Exception + end +end + +module Restricted + + printf STDERR, "feel free for some warnings:\n" if $VERBOSE + module Bastion + include Restricted + extend Restricted + BINDING = binding + def Bastion.to_s; "main" end + end + + class R_File<File + NG_FILE_OP = [] + def R_File.open(*args) + raise SecurityError, "can't use File.open() in safe mode" #' + end + end + + IO = nil + File = R_File + FileTest = nil + Dir = nil + ObjectSpace = nil + + def eval(string) + begin + super(string, Bastion::BINDING) + rescue + $@ = caller + raise + end + end + module_function :eval + + DEFAULT_SECURITY_MANAGER = Object.new + + def Restricted.set_securuty_manager(sec_man) + if @sec_man + raise SecurityError, "cannot change security manager" + end + @sec_man = sec_man + end + + def Restricted.securuty_manager + return @sec_man if @sec_man + return DEFAULT_SECURITY_MANAGER + end + + for cmd in ["test", "require", "load", "open", "system"] + eval format("def DEFAULT_SECURITY_MANAGER.%s(*args) + raise SecurityError, \"can't use %s() in safe mode\" + end", cmd, cmd) #' + eval format("def %s(*args) + Restricted.securuty_manager.%s(*args) + end", cmd, cmd) + end + + def `(arg) #` + Restricted.securuty_manager.send(:`, arg) #`) + end + + def DEFAULT_SECURITY_MANAGER.`(arg) #` + raise SecurityError, "can't use backquote(``) in safe mode" + end +end + +if $DEBUG + p eval("File.open('/dev/null')") + p Restricted.eval("self") + p Restricted.eval("open('/dev/null')") + p Restricted.eval("File.open('/dev/null')") +end diff --git a/lib/thread.rb b/lib/thread.rb new file mode 100644 index 0000000000..c3347b60b4 --- /dev/null +++ b/lib/thread.rb @@ -0,0 +1,153 @@ +# +# thread.rb - thread support classes +# $Date: 1996/05/21 09:29:21 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> +# + +unless defined? Thread + fail "Thread not available for this ruby interpreter" +end + +unless defined? ThreadError + class ThreadError<Exception + end +end + +class Mutex + def initialize + @waiting = [] + @locked = FALSE; + end + + def locked? + @locked + end + + def try_lock + Thread.exclusive do + if not @locked + @locked=TRUE + return TRUE + end + end + FALSE + end + + def lock + while not try_lock + @waiting.push Thread.current + Thread.stop + end + end + + def unlock + @locked = FALSE + if w = @waiting.shift + w.run + end + end + + def synchronize + begin + lock + yield + ensure + unlock + end + end +end + +class SharedMutex<Mutex + def initialize + @locking = nil + @num_locks = 0; + super + end + def try_lock + if @locking == Thread.current + @num_locks += 1 + return TRUE + end + if super + @num_locks = 1 + @locking = Thread.current + TRUE + else + FALSE + end + end + def unlock + unless @locking == Thread.current + raise ThreadError, "cannot release shared mutex" + end + @num_locks -= 1 + if @num_locks == 0 + @locking = nil + super + end + end +end + +class Queue + def initialize + @que = [] + @waiting = [] + end + + def push(obj) + @que.push obj + if t = @waiting.shift + t.run + end + end + + def pop non_block=FALSE + if @que.length == 0 + raise ThreadError, "queue empty" if non_block + @waiting.push Thread.current + Thread.stop + end + @que.shift + end + + def empty? + @que.length == 0 + end + + def length + @que.length + end +end + +class Condition + def initialize + @waiting = [] + end + + def wait(mut) + Thread.exclusive do + mut.unlock + @waiting.push Thread.current + end + Thread.sleep + mut.lock + end + + def signal + th = nil + Thread.exclusive do + th = @waiting.pop + end + th.run + end + + def broadcast + w = @waiting + Thread.exclusive do + th = [] + end + for th in w + th.run + end + end +end @@ -3,477 +3,10 @@ # $Date: 1995/11/03 08:17:15 $ # by Yukihiro Matsumoto <matz@caelum.co.jp> -require "tkutil" - -trap "PIPE", proc{exit 0} -trap "EXIT", proc{Tk.tk_exit} - -module Tk - include TkUtil - extend Tk - - $0 =~ /\/(.*$)/ - - PORT = open(format("|%s -n %s", WISH_PATH, $1), "w+"); - def tk_write(*args) - printf PORT, *args; - PORT.print "\n" - PORT.flush - end - tk_write '\ -wm withdraw . -proc rb_out args { - puts [format %%s $args] - flush stdout -} -proc tkerror args { exit } -proc keepalive {} { rb_out alive; after 120000 keepalive} -after 120000 keepalive' - - READABLE = [] - READ_CMD = {} - - def file_readable(port, cmd) - READABLE.push port - READ_CMD[port] = cmd - end - - WRITABLE = [] - WRITE_CMD = {} - def file_writable - WRITABLE.push port - WRITE_CMD[port] = cmd - end - module_function :file_readable, :file_writable - - file_readable PORT, proc { - exit if not PORT.gets - Tk.dispatch($_.chop!) - } - - def tk_exit - PORT.print "exit\n" - PORT.close - end - - def error_at - n = 1 - while c = caller(n) - break if c !~ /tk\.rb:/ - n+=1 - end - c - end - - def tk_tcl2ruby(val) - case val - when /^-?\d+$/ - val.to_i - when /^\./ - $tk_window_list[val] - when /^rb_out (c\d+)/ - $tk_cmdtbl[$1] - when / / - val.split.collect{|elt| - tk_tcl2ruby(elt) - } - when /^-?\d+\.\d*$/ - val.to_f - else - val - end - end - - def tk_split_list(str) - idx = str.index('{') - return tk_tcl2ruby(str) if not idx - - list = tk_tcl2ruby(str[0,idx]) - str = str[idx+1..-1] - i = -1 - brace = 1 - str.each_byte {|c| - i += 1 - brace += 1 if c == ?{ - brace -= 1 if c == ?} - break if brace == 0 - } - if str[0, i] == ' ' - list.push ' ' - else - list.push tk_split_list(str[0, i]) - end - list += tk_split_list(str[i+1..-1]) - list - end - private :tk_tcl2ruby, :tk_split_list - - def bool(val) - case bool - when "1", 1, 'yes', 'true' - TRUE - else - FALSE - end - end - def number(val) - case val - when /^-?\d+$/ - val.to_i - when /^-?\d+\.\d*$/ - val.to_f - else - val - end - end - def string(val) - if val == "{}" - '' - elsif val[0] == ?{ - val[1..-2] - else - val - end - end - def list(val) - tk_split_list(val) - end - def window(val) - $tk_window_list[val] - end - def procedure(val) - if val =~ /^rb_out (c\d+)/ - $tk_cmdtbl[$1] - else - nil - end - end - private :bool, :number, :string, :list, :window, :procedure - - # mark for non-given arguments - None = Object.new - def None.to_s - 'None' - end - - $tk_event_queue = [] - def tk_call(*args) - args = args.collect{|s| - continue if s == None - if s == FALSE - s = "0" - elsif s == TRUE - s = "1" - elsif s.is_kind_of?(TkObject) - s = s.path - else - s = s.to_s - s.gsub!(/[{}]/, '\\\\\0') - end - "{#{s}}" - } - str = args.join(" ") - tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str - while PORT.gets - $_.chop! - if /^=(.*)@@$/ - val = $1 - break - elsif /^=/ - val = $' + "\n" - while TRUE - PORT.gets - fail 'wish closed' if not $_ - if ~/@@$/ - val += $' - return val - else - val += $_ - end - end - elsif /^!/ - $@ = error_at - msg = $' - if msg =~ /unknown option "-(.*)"/ - fail format("undefined method `%s' for %s(%s)'", $1, self, self.type) - else - fail format("%s - %s", self.type, msg) - end - end - $tk_event_queue.push $_ - end - - while ev = $tk_event_queue.shift - Tk.dispatch ev - end - fail 'wish closed' if not $_ -# tk_split_list(val) - val - end - - def hash_kv(keys) - conf = [] - if keys - for k, v in keys - conf.push("-#{k}") - v = install_cmd(v) if v.type == Proc - conf.push(v) - end - end - conf - end - private :tk_call, :error_at, :hash_kv - - $tk_cmdid = "c00000" - def install_cmd(cmd) - return '' if cmd == '' # uninstall cmd - id = $tk_cmdid - $tk_cmdid = $tk_cmdid.next - $tk_cmdtbl[id] = cmd - @cmdtbl = [] if not @cmdtbl - @cmdtbl.push id - return format('rb_out %s', id) - end - def uninstall_cmd(id) - $tk_cmdtbl[id] = nil - end - private :install_cmd, :uninstall_cmd - - $tk_window_list = {} - class Event - def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) - @serial = seq - @num = b - @focus = (f == 1) - @height = h - @keycode = k - @state = s - @time = t - @width = w - @x = x - @y = y - @char = aa - @send_event = (ee == 1) - @keysym = kk - @keysym_num = nn - @type = tt - @widget = ww - @x_root = xx - @y_root = yy - end - attr :serial - attr :num - attr :focus - attr :height - attr :keycode - attr :state - attr :time - attr :width - attr :x - attr :y - attr :char - attr :send_event - attr :keysym - attr :keysym_num - attr :type - attr :widget - attr :x_root - attr :y_root - end - - def install_bind(cmd) - id = install_cmd(proc{|args| - TkUtil.eval_cmd cmd, Event.new(*args) - }) - id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" - end - - def _bind(path, context, cmd) - begin - id = install_bind(cmd) - tk_call 'bind', path, "<#{context}>", id - rescue - $tk_cmdtbl[id] = nil - fail - end - end - private :install_bind, :_bind - - def bind_all(context, cmd=Proc.new) - _bind 'all', context, cmd - end - - $tk_cmdtbl = {} - - def after(ms, cmd=Proc.new) - myid = $tk_cmdid - tk_call 'after', ms, - install_cmd(proc{ - TkUtil.eval_cmd cmd - uninstall_cmd myid - }) - end - - def update(idle=nil) - if idle - tk_call 'update', 'idletasks' - else - tk_call 'update' - end - end - - def dispatch(line) - if line =~ /^c\d+/ - cmd = $& - fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] - args = tk_split_list($') - TkUtil.eval_cmd $tk_cmdtbl[cmd], *args - elsif line =~ /^alive$/ - # keep alive, do nothing - else - fail "malformed line <#{line}>" - end - end - - def mainloop - begin - tk_write 'after idle {wm deiconify .}' - while TRUE - rf, wf = select(READABLE, WRITABLE) - for f in rf - READ_CMD[f].call(f) if READ_CMD[f] - if f.closed? - READABLE.delete f - READ_CMD[f] = nil - end - end - for f in wf - WRITE_CMD[f].call(f) if WRITE_CMD[f] - if f.closed? - WRITABLE.delete f - WRITE_CMD[f] = nil - end - end - end - rescue - exit if $! =~ /^Interrupt/ - fail - ensure - tk_exit - end - end - - def root - $tk_root - end - - module_function :after, :update, :dispatch, :mainloop, :root - - module Scrollable - def xscrollcommand(cmd) - configure_cmd 'xscrollcommand', cmd - end - def yscrollcommand(cmd) - configure_cmd 'yscrollcommand', cmd - end - end - - module Wm - def aspect(*args) - w = window(tk_call('wm', 'grid', path, *args)) - w.split.collect{|s|s.to_i} if args.length == 0 - end - def client(name=None) - tk_call 'wm', 'client', path, name - end - def colormapwindows(*args) - list(tk_call('wm', 'colormapwindows', path, *args)) - end - def wm_command(value=None) - string(tk_call('wm', 'command', path, value)) - end - def deiconify - tk_call 'wm', 'deiconify', path - end - def focusmodel(*args) - tk_call 'wm', 'focusmodel', path, *args - end - def frame - tk_call 'wm', 'frame', path - end - def geometry(*args) - list(tk_call('wm', 'geometry', path, *args)) - end - def grid(*args) - w = tk_call('wm', 'grid', path, *args) - list(w) if args.size == 0 - end - def group(*args) - tk_call 'wm', 'path', path, *args - end - def iconbitmap(*args) - tk_call 'wm', 'bitmap', path, *args - end - def iconify - tk_call 'wm', 'iconify' - end - def iconmask(*args) - tk_call 'wm', 'iconmask', path, *args - end - def iconname(*args) - tk_call 'wm', 'iconname', path, *args - end - def iconposition(*args) - w = tk_call('wm', 'iconposition', path, *args) - list(w) if args.size == 0 - end - def iconwindow(*args) - tk_call 'wm', 'iconwindow', path, *args - end - def maxsize(*args) - w = tk_call('wm', 'maxsize', path, *args) - list(w) if not args.size == 0 - end - def minsize(*args) - w = tk_call('wm', 'minsize', path, *args) - list(w) if args.size == 0 - end - def overrideredirect(bool=None) - if bool == None - bool(tk_call('wm', 'overrideredirect', path)) - else - tk_call 'wm', 'overrideredirect', path, bool - end - end - def positionfrom(*args) - tk_call 'wm', 'positionfrom', path, *args - end - def protocol(name, func=None) - func = install_cmd(func) if not func == None - tk_call 'wm', 'command', path, name, func - end - def resizable(*args) - w = tk_call('wm', 'resizable', path, *args) - if args.length == 0 - list(w).collect{|e| bool(e)} - end - end - def sizefrom(*args) - list(tk_call('wm', 'sizefrom', path, *args)) - end - def state - tk_call 'wm', 'state', path - end - def title(*args) - tk_call 'wm', 'title', path, *args - end - def transient(*args) - tk_call 'wm', 'transient', path, *args - end - def withdraw - tk_call 'wm', 'withdraw', path - end - end +if defined? Thread and $tk_thread_safe + require "tkthcore" +else + require "tkcore" end module TkSelection @@ -550,11 +83,11 @@ module TkWinfo def winfo_depth(window) TkWinfo.depth self end - def TkWinfo.exists(window) + def TkWinfo.exist?(window) bool(tk_call('winfo', 'exists', window.path)) end - def winfo_exists(window) - TkWinfo.exists self + def winfo_exist?(window) + TkWinfo.exist? self end def TkWinfo.fpixels(window, number) number(tk_call('winfo', 'fpixels', window.path, number)) @@ -580,11 +113,11 @@ module TkWinfo def winfo_id(window) TkWinfo.id self end - def TkWinfo.ismapped(window) + def TkWinfo.mapped?(window) bool(tk_call('winfo', 'ismapped', window.path)) end - def winfo_ismapped(window) - TkWinfo.ismapped self + def winfo_mapped?(window) + TkWinfo.mapped? self end def TkWinfo.parent(window) window(tk_call('winfo', 'parent', window.path)) @@ -742,7 +275,7 @@ module TkPack include Tk extend Tk def configure(win, *args) - if args[-1].is_kind_of(Hash) + if args[-1].kind_of?(Hash) keys = args.pop end wins = [win.epath] @@ -780,7 +313,7 @@ module TkOption module_function :add, :clear, :get, :readfile end -class TkObject:TkKernel +class TkObject<TkKernel include Tk def path @@ -822,16 +355,16 @@ class TkObject:TkKernel configure slot, install_cmd(value) end - def bind(context, cmd=Proc.new) - _bind path, context, cmd + def bind(context, cmd=Proc.new, args=nil) + _bind path, context, cmd, args end end -class TkWindow:TkObject +class TkWindow<TkObject $tk_window_id = "w00000" def initialize(parent=nil, keys=nil) id = $tk_window_id - $tk_window_id = $tk_window_id.next + $tk_window_id = $tk_window_id.succ if !parent or parent == Tk.root @path = format(".%s", id); else @@ -880,7 +413,7 @@ class TkWindow:TkObject return val end else - fail 'wrong # of args' + fail ArgumentError, 'wrong # of args' end end @@ -913,7 +446,7 @@ class TkWindow:TkObject end end -class TkRoot:TkWindow +class TkRoot<TkWindow include Wm def TkRoot.new return $tk_root if $tk_root @@ -926,7 +459,7 @@ class TkRoot:TkWindow $tk_window_list['.'] = $tk_root end -class TkToplevel:TkWindow +class TkToplevel<TkWindow include Wm def initialize(parent=nil, screen=nil, classname=nil) @screen = screen if screen @@ -942,20 +475,21 @@ class TkToplevel:TkWindow end end -class TkFrame:TkWindow +class TkFrame<TkWindow def create_self tk_call 'frame', @path end end -class TkLabel:TkWindow +class TkLabel<TkWindow def create_self tk_call 'label', @path end def textvariable(v) - vn = @path + v.id2name + v = v.id2name unless v.kind_of "String" + vn = @path + v vset = format("global {%s}; set {%s}", vn, vn) - tk_call vset, eval(v.id2name).inspect + tk_call vset, eval(v).inspect trace_var v, proc{|val| tk_call vset, val.inspect } @@ -963,7 +497,7 @@ class TkLabel:TkWindow end end -class TkButton:TkLabel +class TkButton<TkLabel def create_self tk_call 'button', @path end @@ -975,7 +509,7 @@ class TkButton:TkLabel end end -class TkRadioButton:TkButton +class TkRadioButton<TkButton def create_self tk_call 'radiobutton', @path end @@ -986,8 +520,13 @@ class TkRadioButton:TkButton tk_send 'select' end def variable(v) - vn = v.id2name; vn =~ /^./ - vn = 'btns_selected_' + $' + v = v.id2name unless v.kind_of "String" + if v =~ /^\$/ + v = $' + else + fail ArgumentError, "variable must be global(%s)", v + end + vn = 'btns_selected_' + v trace_var v, proc{|val| tk_call 'set', vn, val } @@ -1004,7 +543,7 @@ class TkRadioButton:TkButton end end -class TkCheckButton:TkRadioButton +class TkCheckButton<TkRadioButton def create_self tk_call 'checkbutton', @path end @@ -1013,13 +552,13 @@ class TkCheckButton:TkRadioButton end end -class TkMessage:TkLabel +class TkMessage<TkLabel def create_self tk_call 'message', @path end end -class TkScale:TkWindow +class TkScale<TkWindow def create_self tk_call 'scale', path end @@ -1041,11 +580,23 @@ class TkScale:TkWindow end end -class TkScrollbar:TkWindow +class TkScrollbar<TkWindow def create_self tk_call 'scrollbar', path end + def delta(deltax=None, deltay=None) + number(tk_send('delta', deltax, deltay)) + end + + def fraction(x=None, y=None) + number(tk_send('fraction', x, y)) + end + + def identify(x=None, y=None) + tk_send('fraction', x, y) + end + def get ary1 = tk_send('get', path).split ary2 = [] @@ -1061,7 +612,7 @@ class TkScrollbar:TkWindow end # abstract class for Text and Listbox -class TkTextWin:TkWindow +class TkTextWin<TkWindow def bbox(index) tk_send 'bbox', index end @@ -1091,7 +642,7 @@ class TkTextWin:TkWindow end end -class TkListbox:TkTextWin +class TkListbox<TkTextWin def create_self tk_call 'listbox', path end @@ -1119,7 +670,7 @@ class TkListbox:TkTextWin end end -class TkMenu:TkWindow +class TkMenu<TkWindow def create_self tk_call 'menu', path end @@ -1158,7 +709,7 @@ class TkMenu:TkWindow end end -class TkMenubutton:TkLabel +class TkMenubutton<TkLabel def create_self tk_call 'menubutton', path end @@ -1181,7 +732,7 @@ module TkComposite def delegate(option, *wins) @delegates = {} if not @delegates @delegates['DEFAULT'] = @frame - if option.is_kind_of? String + if option.kind_of? String @delegates[option] = wins else for i in option diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb index 33b28e3eff..b0ae8b1daa 100644 --- a/lib/tkcanvas.rb +++ b/lib/tkcanvas.rb @@ -5,12 +5,12 @@ require "tk" -class TkCanvas:TkWindow +class TkCanvas<TkWindow def create_self tk_call 'canvas', path end def tagid(tag) - if tag.is_kind_of?(TkcItem) + if tag.kind_of?(TkcItem) tag.id else tag @@ -89,6 +89,9 @@ class TkCanvas:TkWindow def move(tag, x, y) tk_send 'move', tagid(tag), x, y end + def itemtype(tag) + tk_send 'type', tagid(tag) + end def postscript(keys=None) tk_call "pack", *hash_kv(keys) end @@ -115,9 +118,9 @@ class TkCanvas:TkWindow end end -class TkcItem:TkObject +class TkcItem<TkObject def initialize(parent, *args) - if not parent.is_kind_of?(TkCanvas) + if not parent.kind_of?(TkCanvas) fail format("%s need to be TkCanvas", parent.inspect) end @c = parent @@ -137,7 +140,7 @@ class TkcItem:TkObject end def configure(slot, value) - tk_call path, 'itemconfigure', id, "-#{slot}", value + tk_call path, 'itemconfigure', @id, "-#{slot}", value end def addtag(tag) @@ -185,59 +188,59 @@ class TkcItem:TkObject def scale(xorigin, yorigin, xscale, yscale) @c.scale @id, xorigin, yorigin, xscale, yscale end - def type - @c.type @id + def itemtype + @c.itemtype @id end def destroy tk_call path, 'delete', @id end end -class TkcArc:TkcItem +class TkcArc<TkcItem def create_self(*args) tk_call(@path, 'create', 'arc', *args) end end -class TkcBitmap:TkcItem +class TkcBitmap<TkcItem def create_self(*args) tk_call(@path, 'create', 'bitmap', *args) end end -class TkcImage:TkcItem +class TkcImage<TkcItem def create_self(*args) tk_call(@path, 'create', 'image', *args) end end -class TkcLine:TkcItem +class TkcLine<TkcItem def create_self(*args) tk_call(@path, 'create', 'line', *args) end end -class TkcOval:TkcItem +class TkcOval<TkcItem def create_self(*args) tk_call(@path, 'create', 'oval', *args) end end -class TkcPolygon:TkcItem +class TkcPolygon<TkcItem def create_self(*args) tk_call(@path, 'create', 'polygon', *args) end end -class TkcText:TkcItem +class TkcText<TkcItem def create_self(*args) tk_call(@path, 'create', 'text', *args) end end -class TkcWindow:TkcItem +class TkcWindow<TkcItem def create_self(*args) tk_call(@path, 'create', 'window', *args) end end -class TkcGroup:TkcItem +class TkcGroup<TkcItem $tk_group_id = 'tkg00000' def create_self(*args) @id = $tk_group_id - $tk_group_id = $tk_group_id.next + $tk_group_id = $tk_group_id.succ end def add(*tags) @@ -262,20 +265,20 @@ class TkcGroup:TkcItem end -class TkImage:TkObject +class TkImage<TkObject include Tk $tk_image_id = 'i00000' def initialize(keys=nil) @path = $tk_image_id - $tk_image_id = $tk_image_id.next + $tk_image_id = $tk_image_id.succ tk_call 'image', @type, @path, *hash_kv(keys) end def height number(tk_call('image', 'height', @path)) end - def type + def itemtype tk_call('image', 'type', @path) end def width @@ -290,14 +293,14 @@ class TkImage:TkObject end end -class TkBitmapImage:TkImage +class TkBitmapImage<TkImage def initialize(*args) @type = 'bitmap' super end end -class TkPhotoImage:TkImage +class TkPhotoImage<TkImage def initialize(*args) @type = 'bitmap' super diff --git a/lib/tkcore.rb b/lib/tkcore.rb new file mode 100644 index 0000000000..df4af669ba --- /dev/null +++ b/lib/tkcore.rb @@ -0,0 +1,521 @@ +# +# tkcore.rb - Tk interface modue without thread +# $Date: 1996/11/09 22:51:15 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> + +require "tkutil" +if defined? Thread + require "thread" +end + +module Tk + include TkUtil + extend Tk + + wish_path = nil + ENV['PATH'].split(":").each {|path| + for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish'] + if File.exist? path+'/'+wish + wish_path = path+'/'+wish + break + end + break if wish_path + end + } + fail 'can\'t find wish' if not wish_path + + def Tk.tk_exit + if not PORT.closed? + PORT.print "exit\n" + PORT.close + end + end + + PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+"); + trap "EXIT", proc{Tk.tk_exit} + trap "PIPE", "" + + def tk_write(*args) + printf PORT, *args; + PORT.print "\n" + PORT.flush + end + tk_write '\ +wm withdraw . +proc rb_out args { + puts [format %%s $args] + flush stdout +} +proc rb_ans args { + if [catch "$args" var] {puts "!$var"} {puts "=$var@@"} + flush stdout +} +proc tkerror args { exit } +proc keepalive {} { rb_out alive; after 120000 keepalive} +after 120000 keepalive' + + READABLE = [] + READ_CMD = {} + + def file_readable(port, cmd) + if cmd == nil + READABLE.delete port + else + READABLE.push port + end + READ_CMD[port] = cmd + end + + WRITABLE = [] + WRITE_CMD = {} + def file_writable(port, cmd) + if cmd == nil + WRITABLE.delete port + else + WRITABLE.push port + end + WRITE_CMD[port] = cmd + end + module_function :file_readable, :file_writable + + file_readable PORT, proc { + line = PORT.gets + exit if not line + Tk.dispatch(line.chop!) + } + + def error_at + n = 1 + while c = caller(n) + break if c !~ /tk\.rb:/ + n+=1 + end + c + end + + def tk_tcl2ruby(val) + case val + when /^-?\d+$/ + val.to_i + when /^\./ + $tk_window_list[val] + when /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + when / / + val.split.collect{|elt| + tk_tcl2ruby(elt) + } + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + + def tk_split_list(str) + idx = str.index('{') + return tk_tcl2ruby(str) if not idx + + list = tk_tcl2ruby(str[0,idx]) + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if str[0, i] == ' ' + list.push ' ' + else + list.push tk_split_list(str[0, i]) + end + list += tk_split_list(str[i+1..-1]) + list + end + private :tk_tcl2ruby, :tk_split_list + + def bool(val) + case bool + when "1", 1, 'yes', 'true' + TRUE + else + FALSE + end + end + def number(val) + case val + when /^-?\d+$/ + val.to_i + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + def string(val) + if val == "{}" + '' + elsif val[0] == ?{ + val[1..-2] + else + val + end + end + def list(val) + tk_split_list(val) + end + def window(val) + $tk_window_list[val] + end + def procedure(val) + if val =~ /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + else + nil + end + end + private :bool, :number, :string, :list, :window, :procedure + + # mark for non-given arguments + None = Object.new + def None.to_s + 'None' + end + + $tk_event_queue = [] + def tk_call(*args) + args = args.collect{|s| + next if s == None + if s.kind_of?(Hash) + s = hash_kv(s).join(" ") + else + if not s + s = "0" + elsif s == TRUE + s = "1" + elsif s.kind_of?(TkObject) + s = s.path + else + s = s.to_s + s.gsub!(/[{}]/, '\\\\\0') + end + "{#{s}}" + end + } + str = args.join(" ") + print str, "\n" if $DEBUG + tk_write 'rb_ans %s', str + while PORT.gets + print $_ if $DEBUG + $_.chop! + if /^=(.*)@@$/ + val = $1 + break + elsif /^=/ + val = $' + "\n" + while TRUE + PORT.readline + if ~/@@$/ + val += $' + return val + else + val += $_ + end + end + elsif /^!/ + $@ = error_at + msg = $' + if msg =~ /unknown option "-(.*)"/ + fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`' + else + fail format("%s - %s", self.type, msg) + end + end + $tk_event_queue.push $_ + end + + while ev = $tk_event_queue.shift + Tk.dispatch ev + end + fail 'wish closed' if PORT.closed? +# tk_split_list(val) + val + end + + def hash_kv(keys) + conf = [] + if keys + for k, v in keys + conf.push("-#{k}") + v = install_cmd(v) if v.type == Proc + conf.push(v) + end + end + conf + end + private :tk_call, :error_at, :hash_kv + + $tk_cmdid = 0 + def install_cmd(cmd) + return '' if cmd == '' # uninstall cmd + id = format("c%.4d", $tk_cmdid) + $tk_cmdid += 1 + $tk_cmdtbl[id] = cmd + @cmdtbl = [] if not @cmdtbl + @cmdtbl.push id + return format('rb_out %s', id) + end + def uninstall_cmd(id) + $tk_cmdtbl[id] = nil + end + private :install_cmd, :uninstall_cmd + + $tk_window_list = {} + class Event + def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) + @serial = seq + @num = b + @focus = (f == 1) + @height = h + @keycode = k + @state = s + @time = t + @width = w + @x = x + @y = y + @char = aa + @send_event = (ee == 1) + @keysym = kk + @keysym_num = nn + @type = tt + @widget = ww + @x_root = xx + @y_root = yy + end + attr :serial + attr :num + attr :focus + attr :height + attr :keycode + attr :state + attr :time + attr :width + attr :x + attr :y + attr :char + attr :send_event + attr :keysym + attr :keysym_num + attr :type + attr :widget + attr :x_root + attr :y_root + end + + def install_bind(cmd, args=nil) + if args + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, *arg + }) + id + " " + args + else + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, Event.new(*arg) + }) + id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" + end + end + + def _bind(path, context, cmd, args=nil) + begin + id = install_bind(cmd, args) + tk_call 'bind', path, "<#{context}>", id + rescue + $tk_cmdtbl[id] = nil + fail + end + end + private :install_bind, :_bind + + def bind_all(context, cmd=Proc.new, args=nil) + _bind 'all', context, cmd, args + end + + def pack(*args) + TkPack.configure *args + end + + $tk_cmdtbl = {} + + def after(ms, cmd=Proc.new) + myid = format("c%.4d", $tk_cmdid) + tk_call 'after', ms, + install_cmd(proc{ + TkUtil.eval_cmd cmd + uninstall_cmd myid + }) + end + + def update(idle=nil) + if idle + tk_call 'update', 'idletasks' + else + tk_call 'update' + end + end + + def dispatch(line) + if line =~ /^c\d+/ + cmd = $& + fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] + args = tk_split_list($') + TkUtil.eval_cmd $tk_cmdtbl[cmd], *args + elsif line =~ /^alive$/ + # keep alive, do nothing + else + fail "malformed line <#{line}>" + end + end + + def mainloop + begin + tk_write 'after idle {wm deiconify .}' + while TRUE + rf, wf = select(READABLE, WRITABLE) + for f in rf + READ_CMD[f].call(f) if READ_CMD[f] + if f.closed? + READABLE.delete f + READ_CMD[f] = nil + end + end + for f in wf + WRITE_CMD[f].call(f) if WRITE_CMD[f] + if f.closed? + WRITABLE.delete f + WRITE_CMD[f] = nil + end + end + end + ensure + Tk.tk_exit + end + end + + def root + $tk_root + end + + def bell + tk_call 'bell' + end + module_function :after, :update, :dispatch, :mainloop, :root, :bell + + module Scrollable + def xscrollcommand(cmd) + configure_cmd 'xscrollcommand', cmd + end + def yscrollcommand(cmd) + configure_cmd 'yscrollcommand', cmd + end + end + + module Wm + def aspect(*args) + w = window(tk_call('wm', 'grid', path, *args)) + w.split.collect{|s|s.to_i} if args.length == 0 + end + def client(name=None) + tk_call 'wm', 'client', path, name + end + def colormapwindows(*args) + list(tk_call('wm', 'colormapwindows', path, *args)) + end + def wm_command(value=None) + string(tk_call('wm', 'command', path, value)) + end + def deiconify + tk_call 'wm', 'deiconify', path + end + def focusmodel(*args) + tk_call 'wm', 'focusmodel', path, *args + end + def frame + tk_call 'wm', 'frame', path + end + def geometry(*args) + list(tk_call('wm', 'geometry', path, *args)) + end + def grid(*args) + w = tk_call('wm', 'grid', path, *args) + list(w) if args.size == 0 + end + def group(*args) + tk_call 'wm', 'path', path, *args + end + def iconbitmap(*args) + tk_call 'wm', 'bitmap', path, *args + end + def iconify + tk_call 'wm', 'iconify' + end + def iconmask(*args) + tk_call 'wm', 'iconmask', path, *args + end + def iconname(*args) + tk_call 'wm', 'iconname', path, *args + end + def iconposition(*args) + w = tk_call('wm', 'iconposition', path, *args) + list(w) if args.size == 0 + end + def iconwindow(*args) + tk_call 'wm', 'iconwindow', path, *args + end + def maxsize(*args) + w = tk_call('wm', 'maxsize', path, *args) + list(w) if not args.size == 0 + end + def minsize(*args) + w = tk_call('wm', 'minsize', path, *args) + list(w) if args.size == 0 + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call('wm', 'overrideredirect', path)) + else + tk_call 'wm', 'overrideredirect', path, bool + end + end + def positionfrom(*args) + tk_call 'wm', 'positionfrom', path, *args + end + def protocol(name, func=None) + func = install_cmd(func) if not func == None + tk_call 'wm', 'command', path, name, func + end + def resizable(*args) + w = tk_call('wm', 'resizable', path, *args) + if args.length == 0 + list(w).collect{|e| bool(e)} + end + end + def sizefrom(*args) + list(tk_call('wm', 'sizefrom', path, *args)) + end + def state + tk_call 'wm', 'state', path + end + def title(*args) + tk_call 'wm', 'title', path, *args + end + def transient(*args) + tk_call 'wm', 'transient', path, *args + end + def withdraw + tk_call 'wm', 'withdraw', path + end + end +end diff --git a/lib/tkentry.rb b/lib/tkentry.rb index dbd848d0ca..9a03c34058 100644 --- a/lib/tkentry.rb +++ b/lib/tkentry.rb @@ -5,7 +5,7 @@ require 'tk.rb' -class TkEntry:TkLabel +class TkEntry<TkLabel def create_self tk_call 'entry', @path end diff --git a/lib/tkscrollbox.rb b/lib/tkscrollbox.rb new file mode 100644 index 0000000000..b8dbe9b236 --- /dev/null +++ b/lib/tkscrollbox.rb @@ -0,0 +1,27 @@ +# +# tkscrollbox.rb - Tk Listbox with Scrollbar +# as an example of Composite Widget +# $Date: 1995/12/12 18:21:01 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> + +require 'tk.rb' + +class TkScrollbox<TkListbox + include TkComposite + def initialize_composite + list = TkListbox.new(@frame) + scroll = TkScrollbar.new(@frame) + @path = list.path + + list.configure 'yscroll', scroll.path+" set" + list.pack 'side'=>'left','fill'=>'both','expand'=>'yes' + scroll.configure 'command', list.path+" yview" + scroll.pack 'side'=>'right','fill'=>'y' + + delegate('DEFALUT', list) + delegate('foreground', list, scroll) + delegate('background', list, scroll) + delegate('borderwidth', @frame) + delegate('relief', @frame) + end +end diff --git a/lib/tktext.rb b/lib/tktext.rb index e7a2be950f..55e396c497 100644 --- a/lib/tktext.rb +++ b/lib/tktext.rb @@ -5,7 +5,7 @@ require 'tk.rb' -class TkText:TkTextWin +class TkText<TkTextWin include Scrollable def create_self tk_call 'text', @path @@ -77,16 +77,16 @@ class TkText:TkTextWin end end -class TkTextTag:TkObject +class TkTextTag<TkObject $tk_text_tag = 'tag0000' def initialize(parent) - if not parent.is_kind_of?(TkText) + if not parent.kind_of?(TkText) fail format("%s need to be TkText", parent.inspect) end @t = parent @path = parent.path @id = $tk_text_tag - $tk_text_tag = $tk_text_tag.next + $tk_text_tag = $tk_text_tag.succ @t._addtag id, self end def id @@ -116,16 +116,16 @@ class TkTextTag:TkObject end end -class TkTextMark:TkObject +class TkTextMark<TkObject $tk_text_mark = 'mark0000' def initialize(parent, index) - if not parent.is_kind_of?(TkText) + if not parent.kind_of?(TkText) fail format("%s need to be TkText", parent.inspect) end @t = parent @path = parent.path @id = $tk_text_mark - $tk_text_mark = $tk_text_mark.next + $tk_text_mark = $tk_text_mark.succ tk_call @t, 'set', @id, index @t._addtag id, self end @@ -143,9 +143,9 @@ class TkTextMark:TkObject alias destroy unset end -class TkTextWindow:TkObject +class TkTextWindow<TkObject def initialize(parent, index, *args) - if not parent.is_kind_of?(TkText) + if not parent.kind_of?(TkText) fail format("%s need to be TkText", parent.inspect) end @t = parent diff --git a/lib/tkthcore.rb b/lib/tkthcore.rb new file mode 100644 index 0000000000..adbad775d0 --- /dev/null +++ b/lib/tkthcore.rb @@ -0,0 +1,546 @@ +# +# tkthcore.rb - Tk interface modue using thread +# $Date: 1996/11/09 22:49:15 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> + +require "tkutil" +require "thread" + +module Tk + include TkUtil + extend Tk + + def Tk.tk_exit + if not PORT.closed? + tk_write "exit" + PORT.close + end + end + + trap "EXIT", proc{Tk.tk_exit} + trap "PIPE", '' + + wish_path = nil + ENV['PATH'].split(":").each {|path| + for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish'] + if File.exist? path+'/'+wish + wish_path = path+'/'+wish + break + end + break if wish_path + end + } + fail 'can\'t find wish' if not wish_path + + # mark for non-given arguments + None = Object.new + def None.to_s + 'None' + end + + Qin = Queue.new + Qout = Queue.new + Qwish = Queue.new + Qcmd = Queue.new + PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+"); + + $tk_not_init = TRUE + + def Tk.init + $tk_not_init = FALSE + Thread.start do + loop do + while line = PORT.gets + line.chop! + if line =~ /^[=!]/ + Qwish.push line + else + Qcmd.push line + end + end + exit + end + end + + Thread.start do + ary = [PORT] + loop do + str = Qin.pop + print str, "\n" if $DEBUG + tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str + Qout.push(tk_recv) + end + end + end + + $tk_event_queue = [] + def tk_recv() + val = nil + $_ = Qwish.pop + loop do + if /^=(.*)@@$/ + val = $1 + break + elsif /^=/ + val = $' + "\n" + while TRUE + PORT.readline + if ~/@@$/ + val += $' + return val + else + v>al += $_ + end + end + elsif /^!/ + $@ = error_at + msg = $' + if msg =~ /unknown option "-(.*)"/ + fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`' + else + fail format("%s - %s", self.type, msg) + end + end + Qcmd.push line + end + + fail 'wish closed' if PORT.closed? +# tk_split_list(val) + val + end + + def tk_call(*args) + Tk.init if $tk_not_init + args = args.collect{|s| + next if s == None + if s.kind_of?(Hash) + s = hash_kv(s).join(" ") + else + if not s + s = "0" + elsif s == TRUE + s = "1" + elsif s.kind_of?(TkObject) + s = s.path + else + s = s.to_s + s.gsub!(/[{}]/, '\\\\\0') + end + "{#{s}}" + end + } + str = args.join(" ") + Qin.push str + return Qout.pop + end + + def tk_write(*args) + PORT.printf *args; PORT.print "\n" + PORT.flush + end + module_function :tk_write, :tk_recv + tk_write '\ +wm withdraw . +proc rb_out args { + puts [format %%s $args] + flush stdout +} +proc tkerror args { exit } +proc keepalive {} { rb_out alive; after 120000 keepalive} +after 120000 keepalive' + + READ_TH = {} + def file_readable(port, cmd) + if cmd == nil + if READ_TH[port].has_key? + READ_TH[port].exit + READ_TH[port] = nil + end + else + READ_TH[port] = Thread.start{ + loop do + TkUtil.eval_cmd cmd + end + } + end + end + + WRITE_TH = {} + def file_writable(port, cmd) + if cmd == nil + if WRITE_TH[port].has_key? + WRITE_TH[port].exit + end + else + WRITE_TH[port] = Thread.start{ + loop do + TkUtil.eval_cmd cmd + end + } + end + end + module_function :file_readable, :file_writable + + def tk_tcl2ruby(val) + case val + when /^-?\d+$/ + val.to_i + when /^\./ + $tk_window_list[val] + when /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + when / / + val.split.collect{|elt| + tk_tcl2ruby(elt) + } + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + + def tk_split_list(str) + idx = str.index('{') + return tk_tcl2ruby(str) if not idx + + list = tk_tcl2ruby(str[0,idx]) + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if str[0, i] == ' ' + list.push ' ' + else + list.push tk_split_list(str[0, i]) + end + list += tk_split_list(str[i+1..-1]) + list + end + private :tk_tcl2ruby, :tk_split_list + + def dispatch(line) + if line =~ /^c\d+/ + cmd = $& + fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] + args = tk_split_list($') + TkUtil.eval_cmd $tk_cmdtbl[cmd], *args + elsif line =~ /^alive$/ + # keep alive, do nothing + else + fail "malformed line <#{line}>" + end + end + module_function :dispatch + + def error_at + n = 1 + while c = caller(n) + break if c !~ /tk\.rb:/ + n+=1 + end + c + end + + def bool(val) + case bool + when "1", 1, 'yes', 'true' + TRUE + else + FALSE + end + end + def number(val) + case val + when /^-?\d+$/ + val.to_i + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + def string(val) + if val == "{}" + '' + elsif val[0] == ?{ + val[1..-2] + else + val + end + end + def list(val) + tk_split_list(val) + end + def window(val) + $tk_window_list[val] + end + def procedure(val) + if val =~ /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + else + nil + end + end + private :bool, :number, :string, :list, :window, :procedure + + def hash_kv(keys) + conf = [] + if keys + for k, v in keys + conf.push("-#{k}") + v = install_cmd(v) if v.type == Proc + conf.push(v) + end + end + conf + end + private :tk_call, :error_at, :hash_kv + + $tk_cmdid = 0 + def install_cmd(cmd) + return '' if cmd == '' # uninstall cmd + id = format("c%.4d", $tk_cmdid) + $tk_cmdid += 1 + $tk_cmdtbl[id] = cmd + @cmdtbl = [] if not @cmdtbl + @cmdtbl.push id + return format('rb_out %s', id) + end + def uninstall_cmd(id) + $tk_cmdtbl[id] = nil + end + private :install_cmd, :uninstall_cmd + + $tk_window_list = {} + class Event + def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) + @serial = seq + @num = b + @focus = (f == 1) + @height = h + @keycode = k + @state = s + @time = t + @width = w + @x = x + @y = y + @char = aa + @send_event = (ee == 1) + @keysym = kk + @keysym_num = nn + @type = tt + @widget = ww + @x_root = xx + @y_root = yy + end + attr :serial + attr :num + attr :focus + attr :height + attr :keycode + attr :state + attr :time + attr :width + attr :x + attr :y + attr :char + attr :send_event + attr :keysym + attr :keysym_num + attr :type + attr :widget + attr :x_root + attr :y_root + end + + def install_bind(cmd, args=nil) + if args + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, *arg + }) + id + " " + args + else + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, Event.new(*arg) + }) + id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" + end + end + + def _bind(path, context, cmd, args=nil) + begin + id = install_bind(cmd, args) + tk_call 'bind', path, "<#{context}>", id + rescue + $tk_cmdtbl[id] = nil + fail + end + end + private :install_bind, :_bind + + def bind_all(context, cmd=Proc.new, args=nil) + _bind 'all', context, cmd, args + end + + def pack(*args) + TkPack.configure *args + end + + $tk_cmdtbl = {} + + Qafter = Queue.new + def after(ms, cmd=Proc.new) + unless $tk_after_thread + $tk_after_thread = Thread.start{ + loop do + cmd = Qafter.pop + TkUtil.eval_cmd cmd + end + } + end + Thread.start do + sleep Float(ms)/1000 + Qafter.push cmd + end + end + + def update(idle=nil) + if idle + tk_call 'update', 'idletasks' + else + tk_call 'update' + end + end + + def root + $tk_root + end + + def bell + tk_call 'bell' + end + + def mainloop + begin + tk_call 'after', 'idle', 'wm deiconify .' + loop do + dispatch Qcmd.pop + end + ensure + Tk.tk_exit + end + end + module_function :after, :update, :dispatch, :mainloop, :root, :bell + + module Scrollable + def xscrollcommand(cmd) + configure_cmd 'xscrollcommand', cmd + end + def yscrollcommand(cmd) + configure_cmd 'yscrollcommand', cmd + end + end + + module Wm + def aspect(*args) + w = window(tk_call('wm', 'grid', path, *args)) + w.split.collect{|s|s.to_i} if args.length == 0 + end + def client(name=None) + tk_call 'wm', 'client', path, name + end + def colormapwindows(*args) + list(tk_call('wm', 'colormapwindows', path, *args)) + end + def wm_command(value=None) + string(tk_call('wm', 'command', path, value)) + end + def deiconify + tk_call 'wm', 'deiconify', path + end + def focusmodel(*args) + tk_call 'wm', 'focusmodel', path, *args + end + def frame + tk_call 'wm', 'frame', path + end + def geometry(*args) + list(tk_call('wm', 'geometry', path, *args)) + end + def grid(*args) + w = tk_call('wm', 'grid', path, *args) + list(w) if args.size == 0 + end + def group(*args) + tk_call 'wm', 'path', path, *args + end + def iconbitmap(*args) + tk_call 'wm', 'bitmap', path, *args + end + def iconify + tk_call 'wm', 'iconify' + end + def iconmask(*args) + tk_call 'wm', 'iconmask', path, *args + end + def iconname(*args) + tk_call 'wm', 'iconname', path, *args + end + def iconposition(*args) + w = tk_call('wm', 'iconposition', path, *args) + list(w) if args.size == 0 + end + def iconwindow(*args) + tk_call 'wm', 'iconwindow', path, *args + end + def maxsize(*args) + w = tk_call('wm', 'maxsize', path, *args) + list(w) if not args.size == 0 + end + def minsize(*args) + w = tk_call('wm', 'minsize', path, *args) + list(w) if args.size == 0 + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call('wm', 'overrideredirect', path)) + else + tk_call 'wm', 'overrideredirect', path, bool + end + end + def positionfrom(*args) + tk_call 'wm', 'positionfrom', path, *args + end + def protocol(name, func=None) + func = install_cmd(func) if not func == None + tk_call 'wm', 'command', path, name, func + end + def resizable(*args) + w = tk_call('wm', 'resizable', path, *args) + if args.length == 0 + list(w).collect{|e| bool(e)} + end + end + def sizefrom(*args) + list(tk_call('wm', 'sizefrom', path, *args)) + end + def state + tk_call 'wm', 'state', path + end + def title(*args) + tk_call 'wm', 'title', path, *args + end + def transient(*args) + tk_call 'wm', 'transient', path, *args + end + def withdraw + tk_call 'wm', 'withdraw', path + end + end +end |