[前][次][番号順一覧][スレッド一覧][生データ]

yarv-diff:228

From: ko1 atdot.net
Date: 12 Feb 2006 07:21:49 -0000
Subject: [yarv-diff:228] r385 - in trunk: . lib lib/irb lib/irb/cmd lib/irb/ext lib/irb/lc lib/irb/lc/ja lib/irb/lc/ja/CVS lib/rss lib/rss/maker

Author: ko1
Date: 2006-02-12 16:21:49 +0900 (Sun, 12 Feb 2006)
New Revision: 385

Added:
   trunk/lib/abbrev.rb
   trunk/lib/base64.rb
   trunk/lib/cgi-lib.rb
   trunk/lib/csv.rb
   trunk/lib/date2.rb
   trunk/lib/eregex.rb
   trunk/lib/ipaddr.rb
   trunk/lib/irb.rb
   trunk/lib/irb/
   trunk/lib/irb/cmd/
   trunk/lib/irb/cmd/chws.rb
   trunk/lib/irb/cmd/fork.rb
   trunk/lib/irb/cmd/help.rb
   trunk/lib/irb/cmd/load.rb
   trunk/lib/irb/cmd/nop.rb
   trunk/lib/irb/cmd/pushws.rb
   trunk/lib/irb/cmd/subirb.rb
   trunk/lib/irb/completion.rb
   trunk/lib/irb/context.rb
   trunk/lib/irb/ext/
   trunk/lib/irb/ext/change-ws.rb
   trunk/lib/irb/ext/history.rb
   trunk/lib/irb/ext/loader.rb
   trunk/lib/irb/ext/math-mode.rb
   trunk/lib/irb/ext/multi-irb.rb
   trunk/lib/irb/ext/save-history.rb
   trunk/lib/irb/ext/tracer.rb
   trunk/lib/irb/ext/use-loader.rb
   trunk/lib/irb/ext/workspaces.rb
   trunk/lib/irb/extend-command.rb
   trunk/lib/irb/frame.rb
   trunk/lib/irb/help.rb
   trunk/lib/irb/init.rb
   trunk/lib/irb/input-method.rb
   trunk/lib/irb/lc/
   trunk/lib/irb/lc/error.rb
   trunk/lib/irb/lc/help-message
   trunk/lib/irb/lc/ja/
   trunk/lib/irb/lc/ja/CVS/
   trunk/lib/irb/lc/ja/CVS/Entries
   trunk/lib/irb/lc/ja/CVS/Repository
   trunk/lib/irb/lc/ja/CVS/Root
   trunk/lib/irb/lc/ja/CVS/Template
   trunk/lib/irb/lc/ja/error.rb
   trunk/lib/irb/lc/ja/help-message
   trunk/lib/irb/locale.rb
   trunk/lib/irb/notifier.rb
   trunk/lib/irb/output-method.rb
   trunk/lib/irb/ruby-lex.rb
   trunk/lib/irb/ruby-token.rb
   trunk/lib/irb/slex.rb
   trunk/lib/irb/version.rb
   trunk/lib/irb/workspace.rb
   trunk/lib/irb/ws-for-case-2.rb
   trunk/lib/irb/xmp.rb
   trunk/lib/jcode.rb
   trunk/lib/logger.rb
   trunk/lib/mailread.rb
   trunk/lib/mathn.rb
   trunk/lib/parsedate.rb
   trunk/lib/pathname.rb
   trunk/lib/ping.rb
   trunk/lib/pstore.rb
   trunk/lib/resolv-replace.rb
   trunk/lib/resolv.rb
   trunk/lib/rss.rb
   trunk/lib/rss/
   trunk/lib/rss/0.9.rb
   trunk/lib/rss/1.0.rb
   trunk/lib/rss/2.0.rb
   trunk/lib/rss/content.rb
   trunk/lib/rss/converter.rb
   trunk/lib/rss/dublincore.rb
   trunk/lib/rss/image.rb
   trunk/lib/rss/maker.rb
   trunk/lib/rss/maker/
   trunk/lib/rss/maker/0.9.rb
   trunk/lib/rss/maker/1.0.rb
   trunk/lib/rss/maker/2.0.rb
   trunk/lib/rss/maker/base.rb
   trunk/lib/rss/maker/content.rb
   trunk/lib/rss/maker/dublincore.rb
   trunk/lib/rss/maker/image.rb
   trunk/lib/rss/maker/syndication.rb
   trunk/lib/rss/maker/taxonomy.rb
   trunk/lib/rss/maker/trackback.rb
   trunk/lib/rss/parser.rb
   trunk/lib/rss/rexmlparser.rb
   trunk/lib/rss/rss.rb
   trunk/lib/rss/syndication.rb
   trunk/lib/rss/taxonomy.rb
   trunk/lib/rss/trackback.rb
   trunk/lib/rss/utils.rb
   trunk/lib/rss/xml-stylesheet.rb
   trunk/lib/rss/xmlparser.rb
   trunk/lib/rss/xmlscanner.rb
   trunk/lib/rubyunit.rb
   trunk/lib/scanf.rb
   trunk/lib/shell.rb
   trunk/lib/singleton.rb
   trunk/lib/tsort.rb
   trunk/lib/weakref.rb
Modified:
   trunk/
   trunk/ChangeLog
Log:
 r564@leremita:  ko1 | 2006-02-12 15:58:16 +0900
 	* lib/abbrev.rb : added
 
 	* lib/base64.rb : ditto
 
 	* lib/cgi-lib.rb : ditto
 
 	* lib/csv.rb : ditto
 
 	* lib/date2.rb : ditto
 
 	* lib/eregex.rb : ditto
 
 	* lib/ipaddr.rb : ditto
 
 	* lib/irb.rb : ditto
 
 	* lib/irb/cmd/chws.rb : ditto
 
 	* lib/irb/cmd/fork.rb : ditto
 
 	* lib/irb/cmd/help.rb : ditto
 
 	* lib/irb/cmd/load.rb : ditto
 
 	* lib/irb/cmd/nop.rb : ditto
 
 	* lib/irb/cmd/pushws.rb : ditto
 
 	* lib/irb/cmd/subirb.rb : ditto
 
 	* lib/irb/completion.rb : ditto
 
 	* lib/irb/context.rb : ditto
 
 	* lib/irb/ext/change-ws.rb : ditto
 
 	* lib/irb/ext/history.rb : ditto
 
 	* lib/irb/ext/loader.rb : ditto
 
 	* lib/irb/ext/math-mode.rb : ditto
 
 	* lib/irb/ext/multi-irb.rb : ditto
 
 	* lib/irb/ext/save-history.rb : ditto
 
 	* lib/irb/ext/tracer.rb : ditto
 
 	* lib/irb/ext/use-loader.rb : ditto
 
 	* lib/irb/ext/workspaces.rb : ditto
 
 	* lib/irb/extend-command.rb : ditto
 
 	* lib/irb/frame.rb : ditto
 
 	* lib/irb/help.rb : ditto
 
 	* lib/irb/init.rb : ditto
 
 	* lib/irb/input-method.rb : ditto
 
 	* lib/irb/lc/error.rb : ditto
 
 	* lib/irb/lc/help-message : ditto
 
 	* lib/irb/lc/ja/CVS/Entries : ditto
 
 	* lib/irb/lc/ja/CVS/Repository : ditto
 
 	* lib/irb/lc/ja/CVS/Root : ditto
 
 	* lib/irb/lc/ja/error.rb : ditto
 
 	* lib/irb/lc/ja/help-message : ditto
 
 	* lib/irb/locale.rb : ditto
 
 	* lib/irb/notifier.rb : ditto
 
 	* lib/irb/output-method.rb : ditto
 
 	* lib/irb/ruby-lex.rb : ditto
 
 	* lib/irb/ruby-token.rb : ditto
 
 	* lib/irb/slex.rb : ditto
 
 	* lib/irb/version.rb : ditto
 
 	* lib/irb/workspace.rb : ditto
 
 	* lib/irb/ws-for-case-2.rb : ditto
 
 	* lib/irb/xmp.rb : ditto
 
 	* lib/jcode.rb : ditto
 
 	* lib/logger.rb : ditto
 
 	* lib/mailread.rb : ditto
 
 	* lib/mathn.rb : ditto
 
 	* lib/parsedate.rb : ditto
 
 	* lib/pathname.rb : ditto
 
 	* lib/ping.rb : ditto
 
 	* lib/pstore.rb : ditto
 
 	* lib/resolv-replace.rb : ditto
 
 	* lib/resolv.rb : ditto
 
 	* lib/rss.rb : ditto
 
 	* lib/rss/0.9.rb : ditto
 
 	* lib/rss/1.0.rb : ditto
 
 	* lib/rss/2.0.rb : ditto
 
 	* lib/rss/content.rb : ditto
 
 	* lib/rss/converter.rb : ditto
 
 	* lib/rss/dublincore.rb : ditto
 
 	* lib/rss/image.rb : ditto
 
 	* lib/rss/maker.rb : ditto
 
 	* lib/rss/maker/0.9.rb : ditto
 
 	* lib/rss/maker/1.0.rb : ditto
 
 	* lib/rss/maker/2.0.rb : ditto
 
 	* lib/rss/maker/base.rb : ditto
 
 	* lib/rss/maker/content.rb : ditto
 
 	* lib/rss/maker/dublincore.rb : ditto
 
 	* lib/rss/maker/image.rb : ditto
 
 	* lib/rss/maker/syndication.rb : ditto
 
 	* lib/rss/maker/taxonomy.rb : ditto
 
 	* lib/rss/maker/trackback.rb : ditto
 
 	* lib/rss/parser.rb : ditto
 
 	* lib/rss/rexmlparser.rb : ditto
 
 	* lib/rss/rss.rb : ditto
 
 	* lib/rss/syndication.rb : ditto
 
 	* lib/rss/taxonomy.rb : ditto
 
 	* lib/rss/trackback.rb : ditto
 
 	* lib/rss/utils.rb : ditto
 
 	* lib/rss/xml-stylesheet.rb : ditto
 
 	* lib/rss/xmlparser.rb : ditto
 
 	* lib/rss/xmlscanner.rb : ditto
 
 	* lib/rubyunit.rb : ditto
 
 	* lib/scanf.rb : ditto
 
 	* lib/shell.rb : ditto
 
 	* lib/singleton.rb : ditto
 
 	* lib/tsort.rb : ditto
 
 	* lib/weakref.rb : ditto
 



Property changes on: trunk
___________________________________________________________________
Name: svk:merge
   - 81cd9672-7512-7e48-ae48-6936450e977d:/local/yarv/trunk:562
   + 81cd9672-7512-7e48-ae48-6936450e977d:/local/yarv/trunk:564

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/ChangeLog	2006-02-12 07:21:49 UTC (rev 385)
@@ -4,6 +4,195 @@
 #  from Mon, 03 May 2004 01:24:19 +0900
 #
 
+2006-02-12(Sun) 15:53:21 +0900  Koichi Sasada  <ko1 atdot.net>
+
+	* lib/abbrev.rb : added
+
+	* lib/base64.rb : ditto
+
+	* lib/cgi-lib.rb : ditto
+
+	* lib/csv.rb : ditto
+
+	* lib/date2.rb : ditto
+
+	* lib/eregex.rb : ditto
+
+	* lib/ipaddr.rb : ditto
+
+	* lib/irb.rb : ditto
+
+	* lib/irb/cmd/chws.rb : ditto
+
+	* lib/irb/cmd/fork.rb : ditto
+
+	* lib/irb/cmd/help.rb : ditto
+
+	* lib/irb/cmd/load.rb : ditto
+
+	* lib/irb/cmd/nop.rb : ditto
+
+	* lib/irb/cmd/pushws.rb : ditto
+
+	* lib/irb/cmd/subirb.rb : ditto
+
+	* lib/irb/completion.rb : ditto
+
+	* lib/irb/context.rb : ditto
+
+	* lib/irb/ext/change-ws.rb : ditto
+
+	* lib/irb/ext/history.rb : ditto
+
+	* lib/irb/ext/loader.rb : ditto
+
+	* lib/irb/ext/math-mode.rb : ditto
+
+	* lib/irb/ext/multi-irb.rb : ditto
+
+	* lib/irb/ext/save-history.rb : ditto
+
+	* lib/irb/ext/tracer.rb : ditto
+
+	* lib/irb/ext/use-loader.rb : ditto
+
+	* lib/irb/ext/workspaces.rb : ditto
+
+	* lib/irb/extend-command.rb : ditto
+
+	* lib/irb/frame.rb : ditto
+
+	* lib/irb/help.rb : ditto
+
+	* lib/irb/init.rb : ditto
+
+	* lib/irb/input-method.rb : ditto
+
+	* lib/irb/lc/error.rb : ditto
+
+	* lib/irb/lc/help-message : ditto
+
+	* lib/irb/lc/ja/CVS/Entries : ditto
+
+	* lib/irb/lc/ja/CVS/Repository : ditto
+
+	* lib/irb/lc/ja/CVS/Root : ditto
+
+	* lib/irb/lc/ja/error.rb : ditto
+
+	* lib/irb/lc/ja/help-message : ditto
+
+	* lib/irb/locale.rb : ditto
+
+	* lib/irb/notifier.rb : ditto
+
+	* lib/irb/output-method.rb : ditto
+
+	* lib/irb/ruby-lex.rb : ditto
+
+	* lib/irb/ruby-token.rb : ditto
+
+	* lib/irb/slex.rb : ditto
+
+	* lib/irb/version.rb : ditto
+
+	* lib/irb/workspace.rb : ditto
+
+	* lib/irb/ws-for-case-2.rb : ditto
+
+	* lib/irb/xmp.rb : ditto
+
+	* lib/jcode.rb : ditto
+
+	* lib/logger.rb : ditto
+
+	* lib/mailread.rb : ditto
+
+	* lib/mathn.rb : ditto
+
+	* lib/parsedate.rb : ditto
+
+	* lib/pathname.rb : ditto
+
+	* lib/ping.rb : ditto
+
+	* lib/pstore.rb : ditto
+
+	* lib/resolv-replace.rb : ditto
+
+	* lib/resolv.rb : ditto
+
+	* lib/rss.rb : ditto
+
+	* lib/rss/0.9.rb : ditto
+
+	* lib/rss/1.0.rb : ditto
+
+	* lib/rss/2.0.rb : ditto
+
+	* lib/rss/content.rb : ditto
+
+	* lib/rss/converter.rb : ditto
+
+	* lib/rss/dublincore.rb : ditto
+
+	* lib/rss/image.rb : ditto
+
+	* lib/rss/maker.rb : ditto
+
+	* lib/rss/maker/0.9.rb : ditto
+
+	* lib/rss/maker/1.0.rb : ditto
+
+	* lib/rss/maker/2.0.rb : ditto
+
+	* lib/rss/maker/base.rb : ditto
+
+	* lib/rss/maker/content.rb : ditto
+
+	* lib/rss/maker/dublincore.rb : ditto
+
+	* lib/rss/maker/image.rb : ditto
+
+	* lib/rss/maker/syndication.rb : ditto
+
+	* lib/rss/maker/taxonomy.rb : ditto
+
+	* lib/rss/maker/trackback.rb : ditto
+
+	* lib/rss/parser.rb : ditto
+
+	* lib/rss/rexmlparser.rb : ditto
+
+	* lib/rss/rss.rb : ditto
+
+	* lib/rss/syndication.rb : ditto
+
+	* lib/rss/taxonomy.rb : ditto
+
+	* lib/rss/trackback.rb : ditto
+
+	* lib/rss/utils.rb : ditto
+
+	* lib/rss/xml-stylesheet.rb : ditto
+
+	* lib/rss/xmlparser.rb : ditto
+
+	* lib/rss/xmlscanner.rb : ditto
+
+	* lib/rubyunit.rb : ditto
+
+	* lib/scanf.rb : ditto
+
+	* lib/shell.rb : ditto
+
+	* lib/singleton.rb : ditto
+
+	* lib/tsort.rb : ditto
+
+	* lib/weakref.rb : ditto
+
+
 2006-02-12(Sun) 15:39:09 +0900  Koichi Sasada  <ko1 atdot.net>
 
 	* parse.y : fix to remove including env.h

