diff options
Diffstat (limited to 'sample')
192 files changed, 6889 insertions, 2816 deletions
diff --git a/sample/README b/sample/README new file mode 100644 index 0000000000..796aba1dc3 --- /dev/null +++ b/sample/README @@ -0,0 +1,45 @@ +README this file +biorhythm.rb biorhythm calculator +cal.rb cal(1) clone +cbreak.rb no echo done by ioctl +clnt.rb socket client +coverage.rb simple test code coverage tool +dir.rb directory access +dualstack-fetch.rb IPv6 demo +dualstack-httpd.rb IPv6 demo +eval.rb simple evaluator +export.rb method access example +exyacc.rb extrace BNF from yacc file +fact.rb factorial calculator +fib.awk Fibonacci number (AWK) +fib.pl Fibonacci number (Perl) +fib.py Fibonacci number (Python) +fib.rb Fibonacci number (Ruby) +fib.scm Fibonacci number (Scheme) +freq.rb count word occurrence +from.rb scan mail spool +fullpath.rb convert ls -lR to fullpath format +less.rb front end for less +list.rb stupid object sample +list2.rb stupid object sample +list3.rb stupid object sample +mine.rb simple mine sweeper +mkproto.rb extract prototype from C +mpart.rb split file int multi part +observ.rb observer design pattern sample +occur.pl count word occurrence (Perl) +occur.rb count word occurrence (Ruby) +occur2.rb count word occurrence - another style +philos.rb famous dining philosophers +pi.rb calculate PI +rcs.awk random character stereogram (AWK) +rcs.rb random character stereogram (Ruby) +rcs.dat data for random character stereogram +sieve.rb sieve of Eratosthenes +svr.rb socket server +test.rb test suite used by `make test' +time.rb /usr/bin/time clone +timeout.rb timeout test +trojan.rb simple tool to find file that may be trojan horse. +tsvr.rb socket server using thread +uumerge.rb merge files and uudecode them diff --git a/sample/benchmark.rb b/sample/benchmark.rb new file mode 100644 index 0000000000..de5d66f505 --- /dev/null +++ b/sample/benchmark.rb @@ -0,0 +1,19 @@ +require 'benchmark' + +include Benchmark + +n = ARGV[0].to_i.nonzero? || 50000 +puts %Q([#{n} times iterations of `a = "1"']) +benchmark(CAPTION, 7, FORMAT) do |x| + x.report("for:") {for _ in 1..n; _ = "1"; end} # Benchmark.measure + x.report("times:") {n.times do ; _ = "1"; end} + x.report("upto:") {1.upto(n) do ; _ = "1"; end} +end + +benchmark do + [ + measure{for _ in 1..n; _ = "1"; end}, # Benchmark.measure + measure{n.times do ; _ = "1"; end}, + measure{1.upto(n) do ; _ = "1"; end} + ] +end diff --git a/sample/biorhythm.rb b/sample/biorhythm.rb index b97ee85e16..bd7c39f5aa 100644 --- a/sample/biorhythm.rb +++ b/sample/biorhythm.rb @@ -1,127 +1,113 @@ #!/usr/local/bin/ruby # -# biorhythm.rb - +# biorhythm.rb - # $Release Version: $ -# $Revision: 1.3 $ -# $Date: 1997/02/14 11:07:08 $ +# $Revision$ # by Yasuo OHBA(STAFS Development Room) # # -- # -# # +# + +# probably based on: +# +# Newsgroups: comp.sources.misc,de.comp.sources.os9 +# From: fkk@stasys.sta.sub.org (Frank Kaefer) +# Subject: v41i126: br - Biorhythm v3.0, Part01/01 +# Message-ID: <1994Feb1.070616.15982@sparky.sterling.com> +# Sender: kent@sparky.sterling.com (Kent Landfield) +# Organization: Sterling Software +# Date: Tue, 1 Feb 1994 07:06:16 GMT +# +# Posting-number: Volume 41, Issue 126 +# Archive-name: br/part01 +# Environment: basic, dos, os9 include Math require "date.rb" -require "parsearg.rb" - -def usage() - print "Usage:\n" - print "biorhythm.rb [options]\n" - print " options...\n" - print " -D YYYYMMDD(birthday) : ¤¹¤Ù¤Æ default Ãͤò»È¤¦. \n" - print " --sdate | --date YYYYMMDD : system date ¤â¤·¤¯¤Ï»ØÄꤷ¤¿ÆüÉÕ¤ò»È¤¦.\n" - print " --birthday YYYYMMDD : ÃÂÀ¸Æü¤Î»ØÄê¤ò¤¹¤ë. \n" - print " -v | -g : Values or Graph ¤Î»ØÄê. \n" - print " --days DAYS : ´ü´Ö¤Î»ØÄê¤ò¤¹¤ë(Graph ¤Î»þ¤Î¤ß͸ú). \n" - print " --help : help\n" -end -$USAGE = 'usage' +require "optparse" +require "optparse/date" -def printHeader(y, m, d, p, w) +def print_header(y, m, d, p, w) print "\n>>> Biorhythm <<<\n" printf "The birthday %04d.%02d.%02d is a %s\n", y, m, d, w printf "Age in days: [%d]\n\n", p end -def getPosition(z) - pi = 3.14159265 +def get_position(z) + pi = Math::PI + z = Integer(z) phys = (50.0 * (1.0 + sin((z / 23.0 - (z / 23)) * 360.0 * pi / 180.0))).to_i emot = (50.0 * (1.0 + sin((z / 28.0 - (z / 28)) * 360.0 * pi / 180.0))).to_i geist =(50.0 * (1.0 + sin((z / 33.0 - (z / 33)) * 360.0 * pi / 180.0))).to_i return phys, emot, geist end +def prompt(msg) + $stderr.print msg + return gets.chomp +end + # # main program # -parseArgs(0, nil, "vg", "D:", "sdate", "date:", "birthday:", "days:") - -if $OPT_D - dd = Date.new(Time.now.strftime("%Y%m%d")) - bd = Date.new($OPT_D) - ausgabeart = "g" -else - if $OPT_birthday - bd = Date.new($OPT_birthday) - else - printf(STDERR, "Birthday (YYYYMMDD) : ") - if (si = STDIN.gets.chop) != "" - bd = Date.new(si) - end - end - if !bd - printf STDERR, "BAD Input Birthday!!\n" - exit() - end - - if $OPT_sdate - dd = Date.new(Time.now.strftime("%Y%m%d")) - elsif $OPT_date - dd = Date.new($OPT_date) - else - printf(STDERR, "Date [<RETURN> for Systemdate] (YYYYMMDD) : ") - if (si = STDIN.gets.chop) != "" - dd = Date.new(si) - end - end - if !dd - dd = Date.new(Time.now.strftime("%Y%m%d")) - end - - if $OPT_v - ausgabeart = "v" - elsif $OPT_g - ausgabeart = "g" - else - printf(STDERR, "Values for today or Graph (v/g) [default g] : ") - ausgabeart = STDIN.gets.chop +options = { + :graph => true, + :date => Date.today, + :days => 9, +} +ARGV.options do |opts| + opts.on("-b", "--birthday=DATE", Date, "specify your birthday"){|v| + options[:birthday] = v + } + opts.on("--date=DATE", Date, "specify date to show"){|v| + options[:date] = v + } + opts.on("-g", "--show-graph", TrueClass, "show graph (default)"){|v| + options[:graph] = v + } + opts.on("-v", "--show-values", TrueClass, "show values"){|v| + options[:graph] = !v + } + opts.on("--days=DAYS", Integer, "graph range (only in effect for graph)"){|v| + options[:days] = v - 1 + } + opts.on_tail("-h", "--help", "show this message"){puts opts; exit} + begin + opts.parse! + rescue => ex + puts "Error: #{ex.message}" + puts opts + exit end end -if (ausgabeart == "v") - printHeader(bd.year, bd.month, bd.day, dd.period - bd.period, bd.name_of_week) + +bd = options[:birthday] || Date.parse(prompt("Your birthday (YYYYMMDD): ")) +dd = options[:date] || Date.today +ausgabeart = options[:graph] ? "g" : "v" +display_period = options[:days] + +if ausgabeart == "v" + print_header(bd.year, bd.month, bd.day, dd - bd, bd.strftime("%a")) print "\n" - - phys, emot, geist = getPosition(dd.period - bd.period) + + phys, emot, geist = get_position(dd - bd) printf "Biorhythm: %04d.%02d.%02d\n", dd.year, dd.month, dd.day printf "Physical: %d%%\n", phys printf "Emotional: %d%%\n", emot printf "Mental: %d%%\n", geist print "\n" else - if $OPT_days - display_period = $OPT_days.to_i - elsif $OPT_D - display_period = 9 - else - printf(STDERR, "Graph for how many days [default 10] : ") - display_period = STDIN.gets.chop - if (display_period == "") - display_period = 9 - else - display_period = display_period.to_i - 1 - end - end - - printHeader(bd.year, bd.month, bd.day, dd.period - bd.period, bd.name_of_week) + print_header(bd.year, bd.month, bd.day, dd - bd, bd.strftime("%a")) print " P=physical, E=emotional, M=mental\n" print " -------------------------+-------------------------\n" print " Bad Condition | Good Condition\n" print " -------------------------+-------------------------\n" - - for z in (dd.period - bd.period)..(dd.period - bd.period + display_period) - phys, emot, geist = getPosition(z) - + + (dd - bd).step(dd - bd + display_period) do |z| + phys, emot, geist = get_position(z) + printf "%04d.%02d.%02d : ", dd.year, dd.month, dd.day p = (phys / 2.0 + 0.5).to_i e = (emot / 2.0 + 0.5).to_i diff --git a/sample/cal.rb b/sample/cal.rb new file mode 100644 index 0000000000..97f75bcf1c --- /dev/null +++ b/sample/cal.rb @@ -0,0 +1,166 @@ +#! /usr/bin/env ruby + +# cal.rb: Written by Tadayoshi Funaba 1998-2004,2006,2008 +# $Id: cal.rb,v 2.11 2008-01-06 08:42:17+09 tadf Exp $ + +require 'date' + +class Cal + + START = + { + 'cn' => Date::GREGORIAN, # China + 'de' => 2342032, # Germany (protestant states) + 'dk' => 2342032, # Denmark + 'es' => 2299161, # Spain + 'fi' => 2361390, # Finland + 'fr' => 2299227, # France + 'gb' => 2361222, # United Kingdom + 'gr' => 2423868, # Greece + 'hu' => 2301004, # Hungary + 'it' => 2299161, # Italy + 'jp' => Date::GREGORIAN, # Japan + 'no' => 2342032, # Norway + 'pl' => 2299161, # Poland + 'pt' => 2299161, # Portugal + 'ru' => 2421639, # Russia + 'se' => 2361390, # Sweden + 'us' => 2361222, # United States + 'os' => Date::JULIAN, # (old style) + 'ns' => Date::GREGORIAN # (new style) + } + + DEFAULT_START = 'gb' + + def initialize + opt_j; opt_m; opt_t; opt_y; opt_c + end + + def opt_j(flag=false) @opt_j = flag end + def opt_m(flag=false) @opt_m = flag end + def opt_t(flag=false) @opt_t = flag end + def opt_y(flag=false) @opt_y = flag end + + def opt_c(arg=DEFAULT_START) @start = START[arg] end + + def set_params + @dw = if @opt_j then 3 else 2 end + @mw = (@dw + 1) * 7 - 1 + @mn = if @opt_j then 2 else 3 end + @tw = (@mw + 2) * @mn - 2 + @k = if @opt_m then 1 else 0 end + @da = if @opt_j then :yday else :mday end + end + + def pict(y, m) + d = (1..31).detect{|x| Date.valid_date?(y, m, x, @start)} + fi = Date.new(y, m, d, @start) + fi -= (fi.jd - @k + 1) % 7 + + ve = (fi..fi + 6).collect{|cu| + %w(S M Tu W Th F S)[cu.wday] + } + ve += (fi..fi + 41).collect{|cu| + if cu.mon == m then cu.send(@da) end.to_s + } + + ve = ve.collect{|e| e.rjust(@dw)} + + gr = group(ve, 7) + gr = trans(gr) if @opt_t + ta = gr.collect{|xs| xs.join(' ')} + + ca = %w(January February March April May June July + August September October November December)[m - 1] + ca = ca + ' ' + y.to_s if !@opt_y + ca = ca.center(@mw) + + ta.unshift(ca) + end + + def group(xs, n) + (0..xs.size / n - 1).collect{|i| xs[i * n, n]} + end + + def trans(xs) + (0..xs[0].size - 1).collect{|i| xs.collect{|x| x[i]}} + end + + def stack(xs) + if xs.empty? then [] else xs[0] + stack(xs[1..-1]) end + end + + def block(xs, n) + stack(group(xs, n).collect{|ys| trans(ys).collect{|zs| zs.join(' ')}}) + end + + def unlines(xs) + xs.collect{|x| x + "\n"}.join + end + + def monthly(y, m) + unlines(pict(y, m)) + end + + def addmon(y, m, n) + y, m = (y * 12 + (m - 1) + n).divmod(12) + return y, m + 1 + end + + def yearly(y) + y.to_s.center(@tw) + "\n\n" + + unlines(block((0..11).collect{|n| pict(*addmon(y, 1, n))}, @mn)) + "\n" + end + + def print(y, m) + set_params + if @opt_y then yearly(y) else monthly(y, m) end + end + +end + +if __FILE__ == $0 + + require 'getoptlong' + + def usage + warn 'usage: cal [-c iso3166] [-jmty] [[month] year]' + exit 1 + end + + cal = Cal.new + + begin + GetoptLong.new(['-c', GetoptLong::REQUIRED_ARGUMENT], + ['-j', GetoptLong::NO_ARGUMENT], + ['-m', GetoptLong::NO_ARGUMENT], + ['-t', GetoptLong::NO_ARGUMENT], + ['-y', GetoptLong::NO_ARGUMENT]). + each do |opt, arg| + case opt + when '-c'; cal.opt_c(arg) || raise + when '-j'; cal.opt_j(true) + when '-m'; cal.opt_m(true) + when '-t'; cal.opt_t(true) + when '-y'; cal.opt_y(true) + end + end + rescue + usage + end + + y, m = ARGV.values_at(1, 0).compact.collect{|x| x.to_i} + cal.opt_y(true) if y && !m + + to = Date.today + y ||= to.year + m ||= to.mon + + usage unless m >= 1 && m <= 12 + usage unless y >= -4712 + + print cal.print(y, m) + +end + +# See Bird & Wadler's Introduction to functional programming 4.5. diff --git a/sample/cbreak.rb b/sample/cbreak.rb new file mode 100644 index 0000000000..7f1385cce3 --- /dev/null +++ b/sample/cbreak.rb @@ -0,0 +1,36 @@ +# ioctl example works on Sun + +CBREAK = 0x00000002 +ECHO = 0x00000008 +TIOCGETP = 0x40067408 +TIOCSETP = 0x80067409 + +def cbreak + set_cbreak(true) +end + +def cooked + set_cbreak(false) +end + +def set_cbreak(on) + tty = "\0" * 256 + STDIN.ioctl(TIOCGETP, tty) + ttys = tty.unpack("C4 S") + if on + ttys[4] |= CBREAK + ttys[4] &= ~ECHO + else + ttys[4] &= ~CBREAK + ttys[4] |= ECHO + end + tty = ttys.pack("C4 S") + STDIN.ioctl(TIOCSETP, tty) +end +cbreak(); + +print("this is no-echo line: "); +readline().display +cooked(); +print("this is echo line: "); +readline() diff --git a/sample/cgi-session-pstore.rb b/sample/cgi-session-pstore.rb new file mode 100644 index 0000000000..ec8b4989d6 --- /dev/null +++ b/sample/cgi-session-pstore.rb @@ -0,0 +1,11 @@ +require 'cgi' +require 'cgi/session/pstore' + +STDIN.reopen(IO::NULL) +cgi = CGI.new +session = CGI::Session.new(cgi, 'database_manager' => CGI::Session::PStore) +session['key'] = {'k' => 'v'} +puts session['key'].class +fail unless Hash === session['key'] +puts session['key'].inspect +fail unless session['key'].inspect == '{"k"=>"v"}' diff --git a/sample/clnt.rb b/sample/clnt.rb index 7998379aa2..0f3d17bf19 100644 --- a/sample/clnt.rb +++ b/sample/clnt.rb @@ -3,15 +3,19 @@ require "socket" -host=(if ARGV.length == 2; ARGV.shift; else "localhost"; end) +if ARGV.length >= 2 + host = ARGV.shift +else + host = "localhost" +end print("Trying ", host, " ...") STDOUT.flush -s = TCPsocket.open(host, ARGV.shift) +s = TCPSocket.open(host, ARGV.shift) print(" done\n") print("addr: ", s.addr.join(":"), "\n") print("peer: ", s.peeraddr.join(":"), "\n") -while gets() - s.write($_) +while line = gets() + s.write(line) print(s.readline) end s.close diff --git a/sample/coverage.rb b/sample/coverage.rb new file mode 100644 index 0000000000..8e8d6167e2 --- /dev/null +++ b/sample/coverage.rb @@ -0,0 +1,62 @@ +require "coverage.so" + +Coverage.start + +ext = ENV["COVERUBY_EXT"] || ".cov" +accum = ENV["COVERUBY_ACCUM"] +accum = !accum || accum == "" || !(%w(f n 0).include?(accum[0])) +pwd = Dir.pwd + +at_exit do + exit_exc = $! + Dir.chdir(pwd) do + Coverage.result.each do |sfile, covs| + cfile = sfile + ext + + writable = proc do |f| + File.writable?(f) || File.writable?(File.dirname(f)) + end + unless writable[cfile] + cfile = cfile.gsub(File::PATH_SEPARATOR, "#") + next unless writable[cfile] + end + + readlines = proc do |f| + File.read(f).force_encoding("ASCII-8BIT").lines.to_a + end + + sources = (readlines[sfile] rescue []) + + pcovs = [] + if accum + pcovs = (readlines[cfile] rescue []).map.with_index do |line, idx| + if line[/^\s*(?:(#####)|(\d+)|-):\s*\d+:(.*)$/n] + cov, line = $1 ? 0 : ($2 ? $2.to_i : nil), $3 + if !sources[idx] || sources[idx].chomp != line.chomp + warn("source file changed, ignoring: `#{ cfile }'") + break [] + end + cov + else + p line + warn("coverage file corrupted, ignoring: #{ cfile }") + break [] + end + end + unless pcovs.empty? || pcovs.size == covs.size + warn("coverage file changed, ignoring: `#{ cfile }'") + pcovs = [] + end + end + + open(cfile, "w") do |out| + covs.zip(sources, pcovs).each_with_index do |(cov, line, pcov), idx| + cov += pcov || 0 if cov + cov = (cov ? (cov == 0 ? "#####" : cov.to_s) : "-").rjust(9) + out.puts("%s:% 5d:%s" % [cov, idx + 1, line]) + end + end + end + end + raise exit_exc if exit_exc +end diff --git a/sample/dbmtest.rb b/sample/dbmtest.rb deleted file mode 100644 index c77cc2065b..0000000000 --- a/sample/dbmtest.rb +++ /dev/null @@ -1,14 +0,0 @@ -# ruby dbm acess -require "dbm" - -d = DBM.open("test") -keys = d.keys -if keys.length > 0 then - for k in keys; print k, "\n"; end - for v in d.values; print v, "\n"; end -else - d['foobar'] = 'FB' - d['baz'] = 'BZ' - d['quux'] = 'QX' -end - diff --git a/sample/delegate.rb b/sample/delegate.rb new file mode 100644 index 0000000000..dc7ea2a0af --- /dev/null +++ b/sample/delegate.rb @@ -0,0 +1,31 @@ +require 'delegate' + +class ExtArray < DelegateClass(Array) + def initialize() + super([]) + end +end + +ary = ExtArray.new +p ary.class +ary.push 25 +p ary +ary.push 42 +ary.each {|x| p x} + +foo = Object.new +def foo.test + 25 +end +def foo.iter + yield self +end +def foo.error + raise 'this is OK' +end +foo2 = SimpleDelegator.new(foo) +p foo2 +foo2.instance_eval{print "foo\n"} +p foo.test == foo2.test # => true +p foo2.iter{[55,true]} # => true +foo2.error # raise error! diff --git a/sample/dir.rb b/sample/dir.rb index 2465c4d68e..44733c2cf4 100644 --- a/sample/dir.rb +++ b/sample/dir.rb @@ -2,8 +2,10 @@ # list all files but .*/*~/*.o dirp = Dir.open(".") for f in dirp - $_ = f - unless (~/^\./ || ~/~$/ || ~/\.o/) + case f + when /\A\./, /~\z/, /\.o/ + # do not print + else print f, "\n" end end diff --git a/sample/drb/README.ja.rdoc b/sample/drb/README.ja.rdoc new file mode 100644 index 0000000000..3ab70f3369 --- /dev/null +++ b/sample/drb/README.ja.rdoc @@ -0,0 +1,59 @@ += サンプルスクリプト + +* Arrayをリモートã‹ã‚‰åˆ©ç”¨ã—ã¦ã‚¤ãƒ†ãƒ¬ãƒ¼ã‚¿ã‚’試ã™ã€‚ + * darray.rb --- server + * darrayc.rb --- client + +* 簡易ãƒãƒ£ãƒƒãƒˆ + * dchats.rb --- server + * dchatc.rb --- client + +* 分散chasen + * dhasen.rb --- server + * dhasenc.rb --- client + +* 簡易ãƒã‚°ã‚µãƒ¼ãƒ + * dlogd.rb --- server + * dlogc.rb --- client + +* Queueサーãƒã€‚ + クライアントdqin.rbã¯Queueサーãƒã®çŸ¥ã‚‰ãªã„オブジェクト(DQEntry)ã‚’ + pushã™ã‚‹ãŒDRbUnknownã«ã‚ˆã‚Šã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆdqout.rbãŒpopã§ãる。 + * dqueue.rb --- server + * dqin.rb --- client。DQEntryオブジェクトをpushã™ã‚‹ + * dqout.rb --- client。DQEntryオブジェクトをpopã™ã‚‹ + * dqlib.rb --- DQEntryを定義ã—ãŸãƒ©ã‚¤ãƒ–ラリ + +* åå‰ã«ã‚ˆã‚‹å‚ç…§ + IdConvをカスタマイズã—ã¦idã§ãªãåå‰ã§å‚ç…§ã™ã‚‹ä¾‹ + * name.rb --- server + * namec.rb --- client + +* extservã®ã‚µãƒ³ãƒ—ル + * extserv_test.rb + +* TimerIdConvã®ä½¿ç”¨ä¾‹ + * holders.rb --- server。ruby -d hodlers.rbã¨ã™ã‚‹ã¨TimerIdConvを使用ã™ã‚‹ã€‚ + * holderc.rb --- client + +* rinda.rbã®ä½¿ç”¨ä¾‹ + * rinda_ts.rb --- TupleSpaceサーãƒã€‚ + * rindac.rb --- TupleSpaceã®clientã§ã‚¢ãƒ—リケーションã®client + * rindas.rb --- TupleSpaceã®clientã§ã‚¢ãƒ—リケーションã®server + +* observerã®ä½¿ç”¨ä¾‹ + cdbiff - http://namazu.org/~satoru/cdbiff/ + * dbiff.rb --- dcdbiff server + * dcdbiff.rb --- dcdbiff client + +* drbsslã®ä½¿ç”¨ä¾‹ + * drbssl_s.rb + * drbssl_c.rb + +* DRbProtoclã®è¿½åР例 + * http0.rb + * http0serv.rb + +* ringã®ä½¿ç”¨ä¾‹ + * ring_place.rb + * ring_echo.rb diff --git a/sample/drb/README.rdoc b/sample/drb/README.rdoc new file mode 100644 index 0000000000..80ae910a8a --- /dev/null +++ b/sample/drb/README.rdoc @@ -0,0 +1,56 @@ += Sample scripts + +* array and iteretor + * darray.rb --- server + * darrayc.rb --- client + +* simple chat + * dchats.rb --- server + * dchatc.rb --- client + +* distributed chasen (for Japanese) + * dhasen.rb --- server + * dhasenc.rb --- client + +* simple log server + * dlogd.rb --- server + * dlogc.rb --- client + +* Queue server, and DRbUnknown demo + * dqueue.rb --- server + * dqin.rb --- client. push DQEntry objects. + * dqout.rb --- client. pop DQEntry objects. + * dqlib.rb --- define DQEntry + +* IdConv customize demo: reference by name + * name.rb --- server + * namec.rb --- client + +* extserv + * extserv_test.rb + +* IdConv customize demo 2: using TimerIdConv + * holders.rb --- server + * holderc.rb --- client + +* rinda, remote tuplespace + * rinda_ts.rb --- TupleSpace server. + * rindas.rb --- provide simple service via TupleSpace. + * rindac.rb --- service user + +* observer + cdbiff - http://namazu.org/~satoru/cdbiff/ + * dbiff.rb --- dcdbiff server + * dcdbiff.rb --- dcdbiff client + +* drbssl + * drbssl_s.rb + * drbssl_c.rb + +* add DRbProtocl + * http0.rb + * http0serv.rb + +* Rinda::Ring + * ring_place.rb + * ring_echo.rb diff --git a/sample/drb/acl.rb b/sample/drb/acl.rb new file mode 100644 index 0000000000..d93eb9c1fc --- /dev/null +++ b/sample/drb/acl.rb @@ -0,0 +1,15 @@ +require 'drb/acl' + +list = %w(deny all + allow 192.168.1.1 + allow ::ffff:192.168.1.2 + allow 192.168.1.3 +) + +addr = ["AF_INET", 10, "lc630", "192.168.1.3"] + +acl = ACL.new +p acl.allow_addr?(addr) + +acl = ACL.new(list, ACL::DENY_ALLOW) +p acl.allow_addr?(addr) diff --git a/sample/drb/darray.rb b/sample/drb/darray.rb new file mode 100644 index 0000000000..d2ac39513f --- /dev/null +++ b/sample/drb/darray.rb @@ -0,0 +1,12 @@ +=begin + distributed Ruby --- Array + Copyright (c) 1999-2001 Masatoshi SEKI +=end + +require 'drb/drb' + +here = ARGV.shift +DRb.start_service(here, [1, 2, "III", 4, "five", 6]) +puts DRb.uri +DRb.thread.join + diff --git a/sample/drb/darrayc.rb b/sample/drb/darrayc.rb new file mode 100644 index 0000000000..579e11564e --- /dev/null +++ b/sample/drb/darrayc.rb @@ -0,0 +1,47 @@ +=begin + distributed Ruby --- Array client + Copyright (c) 1999-2001 Masatoshi SEKI +=end + +require 'drb/drb' + +there = ARGV.shift || raise("usage: #{$0} <server_uri>") + +DRb.start_service(nil, nil) +ro = DRbObject.new(nil, there) +p ro.size + +puts "# collect" +a = ro.collect { |x| + x + x +} +p a + +puts "# find" +p ro.find { |x| x.kind_of? String } + +puts "# each, break" +ro.each do |x| + next if x == "five" + puts x +end + +puts "# each, break" +ro.each do |x| + break if x == "five" + puts x +end + +puts "# each, next" +ro.each do |x| + next if x == "five" + puts x +end + +puts "# each, redo" +count = 0 +ro.each do |x| + count += 1 + puts count + redo if count == 3 +end diff --git a/sample/drb/dbiff.rb b/sample/drb/dbiff.rb new file mode 100644 index 0000000000..290eb1d28b --- /dev/null +++ b/sample/drb/dbiff.rb @@ -0,0 +1,51 @@ +# +# dbiff.rb - distributed cdbiff (server) +# * original: cdbiff by Satoru Takabayashi <http://namazu.org/~satoru/cdbiff> + +require 'drb/drb' +require 'drb/eq' +require 'drb/observer' + +class Biff + include DRb::DRbObservable + + def initialize(filename, interval) + super() + @filename = filename + @interval = interval + end + + def run + last = Time.now + while true + begin + sleep(@interval) + current = File::mtime(@filename) + if current > last + changed + begin + notify_observers(@filename, current) + rescue Error + end + last = current + end + rescue + next + end + end + end +end + +def main + filename = "/var/mail/#{ENV['USER']}" + interval = 15 + uri = 'druby://:19903' + + biff = Biff.new(filename, interval) + + DRb.start_service(uri, biff) + biff.run +end + +main + diff --git a/sample/drb/dcdbiff.rb b/sample/drb/dcdbiff.rb new file mode 100644 index 0000000000..6a24680c33 --- /dev/null +++ b/sample/drb/dcdbiff.rb @@ -0,0 +1,43 @@ +# +# dcdbiff.rb - distributed cdbiff (client) +# * original: cdbiff by Satoru Takabayashi <http://namazu.org/~satoru/cdbiff> + +require 'drb/drb' +require 'drb/eq' + +class Notify + include DRbUndumped + + def initialize(biff, command) + @biff = biff + @command = command + + @biff.add_observer(self) + end + + def update(filename, time) + p [filename, time] if $DEBUG + system(@command) + end + + def done + begin + @biff.delete_observer(self) + rescue + end + end +end + +def main + command = 'eject' + uri = 'druby://localhost:19903' + + DRb.start_service + biff = DRbObject.new(nil, uri) + notify = Notify.new(biff, command) + + trap("INT"){ notify.done } + DRb.thread.join +end + +main diff --git a/sample/drb/dchatc.rb b/sample/drb/dchatc.rb new file mode 100644 index 0000000000..2b8ddbf4cc --- /dev/null +++ b/sample/drb/dchatc.rb @@ -0,0 +1,41 @@ +=begin + distributed Ruby --- chat client + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +require 'drb/drb' + +class ChatClient + include DRbUndumped + + def initialize(name) + @name = name + @key = nil + end + attr_reader(:name) + attr_accessor(:key) + + def message(there, str) + raise 'invalid key' unless @key == there + puts str + end +end + +if __FILE__ == $0 + begin + there = ARGV.shift + name = ARGV.shift + raise "usage" unless (there and name) + rescue + $stderr.puts("usage: #{$0} <server_uri> <your_name>") + exit 1 + end + DRb.start_service + ro = DRbObject.new(nil, there) + + chat = ChatClient.new(name) + entry = ro.add_member(chat) + while gets + entry.say($_) + end +end diff --git a/sample/drb/dchats.rb b/sample/drb/dchats.rb new file mode 100644 index 0000000000..58af3cf005 --- /dev/null +++ b/sample/drb/dchats.rb @@ -0,0 +1,69 @@ +=begin + distributed Ruby --- chat server + Copyright (c) 1999-2000 Masatoshi SEKI +=end +require 'drb/drb' + +class ChatEntry + include DRbUndumped + + def initialize(server, there) + @server = server + @there = there + @name = there.name + @key = there.key = Time.now + end + attr :name, true + attr :there + + def say(str) + @server.distribute(@there, str) + end + + def listen(str) + @there.message(@key, str) + end +end + + +class ChatServer + def initialize + @mutex = Mutex.new + @members = {} + end + + def add_member(there) + client = ChatEntry.new(self, there) + @mutex.synchronize do + @members[there] = client + end + client + end + + def distribute(there, str) + name = @members[there].name + msg = "<#{name}> #{str}" + msg2 = ">#{name}< #{str}" + @mutex.synchronize do + for m in @members.keys + begin + if m == there + @members[m].listen(msg2) + else + @members[m].listen(msg) + end + rescue + p $! + @members.delete(m) + end + end + end + end +end + +if __FILE__ == $0 + here = ARGV.shift + DRb.start_service(here, ChatServer.new) + puts DRb.uri + DRb.thread.join +end diff --git a/sample/drb/dhasen.rb b/sample/drb/dhasen.rb new file mode 100644 index 0000000000..13ff38940e --- /dev/null +++ b/sample/drb/dhasen.rb @@ -0,0 +1,41 @@ +=begin + distributed Ruby --- dRuby Sample Server --- chasen server + Copyright (c) 1999-2001 Masatoshi SEKI +=end + +=begin + How to play. + + Terminal 1 + | % ruby dhasen.rb + | druby://yourhost:7640 + + Terminal 2 + | % ruby dhasenc.rb druby://yourhost:7640 + +=end + +require 'drb/drb' +require 'chasen' + +class Dhasen + include DRbUndumped + + def initialize + @mutex = Thread::Mutex.new + end + + def sparse(str, *arg) + @mutex.synchronize do + Chasen.getopt(*arg) + Chasen.sparse(str) + end + end +end + +if __FILE__ == $0 + DRb.start_service(nil, Dhasen.new) + puts DRb.uri + DRb.thread.join +end + diff --git a/sample/drb/dhasenc.rb b/sample/drb/dhasenc.rb new file mode 100644 index 0000000000..dddac9882c --- /dev/null +++ b/sample/drb/dhasenc.rb @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +=begin + distributed Ruby --- dRuby Sample Client -- chasen client + Copyright (c) 1999-2001 Masatoshi SEKI +=end + +require 'drb/drb' + +there = ARGV.shift || raise("usage: #{$0} <server_uri>") +DRb.start_service +dhasen = DRbObject.new(nil, there) + +print dhasen.sparse("本日ã¯ã€æ™´å¤©ãªã‚Šã€‚", "-F", '(%BB %m %M)\n', "-j") +print dhasen.sparse("本日ã¯ã€æ™´å¤©ãªã‚Šã€‚", "-F", '(%m %M)\n') diff --git a/sample/drb/dlogc.rb b/sample/drb/dlogc.rb new file mode 100644 index 0000000000..3939a71827 --- /dev/null +++ b/sample/drb/dlogc.rb @@ -0,0 +1,16 @@ +=begin + distributed Ruby --- Log test + Copyright (c) 1999-2001 Masatoshi SEKI +=end + +require 'drb/drb' + +there = ARGV.shift || raise("usage: #{$0} <server_uri>") + +DRb.start_service +ro = DRbObject.new(nil, there) +ro.log(123) +ro.log("hello") +sleep 2 +ro.log("wakeup") + diff --git a/sample/drb/dlogd.rb b/sample/drb/dlogd.rb new file mode 100644 index 0000000000..a87e660346 --- /dev/null +++ b/sample/drb/dlogd.rb @@ -0,0 +1,38 @@ +=begin + distributed Ruby --- Log server + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +require 'drb/drb' + +class Logger + def initialize(fname) + @fname = fname.to_s + @fp = File.open(@fname, "a+") + @queue = Thread::Queue.new + @th = Thread.new { self.flush } + end + + def log(str) + @queue.push("#{Time.now}\t" + str.to_s) + end + + def flush + begin + while(1) + @fp.puts(@queue.pop) + @fp.flush + end + ensure + @fp.close + end + end +end + +if __FILE__ == $0 + here = ARGV.shift + DRb.start_service(here, Logger.new('/usr/tmp/dlogd.log')) + puts DRb.uri + DRb.thread.join +end + diff --git a/sample/drb/dqin.rb b/sample/drb/dqin.rb new file mode 100644 index 0000000000..4751335fff --- /dev/null +++ b/sample/drb/dqin.rb @@ -0,0 +1,13 @@ +=begin + distributed Ruby --- store + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +require 'drb/drb' +require 'dqlib' + +there = ARGV.shift || raise("usage: #{$0} <server_uri>") + +DRb.start_service +queue = DRbObject.new(nil, there) +queue.push(DQEntry.new(DRb.uri)) diff --git a/sample/drb/dqlib.rb b/sample/drb/dqlib.rb new file mode 100644 index 0000000000..75f2e6115b --- /dev/null +++ b/sample/drb/dqlib.rb @@ -0,0 +1,14 @@ +class DQEntry + def initialize(name) + @name = name + end + + def greeting + "Hello, This is #{@name}." + end + alias to_s greeting +end + +if __FILE__ == $0 + puts DQEntry.new('DQEntry') +end diff --git a/sample/drb/dqout.rb b/sample/drb/dqout.rb new file mode 100644 index 0000000000..f2b0b4ac95 --- /dev/null +++ b/sample/drb/dqout.rb @@ -0,0 +1,14 @@ +=begin + distributed Ruby --- fetch + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +require 'drb/drb' +require 'dqlib' + +there = ARGV.shift || raise("usage: #{$0} <server_uri>") + +DRb.start_service +queue = DRbObject.new(nil, there) +entry = queue.pop +puts entry.greeting diff --git a/sample/drb/dqueue.rb b/sample/drb/dqueue.rb new file mode 100644 index 0000000000..a9afa8c858 --- /dev/null +++ b/sample/drb/dqueue.rb @@ -0,0 +1,11 @@ +=begin + distributed Ruby --- Queue + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +require 'drb/drb' + +DRb.start_service(nil, Thread::Queue.new) +puts DRb.uri +DRb.thread.join + diff --git a/sample/drb/drbc.rb b/sample/drb/drbc.rb new file mode 100644 index 0000000000..50a86c39e8 --- /dev/null +++ b/sample/drb/drbc.rb @@ -0,0 +1,45 @@ +=begin + distributed Ruby --- dRuby Sample Client + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +require 'drb/drb' + +class DRbEx2 + include DRbUndumped + + def initialize(n) + @n = n + end + + def to_i + @n.to_i + end +end + +if __FILE__ == $0 + there = ARGV.shift + unless there + $stderr.puts("usage: #{$0} <server_uri>") + exit 1 + end + + DRb.start_service() + ro = DRbObject.new_with_uri(there) + + puts ro + p ro.to_a + puts ro.hello + p ro.hello + puts ro.sample(DRbEx2.new(1), 2, 3) + puts ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3)) + + begin + ro.err + rescue DRb::DRbUnknownError + p $! + p $!.unknown + rescue RuntimeError + p $! + end +end diff --git a/sample/drb/drbch.rb b/sample/drb/drbch.rb new file mode 100644 index 0000000000..07fdcd5fae --- /dev/null +++ b/sample/drb/drbch.rb @@ -0,0 +1,48 @@ +=begin + distributed Ruby --- dRuby Sample Client + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +require 'drb/drb' +require 'drb/http' + +class DRbEx2 + include DRbUndumped + + def initialize(n) + @n = n + end + + def to_i + @n.to_i + end +end + +if __FILE__ == $0 + there = ARGV.shift + unless there + $stderr.puts("usage: #{$0} <server_uri>") + exit 1 + end + + DRb::DRbConn.proxy_map['x68k'] = 'http://x68k/~mas/http_cgi.rb' + + DRb.start_service() + ro = DRbObject.new(nil, there) + + puts ro + p ro.to_a + puts ro.hello + p ro.hello + puts ro.sample(DRbEx2.new(1), 2, 3) + puts ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3)) + + begin + ro.err + rescue DRb::DRbUnknownError + p $! + p $!.unknown + rescue RuntimeError + p $! + end +end diff --git a/sample/drb/drbm.rb b/sample/drb/drbm.rb new file mode 100644 index 0000000000..3390608cd1 --- /dev/null +++ b/sample/drb/drbm.rb @@ -0,0 +1,60 @@ +=begin + multiple DRbServer + Copyright (c) 1999-2002 Masatoshi SEKI +=end + +=begin + How to play. + + Terminal 1 + | % ruby drbm.rb + | druby://yourhost:7640 druby://yourhost:7641 + + Terminal 2 + | % ruby drbmc.rb druby://yourhost:7640 druby://yourhost:7641 + | [#<DRb::DRbObject .... @uri="druby://yourhost:7640">, "FOO"] + | [#<DRb::DRbObject .... @uri="druby://yourhost:7641">, "FOO"] + +=end + +require 'drb/drb' + +class Hoge + include DRbUndumped + def initialize(s) + @str = s + end + + def to_s + @str + end +end + +class Foo + def initialize(s='FOO') + @hoge = Hoge.new(s) + end + + def hello + @hoge + end +end + +class Bar < Foo + def initialize(foo) + @hoge = foo.hello + end +end + + +if __FILE__ == $0 + foo = Foo.new + s1 = DRb::DRbServer.new('druby://:7640', foo) + s2 = DRb::DRbServer.new('druby://:7641', Bar.new(foo)) + + puts "#{s1.uri} #{s2.uri}" + + s1.thread.join + s2.thread.join +end + diff --git a/sample/drb/drbmc.rb b/sample/drb/drbmc.rb new file mode 100644 index 0000000000..fd191401e6 --- /dev/null +++ b/sample/drb/drbmc.rb @@ -0,0 +1,22 @@ +=begin + multiple DRbServer client + Copyright (c) 1999-2002 Masatoshi SEKI +=end + +require 'drb/drb' + +if __FILE__ == $0 + s1 = ARGV.shift + s2 = ARGV.shift + unless s1 && s2 + $stderr.puts("usage: #{$0} <server_uri1> <server_uri2>") + exit 1 + end + + DRb.start_service() + r1 = DRbObject.new(nil, s1) + r2 = DRbObject.new(nil, s2) + + p [r1.hello, r1.hello.to_s] + p [r2.hello, r2.hello.to_s] +end diff --git a/sample/drb/drbs-acl.rb b/sample/drb/drbs-acl.rb new file mode 100644 index 0000000000..71c4f7bf42 --- /dev/null +++ b/sample/drb/drbs-acl.rb @@ -0,0 +1,51 @@ +=begin + distributed Ruby --- dRuby Sample Server + Copyright (c) 1999-2000 Masatoshi SEKI +=end + +=begin + How to play. + + Terminal 1 + | % ruby drbs.rb + | druby://yourhost:7640 + + Terminal 2 + | % ruby drbc.rb druby://yourhost:7640 + | "hello" + | 6 + | 10 + +=end + +require 'drb/drb' +require 'acl' + +class DRbEx + def initialize + @hello = 'hello' + end + + def hello + info = Thread.current['DRb'] + p info['socket'].peeraddr if info + @hello + end + + def sample(a, b, c) + a.to_i + b.to_i + c.to_i + end +end + +if __FILE__ == $0 + acl = ACL.new(%w(deny all + allow 192.168.1.* + allow localhost)) + + DRb.install_acl(acl) + + DRb.start_service(nil, DRbEx.new) + puts DRb.uri + DRb.thread.join +end + diff --git a/sample/drb/drbs.rb b/sample/drb/drbs.rb new file mode 100644 index 0000000000..5a913d9918 --- /dev/null +++ b/sample/drb/drbs.rb @@ -0,0 +1,64 @@ +=begin + distributed Ruby --- dRuby Sample Server + Copyright (c) 1999-2000,2002 Masatoshi SEKI +=end + +=begin + How to play. + + Terminal 1 + | % ruby drbs.rb + | druby://yourhost:7640 + + Terminal 2 + | % ruby drbc.rb druby://yourhost:7640 + | "hello" + | .... + +=end + +require 'drb/drb' + +class DRbEx + include DRbUndumped + + def initialize + @hello = 'hello' + end + + def hello + cntxt = Thread.current['DRb'] + if cntxt + p cntxt['server'].uri + p cntxt['client'].peeraddr + end + Foo::Unknown.new + end + + def err + raise FooError + end + + def sample(a, b, c) + a.to_i + b.to_i + c.to_i + end +end + +class Foo + class Unknown + end +end + +class FooError < RuntimeError +end + +if __FILE__ == $0 + DRb.start_service(ARGV.shift || 'druby://:7640', DRbEx.new) + puts DRb.uri + Thread.new do + sleep 10 + DRb.stop_service + end + DRb.thread.join +end + diff --git a/sample/drb/drbssl_c.rb b/sample/drb/drbssl_c.rb new file mode 100644 index 0000000000..65112f6e78 --- /dev/null +++ b/sample/drb/drbssl_c.rb @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby + +require 'drb' +require 'drb/ssl' + +there = ARGV.shift || "drbssl://localhost:3456" + +config = Hash.new +config[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER +config[:SSLVerifyCallback] = lambda{|ok,x509_store| + p [ok, x509_store.error_string] + true +} + +DRb.start_service(nil,nil,config) +h = DRbObject.new(nil, there) +while line = gets + p h.hello(line.chomp) +end diff --git a/sample/drb/drbssl_s.rb b/sample/drb/drbssl_s.rb new file mode 100644 index 0000000000..4d96f591d4 --- /dev/null +++ b/sample/drb/drbssl_s.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require 'drb' +require 'drb/ssl' + +here = ARGV.shift || "drbssl://localhost:3456" + +class HelloWorld + include DRbUndumped + + def hello(name) + "Hello, #{name}." + end +end + +config = Hash.new +config[:verbose] = true +begin + data = open("sample.key"){|io| io.read } + config[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(data) + data = open("sample.crt"){|io| io.read } + config[:SSLCertificate] = OpenSSL::X509::Certificate.new(data) +rescue + $stderr.puts "Switching to use self-signed certificate" + config[:SSLCertName] = + [ ["C","JP"], ["O","Foo.DRuby.Org"], ["CN", "Sample"] ] +end + +DRb.start_service(here, HelloWorld.new, config) +puts DRb.uri +DRb.thread.join diff --git a/sample/drb/extserv_test.rb b/sample/drb/extserv_test.rb new file mode 100644 index 0000000000..2c4f485dc6 --- /dev/null +++ b/sample/drb/extserv_test.rb @@ -0,0 +1,80 @@ +=begin + dRuby sample + Copyright (c) 2000 Masatoshi SEKI + += How to play + +* Terminal 1 + + % ruby -I. extserv_test.rb server + druby://yourhost:12345 + +* Terminal 2 + + % ruby -I. extserv_test.rb druby://yourhost:12345 + ... + +=end + +require 'drb/drb' + +def ARGV.shift + it = super() + raise "usage:\nserver: #{$0} server [<uri>]\nclient: #{$0} [quit] <uri>" unless it + it +end + +class Foo + include DRbUndumped + + def initialize(str) + @str = str + end + + def hello(it) + "#{it}: #{self}" + end + + def to_s + @str + end +end + +cmd = ARGV.shift +case cmd +when 'itest1', 'itest2' + require 'drb/extserv' + + front = Foo.new(cmd) + server = DRb::DRbServer.new(nil, front) + es = DRb::ExtServ.new(ARGV.shift, ARGV.shift, server) + server.thread.join + +when 'server' + require 'drb/extservm' + + DRb::ExtServManager.command['itest1'] = "ruby -I. #{$0} itest1" + DRb::ExtServManager.command['itest2'] = "ruby -I. #{$0} itest2" + + s = DRb::ExtServManager.new + DRb.start_service(ARGV.shift, s) + puts DRb.uri + DRb.thread.join + + +else + uri = (cmd == 'quit') ? ARGV.shift : cmd + + DRb.start_service + s = DRbObject.new(nil, uri) + t1 = s.service('itest1').front + puts t1 + t2 = s.service('itest2').front + puts t2 + puts t1.hello(t2) + if (cmd == 'quit') + s.service('itest1').stop_service + s.service('itest2').stop_service + end +end + diff --git a/sample/drb/gw_ct.rb b/sample/drb/gw_ct.rb new file mode 100644 index 0000000000..0622784018 --- /dev/null +++ b/sample/drb/gw_ct.rb @@ -0,0 +1,29 @@ +require 'drb/drb' + +class Foo + include DRbUndumped + + def foo(n) + n + n + end + + def bar(n) + yield(n) + yield(n) + end +end + +DRb.start_service(nil) +puts DRb.uri + +ro = DRbObject.new(nil, ARGV.shift) +ro[:tcp] = Foo.new +gets + +it = ro[:unix] +p [it, it.foo(1)] +gets + +p it.bar('2') {|n| n * 3} +gets + + diff --git a/sample/drb/gw_cu.rb b/sample/drb/gw_cu.rb new file mode 100644 index 0000000000..8079cbdc4f --- /dev/null +++ b/sample/drb/gw_cu.rb @@ -0,0 +1,28 @@ +require 'drb/drb' +require 'drb/unix' + +class Foo + include DRbUndumped + + def foo(n) + n + n + end + + def bar(n) + yield(n) + yield(n) + end +end + +DRb.start_service('drbunix:', nil) +puts DRb.uri + +ro = DRbObject.new(nil, ARGV.shift) +ro[:unix] = Foo.new +gets + +it = ro[:tcp] +p [it, it.foo(1)] +gets + +p it.bar('2') {|n| n * 3} +gets diff --git a/sample/drb/gw_s.rb b/sample/drb/gw_s.rb new file mode 100644 index 0000000000..c2bea0baad --- /dev/null +++ b/sample/drb/gw_s.rb @@ -0,0 +1,10 @@ +require 'drb/drb' +require 'drb/unix' +require 'drb/gw' + +DRb.install_id_conv(DRb::GWIdConv.new) +gw = DRb::GW.new +s1 = DRb::DRbServer.new(ARGV.shift, gw) +s2 = DRb::DRbServer.new(ARGV.shift, gw) +s1.thread.join +s2.thread.join diff --git a/sample/drb/holderc.rb b/sample/drb/holderc.rb new file mode 100644 index 0000000000..e627916d76 --- /dev/null +++ b/sample/drb/holderc.rb @@ -0,0 +1,22 @@ +require 'drb/drb' + +begin + there = ARGV.shift || raise +rescue + $stderr.puts("usage: #{$0} <server_uri>") + exit 1 +end + +DRb.start_service() +ro = DRbObject.new(nil, there) + +ary = [] +10.times do + ary.push(ro.gen) +end + +sleep 5 if $DEBUG + +ary.each do |e| + p e.sample([1]) +end diff --git a/sample/drb/holders.rb b/sample/drb/holders.rb new file mode 100644 index 0000000000..293426faa5 --- /dev/null +++ b/sample/drb/holders.rb @@ -0,0 +1,63 @@ +=begin += How to play. + +== with timeridconv: + % ruby -d holders.rb + druby://yourhost:1234 + + % ruby holderc.rb druby://yourhost:1234 + + +== without timeridconv: + % ruby holders.rb + druby://yourhost:1234 + + % ruby holderc.rb druby://yourhost:1234 +=end + + +require 'drb/drb' + +class DRbEx3 + include DRbUndumped + + def initialize(n) + @v = n + end + + def sample(list) + sum = 0 + list.each do |e| + sum += e.to_i + end + @v * sum + end +end + +class DRbEx4 + include DRbUndumped + + def initialize + @curr = 1 + end + + def gen + begin + @curr += 1 + DRbEx3.new(@curr) + ensure + GC.start + end + end +end + +if __FILE__ == $0 + if $DEBUG + require 'drb/timeridconv' + DRb.install_id_conv(DRb::TimerIdConv.new(2)) + end + + DRb.start_service(nil, DRbEx4.new) + puts DRb.uri + DRb.thread.join +end diff --git a/sample/drb/http0.rb b/sample/drb/http0.rb new file mode 100644 index 0000000000..e40d810311 --- /dev/null +++ b/sample/drb/http0.rb @@ -0,0 +1,77 @@ +require 'drb/drb' +require 'net/http' +require 'uri' + +module DRb + module HTTP0 + class StrStream + def initialize(str='') + @buf = str + end + attr_reader :buf + + def read(n) + begin + return @buf[0,n] + ensure + @buf[0,n] = '' + end + end + + def write(s) + @buf.concat s + end + end + + def self.uri_option(uri, config) + return uri, nil + end + + def self.open(uri, config) + unless /^http:/ =~ uri + raise(DRbBadScheme, uri) unless uri =~ /^http:/ + raise(DRbBadURI, 'can\'t parse uri:' + uri) + end + ClientSide.new(uri, config) + end + + class ClientSide + def initialize(uri, config) + @uri = uri + @res = nil + @config = config + @msg = DRbMessage.new(config) + @proxy = ENV['HTTP_PROXY'] + end + + def close; end + def alive?; false; end + + def send_request(ref, msg_id, *arg, &b) + stream = StrStream.new + @msg.send_request(stream, ref, msg_id, *arg, &b) + @reply_stream = StrStream.new + post(@uri, stream.buf) + end + + def recv_reply + @msg.recv_reply(@reply_stream) + end + + def post(url, data) + it = URI.parse(url) + path = [(it.path=='' ? '/' : it.path), it.query].compact.join('?') + http = Net::HTTP.new(it.host, it.port) + sio = StrStream.new + http.post(path, data, {'Content-Type'=>'application/octetstream;'}) do |str| + sio.write(str) + if @config[:load_limit] < sio.buf.size + raise TypeError, 'too large packet' + end + end + @reply_stream = sio + end + end + end + DRbProtocol.add_protocol(HTTP0) +end diff --git a/sample/drb/http0serv.rb b/sample/drb/http0serv.rb new file mode 100644 index 0000000000..1a58811fed --- /dev/null +++ b/sample/drb/http0serv.rb @@ -0,0 +1,118 @@ +require 'webrick' +require 'drb/drb' +require 'drb/http0' + +module DRb + module HTTP0 + + def self.open_server(uri, config) + unless /^http:/ =~ uri + raise(DRbBadScheme, uri) unless uri =~ /^http:/ + raise(DRbBadURI, 'can\'t parse uri:' + uri) + end + Server.new(uri, config) + end + + class Callback < WEBrick::HTTPServlet::AbstractServlet + def initialize(config, drb) + @config = config + @drb = drb + @queue = Thread::Queue.new + end + + def do_POST(req, res) + @req = req + @res = res + @drb.push(self) + @res.body = @queue.pop + @res['content-type'] = 'application/octet-stream;' + end + + def req_body + @req.body + end + + def reply(body) + @queue.push(body) + end + + def close + @queue.push('') + end + end + + class Server + def initialize(uri, config) + @uri = uri + @config = config + @queue = Thread::Queue.new + setup_webrick(uri) + end + attr_reader :uri + + def close + @server.shutdown if @server + @server = nil + end + + def push(callback) + @queue.push(callback) + end + + def accept + client = @queue.pop + ServerSide.new(client, @config) + end + + def setup_webrick(uri) + logger = WEBrick::Log::new($stderr, WEBrick::Log::FATAL) + u = URI.parse(uri) + s = WEBrick::HTTPServer.new(:Port => u.port, + :AddressFamily => Socket::AF_INET, + :BindAddress => u.host, + :Logger => logger, + :ServerType => Thread) + s.mount(u.path, Callback, self) + @server = s + s.start + end + end + + class ServerSide + def initialize(callback, config) + @callback = callback + @config = config + @msg = DRbMessage.new(@config) + @req_stream = StrStream.new(@callback.req_body) + end + + def close + @callback.close if @callback + @callback = nil + end + + def alive?; false; end + + def recv_request + begin + @msg.recv_request(@req_stream) + rescue + close + raise $! + end + end + + def send_reply(succ, result) + begin + return unless @callback + stream = StrStream.new + @msg.send_reply(stream, succ, result) + @callback.reply(stream.buf) + rescue + close + raise $! + end + end + end + end +end diff --git a/sample/drb/name.rb b/sample/drb/name.rb new file mode 100644 index 0000000000..a8ad28749d --- /dev/null +++ b/sample/drb/name.rb @@ -0,0 +1,116 @@ +=begin + distributed Ruby --- NamedObject Sample + Copyright (c) 2000-2001 Masatoshi SEKI +=end + +=begin +How to play. + +* start server + Terminal 1 + | % ruby name.rb druby://yourhost:7640 + | druby://yourhost:7640 + | [return] to exit + +* start client + Terminal 2 + | % ruby namec.rb druby://yourhost:7640 + | #<DRb::DRbObject:0x40164174 @uri="druby://yourhost:7640", @ref="seq"> + | #<DRb::DRbObject:0x40163c9c @uri="druby://yourhost:7640", @ref="mutex"> + | 1 + | 2 + | [return] to continue + +* restart server + Terminal 1 + type [return] + | % ruby name.rb druby://yourhost:7640 + | druby://yourhost:7640 + | [return] to exit + +* continue client + Terminal 2 + type [return] + | 1 + | 2 +=end + +require 'drb/drb' + +module DRbNamedObject + DRbNAMEDICT = {} + attr_reader(:drb_name) + + def drb_name=(name) + @drb_name = name + Thread.exclusive do + raise(IndexError, name) if DRbNAMEDICT[name] + DRbNAMEDICT[name] = self + end + end +end + +class DRbNamedIdConv < DRb::DRbIdConv + def initialize + @dict = DRbNamedObject::DRbNAMEDICT + end + + def to_obj(ref) + @dict.fetch(ref) do super end + end + + def to_id(obj) + if obj.kind_of? DRbNamedObject + return obj.drb_name + else + return super + end + end +end + +class Seq + include DRbUndumped + include DRbNamedObject + + def initialize(v, name) + @counter = v + @mutex = Thread::Mutex.new + self.drb_name = name + end + + def next_value + @mutex.synchronize do + @counter += 1 + return @counter + end + end +end + +class Front + def initialize + seq = Seq.new(0, 'seq') + mutex = Thread::Mutex.new + mutex.extend(DRbUndumped) + mutex.extend(DRbNamedObject) + mutex.drb_name = 'mutex' + @name = {} + @name['seq'] = seq + @name['mutex'] = mutex + end + + def [](k) + @name[k] + end +end + +if __FILE__ == $0 + uri = ARGV.shift + + name_conv = DRbNamedIdConv.new + + DRb.install_id_conv(name_conv) + DRb.start_service(uri, Front.new) + puts DRb.uri + DRb.thread.join +end + diff --git a/sample/drb/namec.rb b/sample/drb/namec.rb new file mode 100644 index 0000000000..98b9d0e532 --- /dev/null +++ b/sample/drb/namec.rb @@ -0,0 +1,36 @@ +=begin + distributed Ruby --- NamedObject Sample Client + Copyright (c) 2000-2001 Masatoshi SEKI +=end + +require 'drb/drb' + +begin + there = ARGV.shift || raise +rescue + puts "usage: #{$0} <server_uri>" + exit 1 +end + +DRb.start_service() +ro = DRbObject.new(nil, there) + +seq = ro["seq"] +mutex = ro["mutex"] + +p seq +p mutex + +mutex.synchronize do + p seq.next_value + p seq.next_value +end + +puts '[return] to continue' +gets + +mutex.synchronize do + p seq.next_value + p seq.next_value +end + diff --git a/sample/drb/old_tuplespace.rb b/sample/drb/old_tuplespace.rb new file mode 100644 index 0000000000..8be1542c06 --- /dev/null +++ b/sample/drb/old_tuplespace.rb @@ -0,0 +1,212 @@ +#!/usr/local/bin/ruby +# TupleSpace +# Copyright (c) 1999-2000 Masatoshi SEKI +# You can redistribute it and/or modify it under the same terms as Ruby. + +class TupleSpace + class Template + def initialize(list) + @list = list + @check_idx = [] + @list.each_with_index do |x, i| + @check_idx.push i if x + end + @size = @list.size + end + + attr :size + alias length size + + def match(tuple) + return nil if tuple.size != self.size + @check_idx.each do |i| + unless @list[i] === tuple[i] + return false + end + end + return true + end + end + + def initialize + @que = {} + @waiting = {} + @que.taint # enable tainted comunication + @waiting.taint + self.taint + end + + def wakeup_waiting(tuple) + sz = tuple.length + return nil unless @waiting[sz] + + x = nil + i = -1 + found = false + @waiting[sz] = @waiting[sz].find_all { |x| + if x[0].match(tuple) + begin + x[1].wakeup + rescue ThreadError + end + false + else + true + end + } + end + + def put_waiting(template, thread) + sz = template.length + @waiting[sz] = [] unless @waiting[sz] + @waiting[sz].push([Template.new(template), thread]) + end + private :wakeup_waiting + private :put_waiting + + def get_que(template) + sz = template.length + return nil unless @que[sz] + + template = Template.new(template) + + x = nil + i = -1 + found = false + @que[sz].each_with_index do |x, i| + if template.match(x) + found = true + break + end + end + return nil unless found + + @que[sz].delete_at(i) + + return x + end + + def put_que(tuple) + sz = tuple.length + @que[sz] = [] unless @que[sz] + @que[sz].push tuple + end + private :get_que + private :put_que + + def out(*tuples) + tuples.each do |tuple| + Thread.critical = true + put_que(tuple) + wakeup_waiting(tuple) + Thread.critical = false + end + end + alias put out + alias write out + + def in(template, non_block=false) + begin + loop do + Thread.critical = true + tuple = get_que(template) + unless tuple + if non_block + raise ThreadError, "queue empty" + end + put_waiting(template, Thread.current) + Thread.stop + else + return tuple + end + end + ensure + Thread.critical = false + end + end + alias get in + alias take in + + def rd(template, non_block=false) + tuple = self.in(template, non_block) + out(tuple) + tuple + end + alias read rd + + def mv(dest, template, non_block=false) + tuple = self.in(template, non_block) + begin + dest.out(tuple) + rescue + self.out(tuple) + end + end + alias move mv +end + +if __FILE__ == $0 + ts = TupleSpace.new + clients = [] + servers = [] + + def server(ts, id) + Thread.start { + loop do + req = ts.in(['req', nil, nil]) + ac = req[1] + num = req[2] + sleep id + ts.out([ac, id, num, num * num]) + end + } + end + + def client(ts, n) + Thread.start { + ac = Object.new + tuples = (1..10).collect { |i| + ['req', ac, i * 10 + n] + } + ts.out(*tuples) + ts.out(tuples[0]) + puts "out: #{n}" + 11.times do |i| + ans = ts.in([ac, nil, nil, nil]) + puts "client(#{n}) server(#{ans[1]}) #{ans[2]} #{ans[3]}" + end + } + end + + def watcher(ts) + Thread.start { + loop do + begin + sleep 1 + p ts.rd(['req', nil, nil], true) + rescue ThreadError + puts "'req' not found." + end + end + } + end + + (0..3).each do |n| + servers.push(server(ts, n)) + end + + (1..6).each do |n| + clients.push(client(ts, n)) + end + + (1..3).each do + watcher(ts) + end + + clients.each do |t| + t.join + end +end + + + diff --git a/sample/drb/rinda_ts.rb b/sample/drb/rinda_ts.rb new file mode 100644 index 0000000000..6f2fae5c0f --- /dev/null +++ b/sample/drb/rinda_ts.rb @@ -0,0 +1,7 @@ +require 'drb/drb' +require 'rinda/tuplespace' + +uri = ARGV.shift +DRb.start_service(uri, Rinda::TupleSpace.new) +puts DRb.uri +DRb.thread.join diff --git a/sample/drb/rindac.rb b/sample/drb/rindac.rb new file mode 100644 index 0000000000..72be09deaf --- /dev/null +++ b/sample/drb/rindac.rb @@ -0,0 +1,17 @@ +require 'drb/drb' +require 'rinda/rinda' + +uri = ARGV.shift || raise("usage: #{$0} <server_uri>") + +DRb.start_service +ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, uri)) + +(1..10).each do |n| + ts.write(['sum', DRb.uri, n]) +end + +(1..10).each do |n| + ans = ts.take(['ans', DRb.uri, n, nil]) + p [ans[2], ans[3]] +end + diff --git a/sample/drb/rindas.rb b/sample/drb/rindas.rb new file mode 100644 index 0000000000..9fd9ada2d1 --- /dev/null +++ b/sample/drb/rindas.rb @@ -0,0 +1,18 @@ +require 'drb/drb' +require 'rinda/rinda' + +def do_it(v) + puts "do_it(#{v})" + v + v +end + +uri = ARGV.shift || raise("usage: #{$0} <server_uri>") + +DRb.start_service +ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, uri)) + +while true + r = ts.take(['sum', nil, nil]) + v = do_it(r[2]) + ts.write(['ans', r[1], r[2], v]) +end diff --git a/sample/drb/ring_echo.rb b/sample/drb/ring_echo.rb new file mode 100644 index 0000000000..c54628b54c --- /dev/null +++ b/sample/drb/ring_echo.rb @@ -0,0 +1,29 @@ +require 'drb/drb' +require 'drb/eq' +require 'rinda/ring' + +class RingEcho + include DRbUndumped + def initialize(name) + @name = name + end + + def echo(str) + "#{@name}: #{str}" + end +end + +DRb.start_service + +renewer = Rinda::SimpleRenewer.new + +finder = Rinda::RingFinger.new +ts = finder.lookup_ring_any +ts.read_all([:name, :RingEcho, nil, nil]).each do |tuple| + p tuple[2] + puts tuple[2].echo('Hello, World') rescue nil +end +ts.write([:name, :RingEcho, RingEcho.new(DRb.uri), ''], renewer) + +DRb.thread.join + diff --git a/sample/drb/ring_inspect.rb b/sample/drb/ring_inspect.rb new file mode 100644 index 0000000000..c096cd7034 --- /dev/null +++ b/sample/drb/ring_inspect.rb @@ -0,0 +1,30 @@ +require 'rinda/ring' +require 'drb/drb' + +class Inspector + def initialize + end + + def primary + Rinda::RingFinger.primary + end + + def list_place + Rinda::RingFinger.to_a + end + + def list(idx = -1) + if idx < 0 + ts = primary + else + ts = list_place[idx] + raise "RingNotFound" unless ts + end + ts.read_all([:name, nil, nil, nil]) + end +end + +def main + DRb.start_service + r = Inspector.new +end diff --git a/sample/drb/ring_place.rb b/sample/drb/ring_place.rb new file mode 100644 index 0000000000..11c6c2fe80 --- /dev/null +++ b/sample/drb/ring_place.rb @@ -0,0 +1,25 @@ +require 'drb/drb' +require 'rinda/ring' +require 'rinda/tuplespace' + +unless $DEBUG + # Run as a daemon... + exit!( 0 ) if fork + Process.setsid + exit!( 0 ) if fork +end + +DRb.start_service(ARGV.shift) + +ts = Rinda::TupleSpace.new +place = Rinda::RingServer.new(ts) + +if $DEBUG + puts DRb.uri + DRb.thread.join +else + STDIN.reopen(IO::NULL) + STDOUT.reopen(IO::NULL, 'w') + STDERR.reopen(IO::NULL, 'w') + DRb.thread.join +end diff --git a/sample/drb/simpletuple.rb b/sample/drb/simpletuple.rb new file mode 100644 index 0000000000..4bb4b1cff9 --- /dev/null +++ b/sample/drb/simpletuple.rb @@ -0,0 +1,89 @@ +#!/usr/local/bin/ruby +# SimpleTupleSpace +# Copyright (c) 1999-2000 Masatoshi SEKI +# You can redistribute it and/or modify it under the same terms as Ruby. + +class SimpleTupleSpace + def initialize + @hash = {} + @waiting = {} + @hash.taint + @waiting.taint + self.taint + end + + def out(key, obj) + Thread.critical = true + @hash[key] ||= [] + @waiting[key] ||= [] + @hash[key].push obj + begin + t = @waiting[key].shift + @waiting.delete(key) if @waiting[key].length == 0 + t.wakeup if t + rescue ThreadError + retry + ensure + Thread.critical = false + end + end + + def in(key) + Thread.critical = true + @hash[key] ||= [] + @waiting[key] ||= [] + begin + loop do + if @hash[key].length == 0 + @waiting[key].push Thread.current + Thread.stop + else + return @hash[key].shift + end + end + ensure + @hash.delete(key) if @hash[key].length == 0 + Thread.critical = false + end + end +end + +if __FILE__ == $0 + ts = SimpleTupleSpace.new + clients = [] + servers = [] + + def server(ts) + Thread.start { + loop do + req = ts.in('req') + ac = req[0] + num = req[1] + ts.out(ac, num * num) + end + } + end + + def client(ts, n) + Thread.start { + ac = Object.new + ts.out('req', [ac, n]) + ans = ts.in(ac) + puts "#{n}: #{ans}" + } + end + + 3.times do + servers.push(server(ts)) + end + + (1..6).each do |n| + clients.push(client(ts, n)) + end + + clients.each do |t| + t.join + end +end + + diff --git a/sample/drb/speedc.rb b/sample/drb/speedc.rb new file mode 100644 index 0000000000..64b8a65021 --- /dev/null +++ b/sample/drb/speedc.rb @@ -0,0 +1,21 @@ +#!/usr/local/bin/ruby + +uri = ARGV.shift || raise("usage: #{$0} URI") +N = (ARGV.shift || 100).to_i + +case uri +when /^tcpromp:/, /^unixromp:/ + require 'romp' + + client = ROMP::Client.new(uri, false) + foo = client.resolve("foo") +when /^druby:/ + require 'drb/drb' + + DRb.start_service + foo = DRbObject.new(nil, uri) +end + +N.times do |n| + foo.foo(n) +end diff --git a/sample/drb/speeds.rb b/sample/drb/speeds.rb new file mode 100644 index 0000000000..7984059423 --- /dev/null +++ b/sample/drb/speeds.rb @@ -0,0 +1,31 @@ +class Foo + attr_reader :i + def initialize + @i = 0 + end + + def foo(i) + @i = i + i + i + end +end + +# server = ROMP::Server.new('tcpromp://localhost:4242', nil, true) + +uri = ARGV.shift || raise("usage: #{$0} URI") +foo = Foo.new + +case uri +when /^tcpromp:/, /^unixromp:/ + require 'romp' + + server = ROMP::Server.new(uri, nil, true) + server.bind(foo, "foo") + +when /^druby:/ + require 'drb/drb' + + DRb.start_service(uri, Foo.new) +end + +DRb.thread.join diff --git a/sample/dualstack-fetch.rb b/sample/dualstack-fetch.rb new file mode 100644 index 0000000000..18d33cc45a --- /dev/null +++ b/sample/dualstack-fetch.rb @@ -0,0 +1,48 @@ +# simple webpage fetcher + +# The code demonstrates how a multi-protocol client should be written. +# TCPSocket is using getaddrinfo() internally, so there should be no problem. + +require "socket" + +if ARGV.size != 1 + STDERR.print "requires URL\n" + exit +end + +url = ARGV[0] +if url !~ /^http:\/\/([^\/]+)(\/.*)$/ + STDERR.print "only http with full hostname is supported\n" + exit +end + +# split URL into host, port and path +hostport = $1 +path = $2 +if (hostport =~ /^(.*):([0-9]+)$/) + host = $1 + port = $2 +else + host = hostport + port = 80 +end +if host =~ /^\[(.*)\]$/ + host = $1 +end + +#STDERR.print "url=<#{ARGV[0]}>\n" +#STDERR.print "host=<#{host}>\n" +#STDERR.print "port=<#{port}>\n" +#STDERR.print "path=<#{path}>\n" + +STDERR.print "conntecting to #{host} port #{port}\n" +c = TCPSocket.new(host, port) +dest = Socket.getnameinfo(c.getpeername, + Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV) +STDERR.print "conntected to #{dest[0]} port #{dest[1]}\n" +c.print "GET #{path} HTTP/1.0\n" +c.print "Host: #{host}\n" +c.print "\n" +while c.gets + print +end diff --git a/sample/dualstack-httpd.rb b/sample/dualstack-httpd.rb new file mode 100644 index 0000000000..ab02e17aea --- /dev/null +++ b/sample/dualstack-httpd.rb @@ -0,0 +1,54 @@ +# simple httpd + +# The code demonstrates how a multi-protocol daemon should be written. + +require "socket" + +port = 8888 +res = Socket.getaddrinfo(nil, port, nil, Socket::SOCK_STREAM, nil, Socket::AI_PASSIVE) +sockpool = [] +names = [] +threads = [] + +res.each do |i| + s = TCPServer.new(i[3], i[1]) + n = Socket.getnameinfo(s.getsockname, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV).join(" port ") + sockpool.push s + names.push n +end + +(0 .. sockpool.size - 1).each do |i| + mysock = sockpool[i] + myname = names[i] + STDERR.print "socket #{mysock} started, address #{myname}\n" + threads[i] = Thread.start do # Thread.start cannot be used here! + ls = mysock # copy to dynamic variable + t = Thread.current + STDERR.print "socket #{myname} listener started, pid #{$$} thread #{t}\n" + while true + as = ls.accept + Thread.start do + STDERR.print "socket #{myname} accepted, thread ", Thread.current, "\n" + s = as # copy to dynamic variable + str = '' + while line = s.gets + break if line == "\r\n" or line == "\n" + str << line + end + STDERR.print "socket #{myname} got string\n" + s.write("HTTP/1.0 200 OK\n") + s.write("Content-type: text/plain\n\n") + s.write("this is test: my name is #{myname}, you sent:\n") + s.write("---start\n") + s.write(str) + s.write("---end\n") + s.close + STDERR.print "socket #{myname} processed, thread ", Thread.current, " terminating\n" + end + end + end +end + +for t in threads + t.join +end diff --git a/sample/eval.rb b/sample/eval.rb index 216bf8ca39..ed4b7c3de5 100644 --- a/sample/eval.rb +++ b/sample/eval.rb @@ -1,18 +1,18 @@ line = '' -indent=0 -$stdout.sync = TRUE +indent = 0 +$stdout.sync = true print "ruby> " -while TRUE +loop do l = gets - unless l - break if line == '' + if l.nil? + break if line.empty? else - line = line + l + line += l if l =~ /,\s*$/ print "ruby| " next end - if l =~ /^\s*(class|module|def|if|case|while|for|begin)\b[^_]/ + if l =~ /^\s*(class|module|def|if|unless|case|while|until|for|begin)\b[^_]/ indent += 1 end if l =~ /^\s*end\b[^_]/ @@ -31,11 +31,10 @@ while TRUE end begin print eval(line).inspect, "\n" - rescue - $! = 'exception raised' unless $! - print "ERR: ", $!, "\n" + rescue ScriptError, StandardError + printf "ERR: %s\n", $! || 'exception raised' end - break if not l + break if l.nil? line = '' print "ruby> " end diff --git a/sample/export.rb b/sample/export.rb index 949e5b10bf..2ab2e93f2e 100644 --- a/sample/export.rb +++ b/sample/export.rb @@ -30,7 +30,7 @@ f.printf "%s\n", Foo f.quux -class Bar<Foo +class Bar < Foo def quux super baz() diff --git a/sample/exyacc.rb b/sample/exyacc.rb index dbe0dee710..9a9435a0dc 100644 --- a/sample/exyacc.rb +++ b/sample/exyacc.rb @@ -1,22 +1,20 @@ #! /usr/local/bin/ruby -Kn # usage: exyacc.rb [yaccfiles] -# this is coverted from exyacc.pl in the camel book +# this is covered from exyacc.pl in the camel book -$/ = nil - -while gets() - sbeg = $_.index("\n%%") + 1 - send = $_.rindex("\n%%") + 1 - $_ = $_[sbeg, send-sbeg] - sub!(/.*\n/, "") - gsub!(/'{'/, "'\001'") - gsub!(/'}'/, "'\002'") - gsub!('\*/', "\003\003") - gsub!("/\\*[^\003]*\003\003", '') - while gsub!(/\{[^{}]*}/, ''); end - gsub!(/'\001'/, "'{'") - gsub!(/'\002'/, "'}'") - while gsub!(/^[ \t]*\n(\s)/, '\1'); end - gsub!(/([:|])[ \t\n]+(\w)/, '\1 \2') - print $_ +ARGF.each(nil) do |source| + sbeg = source.index("\n%%") + 1 + send = source.rindex("\n%%") + 1 + grammar = source[sbeg, send-sbeg] + grammar.sub!(/.*\n/, "") + grammar.gsub!(/'\{'/, "'\001'") + grammar.gsub!(/'\}'/, "'\002'") + grammar.gsub!(%r{\*/}, "\003\003") + grammar.gsub!(%r{/\*[^\003]*\003\003}, '') + while grammar.gsub!(/\{[^{}]*\}/, ''); end + grammar.gsub!(/'\001'/, "'{'") + grammar.gsub!(/'\002'/, "'}'") + while grammar.gsub!(/^[ \t]*\n(\s)/, '\1'); end + grammar.gsub!(/([:|])[ \t\n]+(\w)/, '\1 \2') + print grammar end diff --git a/sample/fact.rb b/sample/fact.rb index 49678bc9d0..d8147a40f1 100644 --- a/sample/fact.rb +++ b/sample/fact.rb @@ -1,8 +1,9 @@ def fact(n) - if n == 0 - 1 - else - n * fact(n-1) + return 1 if n == 0 + f = 1 + n.downto(1) do |i| + f *= i end + return f end print fact(ARGV[0].to_i), "\n" diff --git a/sample/fib.awk b/sample/fib.awk index 7ebe8930f5..9589f97965 100644 --- a/sample/fib.awk +++ b/sample/fib.awk @@ -1,5 +1,5 @@ - function fib(n) { - if ( n<2 ) return n; else return fib(n-2) + fib(n-1) - } +function fib(n) { + if ( n<2 ) return n; else return fib(n-2) + fib(n-1) +} - BEGIN { print fib(20); } +BEGIN { print fib(20); } diff --git a/sample/fib.pl b/sample/fib.pl index c5593764aa..4c35eaae31 100644 --- a/sample/fib.pl +++ b/sample/fib.pl @@ -1,10 +1,11 @@ - sub fib { - local($n)=@_; - if( $n<2 ){ - return $n; - } { - return &fib($n-2)+&fib($n-1) - } - } +sub fib { + my($n)=@_; + if ($n<2) { + return $n; + } + else { + return fib($n-2)+fib($n-1); + } +} - print &fib(20), "\n"; +print fib(20), "\n"; diff --git a/sample/fib.py b/sample/fib.py new file mode 100644 index 0000000000..8318021d24 --- /dev/null +++ b/sample/fib.py @@ -0,0 +1,10 @@ +# calculate Fibonacci(20) +# for benchmark +def fib(n): + if n<2: + return n + else: + return fib(n-2)+fib(n-1) + +print fib(20) + diff --git a/sample/fib.scm b/sample/fib.scm index 8eba75bb9e..d2dc770282 100644 --- a/sample/fib.scm +++ b/sample/fib.scm @@ -1,6 +1,8 @@ (define (fib n) (if (< n 2) - n - (+ (fib (- n 2)) (fib (- n 1))))) + n + (+ (fib (- n 2)) (fib (- n 1))))) -(fib 20) +(display (fib 20)) +(newline) +(quit) diff --git a/sample/freq.rb b/sample/freq.rb index d951591735..1b2194c69a 100644 --- a/sample/freq.rb +++ b/sample/freq.rb @@ -1,13 +1,12 @@ # word occurrence listing -# usege: ruby freq.rb file.. -freq = {} -while gets - while sub!(/\w+/, '') - word = $& - freq[word] +=1 +# usage: ruby freq.rb file.. +freq = Hash.new(0) +while line = gets() + line.scan(/\w+/) do |word| + freq[word] += 1 end end -for word in freq.keys.sort - printf("%s -- %d\n", word, freq[word]) +for word in freq.keys.sort! + print word, " -- ", freq[word], "\n" end diff --git a/sample/from.rb b/sample/from.rb index d39bb70084..db1299c869 100755..100644 --- a/sample/from.rb +++ b/sample/from.rb @@ -1,87 +1,113 @@ #! /usr/local/bin/ruby -require "parsedate" +require "time" require "kconv" -require "mailread" - -include ParseDate -include Kconv class String - - public :kconv - - def kconv(code = Kconv::EUC) - Kconv.kconv(self, code, Kconv::AUTO) - end - def kjust(len) - len += 1 - me = self[0, len].ljust(len) - if me =~ /.$/ and $&.size == 2 - me[-2, 2] = ' ' + res = '' + rlen = 0 + self.each_char do |char| + delta = char.bytesize > 1 ? 2 : 1 + break if rlen + delta > len + rlen += delta + res += char end - me.chop! + res += ' ' * (len - rlen) if rlen < len + res end - end -if ARGV[0] == '-w' - wait = TRUE - ARGV.shift +def fromout(date, from, subj) + return 0 if !date + y, m, d = Time.parse(date).to_a.reverse[4, 3] if date + y ||= 0; m ||= 0; d ||= 0 + from ||= "sombody@somewhere" + from.delete!("\r\n") + from = from.kconv(Encoding.default_external).kjust(28) + subj ||= "(nil)" + subj.delete!("\r\n") + subj = subj.kconv(Encoding.default_external).kjust(40) + printf "%02d/%02d/%02d [%s] %s\n", y%100, m, d, from, subj + return 1 end -if ARGV.length == 0 - user = ENV['USER'] -else - user = ARGV[0] -end +def get_mailfile(user) + file = user + unless user + file = ENV['MAIL'] + user = ENV['USER'] || ENV['USERNAME'] || ENV['LOGNAME'] + end -[ENV['SPOOLDIR'], '/usr/spool', '/var/spool', '/usr', '/var'].each do |m| - break if File.exist? ARGV[0] = "#{m}/mail/#{user}" + if file == nil or !File.exist?(file) + [ENV['SPOOLDIR'], '/usr/spool', '/var/spool', '/usr', '/var'].each do |m| + path = "#{m}/mail/#{user}" + if File.exist?(path) + file = path + break + end + end + end + file end -$outcount = 0; -def fromout(date, from, subj) - return if !date - y = m = d = 0 - y, m, d = parsedate(date) if date - if from - from.gsub! /\n/, "" - else - from = "sombody@somewhere" +def from_main + if ARGV[0] == '-w' + wait = true + ARGV.shift end - if subj - subj.gsub! /\n/, "" - else - subj = "(nil)" - end - if ENV['LANG'] =~ /sjis/i - lang = Kconv::SJIS - else - lang = Kconv::EUC + file = get_mailfile(ARGV[0]) + + outcount = 0 + if File.exist?(file) + atime = File.atime(file) + mtime = File.mtime(file) + open(file, "r") do |f| + until f.eof? + header = {} + f.each_line do |line| + next if /^From / =~ line # skip From-line + break if /^$/ =~ line # end of header + + if /^(?<attr>\S+?):\s*(?<value>.*)/ =~ line + attr.capitalize! + header[attr] = value + elsif attr + header[attr] += "\n" + line.lstrip + end + end + + f.each_line do |line| + break if /^From / =~ line + end + outcount += fromout(header['Date'], header['From'], header['Subject']) + end + end + File.utime(atime, mtime, file) end - from = from.kconv(lang).kjust(28) - subj = subj.kconv(lang).kjust(40) - printf "%02d/%02d/%02d [%s] %s\n",y,m,d,from,subj - $outcount += 1 -end -for file in ARGV - next if !File.exist?(file) - f = open(file, "r") - while !f.eof? - mail = Mail.new(f) - fromout mail.header['Date'], mail.header['From'], mail.header['Subject'] + if outcount == 0 + print "You have no mail.\n" + sleep 2 if wait + elsif wait + system "stty cbreak -echo" + $stdin.getc + system "stty cooked echo" end - f.close end -if $outcount == 0 - print "You have no mail.\n" - sleep 2 if wait -elsif wait - system "stty cbreak -echo" - getc() - system "stty cooked echo" +if __FILE__ == $0 + from_main end + +__END__ + +=begin + += from.rb + +== USAGE + +ruby from.rb [-w] [username_or_filename] + +=end diff --git a/sample/fullpath.rb b/sample/fullpath.rb index ce268e20b9..112ca58081 100644 --- a/sample/fullpath.rb +++ b/sample/fullpath.rb @@ -3,21 +3,21 @@ if ARGV[0] =~ /-p/ ARGV.shift - path = ARGV.shift + path = ARGV.shift end if path == nil path = "" -elsif path !~ /\/$/ +elsif path !~ %r|/$| path += "/" end -while gets() - if /:$/ - path = $_.chop.chop + "/" - elsif /^total/ || /^d/ - elsif /^(.*\d )(.+)$/ +while line = gets() + case line + when /:$/ + path = line.chop.chop + "/" + when /^total/, /^d/ + when /^(.*\d )(.+)$/ print($1, path, $2, "\n") end end - diff --git a/sample/getopts.test b/sample/getopts.test deleted file mode 100755 index 2866bccea8..0000000000 --- a/sample/getopts.test +++ /dev/null @@ -1,36 +0,0 @@ -#! /usr/local/bin/ruby - -load("parsearg.rb") - -def usage() - printf "Usage:\n" - printf "%s -d [-x x] [-y y] [--geometry geom] [--version] [string ...]\n", $0 -end - -$USAGE = 'usage' -parseArgs(0, "d&(x|y)", "dfg", "x:", "y:", "geometry:800x600", "version") -if ($OPT_d) - if $OPT_version - printf "version 1.0\n" - end - if ($OPT_x) - printf("x = %d\n", $OPT_x.to_i) - end - if ($OPT_y) - printf("y = %d\n", $OPT_y.to_i) - end - if ($OPT_geometry) - printf("geometry = %s\n", $OPT_geometry) - end - if $OPT_f - printf "f = TRUE\n" - end - if $OPT_g - printf "g = TRUE\n" - end -end - -while (ARGV.length != 0) - print "other = ", ARGV[0], "\n" - ARGV.shift -end diff --git a/sample/io.rb b/sample/io.rb deleted file mode 100644 index 0b38d2112d..0000000000 --- a/sample/io.rb +++ /dev/null @@ -1,44 +0,0 @@ -# IO test -# usage: ruby io.rb file.. - -home = ENV["HOME"] -home.sub("m", "&&") -print(home, "\n") -print(home.reverse, "\n") - -if File.s("io.rb") - print(File.s("io.rb"), ": io.rb\n") -end - -$/="f\n" -for i in "abc\n\ndef\nghi\n" - print("tt: ", i) -end - -printf("%s:(%d)%s\n", $0, ARGV.length, ARGV[0]) -passwd = open(ARGV[0], "r") -#printf("%s", passwd.find{i|i =~ /\*/}) - -n = 1 -for i in passwd #.grep(/^\*/) - printf("%6d: %s", n, i) - n = n + 1; -end - -fp = open("|-", "r") - -if fp == nil - for i in 1..5 - print(i, "\n") - end -else - for line in fp - print(line) - end -end - -def printUsage() - if $USAGE - apply($USAGE); - end -end diff --git a/sample/iseq_loader.rb b/sample/iseq_loader.rb new file mode 100644 index 0000000000..bb2d92ea77 --- /dev/null +++ b/sample/iseq_loader.rb @@ -0,0 +1,243 @@ +# +# iseq_loader.rb - sample of compiler/loader for binary compiled file +# +# Usage as a compiler: ruby iseq_loader.rb [file or directory] ... +# +# It compiles and stores specified files. +# If directories are specified, then compiles and stores all *.rb files. +# (using Dir.glob) +# +# TODO: add remove option +# TODO: add verify option +# +# Usage as a loader: simply require this file with the following setting. +# +# Setting with environment variables. +# +# * RUBY_ISEQ_LOADER_STORAGE to select storage type +# * dbm: use dbm +# * fs: [default] use file system. locate a compiled binary files in same +# directory of scripts like Rubinius. foo.rb.yarb will be created for foo.rb. +# * fs2: use file system. locate compiled file in specified directory. +# * nothing: do nothing. +# +# * RUBY_ISEQ_LOADER_STORAGE_DIR to select directory +# * default: ~/.ruby_binaries/ +# +# * RUBY_ISEQ_LOADER_STORAGE_COMPILE_IF_NOT_COMPILED +# * true: store compiled file if compiled data is not available. +# * false: [default] do nothing if there is no compiled iseq data. + +class RubyVM::InstructionSequence + $ISEQ_LOADER_LOADED = 0 + $ISEQ_LOADER_COMPILED = 0 + $ISEQ_LOADER_IGNORED = 0 + LAUNCHED_TIME = Time.now + COMPILE_FILE_ENABLE = false || true + COMPILE_VERBOSE = $VERBOSE || false # || true + COMPILE_DEBUG = ENV['RUBY_ISEQ_LOADER_DEBUG'] + COMPILE_IF_NOT_COMPILED = ENV['RUBY_ISEQ_LOADER_STORAGE_COMPILE_IF_NOT_COMPILED'] == 'true' + + at_exit{ + STDERR.puts "[ISEQ_LOADER] #{Process.pid} time: #{Time.now - LAUNCHED_TIME}, " + + "loaded: #{$ISEQ_LOADER_LOADED}, " + + "compied: #{$ISEQ_LOADER_COMPILED}, " + + "ignored: #{$ISEQ_LOADER_IGNORED}" + } if COMPILE_VERBOSE + + unless cf_dir = ENV['RUBY_ISEQ_LOADER_STORAGE_DIR'] + cf_dir = File.expand_path("~/.ruby_binaries") + unless File.exist?(cf_dir) + Dir.mkdir(cf_dir) + end + end + CF_PREFIX = "#{cf_dir}/cb." + + class NullStorage + def load_iseq fname; end + def compile_and_save_isq fname; end + def unlink_compiled_iseq; end + end + + class BasicStorage + def initialize + require 'digest/sha1' + end + + def load_iseq fname + iseq_key = iseq_key_name(fname) + if compiled_iseq_exist?(fname, iseq_key) && compiled_iseq_is_younger?(fname, iseq_key) + $ISEQ_LOADER_LOADED += 1 + STDERR.puts "[ISEQ_LOADER] #{Process.pid} load #{fname} from #{iseq_key}" if COMPILE_DEBUG + binary = read_compiled_iseq(fname, iseq_key) + iseq = RubyVM::InstructionSequence.load_from_binary(binary) + # p [extra_data(iseq.path), RubyVM::InstructionSequence.load_from_binary_extra_data(binary)] + # raise unless extra_data(iseq.path) == RubyVM::InstructionSequence.load_from_binary_extra_data(binary) + iseq + elsif COMPILE_IF_NOT_COMPILED + compile_and_save_iseq(fname, iseq_key) + else + $ISEQ_LOADER_IGNORED += 1 + # p fname + nil + end + end + + def extra_data fname + "SHA-1:#{::Digest::SHA1.file(fname).digest}" + end + + def compile_and_save_iseq fname, iseq_key = iseq_key_name(fname) + $ISEQ_LOADER_COMPILED += 1 + STDERR.puts "[RUBY_COMPILED_FILE] compile #{fname}" if COMPILE_DEBUG + iseq = RubyVM::InstructionSequence.compile_file(fname) + + binary = iseq.to_binary(extra_data(fname)) + write_compiled_iseq(fname, iseq_key, binary) + iseq + end + + # def unlink_compiled_iseq; nil; end # should implement at sub classes + + private + + def iseq_key_name fname + fname + end + + # should implement at sub classes + # def compiled_iseq_younger? fname, iseq_key; end + # def compiled_iseq_exist? fname, iseq_key; end + # def read_compiled_file fname, iseq_key; end + # def write_compiled_file fname, iseq_key, binary; end + end + + class FSStorage < BasicStorage + def initialize + super + require 'fileutils' + @dir = CF_PREFIX + "files" + unless File.directory?(@dir) + FileUtils.mkdir_p(@dir) + end + end + + def unlink_compiled_iseq + File.unlink(compile_file_path) + end + + private + + def iseq_key_name fname + "#{fname}.yarb" # same directory + end + + def compiled_iseq_exist? fname, iseq_key + File.exist?(iseq_key) + end + + def compiled_iseq_is_younger? fname, iseq_key + File.mtime(iseq_key) >= File.mtime(fname) + end + + def read_compiled_iseq fname, iseq_key + open(iseq_key, 'rb'){|f| f.read} + end + + def write_compiled_iseq fname, iseq_key, binary + open(iseq_key, 'wb'){|f| f.write(binary)} + end + end + + class FS2Storage < FSStorage + def iseq_key_name fname + @dir + fname.gsub(/[^A-Za-z0-9\._-]/){|c| '%02x' % c.ord} # special directory + end + end + + class DBMStorage < BasicStorage + def initialize + require 'dbm' + @db = DBM.open(CF_PREFIX+'db') + end + + def unlink_compiled_iseq + @db.delete fname + end + + private + + def date_key_name fname + "date.#{fname}" + end + + def iseq_key_name fname + "body.#{fname}" + end + + def compiled_iseq_exist? fname, iseq_key + @db.has_key? iseq_key + end + + def compiled_iseq_is_younger? fname, iseq_key + date_key = date_key_name(fname) + if @db.has_key? date_key + @db[date_key].to_i >= File.mtime(fname).to_i + end + end + + def read_compiled_iseq fname, iseq_key + @db[iseq_key] + end + + def write_compiled_iseq fname, iseq_key, binary + date_key = date_key_name(fname) + @db[iseq_key] = binary + @db[date_key] = Time.now.to_i + end + end + + STORAGE = case ENV['RUBY_ISEQ_LOADER_STORAGE'] + when 'dbm' + DBMStorage.new + when 'fs' + FSStorage.new + when 'fs2' + FS2Storage.new + when 'null' + NullStorage.new + else + FSStorage.new + end + + STDERR.puts "[ISEQ_LOADER] use #{STORAGE.class} " if COMPILE_VERBOSE + + def self.load_iseq fname + STORAGE.load_iseq(fname) + end + + def self.compile_and_save_iseq fname + STORAGE.compile_and_save_iseq fname + end + + def self.unlink_compiled_iseq fname + STORAGE.unlink_compiled_iseq fname + end +end + +if __FILE__ == $0 + ARGV.each{|path| + if File.directory?(path) + pattern = File.join(path, '**/*.rb') + Dir.glob(pattern){|file| + begin + RubyVM::InstructionSequence.compile_and_save_iseq(file) + rescue SyntaxError => e + STDERR.puts e + end + } + else + RubyVM::InstructionSequence.compile_and_save_iseq(path) + end + } +end diff --git a/sample/less.rb b/sample/less.rb index 8be359108f..8be359108f 100755..100644 --- a/sample/less.rb +++ b/sample/less.rb diff --git a/sample/list.rb b/sample/list.rb index 76035e67d6..b4d1d653e4 100644 --- a/sample/list.rb +++ b/sample/list.rb @@ -1,10 +1,11 @@ # Linked list example class MyElem - # ¥ª¥Ö¥¸¥§¥¯¥ÈÀ¸À®»þ¤Ë¼«Æ°Åª¤Ë¸Æ¤Ð¤ì¤ë¥á¥½¥Ã¥É + # object initializer called from Class#new def initialize(item) - # @ÊÑ¿ô¤Ï¥¤¥ó¥¹¥¿¥ó¥¹ÊÑ¿ô(Àë¸À¤ÏÍפé¤Ê¤¤) + # @variables are instance variable, no declaration needed @data = item @succ = nil + @head = nil end def data @@ -15,7 +16,7 @@ class MyElem @succ end - # ¡Öobj.data = val¡×¤È¤·¤¿¤È¤¤Ë°ÅÌۤ˸ƤФì¤ë¥á¥½¥Ã¥É + # the method invoked by ``obj.data = val'' def succ=(new) @succ = new end @@ -40,12 +41,12 @@ class MyList end end - # ¥ª¥Ö¥¸¥§¥¯¥È¤òʸ»úÎó¤ËÊÑ´¹¤¹¤ë¥á¥½¥Ã¥É - # ¤³¤ì¤òºÆÄêµÁ¤¹¤ë¤Èprint¤Ç¤Îɽ¸½¤¬ÊѤï¤ë + # the method to convert object into string. + # redefining this will affect print. def to_s str = "<MyList:\n"; for elt in self - # ¡Östr = str + elt.data.to_s + "\n"¡×¤Î¾Êά·Á + # short form of ``str = str + elt.data.to_s + "\n"'' str += elt.data.to_s + "\n" end str += ">" @@ -64,7 +65,7 @@ class Point end end -# Âç°èÊÑ¿ô¤Ï`$'¤Ç»Ï¤Þ¤ë¡¥ +# global variable name starts with `$'. $list1 = MyList.new $list1.add_to_list(10) $list1.add_to_list(20) @@ -75,6 +76,6 @@ $list2.add_to_list(20) $list2.add_to_list(Point.new(4, 5)) $list2.add_to_list($list1) -# Û£Ëæ¤Ç¤Ê¤¤¸Â¤ê¥á¥½¥Ã¥É¸Æ¤Ó½Ð¤·¤Î³ç¸Ì¤Ï¾Êά¤Ç¤¤ë +# parenthesises around method arguments can be omitted unless ambiguous. print "list1:\n", $list1, "\n" print "list2:\n", $list2, "\n" diff --git a/sample/list2.rb b/sample/list2.rb index 914cb8996e..1d71affc1b 100644 --- a/sample/list2.rb +++ b/sample/list2.rb @@ -9,7 +9,7 @@ class Point sprintf("%d@%d", @x, @y) end end - + list1 = [10, 20, Point.new(2, 3), Point.new(4, 5)] list2 = [20, Point.new(4, 5), list1] print("list1:\n", list1.join("\n"), "\n") diff --git a/sample/list3.rb b/sample/list3.rb index 1d756fdff0..1d9f04b710 100644 --- a/sample/list3.rb +++ b/sample/list3.rb @@ -11,7 +11,7 @@ class Point sprintf("%d@%d", @x, @y) end end - + list1 = [10, 20, Point.new(2, 3), Point.new(4, 5)] list2 = [20, Point.new(4, 5), list1] print("list1: ", list1.inspect, "\n") diff --git a/sample/logger/app.rb b/sample/logger/app.rb new file mode 100644 index 0000000000..97b62bca30 --- /dev/null +++ b/sample/logger/app.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby + +require 'logger' + +class MyApp < Logger::Application + def initialize(a, b, c) + super('MyApp') + + # Set logDevice here. + logfile = 'app.log' + self.log = logfile + self.level = INFO + + # Initialize your application... + @a = a + @b = b + @c = c + end + + def run + @log.info { 'Started.' } + + @log.info { "This block isn't evaled because 'debug' is not severe here." } + @log.debug { "Result = " << foo(0) } + @log.info { "So nothing is dumped." } + + @log.info { "This block is evaled because 'info' is enough severe here." } + @log.info { "Result = " << foo(0) } + @log.info { "Above causes exception, so not reached here." } + + @log.info { 'Finished.' } + end + +private + + def foo(var) + 1 / var + end +end + +status = MyApp.new(1, 2, 3).start + +if status != 0 + puts 'Some error(s) occurred.' + puts 'See "app.log".' +end diff --git a/sample/logger/log.rb b/sample/logger/log.rb new file mode 100644 index 0000000000..aab80e462e --- /dev/null +++ b/sample/logger/log.rb @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby + +require 'logger' + +log = Logger.new(STDERR) + +def do_log(log) + log.debug('do_log1') { "debug" } + log.info('do_log2') { "info" } + log.warn('do_log3') { "warn" } + log.error('do_log4') { "error" } + log.fatal('do_log6') { "fatal" } + log.unknown('do_log7') { "unknown" } +end + +log.level = Logger::DEBUG # Default. +do_log(log) + +puts "Set severity threshold 'WARN'." + +log.level = Logger::WARN +do_log(log) + +puts "Change datetime format. Thanks to Daniel Berger." + +log.datetime_format = "%d-%b-%Y@%H:%M:%S" +do_log(log) diff --git a/sample/logger/shifting.rb b/sample/logger/shifting.rb new file mode 100644 index 0000000000..bd8852a4ae --- /dev/null +++ b/sample/logger/shifting.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby + +require 'logger' + +logfile = 'shifting.log' +# Max 3 age ... logShifting.log, logShifting.log.0, and logShifting.log.1 +shift_age = 3 +# Shift log file about for each 1024 bytes. +shift_size = 1024 + +log = Logger.new(logfile, shift_age, shift_size) + +def do_log(log) + log.debug('do_log1') { 'd' * rand(100) } + log.info('do_log2') { 'i' * rand(100) } + log.warn('do_log3') { 'w' * rand(100) } + log.error('do_log4') { 'e' * rand(100) } + log.fatal('do_log5') { 'f' * rand(100) } + log.unknown('do_log6') { 'u' * rand(100) } +end + +(1..10).each do + do_log(log) +end + +puts 'See shifting.log and shifting.log.[01].' diff --git a/sample/mine.rb b/sample/mine.rb new file mode 100755 index 0000000000..a841d1a60a --- /dev/null +++ b/sample/mine.rb @@ -0,0 +1,176 @@ +#! /usr/bin/ruby -Ku +# -*- coding: utf-8 -*- + +class Board + def clr + print "\e[2J" + end + def pos(x,y) + printf "\e[%d;%dH", y+1, x*2+1 + end + def colorstr(id,s) + printf "\e[%dm%s\e[0m", id, s + end + def put(x, y, col, str) + pos(x,y); colorstr(43,str) + pos(0,@hi); print "残り:",@mc,"/",@total," " + pos(x,y) + end + private :clr, :pos, :colorstr, :put + CHR=["・","1","ï¼’","3","ï¼”","5","ï¼–","ï¼—","8","★","â—","@@"] + COL=[46,43,45] # default,opened,over + def initialize(h,w,m) + # ゲーム盤ã®ç”Ÿæˆ(h:縦,w:横,m:çˆ†å¼¾ã®æ•°) + @hi=h; @wi=w; @m=m + reset + end + def reset + # ゲーム盤を(å†)åˆæœŸåŒ–ã™ã‚‹ + srand() + @cx=0; @cy=0; @mc=@m + @over=false + @data=Array.new(@hi*@wi) + @state=Array.new(@hi*@wi) + @total=@hi*@wi + @total.times {|i| @data[i]=0} + @m.times do + loop do + j=rand(@total-1) + if @data[j] == 0 then + @data[j]=1 + break + end + end + end + clr; pos(0,0) + @hi.times{|y| pos(0,y); colorstr(COL[0],CHR[0]*@wi)} + pos(@cx,@cy) + end + def mark + # ç¾åœ¨ã®ã‚«ãƒ¼ã‚½ãƒ«ä½ç½®ã«ãƒžãƒ¼ã‚¯ã‚’ã¤ã‘ã‚‹ + if @state[@wi*@cy+@cx] != nil then return end + @state[@wi*@cy+@cx] = "MARK" + @mc=@mc-1; + @total=@total-1; + put(@cx, @cy, COL[1], CHR[9]) + end + def open(x=@cx,y=@cy) + # ç¾åœ¨ã®ã‚«ãƒ¼ã‚½ãƒ«ä½ç½®ã‚’オープンã«ã™ã‚‹ + # 爆弾ãŒã‚れã°ã‚²ãƒ¼ãƒ オーãƒãƒ¼ + if @state[@wi*y+x] =="OPEN" then return 0 end + if @state[@wi*y+x] == nil then @total=@total-1 end + if @state[@wi*y+x] =="MARK" then @mc=@mc+1 end + @state[@wi*y+x]="OPEN" + if fetch(x,y) == 1 then @over = 1; return end + c = count(x,y) + put(x, y, COL[1], CHR[c]) + return 0 if c != 0 + if x > 0 && y > 0 then open(x-1,y-1) end + if y > 0 then open(x, y-1) end + if x < @wi-1 && y > 0 then open(x+1,y-1) end + if x > 0 then open(x-1,y) end + if x < @wi-1 then open(x+1,y) end + if x > 0 && y < @hi-1 then open(x-1,y+1) end + if y < @hi -1 then open(x,y+1) end + if x < @wi-1 && y < @hi-1 then open(x+1,y+1) end + pos(@cx,@cy) + end + def fetch(x,y) + # (x,y)ã®ä½ç½®ã®çˆ†å¼¾ã®æ•°(0 or 1)を返㙠+ if x < 0 then 0 + elsif x >= @wi then 0 + elsif y < 0 then 0 + elsif y >= @hi then 0 + else + @data[y*@wi+x] + end + end + def count(x,y) + # (x,y)ã«éš£æŽ¥ã™ã‚‹çˆ†å¼¾ã®æ•°ã‚’返㙠+ fetch(x-1,y-1)+fetch(x,y-1)+fetch(x+1,y-1)+ + fetch(x-1,y) + fetch(x+1,y)+ + fetch(x-1,y+1)+fetch(x,y+1)+fetch(x+1,y+1) + end + def over(win) + # ゲームã®çµ‚了 + quit + unless win + pos(@cx,@cy); print CHR[11] + end + pos(0,@hi) + if win then print "*** YOU WIN !! ***" + else print "*** GAME OVER ***" + end + end + def over? + # ゲームã®çµ‚了ãƒã‚§ãƒƒã‚¯ + # 終了処ç†ã‚‚呼ã³å‡ºã™ + remain = (@mc+@total == 0) + if @over || remain + over(remain) + true + else + false + end + end + def quit + # ゲームã®ä¸æ–(ã¾ãŸã¯çµ‚了) + # 盤é¢ã‚’å…¨ã¦è¦‹ã›ã‚‹ + @hi.times do|y| + pos(0,y) + @wi.times do|x| + colorstr(if @state[y*@wi+x] == "MARK" then COL[1] else COL[2] end, + if fetch(x,y)==1 then CHR[10] else CHR[count(x,y)] end) + end + end + end + def down + # カーソルを下㫠+ if @cy < @hi-1 then @cy=@cy+1; pos(@cx, @cy) end + end + def up + # カーソルを上㫠+ if @cy > 0 then @cy=@cy-1; pos(@cx, @cy) end + end + def left + # カーソルを左㫠+ if @cx > 0 then @cx=@cx-1; pos(@cx, @cy) end + end + def right + # カーソルをå³ã« + if @cx < @wi-1 then @cx=@cx+1; pos(@cx, @cy) end + end +end + +bd=Board.new(10,10,10) +system("stty raw -echo") +begin + loop do + case STDIN.getc + when ?n # new game + bd.reset + when ?m # mark + bd.mark + when ?j + bd.down + when ?k + bd.up + when ?h + bd.left + when ?l + bd.right + when ?\s + bd.open + when ?q,?\C-c # quit game + bd.quit + break + end + if bd.over? + if STDIN.getc == ?q then break end + bd.reset + end + end +ensure + system("stty -raw echo") +end +print "\n" diff --git a/sample/mkproto.rb b/sample/mkproto.rb index 1d9c9faccb..e650fe8d47 100644 --- a/sample/mkproto.rb +++ b/sample/mkproto.rb @@ -1,24 +1,24 @@ $/ = nil -while gets() - if /^((void|VALUE|int|char *\*|ID|struct [\w_]+ *\*|st_table *\*) *)?\n([\w\d_]+)\(.*\)\n\s*((.+;\n)*){/ - $_ = $' +while line = gets() + if /^((void|VALUE|int|char *\*|ID|struct \w+ *\*|st_table *\*) *)?\n(\w+)\(.*\)\n\s*((.+;\n)*)\{/ =~ line + line = $' printf "%s %s(", $2, $3 args = [] for arg in $4.split(/;\n\s*/) - arg.gsub! ' +', ' ' + arg.gsub!(/ +/, ' ') if arg =~ /,/ - if arg =~ /(([^*]+) *\** *[\w\d_]+),/ - type = $2.strip! - args.push $1.strip! - arg = $' - else - type = "" - end - while arg.sub!(/(\** *[\w\d_]+)(,|$)/, "") - args.push type + " " + $1.strip! - end + if arg =~ /(([^*]+) *\** *\w+),/ + type = $2.strip + args.push $1.strip + arg = $' + else + type = "" + end + while arg.sub!(/(\** *\w+)(,|$)/, "") && $~ + args.push type + " " + $1.strip + end else - args.push arg.strip! + args.push arg.strip end end printf "%s);\n", args.join(', ') diff --git a/sample/mpart.rb b/sample/mpart.rb index 6c40d50e18..a88eba0ef6 100755..100644 --- a/sample/mpart.rb +++ b/sample/mpart.rb @@ -31,7 +31,7 @@ for i in ifp = open(basename) end ofp.write(i) line = line + 1 - if line >= lines + if line >= lines and !ifp.eof? ofp.write("END--cut here--cut here\n") ofp.close part = part + 1 diff --git a/sample/mrshtest.rb b/sample/mrshtest.rb deleted file mode 100644 index 402b35ad55..0000000000 --- a/sample/mrshtest.rb +++ /dev/null @@ -1,14 +0,0 @@ -require "marshal" -include Marshal -a = 25.6; -pt = Struct.new('Point', :x,:y); -x = pt.new(10, 10) -y = pt.new(20, 20) -rt = Struct.new('Rectangle', :origin,:corner); -z = rt.new(x, y) -c = Object.new -s = [a, x, z, c, c, "fff"]; -p s -d = dump(s); -p d -p load(d) diff --git a/sample/net-imap.rb b/sample/net-imap.rb new file mode 100644 index 0000000000..b93ecb746e --- /dev/null +++ b/sample/net-imap.rb @@ -0,0 +1,167 @@ +require 'net/imap' +require "getoptlong" + +$stdout.sync = true +$port = nil +$user = ENV["USER"] || ENV["LOGNAME"] +$auth = "login" +$ssl = false +$starttls = false + +def usage + <<EOF +usage: #{$0} [options] <host> + + --help print this message + --port=PORT specifies port + --user=USER specifies user + --auth=AUTH specifies auth type + --starttls use starttls + --ssl use ssl +EOF +end + +begin + require 'io/console' +rescue LoadError + def _noecho(&block) + system("stty", "-echo") + begin + yield STDIN + ensure + system("stty", "echo") + end + end +else + def _noecho(&block) + STDIN.noecho(&block) + end +end + +def get_password + print "password: " + begin + return _noecho(&:gets).chomp + ensure + puts + end +end + +def get_command + printf("%s@%s> ", $user, $host) + if line = gets + return line.strip.split(/\s+/) + else + return nil + end +end + +parser = GetoptLong.new +parser.set_options(['--debug', GetoptLong::NO_ARGUMENT], + ['--help', GetoptLong::NO_ARGUMENT], + ['--port', GetoptLong::REQUIRED_ARGUMENT], + ['--user', GetoptLong::REQUIRED_ARGUMENT], + ['--auth', GetoptLong::REQUIRED_ARGUMENT], + ['--starttls', GetoptLong::NO_ARGUMENT], + ['--ssl', GetoptLong::NO_ARGUMENT]) +begin + parser.each_option do |name, arg| + case name + when "--port" + $port = arg + when "--user" + $user = arg + when "--auth" + $auth = arg + when "--ssl" + $ssl = true + when "--starttls" + $starttls = true + when "--debug" + Net::IMAP.debug = true + when "--help" + usage + exit + end + end +rescue + abort usage +end + +$host = ARGV.shift +unless $host + abort usage +end + +imap = Net::IMAP.new($host, :port => $port, :ssl => $ssl) +begin + imap.starttls if $starttls + class << password = method(:get_password) + alias to_str call + end + imap.authenticate($auth, $user, password) + while true + cmd, *args = get_command + break unless cmd + begin + case cmd + when "list" + for mbox in imap.list("", args[0] || "*") + if mbox.attr.include?(Net::IMAP::NOSELECT) + prefix = "!" + elsif mbox.attr.include?(Net::IMAP::MARKED) + prefix = "*" + else + prefix = " " + end + print prefix, mbox.name, "\n" + end + when "select" + imap.select(args[0] || "inbox") + print "ok\n" + when "close" + imap.close + print "ok\n" + when "summary" + unless messages = imap.responses["EXISTS"][-1] + puts "not selected" + next + end + if messages > 0 + for data in imap.fetch(1..-1, ["ENVELOPE"]) + print data.seqno, ": ", data.attr["ENVELOPE"].subject, "\n" + end + else + puts "no message" + end + when "fetch" + if args[0] + data = imap.fetch(args[0].to_i, ["RFC822.HEADER", "RFC822.TEXT"])[0] + puts data.attr["RFC822.HEADER"] + puts data.attr["RFC822.TEXT"] + else + puts "missing argument" + end + when "logout", "exit", "quit" + break + when "help", "?" + print <<EOF +list [pattern] list mailboxes +select [mailbox] select mailbox +close close mailbox +summary display summary +fetch [msgno] display message +logout logout +help, ? display help message +EOF + else + print "unknown command: ", cmd, "\n" + end + rescue Net::IMAP::Error + puts $! + end + end +ensure + imap.logout + imap.disconnect +end diff --git a/sample/observ.rb b/sample/observ.rb index f7b1e73137..a7ea45271d 100644 --- a/sample/observ.rb +++ b/sample/observ.rb @@ -1,31 +1,31 @@ #! /usr/local/bin/ruby -require "thread" require "observer" class Tick include Observable def initialize Thread.start do - while TRUE - sleep 0.999 - changed - notify_observers(Time.now.strftime("%H:%M:%S")) + loop do + sleep 0.999 + now = Time.now + changed + notify_observers(now.hour, now.min, now.sec) end end end end class Clock - def initialize - @tick = Tick.new + def initialize(tick) + @tick = tick @tick.add_observer(self) end - def update(time) - print "\e[8D", time + def update(h, m, s) + printf "\e[8D%02d:%02d:%02d", h, m, s STDOUT.flush end end -clock = Clock.new +clock = Clock.new(Tick.new) sleep diff --git a/sample/occur.pl b/sample/occur.pl index 1f5fcf27a4..331ce50211 100644 --- a/sample/occur.pl +++ b/sample/occur.pl @@ -1,9 +1,9 @@ while (<>) { - for (split(/\W+/)) { - $freq{$_}++; - } + for (split(/\W+/)) { + $freq{$_}++; + } } for (sort keys %freq) { - print "$_ -- $freq{$_}\n"; + print "$_ -- $freq{$_}\n"; } diff --git a/sample/occur.rb b/sample/occur.rb index 2141fade38..42151d85e8 100644 --- a/sample/occur.rb +++ b/sample/occur.rb @@ -1,12 +1,12 @@ # word occurrence listing -# usege: ruby occur.rb file.. -freq = {} -while gets() - for word in $_.split(/\W+/) - freq[word] +=1 +# usage: ruby occur.rb file.. +freq = Hash.new(0) +while line = gets() + for word in line.split(/\W+/) + freq[word] += 1 end end -for word in freq.keys.sort - printf("%s -- %d\n", word, freq[word]) +for word in freq.keys.sort! + print word, " -- ", freq[word], "\n" end diff --git a/sample/occur2.rb b/sample/occur2.rb index c450c30b0f..ef8ad2c541 100644 --- a/sample/occur2.rb +++ b/sample/occur2.rb @@ -1,13 +1,10 @@ # word occurrence listing -# usege: ruby occur2.rb file.. +# usage: ruby occur2.rb file.. freq = {} -while gets() - for word in $_.split(/\W+/) - begin - freq[word] = freq[word] + 1 - rescue - freq[word] = 1 - end +ARGF.each_line do |line| + for word in line.split(/\W+/) + freq[word] ||= 0 + freq[word] += 1 end end diff --git a/sample/open3.rb b/sample/open3.rb new file mode 100644 index 0000000000..bc6cdfe3bf --- /dev/null +++ b/sample/open3.rb @@ -0,0 +1,12 @@ +require 'open3' + +a = Open3.popen3("nroff -man") +Thread.start do + while line = gets + a[0].print line + end + a[0].close +end +while line = a[1].gets + print ":", line +end diff --git a/sample/openssl/c_rehash.rb b/sample/openssl/c_rehash.rb new file mode 100644 index 0000000000..cd6c9d5fd4 --- /dev/null +++ b/sample/openssl/c_rehash.rb @@ -0,0 +1,174 @@ +#!/usr/bin/env ruby + +require 'openssl' +require 'digest/md5' + +class CHashDir + include Enumerable + + def initialize(dirpath) + @dirpath = dirpath + @fingerprint_cache = @cert_cache = @crl_cache = nil + end + + def hash_dir(silent = false) + # ToDo: Should lock the directory... + @silent = silent + @fingerprint_cache = Hash.new + @cert_cache = Hash.new + @crl_cache = Hash.new + do_hash_dir + end + + def get_certs(name = nil) + if name + @cert_cache[hash_name(name)] + else + @cert_cache.values.flatten + end + end + + def get_crls(name = nil) + if name + @crl_cache[hash_name(name)] + else + @crl_cache.values.flatten + end + end + + def delete_crl(crl) + File.unlink(crl_filename(crl)) + hash_dir(true) + end + + def add_crl(crl) + File.open(crl_filename(crl), "w") do |f| + f << crl.to_pem + end + hash_dir(true) + end + + def load_pem_file(filepath) + str = File.read(filepath) + begin + OpenSSL::X509::Certificate.new(str) + rescue + begin + OpenSSL::X509::CRL.new(str) + rescue + begin + OpenSSL::X509::Request.new(str) + rescue + nil + end + end + end + end + +private + + def crl_filename(crl) + path(hash_name(crl.issuer)) + '.pem' + end + + def do_hash_dir + Dir.chdir(@dirpath) do + delete_symlink + Dir.glob('*.pem') do |pemfile| + cert = load_pem_file(pemfile) + case cert + when OpenSSL::X509::Certificate + link_hash_cert(pemfile, cert) + when OpenSSL::X509::CRL + link_hash_crl(pemfile, cert) + else + STDERR.puts("WARNING: #{pemfile} does not contain a certificate or CRL: skipping") unless @silent + end + end + end + end + + def delete_symlink + Dir.entries(".").each do |entry| + next unless /^[\da-f]+\.r{0,1}\d+$/ =~ entry + File.unlink(entry) if FileTest.symlink?(entry) + end + end + + def link_hash_cert(org_filename, cert) + name_hash = hash_name(cert.subject) + fingerprint = fingerprint(cert.to_der) + filepath = link_hash(org_filename, name_hash, fingerprint) { |idx| + "#{name_hash}.#{idx}" + } + unless filepath + unless @silent + STDERR.puts("WARNING: Skipping duplicate certificate #{org_filename}") + end + else + (@cert_cache[name_hash] ||= []) << path(filepath) + end + end + + def link_hash_crl(org_filename, crl) + name_hash = hash_name(crl.issuer) + fingerprint = fingerprint(crl.to_der) + filepath = link_hash(org_filename, name_hash, fingerprint) { |idx| + "#{name_hash}.r#{idx}" + } + unless filepath + unless @silent + STDERR.puts("WARNING: Skipping duplicate CRL #{org_filename}") + end + else + (@crl_cache[name_hash] ||= []) << path(filepath) + end + end + + def link_hash(org_filename, name, fingerprint) + idx = 0 + filepath = nil + while true + filepath = yield(idx) + break unless FileTest.symlink?(filepath) or FileTest.exist?(filepath) + if @fingerprint_cache[filepath] == fingerprint + return false + end + idx += 1 + end + STDOUT.puts("#{org_filename} => #{filepath}") unless @silent + symlink(org_filename, filepath) + @fingerprint_cache[filepath] = fingerprint + filepath + end + + def symlink(from, to) + begin + File.symlink(from, to) + rescue + File.open(to, "w") do |f| + f << File.read(from) + end + end + end + + def path(filename) + File.join(@dirpath, filename) + end + + def hash_name(name) + sprintf("%x", name.hash) + end + + def fingerprint(der) + Digest::MD5.hexdigest(der).upcase + end +end + +if $0 == __FILE__ + dirlist = ARGV + dirlist << '/usr/ssl/certs' if dirlist.empty? + dirlist.each do |dir| + CHashDir.new(dir).hash_dir + end +end diff --git a/sample/openssl/cert2text.rb b/sample/openssl/cert2text.rb new file mode 100644 index 0000000000..50da224e76 --- /dev/null +++ b/sample/openssl/cert2text.rb @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby + +require 'openssl' +include OpenSSL::X509 + +def cert2text(cert_str) + [Certificate, CRL, Request].each do |klass| + begin + puts klass.new(cert_str).to_text + return + rescue + end + end + raise ArgumentError.new('Unknown format.') +end + +if ARGV.empty? + cert2text(STDIN.read) +else + ARGV.each do |file| + cert2text(File.read(file)) + end +end diff --git a/sample/openssl/certstore.rb b/sample/openssl/certstore.rb new file mode 100644 index 0000000000..c6e8f816bc --- /dev/null +++ b/sample/openssl/certstore.rb @@ -0,0 +1,161 @@ +require 'c_rehash' +require 'crlstore' + + +class CertStore + include OpenSSL + include X509 + + attr_reader :self_signed_ca + attr_reader :other_ca + attr_reader :ee + attr_reader :crl + attr_reader :request + + def initialize(certs_dir) + @certs_dir = certs_dir + @c_store = CHashDir.new(@certs_dir) + @c_store.hash_dir(true) + @crl_store = CrlStore.new(@c_store) + @x509store = Store.new + @self_signed_ca = @other_ca = @ee = @crl = nil + + # Uncomment this line to let OpenSSL to check CRL for each certs. + # @x509store.flags = V_FLAG_CRL_CHECK | V_FLAG_CRL_CHECK_ALL + + add_path + scan_certs + end + + def generate_cert(filename) + @c_store.load_pem_file(filename) + end + + def verify(cert) + error, crl_map = do_verify(cert) + if error + [[false, cert, crl_map[cert.subject], error]] + else + @x509store.chain.collect { |c| [true, c, crl_map[c.subject], nil] } + end + end + + def match_cert(cert1, cert2) + (cert1.issuer.cmp(cert2.issuer) == 0) and cert1.serial == cert2.serial + end + + def is_ca?(cert) + case guess_cert_type(cert) + when CERT_TYPE_SELF_SIGNED + true + when CERT_TYPE_OTHER + true + else + false + end + end + + def scan_certs + @self_signed_ca = [] + @other_ca = [] + @ee = [] + @crl = [] + @request = [] + load_certs + end + +private + + def add_path + @x509store.add_path(@certs_dir) + end + + def do_verify(cert) + error_map = {} + crl_map = {} + result = @x509store.verify(cert) do |ok, ctx| + cert = ctx.current_cert + if ctx.current_crl + crl_map[cert.subject] = true + end + if ok + if !ctx.current_crl + if crl = @crl_store.find_crl(cert) + crl_map[cert.subject] = true + if crl.revoked.find { |revoked| revoked.serial == cert.serial } + ok = false + error_string = 'certification revoked' + end + end + end + end + error_map[cert.subject] = error_string if error_string + ok + end + error = if result + nil + else + error_map[cert.subject] || @x509store.error_string + end + return error, crl_map + end + + def load_certs + @c_store.get_certs.each do |certfile| + cert = generate_cert(certfile) + case guess_cert_type(cert) + when CERT_TYPE_SELF_SIGNED + @self_signed_ca << cert + when CERT_TYPE_OTHER + @other_ca << cert + when CERT_TYPE_EE + @ee << cert + else + raise "Unknown cert type." + end + end + @c_store.get_crls.each do |crlfile| + @crl << generate_cert(crlfile) + end + end + + CERT_TYPE_SELF_SIGNED = 0 + CERT_TYPE_OTHER = 1 + CERT_TYPE_EE = 2 + def guess_cert_type(cert) + ca = self_signed = is_cert_self_signed(cert) + cert.extensions.each do |ext| + # Ignores criticality of extensions. It's 'guess'ing. + case ext.oid + when 'basicConstraints' + /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ext.value + ca = ($1 == 'TRUE') unless ca + when 'keyUsage' + usage = ext.value.split(/\s*,\s*/) + ca = usage.include?('Certificate Sign') unless ca + when 'nsCertType' + usage = ext.value.split(/\s*,\s*/) + ca = usage.include?('SSL CA') unless ca + end + end + if ca + if self_signed + CERT_TYPE_SELF_SIGNED + else + CERT_TYPE_OTHER + end + else + CERT_TYPE_EE + end + end + + def is_cert_self_signed(cert) + # cert.subject.cmp(cert.issuer) == 0 + cert.subject.to_s == cert.issuer.to_s + end +end + + +if $0 == __FILE__ + c = CertStore.new("trust_certs") +end diff --git a/sample/openssl/cipher.rb b/sample/openssl/cipher.rb new file mode 100644 index 0000000000..a33dc3e95c --- /dev/null +++ b/sample/openssl/cipher.rb @@ -0,0 +1,54 @@ +#!/usr/bin/env ruby +require 'openssl' + +def crypt_by_password(alg, pass, salt, text) + puts "--Setup--" + puts %(cipher alg: "#{alg}") + puts %(plain text: "#{text}") + puts %(password: "#{pass}") + puts %(salt: "#{salt}") + puts + + puts "--Encrypting--" + enc = OpenSSL::Cipher.new(alg) + enc.encrypt + enc.pkcs5_keyivgen(pass, salt) + cipher = enc.update(text) + cipher << enc.final + puts %(encrypted text: #{cipher.inspect}) + puts + + puts "--Decrypting--" + dec = OpenSSL::Cipher.new(alg) + dec.decrypt + dec.pkcs5_keyivgen(pass, salt) + plain = dec.update(cipher) + plain << dec.final + puts %(decrypted text: "#{plain}") + puts +end + +def ciphers + ciphers = OpenSSL::Cipher.ciphers.sort + ciphers.each{|i| + if i.upcase != i && ciphers.include?(i.upcase) + ciphers.delete(i) + end + } + return ciphers +end + +puts "Supported ciphers in #{OpenSSL::OPENSSL_VERSION}:" +ciphers.each_with_index{|name, i| + printf("%-15s", name) + puts if (i + 1) % 5 == 0 +} +puts +puts + +alg = ARGV.shift || ciphers.first +pass = "secret password" +salt = "8 octets" # or nil +text = "abcdefghijklmnopqrstuvwxyz" + +crypt_by_password(alg, pass, salt, text) diff --git a/sample/openssl/crlstore.rb b/sample/openssl/crlstore.rb new file mode 100644 index 0000000000..e3a592567c --- /dev/null +++ b/sample/openssl/crlstore.rb @@ -0,0 +1,122 @@ +begin + require 'http-access2' +rescue LoadError + STDERR.puts("Cannot load http-access2. CRL might not be fetched.") +end +require 'c_rehash' + + +class CrlStore + def initialize(c_store) + @c_store = c_store + @c_store.hash_dir(true) + end + + def find_crl(cert) + do_find_crl(cert) + end + +private + + def do_find_crl(cert) + unless ca = find_ca(cert) + return nil + end + unless crlfiles = @c_store.get_crls(ca.subject) + if crl = renew_crl(cert, ca) + @c_store.add_crl(crl) + return crl + end + return nil + end + crlfiles.each do |crlfile| + next unless crl = load_crl(crlfile) + if crl.next_update < Time.now + if new_crl = renew_crl(cert, ca) + @c_store.delete_crl(crl) + @c_store.add_crl(new_crl) + crl = new_crl + end + end + if check_valid(crl, ca) + return crl + end + end + nil + end + + def find_ca(cert) + @c_store.get_certs(cert.issuer).each do |cafile| + ca = load_cert(cafile) + if cert.verify(ca.public_key) + return ca + end + end + nil + end + + def fetch(location) + if /\AURI:(.*)\z/ =~ location + begin + c = HTTPAccess2::Client.new(ENV['http_proxy'] || ENV['HTTP_PROXY']) + c.get_content($1) + rescue NameError, StandardError + nil + end + else + nil + end + end + + def load_cert(certfile) + load_cert_str(File.read(certfile)) + end + + def load_crl(crlfile) + load_crl_str(File.read(crlfile)) + end + + def load_cert_str(cert_str) + OpenSSL::X509::Certificate.new(cert_str) + end + + def load_crl_str(crl_str) + OpenSSL::X509::CRL.new(crl_str) + end + + def check_valid(crl, ca) + unless crl.verify(ca.public_key) + return false + end + crl.last_update <= Time.now + end + + RE_CDP = /\AcrlDistributionPoints\z/ + def get_cdp(cert) + if cdp_ext = cert.extensions.find { |ext| RE_CDP =~ ext.oid } + cdp_ext.value.chomp + else + false + end + end + + def renew_crl(cert, ca) + if cdp = get_cdp(cert) + if new_crl_str = fetch(cdp) + new_crl = load_crl_str(new_crl_str) + if check_valid(new_crl, ca) + return new_crl + end + end + end + false + end +end + +if $0 == __FILE__ + dir = "trust_certs" + c_store = CHashDir.new(dir) + s = CrlStore.new(c_store) + c = OpenSSL::X509::Certificate.new(File.read("cert_store/google_codesign.pem")) + p s.find_crl(c) +end diff --git a/sample/openssl/echo_cli.rb b/sample/openssl/echo_cli.rb new file mode 100644 index 0000000000..069a21ec94 --- /dev/null +++ b/sample/openssl/echo_cli.rb @@ -0,0 +1,44 @@ +#!/usr/bin/env ruby + +require 'socket' +require 'openssl' +require 'optparse' + +options = ARGV.getopts("p:c:k:C:") + +host = ARGV[0] || "localhost" +port = options["p"] || "2000" +cert_file = options["c"] +key_file = options["k"] +ca_path = options["C"] + +ctx = OpenSSL::SSL::SSLContext.new() +if cert_file && key_file + ctx.cert = OpenSSL::X509::Certificate.new(File::read(cert_file)) + ctx.key = OpenSSL::PKey::RSA.new(File::read(key_file)) +end +if ca_path + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + ctx.ca_path = ca_path +else + $stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!" +end + +s = TCPSocket.new(host, port) +ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) +ssl.connect # start SSL session +p ssl.peer_cert +errors = Hash.new +OpenSSL::X509.constants.grep(/^V_(ERR_|OK)/).each do |name| + errors[OpenSSL::X509.const_get(name)] = name +end +p errors[ssl.verify_result] + +ssl.sync_close = true # if true the underlying socket will be + # closed in SSLSocket#close. (default: false) +while line = $stdin.gets + ssl.write line + puts ssl.gets.inspect +end + +ssl.close diff --git a/sample/openssl/echo_svr.rb b/sample/openssl/echo_svr.rb new file mode 100644 index 0000000000..719de6be84 --- /dev/null +++ b/sample/openssl/echo_svr.rb @@ -0,0 +1,65 @@ +#!/usr/bin/env ruby + +require 'socket' +require 'openssl' +require 'optparse' + +options = ARGV.getopts("p:c:k:C:") + +port = options["p"] || "2000" +cert_file = options["c"] +key_file = options["k"] +ca_path = options["C"] + +if cert_file && key_file + cert = OpenSSL::X509::Certificate.new(File::read(cert_file)) + key = OpenSSL::PKey::RSA.new(File::read(key_file)) +else + key = OpenSSL::PKey::RSA.new(512){ print "." } + puts + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 0 + name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]]) + cert.subject = name + cert.issuer = name + cert.not_before = Time.now + cert.not_after = Time.now + 3600 + cert.public_key = key.public_key + ef = OpenSSL::X509::ExtensionFactory.new(nil,cert) + cert.extensions = [ + ef.create_extension("basicConstraints","CA:FALSE"), + ef.create_extension("subjectKeyIdentifier","hash"), + ef.create_extension("extendedKeyUsage","serverAuth"), + ef.create_extension("keyUsage", + "keyEncipherment,dataEncipherment,digitalSignature") + ] + ef.issuer_certificate = cert + cert.add_extension ef.create_extension("authorityKeyIdentifier", + "keyid:always,issuer:always") + cert.sign(key, OpenSSL::Digest::SHA1.new) +end + +ctx = OpenSSL::SSL::SSLContext.new() +ctx.key = key +ctx.cert = cert +if ca_path + ctx.verify_mode = + OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + ctx.ca_path = ca_path +else + $stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!" +end + +tcps = TCPServer.new(port) +ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) +loop do + ns = ssls.accept + puts "connected from #{ns.peeraddr}" + while line = ns.gets + puts line.inspect + ns.write line + end + puts "connection closed" + ns.close +end diff --git a/sample/openssl/gen_csr.rb b/sample/openssl/gen_csr.rb new file mode 100644 index 0000000000..4228707fdb --- /dev/null +++ b/sample/openssl/gen_csr.rb @@ -0,0 +1,51 @@ +#!/usr/bin/env ruby + +require 'optparse' +require 'openssl' + +include OpenSSL + +def usage + myname = File::basename($0) + $stderr.puts <<EOS +Usage: #{myname} [--key keypair_file] name + name ... ex. /C=JP/O=RRR/OU=CA/CN=NaHi/emailAddress=nahi@example.org +EOS + exit +end + +options = ARGV.getopts(nil, "key:", "csrout:", "keyout:") +keypair_file = options["key"] +csrout = options["csrout"] || "csr.pem" +keyout = options["keyout"] || "keypair.pem" + +$stdout.sync = true +name_str = ARGV.shift or usage() +name = X509::Name.parse(name_str) + +keypair = nil +if keypair_file + keypair = PKey::RSA.new(File.open(keypair_file).read) +else + keypair = PKey::RSA.new(1024) { putc "." } + puts + puts "Writing #{keyout}..." + File.open(keyout, "w", 0400) do |f| + f << keypair.to_pem + end +end + +puts "Generating CSR for #{name_str}" + +req = X509::Request.new +req.version = 0 +req.subject = name +req.public_key = keypair.public_key +req.sign(keypair, Digest::MD5.new) + +puts "Writing #{csrout}..." +File.open(csrout, "w") do |f| + f << req.to_pem +end +puts req.to_text +puts req.to_pem diff --git a/sample/openssl/smime_read.rb b/sample/openssl/smime_read.rb new file mode 100644 index 0000000000..17394f9b8d --- /dev/null +++ b/sample/openssl/smime_read.rb @@ -0,0 +1,23 @@ +require 'optparse' +require 'openssl' +include OpenSSL + +options = ARGV.getopts("c:k:C:") + +cert_file = options["c"] +key_file = options["k"] +ca_path = options["C"] + +data = $stdin.read + +cert = X509::Certificate.new(File::read(cert_file)) +key = PKey::RSA.new(File::read(key_file)) +p7enc = PKCS7::read_smime(data) +data = p7enc.decrypt(key, cert) + +store = X509::Store.new +store.add_path(ca_path) +p7sig = PKCS7::read_smime(data) +if p7sig.verify([], store) + puts p7sig.data +end diff --git a/sample/openssl/smime_write.rb b/sample/openssl/smime_write.rb new file mode 100644 index 0000000000..5a5236c750 --- /dev/null +++ b/sample/openssl/smime_write.rb @@ -0,0 +1,23 @@ +require 'openssl' +require 'optparse' +include OpenSSL + +options = ARGV.getopts("c:k:r:") + +cert_file = options["c"] +key_file = options["k"] +rcpt_file = options["r"] + +cert = X509::Certificate.new(File::read(cert_file)) +key = PKey::RSA.new(File::read(key_file)) + +data = "Content-Type: text/plain\r\n" +data << "\r\n" +data << "This is a clear-signed message.\r\n" + +p7sig = PKCS7::sign(cert, key, data, [], PKCS7::DETACHED) +smime0 = PKCS7::write_smime(p7sig) + +rcpt = X509::Certificate.new(File::read(rcpt_file)) +p7enc = PKCS7::encrypt([rcpt], smime0) +print PKCS7::write_smime(p7enc) diff --git a/sample/openssl/wget.rb b/sample/openssl/wget.rb new file mode 100644 index 0000000000..ee637204db --- /dev/null +++ b/sample/openssl/wget.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby + +require 'net/https' +require 'optparse' + +options = ARGV.getopts('C:') + +cert_store = options["C"] + +uri = URI.parse(ARGV[0]) +if proxy = ENV['HTTP_PROXY'] + prx_uri = URI.parse(proxy) + prx_host = prx_uri.host + prx_port = prx_uri.port +end + +h = Net::HTTP.new(uri.host, uri.port, prx_host, prx_port) +h.set_debug_output($stderr) if $DEBUG +if uri.scheme == "https" + h.use_ssl = true + if cert_store + if File.directory?(cert_store) + h.ca_path = cert_store + else + h.ca_file = cert_store + end + end +end + +path = uri.path.empty? ? "/" : uri.path +h.get2(path){|resp| + STDERR.puts h.peer_cert.inspect if h.peer_cert + print resp.body +} diff --git a/sample/optparse/opttest.rb b/sample/optparse/opttest.rb new file mode 100755 index 0000000000..b2013c5253 --- /dev/null +++ b/sample/optparse/opttest.rb @@ -0,0 +1,125 @@ +#!/usr/bin/ruby -I. + +require 'optparse' +require 'optparse/time' +require 'pp' + +# keywords +CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary] +CODE_ALIASES = {"jis" => "iso-2022-jp", "sjis" => "shift_jis"} +POSSIBLE_CODES = "(#{(CODES+CODE_ALIASES.keys).join(',')})" + +ARGV.options do + |opts| + opts.banner << " argv..." + + # separator + opts.on_tail + opts.on_tail("common options:") + + # no argument, shows at tail + opts.on_tail("--help", "show this message") do + puts opts + exit + end + + # mandatory argument + opts.on("-r", "--require=LIBRARY", String, + "require the LIBRARY, before", + "executing your script") do + |lib| + @library = lib + end + + # optional argument + opts.on("-i", "--inplace=[EXTENSION]", + "edit ARGV files in place", # multiline description + "(make backup if EXTENSION supplied)") do + |inplace| + @inplace = inplace || '' + end + + opts.on("-N=[NUM]", Integer) do + |num| + @number = num + end + + # additional class + opts.on("-t", "--[no-]time[=TIME]", Time, "it's the time") do + |time| + @time = time + end + + # limit argument syntax + opts.on("-[0-7]", "-F", "--irs=[OCTAL]", OptionParser::OctalInteger, + "specify record separator", "(\\0, if no argument)") do + |irs| + @irs = irs + end + + # boolean switch(default true) + @exec = true + opts.on("-n", "--no-exec[=FLAG]", TrueClass, "not really execute") do + |exec| + @exec = exec + end + + # array + opts.on("-a", "--list[=LIST,LIST]", Array, "list") do + |list| + @list = list + end + + # fixed size array + opts.on("--pair[=car,cdr]", Array, "pair") do + |x, y| + @x = x + @y = y + end + + # keyword completion + opts.on("--code=CODE", CODES, CODE_ALIASES, "select coding system", + "("+CODES.join(",")+",", " "+CODE_ALIASES.keys.join(",")+")") do + |c| + @code = c + end + + # optional argument with keyword completion + opts.on("--type[=TYPE]", [:text, :binary], "select type(text, binary)") do + |t| + @type = t + end + + # boolean switch with optional argument(default false) + opts.on("-v", "--[no-]verbose=[FLAG]", "run verbosely") do + |v| + @verbose = v + end + + # easy way, set local variable + opts.on("-q", "--quit", "quit when ARGV is empty") do + |q| + @quit = q + end + + # adding on the fly + opts.on("--add=SWITCH=[ARG]", "add option on the fly", /\A(\w+)(?:=.+)?\Z/) do + |opt, var| + opts.on("--#{opt}", "added in runtime", &eval("proc {|x|@#{var}=x}")) + end + + opts.on_head("specific options:") + + # no argument + opts.on_tail("--version", "show version") do + puts OptionParser::Version.join('.') + exit + end + opts.parse! +end + +pp self +begin print ARGV.options; exit end if @quit +ARGV.options = nil # no more parse +puts "ARGV = #{ARGV.join(' ')}" if !ARGV.empty? +#opts.variable.each {|sym| puts "#{sym} = #{opts.send(sym).inspect}"} diff --git a/sample/optparse/subcommand.rb b/sample/optparse/subcommand.rb new file mode 100755 index 0000000000..21c42dd60a --- /dev/null +++ b/sample/optparse/subcommand.rb @@ -0,0 +1,19 @@ +#! /usr/bin/ruby +# contributed by Minero Aoki. + +require 'optparse' + +parser = OptionParser.new +parser.on('-i') { puts "-i" } +parser.on('-o') { puts '-o' } + +subparsers = Hash.new {|h,k| + $stderr.puts "no such subcommand: #{k}" + exit 1 +} +subparsers['add'] = OptionParser.new.on('-i') { puts "add -i" } +subparsers['del'] = OptionParser.new.on('-i') { puts "del -i" } +subparsers['list'] = OptionParser.new.on('-i') { puts "list -i" } + +parser.order!(ARGV) +subparsers[ARGV.shift].parse!(ARGV) unless ARGV.empty? diff --git a/sample/philos.rb b/sample/philos.rb index 3ccb052532..c38aa4a1cc 100644 --- a/sample/philos.rb +++ b/sample/philos.rb @@ -1,14 +1,13 @@ # # The Dining Philosophers - thread example # -require "thread" srand #srand N=9 # number of philosophers $forks = [] for i in 0..N-1 - $forks[i] = Mutex.new + $forks[i] = Thread::Mutex.new end $state = "-o"*N @@ -25,7 +24,7 @@ def eat(n) end def philosopher(n) - while TRUE + while true think n $forks[n].lock if not $forks[(n+1)%N].try_lock @@ -46,8 +45,8 @@ def philosopher(n) end end -for i in 0..N-1 - Thread.start{philosopher(i)} +for n in 0..N-1 + Thread.start(n){|i| philosopher(i)} sleep 0.1 end diff --git a/sample/pi.rb b/sample/pi.rb index 49067cc347..63be974285 100644 --- a/sample/pi.rb +++ b/sample/pi.rb @@ -2,7 +2,7 @@ k, a, b, a1, b1 = 2, 4, 1, 12, 4 -while TRUE +loop do # Next approximation p, q, k = k*k, 2*k+1, k+1 a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1 diff --git a/sample/pstore.rb b/sample/pstore.rb new file mode 100644 index 0000000000..38c2305516 --- /dev/null +++ b/sample/pstore.rb @@ -0,0 +1,19 @@ +require 'pstore' + +db = PStore.new("/tmp/foo") +db.transaction do + p db.roots + ary = db["root"] = [1,2,3,4] + ary[1] = [1,1.5] +end + +1000.times do + db.transaction do + db["root"][0] += 1 + p db["root"][0] + end +end + +db.transaction(true) do + p db["root"] +end diff --git a/sample/pty/expect_sample.rb b/sample/pty/expect_sample.rb new file mode 100644 index 0000000000..199d98b79c --- /dev/null +++ b/sample/pty/expect_sample.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true +# +# sample program of expect.rb +# +# by A. Ito +# +# This program reports the latest version of Ruby interpreter +# by connecting to ftp server at ruby-lang.org. +# +require 'pty' +require 'expect' + +fnames = [] +PTY.spawn("ftp ftp.ruby-lang.org") do |r_f,w_f,pid| + w_f.sync = true + + $expect_verbose = false + + if !ENV['USER'].nil? + username = ENV['USER'] + elsif !ENV['LOGNAME'].nil? + username = ENV['LOGNAME'] + else + username = 'guest' + end + + r_f.expect(/^Name.*: /) do + w_f.puts("ftp") + end + r_f.expect(/word:/) do + w_f.puts("#{username}@") + end + r_f.expect(/> /) do + w_f.puts("cd pub/ruby") + end + r_f.expect("> ") do + w_f.print "pass\n" + end + r_f.expect("> ") do + w_f.print "dir\n" + end + + r_f.expect(/[^\-]> /) do |output| + for x in output[0].split("\n") + if x =~ /(ruby.*?\.tar\.gz)/ then + fnames.push $1 + end + end + end + begin + w_f.print "quit\n" + rescue + end +end + +print "The latest ruby interpreter is " +print fnames.sort.pop +print "\n" diff --git a/sample/pty/script.rb b/sample/pty/script.rb new file mode 100644 index 0000000000..c6659a4807 --- /dev/null +++ b/sample/pty/script.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +require 'pty' + +if ARGV.size == 0 then + ofile = "typescript" +else + ofile = ARGV[0] +end + +logfile = File.open(ofile,"a") + +system "stty -echo raw lnext ^_" + +PTY.spawn("/bin/csh") do |r_pty,w_pty,pid| + + Thread.new do + while true + w_pty.print STDIN.getc.chr + w_pty.flush + end + end + + begin + while true + c = r_pty.sysread(512) + break if c.nil? + print c + STDOUT.flush + logfile.print c + end + rescue + # print $@,':',$!,"\n" + logfile.close + end +end + +system "stty echo -raw lnext ^v" diff --git a/sample/pty/shl.rb b/sample/pty/shl.rb new file mode 100644 index 0000000000..980748e8f5 --- /dev/null +++ b/sample/pty/shl.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true +# +# old-fashioned 'shl' like program +# by A. Ito +# +# commands: +# c creates new shell +# C-z suspends shell +# p lists all shell +# 0,1,... choose shell +# q quit + +require 'pty' +require 'io/console' + +$shells = [] + +$r_pty = nil +$w_pty = nil + +def writer + STDIN.raw! + begin + while true + c = STDIN.getc + if c == ?\C-z then + $reader.raise('Suspend') + return 'Suspend' + end + $w_pty.print c.chr + $w_pty.flush + end + rescue + $reader.raise('Exit') + return 'Exit' + ensure + STDIN.cooked! + end +end + +$reader = Thread.new { + while true + begin + Thread.stop unless $r_pty + c = $r_pty.getc + if c.nil? then + Thread.main.raise('Exit') + Thread.stop + end + print c.chr + STDOUT.flush + rescue + Thread.stop + end + end +} + +# $reader.raise(nil) + + +while true + print ">> " + STDOUT.flush + n = nil + case gets + when /^c/i + $shells << PTY.spawn("/bin/csh") + n = -1 + when /^p/i + $shells.each_with_index do |s, i| + if s + print i,"\n" + end + end + when /^([0-9]+)/ + n = $1.to_i + if $shells[n].nil? + print "\##{i} doesn't exist\n" + n = nil + end + when /^q/i + exit + end + if n + $r_pty, $w_pty, pid = $shells[n] + $reader.run + if writer == 'Exit' then + Process.wait(pid) + $shells[n] = nil + $shells.pop until $shells.empty? or $shells[-1] + end + end +end diff --git a/sample/rcs.awk b/sample/rcs.awk index 08979285c9..e64af5b628 100644 --- a/sample/rcs.awk +++ b/sample/rcs.awk @@ -1,33 +1,33 @@ BEGIN { - sw = 40.0; - dw = 78.0; - hdw = dw / 2.0; - w = 20.0; - h =1.0; - d = 0.2; - ss="abcdefghijklmnopqrstuvwxyz0123456789!#$%^&*()-=\\[];'`,./"; - rnd = srand(); + sw = 40.0; + dw = 78.0; + hdw = dw / 2.0; + w = 20.0; + h =1.0; + d = 0.2; + ss="abcdefghijklmnopqrstuvwxyz0123456789!#$%^&*()-=\\[];'`,./"; + rnd = srand(); } { - xr = -hdw; y = h * 1.0; maxxl = -999; - s = ""; - while (xr < hdw) { - x = xr * (1 + y) - y * w / 2; - i = (x / (1 + h) + sw /2); - c = (0 < i && i < length($0)) ? substr($0, i, 1) : "0"; - y = h - d * c; - xl = xr - w * y / (1 + y); - if (xl < -hdw || xl >= hdw || xl <= maxxl) { - t = rand() * length(ss); - c = substr(ss, t, 1); - } - else { - c = substr(s, xl + hdw, 1); - maxxl = xl; - } - s = s c; - xr = xr + 1; + xr = -hdw; y = h * 1.0; maxxl = -999; + s = ""; + while (xr < hdw) { + x = xr * (1 + y) - y * w / 2; + i = (x / (1 + h) + sw /2); + c = (0 < i && i < length($0)) ? substr($0, i, 1) : "0"; + y = h - d * c; + xl = xr - w * y / (1 + y); + if (xl < -hdw || xl >= hdw || xl <= maxxl) { + t = rand() * length(ss); + c = substr(ss, t, 1); } - print s; + else { + c = substr(s, xl + hdw, 1); + maxxl = xl; + } + s = s c; + xr = xr + 1; + } + print s; } diff --git a/sample/rcs.rb b/sample/rcs.rb index 3f74da9ef2..0bdf81c45d 100644 --- a/sample/rcs.rb +++ b/sample/rcs.rb @@ -1,29 +1,30 @@ # random dot steraogram # usage: rcs.rb rcs.dat -sw = 40.0 # Œ³‚̃pƒ^[ƒ“‚Ì• -dw = 78.0 # ¶¬‚³‚ê‚é Random Character Streogram ‚Ì• +sw = 40.0 # width of original pattern +dw = 78.0 # width of generating Random Character Streogram hdw = dw / 2.0 -w = 20.0 # —¼Šá‚Ì• -h =1.0 # ‰æ–ʂƊʂ̋——£ -d = 0.2 # ’PˆÊ“–‚½‚è‚Ì•‚‚«ã‚ª‚è•û +w = 20.0 # distance between eyes +h =1.0 # distance from screen and base plane +d = 0.2 # z value unit ss="abcdefghijklmnopqrstuvwxyz0123456789#!$%^&*()-=\\[];'`,./" -rnd = srand() +rnd = srand() # You don't actually need this in ruby - srand() is called + # on the first call of rand(). while gets() # print($_) xr = -hdw; y = h * 1.0; maxxl = -999 - s = ""; + s = "" while xr < hdw x = xr * (1 + y) - y * w / 2 i = (x / (1 + h) + sw / 2) - if (1 < i && i < $_.length); + if (1 < i && i < $_.length) c = $_[i, 1].to_i else c = 0 end y = h - d * c - xl = xr - w * y / (1 + y); + xl = xr - w * y / (1 + y) if xl < -hdw || xl >= hdw || xl <= maxxl tt = rand(ss.length) c = ss[tt, 1] @@ -36,14 +37,3 @@ while gets() end print(s, "\n") end - - - - - - - - - - - diff --git a/sample/rdoc/markup/rdoc2latex.rb b/sample/rdoc/markup/rdoc2latex.rb new file mode 100644 index 0000000000..aa8079eb90 --- /dev/null +++ b/sample/rdoc/markup/rdoc2latex.rb @@ -0,0 +1,15 @@ +#!/usr/local/bin/ruby +# Illustration of a script to convert an RDoc-style file to a LaTeX document + +require 'rdoc/markup' +require 'rdoc/markup/to_latex' + +p = RDoc::Markup.new +h = RDoc::Markup::ToLaTeX.new + +#puts "\\documentclass{report}" +#puts "\\usepackage{tabularx}" +#puts "\\usepackage{parskip}" +#puts "\\begin{document}" +puts p.convert(ARGF.read, h) +#puts "\\end{document}" diff --git a/sample/rdoc/markup/sample.rb b/sample/rdoc/markup/sample.rb new file mode 100644 index 0000000000..db5d88d150 --- /dev/null +++ b/sample/rdoc/markup/sample.rb @@ -0,0 +1,40 @@ +# This program illustrates the basic use of the SimpleMarkup +# class. It extracts the first comment block from the +# simple_markup.rb file and converts it into HTML on +# standard output. Run it using +# +# % ruby sample.rb +# +# You should be in the sample/rdoc/markup/ directory when you do this, +# as it hardwires the path to the files it needs to require. +# This isn't necessary in the code you write once you've +# installed the package. +# +# For a better way of formatting code comment blocks (and more) +# see the rdoc package. +# + +require 'rdoc/markup/simple_markup' +require 'rdoc/markup/simple_markup/to_html' + +# Extract the comment block from the source file + +input_string = "" + +File.foreach("../../../lib/rdoc/markup/simple_markup.rb") do |line| + break unless line.gsub!(/^\# ?/, '') + input_string << line +end + +# Create a markup object +markup = SM::SimpleMarkup.new + +# Attach it to an HTML formatter +h = SM::ToHtml.new + +# And convert out comment block to html. Wrap it a body +# tag pair to let browsers view it + +puts "<html><body>" +puts markup.convert(input_string, h) +puts "</body></html>" diff --git a/sample/regx.rb b/sample/regx.rb deleted file mode 100644 index aaf4b5f1ee..0000000000 --- a/sample/regx.rb +++ /dev/null @@ -1,23 +0,0 @@ -st = "\033[7m" -en = "\033[m" -#st = "<<" -#en = ">>" - -while TRUE - print "str> " - STDOUT.flush - input = gets - break if not input - if input != "" - str = input - str.chop! - end - print "pat> " - STDOUT.flush - re = gets - break if not re - re.chop! - str.gsub! re, "#{st}\\&#{en}" - print str, "\n" -end -print "\n" diff --git a/sample/rinda-ring.rb b/sample/rinda-ring.rb new file mode 100644 index 0000000000..f9bd934029 --- /dev/null +++ b/sample/rinda-ring.rb @@ -0,0 +1,22 @@ +require 'rinda/ring' + +DRb.start_service +case ARGV.shift +when 's' + require 'rinda/tuplespace' + ts = Rinda::TupleSpace.new + Rinda::RingServer.new(ts) + $stdin.gets +when 'w' + finger = Rinda::RingFinger.new(nil) + finger.lookup_ring do |ts2| + p ts2 + ts2.write([:hello, :world]) + end +when 'r' + finger = Rinda::RingFinger.new(nil) + finger.lookup_ring do |ts2| + p ts2 + p ts2.take([nil, nil]) + end +end diff --git a/sample/ripper/ruby2html.rb b/sample/ripper/ruby2html.rb new file mode 100644 index 0000000000..8f64f5a713 --- /dev/null +++ b/sample/ripper/ruby2html.rb @@ -0,0 +1,112 @@ +#!/usr/bin/env ruby +# $originalId: ruby2html.rb,v 1.2 2005/09/23 22:53:47 aamine Exp $ + +TEMPLATE_LINE = __LINE__ + 2 +TEMPLATE = <<-EndTemplate +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=<%= encoding %>"> +<% if css %> + <link rel="stylesheet" type="text/css" href="<%= css %>"> +<% end %> + <title><%= File.basename(f.path) %></title> +</head> +<body> +<pre> +<% + if print_line_number + Ruby2HTML.compile(f).each_with_index do |line, idx| +%><%= sprintf('%4d %s', idx+1, line) %><% + end + else +%><%= Ruby2HTML.compile(f) %><% + end +%> +</pre> +</body> +</html> +EndTemplate + +require 'ripper' +require 'stringio' +require 'cgi' +require 'erb' +require 'optparse' + +def main + encoding = 'us-ascii' + css = nil + print_line_number = false + parser = OptionParser.new + parser.banner = "Usage: #{File.basename($0)} [-l] [<file>...]" + parser.on('--encoding=NAME', 'Character encoding [us-ascii].') {|name| + encoding = name + } + parser.on('--css=URL', 'Set a link to CSS.') {|url| + css = url + } + parser.on('-l', '--line-number', 'Show line number.') { + print_line_number = true + } + parser.on('--help', 'Prints this message and quit.') { + puts parser.help + exit 0 + } + begin + parser.parse! + rescue OptionParser::ParseError => err + $stderr.puts err + $stderr.puts parser.help + exit 1 + end + puts ruby2html(ARGF, encoding, css, print_line_number) +end + +class ERB + attr_accessor :lineno + + remove_method :result + def result(b) + eval(@src, b, (@filename || '(erb)'), (@lineno || 1)) + end +end + +def ruby2html(f, encoding, css, print_line_number) + erb = ERB.new(TEMPLATE, nil, '>') + erb.filename = __FILE__ + erb.lineno = TEMPLATE_LINE + erb.result(binding()) +end + +class Ruby2HTML < Ripper::Filter + def Ruby2HTML.compile(f) + buf = StringIO.new + Ruby2HTML.new(f).parse(buf) + buf.string + end + + def on_default(event, tok, f) + f << CGI.escapeHTML(tok) + end + + def on_kw(tok, f) + f << %Q[<span class="resword">#{CGI.escapeHTML(tok)}</span>] + end + + def on_comment(tok, f) + f << %Q[<span class="comment">#{CGI.escapeHTML(tok.rstrip)}</span>\n] + end + + def on_tstring_beg(tok, f) + f << %Q[<span class="string">#{CGI.escapeHTML(tok)}] + end + + def on_tstring_end(tok, f) + f << %Q[#{CGI.escapeHTML(tok)}</span>] + end +end + +if $0 == __FILE__ + main +end diff --git a/sample/ripper/strip-comment.rb b/sample/ripper/strip-comment.rb new file mode 100644 index 0000000000..bd26b6a377 --- /dev/null +++ b/sample/ripper/strip-comment.rb @@ -0,0 +1,19 @@ +# $Id$ + +require 'ripper/filter' + +class CommentStripper < Ripper::Filter + def CommentStripper.strip(src) + new(src).parse(nil) + end + + def on_default(event, token, data) + print token + end + + def on_comment(token, data) + puts + end +end + +CommentStripper.strip(ARGF) diff --git a/sample/rss/blend.rb b/sample/rss/blend.rb new file mode 100755 index 0000000000..351f6f373f --- /dev/null +++ b/sample/rss/blend.rb @@ -0,0 +1,79 @@ +#!/usr/bin/env ruby + +require "rss" + +feeds = [] +verbose = false +encoding = "UTF-8" + +def error(exception) + mark = "=" * 20 + mark = "#{mark} error #{mark}" + STDERR.puts mark + STDERR.puts exception.class + STDERR.puts exception.message + STDERR.puts exception.backtrace + STDERR.puts mark +end + +before_time = Time.now +ARGV.each do |fname| + if fname == '-v' + verbose = true + next + end + rss = nil + f = File.new(fname).read + begin + ## do validate parse + rss = RSS::Parser.parse(f) + rescue RSS::InvalidRSSError + error($!) if verbose + ## do non validate parse for invalid RSS 1.0 + begin + rss = RSS::Parser.parse(f, false) + rescue RSS::Error + ## invalid RSS. + error($!) if verbose + end + rescue RSS::Error + error($!) if verbose + end + if rss.nil? + STDERR.puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" + else + begin + rss.output_encoding = encoding + rescue RSS::UnknownConversionMethodError + error($!) if verbose + end + feeds << rss + end +end +processing_time = Time.now - before_time + +rss = RSS::Maker.make("1.0") do |maker| + maker.encoding = encoding + maker.channel.about = "http://example.com/blend.rdf" + maker.channel.title = "blended feeds" + maker.channel.link = "http://example.com/" + maker.channel.description = "blended feeds generated by RSS Parser" + + feeds.each do |feed| + feed.items.each do |item| + item.setup_maker(maker.items) + end + end + + maker.items.each do |item| + item.title ||= "UNKNOWN" + item.link ||= "UNKNOWN" + end + + maker.items.do_sort = true + maker.items.max_size = 15 +end +puts rss + +STDERR.puts "Used XML parser: #{RSS::Parser.default_parser}" +STDERR.puts "Processing time: #{processing_time}s" diff --git a/sample/rss/convert.rb b/sample/rss/convert.rb new file mode 100755 index 0000000000..e6bff4c623 --- /dev/null +++ b/sample/rss/convert.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require "rss" + +feeds = [] +verbose = false +encoding = "UTF-8" +to_version = "1.0" + +def error(exception) + mark = "=" * 20 + mark = "#{mark} error #{mark}" + STDERR.puts mark + STDERR.puts exception.class + STDERR.puts exception.message + STDERR.puts exception.backtrace + STDERR.puts mark +end + +before_time = Time.now +ARGV.each do |fname| + case fname + when '-v' + verbose = true + next + when /^-t(0\.91|1\.0|2\.0|atom)$/ + to_version = $1 + next + end + rss = nil + f = File.read(fname) + begin + ## do validate parse + rss = RSS::Parser.parse(f) + rescue RSS::InvalidRSSError + error($!) if verbose + ## do non validate parse for invalid RSS 1.0 + begin + rss = RSS::Parser.parse(f, false) + rescue RSS::Error + ## invalid RSS. + error($!) if verbose + end + rescue RSS::Error + error($!) if verbose + end + if rss.nil? + STDERR.puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" + else + begin + rss.output_encoding = encoding + rescue RSS::UnknownConversionMethodError + error($!) if verbose + end + feeds << [fname, rss] + end +end +processing_time = Time.now - before_time + +feeds.each do |fname, rss| + converted_rss = rss.to_xml(to_version) + output_name = fname.sub(/(\.[^\.]+)$/, "-#{to_version}\\1") + File.open(output_name, "w") do |output| + output.print(converted_rss) + end +end + +STDERR.puts "Used XML parser: #{RSS::Parser.default_parser}" +STDERR.puts "Processing time: #{processing_time}s" diff --git a/sample/rss/list_description.rb b/sample/rss/list_description.rb new file mode 100755 index 0000000000..990974d8f5 --- /dev/null +++ b/sample/rss/list_description.rb @@ -0,0 +1,91 @@ +#!/usr/bin/env ruby + +require "nkf" +class String + # From tdiary.rb + def shorten( len = 120 ) + lines = NKF::nkf( "-t -m0 -f#{len}", self.gsub( /\n/, ' ' ) ).split( /\n/ ) + lines[0].concat( '...' ) if lines[0] and lines[1] + lines[0] + end +end + +require "rss" + +channels = {} +verbose = false + +def error(exception) + mark = "=" * 20 + mark = "#{mark} error #{mark}" + puts mark + puts exception.class + puts exception.message + puts exception.backtrace + puts mark +end + +before_time = Time.now +ARGV.each do |fname| + if fname == '-v' + verbose = true + next + end + rss = nil + f = File.new(fname).read + begin + ## do validate parse + rss = RSS::Parser.parse(f) + rescue RSS::InvalidRSSError + error($!) if verbose + ## do non validate parse for invalid RSS 1.0 + begin + rss = RSS::Parser.parse(f, false) + rescue RSS::Error + ## invalid RSS. + error($!) if verbose + end + rescue RSS::Error + error($!) if verbose + end + if rss.nil? + puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" + else + begin + rss.output_encoding = "utf-8" + rescue RSS::UnknownConversionMethodError + error($!) if verbose + end + + rss = rss.to_rss("1.0") do |maker| + maker.channel.about ||= maker.channel.link + maker.channel.description ||= "No description" + maker.items.each do |item| + item.title ||= "No title" + item.link ||= "UNKNOWN" + end + end + next if rss.nil? + + rss.items.each do |item| + channels[rss.channel.title] ||= [] + channels[rss.channel.title] << item if item.description + end + end +end +processing_time = Time.now - before_time + +channels.sort do |x, y| + x[0] <=> y[0] +end[0..20].each do |title, items| + puts "Channel: #{title}" unless items.empty? + items.sort do |x, y| + x.title <=> y.title + end[0..10].each do |item| + puts " Item: #{item.title.shorten(50)}" + puts " Description: #{item.description.shorten(50)}" + end +end + +puts "Used XML parser: #{RSS::Parser.default_parser}" +puts "Processing time: #{processing_time}s" diff --git a/sample/rss/re_read.rb b/sample/rss/re_read.rb new file mode 100755 index 0000000000..c386ab20f6 --- /dev/null +++ b/sample/rss/re_read.rb @@ -0,0 +1,64 @@ +#!/usr/bin/env ruby + +require "rss" + +def error(exception) + mark = "=" * 20 + mark = "#{mark} error #{mark}" + puts mark + puts exception.class + puts exception.message + puts exception.backtrace + puts mark +end + +verbose = false +before_time = Time.now + +ARGV.each do |fname| + if fname == '-v' + verbose = true + next + end + source = nil + File.open(fname) do |f| + source = f.read + end + + rss = nil + read = false + begin + rss = RSS::Parser.parse(source) + puts "Re-read valid feed: #{fname}" + RSS::Parser.parse(rss.to_s) + read = true + rescue RSS::InvalidRSSError + error($!) if verbose + ## do non validate parse for invalid feed + begin + rss = RSS::Parser.parse(source, false) + rescue RSS::Error + ## invalid feed + error($!) if verbose + end + rescue RSS::Error + error($!) if verbose + end + + if rss.nil? + puts "Invalid feed: #{fname}" + elsif !read + puts "Re-read invalid feed: #{fname}" + begin + RSS::Parser.parse(rss.to_s) + rescue RSS::Error + puts " Error occurred: #{fname}" + error($!) if verbose + end + end +end + +processing_time = Time.now - before_time + +puts "Used XML parser: #{RSS::Parser.default_parser}" +puts "Processing time: #{processing_time}s" diff --git a/sample/rss/rss_recent.rb b/sample/rss/rss_recent.rb new file mode 100755 index 0000000000..14c861284e --- /dev/null +++ b/sample/rss/rss_recent.rb @@ -0,0 +1,85 @@ +#!/usr/bin/env ruby + +require "nkf" +class String + # From tdiary.rb + def shorten( len = 120 ) + lines = NKF::nkf( "-t -m0 -f#{len}", self.gsub( /\n/, ' ' ) ).split( /\n/ ) + lines[0].concat( '...' ) if lines[0] and lines[1] + lines[0] + end +end + +require "rss" + +items = [] +verbose = false + +def error(exception) + mark = "=" * 20 + mark = "#{mark} error #{mark}" + puts mark + puts exception.class + puts exception.message + puts exception.backtrace + puts mark +end +before_time = Time.now +ARGV.each do |fname| + if fname == '-v' + verbose = true + next + end + rss = nil + f = File.new(fname).read + begin + ## do validate parse + rss = RSS::Parser.parse(f) + rescue RSS::InvalidRSSError + error($!) if verbose + ## do non validate parse for invalid RSS 1.0 + begin + rss = RSS::Parser.parse(f, false) + rescue RSS::Error + ## invalid RSS. + error($!) if verbose + end + rescue RSS::Error + error($!) if verbose + end + if rss.nil? + puts "#{fname} does not include RSS 1.0 or 0.9x/2.0" + else + begin + rss.output_encoding = "utf-8" + rescue RSS::UnknownConversionMethodError + error($!) if verbose + end + + rss = rss.to_rss("1.0") do |maker| + maker.channel.about ||= maker.channel.link + maker.channel.description ||= "No description" + maker.items.each do |item| + item.title ||= "UNKNOWN" + item.link ||= "UNKNOWN" + end + end + next if rss.nil? + + rss.items.each do |item| + items << [rss.channel, item] if item.dc_date + end + end +end +processing_time = Time.now - before_time + +items.sort do |x, y| + y[1].dc_date <=> x[1].dc_date +end[0..20].each do |channel, item| + puts "#{item.dc_date.localtime.iso8601}: " << + "#{channel.title}: #{item.title}" + puts " Description: #{item.description.shorten(50)}" if item.description +end + +puts "Used XML parser: #{RSS::Parser.default_parser}" +puts "Processing time: #{processing_time}s" diff --git a/sample/ruby-mode.el b/sample/ruby-mode.el deleted file mode 100644 index 678a43ba77..0000000000 --- a/sample/ruby-mode.el +++ /dev/null @@ -1,629 +0,0 @@ -;;; -;;; ruby-mode.el - -;;; -;;; $Author: matz$ -;;; Time-stamp: <97/03/21 01:16:05 matz> -;;; created at: Fri Feb 4 14:49:13 JST 1994 -;;; - -(defconst ruby-mode-version "1.0.7") - -(defconst ruby-block-beg-re - "class\\|module\\|def\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin\\|do" - ) - -(defconst ruby-indent-beg-re - "\\(\\s *\\(class\\|module\\|def\\)\\)\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin" - ) - -(defconst ruby-modifier-re - "if\\|unless\\|while\\|until" - ) - -(defconst ruby-block-mid-re - "then\\|else\\|elsif\\|when\\|rescue\\|ensure" - ) - -(defconst ruby-block-op-re - "and\\|or\\|not" - ) - -(defconst ruby-block-end-re "end") - -(defconst ruby-delimiter - (concat "[?$/%(){}#\"'`]\\|\\[\\|\\]\\|\\<\\(" - ruby-block-beg-re - "\\|" ruby-block-end-re - "\\)\\>\\|^=begin") - ) - -(defconst ruby-negative - (concat "^[ \t]*\\(\\(" ruby-block-mid-re "\\)\\>\\|\\(" - ruby-block-end-re "\\)\\>\\|\\}\\|\\]\\)") - ) - -(defconst ruby-operator-chars "[,.+*/%-&|^~=<>:]") -(defconst ruby-symbol-chars "[a-zA-Z0-9_]") - -(defvar ruby-mode-abbrev-table nil - "Abbrev table in use in ruby-mode buffers.") - -(define-abbrev-table 'ruby-mode-abbrev-table ()) - -(defvar ruby-mode-map nil "Keymap used in ruby mode.") - -(if ruby-mode-map - nil - (setq ruby-mode-map (make-sparse-keymap)) - (define-key ruby-mode-map "{" 'ruby-electric-brace) - (define-key ruby-mode-map "}" 'ruby-electric-brace) - (define-key ruby-mode-map "\e\C-a" 'ruby-beginning-of-defun) - (define-key ruby-mode-map "\e\C-e" 'ruby-end-of-defun) - (define-key ruby-mode-map "\e\C-b" 'ruby-beginning-of-block) - (define-key ruby-mode-map "\e\C-f" 'ruby-end-of-block) - (define-key ruby-mode-map "\e\C-p" 'ruby-beginning-of-block) - (define-key ruby-mode-map "\e\C-n" 'ruby-end-of-block) - (define-key ruby-mode-map "\t" 'ruby-indent-command) - (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end) - (define-key ruby-mode-map "\C-j" 'ruby-reindent-then-newline-and-indent) - (define-key ruby-mode-map "\C-m" 'newline)) - -(defvar ruby-mode-syntax-table nil - "Syntax table in use in ruby-mode buffers.") - -(if ruby-mode-syntax-table - () - (setq ruby-mode-syntax-table (make-syntax-table)) - (modify-syntax-entry ?\' "\"" ruby-mode-syntax-table) - (modify-syntax-entry ?\" "\"" ruby-mode-syntax-table) - (modify-syntax-entry ?\` "\"" ruby-mode-syntax-table) - (modify-syntax-entry ?# "<" ruby-mode-syntax-table) - (modify-syntax-entry ?\n ">" ruby-mode-syntax-table) - (modify-syntax-entry ?\\ "'" ruby-mode-syntax-table) - (modify-syntax-entry ?$ "/" ruby-mode-syntax-table) - (modify-syntax-entry ?? "_" ruby-mode-syntax-table) - (modify-syntax-entry ?_ "_" ruby-mode-syntax-table) - (modify-syntax-entry ?< "." ruby-mode-syntax-table) - (modify-syntax-entry ?> "." ruby-mode-syntax-table) - (modify-syntax-entry ?& "." ruby-mode-syntax-table) - (modify-syntax-entry ?| "." ruby-mode-syntax-table) - (modify-syntax-entry ?% "." ruby-mode-syntax-table) - (modify-syntax-entry ?= "." ruby-mode-syntax-table) - (modify-syntax-entry ?/ "." ruby-mode-syntax-table) - (modify-syntax-entry ?+ "." ruby-mode-syntax-table) - (modify-syntax-entry ?* "." ruby-mode-syntax-table) - (modify-syntax-entry ?- "." ruby-mode-syntax-table) - (modify-syntax-entry ?\; "." ruby-mode-syntax-table) - (modify-syntax-entry ?\( "()" ruby-mode-syntax-table) - (modify-syntax-entry ?\) ")(" ruby-mode-syntax-table) - (modify-syntax-entry ?\{ "(}" ruby-mode-syntax-table) - (modify-syntax-entry ?\} "){" ruby-mode-syntax-table) - (modify-syntax-entry ?\[ "(]" ruby-mode-syntax-table) - (modify-syntax-entry ?\] ")[" ruby-mode-syntax-table) - ) - -(defvar ruby-indent-level 2 - "*Indentation of ruby statements.") - -(defun ruby-mode () - "Major mode for editing ruby scripts. -\\[ruby-indent-command] properly indents subexpressions of multi-line -class, module, def, if, while, for, do, and case statements, taking -nesting into account. - -The variable ruby-indent-level controls the amount of indentation. -\\{ruby-mode-map}" - (interactive) - (kill-all-local-variables) - (use-local-map ruby-mode-map) - (setq mode-name "ruby") - (setq major-mode 'ruby-mode) - (set-syntax-table ruby-mode-syntax-table) - (setq local-abbrev-table ruby-mode-abbrev-table) - (make-local-variable 'indent-line-function) - (setq indent-line-function 'ruby-indent-line) - (make-local-variable 'require-final-newline) - (setq require-final-newline t) - (make-variable-buffer-local 'comment-start) - (setq comment-start "# ") - (make-variable-buffer-local 'comment-end) - (setq comment-end "") - (make-variable-buffer-local 'comment-column) - (setq comment-column 32) - (make-variable-buffer-local 'comment-start-skip) - (setq comment-start-skip "#+ *") - (make-local-variable 'parse-sexp-ignore-comments) - (setq parse-sexp-ignore-comments t) - (run-hooks 'ruby-mode-hook)) - -(defun ruby-current-indentation () - (save-excursion - (beginning-of-line) - (back-to-indentation) - (current-column))) - -(defun ruby-indent-line (&optional flag) - "Correct indentation of the current ruby line." - (ruby-indent-to (ruby-calculate-indent))) - -(defun ruby-indent-command () - (interactive) - (ruby-indent-line t)) - -(defun ruby-indent-to (x) - (if x - (let (shift top beg) - (and (< x 0) - (error "invalid nest")) - (setq shift (current-column)) - (beginning-of-line) - (setq beg (point)) - (back-to-indentation) - (setq top (current-column)) - (skip-chars-backward " \t") - (cond - ((>= x shift) - (setq shift 0)) - ((>= shift top) - (setq shift (- shift top))) - (t (setq shift 0))) - (if (and (bolp) - (= x top)) - (move-to-column (+ x shift)) - (move-to-column top) - (delete-region beg (point)) - (beginning-of-line) - (indent-to x) - (move-to-column (+ x shift)))))) - -(defun ruby-expr-beg () - (save-excursion - (if (looking-at "\\?") - (progn - (or (bolp) (forward-char -1)) - (not (looking-at "\\sw"))) - (skip-chars-backward " \t") - (or (bolp) (forward-char -1)) - (or (looking-at ruby-operator-chars) - (looking-at "[\\[({]") - (bolp) - (and (looking-at ruby-symbol-chars) - (forward-word -1) - (or - (looking-at ruby-block-beg-re) - (looking-at ruby-block-op-re) - (looking-at ruby-block-mid-re)) - (goto-char (match-end 0)) - (looking-at "[^_]")))))) - -(defun ruby-parse-region (start end) - (let ((indent-point end) - (indent 0) - (in-string nil) - (in-paren nil) - (depth 0) - (nest nil) - (pcol nil)) - (save-excursion - (if start - (goto-char start) - (ruby-beginning-of-indent)) - (save-restriction - (narrow-to-region (point) end) - (while (and (> indent-point (point)) - (re-search-forward ruby-delimiter indent-point t)) - (let ((pnt (point)) w) - (goto-char (match-beginning 0)) - (cond - ((or (looking-at "\"") ;skip string - (looking-at "'") - (looking-at "`")) - (setq w (char-after (point))) - (cond - ((and (not (eobp)) - (re-search-forward (format "[^\\]%c" w) indent-point t)) - nil) - (t - (setq in-string (point)) - (goto-char indent-point)))) - ((looking-at "/") - (cond - ((and (not (eobp)) (ruby-expr-beg)) - (if (re-search-forward "[^\\]/" indent-point t) - nil - (setq in-string (point)) - (goto-char indent-point))) - (t - (goto-char pnt)))) - ((looking-at "%") - (cond - ((and (not (eobp)) (ruby-expr-beg) - (looking-at "%[Qqrx]?\\(.\\)")) - (setq w (buffer-substring (match-beginning 1) - (match-end 1))) - (cond - ((string= w "[") (setq w "]")) - ((string= w "{") (setq w "}")) - ((string= w "(") (setq w ")")) - ((string= w "<") (setq w ">"))) - (goto-char (match-end 0)) - (if (search-forward w indent-point t) - nil - (setq in-string (point)) - (goto-char indent-point))) - (t - (goto-char pnt)))) - ((looking-at "\\?") ;skip ?char - (cond - ((ruby-expr-beg) - (looking-at "?\\(\\\\C-\\|\\\\M-\\)*.") - (goto-char (match-end 0))) - (t - (goto-char pnt)))) - ((looking-at "\\$") ;skip $char - (goto-char pnt) - (forward-char 1)) - ((looking-at "#") ;skip comment - (forward-line 1) - (goto-char (point)) - ) - ((looking-at "(") - (setq nest (cons (cons (char-after (point)) pnt) nest)) - (setq pcol (cons (cons pnt depth) pcol)) - (setq depth 0) - (goto-char pnt) - ) - ((looking-at "[\\[{]") - (setq nest (cons (cons (char-after (point)) pnt) nest)) - (setq depth (1+ depth)) - (goto-char pnt) - ) - ((looking-at ")") - (setq nest (cdr nest)) - (setq depth (cdr (car pcol))) - (setq pcol (cdr pcol)) - (goto-char pnt)) - ((looking-at "[])}]") - (setq nest (cdr nest)) - (setq depth (1- depth)) - (goto-char pnt)) - ((looking-at ruby-block-end-re) - (if (or (and (not (bolp)) - (progn - (forward-char -1) - (eq ?_ (char-after (point))))) - (progn - (goto-char pnt) - (setq w (char-after (point))) - (or (eq ?_ w) - (eq ?! w) - (eq ?? w)))) - nil - (setq nest (cdr nest)) - (setq depth (1- depth))) - (goto-char pnt)) - ((looking-at ruby-block-beg-re) - (and - (or (bolp) - (progn - (forward-char -1) - (not (eq ?_ (char-after (point)))))) - (progn - (goto-char pnt) - (setq w (char-after (point))) - (and (not (eq ?_ w)) - (not (eq ?! w)) - (not (eq ?? w)))) - (progn - (goto-char (match-beginning 0)) - (if (looking-at ruby-modifier-re) - (ruby-expr-beg) - t)) - (progn - (setq nest (cons (cons nil pnt) nest)) - (setq depth (1+ depth)))) - (if (looking-at "def\\s *[/`]") - (goto-char (match-end 0)) - (goto-char pnt))) - ((looking-at "^=begin") - (if (re-search-forward "^=end" indent-point t) - (forward-line 1) - (setq in-string (match-end 0)) - (goto-char indent-point))) - (t - (error (format "bad string %s" - (buffer-substring (point) pnt) - ))))))) - (list in-string (car nest) depth (car (car pcol)))))) - -(defun ruby-calculate-indent (&optional parse-start) - (save-excursion - (beginning-of-line) - (let ((indent-point (point)) - (case-fold-search nil) - state bol eol - (indent 0)) - (if parse-start - (goto-char parse-start) - (ruby-beginning-of-indent) - (setq parse-start (point))) - (back-to-indentation) - (setq indent (current-column)) - (setq state (ruby-parse-region parse-start indent-point)) - (cond - ((nth 0 state) ; within string - (setq indent nil)) ; do nothing - - ((car (nth 1 state)) ; in paren - (goto-char (cdr (nth 1 state))) - (if (eq (car (nth 1 state)) ?\( ) - (let ((column (current-column)) - (s (ruby-parse-region (point) indent-point))) - (cond - ((and (nth 2 s) (> (nth 2 s) 0)) - (goto-char (cdr (nth 1 s))) - (forward-word -1) - (setq indent (+ (current-column) ruby-indent-level))) - (t - (setq indent (current-column))))) - (cond - ((nth 3 state) - (goto-char (nth 3 state)) - (setq indent (+ (current-column) ruby-indent-level))) - (t - (goto-char parse-start) - (back-to-indentation) - (setq indent (+ (current-column) (* (nth 2 state) ruby-indent-level))))) - )) - - ((and (nth 2 state)(> (nth 2 state) 0)) ; in nest - (goto-char (cdr (nth 1 state))) - (forward-word -1) ; skip back a keyword - (cond - ((looking-at "do") ; iter block is a special case - (cond - ((nth 3 state) - (goto-char (nth 3 state)) - (setq indent (+ (current-column) ruby-indent-level))) - (t - (goto-char parse-start) - (back-to-indentation) - (setq indent (+ (current-column) (* (nth 2 state) ruby-indent-level)))))) - (t - (setq indent (+ (current-column) ruby-indent-level))))) - - ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest - (setq indent (+ (current-column) (* (nth 2 state) ruby-indent-level))))) - - (cond - (indent - (goto-char indent-point) - (end-of-line) - (setq eol (point)) - (beginning-of-line) - (cond - ((re-search-forward ruby-negative eol t) - (and (not (eq ?_ (char-after (match-end 0)))) - (setq indent (- indent ruby-indent-level)))) - ;;operator terminated lines - ((and - (save-excursion - (beginning-of-line) - (not (bobp))) - (or (null (car (nth 1 state))) ;not in parens - (and (eq (car (nth 1 state)) ?\{) - (save-excursion ;except non-block braces - (goto-char (cdr (nth 1 state))) - (or (bobp) (forward-char -1)) - (not (ruby-expr-beg)))))) - ;; goto beginning of non-empty no-comment line - (let (end done) - (while (not done) - (skip-chars-backward " \t\n") - (setq end (point)) - (beginning-of-line) - (if (re-search-forward "^\\s *#" end t) - (beginning-of-line) - (setq done t)))) - (setq bol (point)) - (end-of-line) - (skip-chars-backward " \t") - (or (bobp) (forward-char -1)) - (and - (or (and (looking-at ruby-symbol-chars) - (skip-chars-backward ruby-symbol-chars) - (looking-at ruby-block-op-re)) - (and (looking-at ruby-operator-chars) - (or (not (or (eq ?/ (char-after (point))))) - (null (nth 0 (ruby-parse-region parse-start (point))))) - (not (eq (char-after (1- (point))) ?$)) - (or (not (eq ?| (char-after (point)))) - (save-excursion - (or (eolp) (forward-char -1)) - (and (search-backward "|") - (skip-chars-backward " \t\n") - (and (not (eolp)) - (progn - (forward-char -1) - (not (looking-at "\\{"))) - (progn - (forward-word -1) - (not (looking-at "do\\>[^_]"))))))))) - (setq indent (+ indent ruby-indent-level))))))) - indent))) - -(defun ruby-electric-brace (arg) - (interactive "P") - (self-insert-command (prefix-numeric-value arg)) - (ruby-indent-line t)) - -(defun ruby-beginning-of-defun (&optional arg) - "Move backward to next beginning-of-defun. -With argument, do this that many times. -Returns t unless search stops due to end of buffer." - (interactive "p") - (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)\\b") - nil 'move (or arg 1)) - (progn (beginning-of-line) t))) - -(defun ruby-beginning-of-indent () - (and (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\b") - nil 'move) - (progn - (beginning-of-line) - t))) - -(defun ruby-end-of-defun (&optional arg) - "Move forward to next end of defun. -An end of a defun is found by moving forward from the beginning of one." - (interactive "p") - (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\b[^_]") - nil 'move (or arg 1)) - (progn (beginning-of-line) t)) - (forward-line 1)) - -(defun ruby-move-to-block (n) - (let (start pos done down) - (setq start (ruby-calculate-indent)) - (if (eobp) - nil - (while (and (not (bobp)) (not done)) - (forward-line n) - (cond - ((looking-at "^$")) - ((looking-at "^\\s *#")) - (t - (setq pos (current-indentation)) - (cond - ((< start pos) - (setq down t)) - ((and down (= pos start)) - (setq done t)) - ((> start pos) - (setq done t))))) - (if done - (progn - (back-to-indentation) - (if (looking-at ruby-block-mid-re) - (setq done nil))))))) - (back-to-indentation)) - -(defun ruby-beginning-of-block () - "Move backward to next beginning-of-block" - (interactive) - (ruby-move-to-block -1)) - -(defun ruby-end-of-block () - "Move forward to next beginning-of-block" - (interactive) - (ruby-move-to-block 1)) - -(defun ruby-reindent-then-newline-and-indent () - (interactive "*") - (save-excursion - (delete-region (point) (progn (skip-chars-backward " \t") (point)))) - (newline) - (save-excursion - (forward-line -1) - (indent-according-to-mode)) - (indent-according-to-mode)) - -(fset 'ruby-encomment-region (symbol-function 'comment-region)) - -(defun ruby-decomment-region (beg end) - (interactive "r") - (save-excursion - (goto-char beg) - (while (re-search-forward "^\\([ \t]*\\)#" end t) - (replace-match "\\1" nil nil) - (save-excursion - (ruby-indent-line))))) - -(defun ruby-insert-end () - (interactive) - (insert "end") - (ruby-indent-line t) - (end-of-line)) - -(cond - ((featurep 'hilit19) - (hilit-set-mode-patterns - 'ruby-mode - '(("[^$\\?]\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)" 1 string) - ("[^$\\?]\\('[^\\']*\\(\\\\\\(.\\|\n\\)[^\\']*\\)*'\\)" 1 string) - ("[^$\\?]\\(`[^\\`]*\\(\\\\\\(.\\|\n\\)[^\\`]*\\)*`\\)" 1 string) - ("^\\s *#.*$" nil comment) - ("[^$@?\\]\\(#[^$@{].*$\\)" 1 comment) - ("[^a-zA-Z_]\\(\\?\\(\\\\[CM]-\\)*.\\)" 1 string) - ("^\\s *\\(require\\|load\\).*$" nil include) - ("^\\s *\\(include\\|alias\\|undef\\).*$" nil decl) - ("^\\s *\\<\\(class\\|def\\|module\\)\\>" "[)\n;]" defun) - ("[^_]\\<\\(begin\\|case\\|else\\|elsif\\|end\\|ensure\\|for\\|if\\|unless\\|rescue\\|then\\|when\\|while\\|until\\|do\\)\\>[^_]" 1 defun) - ("[^_]\\<\\(and\\|break\\|next\\|raise\\|fail\\|in\\|not\\|or\\|redo\\|retry\\|return\\|super\\|yield\\|self\\|nil\\)\\>[^_]" 1 keyword) - ("\\$\\(.\\|\\sw+\\)" nil type) - ("[$@].[a-zA-Z_0-9]*" nil struct) - ("^__END__" nil label)))) - - ((featurep 'font-lock) - (or (boundp 'font-lock-variable-name-face) - (setq font-lock-variable-name-face font-lock-type-face)) - (defvar ruby-font-lock-keywords - (list - (cons (concat - "\\(^\\|[^_]\\)\\b\\(" - (mapconcat - 'identity - '("alias" - "and" - "begin" - "break" - "case" - "class" - "do" - "elsif" - "else" - "fail" - "ensure" - "for" - "end" - "if" - "in" - "module" - "next" - "nil" - "not" - "or" - "raise" - "redo" - "rescue" - "retry" - "return" - "then" - "self" - "super" - "unless" - "undef" - "until" - "when" - "while" - ) - "\\|") - "\\)[ \n\t()]") - 2) - ;; variables - '("nil\\|self\\|TRUE\\|FALSE" - 0 font-lock-variable-name-face) - ;; variables - '("\\[$@].\\([a-zA-Z0-9_]\\)" - 0 font-lock-variable-name-face) - ;; constants - '("\\b[A-Z]+[a-zA-Z0-9_]*" - 0 font-lock-type-face) - ;; functions - '("\\bdef[ \t]+[a-zA-Z_]+[a-zA-Z0-9_]*[?!]?" - 0 font-lock-function-name-face)) - "*Additional expressions to highlight in ruby mode.") - (add-hook 'ruby-mode-hook - (lambda () - (setq font-lock-keywords ruby-font-lock-keywords) - (font-lock-mode 1))))) diff --git a/sample/rubydb2x.el b/sample/rubydb2x.el deleted file mode 100644 index a74265fb0e..0000000000 --- a/sample/rubydb2x.el +++ /dev/null @@ -1,104 +0,0 @@ -(require 'gud) -(provide 'rubydb) - -;; ====================================================================== -;; rubydb functions - -;;; History of argument lists passed to rubydb. -(defvar gud-rubydb-history nil) - -(defun gud-rubydb-massage-args (file args) - (cons "-I" (cons "." (cons "-r" (cons "debug" (cons file args)))))) - -;; There's no guarantee that Emacs will hand the filter the entire -;; marker at once; it could be broken up across several strings. We -;; might even receive a big chunk with several markers in it. If we -;; receive a chunk of text which looks like it might contain the -;; beginning of a marker, we save it here between calls to the -;; filter. -(defvar gud-rubydb-marker-acc "") - -(defun gud-rubydb-marker-filter (string) - (save-match-data - (setq gud-marker-acc (concat gud-marker-acc string)) - (let ((output "")) - - ;; Process all the complete markers in this chunk. - (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" - gud-marker-acc) - (setq - - ;; Extract the frame position from the marker. - gud-last-frame - (cons (substring gud-marker-acc (match-beginning 1) (match-end 1)) - (string-to-int (substring gud-marker-acc - (match-beginning 2) - (match-end 2)))) - - ;; Append any text before the marker to the output we're going - ;; to return - we don't include the marker in this text. - output (concat output - (substring gud-marker-acc 0 (match-beginning 0))) - - ;; Set the accumulator to the remaining text. - gud-marker-acc (substring gud-marker-acc (match-end 0)))) - - ;; Does the remaining text look like it might end with the - ;; beginning of another marker? If it does, then keep it in - ;; gud-marker-acc until we receive the rest of it. Since we - ;; know the full marker regexp above failed, it's pretty simple to - ;; test for marker starts. - (if (string-match "\032.*\\'" gud-marker-acc) - (progn - ;; Everything before the potential marker start can be output. - (setq output (concat output (substring gud-marker-acc - 0 (match-beginning 0)))) - - ;; Everything after, we save, to combine with later input. - (setq gud-marker-acc - (substring gud-marker-acc (match-beginning 0)))) - - (setq output (concat output gud-marker-acc) - gud-marker-acc "")) - - output))) - -(defun gud-rubydb-find-file (f) - (find-file-noselect f)) - -(defvar rubydb-command-name "ruby" - "File name for executing ruby.") - -;;;###autoload -(defun rubydb (command-line) - "Run rubydb on program FILE in buffer *gud-FILE*. -The directory containing FILE becomes the initial working directory -and source-file directory for your debugger." - (interactive - (list (read-from-minibuffer "Run rubydb (like this): " - (if (consp gud-rubydb-history) - (car gud-rubydb-history) - (concat rubydb-command-name " ")) - nil nil - '(gud-rubydb-history . 1)))) - - (gud-overload-functions '((gud-massage-args . gud-rubydb-massage-args) - (gud-marker-filter . gud-rubydb-marker-filter) - (gud-find-file . gud-rubydb-find-file) - )) - (gud-common-init command-line) - - (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.") -; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") - (gud-def gud-step "s" "\C-s" "Step one source line with display.") - (gud-def gud-next "n" "\C-n" "Step one line (skip functions).") - (gud-def gud-cont "c" "\C-r" "Continue with display.") - (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") - (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") - (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") - (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.") - - (setq comint-prompt-regexp "^(rdb:-) ") - (setq paragraph-start comint-prompt-regexp) - (run-hooks 'rubydb-mode-hook) - ) diff --git a/sample/rubydb3x.el b/sample/rubydb3x.el deleted file mode 100644 index 9d4e31f90e..0000000000 --- a/sample/rubydb3x.el +++ /dev/null @@ -1,104 +0,0 @@ -(require 'gud) -(provide 'rubydb) - -;; ====================================================================== -;; rubydb functions - -;;; History of argument lists passed to rubydb. -(defvar gud-rubydb-history nil) - -(defun gud-rubydb-massage-args (file args) - (cons "-r" (cons "debug" args))) - -;; There's no guarantee that Emacs will hand the filter the entire -;; marker at once; it could be broken up across several strings. We -;; might even receive a big chunk with several markers in it. If we -;; receive a chunk of text which looks like it might contain the -;; beginning of a marker, we save it here between calls to the -;; filter. -(defvar gud-rubydb-marker-acc "") - -(defun gud-rubydb-marker-filter (string) - (setq gud-marker-acc (concat gud-marker-acc string)) - (let ((output "")) - - ;; Process all the complete markers in this chunk. - (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" - gud-marker-acc) - (setq - - ;; Extract the frame position from the marker. - gud-last-frame - (cons (substring gud-marker-acc (match-beginning 1) (match-end 1)) - (string-to-int (substring gud-marker-acc - (match-beginning 2) - (match-end 2)))) - - ;; Append any text before the marker to the output we're going - ;; to return - we don't include the marker in this text. - output (concat output - (substring gud-marker-acc 0 (match-beginning 0))) - - ;; Set the accumulator to the remaining text. - gud-marker-acc (substring gud-marker-acc (match-end 0)))) - - ;; Does the remaining text look like it might end with the - ;; beginning of another marker? If it does, then keep it in - ;; gud-marker-acc until we receive the rest of it. Since we - ;; know the full marker regexp above failed, it's pretty simple to - ;; test for marker starts. - (if (string-match "\032.*\\'" gud-marker-acc) - (progn - ;; Everything before the potential marker start can be output. - (setq output (concat output (substring gud-marker-acc - 0 (match-beginning 0)))) - - ;; Everything after, we save, to combine with later input. - (setq gud-marker-acc - (substring gud-marker-acc (match-beginning 0)))) - - (setq output (concat output gud-marker-acc) - gud-marker-acc "")) - - output)) - -(defun gud-rubydb-find-file (f) - (save-excursion - (let ((buf (find-file-noselect f))) - (set-buffer buf) - (gud-make-debug-menu) - buf))) - -(defvar rubydb-command-name "ruby" - "File name for executing ruby.") - -;;;###autoload -(defun rubydb (command-line) - "Run rubydb on program FILE in buffer *gud-FILE*. -The directory containing FILE becomes the initial working directory -and source-file directory for your debugger." - (interactive - (list (read-from-minibuffer "Run rubydb (like this): " - (if (consp gud-rubydb-history) - (car gud-rubydb-history) - (concat rubydb-command-name " ")) - nil nil - '(gud-rubydb-history . 1)))) - - (gud-common-init command-line 'gud-rubydb-massage-args - 'gud-rubydb-marker-filter 'gud-rubydb-find-file) - - (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.") -; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") - (gud-def gud-step "s" "\C-s" "Step one source line with display.") - (gud-def gud-next "n" "\C-n" "Step one line (skip functions).") - (gud-def gud-cont "c" "\C-r" "Continue with display.") - (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") - (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") - (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") - (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.") - - (setq comint-prompt-regexp "^(rdb:-) ") - (setq paragraph-start comint-prompt-regexp) - (run-hooks 'rubydb-mode-hook) - ) diff --git a/sample/sieve.rb b/sample/sieve.rb index 03ff8a67f4..e0bb21d640 100644 --- a/sample/sieve.rb +++ b/sample/sieve.rb @@ -1,18 +1,14 @@ # sieve of Eratosthenes +max = Integer(ARGV.shift || 100) sieve = [] -if ! max = ARGV.shift; max = 100; end -max = max.to_i +for i in 2 .. max + sieve[i] = i +end -print "1" -for i in 2 .. max - begin - for d in sieve - fail if i % d == 0 - end - print ", " - print i - sieve.push(i) - rescue +for i in 2 .. Math.sqrt(max) + next unless sieve[i] + (i*i).step(max, i) do |j| + sieve[j] = nil end end -print "\n" +puts sieve.compact.join(", ") diff --git a/sample/simple-bench.rb b/sample/simple-bench.rb new file mode 100644 index 0000000000..607fdbf6e9 --- /dev/null +++ b/sample/simple-bench.rb @@ -0,0 +1,140 @@ +require 'benchmark' + +def foo0 +end +def foo3 a, b, c +end +def foo6 a, b, c, d, e, f +end + +def iter0 + yield +end + +def iter1 + yield 1 +end + +def iter3 + yield 1, 2, 3 +end + +def iter6 + yield 1, 2, 3, 4, 5, 6 +end + +(1..6).each{|i| + kws = (1..i).map{|e| "k#{e}: #{e}"} + eval %Q{ + def foo_kw#{i}(#{kws.join(', ')}) + end + } + + kws = (1..i).map{|e| "k#{e}:"} + eval %Q{ + def foo_required_kw#{i}(#{kws.join(', ')}) + end + } +} + +(1..6).each{|i| + kws = (1..i).map{|e| "k#{e}: #{e} + 1"} + eval %Q{ + def foo_complex_kw#{i}(#{kws.join(', ')}) + end + } +} + +(1..6).each{|i| + kws = (1..i).map{|e| "k#{e}: #{e}"} + eval %Q{ + def iter_kw#{i} + yield #{kws.join(', ')} + end + } +} + +ary1 = [1] +ary2 = [[1, 2, 3, 4, 5]] + +test_methods = %Q{ + # empty 1 + # empty 2 + foo0 + foo3 1, 2, 3 + foo6 1, 2, 3, 4, 5, 6 + foo_kw1 + foo_kw2 + foo_kw3 + foo_kw4 + foo_kw5 + foo_kw6 + foo_kw6 k1: 1 + foo_kw6 k1: 1, k2: 2 + foo_kw6 k1: 1, k2: 2, k3: 3 + foo_kw6 k1: 1, k2: 2, k3: 3, k4: 4 + foo_kw6 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5 + foo_kw6 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5, k6: 6 + foo_required_kw1 k1: 1 + foo_required_kw2 k1: 1, k2: 2 + foo_required_kw3 k1: 1, k2: 2, k3: 3 + foo_required_kw4 k1: 1, k2: 2, k3: 3, k4: 4 + foo_required_kw5 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5 + foo_required_kw6 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5, k6: 6 + foo_complex_kw1 + foo_complex_kw2 + foo_complex_kw3 + foo_complex_kw4 + foo_complex_kw5 + foo_complex_kw6 + foo_complex_kw6 k1: 1 + foo_complex_kw6 k1: 1, k2: 2 + foo_complex_kw6 k1: 1, k2: 2, k3: 3 + foo_complex_kw6 k1: 1, k2: 2, k3: 3, k4: 4 + foo_complex_kw6 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5 + foo_complex_kw6 k1: 1, k2: 2, k3: 3, k4: 4, k5: 5, k6: 6 + iter0{} + iter1{} + iter1{|a|} + iter3{} + iter3{|a|} + iter3{|a, b, c|} + iter6{} + iter6{|a|} + iter6{|a, b, c, d, e, f, g|} + iter0{|k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil|} + iter_kw1{|k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil|} + iter_kw2{|k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil|} + iter_kw3{|k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil|} + iter_kw4{|k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil|} + iter_kw5{|k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil|} + iter_kw6{|k1: nil, k2: nil, k3: nil, k4: nil, k5: nil, k6: nil|} + ary1.each{|e|} + ary1.each{|e,|} + ary1.each{|a, b, c, d, e|} + ary2.each{|e|} + ary2.each{|e,|} + ary2.each{|a, b, c, d, e|} +} + +N = 10_000_000 + +max_line = test_methods.each_line.max_by{|line| line.strip.size} +max_size = max_line.strip.size + +Benchmark.bm(max_size){|x| + + str = test_methods.each_line.map{|line| line.strip! + next if line.empty? + %Q{ + x.report(#{line.dump}){ + i = 0 + while i<#{N} + #{line} + i+=1 + end + } + } + }.join("\n") + eval str +} diff --git a/sample/svr.rb b/sample/svr.rb index c866407eb0..eb49ccf170 100644 --- a/sample/svr.rb +++ b/sample/svr.rb @@ -1,15 +1,18 @@ # socket example - server side # usage: ruby svr.rb +# this server might be blocked by an ill-behaved client. +# see tsvr.rb which is safe from client blocking. + require "socket" -gs = TCPserver.open(0) +gs = TCPServer.open(0) addr = gs.addr addr.shift -printf("server is on %d\n", addr.join(":")) +printf("server is on %s\n", addr.join(":")) socks = [gs] -while TRUE +loop do nsock = select(socks); next if nsock == nil for s in nsock[0] @@ -22,10 +25,9 @@ while TRUE print(s, " is gone\n") s.close socks.delete(s) - else - if str = s.gets; + # single thread gets may block whole service + elsif str = s.gets s.write(str) - end end end end diff --git a/sample/tempfile.rb b/sample/tempfile.rb new file mode 100644 index 0000000000..5a363614a3 --- /dev/null +++ b/sample/tempfile.rb @@ -0,0 +1,8 @@ +require 'tempfile' + +f = Tempfile.new("foo") +f.print("foo\n") +f.close +f.open +p f.gets # => "foo\n" +f.close! diff --git a/sample/test.rb b/sample/test.rb index 382ca9428a..65dd9abd10 100644..100755 --- a/sample/test.rb +++ b/sample/test.rb @@ -1,943 +1,2 @@ -#! /usr/local/bin/ruby - -$testnum=0 -$ntest=0 -$failed = 0 - -def check(what) - printf "%s\n", what - $what = what - $testnum = 0 -end - -def ok(cond) - $testnum+=1 - $ntest+=1 - if cond - printf "ok %d\n", $testnum - else - where = caller[0] - printf "not ok %s %d -- %s\n", $what, $testnum, where - $failed+=1 - end -end - -# make sure conditional operators work - -check "condition" - -$x = '0'; - -$x == $x && ok(TRUE) -$x != $x && ok(FALSE) -$x == $x || ok(FALSE) -$x != $x || ok(TRUE) - -# first test to see if we can run the tests. - -check "if/unless"; - -$x = 'test'; -ok(if $x == $x then TRUE else FALSE end) -$bad = FALSE -unless $x == $x - $bad = TRUE -end -ok(!$bad) -ok(unless $x != $x then TRUE else FALSE end) - -check "case" - -case 5 -when 1, 2, 3, 4, 6, 7, 8 - ok(FALSE) -when 5 - ok(TRUE) -end - -case 5 -when 5 - ok(TRUE) -when 1..10 - ok(FALSE) -end - -case 5 -when 1..10 - ok(TRUE) -else - ok(FALSE) -end - -case 5 -when 5 - ok(TRUE) -else - ok(FALSE) -end - -case "foobar" -when /^f.*r$/ - ok(TRUE) -else - ok(FALSE) -end - -check "while/until"; - -tmp = open("while_tmp", "w") -tmp.print "tvi925\n"; -tmp.print "tvi920\n"; -tmp.print "vt100\n"; -tmp.print "Amiga\n"; -tmp.print "paper\n"; -tmp.close - -# test break - -tmp = open("while_tmp", "r") -ok(tmp.kind_of?(File)) - -while tmp.gets() - break if /vt100/ -end - -ok(!tmp.eof? && /vt100/) -tmp.close - -# test next -$bad = FALSE -tmp = open("while_tmp", "r") -while tmp.gets() - next if /vt100/; - $bad = 1 if /vt100/; -end -ok(!(!tmp.eof? || /vt100/ || $bad)) -tmp.close - -# test redo -$bad = FALSE -tmp = open("while_tmp", "r") -while tmp.gets() - if gsub!('vt100', 'VT100') - gsub!('VT100', 'Vt100') - redo; - end - $bad = 1 if /vt100/; - $bad = 1 if /VT100/; -end -ok(tmp.eof? && !$bad) -tmp.close - -sum=0 -for i in 1..10 - sum += i - i -= 1 - if i > 0 - redo - end -end -ok(sum == 220) - -# test interval -$bad = FALSE -tmp = open("while_tmp", "r") -while tmp.gets() - break unless 1..2 - if /vt100/ || /Amiga/ || /paper/ - $bad = TRUE - break - end -end -ok(!$bad) -tmp.close - -File.unlink "while_tmp" or `/bin/rm -f "while_tmp"` -ok(!File.exist?("while_tmp")) - -i = 0 -until i>4 - i+=1 -end -ok(i>4) - -# exception handling -check "exception"; - -begin - fail "this must be handled" - ok(FALSE) -rescue - ok(TRUE) -end - -$bad = TRUE -begin - fail "this must be handled no.2" -rescue - if $bad - $bad = FALSE - retry - ok(FALSE) - end -end -ok(TRUE) - -# exception in rescue clause -$string = "this must be handled no.3" -begin - begin - fail "exception in rescue clause" - rescue - fail $string - end - ok(FALSE) -rescue - ok(TRUE) if $! == $string -end - -# exception in ensure clause -begin - begin - fail "this must be handled no.4" - ensure - fail "exception in ensure clause" - end - ok(FALSE) -rescue - ok(TRUE) -end - -$bad = TRUE -begin - begin - fail "this must be handled no.5" - ensure - $bad = FALSE - end -rescue -end -ok(!$bad) - -$bad = TRUE -begin - begin - fail "this must be handled no.6" - ensure - $bad = FALSE - end -rescue -end -ok(!$bad) - -$bad = TRUE -while TRUE - begin - break - ensure - $bad = FALSE - end -end -ok(!$bad) - -check "array" -ok([1, 2] + [3, 4] == [1, 2, 3, 4]) -ok([1, 2] * 2 == [1, 2, 1, 2]) -ok([1, 2] * ":" == "1:2") - -ok([1, 2].hash == [1, 2].hash) - -ok([1,2,3] & [2,3,4] == [2,3]) -ok([1,2,3] | [2,3,4] == [1,2,3,4]) -ok([1,2,3] - [2,3] == [1]) - -$x = [0, 1, 2, 3, 4, 5] -ok($x[2] == 2) -ok($x[1..3] == [1, 2, 3]) -ok($x[1,3] == [1, 2, 3]) - -$x[0, 2] = 10 -ok($x[0] == 10 && $x[1] == 2) - -$x[0, 0] = -1 -ok($x[0] == -1 && $x[1] == 10) - -$x[-1, 1] = 20 -ok($x[-1] == 20 && $x.pop == 20) - -# compact -$x = [nil, 1, nil, nil, 5, nil, nil] -$x.compact! -ok($x == [1, 5]) - -# empty? -ok(!$x.empty?) -$x = [] -ok($x.empty?) - -# sort -$x = ["it", "came", "to", "pass", "that", "..."] -$x = $x.sort.join(" ") -ok($x == "... came it pass that to") -$x = [2,5,3,1,7] -$x.sort!{|a,b| a<=>b} # sort with condition -ok($x == [1,2,3,5,7]) -$x.sort!{|a,b| b-a} # reverse sort -ok($x == [7,5,3,2,1]) - -# split test -$x = "The Book of Mormon" -ok($x.split(//).reverse!.join == "nomroM fo kooB ehT") -ok("1 byte string".split(//).reverse.join(":") == "g:n:i:r:t:s: :e:t:y:b: :1") -$x = "a b c d" -ok($x.split == ['a', 'b', 'c', 'd']) -ok($x.split(' ') == ['a', 'b', 'c', 'd']) - -$x = [1] -ok(($x * 5).join(":") == '1:1:1:1:1') -ok(($x * 1).join(":") == '1') -ok(($x * 0).join(":") == '') - -*$x = 1..7 -ok($x.size == 7) -ok($x == [1, 2, 3, 4, 5, 6, 7]) - -check "hash" -$x = {1=>2, 2=>4, 3=>6} -$y = {1, 2, 2, 4, 3, 6} - -ok($x[1] == 2) - -ok(begin - for k,v in $y - fail if k*2 != v - end - TRUE - rescue - FALSE - end) - -ok($x.length == 3) -ok($x.has_key?(1)) -ok($x.has_value?(4)) -ok($x.indexes(2,3) == [4,6]) -ok($x == (1=>2, 2=>4, 3=>6)) - -$z = $y.keys.join(":") -ok($z == "1:2:3") - -$z = $y.values.join(":") -ok($z == "2:4:6") -ok($x == $y) - -$y.shift -ok($y.length == 2) - -$z = [1,2] -$y[$z] = 256 -ok($y[$z] == 256) - -check "iterator" - -ok(!iterator?) - -def ttt - ok(iterator?) -end -ttt{} - -# yield at top level -ok(!defined?(yield)) - -$x = [1, 2, 3, 4] -$y = [] - -# iterator over array -for i in $x - $y.push i -end -ok($x == $y) - -# nested iterator -def tt - 1.upto(10) {|i| - yield i - } -end - -tt{|i| break if i == 5} -ok(i == 5) - -# iterator break/redo/next/retry -unless defined? loop - def loop - while TRUE - yield - end - end - ok(FALSE) -else - ok(TRUE) -end - -done = TRUE -loop{ - break - done = FALSE -} -ok(done) - -done = FALSE -$bad = FALSE -loop { - break if done - done = TRUE - next - $bad = TRUE -} -ok(!$bad) - -done = FALSE -$bad = FALSE -loop { - break if done - done = TRUE - redo - $bad = TRUE -} -ok(!$bad) - -$x = [] -for i in 1 .. 7 - $x.push i -end -ok($x.size == 7) -ok($x == [1, 2, 3, 4, 5, 6, 7]) - -$done = FALSE -$x = [] -for i in 1 .. 7 # see how retry works in iterator loop - if i == 4 and not $done - $done = TRUE - retry - end - $x.push(i) -end -ok($x.size == 10) -ok($x == [1, 2, 3, 1, 2, 3, 4, 5, 6, 7]) - -check "bignum" -def fact(n) - return 1 if n == 0 - f = 1 - while n>0 - f *= n - n -= 1 - end - return f -end -fact(3) -$x = fact(40) -ok($x == $x) -ok($x == fact(40)) -ok($x < $x+2) -ok($x > $x-2) -ok($x == 815915283247897734345611269596115894272000000000) -ok($x != 815915283247897734345611269596115894272000000001) -ok($x+1 == 815915283247897734345611269596115894272000000001) -ok($x/fact(20) == 335367096786357081410764800000) -$x = -$x -ok($x == -815915283247897734345611269596115894272000000000) -ok(2-(2**32) == -(2**32-2)) -ok(2**32 - 5 == (2**32-3)-2) - -$good = TRUE; -for i in 1000..1024 - $good = FALSE if ((1<<i) != (2**i)) -end -ok($good) - -$good = TRUE; -n1=1<<1000 -for i in 1000..1024 - $good = FALSE if ((1<<i) != n1) - n1 *= 2 -end -ok($good) - -$good = TRUE; -n2=n1 -for i in 1..10 - n1 = n1 / 2 - n2 = n2 >> 1 - $good = FALSE if (n1 != n2) -end -ok($good) - -$good = TRUE; -for i in 4000..4192 - n1 = 1 << i; - $good = FALSE if ((n1**2-1) / (n1+1) != (n1-1)) -end -ok($good) - -check "string & char" - -ok("abcd" == "abcd") -ok("abcd" =~ "abcd") -ok("abcd" === "abcd") -ok(("abc" =~ /^$/) == FALSE) -ok(("abc\n" =~ /^$/) == FALSE) -ok(("abc" =~ /^d*$/) == FALSE) -ok(("abc" =~ /d*$/) == 3) -ok("" =~ /^$/) -ok("\n" =~ /^$/) -ok("a\n\n" =~ /^$/) - -$foo = "abc" -ok("#$foo = abc" == "abc = abc") -ok("#{$foo} = abc" == "abc = abc") - -foo = "abc" -ok("#{foo} = abc" == "abc = abc") - -ok('-' * 5 == '-----') -ok('-' * 1 == '-') -ok('-' * 0 == '') - -foo = '-' -ok(foo * 5 == '-----') -ok(foo * 1 == '-') -ok(foo * 0 == '') - -$x = "a.gif" -ok($x.sub(/.*\.([^\.]+)$/, '\1') == "gif") -ok($x.sub(/.*\.([^\.]+)$/, 'b.\1') == "b.gif") -ok($x.sub(/.*\.([^\.]+)$/, '\2') == "") -ok($x.sub(/.*\.([^\.]+)$/, 'a\2b') == "ab") -ok($x.sub(/.*\.([^\.]+)$/, '<\&>') == "<a.gif>") - -# character constants(assumes ASCII) -ok("a"[0] == ?a) -ok(?a == ?a) -ok(?\C-a == 1) -ok(?\M-a == 225) -ok(?\M-\C-a == 129) - -$x = "abcdef" -$y = [ ?a, ?b, ?c, ?d, ?e, ?f ] -$bad = FALSE -$x.each_byte {|i| - if i != $y.shift - $bad = TRUE - break - end -} -ok(!$bad) - -check "asignment" -a = nil -ok(defined?(a)) -ok(a == nil) - -# multiple asignment -a, b = 1, 2 -ok(a == 1 && b == 2) - -a, b = b, a -ok(a == 2 && b == 1) - -a, = 1,2 -ok(a == 1) - -a, *b = 1, 2, 3 -ok(a == 1 && b == [2, 3]) - -*a = 1, 2, 3 -ok(a == [1, 2, 3]) - -check "call" -def aaa(a, b=100, *rest) - res = [a, b] - res += rest if rest - return res -end - -# not enough argument -begin - aaa() # need at least 1 arg - ok(FALSE) -rescue - ok(TRUE) -end - -begin - aaa # no arg given (exception raised) - ok(FALSE) -rescue - ok(TRUE) -end - -begin - if aaa(1) == [1, 100] - ok(TRUE) - else - fail - end -rescue - ok(FALSE) -end - -begin - if aaa(1, 2) == [1, 2] - ok(TRUE) - else - fail - end -rescue - ok(FALSE) -end - -ok(aaa(1, 2, 3, 4) == [1, 2, 3, 4]) -ok(aaa(1, *[2, 3, 4]) == [1, 2, 3, 4]) - -check "proc" -$proc = proc{|i| i} -ok($proc.call(2) == 2) -ok($proc.call(3) == 3) - -$proc = proc{|i| i*2} -ok($proc.call(2) == 4) -ok($proc.call(3) == 6) - -proc{ - iii=5 # dynamic local variable - $proc = proc{|i| - iii = i - } - $proc2 = proc { - $x = iii # dynamic variables shared by procs - } - # scope of dynamic variables - ok(defined?(iii)) -}.call -ok(!defined?(iii)) # out of scope - -$x=0 -$proc.call(5) -$proc2.call -ok($x == 5) - -if defined? Process.kill - check "signal" - - $x = 0 - trap "SIGINT", proc{|sig| $x = 2} - Process.kill "SIGINT", $$ - sleep 0.1 - ok($x == 2) - - trap "SIGINT", proc{fail "Interrupt"} - - x = FALSE - begin - Process.kill "SIGINT", $$ - sleep 0.1 - rescue - x = $! - end - ok(x && x =~ /Interrupt/) -else - ok(FALSE) -end - -check "eval" -ok(eval("") == nil) -$bad=FALSE -eval 'while FALSE; $bad = TRUE; print "foo\n" end' -ok(!$bad) - -ok(eval('TRUE')) - -$foo = 'ok(TRUE)' -begin - eval $foo -rescue - ok(FALSE) -end - -ok(eval("$foo") == 'ok(TRUE)') -ok(eval("TRUE") == TRUE) -i = 5 -ok(eval("i == 5")) -ok(eval("i") == 5) -ok(eval("defined? i")) - -# eval with binding -def test_ev - local1 = "local1" - lambda { - local2 = "local2" - return binding - }.call -end - -$x = test_ev -ok(eval("local1", $x) == "local1") # static local var -ok(eval("local2", $x) == "local2") # dynamic local var -$bad = TRUE -begin - p eval("local1") -rescue NameError # must raise error - $bad = FALSE -end -ok(!$bad) - -module EvTest - EVTEST1 = 25 - evtest2 = 125 - $x = binding -end -ok(eval("EVTEST1", $x) == 25) # constant in module -ok(eval("evtest2", $x) == 125) # local var in module -$bad = TRUE -begin - eval("EVTEST1") -rescue NameError # must raise error - $bad = FALSE -end -ok(!$bad) - -check "system" -ok(`echo foobar` == "foobar\n") -ok(`./ruby -e 'print "foobar"'` == 'foobar') - -tmp = open("script_tmp", "w") -tmp.print "print $zzz\n"; -tmp.close - -ok(`./ruby -s script_tmp -zzz` == 'TRUE') -ok(`./ruby -s script_tmp -zzz=555` == '555') - -tmp = open("script_tmp", "w") -tmp.print "#! /usr/local/bin/ruby -s\n"; -tmp.print "print $zzz\n"; -tmp.close - -ok(`./ruby script_tmp -zzz=678` == '678') - -tmp = open("script_tmp", "w") -tmp.print "this is a leading junk\n"; -tmp.print "#! /usr/local/bin/ruby -s\n"; -tmp.print "print $zzz\n"; -tmp.print "__END__\n"; -tmp.print "this is a trailing junk\n"; -tmp.close - -ok(`./ruby -x script_tmp` == 'nil') -ok(`./ruby -x script_tmp -zzz=555` == '555') - -tmp = open("script_tmp", "w") -for i in 1..5 - tmp.print i, "\n" -end -tmp.close - -`./ruby -i.bak -pe 'sub(/^[0-9]+$/){$&.to_i * 5}' script_tmp` -done = TRUE -tmp = open("script_tmp", "r") -while tmp.gets - if $_.to_i % 5 != 0 - done = FALSE - break - end -end -tmp.close -ok(done) - -File.unlink "script_tmp" or `/bin/rm -f "script_tmp"` -File.unlink "script_tmp.bak" or `/bin/rm -f "script_tmp.bak"` - -check "const" -TEST1 = 1 -TEST2 = 2 - -module Const - TEST3 = 3 - TEST4 = 4 -end - -module Const2 - TEST3 = 6 - TEST4 = 8 -end - -include Const - -ok([TEST1,TEST2,TEST3,TEST4] == [1,2,3,4]) - -include Const2 -STDERR.print "intentionally redefines TEST3, TEST4\n" if $VERBOSE -ok([TEST1,TEST2,TEST3,TEST4] == [1,2,6,8]) - -check "clone" -foo = Object.new -def foo.test - "test" -end -bar = foo.clone -def bar.test2 - "test2" -end - -ok(bar.test2 == "test2") -ok(bar.test == "test") -ok(foo.test == "test") - -begin - foo.test2 - ok FALSE -rescue - ok TRUE -end - -check "pack" - -$format = "c2x5CCxsdila6"; -# Need the expression in here to force ary[5] to be numeric. This avoids -# test2 failing because ary2 goes str->numeric->str and ary does not. -ary = [1,-100,127,128,32767,987.654321098 / 100.0,12345,123456,"abcdef"] -$x = ary.pack($format) -ary2 = $x.unpack($format) - -ok(ary.length == ary2.length) -ok(ary.join(':') == ary2.join(':')) -ok($x =~ /def/) - -check "math" -ok(Math.sqrt(4) == 2) - -include Math -ok(sqrt(4) == 2) - -check "struct" -struct_test = Struct.new("Test", :foo, :bar) -ok(struct_test == Struct::Test) - -test = struct_test.new(1, 2) -ok(test.foo == 1 && test.bar == 2) -ok(test[0] == 1 && test[1] == 2) - -a, b = test -ok(a == 1 && b == 2) - -test[0] = 22 -ok(test.foo == 22) - -test.bar = 47 -ok(test.bar == 47) - -check "variable" -ok($$.instance_of?(Fixnum)) - -# read-only variable -begin - $$ = 5 - ok FALSE -rescue - ok TRUE -end - -foobar = "foobar" -$_ = foobar -ok($_ == foobar) - -check "trace" -$x = 1234 -$y = 0 -trace_var :$x, proc{$y = $x} -$x = 40414 -ok($y == $x) - -untrace_var :$x -$x = 19660208 -ok($y != $x) - -trace_var :$x, proc{$x *= 2} -$x = 5 -ok($x == 10) - -untrace_var :$x - -check "defined?" - -ok(defined?($x)) # global variable -ok(defined?($x) == 'global-variable')# returns description - -foo=5 -ok(defined?(foo)) # local variable - -ok(defined?(Array)) # constant -ok(defined?(Object.new)) # method -ok(!defined?(Object.print)) # private method -ok(defined?(1 == 2)) # operator expression - -def defined_test - return !defined?(yield) -end - -ok(defined_test) # not iterator -ok(!defined_test{}) # called as iterator - -check "alias" -class Alias0 - def foo; "foo" end -end -class Alias1<Alias0 - alias bar foo - def foo; "foo+" + super end -end -class Alias2<Alias1 - alias baz foo - undef foo -end - -x = Alias2.new -ok(x.bar == "foo") -ok(x.baz == "foo+foo") - -# check for cache -ok(x.baz == "foo+foo") - -class Alias3<Alias2 - def foo - defined? super - end - def bar - defined? super - end - def quux - defined? super - end -end -x = Alias3.new -ok(!x.foo) -ok(x.bar) -ok(!x.quux) - -check "gc" -begin - 1.upto(10000) { - tmp = [0,1,2,3,4,5,6,7,8,9] - } - tmp = nil - ok TRUE -rescue - ok FALSE -end - -if $failed > 0 - printf "test: %d failed %d\n", $ntest, $failed -else - printf "end of test(test: %d)\n", $ntest -end +# backward compatibility for chkbuild +require_relative '../basictest/test' diff --git a/sample/testunit/adder.rb b/sample/testunit/adder.rb new file mode 100644 index 0000000000..aa5c88cc7b --- /dev/null +++ b/sample/testunit/adder.rb @@ -0,0 +1,13 @@ +# Author:: Nathaniel Talbott. +# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. +# License:: Ruby license. + +class Adder + def initialize(number) + @number = number + end + def add(number) + return @number + number + end +end + diff --git a/sample/testunit/subtracter.rb b/sample/testunit/subtracter.rb new file mode 100644 index 0000000000..2c08247805 --- /dev/null +++ b/sample/testunit/subtracter.rb @@ -0,0 +1,12 @@ +# Author:: Nathaniel Talbott. +# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. +# License:: Ruby license. + +class Subtracter + def initialize(number) + @number = number + end + def subtract(number) + return @number - number + end +end diff --git a/sample/testunit/tc_adder.rb b/sample/testunit/tc_adder.rb new file mode 100644 index 0000000000..8453beb20a --- /dev/null +++ b/sample/testunit/tc_adder.rb @@ -0,0 +1,18 @@ +# Author:: Nathaniel Talbott. +# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. +# License:: Ruby license. + +require 'test/unit' +require 'adder' + +class TC_Adder < Test::Unit::TestCase + def setup + @adder = Adder.new(5) + end + def test_add + assert_equal(7, @adder.add(2), "Should have added correctly") + end + def teardown + @adder = nil + end +end diff --git a/sample/testunit/tc_subtracter.rb b/sample/testunit/tc_subtracter.rb new file mode 100644 index 0000000000..d2c8313350 --- /dev/null +++ b/sample/testunit/tc_subtracter.rb @@ -0,0 +1,18 @@ +# Author:: Nathaniel Talbott. +# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. +# License:: Ruby license. + +require 'test/unit' +require 'subtracter' + +class TC_Subtracter < Test::Unit::TestCase + def setup + @subtracter = Subtracter.new(5) + end + def test_subtract + assert_equal(3, @subtracter.subtract(2), "Should have subtracted correctly") + end + def teardown + @subtracter = nil + end +end diff --git a/sample/testunit/ts_examples.rb b/sample/testunit/ts_examples.rb new file mode 100644 index 0000000000..3d24dd6522 --- /dev/null +++ b/sample/testunit/ts_examples.rb @@ -0,0 +1,7 @@ +# Author:: Nathaniel Talbott. +# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved. +# License:: Ruby license. + +require 'test/unit' +require 'tc_adder' +require 'tc_subtracter' diff --git a/sample/time.rb b/sample/time.rb index f4f4ec4883..e16912052e 100755..100644 --- a/sample/time.rb +++ b/sample/time.rb @@ -1,8 +1,12 @@ -#! /usr/local/bin/ruby -cmd = ARGV.join(" ") +#! /usr/bin/env ruby + b = Time.now -system(cmd) +system(*ARGV) e = Time.now -ut, st, cut, cst = Time.times -total = (e - b).to_f -printf STDERR, "%11.1f real %11.1f user %11.1f sys\n", total, cut, cst + +tms = Process.times +real = e - b +user = tms.cutime +sys = tms.cstime + +STDERR.printf("%11.1f real %11.1f user %11.1f sys\n", real, user, sys) diff --git a/sample/timeout.rb b/sample/timeout.rb new file mode 100644 index 0000000000..8d25d72a76 --- /dev/null +++ b/sample/timeout.rb @@ -0,0 +1,42 @@ +require 'timeout' + +def progress(n = 5) + n.times {|i| print i; STDOUT.flush; sleep 1; i+= 1} + puts "never reach" +end + +p timeout(5) { + 45 +} +p timeout(5, Timeout::Error) { + 45 +} +p timeout(nil) { + 54 +} +p timeout(0) { + 54 +} +begin + timeout(5) {progress} +rescue => e + puts e.message +end +begin + timeout(3) { + begin + timeout(5) {progress} + rescue => e + puts "never reach" + end + } +rescue => e + puts e.message +end +class MyTimeout < StandardError +end +begin + timeout(2, MyTimeout) {progress} +rescue MyTimeout => e + puts e.message +end diff --git a/sample/tkbiff.rb b/sample/tkbiff.rb deleted file mode 100644 index d2d7bf7beb..0000000000 --- a/sample/tkbiff.rb +++ /dev/null @@ -1,149 +0,0 @@ -#! /usr/local/bin/ruby - -if ARGV[0] != '-d' - unless $DEBUG - exit if fork - end -else - ARGV.shift -end - -if ARGV.length == 0 - if ENV['MAIL'] - $spool = ENV['MAIL'] - else - $spool = '/usr/spool/mail/' + ENV['USER'] - end -else - $spool = ARGV[0] -end - -require "parsedate" -require "base64" - -include ParseDate - -class Mail - def Mail.new(f) - if !f.kind_of?(IO) - f = open(f, "r") - me = super - f.close - else - me = super - end - return me - end - - def initialize(f) - @header = {} - @body = [] - while f.gets() - $_.chop! - next if /^From / # skip From-line - break if /^$/ # end of header - if /^(\S+):\s*(.*)/ - @header[attr = $1.capitalize] = $2 - elsif attr - sub(/^\s*/, '') - @header[attr] += "\n" + $_ - end - end - - return if ! $_ - - while f.gets() - break if /^From / - @body.push($_) - end - end - - def header - return @header - end - - def body - return @body - end - -end - -require "tkscrollbox" - -$top = TkRoot.new -$top.withdraw -$list = TkScrollbox.new($top) { - relief 'raised' - width 80 - height 8 - setgrid 'yes' - pack -} -TkButton.new($top) { - text 'Dismiss' - command proc {$top.withdraw} - pack('fill'=>'both','expand'=>'yes') -} -$top.bind "Control-c", proc{exit} -$top.bind "Control-q", proc{exit} -$top.bind "space", proc{exit} - -$spool_size = 0 -$check_time = Time.now - -def check - $check_time = Time.now - size = File.size($spool) - if size and size != $spool_size - $spool_size = size - pop_up if size > 0 - end - Tk.after 5000, proc{check} -end - -if defined? Thread - Thread.start do - loop do - sleep 600 - if Time.now - $check_time > 200 - Tk.after 5000, proc{check} - end - end - end -end - -def pop_up - outcount = 0; - $list.delete 0, 'end' - f = open($spool, "r") - while !f.eof? - mail = Mail.new(f) - date, from, subj = mail.header['Date'], mail.header['From'], mail.header['Subject'] - next if !date - y = m = d = 0 - y, m, d = parsedate(date) if date - from = "sombody@somewhere" if ! from - subj = "(nil)" if ! subj - from = decode_b(from) - subj = decode_b(subj) - $list.insert 'end', format('%-02d/%02d/%02d [%-28.28s] %s',y,m,d,from,subj) - outcount += 1 - end - f.close - if outcount == 0 - $list.insert 'end', "You have no mail." - else - $list.see 'end' - end - $top.deiconify - Tk.after 2000, proc{$top.withdraw} -end - -$list.insert 'end', "You have no mail." -check -Tk.after 2000, proc{$top.withdraw} -begin - Tk.mainloop -rescue - `echo #$! > /tmp/tkbiff` -end diff --git a/sample/tkbrowse.rb b/sample/tkbrowse.rb deleted file mode 100644 index d127996173..0000000000 --- a/sample/tkbrowse.rb +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/local/bin/ruby -# -# This script generates a directory browser, which lists the working -# directory and allows you to open files or subdirectories by -# double-clicking. - -# Create a scrollbar on the right side of the main window and a listbox -# on the left side. - -require "tkscrollbox" - -list = TkScrollbox.new { - relief 'raised' - width 20 - height 20 - setgrid 'yes' - pack -} - -# The procedure below is invoked to open a browser on a given file; if the -# file is a directory then another instance of this program is invoked; if -# the file is a regular file then the Mx editor is invoked to display -# the file. - -def browse (dir, file) - if dir != "." - file="#{dir}/#{file}" - if File.directory? file - system "browse #{file} &" - else - if File.file? file - if ENV['EDITOR'] - system format("%s %s&", ENV['EDITOR'], file) - else - sysmte "xedit #{file}&" - end - else - STDERR.print "\"#{file}\" isn't a directory or regular file" - end - end - end -end - -# Fill the listbox with a list of all the files in the directory (run -# the "ls" command to get that information). - -if ARGV.length>0 - dir = ARGV[0] -else - dir="." -end -list.insert 'end', *`ls #{dir}`.split - -# Set up bindings for the browser. - -list.focus -list.bind "Control-q", proc{exit} -list.bind "Control-c", proc{exit} -list.bind "Control-p", proc{ - print "selection <", TkSelection.get, ">\n" -} - -list.bind "Double-Button-1", proc{ - for i in TkSelection.get.split - print "clicked ", i, "\n" - browse dir, i - end -} -Tk.mainloop diff --git a/sample/tkdialog.rb b/sample/tkdialog.rb deleted file mode 100644 index e83e16d0a8..0000000000 --- a/sample/tkdialog.rb +++ /dev/null @@ -1,62 +0,0 @@ -#! /usr/local/bin/ruby -require "tk" - -root = TkFrame.new -top = TkFrame.new(root) { - relief 'raised' - border 1 -} -msg = TkMessage.new(top) { - text "File main.c hasn't been saved to disk since \ -it was last modified. What should I do?" - justify 'center' - aspect 200 - font '-Adobe-helvetica-medium-r-normal--*-240*' - pack('padx'=>5, 'pady'=>5, 'expand'=>'yes') -} -top.pack('fill'=>'both') -root.pack - -bot = TkFrame.new(root) { - relief 'raised' - border 1 -} - -TkFrame.new(bot) { |left| - relief 'sunken' - border 1 - pack('side'=>'left', 'expand'=>'yes', 'padx'=>10, 'pady'=> 10) - TkButton.new(left) { - text "Save File" - command "quit 'save'" - pack('expand'=>'yes','padx'=>6,'pady'=> 6) - top.bind "Enter", proc{state 'active'} - msg.bind "Enter", proc{state 'active'} - bot.bind "Enter", proc{state 'active'} - top.bind "Leave", proc{state 'normal'} - msg.bind "Leave", proc{state 'normal'} - bot.bind "Leave", proc{state 'normal'} - Tk.root.bind "ButtonRelease-1", proc{quit 'save'} - Tk.root.bind "Return", proc{quit 'save'} - } -} -TkButton.new(bot) { - text "Quit Anyway" - command "quit 'quit'" - pack('side'=>'left', 'expand'=>'yes', 'padx'=>10) -} -TkButton.new(bot) { - text "Return To Editor" - command "quit 'return'" - pack('side'=>'left', 'expand'=>'yes', 'padx'=>10) -} -bot.pack -root.pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes') - -def quit(button) - print "aaa\n" - print "You pressed the \"#{button}\" button; bye-bye!\n" - exit -end - -Tk.mainloop diff --git a/sample/tkfrom.rb b/sample/tkfrom.rb deleted file mode 100644 index b0ef8995ca..0000000000 --- a/sample/tkfrom.rb +++ /dev/null @@ -1,126 +0,0 @@ -#! /usr/local/bin/ruby - -require "parsedate" -require "base64" - -include ParseDate - -class Mail - def Mail.new(f) - if !f.kind_of?(IO) - f = open(f, "r") - me = super(f) - f.close - else - me = super - end - return me - end - - def initialize(f) - @header = {} - @body = [] - while f.gets() - $_.chop! - next if /^From / # skip From-line - break if /^$/ # end of header - if /^(\S+):\s*(.*)/ - @header[attr = $1.capitalize] = $2 - elsif attr - sub(/^\s*/, '') - @header[attr] += "\n" + $_ - end - end - - return if ! $_ - - while f.gets() - break if /^From / - @body.push($_) - end - end - - def header - return @header - end - - def body - return @body - end - -end - -if ARGV.length == 0 - if ENV['MAIL'] - ARGV[0] = ENV['MAIL'] - elsif ENV['USER'] - ARGV[0] = '/usr/spool/mail/' + ENV['USER'] - elsif ENV['LOGNAME'] - ARGV[0] = '/usr/spool/mail/' + ENV['LOGNAME'] - end -end - -require "tk" -list = scroll = nil -TkFrame.new{|f| - list = TkListbox.new(f) { - yscroll proc{|idx| - scroll.set *idx - } - relief 'raised' -# geometry "80x5" - width 80 - height 5 - setgrid 'yes' - pack('side'=>'left','fill'=>'both','expand'=>'yes') - } - scroll = TkScrollbar.new(f) { - command proc{|idx| - list.yview *idx - } - pack('side'=>'right','fill'=>'y') - } - pack -} -root = Tk.root -TkButton.new(root) { - text 'Dismiss' - command proc {exit} - pack('fill'=>'both','expand'=>'yes') -} -root.bind "Control-c", proc{exit} -root.bind "Control-q", proc{exit} -root.bind "space", proc{exit} - -$outcount = 0; -for file in ARGV - next if !File.exist?(file) - f = open(file, "r") - while !f.eof - mail = Mail.new(f) - date = mail.header['Date'] - next if !date - from = mail.header['From'] - subj = mail.header['Subject'] - y = m = d = 0 - y, m, d = parsedate(date) if date - from = "sombody@somewhere" if ! from - subj = "(nil)" if ! subj - from = decode_b(from) - subj = decode_b(subj) - list.insert 'end', format('%-02d/%02d/%02d [%-28.28s] %s',y,m,d,from,subj) - $outcount += 1 - end - f.close - list.see 'end' -end - -limit = 10000 -if $outcount == 0 - list.insert 'end', "You have no mail." - limit = 2000 -end -Tk.after limit, proc{ - exit -} -Tk.mainloop diff --git a/sample/tkhello.rb b/sample/tkhello.rb deleted file mode 100644 index 1ff1403e71..0000000000 --- a/sample/tkhello.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "tk" - -TkButton.new { - text 'hello' - command proc{print "hello\n"} - pack('fill'=>'x') -} -TkButton.new { - text 'quit' - command 'exit' - pack('fill'=>'x') -} -Tk.mainloop diff --git a/sample/tkline.rb b/sample/tkline.rb deleted file mode 100644 index 63d763a680..0000000000 --- a/sample/tkline.rb +++ /dev/null @@ -1,46 +0,0 @@ - -$tk_thread_safe = TRUE -require "tkclass" - -$tkline_init = FALSE -def start_random - return if $tkline_init - $tkline_init = TRUE - if defined? Thread - Thread.start do - loop do - sleep 2 - Line.new($c, rand(400), rand(200), rand(400), rand(200)) - end - end - end -end - -$c = Canvas.new -$c.pack -$start_x = start_y = 0 - -def do_press(x, y) - $start_x = x - $start_y = y - $current_line = Line.new($c, x, y, x, y) - start_random -end -def do_motion(x, y) - if $current_line - $current_line.coords $start_x, $start_y, x, y - end -end - -def do_release(x, y) - if $current_line - $current_line.coords $start_x, $start_y, x, y - $current_line.fill 'black' - $current_line = nil - end -end - -$c.bind("1", proc{|e| do_press e.x, e.y}) -$c.bind("B1-Motion", proc{|x, y| do_motion x, y}, "%x %y") -$c.bind("ButtonRelease-1", proc{|x, y| do_release x, y}, "%x %y") -Tk.mainloop diff --git a/sample/tktimer.rb b/sample/tktimer.rb deleted file mode 100644 index 34377e2f39..0000000000 --- a/sample/tktimer.rb +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/local/bin/ruby -# This script generates a counter with start and stop buttons. - -require "tk" -$label = TkLabel.new { - text '0.00' - relief 'raised' - width 10 - pack('side'=>'bottom', 'fill'=>'both') -} - -TkButton.new { - text 'Start' - command proc { - if $stopped - $stopped = FALSE - tick - end - } - pack('side'=>'left','fill'=>'both','expand'=>'yes') -} -TkButton.new { - text 'Stop' - command proc{ - exit if $stopped - $stopped = TRUE - } - pack('side'=>'right','fill'=>'both','expand'=>'yes') -} - -$seconds=0 -$hundredths=0 -$stopped=TRUE - -def tick - if $stopped then return end - Tk.after 50, proc{tick} - $hundredths+=5 - if $hundredths >= 100 - $hundredths=0 - $seconds+=1 - end - $label.text format("%d.%02d", $seconds, $hundredths) -end - -root = Tk.root -root.bind "Control-c", proc{root.destroy} -root.bind "Control-q", proc{root.destroy} -Tk.root.focus -Tk.mainloop diff --git a/sample/trick2013/README.md b/sample/trick2013/README.md new file mode 100644 index 0000000000..d6458c9d51 --- /dev/null +++ b/sample/trick2013/README.md @@ -0,0 +1,15 @@ +This directory contains the award-winning entries of +the 1st Transcendental Ruby Imbroglio Contest for rubyKaigi (TRICK 2013). + +THESE ARE BAD EXAMPLES! You must NOT use them as a sample code. + +* kinaba/entry.rb: "Best pangram" - Gold award +* mame/entry.rb: "Most classic" - Bronze award +* shinh/entry.rb: "Most Readable" - Silver award +* yhara/entry.rb: "Worst abuse of constants" - Dishonorable mention + +These files are licensed under MIT license. + +For the contest outline and other winning entries, see: + +https://github.com/tric/trick2013 diff --git a/sample/trick2013/kinaba/authors.markdown b/sample/trick2013/kinaba/authors.markdown new file mode 100644 index 0000000000..84c011ee05 --- /dev/null +++ b/sample/trick2013/kinaba/authors.markdown @@ -0,0 +1,3 @@ +* kinaba + * kiki@kmonos.net + * cctld: jp diff --git a/sample/trick2013/kinaba/entry.rb b/sample/trick2013/kinaba/entry.rb new file mode 100644 index 0000000000..8a3f855e46 --- /dev/null +++ b/sample/trick2013/kinaba/entry.rb @@ -0,0 +1 @@ +!@THEqQUICKbBROWNfFXjJMPSvVLAZYDGgkyz&[%r{\"}mosx,4>6]|?'while(putc 3_0-~$.+=9/2^5;)<18*7and:`# diff --git a/sample/trick2013/kinaba/remarks.markdown b/sample/trick2013/kinaba/remarks.markdown new file mode 100644 index 0000000000..a454a5f0a1 --- /dev/null +++ b/sample/trick2013/kinaba/remarks.markdown @@ -0,0 +1,37 @@ +### Remarks + +Just run it with no argument: + + ruby entry.rb + +I confirmed the following implementations/platforms: + +* ruby 2.0.0p0 (2013-02-24) [i386-mswin32\_100] + +### Description + +The program prints each ASCII character from 0x20 ' ' to 0x7e '~' exactly once. + +The program contains each ASCII character from 0x20 ' ' to 0x7e '~' exactly once. + +### Internals + +The algorthim is the obvious loop "32.upto(126){|x| putc x}". + +It is not so hard to transform it to use each character *at most once*. The only slight difficulty comes from the constraint that we cannot "declare and then use" variables, because then the code will contain the variable name twice. This restriction is worked around by the $. global variable, the best friend of Ruby golfers. + +The relatively interesting part is to use all the charcters *at least once*. Of course, this is easily accomplished by putting everything into a comment (i.e., #unused...) or to a string literal (%(unused...), note that normal string literals are forbidden since they use quotation marks twice). Hey, but that's not fun at all! I tried to minimize the escapeway. + +* "@THEqQUICKbBROWNfFXjJMPSvVLAZYDGgkyz". Trash box of unused alphabet. I wish I could have used "gkyz" somewhere else. + +* "%r{\"}mosx". Regex literal, with %-syntax. I don't even know what each m,o,s,x means... + +* "?'" Symbol literal. The quote characters (' " \`) are the first obstacle to this trial because they have to be used in pair usually. These are escaped as \" and ?' and :\`. + +* "4>6" "3\_0-~$.+=9/2^5" "18\*7". I had to consume many arithmetic operators +-\*/^~<>, but I only have ten literals 0 to 9 and $. as operands. Besides I have to express the print loop. This is an interesting puzzle. + +* "(putc ...;)<18*7". Trail semicolon doesn't change the value of the expression. + +### Limitation + +n/a. diff --git a/sample/trick2013/mame/authors.markdown b/sample/trick2013/mame/authors.markdown new file mode 100644 index 0000000000..e99cd71554 --- /dev/null +++ b/sample/trick2013/mame/authors.markdown @@ -0,0 +1,3 @@ +* Yusuke Endoh + * mame@tsg.ne.jp + * cctld: jp diff --git a/sample/trick2013/mame/entry.rb b/sample/trick2013/mame/entry.rb new file mode 100644 index 0000000000..8abfc2be40 --- /dev/null +++ b/sample/trick2013/mame/entry.rb @@ -0,0 +1,97 @@ + eval$C=%q(at_exit{ + open("/dev/dsp","wb"){|g|h=[0]*80 + $><<"\s"*18+"eval$C=%q(#$C);S=%:" + (S<<m=58).lines{|l|s=[128]*n=20E2 + t=0; h.map!{|v|d=?!==l[ + t]?1 :(l[ + t]== ?#)? + 0*v= 6:03 + (v<1 ?[]: + 0..n -1). + each {|z| + s[z] +=2* + M.sin(($*[0] ||1) + .to_f*M.sin(y= 40*(z+m)*2** + (t/12E0)/463)+ y)*(v-z*d/n)}; + t+=1;v-d};m+= n;g.flush<<(s. + pack"C*"); puts(l)}}};M= + Math);S=%: + + Jesu, Joy of Man's Desiring + Johann Sebastian Bach + + # + | # + | # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # + # # # # + | | | # + | #| # + # # | # + | | | # + | | # # + # # # # + | | # | + | | # # + # # # # + | | | # + | | # + # # # # + | | # | + | # # | + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | | # # + # # # # + | | | # + | # # + # # # + | | | # + | # | # + # # # # + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | : diff --git a/sample/trick2013/mame/music-box.mp4 b/sample/trick2013/mame/music-box.mp4 Binary files differnew file mode 100644 index 0000000000..6d1e87c01c --- /dev/null +++ b/sample/trick2013/mame/music-box.mp4 diff --git a/sample/trick2013/mame/remarks.markdown b/sample/trick2013/mame/remarks.markdown new file mode 100644 index 0000000000..8c1988c809 --- /dev/null +++ b/sample/trick2013/mame/remarks.markdown @@ -0,0 +1,47 @@ +### Remarks + +Run the program under a platform that `/dev/dsp` is available. +For example, if you are using pulseaudio, use `padsp`: + + padsp ruby entry.rb + +Please see Limitation if you want to run this program on os x. + +I confirmed the following platforms. + +* ruby 2.0.0p0 (2013-02-24 revision 39474) [x86\_64-linux] +* ruby 1.9.3p194 (2012-04-20 revision 35410) [x86\_64-linux] +* ruby 1.9.3p327 (2012-11-10 revision 37606) [x86\_64-darwin10.8.0] + +For those who are lazy, I'm attaching a screencast. + +### Description + +This program is a music-box quine. +It prints itself with playing "Jesu, Joy of Man's Desiring". + +### Internal + +Like a real music box, this program consists of a mechanical part (code) and a piano roll. +In the piano roll, `#` represents a pin that hits a note, and `|` represents a slur. +The leftmost column corresponds 110Hz (low A). +Every column corresponds a semitone higher than the left one. + +This program uses [the frequency modulation synthesis](http://en.wikipedia.org/wiki/Frequency_modulation_synthesis) to play the sound like a music-box. +You can create a different-sounding tone by changing the parameter. +For example, the following will play the sound like a harpsichord. + + padsp ruby entry.rb 2.0 + +Note that this program does *not* use an idiom to remove whitespace, such as `.split.join`. All newlines and spaces do not violate any of the Ruby syntax rules. + +### Limitation + +On os x, `/dev/dsp` is not available. +You have to use sox by replacing the following part: + + open("/dev/dsp","wb") + +with: + + IO.popen("./pl","wb")
\ No newline at end of file diff --git a/sample/trick2013/shinh/authors.markdown b/sample/trick2013/shinh/authors.markdown new file mode 100644 index 0000000000..7ea2298a1a --- /dev/null +++ b/sample/trick2013/shinh/authors.markdown @@ -0,0 +1,2 @@ +Shinichiro Hamaji +Japan, .jp diff --git a/sample/trick2013/shinh/entry.rb b/sample/trick2013/shinh/entry.rb new file mode 100644 index 0000000000..cd4517358a --- /dev/null +++ b/sample/trick2013/shinh/entry.rb @@ -0,0 +1,10 @@ +begin with an easy program. +you should be able to write +a program unless for you, +program in ruby language is +too difficult. At the end +of your journey towards the +ultimate program; you must +be a part of a programming +language. You will end if +you != program diff --git a/sample/trick2013/shinh/remarks.markdown b/sample/trick2013/shinh/remarks.markdown new file mode 100644 index 0000000000..1cd190db9f --- /dev/null +++ b/sample/trick2013/shinh/remarks.markdown @@ -0,0 +1,4 @@ +This program is a meaningless poem. +This does nothing for you. +Almost everything in this code is junk, +but you and program would confuse you a bit. diff --git a/sample/trick2013/yhara/authors.markdown b/sample/trick2013/yhara/authors.markdown new file mode 100644 index 0000000000..c0adc2bfdb --- /dev/null +++ b/sample/trick2013/yhara/authors.markdown @@ -0,0 +1,3 @@ +* Yutaka Hara + * yutaka.hara.gmail.com + * cctld: jp diff --git a/sample/trick2013/yhara/entry.rb b/sample/trick2013/yhara/entry.rb new file mode 100644 index 0000000000..ce125ed3df --- /dev/null +++ b/sample/trick2013/yhara/entry.rb @@ -0,0 +1,28 @@ +def _(&b)$><<->(x){x ? (String===x ?x.upcase: +(Class===x ? x : x.class).name[$a?0:($a=5)]): +" "}[ begin b[];rescue Exception;$!;end ] end + +_ { yield } +_ { method(:p).unbind } +_ { eval "{ " } +_ { Thread.current.join } +_ { nil } +_ { select } +_ { ruby } +_ { self.class } +_ { Thread.current.group } +_ { nil.to_h } +_ { "\xFF".encode("big5") } +_ { raise } +_ { [0][1] } +_ { Regexp.compile "*" } +_ { RUBY_COPYRIGHT[32] } +_ { binding } +_ { :s.class.name[1] } +_ { warn } +_ { [a: :b][0] } +_ { methods } +_ { IO.class } +_ { {}.fetch(0) } +_ { open " " } +_ { 1000000.chr } diff --git a/sample/trick2013/yhara/remarks.en.markdown b/sample/trick2013/yhara/remarks.en.markdown new file mode 100644 index 0000000000..bd821e882c --- /dev/null +++ b/sample/trick2013/yhara/remarks.en.markdown @@ -0,0 +1,23 @@ +### Remarks + +Just run it with no argument: + + ruby entry.rb + +I confirmed the following implementations/platforms: + +* ruby 2.0.0p0 (2013-02-24 revision 39474) [x86\_64-darwin12.2.1] + +### Description + +It prints JUST ANOTHER RUBY HACKER¡£ + +### Internals + +This script uses characters in constants in Object class. It +intentionally raises some exceptions. The second 'U' comes from +RUBY\_COPYRIGHT, "Yukihiro Matsumoto". + +### Limitation + +This program does not work on JRuby because "return" does not raise an exception. diff --git a/sample/trick2013/yhara/remarks.markdown b/sample/trick2013/yhara/remarks.markdown new file mode 100644 index 0000000000..99cb4b557c --- /dev/null +++ b/sample/trick2013/yhara/remarks.markdown @@ -0,0 +1,24 @@ +### Remarks + +引数ãªã—ã§æ™®é€šã«å®Ÿè¡Œã—ã¦ãã ã•ã„。 + + ruby entry.rb + +以下ã®å®Ÿè£…・プラットフォームã§å‹•作確èªã—ã¦ã„ã¾ã™ã€‚ + +* ruby 2.0.0p0 (2013-02-24 revision 39474) [x86\_64-darwin12.2.1] + +### Description + +JUST ANOTHER RUBY HACKERã¨è¡¨ç¤ºã—ã¾ã™ã€‚ + +### Internals + +Objectクラスã®å®šæ•°ã‹ã‚‰æ–‡å—を拾ã£ã¦ã„ã¾ã™ã€‚ +ãã®ãŸã‚ã«ã€æ„図的ã«ä¾‹å¤–ã‚’èµ·ã“ã—ã¦ã„ã¾ã™ã€‚ +「Uã€ãŒä¸€ã¤ã—ã‹è¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸã®ã§ã€ã‚‚ã†ä¸€å€‹ã¯RUBY\_COPYRIGHTã® +「Yukihiro Matsumotoã€ã‹ã‚‰å–ã£ã¦ã„ã¾ã™ã€‚ + +### Limitation + +JRubyã¯returnãŒã‚¨ãƒ©ãƒ¼ã«ãªã‚‰ãªãã¦ã€å‹•ãã¾ã›ã‚“ã§ã—ãŸã€‚ diff --git a/sample/trick2015/README.md b/sample/trick2015/README.md new file mode 100644 index 0000000000..6cae824796 --- /dev/null +++ b/sample/trick2015/README.md @@ -0,0 +1,16 @@ +This directory contains the award-winning entries of +the 2nd Transcendental Ruby Imbroglio Contest for rubyKaigi (TRICK 2015). + +THESE ARE BAD EXAMPLES! You must NOT use them as a sample code. + +* kinaba/entry.rb: "Best piphilology" - **Gold award** +* ksk\_1/entry.rb: "Most unreadable ALU" - **Silver award** +* monae/entry.rb: "Doubling amphisbaena award" - **Bronze award** +* eregon/entry.rb: "Least general solver" - 4th prize +* ksk\_2/entry.rb: "Most general solver" - 5th prize + +These files are licensed under MIT license. + +For the contest outline and other winning entries, see: + +https://github.com/tric/trick2015 diff --git a/sample/trick2015/eregon/authors.markdown b/sample/trick2015/eregon/authors.markdown new file mode 100644 index 0000000000..68ca8cdfe0 --- /dev/null +++ b/sample/trick2015/eregon/authors.markdown @@ -0,0 +1,3 @@ +* Benoit Daloze (eregon) + * eregontp@gmail.com + * cctld: be diff --git a/sample/trick2015/eregon/entry.rb b/sample/trick2015/eregon/entry.rb new file mode 100644 index 0000000000..51d5c768b2 --- /dev/null +++ b/sample/trick2015/eregon/entry.rb @@ -0,0 +1,16 @@ +class String;def[]*a;$*<<a;b;end;end; +_=0;z="C=Fiber;s=$*;a=*0..8;l=C.new{e +xit},*a.product(a).select{|r,c|s[r][c +]==0}."[1,9,_, _,_,8, _,_,5]+"map{|r, +c|C.ne"[_,_,2, _,5,_, _,8,9]+"w{o=s[r +][c];l"[8,_,6, 7,4,_, _,_,_]+"oop{(1. +.9).map{|n|C.yield(s[r][c]=n)if a.non +e?{|k|"[_,_,_, _,_,4, _,9,2]+"s[r][k] +==n||s"[_,2,3, _,7,_, 8,1,_]+"[k][c]= +=n||s["[5,6,_, 8,_,_, _,_,_]+"r-r%3+k +%3][c-c%3+k/3]==n}};s[r][c]=o;C.yield +}}},C."[_,_,_, _,2,7, 9,_,3]+"new{loo +p{puts"[9,3,_, _,8,_, 1,_,_]+" s.map{ +|r|r*'"[2,_,_, 5,_,_, _,4,8]+" '}<<'' +;C.yield}};c=l[i=1];loop{c=l[i+=c.res +ume ? 1:-1]}";eval z.tr ?\n,'' diff --git a/sample/trick2015/eregon/remarks.markdown b/sample/trick2015/eregon/remarks.markdown new file mode 100644 index 0000000000..a56f24da71 --- /dev/null +++ b/sample/trick2015/eregon/remarks.markdown @@ -0,0 +1,70 @@ +### Remarks + +Just run it without arguments: + + ruby entry.rb + +I confirmed the following implementations and platforms: + +* Linux: + * ruby 2.3.0dev (2015-10-30 trunk 52394) [x86\_64-linux] + * ruby 2.2.2p95 (2015-04-13 revision 50295) [x86\_64-linux] + * ruby 2.0.0p647 (2015-08-18) [x86\_64-linux] +* Darwin: + * ruby 2.0.0p247 (2013-06-27 revision 41674) [x86\_64-darwin10.8.0] + * jruby 9.0.3.0 (2.2.2) 2015-10-21 633c9aa Java HotSpot(TM) 64-Bit Server VM 25.11-b03 on 1.8.0\_11-b12 +jit [darwin-x86\_64] + * rubinius 2.2.6.n74 (2.1.0 94b3a9b4 2014-03-15 JI) [x86\_64-darwin12.5.0] + +### Description + +This program shows all solutions of any sudoku puzzle. + +The embedded sudoku puzzle can be changed at wish. + +Giving an empty puzzle (all `0` or `_`), the program will print every possible completed sudoku puzzle. +We do not however make any time guarantee on such behavior. + +The program is rather small for the task: the solver is actually 302 characters long, +assuming the sudoku puzzle is in a variable `s` and encoded as an array of rows of numbers. + +### Internals + +* The program implements backtracking and keeps state in a very elegant way. +* The whole program never goes deeper than 9 stack frames, + but yet can backtrack up to 81 levels! +* The main loop of a program is a dance between cells. + On one end is the solutions, on the other the program ends. +* The program only uses *infinite* loops and no `break`. +* The program interleaves the creation of the solver and the puzzle. +* The program is easy to deobfuscate but finding how it works will be more challenging. +* The last line contains a smiley. + +The author likes good numbers: + + $ wc entry.rb + 15 42 600 + +The inspiration for this entry comes from: + +* A newspaper sudoku with multiple solutions +* An inspiring paper: `Revisiting Coroutines` + +Various tricks used for brevity: + +* The method defined is one of the fews which may contain neither parenthesis nor spaces. +* The program uses the return value of Fiber.yield without arguments. +* `String#b` is used as a very short `self`. + +Design issues: + +* Since `return`-ing from a Fiber is not allowed, the programs must `exit`. +* The program reveals that the cartesian product operator is still too long: `a.product(a)` while it could be `a*a`. + +Note: + +* In the original code, the last cell was: `C.new{loop{yield s; C.yield}}`, + implementing some sort of "forwarding coroutine". + +### Limitation + +* The program does not want any *argument* with you and will quit quietly if you try some. diff --git a/sample/trick2015/kinaba/authors.markdown b/sample/trick2015/kinaba/authors.markdown new file mode 100644 index 0000000000..23d4448cf3 --- /dev/null +++ b/sample/trick2015/kinaba/authors.markdown @@ -0,0 +1,4 @@ +* kinaba + * twitter.com/kinaba + * kiki@kmonos.net + * cctld: jp diff --git a/sample/trick2015/kinaba/entry.rb b/sample/trick2015/kinaba/entry.rb new file mode 100644 index 0000000000..18923a6a9f --- /dev/null +++ b/sample/trick2015/kinaba/entry.rb @@ -0,0 +1,150 @@ +big, temp = Array 100000000**0x04e2 +srand big +alias $curTerm $initTerm + +Numeric +Interrupt + +big += big +printout _pi_ finish if $never +init ||= big +$counter ||= 02 + +private +@mainloop +while 0x00012345 >= $counter + + Rational aprx = 3.141592r + numbase = 0o0000 + + @justonce + def increment + $initTerm ||= Integer srand * 0x00000002 + srand $counter += 0x00000001 + + $noaction + Integer rand + $noaction + rand + rand + alias $line_cnt $. + end + + @lets_just + @assume + diameter = 100000 + + @you + @then_have + permtr |= +3_14159 + + return if $nomeaning + + @onlyuse + increment + + beautiful computer action if $nothing + $sigmaTerm ||= init + $curTerm /= srand and init + pi, = Integer $sigmaTerm unless $nomean + + iterator? + $counter += 1 + atan real_one multiplied by__four unless + srand +big && $counter >> 0b1 + + Enumerable + Fixnum + Bignum + Math + Complex + Comparable + TrueClass + Dir + Encoding + Data + Hash + Method + Enumerator + Exception + Fiber + Errno + FalseClass + Mutex + NilClass + IO + GC + + num = numbase |= srand + + ENV + Float + MatchData + Proc + TracePoint + KeyError + p or + FileTest + File + EOFError + p + p + p + Binding + Time + Class + + $sigmaTerm += $curTerm + puts a HelloWorld if $nomean + SystemExit + + !LoadError + 31i + 3.1415e0 + Array 14 + 3 + IndexError + Range + false + 55555 + NameError + + Object + @ori + @ent + RubyVM + + pi += 3_3_1_3_8 + + @use + @lots_of + @keywords + begin + self + $noaction + not $important + nil + __FILE__.object_id + rescue + next + redo if __LINE__ + defined? +$nomeaning + $noaction + $nomean + break $never + ensure + class PiCompute + end + end + + This code cannot _ be executed with typical style unless true + $curTerm *= num +end + +@ll_set +@re_U_ok + +$Enjoy +$Superb +$TRICK15 and a number + +print pi diff --git a/sample/trick2015/kinaba/remarks.markdown b/sample/trick2015/kinaba/remarks.markdown new file mode 100644 index 0000000000..6316c51fb6 --- /dev/null +++ b/sample/trick2015/kinaba/remarks.markdown @@ -0,0 +1,85 @@ +### Remarks + +Just run it with no argument: + + $ ruby entry.rb + +I confirmed the following implementation/platform: + +- ruby 2.2.3p173 (2015-08-18 revision 51636) [x64-mingw32] + + +### Description + +The program is a [Piphilology](https://en.wikipedia.org/wiki/Piphilology#Examples_in_English) +suitable for Rubyists to memorize the digits of [Pi](https://en.wikipedia.org/wiki/Pi). + +In English, the poems for memorizing Pi start with a word consisting of 3-letters, +1-letter, 4-letters, 1-letter, 5-letters, ... and so on. 10-letter words are used for the +digit `0`. In Ruby, the lengths of the lexical tokens tell you the number. + + $ ruby -r ripper -e \ + 'puts Ripper.tokenize(STDIN).grep(/\S/).map{|t|t.size%10}.join' < entry.rb + 31415926535897932384626433832795028841971693993751058209749445923078164062862... + +The program also tells you the first 10000 digits of Pi, by running. + + $ ruby entry.rb + 31415926535897932384626433832795028841971693993751058209749445923078164062862... + + +### Internals + +Random notes on what you might think interesting: + +- The 10000 digits output of Pi is seriously computed with no cheets. It is calculated + by the formula `Pi/2 = 1 + 1/3 + 1/3*2/5 + 1/3*2/5*3/7 + 1/3*2/5*3/7*4/9 + ...`. + +- Lexical tokens are not just space-separated units. For instance, `a*b + cdef` does + not represent [3,1,4]; rather it's [1,1,1,1,4]. The token length + burden imposes hard constraints on what we can write. + +- That said, Pi is [believed](https://en.wikipedia.org/wiki/Normal_number) to contain + all digit sequences in it. If so, you can find any program inside Pi in theory. + In practice it isn't that easy particularly under the TRICK's 4096-char + limit rule. Suppose we want to embed `g += hij`. We have to find [1,2,3] from Pi. + Assuming uniform distribution, it occurs once in 1000 digits, which already consumes + 5000 chars in average to reach the point. We need some TRICK. + + - `alias` of global variables was useful. It allows me to access the same value from + different token-length positions. + + - `srand` was amazingly useful. Since it returns the "previous seed", the token-length + `5` essentially becomes a value-store that can be written without waiting for the + 1-letter token `=`. + +- Combination of these techniques leads to a carefully chosen 77-token Pi computation + program (quoted below), which is embeddable to the first 242 tokens of Pi. + Though the remaining 165 tokens are just no-op fillers, it's not so bad compared to + the 1000/3 = 333x blowup mentioned above. + + + big, temp = Array 100000000**0x04e2 + srand big + alias $curTerm $initTerm + big += big + init ||= big + $counter ||= 02 + while 0x00012345 >= $counter + numbase = 0x0000 + $initTerm ||= Integer srand * 0x00000002 + srand $counter += 0x00000001 + $sigmaTerm ||= init + $curTerm /= srand + pi, = Integer $sigmaTerm + $counter += 1 + srand +big && $counter >> 0b1 + num = numbase |= srand + $sigmaTerm += $curTerm + pi += 3_3_1_3_8 + $curTerm *= num + end + print pi + +- By the way, what's the blowup ratio of the final code, then? + It's 242/77, whose first three digits are, of course, 3.14. diff --git a/sample/trick2015/ksk_1/authors.markdown b/sample/trick2015/ksk_1/authors.markdown new file mode 100644 index 0000000000..bd6d41f6c7 --- /dev/null +++ b/sample/trick2015/ksk_1/authors.markdown @@ -0,0 +1,3 @@ +* Keisuke Nakano + * ksk@github, ksknac@twitter + * cctld: jp diff --git a/sample/trick2015/ksk_1/entry.rb b/sample/trick2015/ksk_1/entry.rb new file mode 100644 index 0000000000..64d3efd799 --- /dev/null +++ b/sample/trick2015/ksk_1/entry.rb @@ -0,0 +1 @@ +%%%while eval '_=%%r%%(.)...\1=%%=~[%%%%,,,,,%%%s ?=]*%%%%%%#"]*%%%%3x+1?%%'.% %%",%*p(_||=eval($**%%%)) diff --git a/sample/trick2015/ksk_1/remarks.markdown b/sample/trick2015/ksk_1/remarks.markdown new file mode 100644 index 0000000000..b822dc55c8 --- /dev/null +++ b/sample/trick2015/ksk_1/remarks.markdown @@ -0,0 +1,120 @@ +### Remarks + +The program is run with a positive integer as an argument, e.g., +```shell + ruby entry.rb 27 +``` +It has been confirmed to be run on +``` + ruby 1.9.3p385 (2013-02-06 revision 39114) [x86_64-darwin11.4.2] + ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin13] + ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux] +``` + + +### Description + +The program prints a Collatz sequence started with a given number, +that is, it repeatedly outputs numbers obtained by applying the +following Half-Or-Triple-Plus-One (HOTPO) process to the previous +number: + +> If the number is even, divide it by two, otherwise, multiply it by three and add one. + +until the number becomes 1. Collatz conjectured that no matter from +the process starts it always eventually terminates. This is still +an open problem, hence the program may not terminate for some +numbers. It is known that there is no such exception below 2<sup>60</sup>. + + +### Internals + +The source code does not contain either conditional branch or arithmetic operation. +The trick shall be revealed step by step. + +First, the code is obfuscated by using `%`-notations, +`*`(String#join), `%`-formatting, restructuring, and so on. +Here is an equivalent readable program: +```ruby +n = ARGV[0].to_i +begin + # do nothing +end while begin + puts n + n = (/(.)...\1=/ =~ eval('[",,,,,"'+ '",'*n + ' ?=].join#"].join("3x+1?")')) +end +``` +The line +```ruby + n = (/(.)...\1=/ =~ eval('[",,,,,"'+ '",'*n + ' ?=].join#"].join("3x+1?")')) +``` +performs the HOTPO process. +The `eval` expression here returns a string as explained in detail later. +Since *regex*`=~`*str* returns index of first match of *regex* in *str*, +the regular expression `(.)...\1` must match the string +at index `n/2` if `n` is even and +at `3*n+1` if `n` is odd greater than 1. +The match must fail in the case of `n = 1` so that it returns `nil`. + +The key of simulating the even-odd conditional branch on `n` in the +HOTPO process is an `n`-length sequence of the incomplete fragments +`",` where the double-quote `"` changes its role of opening/closing +string literals alternately. If `n` is even, the string in the `eval` +expression is evaluated as +```ruby + => '[",,,,,"'+ '",' + '",' + '",' + ... + '",' + ' ?=].join#...' + => '[",,,,,"",",",...", ?=].join#...' +``` +where the last double-quote `"` is closing hence the code after `#` is +ignored as comments. Note that `"ab""cd"` in Ruby is equivalent to +`"abcd"`. Therefore the `eval` expression is evaluated into +```ruby + ",,,,,...,=" +``` +where the number of commas is `5+n/2`. +As a result, the regular expression `(.)...\1=` matches `,,,,,=` +at the end of string, that is, at index `5+n/2-5 = n/2`. + +If `n` is odd, the string in the `eval` expression is evaluated as +```ruby + => '[",,,,,"'+ '",' + '",' + '",' + '",' + ... + '",' + ' ?=].join#"].join("3x+1?")' + => '[",,,,,"",",",",...,", ?=].join#"].join("3x+1?")' +``` +where the last element in the array is `", ?=].join#"`. Threfore the +`eval` expression is evaluated into +``` + ",,,,,,3x+1?,3x+1?,...,3x+1?, ?=].join#" +``` +where the number of `,3x+1?` is `(n-1)/2`. As a result, the regular +expression `(.)...\1=` matches `?, ?=` at the almost end of string, +that is, at index `5+(n-1)/2*6-1 = 3n+1`, provided that the match +fails in the case of `n = 1` because the symbol `?` occurs only once +in the string. + +One may notice that the string `3x+1` in the code could be other +four-character words. I chose it because the Collatz conjecture is +also called the 3x+1 problem. + + +### Variant + +The Collatz conjecture is equivalently stated as, + +> no matter from the HOTPO process starts, it always eventually + reaches the cycle of 4, 2, and 1 + +instead of termination of the process at 1. This alternative +statement makes the program simpler because we do not have to care the +case of n = 1. It can be obtained by replacing the regular expression +is simply `/=/` and removing a padding `",,,,,"`. The program no +longer terminates, though. + + +### Limination + +The implementation requires to manipulate long strings even for some +small starting numbers. For example, starting from 1,819, the number +will reach up to 1,276,936 which causes SystemStackError on Ruby 1.9.3. +The program works on Ruby 2.0.0 and 2.2.3, though. + + diff --git a/sample/trick2015/ksk_2/abnormal.cnf b/sample/trick2015/ksk_2/abnormal.cnf new file mode 100644 index 0000000000..084303f041 --- /dev/null +++ b/sample/trick2015/ksk_2/abnormal.cnf @@ -0,0 +1,6 @@ +c Example CNF format file +c +p cnf 4 3 +1 3 -4 0 +4 0 2 +-3 diff --git a/sample/trick2015/ksk_2/authors.markdown b/sample/trick2015/ksk_2/authors.markdown new file mode 100644 index 0000000000..bd6d41f6c7 --- /dev/null +++ b/sample/trick2015/ksk_2/authors.markdown @@ -0,0 +1,3 @@ +* Keisuke Nakano + * ksk@github, ksknac@twitter + * cctld: jp diff --git a/sample/trick2015/ksk_2/entry.rb b/sample/trick2015/ksk_2/entry.rb new file mode 100644 index 0000000000..55b488e3a8 --- /dev/null +++ b/sample/trick2015/ksk_2/entry.rb @@ -0,0 +1 @@ +_='s %sSATISFIABLE';puts eval$<.read.gsub(/.*p.*?(\d+).*?$|\d+/m){$1?%w[?-* +'=-'=~/#{'(-?)'* }-*=(?=]*$1:$&>?0?"\\#$&$|":'$)(?='}+')/x?[_%p%i=0,[*$~].map{|x|x>?-?:v:eval(x+?1)*i-=1}*" "]:_%:UN' diff --git a/sample/trick2015/ksk_2/quinn.cnf b/sample/trick2015/ksk_2/quinn.cnf new file mode 100644 index 0000000000..556a9b33f5 --- /dev/null +++ b/sample/trick2015/ksk_2/quinn.cnf @@ -0,0 +1,21 @@ +c quinn.cnf +c +p cnf 16 18 + 1 2 0 + -2 -4 0 + 3 4 0 + -4 -5 0 + 5 -6 0 + 6 -7 0 + 6 7 0 + 7 -16 0 + 8 -9 0 + -8 -14 0 + 9 10 0 + 9 -10 0 +-10 -11 0 + 10 12 0 + 11 12 0 + 13 14 0 + 14 -15 0 + 15 16 0
\ No newline at end of file diff --git a/sample/trick2015/ksk_2/remarks.markdown b/sample/trick2015/ksk_2/remarks.markdown new file mode 100644 index 0000000000..bb9b705773 --- /dev/null +++ b/sample/trick2015/ksk_2/remarks.markdown @@ -0,0 +1,204 @@ +### Remarks + +The program is run with a data file from the standard input, e.g., +```shell + ruby entry.rb < data +``` +where ``<`` can be omitted. The data file must be in the DIMACS CNF +format (see Description for detail). It has been confirmed to be run on +``` + ruby 1.9.3p385 (2013-02-06 revision 39114) [x86_64-darwin11.4.2] + ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin13] + ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux] +``` +For particular inputs, the program works differently on these environments +(see Limitation). + + +### Description + +The program is a very small SAT solver with 194 bytes making use of a +powerful feature of Regexp matching in Ruby. It receives a data file +from the standard input in the DIMACS CNF that is a standard format +for inputs of SAT solvers. For example, the text in the DIMACS CNF +format, +``` +c +c This is a sample input file. +c +p cnf 3 5 + 1 -2 3 0 +-1 2 0 +-2 -3 0 + 1 2 -3 0 + 1 3 0 +``` +corresponds to a propositional formula in conjunctive normal form, + + (L1 ∨ ¬L2 ∨ L3) ∧ + (¬L1 ∨ L2) ∧ + (¬L2 ∨ ¬L3) ∧ + (L1 ∨ L2 ∨ ¬L3) ∧ + (L1 ∨ L3). + +In the DIMACS CNF format, the lines starting with ``c`` are comments +that are allowed only before the line ``p cnf ...``. The line ``p cnf +3 5`` represents that the problem is given in conjunctive normal form +with 3 variables (L1,L2,and L3) and 5 clauses. A clause is given by a +sequence of the indices of positive literals and the negative indices +of negative literals. Each clause is terminated by ``0``. For the +input above, the program outputs +``` +s SATISFIABLE +v 1 2 -3 +``` +because the formula is satisfiable by L1=true, L2=true, and L3=false. +If an unsatisfiable formula is given, the program should output +``` +s UNSATISFIABLE +``` +This specification is common in most exiting SAT solvers and required +for entries of [SAT competition](http://www.satcompetition.org/). + +The program is very small with no other external libraries thanks to +the wealth of string manipulations in Ruby. It is much smaller than +existing small SAT solvers like [minisat](http://minisat.se/) and +[picosat](http://fmv.jku.at/picosat/)! + + +### Internals + +The basic idea of the program is a translation from DIMACS CNF format +into Ruby. For example, the data file above is translated into a +``Regexp`` matching expression equivalent to +```ruby + '---=-' =~ + /(-?)(-?)(-?)-*=(?=\1$|-\2$|\3$|$)(?=-\1$|\2$|$)(?=-\2$|-\3$|$)(?=\1$|\2$|-\3$|$)(?=\1$|\3$|$)(?=)/ +``` +that returns ``MatchData`` if the formula is satisfiable and otherwise +returns ``nil``. The beginning of regular expression +``(-?)(-?)(-?)-*=`` matches a string ``"---="`` so that each +capturing pattern ``(-?)`` matches either ``"-"`` or `""`, which +corresponds to an assignment of true or false, respectively, for a +propositional variable. Each clause is translated into positive +lookahead assertion like ``(?=\1$|-\2$|\3$|$)`` that matches +``"-"`` only when ``\1`` holds ``"-"``, ``\2`` holds ``""``, or ``\3`` +holds ``"-"``. This exactly corresponds to the condition for +L1∨¬L2∨L3 to be true. The last case ``|$`` never matches +``"-"`` but it is required for making the translation simple. +The last meaningless positive lookahead assertion ``(?=)`` is added +for a similar reason. This translation is based on +[Abigail's idea](http://perl.plover.com/NPC/NPC-3SAT.html) where a +3SAT formula is translated into a similar Perl regular expression. +The differences are the submitted Ruby program translates directly +from the DIMACS CNF format and tries to make the code shorter by using +lookahead assertion which can also make matching more faster. + +Thanks to the ``x`` option for regular expression, the input above is +simply translated into +```ruby + ?-*3+'=-'=~/#{'(-?)'*3}-*=(?= + \1$| -\2$| \3$| $)(?= + -\1$| \2$| $)(?= + -\2$| -\3$| $)(?= + \1$| \2$| -\3$| $)(?= + \1$| \3$| $)(?= + )/x +``` +which has a structure similar to the DIMACS CNF format. + +The part of formatting outputs in the program is obfuscated as an +inevitable result of 'golfing' the original program +```ruby + if ...the matching expression above... then + puts 's SATISFIABLE' + puts 'v '+$~[1..-1].map.with_index{|x,i| + if x == '-' then + i+1 + else + ['-',i+1].join + end + }.join(' ') + else + puts 's UNSATISFIABLE' + end +``` +In the satisfiable case, the MatchData ``$~`` obtained by the regular expression +has the form of +``` + #<MatchData "---=" 1:"-" 2:"-" 3:""> +``` +which should be translated into a string ``1 2 -3``. The golfed code simply +does it by `eval(x+?1)*i-=1` where ``x`` is matched string ``"x"`` or ``""`` +and ``i`` be a negated index. + + +### Data files + +The submission includes some input files in the DIMACS CNF format for +testing the program. + +* [sample.cnf](sample.cnf) : an example shown above. + +* [unsat.cnf](unsat.cnf) : an example of an unsatisfiable formula. + +* [quinn.cnf](quinn.cnf) : an example from Quinn's text, 16 variables and 18 clauses + (available from [http://people.sc.fsu.edu/~jburkardt/data/cnf/cnf.html]) + +* [abnormal.cnf](abnormal.cnf) : an example from [the unofficial manual of the DIMACS challenge](http://www.domagoj-babic.com/uploads/ResearchProjects/Spear/dimacs-cnf.pdf) + where a single clause may be on multiple lines. + +* [uf20-01.cnf](uf20-01.cnf) : an example, with 20 variables and 91 clauses, from [SATLIB benchmark suite](http://www.cs.ubc.ca/~hoos/SATLIB/benchm.html). The last two lines are removed from the original because they are illegal in the DIMACS CNF format (all examples in 'Uniform Random-3-SAT' of the linked page need this modification). + + +### Limitation + +The program may not work when the number of variables exceeds 99 +because ``\nnn`` in regular expression with number ``nnn`` does not +always represent backreference but octal notation of characters. For +example, +```ruby + /#{"(x)"*999}:\502/=~"x"*999+":x" + /#{"(x)"*999}:\661/=~"x"*999+":x" + /#{"(x)"*999}:\775/=~"x"*999+":x" +``` +fail due to the syntax error (invalid escape), while +```ruby + /#{"(x)"*999}:\508/=~"x"*999+":x" + /#{"(x)"*999}:\691/=~"x"*999+":x" + /#{"(x)"*999}:\785/=~"x"*999+":x" +``` +succeed (to return 0) because 508, 691, and 785 are not in octal notation. +Since Ruby 1.9.3 incorrectly returns ``nil`` instead of terminating +with the error for +```ruby + /#{"(x)"*999}:\201/=~"x"*999+":x" + /#{"(x)"*999}:\325/=~"x"*999+":x" +``` +the present SAT solver may unexpectedly return "UNSATISFIABLE" even +for satisfiable inputs. This happens when the number is in octal +notation starting with either 2 or 3. + +In the case of the number starting with 1, the code like the above +does work on all versions of Ruby I tried. For example, +```ruby + /#{"(x)"*999}:\101/=~"x"*999+":x" + /#{"(x)"*999}:\177/=~"x"*999+":x" +``` +succeed (to return 0). Interestingly, +```ruby + /#{"(x)"*999}:\101/=~"x"*999+":\101" + /#{"(x)"*999}:\177/=~"x"*999+":\177" +``` +return ``nil``, while +```ruby + /:\101/=~":\101" + /:\177/=~":\177" +``` +succeed to return 0. The meaning of ``\1nn`` in regular expression +seems to depend on the existence of capturing expressions. + +In spite of these Ruby's behaviors, we have a good news! The present +SAT sover does not suffer from the issues because the program cannot +return solutions in practical time for inputs with variables more than +40.
\ No newline at end of file diff --git a/sample/trick2015/ksk_2/sample.cnf b/sample/trick2015/ksk_2/sample.cnf new file mode 100644 index 0000000000..295f81c942 --- /dev/null +++ b/sample/trick2015/ksk_2/sample.cnf @@ -0,0 +1,9 @@ +c +c This is a sample input file. +c +p cnf 3 5 + 1 -2 3 0 +-1 2 0 +-2 -3 0 + 1 2 -3 0 + 1 3 0 diff --git a/sample/trick2015/ksk_2/uf20-01.cnf b/sample/trick2015/ksk_2/uf20-01.cnf new file mode 100644 index 0000000000..0d9503c451 --- /dev/null +++ b/sample/trick2015/ksk_2/uf20-01.cnf @@ -0,0 +1,99 @@ +c This Formular is generated by mcnf +c +c horn? no +c forced? no +c mixed sat? no +c clause length = 3 +c +p cnf 20 91 + 4 -18 19 0 +3 18 -5 0 +-5 -8 -15 0 +-20 7 -16 0 +10 -13 -7 0 +-12 -9 17 0 +17 19 5 0 +-16 9 15 0 +11 -5 -14 0 +18 -10 13 0 +-3 11 12 0 +-6 -17 -8 0 +-18 14 1 0 +-19 -15 10 0 +12 18 -19 0 +-8 4 7 0 +-8 -9 4 0 +7 17 -15 0 +12 -7 -14 0 +-10 -11 8 0 +2 -15 -11 0 +9 6 1 0 +-11 20 -17 0 +9 -15 13 0 +12 -7 -17 0 +-18 -2 20 0 +20 12 4 0 +19 11 14 0 +-16 18 -4 0 +-1 -17 -19 0 +-13 15 10 0 +-12 -14 -13 0 +12 -14 -7 0 +-7 16 10 0 +6 10 7 0 +20 14 -16 0 +-19 17 11 0 +-7 1 -20 0 +-5 12 15 0 +-4 -9 -13 0 +12 -11 -7 0 +-5 19 -8 0 +1 16 17 0 +20 -14 -15 0 +13 -4 10 0 +14 7 10 0 +-5 9 20 0 +10 1 -19 0 +-16 -15 -1 0 +16 3 -11 0 +-15 -10 4 0 +4 -15 -3 0 +-10 -16 11 0 +-8 12 -5 0 +14 -6 12 0 +1 6 11 0 +-13 -5 -1 0 +-7 -2 12 0 +1 -20 19 0 +-2 -13 -8 0 +15 18 4 0 +-11 14 9 0 +-6 -15 -2 0 +5 -12 -15 0 +-6 17 5 0 +-13 5 -19 0 +20 -1 14 0 +9 -17 15 0 +-5 19 -18 0 +-12 8 -10 0 +-18 14 -4 0 +15 -9 13 0 +9 -5 -1 0 +10 -19 -14 0 +20 9 4 0 +-9 -2 19 0 +-5 13 -17 0 +2 -10 -18 0 +-18 3 11 0 +7 -9 17 0 +-15 -6 -3 0 +-2 3 -13 0 +12 3 -2 0 +-2 -3 17 0 +20 -15 -16 0 +-5 -17 -19 0 +-20 -18 11 0 +-9 1 -5 0 +-19 9 17 0 +12 -2 17 0 +4 -16 -5 0 diff --git a/sample/trick2015/ksk_2/unsat.cnf b/sample/trick2015/ksk_2/unsat.cnf new file mode 100644 index 0000000000..7283933a9f --- /dev/null +++ b/sample/trick2015/ksk_2/unsat.cnf @@ -0,0 +1,11 @@ +c +c This is a sample input file. +c (unsatisfiable) +c +p cnf 3 5 +1 -2 3 0 +-1 2 0 +-2 -3 0 +1 2 -3 0 +1 3 0 +-1 -2 3 0 diff --git a/sample/trick2015/monae/authors.markdown b/sample/trick2015/monae/authors.markdown new file mode 100644 index 0000000000..58d63b16ac --- /dev/null +++ b/sample/trick2015/monae/authors.markdown @@ -0,0 +1 @@ +monae (@monae, jp) diff --git a/sample/trick2015/monae/entry.rb b/sample/trick2015/monae/entry.rb new file mode 100644 index 0000000000..6961df21cd --- /dev/null +++ b/sample/trick2015/monae/entry.rb @@ -0,0 +1,26 @@ + ;; ;; ;; ;; + ;; ;; ;; ;; + ;;eval$s =%q[i=1# + eval(%q[ xxxxxxxx + xx xxxx xx xx xxxx xx + xx xxxx xx xx xxxx xx + xxxxxxxx xxxxxxxx + xxxxxxxx xxxxxxxx + xx xx xxxxxxxxxx xx xxxxxxxx + j, t, p=0,[?;]," ev al$s=%qx +[#$s]".split*"";i,j,t=i-j,i+j,(x + [b=?\s]*j.abs+t).map{|s|r=t.shix +ft ||b;r.gsub!(?;){p.slice!0}if $x + f| |=p>p=p.center(i*i+j*j,?;);r ,x + s=[s,r]if(i*j<0);(b*i.abs+s).ljx + ust(r.size).gsub(b){r[$`.size]|x + |b}}unti l$ f;puts(t)# xx xx + xxxxxxxx xx xxxxxxxxxx xx xx +xxxxxxxx xxxxxxxx + xxxxxxxx xxxxxxxx +xx xxxx xx xx xxxx xx + xx xxxx xx xx xxxx xx + xxxxxxxx x].gsub\ + /x.*|\s/ ,"")#];; + ;; ;; ;; ;; + ;; ;; ;; ;; diff --git a/sample/trick2015/monae/remarks.markdown b/sample/trick2015/monae/remarks.markdown new file mode 100644 index 0000000000..48be61bd12 --- /dev/null +++ b/sample/trick2015/monae/remarks.markdown @@ -0,0 +1,25 @@ + +# How to run + +``` +ruby entry.rb +ruby entry.rb | ruby +ruby entry.rb | ruby | ruby +ruby entry.rb | ruby | ruby | ruby +... +``` + +Confirmed on the following environments: +- ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin14] +- ruby 2.0.0p353 (2013-11-22) [i386-mingw32] + +# Description + +A simple quine which prints itself twice +on a slightly complex base. + +> geminum caput amphisbaenae, hoc est et a cauda, +> tamquam parum esset uno ore fundi venenum. +> aliis squamas esse, aliis picturas, omnibus exitiale virus. +> +> — <cite>GAIUS PLINIUS SECUNDUS, Naturalis Historia 8.85.1</cite> diff --git a/sample/trojan.rb b/sample/trojan.rb index 2024da0908..cea0dae098 100644 --- a/sample/trojan.rb +++ b/sample/trojan.rb @@ -1,12 +1,13 @@ #! /usr/local/bin/ruby -path = ENV['PATH'].split(/:/) + +path = ENV['PATH'].split(File::PATH_SEPARATOR) for dir in path - if File.d(dir) + if File.directory?(dir) for f in d = Dir.open(dir) - fpath = dir+"/"+f - if File.f(fpath) && (File.stat(fpath).mode & 022) != 0 - printf("file %s is writable from other users\n", fpath) + fpath = File.join(dir, f) + if File.file?(fpath) && (File.stat(fpath).mode & 022) != 0 + printf("file %s is writable from other users\n", fpath) end end d.close diff --git a/sample/tsvr.rb b/sample/tsvr.rb index fbc6545bb5..2fa6c87ef9 100644 --- a/sample/tsvr.rb +++ b/sample/tsvr.rb @@ -2,20 +2,17 @@ # usage: ruby tsvr.rb require "socket" -require "thread" -gs = TCPserver.open(0) +gs = TCPServer.open(0) addr = gs.addr addr.shift -printf("server is on %d\n", addr.join(":")) +printf("server is on %s\n", addr.join(":")) -while TRUE - ns = gs.accept - print(ns, " is accepted\n") - Thread.start do - s = ns # save to dynamic variable - while s.gets - s.write($_) +loop do + Thread.start(gs.accept) do |s| + print(s, " is accepted\n") + while line = s.gets + s.write(line) end print(s, " is gone\n") s.close diff --git a/sample/uumerge.rb b/sample/uumerge.rb index 297b08f26a..2576bcb864 100755..100644 --- a/sample/uumerge.rb +++ b/sample/uumerge.rb @@ -1,37 +1,43 @@ -#!/usr/local/bin/ruby +#!/usr/bin/env ruby if ARGV[0] == "-c" - out_stdout = 1; + out_stdout = 1 ARGV.shift end -while gets() - if /^begin\s*(\d*)\s*(\S*)/ +$sawbegin = 0 +$sawend = 0 + +while line = gets() + if /^begin\s*(\d*)\s*(\S*)/ =~ line $mode, $file = $1, $2 $sawbegin+=1 + if out_stdout + out = STDOUT + else + out = open($file, "w") if $file != "" + end + out.binmode break end end -fail "missing begin" if ! $sawbegin; - -if out_stdout - out = STDOUT -else - out = open($file, "w") if $file != ""; -end +raise "missing begin" unless $sawbegin -while gets() - if /^end/ +out.binmode +while line = gets() + if /^end/ =~ line $sawend+=1 - break + out.close unless out_stdout + File.chmod $mode.oct, $file unless out_stdout + next end - sub(/[a-z]+$/, ""); # handle stupid trailing lowercase letters - next if /[a-z]/ + line.sub!(/[a-z]+$/, "") # handle stupid trailing lowercase letters + next if /[a-z]/ =~ line next if !(((($_[0] - 32) & 077) + 2) / 3 == $_.length / 4) - out << $_.unpack("u"); + out << $_.unpack("u") if $sawbegin > $sawend end -fail "missing end" if !$sawend; -File.chmod $mode.oct, $file if ! out_stdout -exit 0; +raise "missing end" if $sawbegin > $sawend +raise "missing begin" if ! $sawbegin +exit 0 diff --git a/sample/weakref.rb b/sample/weakref.rb new file mode 100644 index 0000000000..b9f38f954f --- /dev/null +++ b/sample/weakref.rb @@ -0,0 +1,9 @@ +require 'weakref' + +foo = Object.new +p foo.to_s # original's class +foo = WeakRef.new(foo) +p foo.to_s # should be same class +ObjectSpace.garbage_collect +ObjectSpace.garbage_collect +p foo.to_s # should raise exception (recycled) diff --git a/sample/webrick/demo-app.rb b/sample/webrick/demo-app.rb new file mode 100644 index 0000000000..c7a2a0a6a4 --- /dev/null +++ b/sample/webrick/demo-app.rb @@ -0,0 +1,66 @@ +require "pp" + +module DemoApplication + def initialize(config, enctype) + super + @enctype = enctype + end + + def do_GET(req, res) + if req.path_info != "/" + res.set_redirect(WEBrick::HTTPStatus::Found, req.script_name + "/") + end + res.body =<<-_end_of_html_ + <HTML> + <FORM method="POST" enctype=#{@enctype}> + text: <INPUT type="text" name="text"><BR> + file: <INPUT type="file" name="file"><BR> + check: + <INPUT type="checkbox" name="check" value="a">a, + <INPUT type="checkbox" name="check" value="b">b, + <INPUT type="checkbox" name="check" value="c">c, + <BR> + <INPUT type="submit"> + </FORM> + </HTML> + _end_of_html_ + res['content-type'] = 'text/html; charset=iso-8859-1' + end + + def do_POST(req, res) + if req["content-length"].to_i > 1024*10 + raise WEBrick::HTTPStatus::Forbidden, "file size too large" + end + res.body =<<-_end_of_html_ + <HTML> + <H2>Query Parameters</H2> + #{display_query(req.query)} + <A href="#{req.path}">return</A> + <H2>Request</H2> + <PRE>#{WEBrick::HTMLUtils::escape(PP::pp(req, "", 80))}</PRE> + <H2>Response</H2> + <PRE>#{WEBrick::HTMLUtils::escape(PP::pp(res, "", 80))}</PRE> + </HTML> + _end_of_html_ + res['content-type'] = 'text/html; charset=iso-8859-1' + end + + private + + def display_query(q) + ret = "" + q.each{|key, val| + ret << "<H3>#{WEBrick::HTMLUtils::escape(key)}</H3>" + ret << "<TABLE border=1>" + ret << make_tr("val", val.inspect) + ret << make_tr("val.to_a", val.to_a.inspect) + ret << make_tr("val.to_ary", val.to_ary.inspect) + ret << "</TABLE>" + } + ret + end + + def make_tr(arg0, arg1) + "<TR><TD>#{arg0}</TD><TD>#{WEBrick::HTMLUtils::escape(arg1)}</TD></TR>" + end +end diff --git a/sample/webrick/demo-multipart.cgi b/sample/webrick/demo-multipart.cgi new file mode 100644 index 0000000000..0893fadadf --- /dev/null +++ b/sample/webrick/demo-multipart.cgi @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +require "webrick/cgi" +require "webrick/https" # should load if it runs on HTTPS server +require "./demo-app" + +class DemoCGI < WEBrick::CGI + include DemoApplication +end + +config = { :NPH => false } +cgi = DemoCGI.new(config, "multipart/form-data") +cgi.start diff --git a/sample/webrick/demo-servlet.rb b/sample/webrick/demo-servlet.rb new file mode 100644 index 0000000000..9c18cc65d1 --- /dev/null +++ b/sample/webrick/demo-servlet.rb @@ -0,0 +1,6 @@ +require "webrick" +require "./demo-app" + +class DemoServlet < WEBrick::HTTPServlet::AbstractServlet + include DemoApplication +end diff --git a/sample/webrick/demo-urlencoded.cgi b/sample/webrick/demo-urlencoded.cgi new file mode 100644 index 0000000000..e4706f8b59 --- /dev/null +++ b/sample/webrick/demo-urlencoded.cgi @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +require "webrick/cgi" +require "webrick/https" # should load if it runs on HTTPS server +require "./demo-app" + +class DemoCGI < WEBrick::CGI + include DemoApplication +end + +config = { :NPH => false } +cgi = DemoCGI.new(config, "application/x-www-form-urlencoded") +cgi.start diff --git a/sample/webrick/hello.cgi b/sample/webrick/hello.cgi new file mode 100644 index 0000000000..35d2240df0 --- /dev/null +++ b/sample/webrick/hello.cgi @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +require "webrick/cgi" + +class HelloCGI < WEBrick::CGI + def do_GET(req, res) + res["content-type"] = "text/plain" + res.body = "Hello, world.\n" + end +end + +HelloCGI.new.start diff --git a/sample/webrick/hello.rb b/sample/webrick/hello.rb new file mode 100644 index 0000000000..4d02676818 --- /dev/null +++ b/sample/webrick/hello.rb @@ -0,0 +1,8 @@ +require "webrick" + +class HelloServlet < WEBrick::HTTPServlet::AbstractServlet + def do_GET(req, res) + res["content-type"] = "text/plain" + res.body = "Hello, world.\n" + end +end diff --git a/sample/webrick/httpd.rb b/sample/webrick/httpd.rb new file mode 100644 index 0000000000..b0edf47582 --- /dev/null +++ b/sample/webrick/httpd.rb @@ -0,0 +1,23 @@ +require "webrick" + +httpd = WEBrick::HTTPServer.new( + :DocumentRoot => File::dirname(__FILE__), + :Port => 10080, + :Logger => WEBrick::Log.new($stderr, WEBrick::Log::DEBUG), + :AccessLog => [ + [ $stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT ], + [ $stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT ], + [ $stderr, WEBrick::AccessLog::AGENT_LOG_FORMAT ], + ], + :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI. +) + +require "./hello" +httpd.mount("/hello", HelloServlet) + +require "./demo-servlet" +httpd.mount("/urlencoded", DemoServlet, "application/x-www-form-urlencoded") +httpd.mount("/multipart", DemoServlet, "multipart/form-data") + +trap(:INT){ httpd.shutdown } +httpd.start diff --git a/sample/webrick/httpproxy.rb b/sample/webrick/httpproxy.rb new file mode 100644 index 0000000000..c84457ece7 --- /dev/null +++ b/sample/webrick/httpproxy.rb @@ -0,0 +1,25 @@ +require "webrick" +require "webrick/httpproxy" + +# The :ProxyContentHandler proc will be invoked before sending a response to +# the User-Agent. You can inspect the pair of request and response messages +# (or edit the response message if necessary). + +pch = Proc.new{|req, res| + p [ req.request_line, res.status_line ] +} + +def upstream_proxy + if prx = ENV["http_proxy"] + return URI.parse(prx) + end + return nil +end + +httpd = WEBrick::HTTPProxyServer.new( + :Port => 10080, + :ProxyContentHandler => pch, + :ProxyURI => upstream_proxy +) +Signal.trap(:INT){ httpd.shutdown } +httpd.start diff --git a/sample/webrick/httpsd.rb b/sample/webrick/httpsd.rb new file mode 100644 index 0000000000..a120782c3c --- /dev/null +++ b/sample/webrick/httpsd.rb @@ -0,0 +1,33 @@ +require "webrick" +require "webrick/https" + +hostname = WEBrick::Utils::getservername +subject = [["O", "ruby-lang.org"], ["OU", "sample"], ["CN", hostname]] +comment = "Comment for self-signed certificate" + +httpd = WEBrick::HTTPServer.new( + :DocumentRoot => File::dirname(__FILE__), + :Port => 10443, + :SSLEnable => true, + + # Specify key pair and server certificate. + # :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read("server.key")), + # :SSLCertificate => OpenSSL::X509::Certificate.new(File.read("server.crt")), + + # specify the following SSL options if you want to use auto + # generated self-signed certificate. + :SSLCertName => subject, + :SSLComment => comment, + + :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI. +) + +require "./hello" +httpd.mount("/hello", HelloServlet) + +require "./demo-servlet" +httpd.mount("/urlencoded", DemoServlet, "application/x-www-form-urlencoded") +httpd.mount("/multipart", DemoServlet, "multipart/form-data") + +trap(:INT){ httpd.shutdown } +httpd.start |