Added: trunk/lib/abbrev.rb
===================================================================
--- trunk/lib/abbrev.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/abbrev.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,103 @@
+#!/usr/bin/env ruby
+=begin
+#
+# Copyright (c) 2001,2003 Akinori MUSHA <knu iDaemons.org>
+#
+# All rights reserved.  You can redistribute and/or modify it under
+# the same terms as Ruby.
+#
+# $Idaemons: /home/cvs/rb/abbrev.rb,v 1.2 2001/05/30 09:37:45 knu Exp $
+# $RoughId: abbrev.rb,v 1.4 2003/10/14 19:45:42 knu Exp $
+# $Id: abbrev.rb,v 1.2 2004/01/20 05:27:23 dave Exp $
+=end
+
+# Calculate the set of unique abbreviations for a given set of strings.
+#
+#   require 'abbrev'
+#   require 'pp'
+#
+#   pp Abbrev::abbrev(['ruby', 'rules']).sort
+#
+# <i>Generates:</i>
+#
+#   [["rub", "ruby"],
+#    ["ruby", "ruby"],
+#    ["rul", "rules"],
+#    ["rule", "rules"],
+#    ["rules", "rules"]]
+#
+# Also adds an +abbrev+ method to class +Array+.
+
+module Abbrev
+
+  # Given a set of strings, calculate the set of unambiguous
+  # abbreviations for those strings, and return a hash where the keys
+  # are all the possible abbreviations and the values are the full
+  # strings. Thus, given input of "car" and "cone", the keys pointing
+  # to "car" would be "ca" and "car", while those pointing to "cone"
+  # would be "co", "con", and "cone".
+  #
+  # The optional +pattern+ parameter is a pattern or a string. Only
+  # those input strings matching the pattern, or begging the string,
+  # are considered for inclusion in the output hash
+
+  def abbrev(words, pattern = nil)
+    table = {}
+    seen = Hash.new(0)
+
+    if pattern.is_a?(String)
+      pattern = /^#{Regexp.quote(pattern)}/	# regard as a prefix
+    end
+
+    words.each do |word|
+      next if (abbrev = word).empty?
+      while (len = abbrev.rindex(/[\w\W]\z/)) > 0
+	abbrev = word[0,len]
+
+	next if pattern && pattern !~ abbrev
+
+	case seen[abbrev] += 1
+	when 1
+	  table[abbrev] = word
+	when 2
+	  table.delete(abbrev)
+	else
+	  break
+	end
+      end
+    end
+
+    words.each do |word|
+      next if pattern && pattern !~ word
+
+      table[word] = word
+    end
+
+    table
+  end
+
+  module_function :abbrev
+end
+
+class Array
+  # Calculates the set of unambiguous abbreviations for the strings in
+  # +self+. If passed a pattern or a string, only the strings matching
+  # the pattern or starting with the string are considered.
+  #
+  #   %w{ car cone }.abbrev   #=> { "ca" => "car", "car" => "car",
+  #                                 "co" => "cone", "con" => cone",
+  #                                 "cone" => "cone" }
+  def abbrev(pattern = nil)
+    Abbrev::abbrev(self, pattern)
+  end
+end
+
+if $0 == __FILE__
+  while line = gets
+    hash = line.split.abbrev
+
+    hash.sort.each do |k, v|
+      puts "#{k} => #{v}"
+    end
+  end
+end


Property changes on: trunk/lib/abbrev.rb
___________________________________________________________________
Name: svn:mime-type
   + text/script

Added: trunk/lib/base64.rb
===================================================================
--- trunk/lib/base64.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/base64.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,136 @@
+#
+# = base64.rb: methods for base64-encoding and -decoding stings
+#
+# Author:: Yukihiro Matsumoto 
+# Documentation:: Dave Thomas and Gavin Sinclair
+#
+# Until Ruby 1.8.1, these methods were defined at the top-level.  Now
+# they are in the Base64 module but included in the top-level, where
+# their usage is deprecated.
+#
+# See Base64 for documentation.
+#
+
+require "kconv"
+
+
+# The Base64 module provides for the encoding (#encode64) and decoding
+# (#decode64) of binary data using a Base64 representation.
+# 
+# The following particular features are also provided:
+# - encode into lines of a given length (#b64encode)
+# - decode the special format specified in RFC2047 for the
+#   representation of email headers (decode_b)
+#
+# == Example
+#
+# A simple encoding and decoding. 
+# 
+#     require "base64"
+#
+#     enc   = Base64.encode64('Send reinforcements')
+#                         # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n" 
+#     plain = Base64.decode64(enc)
+#                         # -> "Send reinforcements"
+#
+# The purpose of using base64 to encode data is that it translates any
+# binary data into purely printable characters.  It is specified in
+# RFC 2045 (http://www.faqs.org/rfcs/rfc2045.html).
+
+module Base64
+  module_function
+
+  # Returns the Base64-decoded version of +str+.
+  #
+  #   require 'base64'
+  #   str = 'VGhpcyBpcyBsaW5lIG9uZQpUaGlzIG' +
+  #         'lzIGxpbmUgdHdvClRoaXMgaXMgbGlu' +
+  #         'ZSB0aHJlZQpBbmQgc28gb24uLi4K'
+  #   puts Base64.decode64(str)
+  #
+  # <i>Generates:</i>
+  #
+  #    This is line one
+  #    This is line two
+  #    This is line three
+  #    And so on...
+
+  def decode64(str)
+    str.unpack("m")[0]
+  end
+
+
+  # Decodes text formatted using a subset of RFC2047 (the one used for
+  # mime-encoding mail headers).
+  #
+  # Only supports an encoding type of 'b' (base 64), and only supports
+  # the character sets ISO-2022-JP and SHIFT_JIS (so the only two
+  # encoded word sequences recognized are <tt>=?ISO-2022-JP?B?...=</tt> and
+  # <tt>=?SHIFT_JIS?B?...=</tt>).  Recognition of these sequences is case
+  # insensitive.
+
+  def decode_b(str)
+    str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) {
+      decode64($1)
+    }
+    str = Kconv::toeuc(str)
+    str.gsub!(/=\?SHIFT_JIS\?B\?([!->@-~]+)\?=/i) {
+      decode64($1)
+    }
+    str = Kconv::toeuc(str)
+    str.gsub!(/\n/, ' ') 
+    str.gsub!(/\0/, '')
+    str
+  end
+
+  # Returns the Base64-encoded version of +str+.
+  #
+  #    require 'base64'
+  #    Base64.b64encode("Now is the time for all good coders\nto learn Ruby")
+  #
+  # <i>Generates:</i>
+  #
+  #    Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g
+  #    UnVieQ==
+
+  def encode64(bin)
+    [bin].pack("m")
+  end
+
+  # _Prints_ the Base64 encoded version of +bin+ (a +String+) in lines of
+  # +len+ (default 60) characters.
+  #
+  #    require 'base64'
+  #    data = "Now is the time for all good coders\nto learn Ruby" 
+  #    puts Base64.b64encode(data)
+  #
+  # <i>Generates:</i>
+  #
+  #    Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g
+  #    UnVieQ==
+
+  def b64encode(bin, len = 60)
+    encode64(bin).scan(/.{1,#{len}}/o) do
+      print $&, "\n"
+    end
+  end 
+
+
+  module Deprecated # :nodoc:
+    include Base64
+
+    def _deprecated_base64(*args)
+      m0, m1 = caller(0)
+      m = m0[/\`(.*?)\'\z/, 1]
+      warn("#{m1}: #{m} is deprecated; use Base64.#{m} instead")
+      super
+    end
+    dep = instance_method(:_deprecated_base64)
+    remove_method(:_deprecated_base64)
+    for m in Base64.private_instance_methods(false)
+      define_method(m, dep)
+    end
+  end
+end
+
+include Base64::Deprecated

Added: trunk/lib/cgi-lib.rb
===================================================================
--- trunk/lib/cgi-lib.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/cgi-lib.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,272 @@
+warn "Warning:#{caller[0].sub(/:in `.*'\z/, '')}: cgi-lib is deprecated after Ruby 1.8.1; use cgi instead"
+
+=begin
+
+= simple CGI support library
+
+= example
+
+== get form values
+
+	require "cgi-lib.rb"
+	query = CGI.new
+	query['field']   # <== value of 'field'
+	query.keys       # <== array of fields
+
+and query has Hash class methods
+
+
+== get cookie values
+
+	require "cgi-lib.rb"
+	query = CGI.new
+	query.cookie['name']  # <== cookie value of 'name'
+	query.cookie.keys     # <== all cookie names
+
+and query.cookie has Hash class methods
+
+
+== print HTTP header and HTML string to $>
+
+	require "cgi-lib.rb"
+	CGI::print{
+	  CGI::tag("HTML"){
+	    CGI::tag("HEAD"){ CGI::tag("TITLE"){"TITLE"} } +
+	    CGI::tag("BODY"){
+	      CGI::tag("FORM", {"ACTION"=>"test.rb", "METHOD"=>"POST"}){
+	        CGI::tag("INPUT", {"TYPE"=>"submit", "VALUE"=>"submit"})
+	      } +
+	      CGI::tag("HR")
+	    }
+	  }
+	}
+
+
+== make raw cookie string
+
+	require "cgi-lib.rb"
+	cookie1 = CGI::cookie({'name'    => 'name',
+	                       'value'   => 'value',
+	                       'path'    => 'path',   # optional
+	                       'domain'  => 'domain', # optional
+	                       'expires' => Time.now, # optional
+	                       'secure'  => true      # optional
+	                      })
+
+	CGI::print("Content-Type: text/html", cookie1, cookie2){ "string" }
+
+
+== print HTTP header and string to $>
+
+	require "cgi-lib.rb"
+	CGI::print{ "string" }
+	  # == CGI::print("Content-Type: text/html"){ "string" }
+	CGI::print("Content-Type: text/html", cookie1, cookie2){ "string" }
+
+
+=== NPH (no-parse-header) mode
+
+	require "cgi-lib.rb"
+	CGI::print("nph"){ "string" }
+	  # == CGI::print("nph", "Content-Type: text/html"){ "string" }
+	CGI::print("nph", "Content-Type: text/html", cookie1, cookie2){ "string" }
+
+
+== make HTML tag string
+
+	require "cgi-lib.rb"
+	CGI::tag("element", {"attribute_name"=>"attribute_value"}){"content"}
+
+
+== make HTTP header string
+
+	require "cgi-lib.rb"
+	CGI::header # == CGI::header("Content-Type: text/html")
+	CGI::header("Content-Type: text/html", cookie1, cookie2)
+
+
+=== NPH (no-parse-header) mode
+
+	CGI::header("nph") # == CGI::header("nph", "Content-Type: text/html")
+	CGI::header("nph", "Content-Type: text/html", cookie1, cookie2)
+
+
+== escape url encode
+
+	require "cgi-lib.rb"
+	url_encoded_string = CGI::escape("string")
+
+
+== unescape url encoded
+
+	require "cgi-lib.rb"
+	string = CGI::unescape("url encoded string")
+
+
+== escape HTML &"<>
+
+	require "cgi-lib.rb"
+	CGI::escapeHTML("string")
+
+
+=end
+
+require "delegate"
+
+class CGI < SimpleDelegator
+
+  CR  = "\015"
+  LF  = "\012"
+  EOL = CR + LF
+
+  RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
+  RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
+
+  # make rfc1123 date string
+  def CGI::rfc1123_date(time)
+    t = time.clone.gmtime
+    return format("%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
+                RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
+                t.hour, t.min, t.sec)
+  end
+
+  # escape url encode
+  def CGI::escape(str)
+    str.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
+  end
+
+  # unescape url encoded
+  def CGI::unescape(str)
+    str.gsub(/\+/, ' ').gsub(/%([0-9a-fA-F]{2})/){ [$1.hex].pack("c") }
+  end
+
+  # escape HTML
+  def CGI::escapeHTML(str)
+    str.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
+  end
+
+  # offline mode. read name=value pairs on standard input.
+  def read_from_cmdline
+    require "shellwords.rb"
+    words = Shellwords.shellwords(
+              if not ARGV.empty?
+                ARGV.join(' ')
+              else
+                STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDIN.tty?
+                readlines.join(' ').gsub(/\n/, '')
+              end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26'))
+
+    if words.find{|x| x =~ /=/} then words.join('&') else words.join('+') end
+  end
+
+  def initialize(input = $stdin)
+
+    @inputs = {}
+    @cookie = {}
+
+    case ENV['REQUEST_METHOD']
+    when "GET"
+      ENV['QUERY_STRING'] or ""
+    when "POST"
+      input.read(Integer(ENV['CONTENT_LENGTH'])) or ""
+    else
+      read_from_cmdline
+    end.split(/[&;]/).each do |x|
+      key, val = x.split(/=/,2).collect{|x|CGI::unescape(x)}
+      if @inputs.include?(key)
+        @inputs[key] += "\0" + (val or "")
+      else
+        @inputs[key] = (val or "")
+      end
+    end
+
+    super(@inputs)
+
+    if ENV.has_key?('HTTP_COOKIE') or ENV.has_key?('COOKIE')
+      (ENV['HTTP_COOKIE'] or ENV['COOKIE']).split(/; /).each do |x|
+        key, val = x.split(/=/,2)
+        key = CGI::unescape(key)
+        val = val.split(/&/).collect{|x|CGI::unescape(x)}.join("\0")
+        if @cookie.include?(key)
+          @cookie[key] += "\0" + val
+        else
+          @cookie[key] = val
+        end
+      end
+    end
+  end
+
+  attr("inputs")
+  attr("cookie")
+
+  # make HTML tag string
+  def CGI::tag(element, attributes = {})
+    "<" + escapeHTML(element) + attributes.collect{|name, value|
+      " " + escapeHTML(name) + '="' + escapeHTML(value) + '"'
+    }.to_s + ">" +
+    (iterator? ? yield.to_s + "</" + escapeHTML(element) + ">" : "")
+  end
+
+  # make raw cookie string
+  def CGI::cookie(options)
+    "Set-Cookie: " + options['name'] + '=' + escape(options['value']) +
+    (options['domain']  ? '; domain='  + options['domain'] : '') +
+    (options['path']    ? '; path='    + options['path']   : '') +
+    (options['expires'] ? '; expires=' + rfc1123_date(options['expires']) : '') +
+    (options['secure']  ? '; secure' : '')
+  end
+
+  # make HTTP header string
+  def CGI::header(*options)
+    if defined?(MOD_RUBY)
+      options.each{|option|
+        option.sub(/(.*?): (.*)/){
+          Apache::request.headers_out[$1] = $2
+        }
+      }
+      Apache::request.send_http_header
+      ''
+    else
+      if options.delete("nph") or (ENV['SERVER_SOFTWARE'] =~ /IIS/)
+        [(ENV['SERVER_PROTOCOL'] or "HTTP/1.0") + " 200 OK",
+         "Date: " + rfc1123_date(Time.now),
+         "Server: " + (ENV['SERVER_SOFTWARE'] or ""),
+         "Connection: close"] +
+        (options.empty? ? ["Content-Type: text/html"] : options)
+      else
+        options.empty? ? ["Content-Type: text/html"] : options
+      end.join(EOL) + EOL + EOL
+    end
+  end
+
+  # print HTTP header and string to $>
+  def CGI::print(*options)
+    $>.print CGI::header(*options) + yield.to_s
+  end
+
+  # print message to $>
+  def CGI::message(message, title = "", header = ["Content-Type: text/html"])
+    if message.kind_of?(Hash)
+      title   = message['title']
+      header  = message['header']
+      message = message['body']
+    end
+    CGI::print(*header){
+      CGI::tag("HTML"){
+        CGI::tag("HEAD"){ CGI.tag("TITLE"){ title } } +
+        CGI::tag("BODY"){ message }
+      }
+    }
+    true
+  end
+
+  # print error message to $> and exit
+  def CGI::error
+    CGI::message({'title'=>'ERROR', 'body'=>
+      CGI::tag("PRE"){
+        "ERROR: " + CGI::tag("STRONG"){ escapeHTML($!.to_s) } + "\n" + escapeHTML($@.join("\n"))
+      }
+    })
+    exit
+  end
+end

Added: trunk/lib/csv.rb
===================================================================
--- trunk/lib/csv.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/csv.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,972 @@
+# CSV -- module for generating/parsing CSV data.
+# Copyright (C) 2000-2004  NAKAMURA, Hiroshi <nakahiro sarion.co.jp>.
+  
+# $Id: csv.rb,v 1.10 2004/05/26 14:30:29 nahi Exp $
+  
+# This program is copyrighted free software by NAKAMURA, Hiroshi.  You can
+# redistribute it and/or modify it under the same terms of Ruby's license;
+# either the dual license version in 2003, or any later version.
+  
+  
+class CSV
+  class IllegalFormatError < RuntimeError; end
+
+  # Open a CSV formatted file for reading or writing.
+  #
+  # For reading.
+  #
+  # EXAMPLE 1
+  #   CSV.open('csvfile.csv', 'r') do |row|
+  #     p row
+  #   end
+  #
+  # EXAMPLE 2
+  #   reader = CSV.open('csvfile.csv', 'r')
+  #   row1 = reader.shift
+  #   row2 = reader.shift
+  #   if row2.empty?
+  #     p 'row2 not find.'
+  #   end
+  #   reader.close
+  #
+  # ARGS
+  #   filename: filename to parse.
+  #   col_sep: Column separator.  ?, by default.  If you want to separate
+  #     fields with semicolon, give ?; here.
+  #   row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
+  #     want to separate records with \r, give ?\r here.
+  #
+  # RETURNS
+  #   reader instance.  To get parse result, see CSV::Reader#each.
+  #
+  #
+  # For writing.
+  #
+  # EXAMPLE 1
+  #   CSV.open('csvfile.csv', 'w') do |writer|
+  #     writer << ['r1c1', 'r1c2']
+  #     writer << ['r2c1', 'r2c2']
+  #     writer << [nil, nil]
+  #   end
+  #
+  # EXAMPLE 2
+  #   writer = CSV.open('csvfile.csv', 'w')
+  #   writer << ['r1c1', 'r1c2'] << ['r2c1', 'r2c2'] << [nil, nil]
+  #   writer.close
+  #
+  # ARGS
+  #   filename: filename to generate.
+  #   col_sep: Column separator.  ?, by default.  If you want to separate
+  #     fields with semicolon, give ?; here.
+  #   row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
+  #     want to separate records with \r, give ?\r here.
+  #
+  # RETURNS
+  #   writer instance.  See CSV::Writer#<< and CSV::Writer#add_row to know how
+  #   to generate CSV string.
+  #
+  def CSV.open(path, mode, fs = nil, rs = nil, &block)
+    if mode == 'r' or mode == 'rb'
+      open_reader(path, mode, fs, rs, &block)
+    elsif mode == 'w' or mode == 'wb'
+      open_writer(path, mode, fs, rs, &block)
+    else
+      raise ArgumentError.new("'mode' must be 'r', 'rb', 'w', or 'wb'")
+    end
+  end
+
+  def CSV.foreach(path, rs = nil, &block)
+    open_reader(path, 'r', ',', rs, &block)
+  end
+
+  def CSV.read(path, length = nil, offset = nil)
+    CSV.parse(IO.read(path, length, offset))
+  end
+  
+  def CSV.readlines(path, rs = nil)
+    reader = open_reader(path, 'r', ',', rs)
+    begin
+      reader.collect { |row| row }
+    ensure
+      reader.close
+    end
+  end
+
+  def CSV.generate(path, fs = nil, rs = nil, &block)
+    open_writer(path, 'w', fs, rs, &block)
+  end
+
+  # Parse lines from given string or stream.  Return rows as an Array of Arrays.
+  def CSV.parse(str_or_readable, fs = nil, rs = nil, &block)
+    if block
+      CSV::Reader.parse(str_or_readable, fs, rs) do |row|
+        yield(row)
+      end
+      nil
+    else
+      CSV::Reader.create(str_or_readable, fs, rs).collect { |row| row }
+    end
+  end
+
+  # Parse a line from given string.  Bear in mind it parses ONE LINE.  Rest of
+  # the string is ignored for example "a,b\r\nc,d" => ['a', 'b'] and the
+  # second line 'c,d' is ignored.
+  #
+  # If you don't know whether a target string to parse is exactly 1 line or
+  # not, use CSV.parse_row instead of this method.
+  def CSV.parse_line(src, fs = nil, rs = nil)
+    fs ||= ','
+    if fs.is_a?(Fixnum)
+      fs = fs.chr
+    end
+    if !rs.nil? and rs.is_a?(Fixnum)
+      rs = rs.chr
+    end
+    idx = 0
+    res_type = :DT_COLSEP
+    row = []
+    begin
+      while res_type == :DT_COLSEP
+        res_type, idx, cell = parse_body(src, idx, fs, rs)
+        row << cell
+      end
+    rescue IllegalFormatError
+      return []
+    end
+    row
+  end
+
+  # Create a line from cells.  each cell is stringified by to_s.
+  def CSV.generate_line(row, fs = nil, rs = nil)
+    if row.size == 0
+      return ''
+    end
+    fs ||= ','
+    if fs.is_a?(Fixnum)
+      fs = fs.chr
+    end
+    if !rs.nil? and rs.is_a?(Fixnum)
+      rs = rs.chr
+    end
+    res_type = :DT_COLSEP
+    result_str = ''
+    idx = 0
+    while true
+      generate_body(row[idx], result_str, fs, rs)
+      idx += 1
+      if (idx == row.size)
+        break
+      end
+      generate_separator(:DT_COLSEP, result_str, fs, rs)
+    end
+    result_str
+  end
+  
+  # Parse a line from string.  Consider using CSV.parse_line instead.
+  # To parse lines in CSV string, see EXAMPLE below.
+  #
+  # EXAMPLE
+  #   src = "a,b\r\nc,d\r\ne,f"
+  #   idx = 0
+  #   begin
+  #     parsed = []
+  #     parsed_cells, idx = CSV.parse_row(src, idx, parsed)
+  #     puts "Parsed #{ parsed_cells } cells."
+  #     p parsed
+  #   end while parsed_cells > 0
+  #
+  # ARGS
+  #   src: a CSV data to be parsed.  Must respond '[](idx)'.
+  #     src[](idx) must return a char. (Not a string such as 'a', but 97).
+  #     src[](idx_out_of_bounds) must return nil.  A String satisfies this
+  #     requirement.
+  #   idx: index of parsing location of 'src'.  0 origin.
+  #   out_dev: buffer for parsed cells.  Must respond '<<(aString)'.
+  #   col_sep: Column separator.  ?, by default.  If you want to separate
+  #     fields with semicolon, give ?; here.
+  #   row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
+  #     want to separate records with \r, give ?\r here.
+  #
+  # RETURNS
+  #   parsed_cells: num of parsed cells.
+  #   idx: index of next parsing location of 'src'.
+  #
+  def CSV.parse_row(src, idx, out_dev, fs = nil, rs = nil)
+    fs ||= ','
+    if fs.is_a?(Fixnum)
+      fs = fs.chr
+    end
+    if !rs.nil? and rs.is_a?(Fixnum)
+      rs = rs.chr
+    end
+    idx_backup = idx
+    parsed_cells = 0
+    res_type = :DT_COLSEP
+    begin
+      while res_type != :DT_ROWSEP
+        res_type, idx, cell = parse_body(src, idx, fs, rs)
+        if res_type == :DT_EOS
+          if idx == idx_backup #((parsed_cells == 0) and cell.nil?)
+            return 0, 0
+          end
+          res_type = :DT_ROWSEP
+        end
+        parsed_cells += 1
+        out_dev << cell
+      end
+    rescue IllegalFormatError
+      return 0, 0
+    end
+    return parsed_cells, idx
+  end
+  
+  # Convert a line from cells data to string.  Consider using CSV.generate_line
+  # instead.  To generate multi-row CSV string, see EXAMPLE below.
+  #
+  # EXAMPLE
+  #   row1 = ['a', 'b']
+  #   row2 = ['c', 'd']
+  #   row3 = ['e', 'f']
+  #   src = [row1, row2, row3]
+  #   buf = ''
+  #   src.each do |row|
+  #     parsed_cells = CSV.generate_row(row, 2, buf)
+  #     puts "Created #{ parsed_cells } cells."
+  #   end
+  #   p buf
+  #
+  # ARGS
+  #   src: an Array of String to be converted to CSV string.  Must respond to
+  #     'size' and '[](idx)'.  src[idx] must return String.
+  #   cells: num of cells in a line.
+  #   out_dev: buffer for generated CSV string.  Must respond to '<<(string)'.
+  #   col_sep: Column separator.  ?, by default.  If you want to separate
+  #     fields with semicolon, give ?; here.
+  #   row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
+  #     want to separate records with \r, give ?\r here.
+  #
+  # RETURNS
+  #   parsed_cells: num of converted cells.
+  #
+  def CSV.generate_row(src, cells, out_dev, fs = nil, rs = nil)
+    fs ||= ','
+    if fs.is_a?(Fixnum)
+      fs = fs.chr
+    end
+    if !rs.nil? and rs.is_a?(Fixnum)
+      rs = rs.chr
+    end
+    src_size = src.size
+    if (src_size == 0)
+      if cells == 0
+        generate_separator(:DT_ROWSEP, out_dev, fs, rs)
+      end
+      return 0
+    end
+    res_type = :DT_COLSEP
+    parsed_cells = 0
+    generate_body(src[parsed_cells], out_dev, fs, rs)
+    parsed_cells += 1
+    while ((parsed_cells < cells) and (parsed_cells != src_size))
+      generate_separator(:DT_COLSEP, out_dev, fs, rs)
+      generate_body(src[parsed_cells], out_dev, fs, rs)
+      parsed_cells += 1
+    end
+    if (parsed_cells == cells)
+      generate_separator(:DT_ROWSEP, out_dev, fs, rs)
+    else
+      generate_separator(:DT_COLSEP, out_dev, fs, rs)
+    end
+    parsed_cells
+  end
+  
+  # Private class methods.
+  class << self
+  private
+
+    def open_reader(path, mode, fs, rs, &block)
+      file = File.open(path, mode)
+      if block
+        begin
+          CSV::Reader.parse(file, fs, rs) do |row|
+            yield(row)
+          end
+        ensure
+          file.close
+        end
+        nil
+      else
+        reader = CSV::Reader.create(file, fs, rs)
+        reader.close_on_terminate
+        reader
+      end
+    end
+
+    def open_writer(path, mode, fs, rs, &block)
+      file = File.open(path, mode)
+      if block
+        begin
+          CSV::Writer.generate(file, fs, rs) do |writer|
+            yield(writer)
+          end
+        ensure
+          file.close
+        end
+        nil
+      else
+        writer = CSV::Writer.create(file, fs, rs) 
+        writer.close_on_terminate
+        writer
+      end
+    end
+
+    def parse_body(src, idx, fs, rs)
+      fs_str = fs
+      fs_size = fs_str.size
+      rs_str = rs || "\n"
+      rs_size = rs_str.size
+      fs_idx = rs_idx = 0
+      cell = ''
+      state = :ST_START
+      quoted = cr = false
+      c = nil
+      last_idx = idx
+      while c = src[idx]
+        unless quoted
+          fschar = (c == fs_str[fs_idx])
+          rschar = (c == rs_str[rs_idx])
+          # simple 1 char backtrack
+          if !fschar and c == fs_str[0]
+            fs_idx = 0
+            fschar = true
+            if state == :ST_START
+              state = :ST_DATA
+            elsif state == :ST_QUOTE
+              raise IllegalFormatError
+            end
+          end
+          if !rschar and c == rs_str[0]
+            rs_idx = 0
+            rschar = true
+            if state == :ST_START
+              state = :ST_DATA
+            elsif state == :ST_QUOTE
+              raise IllegalFormatError
+            end
+          end
+        end
+        if c == ?"
+          fs_idx = rs_idx = 0
+          if cr
+            raise IllegalFormatError
+          end
+          cell << src[last_idx, (idx - last_idx)]
+          last_idx = idx
+          if state == :ST_DATA
+            if quoted
+              last_idx += 1
+              quoted = false
+              state = :ST_QUOTE
+            else
+              raise IllegalFormatError
+            end
+          elsif state == :ST_QUOTE
+            cell << c.chr
+            last_idx += 1
+            quoted = true
+            state = :ST_DATA
+          else  # :ST_START
+            quoted = true
+            last_idx += 1
+            state = :ST_DATA
+          end
+        elsif fschar or rschar
+          if fschar
+            fs_idx += 1
+          end
+          if rschar
+            rs_idx += 1
+          end
+          sep = nil
+          if fs_idx == fs_size
+            if state == :ST_START and rs_idx > 0 and fs_idx < rs_idx
+              state = :ST_DATA
+            end
+            cell << src[last_idx, (idx - last_idx - (fs_size - 1))]
+            last_idx = idx
+            fs_idx = rs_idx = 0
+            if cr
+              raise IllegalFormatError
+            end
+            sep = :DT_COLSEP
+          elsif rs_idx == rs_size
+            if state == :ST_START and fs_idx > 0 and rs_idx < fs_idx
+              state = :ST_DATA
+            end
+            if !(rs.nil? and cr)
+              cell << src[last_idx, (idx - last_idx - (rs_size - 1))]
+              last_idx = idx
+            end
+            fs_idx = rs_idx = 0
+            sep = :DT_ROWSEP
+          end
+          if sep
+            if state == :ST_DATA
+              return sep, idx + 1, cell;
+            elsif state == :ST_QUOTE
+              return sep, idx + 1, cell;
+            else  # :ST_START
+              return sep, idx + 1, nil
+            end
+          end
+        elsif rs.nil? and c == ?\r
+          # special \r treatment for backward compatibility
+          fs_idx = rs_idx = 0
+          if cr
+            raise IllegalFormatError
+          end
+          cell << src[last_idx, (idx - last_idx)]
+          last_idx = idx
+          if quoted
+            state = :ST_DATA
+          else
+            cr = true
+          end
+        else
+          fs_idx = rs_idx = 0
+          if state == :ST_DATA or state == :ST_START
+            if cr
+              raise IllegalFormatError
+            end
+            state = :ST_DATA
+          else  # :ST_QUOTE
+            raise IllegalFormatError
+          end
+        end
+        idx += 1
+      end
+      if state == :ST_START
+        if fs_idx > 0 or rs_idx > 0
+          state = :ST_DATA
+        else
+          return :DT_EOS, idx, nil
+        end
+      elsif quoted
+        raise IllegalFormatError
+      elsif cr
+        raise IllegalFormatError
+      end
+      cell << src[last_idx, (idx - last_idx)]
+      last_idx = idx
+      return :DT_EOS, idx, cell
+    end
+  
+    def generate_body(cell, out_dev, fs, rs)
+      if cell.nil?
+        # empty
+      else
+        cell = cell.to_s
+        row_data = cell.dup
+        if (row_data.gsub!('"', '""') or
+            row_data.index(fs) or
+            (rs and row_data.index(rs)) or
+            (/[\r\n]/ =~ row_data) or
+            (cell.empty?))
+          out_dev << '"' << row_data << '"'
+        else
+          out_dev << row_data
+        end
+      end
+    end
+    
+    def generate_separator(type, out_dev, fs, rs)
+      case type
+      when :DT_COLSEP
+        out_dev << fs
+      when :DT_ROWSEP
+        out_dev << (rs || "\n")
+      end
+    end
+  end
+
+
+  # CSV formatted string/stream reader.
+  #
+  # EXAMPLE
+  #   read CSV lines untill the first column is 'stop'.
+  #
+  #   CSV::Reader.parse(File.open('bigdata', 'rb')) do |row|
+  #     p row
+  #     break if !row[0].is_null && row[0].data == 'stop'
+  #   end
+  #
+  class Reader
+    include Enumerable
+
+    # Parse CSV data and get lines.  Given block is called for each parsed row.
+    # Block value is always nil.  Rows are not cached for performance reason.
+    def Reader.parse(str_or_readable, fs = ',', rs = nil, &block)
+      reader = Reader.create(str_or_readable, fs, rs)
+      if block
+        reader.each do |row|
+          yield(row)
+        end
+        reader.close
+        nil
+      else
+        reader
+      end
+    end
+
+    # Returns reader instance.
+    def Reader.create(str_or_readable, fs = ',', rs = nil)
+      case str_or_readable
+      when IO
+        IOReader.new(str_or_readable, fs, rs)
+      when String
+        StringReader.new(str_or_readable, fs, rs)
+      else
+        IOReader.new(str_or_readable, fs, rs)
+      end
+    end
+
+    def each
+      while true
+        row = []
+        parsed_cells = get_row(row)
+        if parsed_cells == 0
+          break
+        end
+        yield(row)
+      end
+      nil
+    end
+
+    def shift
+      row = []
+      parsed_cells = get_row(row)
+      row
+    end
+
+    def close
+      terminate
+    end
+
+  private
+
+    def initialize(dev)
+      raise RuntimeError.new('Do not instanciate this class directly.')
+    end
+
+    def get_row(row)
+      raise NotImplementedError.new('Method get_row must be defined in a derived class.')
+    end
+
+    def terminate
+      # Define if needed.
+    end
+  end
+  
+
+  class StringReader < Reader
+    def initialize(string, fs = ',', rs = nil)
+      @fs = fs
+      @rs = rs
+      @dev = string
+      @idx = 0
+      if @dev[0, 3] == "\xef\xbb\xbf"
+        @idx += 3
+      end
+    end
+
+  private
+
+    def get_row(row)
+      parsed_cells, next_idx = CSV.parse_row(@dev, @idx, row, @fs, @rs)
+      if parsed_cells == 0 and next_idx == 0 and @idx != @dev.size
+        raise IllegalFormatError.new
+      end
+      @idx = next_idx
+      parsed_cells
+    end
+  end
+
+
+  class IOReader < Reader
+    def initialize(io, fs = ',', rs = nil)
+      @io = io
+      @fs = fs
+      @rs = rs
+      @dev = CSV::IOBuf.new(@io)
+      @idx = 0
+      if @dev[0] == 0xef and @dev[1] == 0xbb and @dev[2] == 0xbf
+        @idx += 3
+      end
+      @close_on_terminate = false
+    end
+
+    # Tell this reader to close the IO when terminated (Triggered by invoking
+    # CSV::IOReader#close).
+    def close_on_terminate
+      @close_on_terminate = true
+    end
+
+  private
+
+    def get_row(row)
+      parsed_cells, next_idx = CSV.parse_row(@dev, @idx, row, @fs, @rs)
+      if parsed_cells == 0 and next_idx == 0 and ! dev.is_eos?
+        raise IllegalFormatError.new
+      end
+      dropped = @dev.drop(next_idx)
+      @idx = next_idx - dropped
+      parsed_cells
+    end
+
+    def terminate
+      if @close_on_terminate
+        @io.close
+      end
+
+      if @dev
+        @dev.close
+      end
+    end
+  end
+
+
+  # CSV formatted string/stream writer.
+  #
+  # EXAMPLE
+  #   Write rows to 'csvout' file.
+  #
+  #   outfile = File.open('csvout', 'wb')
+  #   CSV::Writer.generate(outfile) do |csv|
+  #     csv << ['c1', nil, '', '"', "\r\n", 'c2']
+  #     ...
+  #   end
+  #
+  #   outfile.close
+  #
+  class Writer
+    # Given block is called with the writer instance.  str_or_writable must
+    # handle '<<(string)'.
+    def Writer.generate(str_or_writable, fs = ',', rs = nil, &block)
+      writer = Writer.create(str_or_writable, fs, rs)
+      if block
+        yield(writer)
+        writer.close
+        nil
+      else
+        writer
+      end
+    end
+
+    # str_or_writable must handle '<<(string)'.
+    def Writer.create(str_or_writable, fs = ',', rs = nil)
+      BasicWriter.new(str_or_writable, fs, rs)
+    end
+
+    # dump CSV stream to the device.  argument must be an Array of String.
+    def <<(row)
+      CSV.generate_row(row, row.size, @dev, @fs, @rs)
+      self
+    end
+    alias add_row <<
+
+    def close
+      terminate
+    end
+
+  private
+
+    def initialize(dev)
+      raise RuntimeError.new('Do not instanciate this class directly.')
+    end
+
+    def terminate
+      # Define if needed.
+    end
+  end
+
+
+  class BasicWriter < Writer
+    def initialize(str_or_writable, fs = ',', rs = nil)
+      @fs = fs
+      @rs = rs
+      @dev = str_or_writable
+      @close_on_terminate = false
+    end
+
+    # Tell this writer to close the IO when terminated (Triggered by invoking
+    # CSV::BasicWriter#close).
+    def close_on_terminate
+      @close_on_terminate = true
+    end
+
+  private
+
+    def terminate
+      if @close_on_terminate
+        @dev.close
+      end
+    end
+  end
+
+private
+
+  # Buffered stream.
+  #
+  # EXAMPLE 1 -- an IO.
+  #   class MyBuf < StreamBuf
+  #     # Do initialize myself before a super class.  Super class might call my
+  #     # method 'read'. (Could be awful for C++ user. :-)
+  #     def initialize(s)
+  #       @s = s
+  #       super()
+  #     end
+  #
+  #     # define my own 'read' method.
+  #     # CAUTION: Returning nil means EnfOfStream.
+  #     def read(size)
+  #       @s.read(size)
+  #     end
+  #
+  #     # release buffers. in Ruby which has GC, you do not have to call this...
+  #     def terminate
+  #       @s = nil
+  #       super()
+  #     end
+  #   end
+  #
+  #   buf = MyBuf.new(STDIN)
+  #   my_str = ''
+  #   p buf[0, 0]               # => '' (null string)
+  #   p buf[0]                  # => 97 (char code of 'a')
+  #   p buf[0, 1]               # => 'a'
+  #   my_str = buf[0, 5]
+  #   p my_str                  # => 'abcde' (5 chars)
+  #   p buf[0, 6]               # => "abcde\n" (6 chars)
+  #   p buf[0, 7]               # => "abcde\n" (6 chars)
+  #   p buf.drop(3)             # => 3 (dropped chars)
+  #   p buf.get(0, 2)           # => 'de' (2 chars)
+  #   p buf.is_eos?             # => false (is not EOS here)
+  #   p buf.drop(5)             # => 3 (dropped chars)
+  #   p buf.is_eos?             # => true (is EOS here)
+  #   p buf[0]                  # => nil (is EOS here)
+  #
+  # EXAMPLE 2 -- String.
+  #   This is a conceptual example.  No pros with this.
+  #
+  #   class StrBuf < StreamBuf
+  #     def initialize(s)
+  #       @str = s
+  #       @idx = 0
+  #       super()
+  #     end
+  #
+  #     def read(size)
+  #       str = @str[@idx, size]
+  #       @idx += str.size
+  #       str
+  #     end
+  #   end
+  #
+  class StreamBuf
+    # get a char or a partial string from the stream.
+    # idx: index of a string to specify a start point of a string to get.
+    # unlike String instance, idx < 0 returns nil.
+    # n: size of a string to get.
+    # returns char at idx if n == nil.
+    # returns a partial string, from idx to (idx + n) if n != nil.  at EOF,
+    # the string size could not equal to arg n.
+    def [](idx, n = nil) 
+      if idx < 0
+        return nil
+      end
+      if (idx_is_eos?(idx))
+        if n and (@offset + idx == buf_size(@cur_buf))
+          # Like a String, 'abc'[4, 1] returns nil and
+          # 'abc'[3, 1] returns '' not nil.
+          return ''
+        else
+          return nil
+        end
+      end
+      my_buf = @cur_buf
+      my_offset = @offset
+      next_idx = idx
+      while (my_offset + next_idx >= buf_size(my_buf))
+        if (my_buf == @buf_tail_idx)
+          unless add_buf
+            break
+          end
+        end
+        next_idx = my_offset + next_idx - buf_size(my_buf)
+        my_buf += 1
+        my_offset = 0
+      end
+      loc = my_offset + next_idx
+      if !n
+        return @buf_list[my_buf][loc]           # Fixnum of char code.
+      elsif (loc + n - 1 < buf_size(my_buf))
+        return @buf_list[my_buf][loc, n]        # String.
+      else # should do loop insted of (tail) recursive call...
+        res = @buf_list[my_buf][loc, BufSize]
+        size_added = buf_size(my_buf) - loc
+        if size_added > 0
+          idx += size_added
+          n -= size_added
+          ret = self[idx, n]
+          if ret
+            res << ret
+          end
+        end
+        return res
+      end
+    end
+    alias get []
+  
+    # drop a string from the stream.
+    # returns dropped size.  at EOF, dropped size might not equals to arg n.
+    # Once you drop the head of the stream, access to the dropped part via []
+    # or get returns nil.
+    def drop(n)
+      if is_eos?
+        return 0
+      end
+      size_dropped = 0
+      while (n > 0)
+        if !@is_eos or (@cur_buf != @buf_tail_idx)
+          if (@offset + n < buf_size(@cur_buf))
+            size_dropped += n
+            @offset += n
+            n = 0
+          else
+            size = buf_size(@cur_buf) - @offset
+            size_dropped += size
+            n -= size
+            @offset = 0
+            unless rel_buf
+              unless add_buf
+                break
+              end
+              @cur_buf = @buf_tail_idx
+            end
+          end
+        end
+      end
+      size_dropped
+    end
+  
+    def is_eos?
+      return idx_is_eos?(0)
+    end
+  
+    # WARN: Do not instantiate this class directly.  Define your own class
+    # which derives this class and define 'read' instance method.
+    def initialize
+      @buf_list = []
+      @cur_buf = @buf_tail_idx = -1
+      @offset = 0
+      @is_eos = false
+      add_buf
+      @cur_buf = @buf_tail_idx
+    end
+  
+  protected
+
+    def terminate
+      while (rel_buf); end
+    end
+  
+    # protected method 'read' must be defined in derived classes.
+    # CAUTION: Returning a string which size is not equal to 'size' means
+    # EnfOfStream.  When it is not at EOS, you must block the callee, try to
+    # read and return the sized string.
+    def read(size) # raise EOFError
+      raise NotImplementedError.new('Method read must be defined in a derived class.')
+    end
+  
+  private
+  
+    def buf_size(idx)
+      @buf_list[idx].size
+    end
+
+    def add_buf
+      if @is_eos
+        return false
+      end
+      begin
+        str_read = read(BufSize)
+      rescue EOFError
+        str_read = nil
+      rescue
+        terminate
+        raise
+      end
+      if str_read.nil?
+        @is_eos = true
+        @buf_list.push('')
+        @buf_tail_idx += 1
+        false
+      else
+        @buf_list.push(str_read)
+        @buf_tail_idx += 1
+        true
+      end
+    end
+  
+    def rel_buf
+      if (@cur_buf < 0)
+        return false
+      end
+      @buf_list[@cur_buf] = nil
+      if (@cur_buf == @buf_tail_idx)
+        @cur_buf = -1
+        return false
+      else
+        @cur_buf += 1
+        return true
+      end
+    end
+  
+    def idx_is_eos?(idx)
+      (@is_eos and ((@cur_buf < 0) or (@cur_buf == @buf_tail_idx)))
+    end
+  
+    BufSize = 1024 * 8
+  end
+
+  # Buffered IO.
+  #
+  # EXAMPLE
+  #   # File 'bigdata' could be a giga-byte size one!
+  #   buf = CSV::IOBuf.new(File.open('bigdata', 'rb'))
+  #   CSV::Reader.new(buf).each do |row|
+  #     p row
+  #     break if row[0].data == 'admin'
+  #   end
+  #
+  class IOBuf < StreamBuf
+    def initialize(s)
+      @s = s
+      super()
+    end
+  
+    def close
+      terminate
+    end
+
+  private
+
+    def read(size)
+      @s.read(size)
+    end
+ 
+    def terminate
+      super()
+    end
+  end
+end

Added: trunk/lib/date2.rb
===================================================================
--- trunk/lib/date2.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/date2.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,5 @@
+# date2 was overridden by date.
+# To be precise, date was overridden by date2,
+# and date2 was renamed to date.
+
+require 'date'

Added: trunk/lib/eregex.rb
===================================================================
--- trunk/lib/eregex.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/eregex.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,37 @@
+# this is just a proof of concept toy.
+
+class RegOr
+  def initialize(re1, re2)
+    @re1 = re1
+    @re2 = re2
+  end
+
+  def =~ (str)
+    @re1 =~ str or @re2 =~ str
+  end
+end
+
+class RegAnd
+  def initialize(re1, re2)
+    @re1 = re1
+    @re2 = re2
+  end
+
+  def =~ (str)
+    @re1 =~ str and @re2 =~ str
+  end
+end
+
+class Regexp
+  def |(other)
+    RegOr.new(self, other)
+  end
+  def &(other)
+    RegAnd.new(self, other)
+  end
+end
+
+if __FILE__ == $0
+  p "abc" =~ /b/|/c/
+  p "abc" =~ /b/&/c/
+end

Added: trunk/lib/ipaddr.rb
===================================================================
--- trunk/lib/ipaddr.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/ipaddr.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,767 @@
+#
+# ipaddr.rb - A class to manipulate an IP address
+#
+# Copyright (c) 2002 Hajimu UMEMOTO <ume mahoroba.org>.
+# All rights reserved.
+#
+# You can redistribute and/or modify it under the same terms as Ruby.
+#
+# $Id: ipaddr.rb,v 1.7 2005/01/19 09:13:55 usa Exp $
+#--
+# TODO:
+#   - scope_id support
+#++
+#
+#== Example
+#
+#  require 'ipaddr'
+#
+#  ipaddr1 = IPAddr.new "3ffe:505:2::1"
+#
+#  p ipaddr1			#=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
+#
+#  p ipaddr1.to_s		#=> "3ffe:505:2::1"
+#
+#  ipaddr2 = ipaddr1.mask(48)	#=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
+#
+#  p ipaddr2.to_s		#=> "3ffe:505:2::"
+#
+#  ipaddr3 = IPAddr.new "192.168.2.0/24"
+#
+#  p ipaddr3			#=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
+
+require 'socket'
+
+unless Socket.const_defined? "AF_INET6"
+  class Socket
+    AF_INET6 = Object.new
+  end
+
+  class << IPSocket
+    def valid_v4?(addr)
+      if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
+        return $~.captures.all? {|i| i.to_i < 256}
+      end
+      return false
+    end
+
+    def valid_v6?(addr)
+      # IPv6 (normal)
+      return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
+      return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
+      return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
+      # IPv6 (IPv4 compat)
+      return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_v4?($')
+      return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
+      return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
+
+      false
+    end
+
+    def valid?(addr)
+      valid_v4?(addr) || valid_v6?(addr)
+    end
+
+    alias getaddress_orig getaddress
+    def getaddress(s)
+      if valid?(s)
+        s
+      elsif /\A[-A-Za-z\d.]+\Z/ =~ s
+        getaddress_orig(s)
+      else
+        raise ArgumentError, "invalid address"
+      end
+    end
+  end
+end
+
+# IPAddr provides a set of methods to manipulate an IP address.  Both
+# IPv4 and IPv6 are supported.
+class IPAddr
+
+  IN4MASK = 0xffffffff
+  IN6MASK = 0xffffffffffffffffffffffffffffffff
+  IN6FORMAT = (["%.4x"] * 8).join(':')
+
+  # Returns the address family of this IP address.
+  attr :family
+
+  # Creates a new ipaddr containing the given network byte ordered
+  # string form of an IP address.
+  def IPAddr::new_ntoh(addr)
+    return IPAddr.new(IPAddr::ntop(addr))
+  end
+
+  # Convert a network byte ordered string form of an IP address into
+  # human readable form.
+  def IPAddr::ntop(addr)
+    case addr.size
+    when 4
+      s = addr.unpack('C4').join('.')
+    when 16
+      s = IN6FORMAT % addr.unpack('n8')
+    else
+      raise ArgumentError, "unsupported address family"
+    end
+    return s
+  end
+
+  # Returns a new ipaddr built by bitwise AND.
+  def &(other)
+    return self.clone.set(@addr & other.to_i)
+  end
+
+  # Returns a new ipaddr built by bitwise OR.
+  def |(other)
+    return self.clone.set(@addr | other.to_i)
+  end
+
+  # Returns a new ipaddr built by bitwise right-shift.
+  def >>(num)
+    return self.clone.set(@addr >> num)
+  end
+
+  # Returns a new ipaddr built by bitwise left shift.
+  def <<(num)
+    return self.clone.set(addr_mask(@addr << num))
+  end
+
+  # Returns a new ipaddr built by bitwise negation.
+  def ~
+    return self.clone.set(addr_mask(~@addr))
+  end
+
+  # Returns true if two ipaddr are equal.
+  def ==(other)
+    if other.kind_of?(IPAddr) && @family != other.family
+      return false
+    end
+    return (@addr == other.to_i)
+  end
+
+  # Returns a new ipaddr built by masking IP address with the given
+  # prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.)
+  def mask(prefixlen)
+    return self.clone.mask!(prefixlen)
+  end
+
+  # Returns true if the given ipaddr is in the range.
+  #
+  # e.g.:
+  #   require 'ipaddr'
+  #   net1 = IPAddr.new("192.168.2.0/24")
+  #   p net1.include?(IPAddr.new("192.168.2.0"))	#=> true
+  #   p net1.include?(IPAddr.new("192.168.2.255"))	#=> true
+  #   p net1.include?(IPAddr.new("192.168.3.0"))	#=> false
+  def include?(other)
+    if ipv4_mapped?
+      if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
+	return false
+      end
+      mask_addr = (@mask_addr & IN4MASK)
+      addr = (@addr & IN4MASK)
+      family = Socket::AF_INET
+    else
+      mask_addr = @mask_addr
+      addr = @addr
+      family = @family
+    end
+    if other.kind_of?(IPAddr)
+      if other.ipv4_mapped?
+	other_addr = (other.to_i & IN4MASK)
+	other_family = Socket::AF_INET
+      else
+	other_addr = other.to_i
+	other_family = other.family
+      end
+    else # Not IPAddr - assume integer in same family as us
+      other_addr   = other.to_i
+      other_family = family
+    end
+
+    if family != other_family
+      return false
+    end
+    return ((addr & mask_addr) == (other_addr & mask_addr))
+  end
+  alias === include?
+
+  # Returns the integer representation of the ipaddr.
+  def to_i
+    return @addr
+  end
+
+  # Returns a string containing the IP address representation.
+  def to_s
+    str = to_string
+    return str if ipv4?
+
+    str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
+    loop do
+      break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
+      break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
+      break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
+      break if str.sub!(/\b0:0:0:0:0\b/, ':')
+      break if str.sub!(/\b0:0:0:0\b/, ':')
+      break if str.sub!(/\b0:0:0\b/, ':')
+      break if str.sub!(/\b0:0\b/, ':')
+      break
+    end
+    str.sub!(/:{3,}/, '::')
+
+    if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\Z/i =~ str
+      str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
+    end
+
+    str
+  end
+
+  # Returns a string containing the IP address representation in
+  # canonical form.
+  def to_string
+    return _to_string(@addr)
+  end
+
+  # Returns a network byte ordered string form of the IP address.
+  def hton
+    case @family
+    when Socket::AF_INET
+      return [ addr].pack('N')
+    when Socket::AF_INET6
+      return (0..7).map { |i|
+	(@addr >> (112 - 16 * i)) & 0xffff
+      }.pack('n8')
+    else
+      raise "unsupported address family"
+    end
+  end
+
+  # Returns true if the ipaddr is an IPv4 address.
+  def ipv4?
+    return @family == Socket::AF_INET
+  end
+
+  # Returns true if the ipaddr is an IPv6 address.
+  def ipv6?
+    return @family == Socket::AF_INET6
+  end
+
+  # Returns true if the ipaddr is an IPv4-mapped IPv6 address.
+  def ipv4_mapped?
+    return ipv6? && (@addr >> 32) == 0xffff
+  end
+
+  # Returns true if the ipaddr is an IPv4-compatible IPv6 address.
+  def ipv4_compat?
+    if !ipv6? || (@addr >> 32) != 0
+      return false
+    end
+    a = (@addr & IN4MASK)
+    return a != 0 && a != 1
+  end
+
+  # Returns a new ipaddr built by converting the native IPv4 address
+  # into an IPv4-mapped IPv6 address.
+  def ipv4_mapped
+    if !ipv4?
+      raise ArgumentError, "not an IPv4 address"
+    end
+    return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
+  end
+
+  # Returns a new ipaddr built by converting the native IPv4 address
+  # into an IPv4-compatible IPv6 address.
+  def ipv4_compat
+    if !ipv4?
+      raise ArgumentError, "not an IPv4 address"
+    end
+    return self.clone.set(@addr, Socket::AF_INET6)
+  end
+
+  # Returns a new ipaddr built by converting the IPv6 address into a
+  # native IPv4 address.  If the IP address is not an IPv4-mapped or
+  # IPv4-compatible IPv6 address, returns self.
+  def native
+    if !ipv4_mapped? && !ipv4_compat?
+      return self
+    end
+    return self.clone.set(@addr & IN4MASK, Socket::AF_INET)
+  end
+
+  # Returns a string for DNS reverse lookup.  It returns a string in
+  # RFC3172 form for an IPv6 address.
+  def reverse
+    case @family
+    when Socket::AF_INET
+      return _reverse + ".in-addr.arpa"
+    when Socket::AF_INET6
+      return ip6_arpa
+    else
+      raise "unsupported address family"
+    end
+  end
+
+  # Returns a string for DNS reverse lookup compatible with RFC3172.
+  def ip6_arpa
+    if !ipv6?
+      raise ArgumentError, "not an IPv6 address"
+    end
+    return _reverse + ".ip6.arpa"
+  end
+
+  # Returns a string for DNS reverse lookup compatible with RFC1886.
+  def ip6_int
+    if !ipv6?
+      raise ArgumentError, "not an IPv6 address"
+    end
+    return _reverse + ".ip6.int"
+  end
+
+  # Returns a string containing a human-readable representation of the
+  # ipaddr. ("#<IPAddr: family:address/mask>")
+  def inspect
+    case @family
+    when Socket::AF_INET
+      af = "IPv4"
+    when Socket::AF_INET6
+      af = "IPv6"
+    else
+      raise "unsupported address family"
+    end
+    return sprintf("#<%s: %s:%s/%s>", self.class.name,
+		   af, _to_string(@addr), _to_string(@mask_addr))
+  end
+
+  protected
+
+  def set(addr, *family)
+    case family[0] ? family[0] : @family
+    when Socket::AF_INET
+      if addr < 0 || addr > IN4MASK
+	raise ArgumentError, "invalid address"
+      end
+    when Socket::AF_INET6
+      if addr < 0 || addr > IN6MASK
+	raise ArgumentError, "invalid address"
+      end
+    else
+      raise ArgumentError, "unsupported address family"
+    end
+    @addr = addr
+    if family[0]
+      @family = family[0]
+    end
+    return self
+  end
+
+  def mask!(mask)
+    if mask.kind_of?(String)
+      if mask =~ /^\d+$/
+	prefixlen = mask.to_i
+      else
+	m = IPAddr.new(mask)
+	if m.family != @family
+	  raise ArgumentError, "address family is not same"
+	end
+	@mask_addr = m.to_i
+	@addr &= @mask_addr
+	return self
+      end
+    else
+      prefixlen = mask
+    end
+    case @family
+    when Socket::AF_INET
+      if prefixlen < 0 || prefixlen > 32
+	raise ArgumentError, "invalid length"
+      end
+      masklen = 32 - prefixlen
+      @mask_addr = ((IN4MASK >> masklen) << masklen)
+    when Socket::AF_INET6
+      if prefixlen < 0 || prefixlen > 128
+	raise ArgumentError, "invalid length"
+      end
+      masklen = 128 - prefixlen
+      @mask_addr = ((IN6MASK >> masklen) << masklen)
+    else
+      raise "unsupported address family"
+    end
+    @addr = ((@addr >> masklen) << masklen)
+    return self
+  end
+
+  private
+
+  # Creates a new ipaddr containing the given human readable form of
+  # an IP address.  It also accepts `address/prefixlen' and
+  # `address/mask'.  When prefixlen or mask is specified, it returns a
+  # masked ipaddr.  IPv6 address may beenclosed with `[' and `]'.
+  #
+  # Although an address family is determined automatically from a
+  # specified address, you can specify an address family explicitly by
+  # the optional second argument.
+  def initialize(addr = '::', family = Socket::AF_UNSPEC)
+    if !addr.kind_of?(String)
+      if family != Socket::AF_INET6 && family != Socket::AF_INET
+	raise ArgumentError, "unsupported address family"
+      end
+      set(addr, family)
+      @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
+      return
+    end
+    prefix, prefixlen = addr.split('/')
+    if prefix =~ /^\[(.*)\]$/i
+      prefix = $1
+      family = Socket::AF_INET6
+    end
+    # It seems AI_NUMERICHOST doesn't do the job.
+    #Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
+    #		       Socket::AI_NUMERICHOST)
+    begin
+      IPSocket.getaddress(prefix)		# test if address is vaild
+    rescue
+      raise ArgumentError, "invalid address"
+    end
+    @addr = @family = nil
+    if family == Socket::AF_UNSPEC || family == Socket::AF_INET
+      @addr = in_addr(prefix)
+      if @addr
+	@family = Socket::AF_INET
+      end
+    end
+    if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
+      @addr = in6_addr(prefix)
+      @family = Socket::AF_INET6
+    end
+    if family != Socket::AF_UNSPEC && @family != family
+      raise ArgumentError, "address family unmatch"
+    end
+    if prefixlen
+      mask!(prefixlen)
+    else
+      @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
+    end
+  end
+
+  def in_addr(addr)
+    if addr =~ /^\d+\.\d+\.\d+\.\d+$/
+      n = 0
+      addr.split('.').each { |i|
+	n <<= 8
+	n += i.to_i
+      }
+      return n
+    end
+    return nil
+  end
+
+  def in6_addr(left)
+    case left
+    when /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i
+      return in_addr($1) + 0xffff00000000
+    when /^::(\d+\.\d+\.\d+\.\d+)$/i
+      return in_addr($1)
+    when /[^0-9a-f:]/i
+      raise ArgumentError, "invalid address"
+    when /^(.*)::(.*)$/
+      left, right = $1, $2
+    else
+      right = ''
+    end
+    l = left.split(':')
+    r = right.split(':')
+    rest = 8 - l.size - r.size
+    if rest < 0
+      return nil
+    end
+    a = [l, Array.new(rest, '0'), r].flatten!
+    n = 0
+    a.each { |i|
+      n <<= 16
+      n += i.hex
+    }
+    return n
+  end
+
+  def addr_mask(addr)
+    case @family
+    when Socket::AF_INET
+      addr &= IN4MASK
+    when Socket::AF_INET6
+      addr &= IN6MASK
+    else
+      raise "unsupported address family"
+    end
+    return addr
+  end
+
+  def _reverse
+    case @family
+    when Socket::AF_INET
+      return (0..3).map { |i|
+	(@addr >> (8 * i)) & 0xff
+      }.join('.')
+    when Socket::AF_INET6
+      return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
+    else
+      raise "unsupported address family"
+    end
+  end
+
+  def _to_string(addr)
+    case @family
+    when Socket::AF_INET
+      return (0..3).map { |i|
+	(addr >> (24 - 8 * i)) & 0xff
+      }.join('.')
+    when Socket::AF_INET6
+      return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
+    else
+      raise "unsupported address family"
+    end
+  end
+
+end
+
+if $0 == __FILE__
+  eval DATA.read, nil, $0, __LINE__+4
+end
+
+__END__
+
+require 'test/unit'
+require 'test/unit/ui/console/testrunner'
+
+class TC_IPAddr < Test::Unit::TestCase
+  def test_s_new
+    assert_nothing_raised {
+      IPAddr.new("3FFE:505:ffff::/48")
+      IPAddr.new("0:0:0:1::")
+      IPAddr.new("2001:200:300::/48")
+    }
+
+    a = IPAddr.new
+    assert_equal("::", a.to_s)
+    assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string)
+    assert_equal(Socket::AF_INET6, a.family)
+
+    a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678")
+    assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s)
+    assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string)
+    assert_equal(Socket::AF_INET6, a.family)
+
+    a = IPAddr.new("3ffe:505:2::/48")
+    assert_equal("3ffe:505:2::", a.to_s)
+    assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
+    assert_equal(Socket::AF_INET6, a.family)
+    assert_equal(false, a.ipv4?)
+    assert_equal(true, a.ipv6?)
+    assert_equal("#<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>", a.inspect)
+
+    a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::")
+    assert_equal("3ffe:505:2::", a.to_s)
+    assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
+    assert_equal(Socket::AF_INET6, a.family)
+
+    a = IPAddr.new("0.0.0.0")
+    assert_equal("0.0.0.0", a.to_s)
+    assert_equal("0.0.0.0", a.to_string)
+    assert_equal(Socket::AF_INET, a.family)
+
+    a = IPAddr.new("192.168.1.2")
+    assert_equal("192.168.1.2", a.to_s)
+    assert_equal("192.168.1.2", a.to_string)
+    assert_equal(Socket::AF_INET, a.family)
+    assert_equal(true, a.ipv4?)
+    assert_equal(false, a.ipv6?)
+
+    a = IPAddr.new("192.168.1.2/24")
+    assert_equal("192.168.1.0", a.to_s)
+    assert_equal("192.168.1.0", a.to_string)
+    assert_equal(Socket::AF_INET, a.family)
+    assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.0>", a.inspect)
+
+    a = IPAddr.new("192.168.1.2/255.255.255.0")
+    assert_equal("192.168.1.0", a.to_s)
+    assert_equal("192.168.1.0", a.to_string)
+    assert_equal(Socket::AF_INET, a.family)
+
+    assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s)
+    assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s)
+
+    assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
+
+    [
+      ["fe80::1%fxp0"],
+      ["::1/255.255.255.0"],
+      ["::1:192.168.1.2/120"],
+      [IPAddr.new("::1").to_i],
+      ["::ffff:192.168.1.2/120", Socket::AF_INET],
+      ["[192.168.1.2]/120"],
+    ].each { |args|
+      assert_raises(ArgumentError) {
+	IPAddr.new(*args)
+      }
+    }
+  end
+
+  def test_s_new_ntoh
+    addr = ''
+    IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte { |c|
+      addr += sprintf("%02x", c)
+    }
+    assert_equal("123456789abcdef0123456789abcdef0", addr)
+    addr = ''
+    IPAddr.new("123.45.67.89").hton.each_byte { |c|
+      addr += sprintf("%02x", c)
+    }
+    assert_equal(sprintf("%02x%02x%02x%02x", 123, 45, 67, 89), addr)
+    a = IPAddr.new("3ffe:505:2::")
+    assert_equal("3ffe:505:2::", IPAddr.new_ntoh(a.hton).to_s)
+    a = IPAddr.new("192.168.2.1")
+    assert_equal("192.168.2.1", IPAddr.new_ntoh(a.hton).to_s)
+  end
+
+  def test_ipv4_compat
+    a = IPAddr.new("::192.168.1.2")
+    assert_equal("::192.168.1.2", a.to_s)
+    assert_equal("0000:0000:0000:0000:0000:0000:c0a8:0102", a.to_string)
+    assert_equal(Socket::AF_INET6, a.family)
+    assert_equal(true, a.ipv4_compat?)
+    b = a.native
+    assert_equal("192.168.1.2", b.to_s)
+    assert_equal(Socket::AF_INET, b.family)
+    assert_equal(false, b.ipv4_compat?)
+
+    a = IPAddr.new("192.168.1.2")
+    b = a.ipv4_compat
+    assert_equal("::192.168.1.2", b.to_s)
+    assert_equal(Socket::AF_INET6, b.family)
+  end
+
+  def test_ipv4_mapped
+    a = IPAddr.new("::ffff:192.168.1.2")
+    assert_equal("::ffff:192.168.1.2", a.to_s)
+    assert_equal("0000:0000:0000:0000:0000:ffff:c0a8:0102", a.to_string)
+    assert_equal(Socket::AF_INET6, a.family)
+    assert_equal(true, a.ipv4_mapped?)
+    b = a.native
+    assert_equal("192.168.1.2", b.to_s)
+    assert_equal(Socket::AF_INET, b.family)
+    assert_equal(false, b.ipv4_mapped?)
+
+    a = IPAddr.new("192.168.1.2")
+    b = a.ipv4_mapped
+    assert_equal("::ffff:192.168.1.2", b.to_s)
+    assert_equal(Socket::AF_INET6, b.family)
+  end
+
+  def test_reverse
+    assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").reverse)
+    assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse)
+  end
+
+  def test_ip6_arpa
+    assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa)
+    assert_raises(ArgumentError) {
+      IPAddr.new("192.168.2.1").ip6_arpa
+    }
+  end
+
+  def test_ip6_int
+    assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int)
+    assert_raises(ArgumentError) {
+      IPAddr.new("192.168.2.1").ip6_int
+    }
+  end
+
+  def test_to_s
+    assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string)
+    assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s)
+  end
+end
+
+class TC_Operator < Test::Unit::TestCase
+
+  IN6MASK32  = "ffff:ffff::"
+  IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
+
+  def setup
+    @in6_addr_any = IPAddr.new()
+    @a = IPAddr.new("3ffe:505:2::/48")
+    @b = IPAddr.new("0:0:0:1::")
+    @c = IPAddr.new(IN6MASK32)
+  end
+  alias set_up setup
+
+  def test_or
+    assert_equal("3ffe:505:2:1::", (@a | @b).to_s)
+    a = @a
+    a |= @b
+    assert_equal("3ffe:505:2:1::", a.to_s)
+    assert_equal("3ffe:505:2::", @a.to_s)
+    assert_equal("3ffe:505:2:1::",
+		 (@a | 0x00000000000000010000000000000000).to_s)
+  end
+
+  def test_and
+    assert_equal("3ffe:505::", (@a & @c).to_s)
+    a = @a
+    a &= @c
+    assert_equal("3ffe:505::", a.to_s)
+    assert_equal("3ffe:505:2::", @a.to_s)
+    assert_equal("3ffe:505::", (@a & 0xffffffff000000000000000000000000).to_s)
+  end
+
+  def test_shift_right
+    assert_equal("0:3ffe:505:2::", (@a >> 16).to_s)
+    a = @a
+    a >>= 16
+    assert_equal("0:3ffe:505:2::", a.to_s)
+    assert_equal("3ffe:505:2::", @a.to_s)
+  end
+
+  def test_shift_left
+    assert_equal("505:2::", (@a << 16).to_s)
+    a = @a
+    a <<= 16
+    assert_equal("505:2::", a.to_s)
+    assert_equal("3ffe:505:2::", @a.to_s)
+  end
+
+  def test_carrot
+    a = ~@in6_addr_any
+    assert_equal(IN6MASK128, a.to_s)
+    assert_equal("::", @in6_addr_any.to_s)
+  end
+
+  def test_equal
+    assert_equal(true, @a == IPAddr.new("3ffe:505:2::"))
+    assert_equal(false, @a == IPAddr.new("3ffe:505:3::"))
+    assert_equal(true, @a != IPAddr.new("3ffe:505:3::"))
+    assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
+  end
+
+  def test_mask
+    a = @a.mask(32)
+    assert_equal("3ffe:505::", a.to_s)
+    assert_equal("3ffe:505:2::", @a.to_s)
+  end
+
+  def test_include?
+    assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::")))
+    assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::1")))
+    assert_equal(false, @a.include?(IPAddr.new("3ffe:505:3::")))
+    net1 = IPAddr.new("192.168.2.0/24")
+    assert_equal(true, net1.include?(IPAddr.new("192.168.2.0")))
+    assert_equal(true, net1.include?(IPAddr.new("192.168.2.255")))
+    assert_equal(false, net1.include?(IPAddr.new("192.168.3.0")))
+    # test with integer parameter
+    int = (192 << 24) + (168 << 16) + (2 << 8) + 13
+
+    assert_equal(true, net1.include?(int))
+    assert_equal(false, net1.include?(int+255))
+
+  end
+
+end

Added: trunk/lib/irb/cmd/chws.rb
===================================================================
--- trunk/lib/irb/cmd/chws.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/cmd/chws.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,33 @@
+#
+#   change-ws.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:08 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+require "irb/cmd/nop.rb"
+require "irb/ext/change-ws.rb"
+
+module IRB
+  module ExtendCommand
+
+    class CurrentWorkingWorkspace<Nop
+      def execute(*obj)
+	irb_context.main
+      end
+    end
+
+    class ChangeWorkspace<Nop
+      def execute(*obj)
+	irb_context.change_workspace(*obj)
+	irb_context.main
+      end
+    end
+  end
+end
+

Added: trunk/lib/irb/cmd/fork.rb
===================================================================
--- trunk/lib/irb/cmd/fork.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/cmd/fork.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,39 @@
+#
+#   fork.rb - 
+#   	$Release Version: 0.9.5 $
+#   	$Revision: 1.3 $
+#   	$Date: 2005/04/13 15:27:08 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+@RCS_ID='-$Id: fork.rb,v 1.3 2005/04/13 15:27:08 keiju Exp $-'
+
+
+module IRB
+  module ExtendCommand
+    class Fork<Nop
+      def execute(&block)
+	pid = send ExtendCommand.irb_original_method_name("fork")
+	unless pid 
+	  class<<self
+	    alias_method :exit, ExtendCommand.irb_original_method_name('exit')
+	  end
+	  if iterator?
+	    begin
+	      yield
+	    ensure
+	      exit
+	    end
+	  end
+	end
+	pid
+      end
+    end
+  end
+end
+
+

Added: trunk/lib/irb/cmd/help.rb
===================================================================
--- trunk/lib/irb/cmd/help.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/cmd/help.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,34 @@
+#
+#   help.rb - helper using ri
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/14 09:58:18 $
+#
+# --
+#
+#   
+#
+
+require 'rdoc/ri/ri_driver'
+
+module IRB
+  module ExtendCommand
+    module Help
+      begin
+        @ri = RiDriver.new
+      rescue SystemExit
+      else
+        def self.execute(context, *names)
+          names.each do |name|
+            begin
+              @ri.get_info_for(name.to_s)
+            rescue RiError
+              puts $!.message
+            end
+          end
+          nil
+        end
+      end
+    end
+  end
+end

Added: trunk/lib/irb/cmd/load.rb
===================================================================
--- trunk/lib/irb/cmd/load.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/cmd/load.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,67 @@
+#
+#   load.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:08 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+require "irb/cmd/nop.rb"
+require "irb/ext/loader"
+
+module IRB
+  module ExtendCommand
+    class Load<Nop
+      include IrbLoader
+
+      def execute(file_name, priv = nil)
+#	return ruby_load(file_name) unless IRB.conf[:USE_LOADER]
+	return irb_load(file_name, priv)
+      end
+    end
+
+    class Require<Nop
+      include IrbLoader
+      
+      def execute(file_name)
+#	return ruby_require(file_name) unless IRB.conf[:USE_LOADER]
+
+	rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
+	return false if $".find{|f| f =~ rex}
+
+	case file_name
+	when /\.rb$/
+	  begin
+	    if irb_load(file_name)
+	      $".push file_name
+	      return true
+	    end
+	  rescue LoadError
+	  end
+	when /\.(so|o|sl)$/
+	  return ruby_require(file_name)
+	end
+	
+	begin
+	  irb_load(f = file_name + ".rb")
+	  $".push f
+	  return true
+	rescue LoadError
+	  return ruby_require(file_name)
+	end
+      end
+    end
+
+    class Source<Nop
+      include IrbLoader
+      def execute(file_name)
+	source_file(file_name)
+      end
+    end
+  end
+
+end

Added: trunk/lib/irb/cmd/nop.rb
===================================================================
--- trunk/lib/irb/cmd/nop.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/cmd/nop.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,39 @@
+#
+#   nop.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:08 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+module IRB
+  module ExtendCommand
+    class Nop
+      
+      @RCS_ID='-$Id: nop.rb,v 1.2 2005/04/13 15:27:08 keiju Exp $-'
+
+      def self.execute(conf, *opts)
+	command = new(conf)
+	command.execute(*opts)
+      end
+
+      def initialize(conf)
+	@irb_context = conf
+      end
+
+      attr_reader :irb_context
+
+      def irb
+	@irb_context.irb
+      end
+
+      def execute(*opts)
+	#nop
+      end
+    end
+  end
+end
+

Added: trunk/lib/irb/cmd/pushws.rb
===================================================================
--- trunk/lib/irb/cmd/pushws.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/cmd/pushws.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,39 @@
+#
+#   change-ws.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:08 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+require "irb/cmd/nop.rb"
+require "irb/ext/workspaces.rb"
+
+module IRB
+  module ExtendCommand
+    class Workspaces<Nop
+      def execute(*obj)
+	irb_context.workspaces.collect{|ws| ws.main}
+      end
+    end
+
+    class PushWorkspace<Workspaces
+      def execute(*obj)
+	irb_context.push_workspace(*obj)
+	super
+      end
+    end
+
+    class PopWorkspace<Workspaces
+      def execute(*obj)
+	irb_context.pop_workspace(*obj)
+	super
+      end
+    end
+  end
+end
+

Added: trunk/lib/irb/cmd/subirb.rb
===================================================================
--- trunk/lib/irb/cmd/subirb.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/cmd/subirb.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,43 @@
+#!/usr/local/bin/ruby
+#
+#   multi.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:08 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+require "irb/cmd/nop.rb"
+require "irb/ext/multi-irb"
+
+module IRB
+  module ExtendCommand
+    class IrbCommand<Nop
+      def execute(*obj)
+	IRB.irb(nil, *obj)
+      end
+    end
+
+    class Jobs<Nop
+      def execute
+	IRB.JobManager
+      end
+    end
+
+    class Foreground<Nop
+      def execute(key)
+	IRB.JobManager.switch(key)
+      end
+    end
+
+    class Kill<Nop
+      def execute(*keys)
+	IRB.JobManager.kill(*keys)
+      end
+    end
+  end
+end


Property changes on: trunk/lib/irb/cmd/subirb.rb
___________________________________________________________________
Name: svn:mime-type
   + text/script

Added: trunk/lib/irb/completion.rb
===================================================================
--- trunk/lib/irb/completion.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/completion.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,188 @@
+#
+#   irb/completor.rb - 
+#   	$Release Version: 0.9$
+#   	$Revision: 1.9 $
+#   	$Date: 2004/03/10 07:05:18 $
+#   	by Keiju ISHITSUKA(keiju ishitsuka.com)
+#       From Original Idea of shugo ruby-lang.org
+#
+
+require "readline"
+
+module IRB
+  module InputCompletor
+
+    @RCS_ID='-$Id: completion.rb,v 1.9 2004/03/10 07:05:18 matz Exp $-'
+
+    ReservedWords = [
+      "BEGIN", "END",
+      "alias", "and", 
+      "begin", "break", 
+      "case", "class",
+      "def", "defined", "do",
+      "else", "elsif", "end", "ensure",
+      "false", "for", 
+      "if", "in", 
+      "module", 
+      "next", "nil", "not",
+      "or", 
+      "redo", "rescue", "retry", "return",
+      "self", "super",
+      "then", "true",
+      "undef", "unless", "until",
+      "when", "while",
+      "yield",
+    ]
+      
+    CompletionProc = proc { |input|
+      bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
+      
+#      puts "input: #{input}"
+
+      case input
+      when /^(\/[^\/]*\/)\.([^.]*)$/
+	# Regexp
+	receiver = $1
+	message = Regexp.quote($2)
+
+	candidates = Regexp.instance_methods(true)
+	select_message(receiver, message, candidates)
+
+      when /^([^\]]*\])\.([^.]*)$/
+	# Array
+	receiver = $1
+	message = Regexp.quote($2)
+
+	candidates = Array.instance_methods(true)
+	select_message(receiver, message, candidates)
+
+      when /^([^\}]*\})\.([^.]*)$/
+	# Proc or Hash
+	receiver = $1
+	message = Regexp.quote($2)
+
+	candidates = Proc.instance_methods(true) | Hash.instance_methods(true)
+	select_message(receiver, message, candidates)
+	
+      when /^(:[^:.]*)$/
+ 	# Symbol
+	if Symbol.respond_to?(:all_symbols)
+	  sym = $1
+	  candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
+	  candidates.grep(/^#{sym}/)
+	else
+	  []
+	end
+
+      when /^::([A-Z][^:\.\(]*)$/
+	# Absolute Constant or class methods
+	receiver = $1
+	candidates = Object.constants
+	candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
+
+      when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/
+	# Constant or class methods
+	receiver = $1
+	message = Regexp.quote($4)
+	begin
+	  candidates = eval("#{receiver}.constants | #{receiver}.methods", bind)
+	rescue Exception
+	  candidates = []
+	end
+	candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
+
+      when /^(:[^:.]+)\.([^.]*)$/
+	# Symbol
+	receiver = $1
+	message = Regexp.quote($2)
+
+	candidates = Symbol.instance_methods(true)
+	select_message(receiver, message, candidates)
+
+      when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/
+	# Numeric
+	receiver = $1
+	message = Regexp.quote($4)
+
+	begin
+	  candidates = eval(receiver, bind).methods
+	rescue Exception
+	  candidates
+	end
+	select_message(receiver, message, candidates)
+
+      when /^(\$[^.]*)$/
+	candidates = global_variables.grep(Regexp.new(Regexp.quote($1)))
+
+#      when /^(\$?(\.?[^.]+)+)\.([^.]*)$/
+      when /^((\.?[^.]+)+)\.([^.]*)$/
+	# variable
+	receiver = $1
+	message = Regexp.quote($3)
+
+	gv = eval("global_variables", bind)
+	lv = eval("local_variables", bind)
+	cv = eval("self.class.constants", bind)
+	
+	if (gv | lv | cv).include?(receiver)
+	  # foo.func and foo is local var.
+	  candidates = eval("#{receiver}.methods", bind)
+	elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
+	  # Foo::Bar.func
+	  begin
+	    candidates = eval("#{receiver}.methods", bind)
+	  rescue Exception
+	    candidates = []
+	  end
+	else
+	  # func1.func2
+	  candidates = []
+	  ObjectSpace.each_object(Module){|m|
+	    next if m.name != "IRB::Context" and 
+	      /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
+	    candidates.concat m.instance_methods(false)
+	  }
+	  candidates.sort!
+	  candidates.uniq!
+	end
+	select_message(receiver, message, candidates)
+
+      when /^\.([^.]*)$/
+	# unknown(maybe String)
+
+	receiver = ""
+	message = Regexp.quote($1)
+
+	candidates = String.instance_methods(true)
+	select_message(receiver, message, candidates)
+
+      else
+	candidates = eval("methods | private_methods | local_variables | self.class.constants", bind)
+			  
+	(candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/)
+      end
+    }
+
+    Operators = ["%", "&", "*", "**", "+",  "-",  "/",
+      "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
+      "[]", "[]=", "^",]
+
+    def self.select_message(receiver, message, candidates)
+      candidates.grep(/^#{message}/).collect do |e|
+	case e
+	when /^[a-zA-Z_]/
+	  receiver + "." + e
+	when /^[0-9]/
+	when *Operators
+	  #receiver + " " + e
+	end
+      end
+    end
+  end
+end
+
+if Readline.respond_to?("basic_word_break_characters=")
+  Readline.basic_word_break_characters= " \t\n\"\\'`><=;|&{("
+end
+Readline.completion_append_character = nil
+Readline.completion_proc = IRB::InputCompletor::CompletionProc

Added: trunk/lib/irb/context.rb
===================================================================
--- trunk/lib/irb/context.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/context.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,255 @@
+#
+#   irb/context.rb - irb context
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.11 $
+#   	$Date: 2005/07/29 07:18:34 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+require "irb/workspace"
+
+module IRB
+  class Context
+    #
+    # Arguments:
+    #   input_method: nil -- stdin or readline
+    #		      String -- File
+    #		      other -- using this as InputMethod
+    #
+    def initialize(irb, workspace = nil, input_method = nil, output_method = nil)
+      @irb = irb
+      if workspace
+	@workspace = workspace
+      else
+	@workspace = WorkSpace.new
+      end
+      @thread = Thread.current if defined? Thread
+#      @irb_level = 0
+
+      # copy of default configuration
+      @ap_name = IRB.conf[:AP_NAME]
+      @rc = IRB.conf[:RC]
+      @load_modules = IRB.conf[:LOAD_MODULES]
+
+      @use_readline = IRB.conf[:USE_READLINE]
+      @inspect_mode = IRB.conf[:INSPECT_MODE]
+
+      self.math_mode = IRB.conf[:MATH_MODE] if IRB.conf[:MATH_MODE]
+      self.use_tracer = IRB.conf[:USE_TRACER] if IRB.conf[:USE_TRACER]
+      self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER]
+      self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY]
+
+      @ignore_sigint = IRB.conf[:IGNORE_SIGINT]
+      @ignore_eof = IRB.conf[:IGNORE_EOF]
+
+      @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT]
+      
+      self.prompt_mode = IRB.conf[:PROMPT_MODE]
+
+      if IRB.conf[:SINGLE_IRB] or !defined?(JobManager)
+	@irb_name = IRB.conf[:IRB_NAME]
+      else
+	@irb_name = "irb#"+IRB.JobManager.n_jobs.to_s
+      end
+      @irb_path = "(" + @irb_name + ")"
+
+      case input_method
+      when nil
+	case use_readline?
+	when nil
+	  if (defined?(ReadlineInputMethod) && STDIN.tty? &&
+	      IRB.conf[:PROMPT_MODE] != :INF_RUBY)
+	    @io = ReadlineInputMethod.new
+	  else
+	    @io = StdioInputMethod.new
+	  end
+	when false
+	  @io = StdioInputMethod.new
+	when true
+	  if defined?(ReadlineInputMethod)
+	    @io = ReadlineInputMethod.new
+	  else
+	    @io = StdioInputMethod.new
+	  end
+	end
+
+      when String
+	@io = FileInputMethod.new(input_method)
+	@irb_name = File.basename(input_method)
+	@irb_path = input_method
+      else
+	@io = input_method
+      end
+      self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY]
+
+      if output_method
+	@output_method = output_method
+      else
+	@output_method = StdioOutputMethod.new
+      end
+
+      @verbose = IRB.conf[:VERBOSE] 
+      @echo = IRB.conf[:ECHO]
+      if @echo.nil?
+	@echo = true
+      end
+      @debug_level = IRB.conf[:DEBUG_LEVEL]
+    end
+
+    def main
+      @workspace.main
+    end
+
+    attr_reader :workspace_home
+    attr_accessor :workspace
+    attr_reader :thread
+    attr_accessor :io
+    
+    attr_accessor :irb
+    attr_accessor :ap_name
+    attr_accessor :rc
+    attr_accessor :load_modules
+    attr_accessor :irb_name
+    attr_accessor :irb_path
+
+    attr_reader :use_readline
+    attr_reader :inspect_mode
+
+    attr_reader :prompt_mode
+    attr_accessor :prompt_i
+    attr_accessor :prompt_s
+    attr_accessor :prompt_c
+    attr_accessor :prompt_n
+    attr_accessor :auto_indent_mode
+    attr_accessor :return_format
+
+    attr_accessor :ignore_sigint
+    attr_accessor :ignore_eof
+    attr_accessor :echo
+    attr_accessor :verbose
+    attr_reader :debug_level
+
+    attr_accessor :back_trace_limit
+
+    alias use_readline? use_readline
+    alias rc? rc
+    alias ignore_sigint? ignore_sigint
+    alias ignore_eof? ignore_eof
+    alias echo? echo
+
+    def verbose?
+      if @verbose.nil?
+	if defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod) 
+	  false
+	elsif !STDIN.tty? or @io.kind_of?(FileInputMethod)
+	  true
+	else
+	  false
+	end
+      end
+    end
+
+    def prompting?
+      verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) ||
+		(defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)))
+    end
+
+    attr_reader :last_value
+
+    def set_last_value(value)
+      @last_value = value
+      @workspace.evaluate self, "_ = IRB.CurrentContext.last_value"
+    end
+
+    attr_reader :irb_name
+
+    def prompt_mode=(mode)
+      @prompt_mode = mode
+      pconf = IRB.conf[:PROMPT][mode]
+      @prompt_i = pconf[:PROMPT_I]
+      @prompt_s = pconf[:PROMPT_S]
+      @prompt_c = pconf[:PROMPT_C]
+      @prompt_n = pconf[:PROMPT_N]
+      @return_format = pconf[:RETURN]
+      if ai = pconf.include?(:AUTO_INDENT)
+	@auto_indent_mode = ai
+      else
+	@auto_indent_mode = IRB.conf[:AUTO_INDENT]
+      end
+    end
+    
+    def inspect?
+      @inspect_mode.nil? or @inspect_mode
+    end
+
+    def file_input?
+      @io.class == FileInputMethod
+    end
+
+    def inspect_mode=(opt)
+      if opt
+	@inspect_mode = opt
+      else
+	@inspect_mode = !@inspect_mode
+      end
+      print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose?
+      @inspect_mode
+    end
+
+    def use_readline=(opt)
+      @use_readline = opt
+      print "use readline module\n" if @use_readline
+    end
+
+    def debug_level=(value)
+      @debug_level = value
+      RubyLex.debug_level = value
+      SLex.debug_level = value
+    end
+
+    def debug?
+      @debug_level > 0
+    end
+
+    def evaluate(line, line_no)
+      @line_no = line_no
+      set_last_value( workspace.evaluate(self, line, irb_path, line_no))
+#      @workspace.evaluate("_ = IRB.conf[:MAIN_CONTEXT]._")
+#      @_ = @workspace.evaluate(line, irb_path, line_no)
+    end
+
+    alias __exit__ exit
+    def exit(ret = 0)
+      IRB.irb_exit(@irb, ret)
+    end
+
+    NOPRINTING_IVARS = ["@last_value"]
+    NO_INSPECTING_IVARS = ["@irb", "@io"]
+    IDNAME_IVARS = ["@prompt_mode"]
+
+    alias __inspect__ inspect
+    def inspect
+      array = []
+      for ivar in instance_variables.sort{|e1, e2| e1 <=> e2}
+	name = ivar.sub(/^ (.*)$/){$1}
+	val = instance_eval(ivar)
+	case ivar
+	when *NOPRINTING_IVARS
+	  array.push format("conf.%s=%s", name, "...")
+	when *NO_INSPECTING_IVARS
+	  array.push format("conf.%s=%s", name, val.to_s)
+	when *IDNAME_IVARS
+	  array.push format("conf.%s=:%s", name, val.id2name)
+	else
+	  array.push format("conf.%s=%s", name, val.inspect)
+	end
+      end
+      array.join("\n")
+    end
+    alias __to_s__ to_s
+    alias to_s inspect
+  end
+end

Added: trunk/lib/irb/ext/change-ws.rb
===================================================================
--- trunk/lib/irb/ext/change-ws.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/change-ws.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,62 @@
+#
+#   irb/ext/cb.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:09 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+module IRB
+  class Context
+
+    def home_workspace
+      if defined? @home_workspace
+	@home_workspace
+      else
+	@home_workspace = @workspace
+      end
+    end
+
+    def change_workspace(*_main)
+      if _main.empty?
+	@workspace = home_workspace 
+	return main
+      end
+      
+      @workspace = WorkSpace.new(_main[0])
+      
+      if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
+	main.extend ExtendCommandBundle
+      end
+    end
+
+#     def change_binding(*_main)
+#       back = @workspace
+#       @workspace = WorkSpace.new(*_main)
+#       unless _main.empty?
+# 	begin
+# 	  main.extend ExtendCommandBundle
+# 	rescue
+# 	  print "can't change binding to: ", main.inspect, "\n"
+# 	  @workspace = back
+# 	  return nil
+# 	end
+#       end
+#       @irb_level += 1
+#       begin
+# 	catch(:SU_EXIT) do
+# 	  @irb.eval_input
+# 	end
+#       ensure
+# 	@irb_level -= 1
+#  	@workspace = back
+#       end
+#     end
+#     alias change_workspace change_binding
+   end
+end
+

Added: trunk/lib/irb/ext/history.rb
===================================================================
--- trunk/lib/irb/ext/history.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/history.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,110 @@
+#
+#   history.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.4 $
+#   	$Date: 2005/04/14 06:16:08 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+module IRB
+
+  class Context
+
+    NOPRINTING_IVARS.push "@eval_history_values"
+
+    alias _set_last_value set_last_value
+
+    def set_last_value(value)
+      _set_last_value(value)
+
+#      @workspace.evaluate self, "_ = IRB.CurrentContext.last_value"
+      if @eval_history #and ! eval_history_values.equal?(llv)
+ 	@eval_history_values.push @line_no, @last_value
+ 	@workspace.evaluate self, "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
+      end
+
+      @last_value
+    end
+
+    attr_reader :eval_history
+    def eval_history=(no)
+      if no
+	if defined?(@eval_history) && @eval_history
+	  @eval_history_values.size(no)
+	else
+	  @eval_history_values = History.new(no)
+	  IRB.conf[:__TMP__EHV__] = @eval_history_values
+	  @workspace.evaluate(self, "__ = IRB.conf[:__TMP__EHV__]")
+	  IRB.conf.delete(:__TMP_EHV__)
+	end
+      else
+	@eval_history_values = nil
+      end
+      @eval_history = no
+    end
+  end
+
+  class History
+    @RCS_ID='-$Id: history.rb,v 1.4 2005/04/14 06:16:08 keiju Exp $-'
+
+    def initialize(size = 16)
+      @size = size
+      @contents = []
+    end
+
+    def size(size)
+      if size != 0 && size < @size 
+	@contents = @contents[@size - size .. @size]
+      end
+      @size = size
+    end
+
+    def [](idx)
+      begin
+	if idx >= 0
+	  @contents.find{|no, val| no == idx}[1]
+	else
+	  @contents[idx][1]
+	end
+      rescue NameError
+	nil
+      end
+    end
+
+    def push(no, val)
+      @contents.push [no, val]
+      @contents.shift if @size != 0 && @contents.size > @size
+    end
+    
+    alias real_inspect inspect
+
+    def inspect
+      if @contents.empty?
+	return real_inspect
+      end
+
+      unless (last = @contents.pop)[1].equal?(self)
+	@contents.push last
+	last = nil
+      end
+      str = @contents.collect{|no, val|
+	if val.equal?(self)
+	  "#{no} ...self-history..."
+	else
+	  "#{no} #{val.inspect}"
+	end
+      }.join("\n")
+      if str == ""
+	str = "Empty."
+      end
+      @contents.push last if last
+      str
+    end
+  end
+end
+
+

Added: trunk/lib/irb/ext/loader.rb
===================================================================
--- trunk/lib/irb/ext/loader.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/loader.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,120 @@
+#
+#   loader.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.3 $
+#   	$Date: 2005/04/14 09:58:18 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+
+module IRB
+  class LoadAbort < Exception;end
+
+  module IrbLoader
+    @RCS_ID='-$Id: loader.rb,v 1.3 2005/04/14 09:58:18 keiju Exp $-'
+
+    alias ruby_load load
+    alias ruby_require require
+
+    def irb_load(fn, priv = nil)
+      path = search_file_from_ruby_path(fn)
+      raise LoadError, "No such file to load -- #{fn}" unless path
+
+      load_file(path, priv)
+    end
+
+    def search_file_from_ruby_path(fn)
+      if /^#{Regexp.quote(File::Separator)}/ =~ fn
+	return fn if File.exist?(fn)
+	return nil
+      end
+
+      for path in $:
+	if File.exist?(f = File.join(path, fn))
+	  return f
+	end
+      end
+      return nil
+    end
+
+    def source_file(path)
+      irb.suspend_name(path, File.basename(path)) do
+	irb.suspend_input_method(FileInputMethod.new(path)) do
+	  |back_io|
+	  irb.signal_status(:IN_LOAD) do 
+	    if back_io.kind_of?(FileInputMethod)
+	      irb.eval_input
+	    else
+	      begin
+		irb.eval_input
+	      rescue LoadAbort
+		print "load abort!!\n"
+	      end
+	    end
+	  end
+	end
+      end
+    end
+
+    def load_file(path, priv = nil)
+      irb.suspend_name(path, File.basename(path)) do
+	
+	if priv
+	  ws = WorkSpace.new(Module.new)
+	else
+	  ws = WorkSpace.new
+	end
+	irb.suspend_workspace(ws) do
+	  irb.suspend_input_method(FileInputMethod.new(path)) do
+	    |back_io|
+	    irb.signal_status(:IN_LOAD) do 
+#	      p irb.conf
+	      if back_io.kind_of?(FileInputMethod)
+		irb.eval_input
+	      else
+		begin
+		  irb.eval_input
+		rescue LoadAbort
+		  print "load abort!!\n"
+		end
+	      end
+	    end
+	  end
+	end
+      end
+    end
+
+    def old
+      back_io = @io
+      back_path = @irb_path
+      back_name = @irb_name
+      back_scanner = @irb.scanner
+      begin
+ 	@io = FileInputMethod.new(path)
+ 	@irb_name = File.basename(path)
+	@irb_path = path
+	@irb.signal_status(:IN_LOAD) do
+	  if back_io.kind_of?(FileInputMethod)
+	    @irb.eval_input
+	  else
+	    begin
+	      @irb.eval_input
+	    rescue LoadAbort
+	      print "load abort!!\n"
+	    end
+	  end
+	end
+      ensure
+ 	@io = back_io
+ 	@irb_name = back_name
+ 	@irb_path = back_path
+	@irb.scanner = back_scanner
+      end
+    end
+  end
+end
+

Added: trunk/lib/irb/ext/math-mode.rb
===================================================================
--- trunk/lib/irb/ext/math-mode.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/math-mode.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,37 @@
+#
+#   math-mode.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.3 $
+#   	$Date: 2005/04/13 15:27:09 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+require "mathn"
+
+module IRB
+  class Context
+    attr_reader :math_mode
+    alias math? math_mode
+
+    def math_mode=(opt)
+      if @math_mode == true && opt == false
+	IRB.fail CantReturnToNormalMode
+	return
+      end
+
+      @math_mode = opt
+      if math_mode
+	main.extend Math
+	print "start math mode\n" if verbose?
+      end
+    end
+
+    def inspect?
+      @inspect_mode.nil? && !@math_mode or @inspect_mode
+    end
+  end
+end
+

Added: trunk/lib/irb/ext/multi-irb.rb
===================================================================
--- trunk/lib/irb/ext/multi-irb.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/multi-irb.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,241 @@
+#
+#   irb/multi-irb.rb - multiple irb module
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.3 $
+#   	$Date: 2005/04/13 15:27:09 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+IRB.fail CantShiftToMultiIrbMode unless defined?(Thread)
+require "thread"
+
+module IRB
+  # job management class
+  class JobManager
+    @RCS_ID='-$Id: multi-irb.rb,v 1.3 2005/04/13 15:27:09 keiju Exp $-'
+
+    def initialize
+      # @jobs = [[thread, irb],...]
+      @jobs = []
+      @current_job = nil
+    end
+
+    attr_accessor :current_job
+
+    def n_jobs
+      @jobs.size
+    end
+
+    def thread(key)
+      th, irb = search(key)
+      th
+    end
+
+    def irb(key)
+      th, irb = search(key)
+      irb
+    end
+
+    def main_thread
+      @jobs[0][0]
+    end
+
+    def main_irb
+      @jobs[0][1]
+    end
+
+    def insert(irb)
+      @jobs.push [Thread.current, irb]
+    end
+
+    def switch(key)
+      th, irb = search(key)
+      IRB.fail IrbAlreadyDead unless th.alive?
+      IRB.fail IrbSwitchedToCurrentThread if th == Thread.current
+      @current_job = irb
+      th.run
+      Thread.stop
+      @current_job = irb(Thread.current)
+    end
+
+    def kill(*keys)
+      for key in keys
+	th, irb = search(key)
+	IRB.fail IrbAlreadyDead unless th.alive?
+	th.exit
+      end
+    end    
+
+    def search(key)
+      case key
+      when Integer
+	@jobs[key]
+      when Irb
+	@jobs.find{|k, v| v.equal?(key)}
+      when Thread
+	@jobs.assoc(key)
+      else
+	assoc = @jobs.find{|k, v| v.context.main.equal?(key)}
+	IRB.fail NoSuchJob, key if assoc.nil?
+	assoc
+      end
+    end
+
+    def delete(key)
+      case key
+      when Integer
+	IRB.fail NoSuchJob, key unless @jobs[key]
+	@jobs[key] = nil
+      else
+	catch(:EXISTS) do
+	  @jobs.each_index do
+	    |i|
+	    if @jobs[i] and (@jobs[i][0] == key ||
+			     @jobs[i][1] == key ||
+			     @jobs[i][1].context.main.equal?(key))
+	      @jobs[i] = nil
+	      throw :EXISTS
+	    end
+	  end
+	  IRB.fail NoSuchJob, key
+	end
+      end
+      until assoc = @jobs.pop; end unless @jobs.empty?
+      @jobs.push assoc
+    end
+
+    def inspect
+      ary = []
+      @jobs.each_index do
+	|i|
+	th, irb = @jobs[i]
+	next if th.nil?
+
+	if th.alive?
+	  if th.stop?
+	    t_status = "stop"
+	  else
+	    t_status = "running"
+	  end
+	else
+	  t_status = "exited"
+	end
+	ary.push format("#%d->%s on %s (%s: %s)",
+			i, 
+			irb.context.irb_name, 
+			irb.context.main,
+			th,
+			t_status)
+      end
+      ary.join("\n")
+    end
+  end
+
+  @JobManager = JobManager.new
+
+  def IRB.JobManager
+    @JobManager
+  end
+
+  def IRB.CurrentContext
+    IRB.JobManager.irb(Thread.current).context
+  end
+
+  # invoke multi-irb 
+  def IRB.irb(file = nil, *main)
+    workspace = WorkSpace.new(*main)
+    parent_thread = Thread.current
+    Thread.start do
+      begin
+	irb = Irb.new(workspace, file)
+      rescue 
+	print "Subirb can't start with context(self): ", workspace.main.inspect, "\n"
+	print "return to main irb\n"
+	Thread.pass
+	Thread.main.wakeup
+	Thread.exit
+      end
+      @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
+      @JobManager.insert(irb)
+      @JobManager.current_job = irb
+      begin
+	system_exit = false
+	catch(:IRB_EXIT) do
+	  irb.eval_input
+	end
+      rescue SystemExit
+	system_exit = true
+	raise
+	#fail
+      ensure
+	unless system_exit
+	  @JobManager.delete(irb)
+	  if parent_thread.alive?
+	    @JobManager.current_job = @JobManager.irb(parent_thread)
+	    parent_thread.run
+	  else
+	    @JobManager.current_job = @JobManager.main_irb
+	    @JobManager.main_thread.run
+	  end
+	end
+      end
+    end
+    Thread.stop
+    @JobManager.current_job = @JobManager.irb(Thread.current)
+  end
+
+#   class Context
+#     def set_last_value(value)
+#       @last_value = value
+#       @workspace.evaluate "_ = IRB.JobManager.irb(Thread.current).context.last_value"
+#       if @eval_history #and ! __.equal?( last_value)
+# 	@eval_history_values.push @line_no, @last_value
+# 	@workspace.evaluate "__ = IRB.JobManager.irb(Thread.current).context.instance_eval{@eval_history_values}"
+#       end
+#       @last_value
+#     end
+#   end
+
+#  module ExtendCommand
+#     def irb_context
+#       IRB.JobManager.irb(Thread.current).context
+#     end
+# #    alias conf irb_context
+#   end
+
+  @CONF[:SINGLE_IRB_MODE] = false
+  @JobManager.insert( CONF[:MAIN_CONTEXT].irb)
+  @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb
+
+  class Irb
+    def signal_handle
+      unless @context.ignore_sigint?
+	print "\nabort!!\n" if @context.verbose?
+	exit
+      end
+
+      case @signal_status
+      when :IN_INPUT
+	print "^C\n"
+	IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput
+      when :IN_EVAL
+	IRB.irb_abort(self)
+      when :IN_LOAD
+	IRB.irb_abort(self, LoadAbort)
+      when :IN_IRB
+	# ignore
+      else
+	# ignore other cases as well
+      end
+    end
+  end
+
+  trap("SIGINT") do
+    @JobManager.current_job.signal_handle
+    Thread.stop
+  end
+
+end

Added: trunk/lib/irb/ext/save-history.rb
===================================================================
--- trunk/lib/irb/ext/save-history.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/save-history.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,85 @@
+#!/usr/local/bin/ruby
+#
+#   save-history.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/14 09:58:18 $
+#   	by Keiju ISHITSUKAkeiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+require "readline"
+
+module IRB
+  module HistorySavingAbility
+    @RCS_ID='-$Id: save-history.rb,v 1.2 2005/04/14 09:58:18 keiju Exp $-'
+  end
+
+  class Context
+    def init_save_history
+      unless (class<< io;self;end).include?(HistorySavingAbility)
+	@io.extend(HistorySavingAbility)
+      end
+    end
+
+    def save_history
+      IRB.conf[:SAVE_HISTORY]
+    end
+
+    def save_history=(val)
+      IRB.conf[:SAVE_HISTORY] = val
+      if val
+	main_context = IRB.conf[:MAIN_CONTEXT]
+	main_context = self unless main_context
+	main_context.init_save_history
+      end
+    end
+
+    def history_file
+      IRB.conf[:HISTORY_FILE]
+    end
+
+    def history_file=(hist)
+      IRB.conf[:HISTORY_FILE] = hist
+    end
+  end
+
+  module HistorySavingAbility
+    include Readline
+
+    def HistorySavingAbility.create_finalizer
+      proc do
+	if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0
+	  if hf = IRB.conf[:HISTORY_FILE]
+	    file = File.expand_path(hf)
+	  end
+	  file = IRB.rc_file("_history") unless file
+	  open(file, 'w' ) do |f|
+	    hist = HISTORY.to_a
+	    f.puts(hist[-num..-1] || hist)
+	  end
+	end
+      end
+    end
+
+    def HistorySavingAbility.extended(obj)
+      ObjectSpace.define_finalizer(obj, HistorySavingAbility.create_finalizer)
+      obj.load_history
+      obj
+    end
+
+    def load_history
+      hist = IRB.conf[:HISTORY_FILE]
+      hist = IRB.rc_file("_history") unless hist
+      if File.exist?(hist)
+	open(hist) do |f|
+	  f.each {|l| HISTORY << l.chomp}
+	end
+      end
+    end
+  end
+end
+


Property changes on: trunk/lib/irb/ext/save-history.rb
___________________________________________________________________
Name: svn:mime-type
   + text/script

Added: trunk/lib/irb/ext/tracer.rb
===================================================================
--- trunk/lib/irb/ext/tracer.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/tracer.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,61 @@
+#
+#   irb/lib/tracer.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:09 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+require "tracer"
+
+module IRB
+
+  # initialize tracing function
+  def IRB.initialize_tracer
+    Tracer.verbose = false
+    Tracer.add_filter {
+      |event, file, line, id, binding, *rests|
+      /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and
+	File::basename(file) != "irb.rb"
+    }
+  end
+
+  class Context
+    attr_reader :use_tracer
+    alias use_tracer? use_tracer
+
+    def use_tracer=(opt)
+      if opt
+	Tracer.set_get_line_procs(@irb_path) {
+	  |line_no, *rests|
+	  @io.line(line_no)
+	}
+      elsif !opt && @use_tracer
+	Tracer.off
+      end
+      @use_tracer=opt
+    end
+  end
+
+  class WorkSpace
+    alias __evaluate__ evaluate
+    def evaluate(context, statements, file = nil, line = nil)
+      if context.use_tracer? && file != nil && line != nil
+	Tracer.on 
+	begin
+	  __evaluate__(context, statements, file, line)
+	ensure
+	  Tracer.off
+	end
+      else
+	__evaluate__(context, statements, file || __FILE__, line || __LINE__)
+      end
+    end
+  end
+
+  IRB.initialize_tracer
+end
+	

Added: trunk/lib/irb/ext/use-loader.rb
===================================================================
--- trunk/lib/irb/ext/use-loader.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/use-loader.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,65 @@
+#
+#   use-loader.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:09 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+require "irb/cmd/load"
+require "irb/ext/loader"
+
+class Object
+  alias __original__load__IRB_use_loader__ load
+  alias __original__require__IRB_use_loader__ require
+end
+
+module IRB
+  module ExtendCommandBundle
+    def irb_load(*opts, &b)
+      ExtendCommand::Load.execute(irb_context, *opts, &b)
+    end
+    def irb_require(*opts, &b)
+      ExtendCommand::Require.execute(irb_context, *opts, &b)
+    end
+  end
+
+  class Context
+
+    IRB.conf[:USE_LOADER] = false
+    
+    def use_loader
+      IRB.conf[:USE_LOADER]
+    end
+
+    alias use_loader? use_loader
+
+    def use_loader=(opt)
+
+      if IRB.conf[:USE_LOADER] != opt
+	IRB.conf[:USE_LOADER] = opt
+	if opt
+	  if !$".include?("irb/cmd/load")
+	  end
+	  (class<< workspace.main;self;end).instance_eval {
+	    alias_method :load, :irb_load
+	    alias_method :require, :irb_require
+	  }
+	else
+	  (class<< workspace.main;self;end).instance_eval {
+	    alias_method :load, :__original__load__IRB_use_loader__
+	    alias_method :require, :__original__require__IRB_use_loader__
+	  }
+	end
+      end
+      print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose?
+      opt
+    end
+  end
+end
+
+

Added: trunk/lib/irb/ext/workspaces.rb
===================================================================
--- trunk/lib/irb/ext/workspaces.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/ext/workspaces.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,56 @@
+#
+#   push-ws.rb - 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.2 $
+#   	$Date: 2005/04/13 15:27:09 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+module IRB
+  class Context
+
+    def irb_level
+      workspace_stack.size
+    end
+
+    def workspaces
+      if defined? @workspaces
+	@workspaces
+      else
+	@workspaces = []
+      end
+    end
+
+    def push_workspace(*_main)
+      if _main.empty?
+	if workspaces.empty?
+	  print "No other workspace\n"
+	  return nil
+	end
+	ws = workspaces.pop
+	workspaces.push @workspace
+	@workspace = ws
+	return workspaces
+      end
+
+      workspaces.push @workspace
+      @workspace = WorkSpace.new( workspace.binding, _main[0])
+      if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
+	main.extend ExtendCommandBundle
+      end
+    end
+
+    def pop_workspace
+      if workspaces.empty?
+	print "workspace stack empty\n"
+	return
+      end
+      @workspace = workspaces.pop
+    end
+  end
+end
+

Added: trunk/lib/irb/extend-command.rb
===================================================================
--- trunk/lib/irb/extend-command.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/extend-command.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,264 @@
+#
+#   irb/extend-command.rb - irb extend command 
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.7 $
+#   	$Date: 2005/04/13 15:27:07 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+module IRB
+  #
+  # IRB extended command
+  #
+  module ExtendCommandBundle
+    EXCB = ExtendCommandBundle
+
+    NO_OVERRIDE = 0
+    OVERRIDE_PRIVATE_ONLY = 0x01
+    OVERRIDE_ALL = 0x02
+
+    def irb_exit(ret = 0)
+      irb_context.exit(ret)
+    end
+
+    def irb_context
+      IRB.CurrentContext
+    end
+
+    @ALIASES = [
+      [:context, :irb_context, NO_OVERRIDE],
+      [:conf, :irb_context, NO_OVERRIDE],
+      [:irb_quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+      [:exit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+      [:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+    ]
+
+    @EXTEND_COMMANDS = [
+      [:irb_current_working_workspace, :CurrentWorkingWorkspace, "irb/cmd/chws",
+	[:irb_print_working_workspace, OVERRIDE_ALL],
+	[:irb_cwws, OVERRIDE_ALL],
+	[:irb_pwws, OVERRIDE_ALL],
+#	[:irb_cww, OVERRIDE_ALL],
+#	[:irb_pww, OVERRIDE_ALL],
+	[:cwws, NO_OVERRIDE],
+	[:pwws, NO_OVERRIDE],
+#	[:cww, NO_OVERRIDE],
+#	[:pww, NO_OVERRIDE],
+	[:irb_current_working_binding, OVERRIDE_ALL],
+	[:irb_print_working_binding, OVERRIDE_ALL],
+	[:irb_cwb, OVERRIDE_ALL],
+	[:irb_pwb, OVERRIDE_ALL],
+#	[:cwb, NO_OVERRIDE],
+#	[:pwb, NO_OVERRIDE]
+      ],
+      [:irb_change_workspace, :ChangeWorkspace, "irb/cmd/chws",
+	[:irb_chws, OVERRIDE_ALL],
+#	[:irb_chw, OVERRIDE_ALL],
+	[:irb_cws, OVERRIDE_ALL],
+#	[:irb_cw, OVERRIDE_ALL],
+	[:chws, NO_OVERRIDE],
+#	[:chw, NO_OVERRIDE],
+	[:cws, NO_OVERRIDE],
+#	[:cw, NO_OVERRIDE],
+	[:irb_change_binding, OVERRIDE_ALL],
+	[:irb_cb, OVERRIDE_ALL],
+	[:cb, NO_OVERRIDE]],
+
+      [:irb_workspaces, :Workspaces, "irb/cmd/pushws",
+	[:workspaces, NO_OVERRIDE],
+	[:irb_bindings, OVERRIDE_ALL],
+	[:bindings, NO_OVERRIDE]],
+      [:irb_push_workspace, :PushWorkspace, "irb/cmd/pushws",
+	[:irb_pushws, OVERRIDE_ALL],
+#	[:irb_pushw, OVERRIDE_ALL],
+	[:pushws, NO_OVERRIDE],
+#	[:pushw, NO_OVERRIDE],
+	[:irb_push_binding, OVERRIDE_ALL],
+	[:irb_pushb, OVERRIDE_ALL],
+	[:pushb, NO_OVERRIDE]],
+      [:irb_pop_workspace, :PopWorkspace, "irb/cmd/pushws",
+	[:irb_popws, OVERRIDE_ALL],
+#	[:irb_popw, OVERRIDE_ALL],
+	[:popws, NO_OVERRIDE],
+#	[:popw, NO_OVERRIDE],
+	[:irb_pop_binding, OVERRIDE_ALL],
+	[:irb_popb, OVERRIDE_ALL],
+	[:popb, NO_OVERRIDE]],
+
+      [:irb_load, :Load, "irb/cmd/load"],
+      [:irb_require, :Require, "irb/cmd/load"],
+      [:irb_source, :Source, "irb/cmd/load", 
+	[:source, NO_OVERRIDE]],
+
+      [:irb, :IrbCommand, "irb/cmd/subirb"],
+      [:irb_jobs, :Jobs, "irb/cmd/subirb", 
+	[:jobs, NO_OVERRIDE]],
+      [:irb_fg, :Foreground, "irb/cmd/subirb", 
+	[:fg, NO_OVERRIDE]],
+      [:irb_kill, :Kill, "irb/cmd/subirb", 
+	[:kill, OVERRIDE_PRIVATE_ONLY]],
+
+      [:irb_help, :Help, "irb/cmd/help",
+        [:help, NO_OVERRIDE]],
+
+    ]
+
+    def EXCB.install_extend_commands
+      for args in @EXTEND_COMMANDS
+	def_extend_command(*args)
+      end
+    end
+
+    # aliases = [commans_alias, flag], ...
+    def EXCB.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
+      case cmd_class
+      when Symbol
+	cmd_class = cmd_class.id2name
+      when String
+      when Class
+	cmd_class = cmd_class.name
+      end
+
+      if load_file
+	eval %[
+	  def #{cmd_name}(*opts, &b)
+	    require "#{load_file}"
+	    eval %[
+	      def #{cmd_name}(*opts, &b)
+		ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
+	      end
+	    ]
+	    send :#{cmd_name}, *opts, &b
+	  end
+	]
+      else
+	eval %[
+	  def #{cmd_name}(*opts, &b)
+	    ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
+	  end
+	]
+      end
+
+      for ali, flag in aliases
+	@ALIASES.push [ali, cmd_name, flag]
+      end
+    end
+
+    # override = {NO_OVERRIDE, OVERRIDE_PRIVATE_ONLY, OVERRIDE_ALL}
+    def install_alias_method(to, from, override = NO_OVERRIDE)
+      to = to.id2name unless to.kind_of?(String)
+      from = from.id2name unless from.kind_of?(String)
+
+      if override == OVERRIDE_ALL or
+	  (override == OVERRIDE_PRIVATE_ONLY) && !respond_to?(to) or
+	  (override == NO_OVERRIDE) &&  !respond_to?(to, true)
+	target = self
+	(class<<self;self;end).instance_eval{
+	  if target.respond_to?(to, true) && 
+	      !target.respond_to?(EXCB.irb_original_method_name(to), true)
+	    alias_method(EXCB.irb_original_method_name(to), to) 
+	  end
+	  alias_method to, from
+	}
+      else
+	print "irb: warn: can't alias #{to} from #{from}.\n"
+      end
+    end
+
+    def self.irb_original_method_name(method_name)
+      "irb_" + method_name + "_org"
+    end
+
+    def EXCB.extend_object(obj)
+      unless (class<<obj;ancestors;end).include?(EXCB)
+	super
+	for ali, com, flg in @ALIASES
+	  obj.install_alias_method(ali, com, flg)
+	end
+      end
+    end
+
+    install_extend_commands
+  end
+
+  # extension support for Context
+  module ContextExtender
+    CE = ContextExtender
+
+    @EXTEND_COMMANDS = [
+      [:eval_history=, "irb/ext/history.rb"],
+      [:use_tracer=, "irb/ext/tracer.rb"],
+      [:math_mode=, "irb/ext/math-mode.rb"],
+      [:use_loader=, "irb/ext/use-loader.rb"],
+      [:save_history=, "irb/ext/save-history.rb"],
+    ]
+
+    def CE.install_extend_commands
+      for args in @EXTEND_COMMANDS
+	def_extend_command(*args)
+      end
+    end
+
+    def CE.def_extend_command(cmd_name, load_file, *aliases)
+      Context.module_eval %[
+        def #{cmd_name}(*opts, &b)
+	  Context.module_eval {remove_method(:#{cmd_name})}
+	  require "#{load_file}"
+	  send :#{cmd_name}, *opts, &b
+	end
+	for ali in aliases
+	  alias_method ali, cmd_name
+	end
+      ]
+    end
+
+    CE.install_extend_commands
+  end
+
+  module MethodExtender
+    def def_pre_proc(base_method, extend_method)
+      base_method = base_method.to_s
+      extend_method = extend_method.to_s
+
+      alias_name = new_alias_name(base_method)
+      module_eval %[
+        alias_method alias_name, base_method
+        def #{base_method}(*opts)
+	  send :#{extend_method}, *opts
+	  send :#{alias_name}, *opts
+	end
+      ]
+    end
+
+    def def_post_proc(base_method, extend_method)
+      base_method = base_method.to_s
+      extend_method = extend_method.to_s
+
+      alias_name = new_alias_name(base_method)
+      module_eval %[
+        alias_method alias_name, base_method
+        def #{base_method}(*opts)
+	  send :#{alias_name}, *opts
+	  send :#{extend_method}, *opts
+	end
+      ]
+    end
+
+    # return #{prefix}#{name}#{postfix}<num>
+    def new_alias_name(name, prefix = "__alias_of__", postfix = "__")
+      base_name = "#{prefix}#{name}#{postfix}"
+      all_methods = instance_methods(true) + private_instance_methods(true)
+      same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/)
+      return base_name if same_methods.empty?
+      no = same_methods.size
+      while !same_methods.include?(alias_name = base_name + no)
+	no += 1
+      end
+      alias_name
+    end
+  end
+end
+

Added: trunk/lib/irb/frame.rb
===================================================================
--- trunk/lib/irb/frame.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/frame.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,67 @@
+#
+#   frame.rb - 
+#   	$Release Version: 0.9$
+#   	$Revision: 1.4 $
+#   	$Date: 2002/07/09 11:17:16 $
+#   	by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd)
+#
+# --
+#
+#   
+#
+
+require "e2mmap"
+
+module IRB
+  class Frame
+    extend Exception2MessageMapper
+    def_exception :FrameOverflow, "frame overflow"
+    def_exception :FrameUnderflow, "frame underflow"
+
+    INIT_STACK_TIMES = 3
+    CALL_STACK_OFFSET = 3
+
+    def initialize
+      @frames = [TOPLEVEL_BINDING] * INIT_STACK_TIMES
+    end
+
+    def trace_func(event, file, line, id, binding)
+      case event
+      when 'call', 'class'
+	@frames.push binding
+      when 'return', 'end'
+	@frames.pop
+      end
+    end
+
+    def top(n = 0)
+      bind = @frames[-(n + CALL_STACK_OFFSET)]
+      Fail FrameUnderflow unless bind
+      bind
+    end
+
+    def bottom(n = 0)
+      bind = @frames[n]
+      Fail FrameOverflow unless bind
+      bind
+    end
+
+    # singleton functions
+    def Frame.bottom(n = 0)
+      @backtrace.bottom(n)
+    end
+
+    def Frame.top(n = 0)
+      @backtrace.top(n)
+    end
+
+    def Frame.sender
+      eval "self", @backtrace.top
+    end
+
+    @backtrace = Frame.new
+    set_trace_func proc{|event, file, line, id, binding, klass|
+      @backtrace.trace_func(event, file, line, id, binding)
+    }
+  end
+end

Added: trunk/lib/irb/help.rb
===================================================================
--- trunk/lib/irb/help.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/help.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,33 @@
+#
+#   irb/help.rb - print usase module
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.3 $
+#   	$Date: 2005/04/13 15:27:07 $
+#   	by Keiju ISHITSUKA(keiju ishitsuka.com)
+#
+# --
+#
+#   
+#
+
+module IRB
+  def IRB.print_usage
+    lc = IRB.conf[:LC_MESSAGES]
+    path = lc.find("irb/help-message")
+    space_line = false
+    File.foreach(path) do
+      |l|
+      if /^\s*$/ =~ l
+	lc.puts l unless space_line
+	space_line = true
+	next
+      end
+      space_line = false
+      
+      l.sub!(/#.*$/, "")
+      next if /^\s*$/ =~ l
+      lc.puts l
+    end
+  end
+end
+

Added: trunk/lib/irb/init.rb
===================================================================
--- trunk/lib/irb/init.rb	2006-02-12 06:40:38 UTC (rev 384)
+++ trunk/lib/irb/init.rb	2006-02-12 07:21:49 UTC (rev 385)
@@ -0,0 +1,259 @@
+#
+#   irb/init.rb - irb initialize module
+#   	$Release Version: 0.9.5$
+#   	$Revision: 1.14 $
+#   	$Date: 2005/08/30 07:22:06 $
+#   	by Keiju ISHITSUKA(keiju ruby-lang.org)
+#
+# --
+#
+#   
+#
+
+module IRB
+
+  # initialize config
+  def IRB.setup(ap_path)
+    IRB.init_config(ap_path)
+    IRB.init_error
+    IRB.parse_opts
+    IRB.run_config
+    IRB.load_modules
+
+    unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]]
+      IRB.fail(UndefinedPromptMode, @CONF[:PROMPT_MODE]) 
+    end
+  end
+
+  # @CONF default setting
+  def IRB.init_config(ap_path)
+    # class instance variables
+    @TRACER_INITIALIZED = false
+
+    # default configurations
+    unless ap_path and @CONF[:AP_NAME]
+      ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb")
+    end
+    @CONF[:AP_NAME] = File::basename(ap_path, ".rb")
+
+    @CONF[:IRB_NAME] = "irb"
+    @CONF[:IRB_LIB_PATH] = File.dirname(__FILE__)
+
+    @CONF[:RC] = true
+    @CONF[:LOAD_MODULES] = []
+    @CONF[:IRB_RC] = nil
+
+    @CONF[:MATH_MODE] = false
+    @CONF[:USE_READLINE] = false unless defined?(ReadlineInputMethod)
+    @CONF[:INSPECT_MODE] = nil
+    @CONF[:USE_TRACER] = false
+    @CONF[:USE_LOADER] = false
+    @CONF[:IGNORE_SIGINT] = true
+    @CONF[:IGNORE_EOF] = false
+    @CONF[:ECHO] = nil
+    @CONF[:VERBOSE] = nil
+
+    @CONF[:EVAL_HISTORY] = nil
+    @CONF[:SAVE_HISTORY] = nil
+
+    @CONF[:BACK_TRACE_LIMIT] = 16
+
+    @CONF[:PROMPT] = {
+      :NULL => {
+	:PROMPT_I => nil,
+	:PROMPT_N => nil,
+	:PROMPT_S => nil,
+	:PROMPT_C => nil,
+	:RETURN => "%s\n"
+      },
+      :DEFAULT => {
+	:PROMPT_I => "%N(%m):%03n:%i> ",
+	:PROMPT_N => "%N(%m):%03n:%i> ",
+	:PROMPT_S => "%N(%m):%03n:%i%l ",
+	:PROMPT_C => "%N(%m):%03n:%i* ",
+	:RETURN => "=> %s\n"
+      },
+      :CLASSIC => {
+	:PROMPT_I => "%N(%m):%03n:%i> ",
+	:PROMPT_N => "%N(%m