[macruby-changes] [1889] MacRuby/branches/experimental/lib

source_changes at macosforge.org source_changes at macosforge.org
Fri Jun 19 15:42:24 PDT 2009


Revision: 1889
          http://trac.macosforge.org/projects/ruby/changeset/1889
Author:   lsansonetti at apple.com
Date:     2009-06-19 15:42:24 -0700 (Fri, 19 Jun 2009)
Log Message:
-----------
merged stdlib (including hotcocoa) from trunk

Modified Paths:
--------------
    MacRuby/branches/experimental/lib/.document
    MacRuby/branches/experimental/lib/README
    MacRuby/branches/experimental/lib/cgi/session/pstore.rb
    MacRuby/branches/experimental/lib/cgi/session.rb
    MacRuby/branches/experimental/lib/cgi.rb
    MacRuby/branches/experimental/lib/cmath.rb
    MacRuby/branches/experimental/lib/complex.rb
    MacRuby/branches/experimental/lib/csv.rb
    MacRuby/branches/experimental/lib/date/format.rb
    MacRuby/branches/experimental/lib/date.rb
    MacRuby/branches/experimental/lib/debug.rb
    MacRuby/branches/experimental/lib/delegate.rb
    MacRuby/branches/experimental/lib/drb/drb.rb
    MacRuby/branches/experimental/lib/e2mmap.rb
    MacRuby/branches/experimental/lib/erb.rb
    MacRuby/branches/experimental/lib/fileutils.rb
    MacRuby/branches/experimental/lib/find.rb
    MacRuby/branches/experimental/lib/forwardable.rb
    MacRuby/branches/experimental/lib/gserver.rb
    MacRuby/branches/experimental/lib/hotcocoa/delegate_builder.rb
    MacRuby/branches/experimental/lib/hotcocoa/graphics/canvas.rb
    MacRuby/branches/experimental/lib/hotcocoa/kernel_ext.rb
    MacRuby/branches/experimental/lib/hotcocoa/kvo_accessors.rb
    MacRuby/branches/experimental/lib/hotcocoa/layout_view.rb
    MacRuby/branches/experimental/lib/hotcocoa/mapper.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/alert.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/application.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/array_controller.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/box.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/button.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/collection_view.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/column.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/combo_box.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/label.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/movie_view.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/scroll_view.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/table_view.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/text_field.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/web_view.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/window.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings.rb
    MacRuby/branches/experimental/lib/ipaddr.rb
    MacRuby/branches/experimental/lib/irb/completion.rb
    MacRuby/branches/experimental/lib/irb/context.rb
    MacRuby/branches/experimental/lib/irb/ext/change-ws.rb
    MacRuby/branches/experimental/lib/irb/ext/multi-irb.rb
    MacRuby/branches/experimental/lib/irb/ext/save-history.rb
    MacRuby/branches/experimental/lib/irb/extend-command.rb
    MacRuby/branches/experimental/lib/irb/help.rb
    MacRuby/branches/experimental/lib/irb/init.rb
    MacRuby/branches/experimental/lib/irb/input-method.rb
    MacRuby/branches/experimental/lib/irb/lc/help-message
    MacRuby/branches/experimental/lib/irb/lc/ja/error.rb
    MacRuby/branches/experimental/lib/irb/lc/ja/help-message
    MacRuby/branches/experimental/lib/irb/locale.rb
    MacRuby/branches/experimental/lib/irb/notifier.rb
    MacRuby/branches/experimental/lib/irb/ruby-lex.rb
    MacRuby/branches/experimental/lib/irb/slex.rb
    MacRuby/branches/experimental/lib/irb/xmp.rb
    MacRuby/branches/experimental/lib/irb.rb
    MacRuby/branches/experimental/lib/logger.rb
    MacRuby/branches/experimental/lib/mathn.rb
    MacRuby/branches/experimental/lib/matrix.rb
    MacRuby/branches/experimental/lib/mkmf.rb
    MacRuby/branches/experimental/lib/net/ftp.rb
    MacRuby/branches/experimental/lib/net/http.rb
    MacRuby/branches/experimental/lib/net/https.rb
    MacRuby/branches/experimental/lib/net/imap.rb
    MacRuby/branches/experimental/lib/net/pop.rb
    MacRuby/branches/experimental/lib/net/smtp.rb
    MacRuby/branches/experimental/lib/net/telnet.rb
    MacRuby/branches/experimental/lib/open-uri.rb
    MacRuby/branches/experimental/lib/open3.rb
    MacRuby/branches/experimental/lib/optparse/version.rb
    MacRuby/branches/experimental/lib/optparse.rb
    MacRuby/branches/experimental/lib/ostruct.rb
    MacRuby/branches/experimental/lib/pathname.rb
    MacRuby/branches/experimental/lib/pp.rb
    MacRuby/branches/experimental/lib/prettyprint.rb
    MacRuby/branches/experimental/lib/profile.rb
    MacRuby/branches/experimental/lib/profiler.rb
    MacRuby/branches/experimental/lib/pstore.rb
    MacRuby/branches/experimental/lib/racc/parser.rb
    MacRuby/branches/experimental/lib/rake/gempackagetask.rb
    MacRuby/branches/experimental/lib/rake/loaders/makefile.rb
    MacRuby/branches/experimental/lib/rake/packagetask.rb
    MacRuby/branches/experimental/lib/rake/rdoctask.rb
    MacRuby/branches/experimental/lib/rake/tasklib.rb
    MacRuby/branches/experimental/lib/rake/testtask.rb
    MacRuby/branches/experimental/lib/rake.rb
    MacRuby/branches/experimental/lib/rational.rb
    MacRuby/branches/experimental/lib/rdoc/README
    MacRuby/branches/experimental/lib/rdoc/code_objects.rb
    MacRuby/branches/experimental/lib/rdoc/diagram.rb
    MacRuby/branches/experimental/lib/rdoc/generator/chm/chm.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html/hefss.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html/html.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html/kilmer.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html/one_page_html.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html.rb
    MacRuby/branches/experimental/lib/rdoc/generator/ri.rb
    MacRuby/branches/experimental/lib/rdoc/generator/xml/xml.rb
    MacRuby/branches/experimental/lib/rdoc/generator/xml.rb
    MacRuby/branches/experimental/lib/rdoc/generator.rb
    MacRuby/branches/experimental/lib/rdoc/markup/attribute_manager.rb
    MacRuby/branches/experimental/lib/rdoc/markup/fragments.rb
    MacRuby/branches/experimental/lib/rdoc/markup/inline.rb
    MacRuby/branches/experimental/lib/rdoc/markup/lines.rb
    MacRuby/branches/experimental/lib/rdoc/markup/preprocess.rb
    MacRuby/branches/experimental/lib/rdoc/markup/to_html.rb
    MacRuby/branches/experimental/lib/rdoc/markup/to_html_crossref.rb
    MacRuby/branches/experimental/lib/rdoc/markup.rb
    MacRuby/branches/experimental/lib/rdoc/options.rb
    MacRuby/branches/experimental/lib/rdoc/rdoc.rb
    MacRuby/branches/experimental/lib/rdoc/ri/cache.rb
    MacRuby/branches/experimental/lib/rdoc/ri/descriptions.rb
    MacRuby/branches/experimental/lib/rdoc/ri/display.rb
    MacRuby/branches/experimental/lib/rdoc/ri/driver.rb
    MacRuby/branches/experimental/lib/rdoc/ri/formatter.rb
    MacRuby/branches/experimental/lib/rdoc/ri/paths.rb
    MacRuby/branches/experimental/lib/rdoc/ri/reader.rb
    MacRuby/branches/experimental/lib/rdoc/ri/util.rb
    MacRuby/branches/experimental/lib/rdoc/ri.rb
    MacRuby/branches/experimental/lib/rdoc/stats.rb
    MacRuby/branches/experimental/lib/rdoc.rb
    MacRuby/branches/experimental/lib/resolv-replace.rb
    MacRuby/branches/experimental/lib/resolv.rb
    MacRuby/branches/experimental/lib/rexml/attlistdecl.rb
    MacRuby/branches/experimental/lib/rexml/attribute.rb
    MacRuby/branches/experimental/lib/rexml/cdata.rb
    MacRuby/branches/experimental/lib/rexml/child.rb
    MacRuby/branches/experimental/lib/rexml/comment.rb
    MacRuby/branches/experimental/lib/rexml/document.rb
    MacRuby/branches/experimental/lib/rexml/dtd/attlistdecl.rb
    MacRuby/branches/experimental/lib/rexml/dtd/dtd.rb
    MacRuby/branches/experimental/lib/rexml/dtd/elementdecl.rb
    MacRuby/branches/experimental/lib/rexml/dtd/entitydecl.rb
    MacRuby/branches/experimental/lib/rexml/dtd/notationdecl.rb
    MacRuby/branches/experimental/lib/rexml/element.rb
    MacRuby/branches/experimental/lib/rexml/encodings/CP-1252.rb
    MacRuby/branches/experimental/lib/rexml/encodings/ISO-8859-15.rb
    MacRuby/branches/experimental/lib/rexml/entity.rb
    MacRuby/branches/experimental/lib/rexml/formatters/pretty.rb
    MacRuby/branches/experimental/lib/rexml/formatters/transitive.rb
    MacRuby/branches/experimental/lib/rexml/functions.rb
    MacRuby/branches/experimental/lib/rexml/instruction.rb
    MacRuby/branches/experimental/lib/rexml/light/node.rb
    MacRuby/branches/experimental/lib/rexml/namespace.rb
    MacRuby/branches/experimental/lib/rexml/node.rb
    MacRuby/branches/experimental/lib/rexml/output.rb
    MacRuby/branches/experimental/lib/rexml/parsers/lightparser.rb
    MacRuby/branches/experimental/lib/rexml/parsers/sax2parser.rb
    MacRuby/branches/experimental/lib/rexml/parsers/ultralightparser.rb
    MacRuby/branches/experimental/lib/rexml/parsers/xpathparser.rb
    MacRuby/branches/experimental/lib/rexml/quickpath.rb
    MacRuby/branches/experimental/lib/rexml/sax2listener.rb
    MacRuby/branches/experimental/lib/rexml/streamlistener.rb
    MacRuby/branches/experimental/lib/rexml/text.rb
    MacRuby/branches/experimental/lib/rexml/validation/relaxng.rb
    MacRuby/branches/experimental/lib/rexml/xmldecl.rb
    MacRuby/branches/experimental/lib/rexml/xmltokens.rb
    MacRuby/branches/experimental/lib/rexml/xpath.rb
    MacRuby/branches/experimental/lib/rexml/xpath_parser.rb
    MacRuby/branches/experimental/lib/rinda/ring.rb
    MacRuby/branches/experimental/lib/rinda/tuplespace.rb
    MacRuby/branches/experimental/lib/rss/converter.rb
    MacRuby/branches/experimental/lib/rss/maker/base.rb
    MacRuby/branches/experimental/lib/rss/maker/itunes.rb
    MacRuby/branches/experimental/lib/rss/parser.rb
    MacRuby/branches/experimental/lib/rss/rss.rb
    MacRuby/branches/experimental/lib/rss/utils.rb
    MacRuby/branches/experimental/lib/rubygems/command.rb
    MacRuby/branches/experimental/lib/rubygems/command_manager.rb
    MacRuby/branches/experimental/lib/rubygems/commands/cert_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/check_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/contents_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/dependency_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/environment_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/fetch_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/help_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/install_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/list_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/lock_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/outdated_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/pristine_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/query_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/rdoc_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/sources_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/specification_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/unpack_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/update_command.rb
    MacRuby/branches/experimental/lib/rubygems/commands/which_command.rb
    MacRuby/branches/experimental/lib/rubygems/config_file.rb
    MacRuby/branches/experimental/lib/rubygems/custom_require.rb
    MacRuby/branches/experimental/lib/rubygems/defaults.rb
    MacRuby/branches/experimental/lib/rubygems/dependency.rb
    MacRuby/branches/experimental/lib/rubygems/dependency_installer.rb
    MacRuby/branches/experimental/lib/rubygems/dependency_list.rb
    MacRuby/branches/experimental/lib/rubygems/doc_manager.rb
    MacRuby/branches/experimental/lib/rubygems/ext/builder.rb
    MacRuby/branches/experimental/lib/rubygems/ext/rake_builder.rb
    MacRuby/branches/experimental/lib/rubygems/gem_openssl.rb
    MacRuby/branches/experimental/lib/rubygems/gem_path_searcher.rb
    MacRuby/branches/experimental/lib/rubygems/indexer.rb
    MacRuby/branches/experimental/lib/rubygems/install_update_options.rb
    MacRuby/branches/experimental/lib/rubygems/installer.rb
    MacRuby/branches/experimental/lib/rubygems/local_remote_options.rb
    MacRuby/branches/experimental/lib/rubygems/package/tar_reader.rb
    MacRuby/branches/experimental/lib/rubygems/platform.rb
    MacRuby/branches/experimental/lib/rubygems/remote_fetcher.rb
    MacRuby/branches/experimental/lib/rubygems/requirement.rb
    MacRuby/branches/experimental/lib/rubygems/rubygems_version.rb
    MacRuby/branches/experimental/lib/rubygems/security.rb
    MacRuby/branches/experimental/lib/rubygems/server.rb
    MacRuby/branches/experimental/lib/rubygems/source_index.rb
    MacRuby/branches/experimental/lib/rubygems/source_info_cache.rb
    MacRuby/branches/experimental/lib/rubygems/specification.rb
    MacRuby/branches/experimental/lib/rubygems/uninstaller.rb
    MacRuby/branches/experimental/lib/rubygems/user_interaction.rb
    MacRuby/branches/experimental/lib/rubygems/validator.rb
    MacRuby/branches/experimental/lib/rubygems/version.rb
    MacRuby/branches/experimental/lib/rubygems.rb
    MacRuby/branches/experimental/lib/scanf.rb
    MacRuby/branches/experimental/lib/shell/command-processor.rb
    MacRuby/branches/experimental/lib/shell/process-controller.rb
    MacRuby/branches/experimental/lib/shell.rb
    MacRuby/branches/experimental/lib/singleton.rb
    MacRuby/branches/experimental/lib/sync.rb
    MacRuby/branches/experimental/lib/tempfile.rb
    MacRuby/branches/experimental/lib/test/unit/assertions.rb
    MacRuby/branches/experimental/lib/test/unit/testcase.rb
    MacRuby/branches/experimental/lib/test/unit.rb
    MacRuby/branches/experimental/lib/thwait.rb
    MacRuby/branches/experimental/lib/time.rb
    MacRuby/branches/experimental/lib/tmpdir.rb
    MacRuby/branches/experimental/lib/tsort.rb
    MacRuby/branches/experimental/lib/un.rb
    MacRuby/branches/experimental/lib/uri/common.rb
    MacRuby/branches/experimental/lib/uri/generic.rb
    MacRuby/branches/experimental/lib/uri/mailto.rb
    MacRuby/branches/experimental/lib/webrick/cgi.rb
    MacRuby/branches/experimental/lib/webrick/httpauth/digestauth.rb
    MacRuby/branches/experimental/lib/webrick/httpproxy.rb
    MacRuby/branches/experimental/lib/webrick/httprequest.rb
    MacRuby/branches/experimental/lib/webrick/httpresponse.rb
    MacRuby/branches/experimental/lib/webrick/httpservlet/abstract.rb
    MacRuby/branches/experimental/lib/webrick/httpservlet/cgi_runner.rb
    MacRuby/branches/experimental/lib/webrick/httpservlet/cgihandler.rb
    MacRuby/branches/experimental/lib/webrick/httpservlet/filehandler.rb
    MacRuby/branches/experimental/lib/webrick/httputils.rb
    MacRuby/branches/experimental/lib/webrick/server.rb
    MacRuby/branches/experimental/lib/webrick/utils.rb
    MacRuby/branches/experimental/lib/xmlrpc/client.rb
    MacRuby/branches/experimental/lib/xmlrpc/create.rb
    MacRuby/branches/experimental/lib/xmlrpc/httpserver.rb
    MacRuby/branches/experimental/lib/xmlrpc/parser.rb
    MacRuby/branches/experimental/lib/xmlrpc/server.rb
    MacRuby/branches/experimental/lib/xmlrpc/utils.rb
    MacRuby/branches/experimental/lib/yaml/baseemitter.rb
    MacRuby/branches/experimental/lib/yaml/rubytypes.rb
    MacRuby/branches/experimental/lib/yaml/yamlnode.rb
    MacRuby/branches/experimental/lib/yaml.rb

Added Paths:
-----------
    MacRuby/branches/experimental/lib/base64.rb
    MacRuby/branches/experimental/lib/cgi/cookie.rb
    MacRuby/branches/experimental/lib/cgi/core.rb
    MacRuby/branches/experimental/lib/cgi/html.rb
    MacRuby/branches/experimental/lib/cgi/util.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/progress_indicator.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/search_field.rb
    MacRuby/branches/experimental/lib/hotcocoa/mappings/sort_descriptor.rb
    MacRuby/branches/experimental/lib/hotcocoa/mvc.rb
    MacRuby/branches/experimental/lib/irb/lc/ja/encoding_aliases.rb
    MacRuby/branches/experimental/lib/irb/magic-file.rb
    MacRuby/branches/experimental/lib/irb/src_encoding.rb
    MacRuby/branches/experimental/lib/minitest/
    MacRuby/branches/experimental/lib/minitest/autorun.rb
    MacRuby/branches/experimental/lib/minitest/mock.rb
    MacRuby/branches/experimental/lib/minitest/spec.rb
    MacRuby/branches/experimental/lib/minitest/unit.rb
    MacRuby/branches/experimental/lib/prime.rb
    MacRuby/branches/experimental/lib/rake/win32.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html/common.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html/frameless.rb
    MacRuby/branches/experimental/lib/rdoc/generator/html/kilmerfactory.rb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/class.texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/file.texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/method.texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo.rb
    MacRuby/branches/experimental/lib/rdoc/known_classes.rb
    MacRuby/branches/experimental/lib/rdoc/markup/to_texinfo.rb
    MacRuby/branches/experimental/lib/rdoc/parser/
    MacRuby/branches/experimental/lib/rdoc/parser/c.rb
    MacRuby/branches/experimental/lib/rdoc/parser/f95.rb
    MacRuby/branches/experimental/lib/rdoc/parser/perl.rb
    MacRuby/branches/experimental/lib/rdoc/parser/ruby.rb
    MacRuby/branches/experimental/lib/rdoc/parser/simple.rb
    MacRuby/branches/experimental/lib/rdoc/parser.rb
    MacRuby/branches/experimental/lib/rubygems/commands/stale_command.rb
    MacRuby/branches/experimental/lib/rubygems/spec_fetcher.rb
    MacRuby/branches/experimental/lib/rubygems/test_utilities.rb

Removed Paths:
-------------
    MacRuby/branches/experimental/lib/minitest/autorun.rb
    MacRuby/branches/experimental/lib/minitest/mock.rb
    MacRuby/branches/experimental/lib/minitest/spec.rb
    MacRuby/branches/experimental/lib/minitest/unit.rb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/class.texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/file.texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/method.texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/generator/texinfo/texinfo.erb
    MacRuby/branches/experimental/lib/rdoc/parser/c.rb
    MacRuby/branches/experimental/lib/rdoc/parser/f95.rb
    MacRuby/branches/experimental/lib/rdoc/parser/perl.rb
    MacRuby/branches/experimental/lib/rdoc/parser/ruby.rb
    MacRuby/branches/experimental/lib/rdoc/parser/simple.rb
    MacRuby/branches/experimental/lib/rdoc/parsers/
    MacRuby/branches/experimental/lib/test/unit/assertionfailederror.rb
    MacRuby/branches/experimental/lib/test/unit/autorunner.rb
    MacRuby/branches/experimental/lib/test/unit/collector/
    MacRuby/branches/experimental/lib/test/unit/collector.rb
    MacRuby/branches/experimental/lib/test/unit/error.rb
    MacRuby/branches/experimental/lib/test/unit/failure.rb
    MacRuby/branches/experimental/lib/test/unit/testresult.rb
    MacRuby/branches/experimental/lib/test/unit/testsuite.rb
    MacRuby/branches/experimental/lib/test/unit/ui/
    MacRuby/branches/experimental/lib/test/unit/util/

Modified: MacRuby/branches/experimental/lib/.document
===================================================================
--- MacRuby/branches/experimental/lib/.document	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/.document	2009-06-19 22:42:24 UTC (rev 1889)
@@ -59,6 +59,7 @@
 ping.rb
 pp.rb
 prettyprint.rb
+prime.rb
 profile.rb
 profiler.rb
 pstore.rb

Modified: MacRuby/branches/experimental/lib/README
===================================================================
--- MacRuby/branches/experimental/lib/README	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/README	2009-06-19 22:42:24 UTC (rev 1889)
@@ -42,6 +42,7 @@
 pathname.rb	Object-Oriented Pathname Class
 pp.rb		pretty print objects
 prettyprint.rb	pretty printing algorithm
+prime.rb        prime numbers and factorization
 profile.rb	runs ruby profiler
 profiler.rb	ruby profiler module
 pstore.rb	persistent object strage using marshal

Copied: MacRuby/branches/experimental/lib/base64.rb (from rev 1886, MacRuby/trunk/lib/base64.rb)
===================================================================
--- MacRuby/branches/experimental/lib/base64.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/base64.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,91 @@
+#
+# = base64.rb: methods for base64-encoding and -decoding stings
+#
+
+# The Base64 module provides for the encoding (#encode64, #strict_encode64,
+# #urlsafe_encode64) and decoding (#decode64, #strict_decode64,
+# #urlsafe_decode64) of binary data using a Base64 representation.
+#
+# == 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.
+
+module Base64
+  module_function
+
+  # Returns the Base64-encoded version of +bin+.
+  # This method complies with RFC 2045.
+  # Line feeds are added to every 60 encoded charactors.
+  #
+  #    require 'base64'
+  #    Base64.encode64("Now is the time for all good coders\nto learn Ruby")
+  #
+  # <i>Generates:</i>
+  #
+  #    Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g
+  #    UnVieQ==
+  def encode64(bin)
+    [bin].pack("m")
+  end
+
+  # Returns the Base64-decoded version of +str+.
+  # This method complies with RFC 2045.
+  # Characters outside the base alphabet are ignored.
+  #
+  #   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").first
+  end
+
+  # Returns the Base64-encoded version of +bin+.
+  # This method complies with RFC 4648.
+  # No line feeds are added.
+  def strict_encode64(bin)
+    [bin].pack("m0")
+  end
+
+  # Returns the Base64-decoded version of +str+.
+  # This method complies with RFC 4648.
+  # ArgumentError is raised if +str+ is incorrectly padded or contains
+  # non-alphabet characters.  Note that CR or LF are also rejected.
+  def strict_decode64(str)
+    str.unpack("m0").first
+  end
+
+  # Returns the Base64-encoded version of +bin+.
+  # This method complies with ``Base 64 Encoding with URL and Filename Safe
+  # Alphabet'' in RFC 4648.
+  # The alphabet uses '-' instead of '+' and '_' instead of '/'.
+  def urlsafe_encode64(bin)
+    strict_encode64(bin).tr("+/", "-_")
+  end
+
+  # Returns the Base64-decoded version of +str+.
+  # This method complies with ``Base 64 Encoding with URL and Filename Safe
+  # Alphabet'' in RFC 4648.
+  # The alphabet uses '-' instead of '+' and '_' instead of '/'.
+  def urlsafe_decode64(str)
+    strict_decode64(str.tr("-_", "+/"))
+  end
+end

Copied: MacRuby/branches/experimental/lib/cgi/cookie.rb (from rev 1886, MacRuby/trunk/lib/cgi/cookie.rb)
===================================================================
--- MacRuby/branches/experimental/lib/cgi/cookie.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/cgi/cookie.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,137 @@
+  # Class representing an HTTP cookie.
+  #
+  # In addition to its specific fields and methods, a Cookie instance
+  # is a delegator to the array of its values.
+  #
+  # See RFC 2965.
+  #
+  # == Examples of use
+  #   cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
+  #   cookie1 = CGI::Cookie::new("name" => "name", "value" => "value")
+  #   cookie1 = CGI::Cookie::new('name'    => 'name',
+  #                              'value'   => ['value1', 'value2', ...],
+  #                              'path'    => 'path',   # optional
+  #                              'domain'  => 'domain', # optional
+  #                              'expires' => Time.now, # optional
+  #                              'secure'  => true      # optional
+  #                             )
+  # 
+  #   cgi.out("cookie" => [cookie1, cookie2]) { "string" }
+  # 
+  #   name    = cookie1.name
+  #   values  = cookie1.value
+  #   path    = cookie1.path
+  #   domain  = cookie1.domain
+  #   expires = cookie1.expires
+  #   secure  = cookie1.secure
+  # 
+  #   cookie1.name    = 'name'
+  #   cookie1.value   = ['value1', 'value2', ...]
+  #   cookie1.path    = 'path'
+  #   cookie1.domain  = 'domain'
+  #   cookie1.expires = Time.now + 30
+  #   cookie1.secure  = true
+class CGI
+  class Cookie < Array
+
+    # Create a new CGI::Cookie object.
+    #
+    # The contents of the cookie can be specified as a +name+ and one
+    # or more +value+ arguments.  Alternatively, the contents can
+    # be specified as a single hash argument.  The possible keywords of
+    # this hash are as follows:
+    #
+    # name:: the name of the cookie.  Required.
+    # value:: the cookie's value or list of values.
+    # path:: the path for which this cookie applies.  Defaults to the
+    #        base directory of the CGI script.
+    # domain:: the domain for which this cookie applies.
+    # expires:: the time at which this cookie expires, as a +Time+ object.
+    # secure:: whether this cookie is a secure cookie or not (default to
+    #          false).  Secure cookies are only transmitted to HTTPS 
+    #          servers.
+    #
+    # These keywords correspond to attributes of the cookie object.
+    def initialize(name = "", *value)
+      if name.kind_of?(String)
+        @name = name
+        @value = value
+        %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
+        @path = ($1 or "")
+        @secure = false
+        return super(@value)
+      end
+
+      options = name
+      unless options.has_key?("name")
+        raise ArgumentError, "`name' required"
+      end
+
+      @name = options["name"]
+      @value = Array(options["value"])
+      # simple support for IE
+      if options["path"]
+        @path = options["path"]
+      else
+        %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
+        @path = ($1 or "")
+      end
+      @domain = options["domain"]
+      @expires = options["expires"]
+      @secure = options["secure"] == true ? true : false
+
+      super(@value)
+    end
+
+    attr_accessor("name", "value", "path", "domain", "expires")
+    attr_reader("secure")
+
+    # Set whether the Cookie is a secure cookie or not.
+    #
+    # +val+ must be a boolean.
+    def secure=(val)
+      @secure = val if val == true or val == false
+      @secure
+    end
+
+    # Convert the Cookie to its string representation.
+    def to_s
+      val = @value.kind_of?(String) ? CGI::escape(@value) : @value.collect{|v| CGI::escape(v) }.join("&")
+      buf = "#{@name}=#{val}"
+      buf << "; domain=#{@domain}" if @domain
+      buf << "; path=#{@path}"     if @path
+      buf << "; expires=#{CGI::rfc1123_date(@expires)}" if @expires
+      buf << "; secure"            if @secure == true
+      buf
+    end
+
+  end # class Cookie
+
+
+  # Parse a raw cookie string into a hash of cookie-name=>Cookie
+  # pairs.
+  #
+  #   cookies = CGI::Cookie::parse("raw_cookie_string")
+  #     # { "name1" => cookie1, "name2" => cookie2, ... }
+  #
+  def Cookie::parse(raw_cookie)
+    cookies = Hash.new([])
+    return cookies unless raw_cookie
+
+    raw_cookie.split(/[;,]\s?/).each do |pairs|
+      name, values = pairs.split('=',2)
+      next unless name and values
+      name = CGI::unescape(name)
+      values ||= ""
+      values = values.split('&').collect{|v| CGI::unescape(v) }
+      if cookies.has_key?(name)
+        values = cookies[name].value + values
+      end
+      cookies[name] = Cookie::new(name, *values)
+    end
+
+    cookies
+  end
+end
+
+

Copied: MacRuby/branches/experimental/lib/cgi/core.rb (from rev 1886, MacRuby/trunk/lib/cgi/core.rb)
===================================================================
--- MacRuby/branches/experimental/lib/cgi/core.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/cgi/core.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,786 @@
+class CGI
+
+  $CGI_ENV = ENV    # for FCGI support
+
+  # String for carriage return
+  CR  = "\015"
+
+  # String for linefeed
+  LF  = "\012"
+
+  # Standard internet newline sequence
+  EOL = CR + LF
+
+  REVISION = '$Id: core.rb 21825 2009-01-28 09:21:49Z yugui $' #:nodoc:
+
+  NEEDS_BINMODE = true if /WIN/i.match(RUBY_PLATFORM) 
+
+  # Path separators in different environments.
+  PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
+
+  # HTTP status codes.
+  HTTP_STATUS = {
+    "OK"                  => "200 OK",
+    "PARTIAL_CONTENT"     => "206 Partial Content",
+    "MULTIPLE_CHOICES"    => "300 Multiple Choices",
+    "MOVED"               => "301 Moved Permanently",
+    "REDIRECT"            => "302 Found",
+    "NOT_MODIFIED"        => "304 Not Modified",
+    "BAD_REQUEST"         => "400 Bad Request",
+    "AUTH_REQUIRED"       => "401 Authorization Required",
+    "FORBIDDEN"           => "403 Forbidden",
+    "NOT_FOUND"           => "404 Not Found",
+    "METHOD_NOT_ALLOWED"  => "405 Method Not Allowed",
+    "NOT_ACCEPTABLE"      => "406 Not Acceptable",
+    "LENGTH_REQUIRED"     => "411 Length Required",
+    "PRECONDITION_FAILED" => "412 Rrecondition Failed",
+    "SERVER_ERROR"        => "500 Internal Server Error",
+    "NOT_IMPLEMENTED"     => "501 Method Not Implemented",
+    "BAD_GATEWAY"         => "502 Bad Gateway",
+    "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
+  }
+
+  # Abbreviated day-of-week names specified by RFC 822
+  RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
+
+  # Abbreviated month names specified by RFC 822
+  RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
+
+  # :startdoc:
+
+  def env_table 
+    ENV
+  end
+
+  def stdinput
+    $stdin
+  end
+
+  def stdoutput
+    $stdout
+  end
+
+  private :env_table, :stdinput, :stdoutput
+
+
+  # Create an HTTP header block as a string.
+  #
+  # Includes the empty line that ends the header block.
+  #
+  # +options+ can be a string specifying the Content-Type (defaults
+  # to text/html), or a hash of header key/value pairs.  The following
+  # header keys are recognized:
+  #
+  # type:: the Content-Type header.  Defaults to "text/html"
+  # charset:: the charset of the body, appended to the Content-Type header.
+  # nph:: a boolean value.  If true, prepend protocol string and status code, and
+  #       date; and sets default values for "server" and "connection" if not
+  #       explicitly set.
+  # status:: the HTTP status code, returned as the Status header.  See the
+  #          list of available status codes below.
+  # server:: the server software, returned as the Server header.
+  # connection:: the connection type, returned as the Connection header (for 
+  #              instance, "close".
+  # length:: the length of the content that will be sent, returned as the
+  #          Content-Length header.
+  # language:: the language of the content, returned as the Content-Language
+  #            header.
+  # expires:: the time on which the current content expires, as a +Time+
+  #           object, returned as the Expires header.
+  # cookie:: a cookie or cookies, returned as one or more Set-Cookie headers.
+  #          The value can be the literal string of the cookie; a CGI::Cookie
+  #          object; an Array of literal cookie strings or Cookie objects; or a 
+  #          hash all of whose values are literal cookie strings or Cookie objects.
+  #          These cookies are in addition to the cookies held in the
+  #          @output_cookies field.
+  #
+  # Other header lines can also be set; they are appended as key: value.
+  # 
+  #   header
+  #     # Content-Type: text/html
+  # 
+  #   header("text/plain")
+  #     # Content-Type: text/plain
+  # 
+  #   header("nph"        => true,
+  #          "status"     => "OK",  # == "200 OK"
+  #            # "status"     => "200 GOOD",
+  #          "server"     => ENV['SERVER_SOFTWARE'],
+  #          "connection" => "close",
+  #          "type"       => "text/html",
+  #          "charset"    => "iso-2022-jp",
+  #            # Content-Type: text/html; charset=iso-2022-jp
+  #          "length"     => 103,
+  #          "language"   => "ja",
+  #          "expires"    => Time.now + 30,
+  #          "cookie"     => [cookie1, cookie2],
+  #          "my_header1" => "my_value"
+  #          "my_header2" => "my_value")
+  # 
+  # The status codes are:
+  # 
+  #   "OK"                  --> "200 OK"
+  #   "PARTIAL_CONTENT"     --> "206 Partial Content"
+  #   "MULTIPLE_CHOICES"    --> "300 Multiple Choices"
+  #   "MOVED"               --> "301 Moved Permanently"
+  #   "REDIRECT"            --> "302 Found"
+  #   "NOT_MODIFIED"        --> "304 Not Modified"
+  #   "BAD_REQUEST"         --> "400 Bad Request"
+  #   "AUTH_REQUIRED"       --> "401 Authorization Required"
+  #   "FORBIDDEN"           --> "403 Forbidden"
+  #   "NOT_FOUND"           --> "404 Not Found"
+  #   "METHOD_NOT_ALLOWED"  --> "405 Method Not Allowed"
+  #   "NOT_ACCEPTABLE"      --> "406 Not Acceptable"
+  #   "LENGTH_REQUIRED"     --> "411 Length Required"
+  #   "PRECONDITION_FAILED" --> "412 Precondition Failed"
+  #   "SERVER_ERROR"        --> "500 Internal Server Error"
+  #   "NOT_IMPLEMENTED"     --> "501 Method Not Implemented"
+  #   "BAD_GATEWAY"         --> "502 Bad Gateway"
+  #   "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates"
+  # 
+  # This method does not perform charset conversion. 
+  def header(options='text/html')
+    if options.is_a?(String)
+      content_type = options
+      buf = _header_for_string(content_type)
+    elsif options.is_a?(Hash)
+      if options.size == 1 && options.has_key?('type')
+        content_type = options['type']
+        buf = _header_for_string(content_type)
+      else
+        buf = _header_for_hash(options.dup)
+      end
+    else
+      raise ArgumentError.new("expected String or Hash but got #{options.class}")
+    end
+    if defined?(MOD_RUBY)
+      _header_for_modruby(buf)
+      return ''
+    else
+      buf << EOL    # empty line of separator
+      return buf
+    end
+  end # header()
+
+  def _header_for_string(content_type) #:nodoc:
+    buf = ''
+    if nph?()
+      buf << "#{$CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0'} 200 OK#{EOL}"
+      buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}"
+      buf << "Server: #{$CGI_ENV['SERVER_SOFTWARE']}#{EOL}"
+      buf << "Connection: close#{EOL}"
+    end
+    buf << "Content-Type: #{content_type}#{EOL}"
+    if @output_cookies
+      @output_cookies.each {|cookie| buf << "Set-Cookie: #{cookie}#{EOL}" }
+    end
+    return buf
+  end # _header_for_string
+  private :_header_for_string
+
+  def _header_for_hash(options)  #:nodoc:
+    buf = ''
+    ## add charset to option['type']
+    options['type'] ||= 'text/html'
+    charset = options.delete('charset')
+    options['type'] += "; charset=#{charset}" if charset
+    ## NPH
+    options.delete('nph') if defined?(MOD_RUBY)
+    if options.delete('nph') || nph?()
+      protocol = $CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0'
+      status = options.delete('status')
+      status = HTTP_STATUS[status] || status || '200 OK'
+      buf << "#{protocol} #{status}#{EOL}"
+      buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}"
+      options['server'] ||= $CGI_ENV['SERVER_SOFTWARE'] || ''
+      options['connection'] ||= 'close'
+    end
+    ## common headers
+    status = options.delete('status')
+    buf << "Status: #{HTTP_STATUS[status] || status}#{EOL}" if status
+    server = options.delete('server')
+    buf << "Server: #{server}#{EOL}" if server
+    connection = options.delete('connection')
+    buf << "Connection: #{connection}#{EOL}" if connection
+    type = options.delete('type')
+    buf << "Content-Type: #{type}#{EOL}" #if type
+    length = options.delete('length')
+    buf << "Content-Length: #{length}#{EOL}" if length
+    language = options.delete('language')
+    buf << "Content-Language: #{language}#{EOL}" if language
+    expires = options.delete('expires')
+    buf << "Expires: #{CGI.rfc1123_date(expires)}#{EOL}" if expires
+    ## cookie
+    if cookie = options.delete('cookie')
+      case cookie
+      when String, Cookie
+        buf << "Set-Cookie: #{cookie}#{EOL}"
+      when Array
+        arr = cookie
+        arr.each {|c| buf << "Set-Cookie: #{c}#{EOL}" }
+      when Hash
+        hash = cookie
+        hash.each {|name, c| buf << "Set-Cookie: #{c}#{EOL}" }
+      end
+    end
+    if @output_cookies
+      @output_cookies.each {|c| buf << "Set-Cookie: #{c}#{EOL}" }
+    end
+    ## other headers
+    options.each do |key, value|
+      buf << "#{key}: #{value}#{EOL}"
+    end
+    return buf
+  end # _header_for_hash
+  private :_header_for_hash
+
+  def nph?  #:nodoc:
+    return /IIS\/(\d+)/.match($CGI_ENV['SERVER_SOFTWARE']) && $1.to_i < 5
+  end
+
+  def _header_for_modruby(buf)  #:nodoc:
+    request = Apache::request
+    buf.scan(/([^:]+): (.+)#{EOL}/o) do |name, value|
+      warn sprintf("name:%s value:%s\n", name, value) if $DEBUG
+      case name
+      when 'Set-Cookie'
+        request.headers_out.add(name, value)
+      when /^status$/i
+        request.status_line = value
+        request.status = value.to_i
+      when /^content-type$/i
+        request.content_type = value
+      when /^content-encoding$/i
+        request.content_encoding = value
+      when /^location$/i
+        request.status = 302 if request.status == 200
+        request.headers_out[name] = value
+      else
+        request.headers_out[name] = value
+      end
+    end
+    request.send_http_header
+    return ''
+  end
+  private :_header_for_modruby
+  #
+
+  # Print an HTTP header and body to $DEFAULT_OUTPUT ($>)
+  #
+  # The header is provided by +options+, as for #header().
+  # The body of the document is that returned by the passed-
+  # in block.  This block takes no arguments.  It is required.
+  #
+  #   cgi = CGI.new
+  #   cgi.out{ "string" }
+  #     # Content-Type: text/html
+  #     # Content-Length: 6
+  #     #
+  #     # string
+  # 
+  #   cgi.out("text/plain") { "string" }
+  #     # Content-Type: text/plain
+  #     # Content-Length: 6
+  #     #
+  #     # string
+  # 
+  #   cgi.out("nph"        => true,
+  #           "status"     => "OK",  # == "200 OK"
+  #           "server"     => ENV['SERVER_SOFTWARE'],
+  #           "connection" => "close",
+  #           "type"       => "text/html",
+  #           "charset"    => "iso-2022-jp",
+  #             # Content-Type: text/html; charset=iso-2022-jp
+  #           "language"   => "ja",
+  #           "expires"    => Time.now + (3600 * 24 * 30),
+  #           "cookie"     => [cookie1, cookie2],
+  #           "my_header1" => "my_value",
+  #           "my_header2" => "my_value") { "string" }
+  # 
+  # Content-Length is automatically calculated from the size of
+  # the String returned by the content block.
+  #
+  # If ENV['REQUEST_METHOD'] == "HEAD", then only the header
+  # is outputted (the content block is still required, but it
+  # is ignored).
+  # 
+  # If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then
+  # the content is converted to this charset, and the language is set 
+  # to "ja".
+  def out(options = "text/html") # :yield:
+
+    options = { "type" => options } if options.kind_of?(String)
+    content = yield
+    options["length"] = content.bytesize.to_s
+    output = stdoutput
+    output.binmode if defined? output.binmode
+    output.print header(options)
+    output.print content unless "HEAD" == env_table['REQUEST_METHOD']
+  end
+
+
+  # Print an argument or list of arguments to the default output stream
+  #
+  #   cgi = CGI.new
+  #   cgi.print    # default:  cgi.print == $DEFAULT_OUTPUT.print
+  def print(*options)
+    stdoutput.print(*options)
+  end
+
+  # Parse an HTTP query string into a hash of key=>value pairs.
+  #
+  #   params = CGI::parse("query_string")
+  #     # {"name1" => ["value1", "value2", ...],
+  #     #  "name2" => ["value1", "value2", ...], ... }
+  #
+  def CGI::parse(query)
+    params = {}
+    query.split(/[&;]/).each do |pairs|
+      key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) }
+      if key && value
+        params.has_key?(key) ? params[key].push(value) : params[key] = [value]
+      elsif key
+        params[key]=[]
+      end
+    end
+    params.default=[].freeze
+    params
+  end
+
+  # Maximum content length of post data
+  ##MAX_CONTENT_LENGTH  = 2 * 1024 * 1024
+
+  # Maximum content length of multipart data
+  MAX_MULTIPART_LENGTH  = 128 * 1024 * 1024
+
+  # Maximum number of request parameters when multipart
+  MAX_MULTIPART_COUNT = 128
+
+  # Mixin module. It provides the follow functionality groups:
+  #
+  # 1. Access to CGI environment variables as methods.  See 
+  #    documentation to the CGI class for a list of these variables.
+  #
+  # 2. Access to cookies, including the cookies attribute.
+  #
+  # 3. Access to parameters, including the params attribute, and overloading
+  #    [] to perform parameter value lookup by key.
+  #
+  # 4. The initialize_query method, for initialising the above
+  #    mechanisms, handling multipart forms, and allowing the
+  #    class to be used in "offline" mode.
+  #
+  module QueryExtension
+
+    %w[ CONTENT_LENGTH SERVER_PORT ].each do |env|
+      define_method(env.sub(/^HTTP_/, '').downcase) do
+        (val = env_table[env]) && Integer(val)
+      end
+    end
+
+    %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
+        PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
+        REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
+        SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
+
+        HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
+        HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
+        HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
+      define_method(env.sub(/^HTTP_/, '').downcase) do
+        env_table[env]
+      end
+    end
+
+    # Get the raw cookies as a string.
+    def raw_cookie
+      env_table["HTTP_COOKIE"]
+    end
+
+    # Get the raw RFC2965 cookies as a string.
+    def raw_cookie2
+      env_table["HTTP_COOKIE2"]
+    end
+
+    # Get the cookies as a hash of cookie-name=>Cookie pairs.
+    attr_accessor :cookies
+
+    # Get the parameters as a hash of name=>values pairs, where
+    # values is an Array.
+    attr_reader :params
+
+    # Get the uploaed files as a hash of name=>values pairs
+    attr_reader :files
+
+    # Set all the parameters.
+    def params=(hash)
+      @params.clear
+      @params.update(hash)
+    end
+
+    def read_multipart(boundary, content_length)
+      ## read first boundary
+      stdin = $stdin
+      first_line = "--#{boundary}#{EOL}"
+      content_length -= first_line.bytesize
+      status = stdin.read(first_line.bytesize)
+      raise EOFError.new("no content body")  unless status
+      raise EOFError.new("bad content body") unless first_line == status
+      ## parse and set params
+      params = {}
+      @files = {}
+      boundary_rexp = /--#{Regexp.quote(boundary)}(#{EOL}|--)/
+      boundary_size = "#{EOL}--#{boundary}#{EOL}".bytesize
+      boundary_end  = nil
+      buf = ''
+      bufsize = 10 * 1024
+      max_count = MAX_MULTIPART_COUNT
+      n = 0
+      while true
+        (n += 1) < max_count or raise StandardError.new("too many parameters.")
+        ## create body (StringIO or Tempfile)
+        body = create_body(bufsize < content_length)
+        class << body
+          alias local_path path
+          attr_reader :original_filename, :content_type
+        end
+        ## find head and boundary
+        head = nil
+        separator = EOL * 2
+        until head && matched = boundary_rexp.match(buf)
+          if !head && pos = buf.index(separator)
+            len  = pos + EOL.bytesize
+            head = buf[0, len]
+            buf  = buf[(pos+separator.bytesize)..-1]
+          else
+            if head && buf.size > boundary_size
+              len = buf.size - boundary_size
+              body.print(buf[0, len])
+              buf[0, len] = ''
+            end
+            c = stdin.read(bufsize < content_length ? bufsize : content_length)
+            raise EOFError.new("bad content body") if c.nil? || c.empty?
+            buf << c
+            content_length -= c.bytesize
+          end
+        end
+        ## read to end of boundary
+        m = matched
+        len = m.begin(0)
+        s = buf[0, len]
+        if s =~ /(\r?\n)\z/
+          s = buf[0, len - $1.bytesize]
+        end
+        body.print(s)
+        buf = buf[m.end(0)..-1]
+        boundary_end = m[1]
+        content_length = -1 if boundary_end == '--'
+        ## reset file cursor position
+        body.rewind
+        ## original filename
+        /Content-Disposition:.* filename=(?:"(.*?)"|([^;\r\n]*))/i.match(head)
+        filename = $1 || $2 || ''
+        filename = CGI.unescape(filename) if unescape_filename?()
+        body.instance_variable_set('@original_filename', filename.taint)
+        ## content type
+        /Content-Type: (.*)/i.match(head)
+        (content_type = $1 || '').chomp!
+        body.instance_variable_set('@content_type', content_type.taint)
+        ## query parameter name
+        /Content-Disposition:.* name=(?:"(.*?)"|([^;\r\n]*))/i.match(head)
+        name = $1 || $2 || ''
+        if body.original_filename.empty?
+          value=body.read.dup.force_encoding(@accept_charset)
+          (params[name] ||= []) << value
+          unless value.valid_encoding?
+            if @accept_charset_error_block
+              @accept_charset_error_block.call(name,value)
+            else
+              raise InvalidEncoding,"Accept-Charset encoding error"
+            end
+          end
+          class << params[name].last;self;end.class_eval do
+            define_method(:read){self}
+            define_method(:original_filename){""}
+            define_method(:content_type){""}
+          end
+        else
+          (params[name] ||= []) << body
+          @files[name]=body
+        end
+        ## break loop
+        break if buf.size == 0
+        break if content_length == -1
+      end
+      raise EOFError, "bad boundary end of body part" unless boundary_end =~ /--/
+      params.default = []
+      params
+    end # read_multipart
+    private :read_multipart
+    def create_body(is_large)  #:nodoc:
+      if is_large
+        require 'tempfile'
+        body = Tempfile.new('CGI', encoding: "ascii-8bit")
+      else
+        begin
+          require 'stringio'
+          body = StringIO.new("".force_encoding("ascii-8bit"))
+        rescue LoadError
+          require 'tempfile'
+          body = Tempfile.new('CGI', encoding: "ascii-8bit")
+        end
+      end
+      body.binmode if defined? body.binmode
+      return body
+    end
+    def unescape_filename?  #:nodoc:
+      user_agent = $CGI_ENV['HTTP_USER_AGENT']
+      return /Mac/i.match(user_agent) && /Mozilla/i.match(user_agent) && !/MSIE/i.match(user_agent)
+    end
+
+    # offline mode. read name=value pairs on standard input.
+    def read_from_cmdline
+      require "shellwords"
+
+      string = unless ARGV.empty?
+        ARGV.join(' ')
+      else
+        if STDIN.tty?
+          STDERR.print(
+            %|(offline mode: enter name=value pairs on standard input)\n|
+          )
+        end
+        readlines.join(' ').gsub(/\n/, '')
+      end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26')
+
+      words = Shellwords.shellwords(string)
+
+      if words.find{|x| /=/.match(x) }
+        words.join('&')
+      else
+        words.join('+')
+      end
+    end
+    private :read_from_cmdline
+
+    # A wrapper class to use a StringIO object as the body and switch
+    # to a TempFile when the passed threshold is passed.
+    # Initialize the data from the query.
+    #
+    # Handles multipart forms (in particular, forms that involve file uploads).
+    # Reads query parameters in the @params field, and cookies into @cookies.
+    def initialize_query()
+      if ("POST" == env_table['REQUEST_METHOD']) and
+         %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|.match(env_table['CONTENT_TYPE'])
+        raise StandardError.new("too large multipart data.") if env_table['CONTENT_LENGTH'].to_i > MAX_MULTIPART_LENGTH
+        boundary = $1.dup
+        @multipart = true
+        @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
+      else
+        @multipart = false
+        @params = CGI::parse(
+                    case env_table['REQUEST_METHOD']
+                    when "GET", "HEAD"
+                      if defined?(MOD_RUBY)
+                        Apache::request.args or ""
+                      else
+                        env_table['QUERY_STRING'] or ""
+                      end
+                    when "POST"
+                      stdinput.binmode if defined? stdinput.binmode
+                      stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
+                    else
+                      read_from_cmdline
+                    end.dup.force_encoding(@accept_charset)
+                  )
+        unless Encoding.find(@accept_charset) == Encoding::ASCII_8BIT
+          @params.each do |key,values|
+            values.each do |value|
+              unless value.valid_encoding?
+                if @accept_charset_error_block
+                  @accept_charset_error_block.call(key,value)
+                else
+                  raise InvalidEncoding,"Accept-Charset encoding error"
+                end
+              end
+            end
+          end
+        end
+      end
+
+      @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
+    end
+    private :initialize_query
+
+    def multipart?
+      @multipart
+    end
+
+    # Get the value for the parameter with a given key.
+    #
+    # If the parameter has multiple values, only the first will be 
+    # retrieved; use #params() to get the array of values.
+    def [](key)
+      params = @params[key]
+      return '' unless params
+      value = params[0]
+      if @multipart
+        if value
+          return value
+        elsif defined? StringIO
+          StringIO.new("".force_encoding("ascii-8bit"))
+        else
+          Tempfile.new("CGI",encoding:"ascii-8bit")
+        end
+      else
+        str = if value then value.dup else "" end
+        str
+      end
+    end
+
+    # Return all parameter keys as an array.
+    def keys(*args)
+      @params.keys(*args)
+    end
+
+    # Returns true if a given parameter key exists in the query.
+    def has_key?(*args)
+      @params.has_key?(*args)
+    end
+    alias key? has_key?
+    alias include? has_key?
+
+  end # QueryExtension
+
+  # InvalidEncoding Exception class
+  class InvalidEncoding < Exception; end
+
+  # @@accept_charset is default accept character set.
+  # This default value default is "UTF-8"
+  # If you want to change the default accept character set
+  # when create a new CGI instance, set this:
+  # 
+  #   CGI.accept_charset = "EUC-JP"
+  #
+
+  @@accept_charset="UTF-8"
+
+  def self.accept_charset
+    @@accept_charset
+  end
+
+  def self.accept_charset=(accept_charset)
+    @@accept_charset=accept_charset
+  end
+
+  # Create a new CGI instance.
+  #
+  # CGI accept constructor parameters either in a hash, string as a block.
+  # But string is as same as using :tag_maker of hash.
+  #
+  #   CGI.new("html3") #=>  CGI.new(:tag_maker=>"html3")
+  #
+  # And, if you specify string, @accept_charset cannot be changed.
+  # Instead, please use hash parameter.
+  #
+  # == accept_charset
+  #
+  # :accept_charset specifies encoding of received query string.
+  # ( Default value is @@accept_charset. )
+  # If not valid, raise CGI::InvalidEncoding
+  #
+  # Example. Suppose @@accept_charset # => "UTF-8"
+  #
+  # when not specified:
+  #
+  #   cgi=CGI.new      # @accept_charset # => "UTF-8"
+  #
+  # when specified "EUC-JP":
+  #
+  #   cgi=CGI.new(:accept_charset => "EUC-JP") # => "EUC-JP"
+  #
+  # == block
+  #
+  # When you use a block, you can write a process 
+  # that query encoding is invalid. Example:
+  #
+  #   encoding_error={}
+  #   cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value| 
+  #     encoding_error[key] = value
+  #   end
+  #
+  # == tag_maker
+  #
+  # :tag_maker specifies which version of HTML to load the HTML generation
+  # methods for.  The following versions of HTML are supported:
+  #
+  # html3:: HTML 3.x
+  # html4:: HTML 4.0
+  # html4Tr:: HTML 4.0 Transitional
+  # html4Fr:: HTML 4.0 with Framesets
+  #
+  # If not specified, no HTML generation methods will be loaded.
+  #
+  # If the CGI object is not created in a standard CGI call environment
+  # (that is, it can't locate REQUEST_METHOD in its environment), then
+  # it will run in "offline" mode.  In this mode, it reads its parameters
+  # from the command line or (failing that) from standard input.  Otherwise,
+  # cookies and other parameters are parsed automatically from the standard
+  # CGI locations, which varies according to the REQUEST_METHOD. It works this:
+  #
+  #   CGI.new(:tag_maker=>"html3")
+  #
+  # This will be obsolete:
+  #
+  #   CGI.new("html3")
+  #
+  attr_reader :accept_charset
+  def initialize(options = {},&block)
+    @accept_charset_error_block=block if block_given?
+    @options={:accept_charset=>@@accept_charset}
+    case options
+    when Hash
+      @options.merge!(options)
+    when String
+      @options[:tag_maker]=options
+    end
+    @accept_charset=@options[:accept_charset]
+    if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
+      Apache.request.setup_cgi_env
+    end
+
+    extend QueryExtension
+    @multipart = false
+
+    initialize_query()  # set @params, @cookies
+    @output_cookies = nil
+    @output_hidden = nil
+
+    case @options[:tag_maker]
+    when "html3"
+      require 'cgi/html'
+      extend Html3
+      element_init()
+      extend HtmlExtension
+    when "html4"
+      require 'cgi/html'
+      extend Html4
+      element_init()
+      extend HtmlExtension
+    when "html4Tr"
+      require 'cgi/html'
+      extend Html4Tr
+      element_init()
+      extend HtmlExtension
+    when "html4Fr"
+      require 'cgi/html'
+      extend Html4Tr
+      element_init()
+      extend Html4Fr
+      element_init()
+      extend HtmlExtension
+    end
+  end
+
+end   # class CGI
+
+

Copied: MacRuby/branches/experimental/lib/cgi/html.rb (from rev 1886, MacRuby/trunk/lib/cgi/html.rb)
===================================================================
--- MacRuby/branches/experimental/lib/cgi/html.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/cgi/html.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,1021 @@
+  # Base module for HTML-generation mixins.
+  #
+  # Provides methods for code generation for tags following
+  # the various DTD element types.
+class CGI
+  module TagMaker # :nodoc:
+
+    # Generate code for an element with required start and end tags.
+    #
+    #   - -
+    def nn_element_def(element)
+      nOE_element_def(element, <<-END)
+          if block_given?
+            yield.to_s
+          else
+            ""
+          end +
+          "</#{element.upcase}>"
+      END
+    end
+
+    # Generate code for an empty element.
+    #
+    #   - O EMPTY
+    def nOE_element_def(element, append = nil)
+      s = <<-END
+          attributes={attributes=>nil} if attributes.kind_of?(String)
+          "<#{element.upcase}" + attributes.collect{|name, value|
+            next unless value
+            " " + CGI::escapeHTML(name.to_s) +
+            if true == value
+              ""
+            else
+              '="' + CGI::escapeHTML(value.to_s) + '"'
+            end
+          }.join + ">"
+      END
+      s.sub!(/\Z/, " +") << append if append
+      s
+    end
+
+    # Generate code for an element for which the end (and possibly the
+    # start) tag is optional.
+    #
+    #   O O or - O
+    def nO_element_def(element)
+      nOE_element_def(element, <<-END)
+          if block_given?
+            yield.to_s + "</#{element.upcase}>"
+          else
+            ""
+          end
+      END
+    end
+
+  end # TagMaker
+
+
+  #
+  # Mixin module providing HTML generation methods.
+  #
+  # For example,
+  #   cgi.a("http://www.example.com") { "Example" }
+  #     # => "<A HREF=\"http://www.example.com\">Example</A>"
+  #
+  # Modules Http3, Http4, etc., contain more basic HTML-generation methods
+  # (:title, :center, etc.).
+  #
+  # See class CGI for a detailed example. 
+  #
+  module HtmlExtension
+
+
+    # Generate an Anchor element as a string.
+    #
+    # +href+ can either be a string, giving the URL
+    # for the HREF attribute, or it can be a hash of
+    # the element's attributes.
+    #
+    # The body of the element is the string returned by the no-argument
+    # block passed in.
+    #
+    #   a("http://www.example.com") { "Example" }
+    #     # => "<A HREF=\"http://www.example.com\">Example</A>"
+    #
+    #   a("HREF" => "http://www.example.com", "TARGET" => "_top") { "Example" }
+    #     # => "<A HREF=\"http://www.example.com\" TARGET=\"_top\">Example</A>"
+    #
+    def a(href = "") # :yield:
+      attributes = if href.kind_of?(String)
+                     { "HREF" => href }
+                   else
+                     href
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+    # Generate a Document Base URI element as a String. 
+    #
+    # +href+ can either by a string, giving the base URL for the HREF
+    # attribute, or it can be a has of the element's attributes.
+    #
+    # The passed-in no-argument block is ignored.
+    #
+    #   base("http://www.example.com/cgi")
+    #     # => "<BASE HREF=\"http://www.example.com/cgi\">"
+    def base(href = "") # :yield:
+      attributes = if href.kind_of?(String)
+                     { "HREF" => href }
+                   else
+                     href
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+    # Generate a BlockQuote element as a string.
+    #
+    # +cite+ can either be a string, give the URI for the source of
+    # the quoted text, or a hash, giving all attributes of the element,
+    # or it can be omitted, in which case the element has no attributes.
+    #
+    # The body is provided by the passed-in no-argument block
+    #
+    #   blockquote("http://www.example.com/quotes/foo.html") { "Foo!" }
+    #     #=> "<BLOCKQUOTE CITE=\"http://www.example.com/quotes/foo.html\">Foo!</BLOCKQUOTE>
+    def blockquote(cite = {})  # :yield:
+      attributes = if cite.kind_of?(String)
+                     { "CITE" => cite }
+                   else
+                     cite
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+
+    # Generate a Table Caption element as a string.
+    #
+    # +align+ can be a string, giving the alignment of the caption
+    # (one of top, bottom, left, or right).  It can be a hash of
+    # all the attributes of the element.  Or it can be omitted.
+    #
+    # The body of the element is provided by the passed-in no-argument block.
+    #
+    #   caption("left") { "Capital Cities" }
+    #     # => <CAPTION ALIGN=\"left\">Capital Cities</CAPTION>
+    def caption(align = {}) # :yield:
+      attributes = if align.kind_of?(String)
+                     { "ALIGN" => align }
+                   else
+                     align
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+
+    # Generate a Checkbox Input element as a string.
+    #
+    # The attributes of the element can be specified as three arguments,
+    # +name+, +value+, and +checked+.  +checked+ is a boolean value;
+    # if true, the CHECKED attribute will be included in the element.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   checkbox("name")
+    #     # = checkbox("NAME" => "name")
+    # 
+    #   checkbox("name", "value")
+    #     # = checkbox("NAME" => "name", "VALUE" => "value")
+    # 
+    #   checkbox("name", "value", true)
+    #     # = checkbox("NAME" => "name", "VALUE" => "value", "CHECKED" => true)
+    def checkbox(name = "", value = nil, checked = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "checkbox", "NAME" => name,
+                       "VALUE" => value, "CHECKED" => checked }
+                   else
+                     name["TYPE"] = "checkbox"
+                     name
+                   end
+      input(attributes)
+    end
+
+    # Generate a sequence of checkbox elements, as a String.
+    #
+    # The checkboxes will all have the same +name+ attribute.
+    # Each checkbox is followed by a label.
+    # There will be one checkbox for each value.  Each value
+    # can be specified as a String, which will be used both
+    # as the value of the VALUE attribute and as the label
+    # for that checkbox.  A single-element array has the
+    # same effect.
+    #
+    # Each value can also be specified as a three-element array.
+    # The first element is the VALUE attribute; the second is the
+    # label; and the third is a boolean specifying whether this
+    # checkbox is CHECKED.
+    #
+    # Each value can also be specified as a two-element
+    # array, by omitting either the value element (defaults
+    # to the same as the label), or the boolean checked element
+    # (defaults to false).
+    #
+    #   checkbox_group("name", "foo", "bar", "baz")
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
+    # 
+    #   checkbox_group("name", ["foo"], ["bar", true], "baz")
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
+    # 
+    #   checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
+    #     # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="2">Bar
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
+    # 
+    #   checkbox_group("NAME" => "name",
+    #                    "VALUES" => ["foo", "bar", "baz"])
+    # 
+    #   checkbox_group("NAME" => "name",
+    #                    "VALUES" => [["foo"], ["bar", true], "baz"])
+    # 
+    #   checkbox_group("NAME" => "name",
+    #                    "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
+    def checkbox_group(name = "", *values)
+      if name.kind_of?(Hash)
+        values = name["VALUES"]
+        name = name["NAME"]
+      end
+      values.collect{|value|
+        if value.kind_of?(String)
+          checkbox(name, value) + value
+        else
+          if value[-1] == true || value[-1] == false
+            checkbox(name, value[0],  value[-1]) +
+            value[-2]
+          else
+            checkbox(name, value[0]) +
+            value[-1]
+          end
+        end
+      }.join
+    end
+
+
+    # Generate an File Upload Input element as a string.
+    #
+    # The attributes of the element can be specified as three arguments,
+    # +name+, +size+, and +maxlength+.  +maxlength+ is the maximum length
+    # of the file's _name_, not of the file's _contents_.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    # See #multipart_form() for forms that include file uploads.
+    #
+    #   file_field("name")
+    #     # <INPUT TYPE="file" NAME="name" SIZE="20">
+    # 
+    #   file_field("name", 40)
+    #     # <INPUT TYPE="file" NAME="name" SIZE="40">
+    # 
+    #   file_field("name", 40, 100)
+    #     # <INPUT TYPE="file" NAME="name" SIZE="40" MAXLENGTH="100">
+    # 
+    #   file_field("NAME" => "name", "SIZE" => 40)
+    #     # <INPUT TYPE="file" NAME="name" SIZE="40">
+    def file_field(name = "", size = 20, maxlength = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "file", "NAME" => name,
+                       "SIZE" => size.to_s }
+                   else
+                     name["TYPE"] = "file"
+                     name
+                   end
+      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+      input(attributes)
+    end
+
+
+    # Generate a Form element as a string.
+    #
+    # +method+ should be either "get" or "post", and defaults to the latter.
+    # +action+ defaults to the current CGI script name.  +enctype+
+    # defaults to "application/x-www-form-urlencoded".  
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    # See also #multipart_form() for forms that include file uploads.
+    #
+    #   form{ "string" }
+    #     # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+    # 
+    #   form("get") { "string" }
+    #     # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+    # 
+    #   form("get", "url") { "string" }
+    #     # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+    # 
+    #   form("METHOD" => "post", "ENCTYPE" => "enctype") { "string" }
+    #     # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
+    def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded")
+      attributes = if method.kind_of?(String)
+                     { "METHOD" => method, "ACTION" => action,
+                       "ENCTYPE" => enctype } 
+                   else
+                     unless method.has_key?("METHOD")
+                       method["METHOD"] = "post"
+                     end
+                     unless method.has_key?("ENCTYPE")
+                       method["ENCTYPE"] = enctype
+                     end
+                     method
+                   end
+      if block_given?
+        body = yield
+      else
+        body = ""
+      end
+      if @output_hidden
+        body += @output_hidden.collect{|k,v|
+          "<INPUT TYPE=\"HIDDEN\" NAME=\"#{k}\" VALUE=\"#{v}\">"
+        }.join
+      end
+      super(attributes){body}
+    end
+
+    # Generate a Hidden Input element as a string.
+    #
+    # The attributes of the element can be specified as two arguments,
+    # +name+ and +value+.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   hidden("name")
+    #     # <INPUT TYPE="hidden" NAME="name">
+    # 
+    #   hidden("name", "value")
+    #     # <INPUT TYPE="hidden" NAME="name" VALUE="value">
+    # 
+    #   hidden("NAME" => "name", "VALUE" => "reset", "ID" => "foo")
+    #     # <INPUT TYPE="hidden" NAME="name" VALUE="value" ID="foo">
+    def hidden(name = "", value = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "hidden", "NAME" => name, "VALUE" => value }
+                   else
+                     name["TYPE"] = "hidden"
+                     name
+                   end
+      input(attributes)
+    end
+
+    # Generate a top-level HTML element as a string.
+    #
+    # The attributes of the element are specified as a hash.  The
+    # pseudo-attribute "PRETTY" can be used to specify that the generated
+    # HTML string should be indented.  "PRETTY" can also be specified as
+    # a string as the sole argument to this method.  The pseudo-attribute
+    # "DOCTYPE", if given, is used as the leading DOCTYPE SGML tag; it
+    # should include the entire text of this tag, including angle brackets.
+    #
+    # The body of the html element is supplied as a block.
+    # 
+    #   html{ "string" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>string</HTML>
+    # 
+    #   html("LANG" => "ja") { "string" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML LANG="ja">string</HTML>
+    # 
+    #   html("DOCTYPE" => false) { "string" }
+    #     # <HTML>string</HTML>
+    # 
+    #   html("DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">') { "string" }
+    #     # <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML>string</HTML>
+    # 
+    #   html("PRETTY" => "  ") { "<BODY></BODY>" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+    #     # <HTML>
+    #     #   <BODY>
+    #     #   </BODY>
+    #     # </HTML>
+    # 
+    #   html("PRETTY" => "\t") { "<BODY></BODY>" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+    #     # <HTML>
+    #     #         <BODY>
+    #     #         </BODY>
+    #     # </HTML>
+    # 
+    #   html("PRETTY") { "<BODY></BODY>" }
+    #     # = html("PRETTY" => "  ") { "<BODY></BODY>" }
+    # 
+    #   html(if $VERBOSE then "PRETTY" end) { "HTML string" }
+    #
+    def html(attributes = {}) # :yield:
+      if nil == attributes
+        attributes = {}
+      elsif "PRETTY" == attributes
+        attributes = { "PRETTY" => true }
+      end
+      pretty = attributes.delete("PRETTY")
+      pretty = "  " if true == pretty
+      buf = ""
+
+      if attributes.has_key?("DOCTYPE")
+        if attributes["DOCTYPE"]
+          buf += attributes.delete("DOCTYPE")
+        else
+          attributes.delete("DOCTYPE")
+        end
+      else
+        buf += doctype
+      end
+
+      if block_given?
+        buf += super(attributes){ yield }
+      else
+        buf += super(attributes)
+      end
+
+      if pretty
+        CGI::pretty(buf, pretty)
+      else
+        buf
+      end
+
+    end
+
+    # Generate an Image Button Input element as a string.
+    #
+    # +src+ is the URL of the image to use for the button.  +name+ 
+    # is the input name.  +alt+ is the alternative text for the image.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    # 
+    #   image_button("url")
+    #     # <INPUT TYPE="image" SRC="url">
+    # 
+    #   image_button("url", "name", "string")
+    #     # <INPUT TYPE="image" SRC="url" NAME="name" ALT="string">
+    # 
+    #   image_button("SRC" => "url", "ATL" => "strng")
+    #     # <INPUT TYPE="image" SRC="url" ALT="string">
+    def image_button(src = "", name = nil, alt = nil)
+      attributes = if src.kind_of?(String)
+                     { "TYPE" => "image", "SRC" => src, "NAME" => name,
+                       "ALT" => alt }
+                   else
+                     src["TYPE"] = "image"
+                     src["SRC"] ||= ""
+                     src
+                   end
+      input(attributes)
+    end
+
+
+    # Generate an Image element as a string.
+    #
+    # +src+ is the URL of the image.  +alt+ is the alternative text for
+    # the image.  +width+ is the width of the image, and +height+ is
+    # its height.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   img("src", "alt", 100, 50)
+    #     # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
+    # 
+    #   img("SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50)
+    #     # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
+    def img(src = "", alt = "", width = nil, height = nil)
+      attributes = if src.kind_of?(String)
+                     { "SRC" => src, "ALT" => alt }
+                   else
+                     src
+                   end
+      attributes["WIDTH"] = width.to_s if width
+      attributes["HEIGHT"] = height.to_s if height
+      super(attributes)
+    end
+
+
+    # Generate a Form element with multipart encoding as a String.
+    #
+    # Multipart encoding is used for forms that include file uploads.
+    #
+    # +action+ is the action to perform.  +enctype+ is the encoding
+    # type, which defaults to "multipart/form-data".
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   multipart_form{ "string" }
+    #     # <FORM METHOD="post" ENCTYPE="multipart/form-data">string</FORM>
+    # 
+    #   multipart_form("url") { "string" }
+    #     # <FORM METHOD="post" ACTION="url" ENCTYPE="multipart/form-data">string</FORM>
+    def multipart_form(action = nil, enctype = "multipart/form-data")
+      attributes = if action == nil
+                     { "METHOD" => "post", "ENCTYPE" => enctype } 
+                   elsif action.kind_of?(String)
+                     { "METHOD" => "post", "ACTION" => action,
+                       "ENCTYPE" => enctype } 
+                   else
+                     unless action.has_key?("METHOD")
+                       action["METHOD"] = "post"
+                     end
+                     unless action.has_key?("ENCTYPE")
+                       action["ENCTYPE"] = enctype
+                     end
+                     action
+                   end
+      if block_given?
+        form(attributes){ yield }
+      else
+        form(attributes)
+      end
+    end
+
+
+    # Generate a Password Input element as a string.
+    #
+    # +name+ is the name of the input field.  +value+ is its default
+    # value.  +size+ is the size of the input field display.  +maxlength+
+    # is the maximum length of the inputted password.
+    #
+    # Alternatively, attributes can be specified as a hash.
+    #
+    #   password_field("name")
+    #     # <INPUT TYPE="password" NAME="name" SIZE="40">
+    # 
+    #   password_field("name", "value")
+    #     # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="40">
+    # 
+    #   password_field("password", "value", 80, 200)
+    #     # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
+    # 
+    #   password_field("NAME" => "name", "VALUE" => "value")
+    #     # <INPUT TYPE="password" NAME="name" VALUE="value">
+    def password_field(name = "", value = nil, size = 40, maxlength = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "password", "NAME" => name,
+                       "VALUE" => value, "SIZE" => size.to_s }
+                   else
+                     name["TYPE"] = "password"
+                     name
+                   end
+      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+      input(attributes)
+    end
+
+    # Generate a Select element as a string.
+    #
+    # +name+ is the name of the element.  The +values+ are the options that
+    # can be selected from the Select menu.  Each value can be a String or
+    # a one, two, or three-element Array.  If a String or a one-element
+    # Array, this is both the value of that option and the text displayed for
+    # it.  If a three-element Array, the elements are the option value, displayed
+    # text, and a boolean value specifying whether this option starts as selected.
+    # The two-element version omits either the option value (defaults to the same
+    # as the display text) or the boolean selected specifier (defaults to false).
+    #
+    # The attributes and options can also be specified as a hash.  In this
+    # case, options are specified as an array of values as described above,
+    # with the hash key of "VALUES".
+    #
+    #   popup_menu("name", "foo", "bar", "baz")
+    #     # <SELECT NAME="name">
+    #     #   <OPTION VALUE="foo">foo</OPTION>
+    #     #   <OPTION VALUE="bar">bar</OPTION>
+    #     #   <OPTION VALUE="baz">baz</OPTION>
+    #     # </SELECT>
+    # 
+    #   popup_menu("name", ["foo"], ["bar", true], "baz")
+    #     # <SELECT NAME="name">
+    #     #   <OPTION VALUE="foo">foo</OPTION>
+    #     #   <OPTION VALUE="bar" SELECTED>bar</OPTION>
+    #     #   <OPTION VALUE="baz">baz</OPTION>
+    #     # </SELECT>
+    # 
+    #   popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+    #     # <SELECT NAME="name">
+    #     #   <OPTION VALUE="1">Foo</OPTION>
+    #     #   <OPTION SELECTED VALUE="2">Bar</OPTION>
+    #     #   <OPTION VALUE="Baz">Baz</OPTION>
+    #     # </SELECT>
+    # 
+    #   popup_menu("NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
+    #               "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
+    #     # <SELECT NAME="name" MULTIPLE SIZE="2">
+    #     #   <OPTION VALUE="1">Foo</OPTION>
+    #     #   <OPTION SELECTED VALUE="2">Bar</OPTION>
+    #     #   <OPTION VALUE="Baz">Baz</OPTION>
+    #     # </SELECT>
+    def popup_menu(name = "", *values)
+
+      if name.kind_of?(Hash)
+        values   = name["VALUES"]
+        size     = name["SIZE"].to_s if name["SIZE"]
+        multiple = name["MULTIPLE"]
+        name     = name["NAME"]
+      else
+        size = nil
+        multiple = nil
+      end
+
+      select({ "NAME" => name, "SIZE" => size,
+               "MULTIPLE" => multiple }){
+        values.collect{|value|
+          if value.kind_of?(String)
+            option({ "VALUE" => value }){ value }
+          else
+            if value[value.size - 1] == true
+              option({ "VALUE" => value[0], "SELECTED" => true }){
+                value[value.size - 2]
+              }
+            else
+              option({ "VALUE" => value[0] }){
+                value[value.size - 1]
+              }
+            end
+          end
+        }.join
+      }
+
+    end
+
+    # Generates a radio-button Input element.
+    #
+    # +name+ is the name of the input field.  +value+ is the value of
+    # the field if checked.  +checked+ specifies whether the field
+    # starts off checked.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   radio_button("name", "value")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="value">
+    # 
+    #   radio_button("name", "value", true)
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="value" CHECKED>
+    # 
+    #   radio_button("NAME" => "name", "VALUE" => "value", "ID" => "foo")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="value" ID="foo">
+    def radio_button(name = "", value = nil, checked = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "radio", "NAME" => name,
+                       "VALUE" => value, "CHECKED" => checked }
+                   else
+                     name["TYPE"] = "radio"
+                     name
+                   end
+      input(attributes)
+    end
+
+    # Generate a sequence of radio button Input elements, as a String.
+    #
+    # This works the same as #checkbox_group().  However, it is not valid
+    # to have more than one radiobutton in a group checked.
+    # 
+    #   radio_group("name", "foo", "bar", "baz")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
+    # 
+    #   radio_group("name", ["foo"], ["bar", true], "baz")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
+    # 
+    #   radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="1">Foo
+    #     # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="2">Bar
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="Baz">Baz
+    # 
+    #   radio_group("NAME" => "name",
+    #                 "VALUES" => ["foo", "bar", "baz"])
+    # 
+    #   radio_group("NAME" => "name",
+    #                 "VALUES" => [["foo"], ["bar", true], "baz"])
+    # 
+    #   radio_group("NAME" => "name",
+    #                 "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
+    def radio_group(name = "", *values)
+      if name.kind_of?(Hash)
+        values = name["VALUES"]
+        name = name["NAME"]
+      end
+      values.collect{|value|
+        if value.kind_of?(String)
+          radio_button(name, value) + value
+        else
+          if value[-1] == true || value[-1] == false
+            radio_button(name, value[0],  value[-1]) +
+            value[-2]
+          else
+            radio_button(name, value[0]) +
+            value[-1]
+          end
+        end
+      }.join
+    end
+
+    # Generate a reset button Input element, as a String.
+    #
+    # This resets the values on a form to their initial values.  +value+
+    # is the text displayed on the button. +name+ is the name of this button.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   reset
+    #     # <INPUT TYPE="reset">
+    # 
+    #   reset("reset")
+    #     # <INPUT TYPE="reset" VALUE="reset">
+    # 
+    #   reset("VALUE" => "reset", "ID" => "foo")
+    #     # <INPUT TYPE="reset" VALUE="reset" ID="foo">
+    def reset(value = nil, name = nil)
+      attributes = if (not value) or value.kind_of?(String)
+                     { "TYPE" => "reset", "VALUE" => value, "NAME" => name }
+                   else
+                     value["TYPE"] = "reset"
+                     value
+                   end
+      input(attributes)
+    end
+
+    alias scrolling_list popup_menu
+
+    # Generate a submit button Input element, as a String.
+    #
+    # +value+ is the text to display on the button.  +name+ is the name
+    # of the input.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   submit
+    #     # <INPUT TYPE="submit">
+    # 
+    #   submit("ok")
+    #     # <INPUT TYPE="submit" VALUE="ok">
+    # 
+    #   submit("ok", "button1")
+    #     # <INPUT TYPE="submit" VALUE="ok" NAME="button1">
+    # 
+    #   submit("VALUE" => "ok", "NAME" => "button1", "ID" => "foo")
+    #     # <INPUT TYPE="submit" VALUE="ok" NAME="button1" ID="foo">
+    def submit(value = nil, name = nil)
+      attributes = if (not value) or value.kind_of?(String)
+                     { "TYPE" => "submit", "VALUE" => value, "NAME" => name }
+                   else
+                     value["TYPE"] = "submit"
+                     value
+                   end
+      input(attributes)
+    end
+
+    # Generate a text field Input element, as a String.
+    #
+    # +name+ is the name of the input field.  +value+ is its initial
+    # value.  +size+ is the size of the input area.  +maxlength+
+    # is the maximum length of input accepted.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   text_field("name")
+    #     # <INPUT TYPE="text" NAME="name" SIZE="40">
+    # 
+    #   text_field("name", "value")
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="40">
+    # 
+    #   text_field("name", "value", 80)
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80">
+    # 
+    #   text_field("name", "value", 80, 200)
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
+    # 
+    #   text_field("NAME" => "name", "VALUE" => "value")
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value">
+    def text_field(name = "", value = nil, size = 40, maxlength = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "text", "NAME" => name, "VALUE" => value,
+                       "SIZE" => size.to_s }
+                   else
+                     name["TYPE"] = "text"
+                     name
+                   end
+      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+      input(attributes)
+    end
+
+    # Generate a TextArea element, as a String.
+    #
+    # +name+ is the name of the textarea.  +cols+ is the number of
+    # columns and +rows+ is the number of rows in the display.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    # The body is provided by the passed-in no-argument block
+    #
+    #   textarea("name")
+    #      # = textarea("NAME" => "name", "COLS" => 70, "ROWS" => 10)
+    #
+    #   textarea("name", 40, 5)
+    #      # = textarea("NAME" => "name", "COLS" => 40, "ROWS" => 5)
+    def textarea(name = "", cols = 70, rows = 10)  # :yield:
+      attributes = if name.kind_of?(String)
+                     { "NAME" => name, "COLS" => cols.to_s,
+                       "ROWS" => rows.to_s }
+                   else
+                     name
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+  end # HtmlExtension
+
+
+  # Mixin module for HTML version 3 generation methods.
+  module Html3 # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      extend TagMaker
+      methods = ""
+      # - -
+      for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
+          DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP
+          APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE
+          STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
+          CAPTION ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
+          ISINDEX META ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # O O or - O
+      for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION tr
+          th td ]
+        methods += <<-BEGIN + nO_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html3
+
+
+  # Mixin module for HTML version 4 generation methods.
+  module Html4 # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      extend TagMaker
+      methods = ""
+      # - -
+      for element in %w[ TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD
+        VAR CITE ABBR ACRONYM SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT
+        H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT OPTGROUP
+        FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT
+        TEXTAREA FORM A BLOCKQUOTE CAPTION ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # O O or - O
+      for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
+          COLGROUP TR TH TD HEAD]
+        methods += <<-BEGIN + nO_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html4
+
+
+  # Mixin module for HTML version 4 transitional generation methods.
+  module Html4Tr # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      extend TagMaker
+      methods = ""
+      # - -
+      for element in %w[ TT I B U S STRIKE BIG SMALL EM STRONG DFN
+          CODE SAMP KBD VAR CITE ABBR ACRONYM FONT SUB SUP SPAN BDO
+          ADDRESS DIV CENTER MAP OBJECT APPLET H1 H2 H3 H4 H5 H6 PRE Q
+          INS DEL DL OL UL DIR MENU LABEL SELECT OPTGROUP FIELDSET
+          LEGEND BUTTON TABLE IFRAME NOFRAMES TITLE STYLE SCRIPT
+          NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
+          COL ISINDEX META ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # O O or - O
+      for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
+          COLGROUP TR TH TD HEAD ]
+        methods += <<-BEGIN + nO_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html4Tr
+
+
+  # Mixin module for generating HTML version 4 with framesets.
+  module Html4Fr # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      methods = ""
+      # - -
+      for element in %w[ FRAMESET ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ FRAME ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html4Fr
+end
+
+

Modified: MacRuby/branches/experimental/lib/cgi/session/pstore.rb
===================================================================
--- MacRuby/branches/experimental/lib/cgi/session/pstore.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/cgi/session/pstore.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -30,7 +30,7 @@
       # characters; automatically generated session ids observe
       # this requirement.
       # 
-      # +option+ is a hash of options for the initialiser.  The
+      # +option+ is a hash of options for the initializer.  The
       # following options are recognised:
       #
       # tmpdir:: the directory to use for storing the PStore
@@ -43,55 +43,55 @@
       # This session's PStore file will be created if it does
       # not exist, or opened if it does.
       def initialize(session, option={})
-	dir = option['tmpdir'] || Dir::tmpdir
-	prefix = option['prefix'] || ''
-	id = session.session_id
+        dir = option['tmpdir'] || Dir::tmpdir
+        prefix = option['prefix'] || ''
+        id = session.session_id
         require 'digest/md5'
         md5 = Digest::MD5.hexdigest(id)[0,16]
-	path = dir+"/"+prefix+md5
-	path.untaint
-	if File::exist?(path)
-	  @hash = nil
-	else
+        path = dir+"/"+prefix+md5
+        path.untaint
+        if File::exist?(path)
+          @hash = nil
+        else
           unless session.new_session
             raise CGI::Session::NoSession, "uninitialized session"
           end
-	  @hash = {}
-	end
-	@p = ::PStore.new(path)
-	@p.transaction do |p|
-	  File.chmod(0600, p.path)
-	end
+          @hash = {}
+        end
+        @p = ::PStore.new(path)
+        @p.transaction do |p|
+          File.chmod(0600, p.path)
+        end
       end
 
       # Restore session state from the session's PStore file.
       #
       # Returns the session state as a hash.
       def restore
-	unless @hash
-	  @p.transaction do
+        unless @hash
+          @p.transaction do
             @hash = @p['hash'] || {}
-	  end
-	end
-	@hash
+          end
+        end
+        @hash
       end
 
       # Save session state to the session's PStore file.
       def update 
-	@p.transaction do
-	    @p['hash'] = @hash
-	end
+        @p.transaction do
+          @p['hash'] = @hash
+        end
       end
 
       # Update and close the session's PStore file.
       def close
-	update
+        update
       end
 
       # Close and delete the session's PStore file.
       def delete
-	path = @p.path
-	File::unlink path
+        path = @p.path
+        File::unlink path
       end
 
     end

Modified: MacRuby/branches/experimental/lib/cgi/session.rb
===================================================================
--- MacRuby/branches/experimental/lib/cgi/session.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/cgi/session.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -163,7 +163,7 @@
 
     def Session::callback(dbman)  #:nodoc:
       Proc.new{
-	dbman[0].close unless dbman.empty?
+        dbman[0].close unless dbman.empty?
       }
     end
 
@@ -188,7 +188,6 @@
         md5.update('foobar')
         session_id = md5.hexdigest
       end
-      @new_session = true
       session_id
     end
     private :create_new_id
@@ -230,7 +229,7 @@
     # session_path:: the path for which this session applies.  Defaults
     #                to the directory of the CGI script.
     #
-    # +option+ is also passed on to the session storage class initialiser; see
+    # +option+ is also passed on to the session storage class initializer; see
     # the documentation for each session storage class for the options
     # they support.
     #                  
@@ -254,24 +253,26 @@
       session_key = option['session_key'] || '_session_id'
       session_id = option['session_id']
       unless session_id
-	if option['new_session']
-	  session_id = create_new_id
-	end
+        if option['new_session']
+          session_id = create_new_id
+          @new_session = true
+        end
       end
       unless session_id
-	if request.key?(session_key)
-	  session_id = request[session_key]
-	  session_id = session_id.read if session_id.respond_to?(:read)
-	end
-	unless session_id
-	  session_id, = request.cookies[session_key]
-	end
-	unless session_id
-	  unless option.fetch('new_session', true)
-	    raise ArgumentError, "session_key `%s' should be supplied"%session_key
-	  end
-	  session_id = create_new_id
-	end
+        if request.key?(session_key)
+          session_id = request[session_key]
+          session_id = session_id.read if session_id.respond_to?(:read)
+        end
+        unless session_id
+          session_id, = request.cookies[session_key]
+        end
+        unless session_id
+          unless option.fetch('new_session', true)
+            raise ArgumentError, "session_key `%s' should be supplied"%session_key
+          end
+          session_id = create_new_id
+          @new_session = true
+        end
       end
       @session_id = session_id
       dbman = option['database_manager'] || FileStore
@@ -281,24 +282,26 @@
         unless option.fetch('new_session', true)
           raise ArgumentError, "invalid session_id `%s'"%session_id
         end
-        session_id = @session_id = create_new_id
+        session_id = @session_id = create_new_id unless session_id
+        @new_session=true
         retry
       end
       request.instance_eval do
-	@output_hidden = {session_key => session_id} unless option['no_hidden']
-	@output_cookies =  [
+        @output_hidden = {session_key => session_id} unless option['no_hidden']
+        @output_cookies =  [
           Cookie::new("name" => session_key,
-		      "value" => session_id,
-		      "expires" => option['session_expires'],
-		      "domain" => option['session_domain'],
-		      "secure" => option['session_secure'],
-		      "path" => if option['session_path'] then
-				  option['session_path']
-		                elsif ENV["SCRIPT_NAME"] then
-				  File::dirname(ENV["SCRIPT_NAME"])
-				else
-				  ""
-				end)
+          "value" => session_id,
+          "expires" => option['session_expires'],
+          "domain" => option['session_domain'],
+          "secure" => option['session_secure'],
+          "path" => 
+          if option['session_path']
+            option['session_path']
+          elsif ENV["SCRIPT_NAME"]
+            File::dirname(ENV["SCRIPT_NAME"])
+          else
+          ""
+          end)
         ] unless option['no_cookies']
       end
       @dbprot = [@dbman]
@@ -357,7 +360,7 @@
       # characters; automatically generated session ids observe
       # this requirement.
       # 
-      # +option+ is a hash of options for the initialiser.  The
+      # +option+ is a hash of options for the initializer.  The
       # following options are recognised:
       #
       # tmpdir:: the directory to use for storing the FileStore
@@ -373,56 +376,56 @@
       # This session's FileStore file will be created if it does
       # not exist, or opened if it does.
       def initialize(session, option={})
-	dir = option['tmpdir'] || Dir::tmpdir
-	prefix = option['prefix'] || 'cgi_sid_'
-	suffix = option['suffix'] || ''
-	id = session.session_id
+        dir = option['tmpdir'] || Dir::tmpdir
+        prefix = option['prefix'] || 'cgi_sid_'
+        suffix = option['suffix'] || ''
+        id = session.session_id
         require 'digest/md5'
         md5 = Digest::MD5.hexdigest(id)[0,16]
-	@path = dir+"/"+prefix+md5+suffix
-	if File::exist? @path
-	  @hash = nil
-	else
+        @path = dir+"/"+prefix+md5+suffix
+        if File::exist? @path
+          @hash = nil
+        else
           unless session.new_session
             raise CGI::Session::NoSession, "uninitialized session"
           end
-	  @hash = {}
-	end
+          @hash = {}
+        end
       end
 
       # Restore session state from the session's FileStore file.
       #
       # Returns the session state as a hash.
       def restore
-	unless @hash
-	  @hash = {}
+        unless @hash
+          @hash = {}
           begin
             lockf = File.open(@path+".lock", "r")
             lockf.flock File::LOCK_SH
-	    f = File.open(@path, 'r')
-	    for line in f
-	      line.chomp!
-	      k, v = line.split('=',2)
-	      @hash[CGI::unescape(k)] = CGI::unescape(v)
-	    end
+            f = File.open(@path, 'r')
+            for line in f
+              line.chomp!
+              k, v = line.split('=',2)
+              @hash[CGI::unescape(k)] = Marshal.restore(CGI::unescape(v))
+            end
           ensure
-	    f.close unless f.nil?
+            f.close unless f.nil?
             lockf.close if lockf
           end
-	end
-	@hash
+        end
+        @hash
       end
 
       # Save session state to the session's FileStore file.
       def update
-	return unless @hash
+        return unless @hash
         begin
           lockf = File.open(@path+".lock", File::CREAT|File::RDWR, 0600)
-	  lockf.flock File::LOCK_EX
+          lockf.flock File::LOCK_EX
           f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600)
-   	  for k,v in @hash
-	    f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(v))
-	  end
+          for k,v in @hash
+            f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(Marshal.dump(v)))
+          end
           f.close
           File.rename @path+".new", @path
         ensure
@@ -433,15 +436,14 @@
 
       # Update and close the session's FileStore file.
       def close
-	update
+        update
       end
 
       # Close and delete the session's FileStore file.
       def delete
         File::unlink @path+".lock" rescue nil
         File::unlink @path+".new" rescue nil
-        File::unlink @path
-      rescue Errno::ENOENT
+        File::unlink @path rescue Errno::ENOENT
       end
     end
 
@@ -459,7 +461,7 @@
       # +option+ is a list of initialisation options.  None are
       # currently recognised.
       def initialize(session, option=nil)
-	@session_id = session.session_id
+        @session_id = session.session_id
         unless GLOBAL_HASH_TABLE.key?(@session_id)
           unless session.new_session
             raise CGI::Session::NoSession, "uninitialized session"
@@ -472,26 +474,26 @@
       #
       # Returns session data as a hash.
       def restore
-	GLOBAL_HASH_TABLE[@session_id]
+        GLOBAL_HASH_TABLE[@session_id]
       end
 
       # Update session state.
       #
       # A no-op.
       def update
-	# don't need to update; hash is shared
+        # don't need to update; hash is shared
       end
 
       # Close session storage.
       #
       # A no-op.
       def close
-	# don't need to close
+        # don't need to close
       end
 
       # Delete the session state.
       def delete
-	GLOBAL_HASH_TABLE.delete(@session_id)
+        GLOBAL_HASH_TABLE.delete(@session_id)
       end
     end
 

Copied: MacRuby/branches/experimental/lib/cgi/util.rb (from rev 1886, MacRuby/trunk/lib/cgi/util.rb)
===================================================================
--- MacRuby/branches/experimental/lib/cgi/util.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/cgi/util.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,181 @@
+class CGI
+  # URL-encode a string.
+  #   url_encoded_string = CGI::escape("'Stop!' said Fred")
+  #      # => "%27Stop%21%27+said+Fred"
+  def CGI::escape(string)
+    string.gsub(/([^ a-zA-Z0-9_.-]+)/) do
+      '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
+    end.tr(' ', '+')
+  end
+
+
+  # URL-decode a string.
+  #   string = CGI::unescape("%27Stop%21%27+said+Fred")
+  #      # => "'Stop!' said Fred"
+  def CGI::unescape(string)
+    enc = string.encoding
+    string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do
+      [$1.delete('%')].pack('H*').force_encoding(enc)
+    end
+  end
+
+  TABLE_FOR_ESCAPE_HTML__ = {
+    '&' => '&amp;',
+    '"' => '&quot;',
+    '<' => '&lt;',
+    '>' => '&gt;',
+  }
+
+  # Escape special characters in HTML, namely &\"<>
+  #   CGI::escapeHTML('Usage: foo "bar" <baz>')
+  #      # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"
+  def CGI::escapeHTML(string)
+    string.gsub(/[&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
+  end
+
+
+  # Unescape a string that has been HTML-escaped
+  #   CGI::unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
+  #      # => "Usage: foo \"bar\" <baz>"
+  def CGI::unescapeHTML(string)
+    enc = string.encoding
+    if [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].include?(enc)
+      return string.gsub(Regexp.new('&(amp|quot|gt|lt|#[0-9]+|#x[0-9A-Fa-f]+);'.encode(enc))) do
+        case $1.encode("US-ASCII")
+        when 'amp'                 then '&'.encode(enc)
+        when 'quot'                then '"'.encode(enc)
+        when 'gt'                  then '>'.encode(enc)
+        when 'lt'                  then '<'.encode(enc)
+        when /\A#0*(\d+)\z/        then $1.to_i.chr(enc)
+        when /\A#x([0-9a-f]+)\z/i  then $1.hex.chr(enc)
+        end
+      end
+    end
+    asciicompat = Encoding.compatible?(string, "a")
+    string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/) do
+      match = $1.dup
+      case match
+      when 'amp'                 then '&'
+      when 'quot'                then '"'
+      when 'gt'                  then '>'
+      when 'lt'                  then '<'
+      when /\A#0*(\d+)\z/
+        n = $1.to_i
+        if enc == Encoding::UTF_8 or
+          enc == Encoding::ISO_8859_1 && n < 256 or
+          asciicompat && n < 128
+          n.chr(enc)
+        else
+          "&##{$1};"
+        end
+      when /\A#x([0-9a-f]+)\z/i
+        n = $1.hex
+        if enc == Encoding::UTF_8 or
+          enc == Encoding::ISO_8859_1 && n < 256 or
+          asciicompat && n < 128
+          n.chr(enc)
+        else
+          "&#x#{$1};"
+        end
+      else
+        "&#{match};"
+      end
+    end
+  end
+  def CGI::escape_html(str)
+    escapeHTML(str)
+  end
+  def CGI::unescape_html(str)
+    unescapeHTML(str)
+  end
+
+  # Escape only the tags of certain HTML elements in +string+.
+  #
+  # Takes an element or elements or array of elements.  Each element
+  # is specified by the name of the element, without angle brackets.
+  # This matches both the start and the end tag of that element.
+  # The attribute list of the open tag will also be escaped (for
+  # instance, the double-quotes surrounding attribute values).
+  #
+  #   print CGI::escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
+  #     # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
+  #
+  #   print CGI::escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
+  #     # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
+  def CGI::escapeElement(string, *elements)
+    elements = elements[0] if elements[0].kind_of?(Array)
+    unless elements.empty?
+      string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do
+        CGI::escapeHTML($&)
+      end
+    else
+      string
+    end
+  end
+
+
+  # Undo escaping such as that done by CGI::escapeElement()
+  #
+  #   print CGI::unescapeElement(
+  #           CGI::escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
+  #     # "&lt;BR&gt;<A HREF="url"></A>"
+  # 
+  #   print CGI::unescapeElement(
+  #           CGI::escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
+  #     # "&lt;BR&gt;<A HREF="url"></A>"
+  def CGI::unescapeElement(string, *elements)
+    elements = elements[0] if elements[0].kind_of?(Array)
+    unless elements.empty?
+      string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) do
+        CGI::unescapeHTML($&)
+      end
+    else
+      string
+    end
+  end
+  def CGI::escape_element(str)
+    escapeElement(str)
+  end
+  def CGI::unescape_element(str)
+    unescapeElement(str)
+  end
+
+  # Format a +Time+ object as a String using the format specified by RFC 1123.
+  #
+  #   CGI::rfc1123_date(Time.now)
+  #     # Sat, 01 Jan 2000 00:00:00 GMT
+  def CGI::rfc1123_date(time)
+    t = time.clone.gmtime
+    return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
+                RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
+                t.hour, t.min, t.sec)
+  end
+
+  # Prettify (indent) an HTML string.
+  #
+  # +string+ is the HTML string to indent.  +shift+ is the indentation
+  # unit to use; it defaults to two spaces.
+  #
+  #   print CGI::pretty("<HTML><BODY></BODY></HTML>")
+  #     # <HTML>
+  #     #   <BODY>
+  #     #   </BODY>
+  #     # </HTML>
+  # 
+  #   print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
+  #     # <HTML>
+  #     #         <BODY>
+  #     #         </BODY>
+  #     # </HTML>
+  #
+  def CGI::pretty(string, shift = "  ")
+    lines = string.gsub(/(?!\A)<(?:.|\n)*?>/, "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/, "\\0\n")
+    end_pos = 0
+    while end_pos = lines.index(/^<\/(\w+)/, end_pos)
+      element = $1.dup
+      start_pos = lines.rindex(/^\s*<#{element}/i, end_pos)
+      lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/, "\n" + shift) + "__"
+    end
+    lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/, '\1')
+  end
+end

Modified: MacRuby/branches/experimental/lib/cgi.rb
===================================================================
--- MacRuby/branches/experimental/lib/cgi.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/cgi.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -30,10 +30,8 @@
 # See http://www.w3.org/CGI/ for more information on the CGI
 # protocol.
 
-raise "Please, use ruby 1.5.4 or later." if RUBY_VERSION < "1.5.4"
+raise "Please, use ruby 1.9.0 or later." if RUBY_VERSION < "1.9.0"
 
-require 'English'
-
 # CGI class.  See documentation for the file cgi.rb for an overview
 # of the CGI protocol.
 #
@@ -271,2063 +269,6 @@
 #   CGI.new("html4Tr")  # html4.01 Transitional
 #   CGI.new("html4Fr")  # html4.01 Frameset
 #
-class CGI
-
-  # :stopdoc:
-
-  # String for carriage return
-  CR  = "\015"
-
-  # String for linefeed
-  LF  = "\012"
-
-  # Standard internet newline sequence
-  EOL = CR + LF
-
-  REVISION = '$Id: cgi.rb 15781 2008-03-14 08:08:51Z matz $' #:nodoc:
-
-  NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM) 
-
-  # Path separators in different environments.
-  PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
-
-  # HTTP status codes.
-  HTTP_STATUS = {
-    "OK"                  => "200 OK",
-    "PARTIAL_CONTENT"     => "206 Partial Content",
-    "MULTIPLE_CHOICES"    => "300 Multiple Choices",
-    "MOVED"               => "301 Moved Permanently",
-    "REDIRECT"            => "302 Found",
-    "NOT_MODIFIED"        => "304 Not Modified",
-    "BAD_REQUEST"         => "400 Bad Request",
-    "AUTH_REQUIRED"       => "401 Authorization Required",
-    "FORBIDDEN"           => "403 Forbidden",
-    "NOT_FOUND"           => "404 Not Found",
-    "METHOD_NOT_ALLOWED"  => "405 Method Not Allowed",
-    "NOT_ACCEPTABLE"      => "406 Not Acceptable",
-    "LENGTH_REQUIRED"     => "411 Length Required",
-    "PRECONDITION_FAILED" => "412 Rrecondition Failed",
-    "SERVER_ERROR"        => "500 Internal Server Error",
-    "NOT_IMPLEMENTED"     => "501 Method Not Implemented",
-    "BAD_GATEWAY"         => "502 Bad Gateway",
-    "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
-  }
-
-  # Abbreviated day-of-week names specified by RFC 822
-  RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
-
-  # Abbreviated month names specified by RFC 822
-  RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
-
-  # :startdoc:
-
-  def env_table 
-    ENV
-  end
-
-  def stdinput
-    $stdin
-  end
-
-  def stdoutput
-    $DEFAULT_OUTPUT
-  end
-
-  private :env_table, :stdinput, :stdoutput
-
-  # URL-encode a string.
-  #   url_encoded_string = CGI::escape("'Stop!' said Fred")
-  #      # => "%27Stop%21%27+said+Fred"
-  def CGI::escape(string)
-    string.gsub(/([^ a-zA-Z0-9_.-]+)/) do
-      '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
-    end.tr(' ', '+')
-  end
-
-
-  # URL-decode a string.
-  #   string = CGI::unescape("%27Stop%21%27+said+Fred")
-  #      # => "'Stop!' said Fred"
-  def CGI::unescape(string)
-    enc = string.encoding
-    string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do
-      [$1.delete('%')].pack('H*').force_encoding(enc)
-    end
-  end
-
-  TABLE_FOR_ESCAPE_HTML__ = {
-    '&' => '&amp;',
-    '"' => '&quot;',
-    '<' => '&lt;',
-    '>' => '&gt;',
-  }
-
-  # Escape special characters in HTML, namely &\"<>
-  #   CGI::escapeHTML('Usage: foo "bar" <baz>')
-  #      # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"
-  def CGI::escapeHTML(string)
-    string.gsub(/[&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
-  end
-
-
-  # Unescape a string that has been HTML-escaped
-  #   CGI::unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
-  #      # => "Usage: foo \"bar\" <baz>"
-  def CGI::unescapeHTML(string)
-    enc = string.encoding
-    string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/) do
-      match = $1.dup
-      case match
-      when 'amp'                 then '&'
-      when 'quot'                then '"'
-      when 'gt'                  then '>'
-      when 'lt'                  then '<'
-      when /\A#0*(\d+)\z/        then
-        if Integer($1) < 256
-          Integer($1).chr.force_encoding(enc)
-        else
-          "&##{$1};"
-        end
-      when /\A#x([0-9a-f]+)\z/i then
-        if $1.hex < 256
-          $1.hex.chr.force_encoding(enc)
-        else
-          "&#x#{$1};"
-        end
-      else
-        "&#{match};"
-      end
-    end
-  end
-  def CGI::escape_html(str)
-    escapeHTML(str)
-  end
-  def CGI::unescape_html(str)
-    unescapeHTML(str)
-  end
-
-  # Escape only the tags of certain HTML elements in +string+.
-  #
-  # Takes an element or elements or array of elements.  Each element
-  # is specified by the name of the element, without angle brackets.
-  # This matches both the start and the end tag of that element.
-  # The attribute list of the open tag will also be escaped (for
-  # instance, the double-quotes surrounding attribute values).
-  #
-  #   print CGI::escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
-  #     # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
-  #
-  #   print CGI::escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
-  #     # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
-  def CGI::escapeElement(string, *elements)
-    elements = elements[0] if elements[0].kind_of?(Array)
-    unless elements.empty?
-      string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
-        CGI::escapeHTML($&)
-      end
-    else
-      string
-    end
-  end
-
-
-  # Undo escaping such as that done by CGI::escapeElement()
-  #
-  #   print CGI::unescapeElement(
-  #           CGI::escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
-  #     # "&lt;BR&gt;<A HREF="url"></A>"
-  # 
-  #   print CGI::unescapeElement(
-  #           CGI::escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
-  #     # "&lt;BR&gt;<A HREF="url"></A>"
-  def CGI::unescapeElement(string, *elements)
-    elements = elements[0] if elements[0].kind_of?(Array)
-    unless elements.empty?
-      string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/ni) do
-        CGI::unescapeHTML($&)
-      end
-    else
-      string
-    end
-  end
-  def CGI::escape_element(str)
-    escapeElement(str)
-  end
-  def CGI::unescape_element(str)
-    unescapeElement(str)
-  end
-
-  # Format a +Time+ object as a String using the format specified by RFC 1123.
-  #
-  #   CGI::rfc1123_date(Time.now)
-  #     # Sat, 01 Jan 2000 00:00:00 GMT
-  def CGI::rfc1123_date(time)
-    t = time.clone.gmtime
-    return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
-                RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
-                t.hour, t.min, t.sec)
-  end
-
-
-  # Create an HTTP header block as a string.
-  #
-  # Includes the empty line that ends the header block.
-  #
-  # +options+ can be a string specifying the Content-Type (defaults
-  # to text/html), or a hash of header key/value pairs.  The following
-  # header keys are recognized:
-  #
-  # type:: the Content-Type header.  Defaults to "text/html"
-  # charset:: the charset of the body, appended to the Content-Type header.
-  # nph:: a boolean value.  If true, prepend protocol string and status code, and
-  #       date; and sets default values for "server" and "connection" if not
-  #       explicitly set.
-  # status:: the HTTP status code, returned as the Status header.  See the
-  #          list of available status codes below.
-  # server:: the server software, returned as the Server header.
-  # connection:: the connection type, returned as the Connection header (for 
-  #              instance, "close".
-  # length:: the length of the content that will be sent, returned as the
-  #          Content-Length header.
-  # language:: the language of the content, returned as the Content-Language
-  #            header.
-  # expires:: the time on which the current content expires, as a +Time+
-  #           object, returned as the Expires header.
-  # cookie:: a cookie or cookies, returned as one or more Set-Cookie headers.
-  #          The value can be the literal string of the cookie; a CGI::Cookie
-  #          object; an Array of literal cookie strings or Cookie objects; or a 
-  #          hash all of whose values are literal cookie strings or Cookie objects.
-  #          These cookies are in addition to the cookies held in the
-  #          @output_cookies field.
-  #
-  # Other header lines can also be set; they are appended as key: value.
-  # 
-  #   header
-  #     # Content-Type: text/html
-  # 
-  #   header("text/plain")
-  #     # Content-Type: text/plain
-  # 
-  #   header("nph"        => true,
-  #          "status"     => "OK",  # == "200 OK"
-  #            # "status"     => "200 GOOD",
-  #          "server"     => ENV['SERVER_SOFTWARE'],
-  #          "connection" => "close",
-  #          "type"       => "text/html",
-  #          "charset"    => "iso-2022-jp",
-  #            # Content-Type: text/html; charset=iso-2022-jp
-  #          "length"     => 103,
-  #          "language"   => "ja",
-  #          "expires"    => Time.now + 30,
-  #          "cookie"     => [cookie1, cookie2],
-  #          "my_header1" => "my_value"
-  #          "my_header2" => "my_value")
-  # 
-  # The status codes are:
-  # 
-  #   "OK"                  --> "200 OK"
-  #   "PARTIAL_CONTENT"     --> "206 Partial Content"
-  #   "MULTIPLE_CHOICES"    --> "300 Multiple Choices"
-  #   "MOVED"               --> "301 Moved Permanently"
-  #   "REDIRECT"            --> "302 Found"
-  #   "NOT_MODIFIED"        --> "304 Not Modified"
-  #   "BAD_REQUEST"         --> "400 Bad Request"
-  #   "AUTH_REQUIRED"       --> "401 Authorization Required"
-  #   "FORBIDDEN"           --> "403 Forbidden"
-  #   "NOT_FOUND"           --> "404 Not Found"
-  #   "METHOD_NOT_ALLOWED"  --> "405 Method Not Allowed"
-  #   "NOT_ACCEPTABLE"      --> "406 Not Acceptable"
-  #   "LENGTH_REQUIRED"     --> "411 Length Required"
-  #   "PRECONDITION_FAILED" --> "412 Precondition Failed"
-  #   "SERVER_ERROR"        --> "500 Internal Server Error"
-  #   "NOT_IMPLEMENTED"     --> "501 Method Not Implemented"
-  #   "BAD_GATEWAY"         --> "502 Bad Gateway"
-  #   "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates"
-  # 
-  # This method does not perform charset conversion. 
-  #
-  def header(options = "text/html")
-
-    buf = ""
-
-    case options
-    when String
-      options = { "type" => options }
-    when Hash
-      options = options.dup
-    end
-
-    unless options.has_key?("type")
-      options["type"] = "text/html"
-    end
-
-    if options.has_key?("charset")
-      options["type"] += "; charset=" + options.delete("charset")
-    end
-
-    options.delete("nph") if defined?(MOD_RUBY)
-    if options.delete("nph") or
-        (/IIS\/(\d+)/n.match(env_table['SERVER_SOFTWARE']) and $1.to_i < 5)
-      buf += (env_table["SERVER_PROTOCOL"] or "HTTP/1.0")  + " " +
-             (HTTP_STATUS[options["status"]] or options["status"] or "200 OK") +
-             EOL +
-             "Date: " + CGI::rfc1123_date(Time.now) + EOL
-
-      unless options.has_key?("server")
-        options["server"] = (env_table['SERVER_SOFTWARE'] or "")
-      end
-
-      unless options.has_key?("connection")
-        options["connection"] = "close"
-      end
-
-      options.delete("status")
-    end
-
-    if options.has_key?("status")
-      buf += "Status: " +
-             (HTTP_STATUS[options["status"]] or options["status"]) + EOL
-      options.delete("status")
-    end
-
-    if options.has_key?("server")
-      buf += "Server: " + options.delete("server") + EOL
-    end
-
-    if options.has_key?("connection")
-      buf += "Connection: " + options.delete("connection") + EOL
-    end
-
-    buf += "Content-Type: " + options.delete("type") + EOL
-
-    if options.has_key?("length")
-      buf += "Content-Length: " + options.delete("length").to_s + EOL
-    end
-
-    if options.has_key?("language")
-      buf += "Content-Language: " + options.delete("language") + EOL
-    end
-
-    if options.has_key?("expires")
-      buf += "Expires: " + CGI::rfc1123_date( options.delete("expires") ) + EOL
-    end
-
-    if options.has_key?("cookie")
-      if options["cookie"].kind_of?(String) or
-           options["cookie"].kind_of?(Cookie)
-        buf += "Set-Cookie: " + options.delete("cookie").to_s + EOL
-      elsif options["cookie"].kind_of?(Array)
-        options.delete("cookie").each{|cookie|
-          buf += "Set-Cookie: " + cookie.to_s + EOL
-        }
-      elsif options["cookie"].kind_of?(Hash)
-        options.delete("cookie").each_value{|cookie|
-          buf += "Set-Cookie: " + cookie.to_s + EOL
-        }
-      end
-    end
-    if @output_cookies
-      for cookie in @output_cookies
-        buf += "Set-Cookie: " + cookie.to_s + EOL
-      end
-    end
-
-    options.each{|key, value|
-      buf += key + ": " + value.to_s + EOL
-    }
-
-    if defined?(MOD_RUBY)
-      table = Apache::request.headers_out
-      buf.scan(/([^:]+): (.+)#{EOL}/n){ |name, value|
-        warn sprintf("name:%s value:%s\n", name, value) if $DEBUG
-        case name
-        when 'Set-Cookie'
-          table.add(name, value)
-        when /^status$/ni
-          Apache::request.status_line = value
-          Apache::request.status = value.to_i
-        when /^content-type$/ni
-          Apache::request.content_type = value
-        when /^content-encoding$/ni
-          Apache::request.content_encoding = value
-        when /^location$/ni
-	  if Apache::request.status == 200
-	    Apache::request.status = 302
-	  end
-          Apache::request.headers_out[name] = value
-        else
-          Apache::request.headers_out[name] = value
-        end
-      }
-      Apache::request.send_http_header
-      ''
-    else
-      buf + EOL
-    end
-
-  end # header()
-
-
-  # Print an HTTP header and body to $DEFAULT_OUTPUT ($>)
-  #
-  # The header is provided by +options+, as for #header().
-  # The body of the document is that returned by the passed-
-  # in block.  This block takes no arguments.  It is required.
-  #
-  #   cgi = CGI.new
-  #   cgi.out{ "string" }
-  #     # Content-Type: text/html
-  #     # Content-Length: 6
-  #     #
-  #     # string
-  # 
-  #   cgi.out("text/plain") { "string" }
-  #     # Content-Type: text/plain
-  #     # Content-Length: 6
-  #     #
-  #     # string
-  # 
-  #   cgi.out("nph"        => true,
-  #           "status"     => "OK",  # == "200 OK"
-  #           "server"     => ENV['SERVER_SOFTWARE'],
-  #           "connection" => "close",
-  #           "type"       => "text/html",
-  #           "charset"    => "iso-2022-jp",
-  #             # Content-Type: text/html; charset=iso-2022-jp
-  #           "language"   => "ja",
-  #           "expires"    => Time.now + (3600 * 24 * 30),
-  #           "cookie"     => [cookie1, cookie2],
-  #           "my_header1" => "my_value",
-  #           "my_header2" => "my_value") { "string" }
-  # 
-  # Content-Length is automatically calculated from the size of
-  # the String returned by the content block.
-  #
-  # If ENV['REQUEST_METHOD'] == "HEAD", then only the header
-  # is outputted (the content block is still required, but it
-  # is ignored).
-  # 
-  # If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then
-  # the content is converted to this charset, and the language is set 
-  # to "ja".
-  def out(options = "text/html") # :yield:
-
-    options = { "type" => options } if options.kind_of?(String)
-    content = yield
-
-    if options.has_key?("charset")
-      require "nkf"
-      case options["charset"]
-      when /iso-2022-jp/ni
-        content = NKF::nkf('-j -m0 -x', content)
-        options["language"] = "ja" unless options.has_key?("language")
-      when /euc-jp/ni
-        content = NKF::nkf('-e -m0 -x', content)
-        options["language"] = "ja" unless options.has_key?("language")
-      when /shift_jis/ni
-        content = NKF::nkf('-s -m0 -x', content)
-        options["language"] = "ja" unless options.has_key?("language")
-      end
-    end
-
-    options["length"] = content.length.to_s
-    output = stdoutput
-    output.binmode if defined? output.binmode
-    output.print header(options)
-    output.print content unless "HEAD" == env_table['REQUEST_METHOD']
-  end
-
-
-  # Print an argument or list of arguments to the default output stream
-  #
-  #   cgi = CGI.new
-  #   cgi.print    # default:  cgi.print == $DEFAULT_OUTPUT.print
-  def print(*options)
-    stdoutput.print(*options)
-  end
-
-  require "delegate"
-
-  # Class representing an HTTP cookie.
-  #
-  # In addition to its specific fields and methods, a Cookie instance
-  # is a delegator to the array of its values.
-  #
-  # See RFC 2965.
-  #
-  # == Examples of use
-  #   cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
-  #   cookie1 = CGI::Cookie::new("name" => "name", "value" => "value")
-  #   cookie1 = CGI::Cookie::new('name'    => 'name',
-  #                              'value'   => ['value1', 'value2', ...],
-  #                              'path'    => 'path',   # optional
-  #                              'domain'  => 'domain', # optional
-  #                              'expires' => Time.now, # optional
-  #                              'secure'  => true      # optional
-  #                             )
-  # 
-  #   cgi.out("cookie" => [cookie1, cookie2]) { "string" }
-  # 
-  #   name    = cookie1.name
-  #   values  = cookie1.value
-  #   path    = cookie1.path
-  #   domain  = cookie1.domain
-  #   expires = cookie1.expires
-  #   secure  = cookie1.secure
-  # 
-  #   cookie1.name    = 'name'
-  #   cookie1.value   = ['value1', 'value2', ...]
-  #   cookie1.path    = 'path'
-  #   cookie1.domain  = 'domain'
-  #   cookie1.expires = Time.now + 30
-  #   cookie1.secure  = true
-  class Cookie < DelegateClass(Array)
-
-    # Create a new CGI::Cookie object.
-    #
-    # The contents of the cookie can be specified as a +name+ and one
-    # or more +value+ arguments.  Alternatively, the contents can
-    # be specified as a single hash argument.  The possible keywords of
-    # this hash are as follows:
-    #
-    # name:: the name of the cookie.  Required.
-    # value:: the cookie's value or list of values.
-    # path:: the path for which this cookie applies.  Defaults to the
-    #        base directory of the CGI script.
-    # domain:: the domain for which this cookie applies.
-    # expires:: the time at which this cookie expires, as a +Time+ object.
-    # secure:: whether this cookie is a secure cookie or not (default to
-    #          false).  Secure cookies are only transmitted to HTTPS 
-    #          servers.
-    #
-    # These keywords correspond to attributes of the cookie object.
-    def initialize(name = "", *value)
-      if name.kind_of?(String)
-        @name = name
-        @value = value
-        %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
-        @path = ($1 or "")
-        @secure = false
-        return super(@value)
-      end
-
-      options = name
-      unless options.has_key?("name")
-        raise ArgumentError, "`name' required"
-      end
-
-      @name = options["name"]
-      @value = Array(options["value"])
-      # simple support for IE
-      if options["path"]
-        @path = options["path"]
-      else
-        %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
-        @path = ($1 or "")
-      end
-      @domain = options["domain"]
-      @expires = options["expires"]
-      @secure = options["secure"] == true ? true : false
-
-      super(@value)
-    end
-
-    attr_accessor("name", "value", "path", "domain", "expires")
-    attr_reader("secure")
-
-    # Set whether the Cookie is a secure cookie or not.
-    #
-    # +val+ must be a boolean.
-    def secure=(val)
-      @secure = val if val == true or val == false
-      @secure
-    end
-
-    # Convert the Cookie to its string representation.
-    def to_s
-      buf = ""
-      buf += @name + '='
-
-      if @value.kind_of?(String)
-        buf += CGI::escape(@value)
-      else
-        buf += @value.collect{|v| CGI::escape(v) }.join("&")
-      end
-
-      if @domain
-        buf += '; domain=' + @domain
-      end
-
-      if @path
-        buf += '; path=' + @path
-      end
-
-      if @expires
-        buf += '; expires=' + CGI::rfc1123_date(@expires)
-      end
-
-      if @secure == true
-        buf += '; secure'
-      end
-
-      buf
-    end
-
-  end # class Cookie
-
-
-  # Parse a raw cookie string into a hash of cookie-name=>Cookie
-  # pairs.
-  #
-  #   cookies = CGI::Cookie::parse("raw_cookie_string")
-  #     # { "name1" => cookie1, "name2" => cookie2, ... }
-  #
-  def Cookie::parse(raw_cookie)
-    cookies = Hash.new([])
-    return cookies unless raw_cookie
-
-    raw_cookie.split(/[;,]\s?/).each do |pairs|
-      name, values = pairs.split('=',2)
-      next unless name and values
-      name = CGI::unescape(name)
-      values ||= ""
-      values = values.split('&').collect{|v| CGI::unescape(v) }
-      if cookies.has_key?(name)
-        values = cookies[name].value + values
-      end
-      cookies[name] = Cookie::new(name, *values)
-    end
-
-    cookies
-  end
-
-  # Parse an HTTP query string into a hash of key=>value pairs.
-  #
-  #   params = CGI::parse("query_string")
-  #     # {"name1" => ["value1", "value2", ...],
-  #     #  "name2" => ["value1", "value2", ...], ... }
-  #
-  def CGI::parse(query)
-    params = Hash.new([].freeze)
-
-    query.split(/[&;]/n).each do |pairs|
-      key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) }
-      if params.has_key?(key)
-        params[key].push(value)
-      else
-        params[key] = [value]
-      end
-    end
-
-    params
-  end
-
-  # Mixin module. It provides the follow functionality groups:
-  #
-  # 1. Access to CGI environment variables as methods.  See 
-  #    documentation to the CGI class for a list of these variables.
-  #
-  # 2. Access to cookies, including the cookies attribute.
-  #
-  # 3. Access to parameters, including the params attribute, and overloading
-  #    [] to perform parameter value lookup by key.
-  #
-  # 4. The initialize_query method, for initialising the above
-  #    mechanisms, handling multipart forms, and allowing the
-  #    class to be used in "offline" mode.
-  #
-  module QueryExtension
-
-    %w[ CONTENT_LENGTH SERVER_PORT ].each do |env|
-      define_method(env.sub(/^HTTP_/n, '').downcase) do
-        (val = env_table[env]) && Integer(val)
-      end
-    end
-
-    %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
-        PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
-        REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
-        SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
-
-        HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
-        HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
-        HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
-      define_method(env.sub(/^HTTP_/n, '').downcase) do
-        env_table[env]
-      end
-    end
-
-    # Get the raw cookies as a string.
-    def raw_cookie
-      env_table["HTTP_COOKIE"]
-    end
-
-    # Get the raw RFC2965 cookies as a string.
-    def raw_cookie2
-      env_table["HTTP_COOKIE2"]
-    end
-
-    # Get the cookies as a hash of cookie-name=>Cookie pairs.
-    attr_accessor :cookies
-
-    # Get the parameters as a hash of name=>values pairs, where
-    # values is an Array.
-    attr_reader :params
-
-    # Set all the parameters.
-    def params=(hash)
-      @params.clear
-      @params.update(hash)
-    end
-
-    def read_multipart(boundary, content_length)
-      params = Hash.new([])
-      boundary = "--" + boundary
-      quoted_boundary = Regexp.quote(boundary)
-      buf = ""
-      bufsize = 10 * 1024
-      boundary_end=""
-
-      # start multipart/form-data
-      stdinput.binmode if defined? stdinput.binmode
-      boundary_size = boundary.size + EOL.size
-      content_length -= boundary_size
-      status = stdinput.read(boundary_size)
-      if nil == status
-        raise EOFError, "no content body"
-      elsif boundary + EOL != status
-        raise EOFError, "bad content body"
-      end
-
-      loop do
-        head = nil
-        body = MorphingBody.new
-
-        until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf)
-          if (not head) and /#{EOL}#{EOL}/n.match(buf)
-            buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
-              head = $1.dup
-              ""
-            end
-            next
-          end
-
-          if head and ( (EOL + boundary + EOL).size < buf.size )
-            body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
-            buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
-          end
-
-          c = if bufsize < content_length
-                stdinput.read(bufsize)
-              else
-                stdinput.read(content_length)
-              end
-          if c.nil? || c.empty?
-            raise EOFError, "bad content body"
-          end
-          buf.concat(c)
-          content_length -= c.size
-        end
-
-        buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
-          body.print $1
-          if "--" == $2
-            content_length = -1
-          end
-          boundary_end = $2.dup
-          ""
-        end
-
-        body.rewind
-
-        /Content-Disposition:.* filename=(?:"((?:\\.|[^\"\s])*)"|([^;\s]*))/ni.match(head)
-	filename = ($1 or $2 or "")
-	if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
-	    /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
-	    (not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
-	  filename = CGI::unescape(filename)
-	end
-        
-        /Content-Type: ([^\s]*)/ni.match(head)
-        content_type = ($1 or "")
-
-        (class << body; self; end).class_eval do
-          alias local_path path
-          define_method(:original_filename) {filename.dup.taint}
-          define_method(:content_type) {content_type.dup.taint}
-        end
-
-        /Content-Disposition:.* name="?([^\";\s]*)"?/ni.match(head)
-        name = ($1 || "").dup
-
-        if params.has_key?(name)
-          params[name].push(body)
-        else
-          params[name] = [body]
-        end
-        break if buf.size == 0
-        break if content_length == -1
-      end
-      raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
-
-      params
-    end # read_multipart
-    private :read_multipart
-
-    # offline mode. read name=value pairs on standard input.
-    def read_from_cmdline
-      require "shellwords"
-
-      string = unless ARGV.empty?
-        ARGV.join(' ')
-      else
-        if STDIN.tty?
-          STDERR.print(
-            %|(offline mode: enter name=value pairs on standard input)\n|
-          )
-        end
-        readlines.join(' ').gsub(/\n/n, '')
-      end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26')
-
-      words = Shellwords.shellwords(string)
-
-      if words.find{|x| /=/n.match(x) }
-        words.join('&')
-      else
-        words.join('+')
-      end
-    end
-    private :read_from_cmdline
-
-    # A wrapper class to use a StringIO object as the body and switch
-    # to a TempFile when the passed threshold is passed.
-    class MorphingBody
-      begin
-        require "stringio"
-        @@small_buffer = lambda{StringIO.new}
-      rescue LoadError
-        require "tempfile"
-        @@small_buffer = lambda{
-          n = Tempfile.new("CGI")
-          n.binmode
-          n
-        }
-      end
-
-      def initialize(morph_threshold = 10240)
-        @threshold = morph_threshold
-        @body = @@small_buffer.call
-        @cur_size = 0
-        @morph_check = true
-      end
-
-      def print(data)
-        if @morph_check && (@cur_size + data.size > @threshold)
-          convert_body
-        end
-        @body.print data
-      end
-      def rewind
-        @body.rewind
-      end
-      def path
-        @body.path
-      end
-
-      # returns the true body object.
-      def extract
-        @body
-      end
-
-      private
-      def convert_body
-        new_body = TempFile.new("CGI")
-        new_body.binmode if defined? @body.binmode
-        new_body.binmode if defined? new_body.binmode
-
-        @body.rewind
-        new_body.print @body.read
-        @body = new_body
-        @morph_check = false
-      end
-    end
-
-    # Initialize the data from the query.
-    #
-    # Handles multipart forms (in particular, forms that involve file uploads).
-    # Reads query parameters in the @params field, and cookies into @cookies.
-    def initialize_query()
-      if ("POST" == env_table['REQUEST_METHOD']) and
-         %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE'])
-        boundary = $1.dup
-        @multipart = true
-        @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
-      else
-        @multipart = false
-        @params = CGI::parse(
-                    case env_table['REQUEST_METHOD']
-                    when "GET", "HEAD"
-                      if defined?(MOD_RUBY)
-                        Apache::request.args or ""
-                      else
-                        env_table['QUERY_STRING'] or ""
-                      end
-                    when "POST"
-                      stdinput.binmode if defined? stdinput.binmode
-                      stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
-                    else
-                      read_from_cmdline
-                    end
-                  )
-      end
-
-      @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
-    end
-    private :initialize_query
-
-    def multipart?
-      @multipart
-    end
-
-    # Get the value for the parameter with a given key.
-    #
-    # If the parameter has multiple values, only the first will be 
-    # retrieved; use #params() to get the array of values.
-    def [](key)
-      params = @params[key]
-      return '' unless params
-      value = params[0]
-      if @multipart
-        if value
-          return value
-        elsif defined? StringIO
-          StringIO.new("")
-        else
-          Tempfile.new("CGI")
-        end
-      else
-        str = if value then value.dup else "" end
-        str
-      end
-    end
-
-    # Return all parameter keys as an array.
-    def keys(*args)
-      @params.keys(*args)
-    end
-
-    # Returns true if a given parameter key exists in the query.
-    def has_key?(*args)
-      @params.has_key?(*args)
-    end
-    alias key? has_key?
-    alias include? has_key?
-
-  end # QueryExtension
-
-
-  # Prettify (indent) an HTML string.
-  #
-  # +string+ is the HTML string to indent.  +shift+ is the indentation
-  # unit to use; it defaults to two spaces.
-  #
-  #   print CGI::pretty("<HTML><BODY></BODY></HTML>")
-  #     # <HTML>
-  #     #   <BODY>
-  #     #   </BODY>
-  #     # </HTML>
-  # 
-  #   print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
-  #     # <HTML>
-  #     #         <BODY>
-  #     #         </BODY>
-  #     # </HTML>
-  #
-  def CGI::pretty(string, shift = "  ")
-    lines = string.gsub(/(?!\A)<(?:.|\n)*?>/n, "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/n, "\\0\n")
-    end_pos = 0
-    while end_pos = lines.index(/^<\/(\w+)/n, end_pos)
-      element = $1.dup
-      start_pos = lines.rindex(/^\s*<#{element}/ni, end_pos)
-      lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/n, "\n" + shift) + "__"
-    end
-    lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/n, '\1')
-  end
-
-
-  # Base module for HTML-generation mixins.
-  #
-  # Provides methods for code generation for tags following
-  # the various DTD element types.
-  module TagMaker # :nodoc:
-
-    # Generate code for an element with required start and end tags.
-    #
-    #   - -
-    def nn_element_def(element)
-      nOE_element_def(element, <<-END)
-          if block_given?
-            yield.to_s
-          else
-            ""
-          end +
-          "</#{element.upcase}>"
-      END
-    end
-
-    # Generate code for an empty element.
-    #
-    #   - O EMPTY
-    def nOE_element_def(element, append = nil)
-      s = <<-END
-          "<#{element.upcase}" + attributes.collect{|name, value|
-            next unless value
-            " " + CGI::escapeHTML(name) +
-            if true == value
-              ""
-            else
-              '="' + CGI::escapeHTML(value) + '"'
-            end
-          }.join + ">"
-      END
-      s.sub!(/\Z/, " +") << append if append
-      s
-    end
-
-    # Generate code for an element for which the end (and possibly the
-    # start) tag is optional.
-    #
-    #   O O or - O
-    def nO_element_def(element)
-      nOE_element_def(element, <<-END)
-          if block_given?
-            yield.to_s + "</#{element.upcase}>"
-          else
-            ""
-          end
-      END
-    end
-
-  end # TagMaker
-
-
-  #
-  # Mixin module providing HTML generation methods.
-  #
-  # For example,
-  #   cgi.a("http://www.example.com") { "Example" }
-  #     # => "<A HREF=\"http://www.example.com\">Example</A>"
-  #
-  # Modules Http3, Http4, etc., contain more basic HTML-generation methods
-  # (:title, :center, etc.).
-  #
-  # See class CGI for a detailed example. 
-  #
-  module HtmlExtension
-
-
-    # Generate an Anchor element as a string.
-    #
-    # +href+ can either be a string, giving the URL
-    # for the HREF attribute, or it can be a hash of
-    # the element's attributes.
-    #
-    # The body of the element is the string returned by the no-argument
-    # block passed in.
-    #
-    #   a("http://www.example.com") { "Example" }
-    #     # => "<A HREF=\"http://www.example.com\">Example</A>"
-    #
-    #   a("HREF" => "http://www.example.com", "TARGET" => "_top") { "Example" }
-    #     # => "<A HREF=\"http://www.example.com\" TARGET=\"_top\">Example</A>"
-    #
-    def a(href = "") # :yield:
-      attributes = if href.kind_of?(String)
-                     { "HREF" => href }
-                   else
-                     href
-                   end
-      if block_given?
-        super(attributes){ yield }
-      else
-        super(attributes)
-      end
-    end
-
-    # Generate a Document Base URI element as a String. 
-    #
-    # +href+ can either by a string, giving the base URL for the HREF
-    # attribute, or it can be a has of the element's attributes.
-    #
-    # The passed-in no-argument block is ignored.
-    #
-    #   base("http://www.example.com/cgi")
-    #     # => "<BASE HREF=\"http://www.example.com/cgi\">"
-    def base(href = "") # :yield:
-      attributes = if href.kind_of?(String)
-                     { "HREF" => href }
-                   else
-                     href
-                   end
-      if block_given?
-        super(attributes){ yield }
-      else
-        super(attributes)
-      end
-    end
-
-    # Generate a BlockQuote element as a string.
-    #
-    # +cite+ can either be a string, give the URI for the source of
-    # the quoted text, or a hash, giving all attributes of the element,
-    # or it can be omitted, in which case the element has no attributes.
-    #
-    # The body is provided by the passed-in no-argument block
-    #
-    #   blockquote("http://www.example.com/quotes/foo.html") { "Foo!" }
-    #     #=> "<BLOCKQUOTE CITE=\"http://www.example.com/quotes/foo.html\">Foo!</BLOCKQUOTE>
-    def blockquote(cite = nil)  # :yield:
-      attributes = if cite.kind_of?(String)
-                     { "CITE" => cite }
-                   else
-                     cite or ""
-                   end
-      if block_given?
-        super(attributes){ yield }
-      else
-        super(attributes)
-      end
-    end
-
-
-    # Generate a Table Caption element as a string.
-    #
-    # +align+ can be a string, giving the alignment of the caption
-    # (one of top, bottom, left, or right).  It can be a hash of
-    # all the attributes of the element.  Or it can be omitted.
-    #
-    # The body of the element is provided by the passed-in no-argument block.
-    #
-    #   caption("left") { "Capital Cities" }
-    #     # => <CAPTION ALIGN=\"left\">Capital Cities</CAPTION>
-    def caption(align = nil) # :yield:
-      attributes = if align.kind_of?(String)
-                     { "ALIGN" => align }
-                   else
-                     align or ""
-                   end
-      if block_given?
-        super(attributes){ yield }
-      else
-        super(attributes)
-      end
-    end
-
-
-    # Generate a Checkbox Input element as a string.
-    #
-    # The attributes of the element can be specified as three arguments,
-    # +name+, +value+, and +checked+.  +checked+ is a boolean value;
-    # if true, the CHECKED attribute will be included in the element.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   checkbox("name")
-    #     # = checkbox("NAME" => "name")
-    # 
-    #   checkbox("name", "value")
-    #     # = checkbox("NAME" => "name", "VALUE" => "value")
-    # 
-    #   checkbox("name", "value", true)
-    #     # = checkbox("NAME" => "name", "VALUE" => "value", "CHECKED" => true)
-    def checkbox(name = "", value = nil, checked = nil)
-      attributes = if name.kind_of?(String)
-                     { "TYPE" => "checkbox", "NAME" => name,
-                       "VALUE" => value, "CHECKED" => checked }
-                   else
-                     name["TYPE"] = "checkbox"
-                     name
-                   end
-      input(attributes)
-    end
-
-    # Generate a sequence of checkbox elements, as a String.
-    #
-    # The checkboxes will all have the same +name+ attribute.
-    # Each checkbox is followed by a label.
-    # There will be one checkbox for each value.  Each value
-    # can be specified as a String, which will be used both
-    # as the value of the VALUE attribute and as the label
-    # for that checkbox.  A single-element array has the
-    # same effect.
-    #
-    # Each value can also be specified as a three-element array.
-    # The first element is the VALUE attribute; the second is the
-    # label; and the third is a boolean specifying whether this
-    # checkbox is CHECKED.
-    #
-    # Each value can also be specified as a two-element
-    # array, by omitting either the value element (defaults
-    # to the same as the label), or the boolean checked element
-    # (defaults to false).
-    #
-    #   checkbox_group("name", "foo", "bar", "baz")
-    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
-    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
-    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
-    # 
-    #   checkbox_group("name", ["foo"], ["bar", true], "baz")
-    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
-    #     # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="bar">bar
-    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
-    # 
-    #   checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
-    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
-    #     # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="2">Bar
-    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
-    # 
-    #   checkbox_group("NAME" => "name",
-    #                    "VALUES" => ["foo", "bar", "baz"])
-    # 
-    #   checkbox_group("NAME" => "name",
-    #                    "VALUES" => [["foo"], ["bar", true], "baz"])
-    # 
-    #   checkbox_group("NAME" => "name",
-    #                    "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
-    def checkbox_group(name = "", *values)
-      if name.kind_of?(Hash)
-        values = name["VALUES"]
-        name = name["NAME"]
-      end
-      values.collect{|value|
-        if value.kind_of?(String)
-          checkbox(name, value) + value
-        else
-          if value[value.size - 1] == true
-            checkbox(name, value[0], true) +
-            value[value.size - 2]
-          else
-            checkbox(name, value[0]) +
-            value[value.size - 1]
-          end
-        end
-      }.join
-    end
-
-
-    # Generate an File Upload Input element as a string.
-    #
-    # The attributes of the element can be specified as three arguments,
-    # +name+, +size+, and +maxlength+.  +maxlength+ is the maximum length
-    # of the file's _name_, not of the file's _contents_.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    # See #multipart_form() for forms that include file uploads.
-    #
-    #   file_field("name")
-    #     # <INPUT TYPE="file" NAME="name" SIZE="20">
-    # 
-    #   file_field("name", 40)
-    #     # <INPUT TYPE="file" NAME="name" SIZE="40">
-    # 
-    #   file_field("name", 40, 100)
-    #     # <INPUT TYPE="file" NAME="name" SIZE="40" MAXLENGTH="100">
-    # 
-    #   file_field("NAME" => "name", "SIZE" => 40)
-    #     # <INPUT TYPE="file" NAME="name" SIZE="40">
-    def file_field(name = "", size = 20, maxlength = nil)
-      attributes = if name.kind_of?(String)
-                     { "TYPE" => "file", "NAME" => name,
-                       "SIZE" => size.to_s }
-                   else
-                     name["TYPE"] = "file"
-                     name
-                   end
-      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
-      input(attributes)
-    end
-
-
-    # Generate a Form element as a string.
-    #
-    # +method+ should be either "get" or "post", and defaults to the latter.
-    # +action+ defaults to the current CGI script name.  +enctype+
-    # defaults to "application/x-www-form-urlencoded".  
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    # See also #multipart_form() for forms that include file uploads.
-    #
-    #   form{ "string" }
-    #     # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
-    # 
-    #   form("get") { "string" }
-    #     # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
-    # 
-    #   form("get", "url") { "string" }
-    #     # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
-    # 
-    #   form("METHOD" => "post", "ENCTYPE" => "enctype") { "string" }
-    #     # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
-    def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded")
-      attributes = if method.kind_of?(String)
-                     { "METHOD" => method, "ACTION" => action,
-                       "ENCTYPE" => enctype } 
-                   else
-                     unless method.has_key?("METHOD")
-                       method["METHOD"] = "post"
-                     end
-                     unless method.has_key?("ENCTYPE")
-                       method["ENCTYPE"] = enctype
-                     end
-                     method
-                   end
-      if block_given?
-        body = yield
-      else
-        body = ""
-      end
-      if @output_hidden
-        body += @output_hidden.collect{|k,v|
-          "<INPUT TYPE=\"HIDDEN\" NAME=\"#{k}\" VALUE=\"#{v}\">"
-        }.join
-      end
-      super(attributes){body}
-    end
-
-    # Generate a Hidden Input element as a string.
-    #
-    # The attributes of the element can be specified as two arguments,
-    # +name+ and +value+.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   hidden("name")
-    #     # <INPUT TYPE="hidden" NAME="name">
-    # 
-    #   hidden("name", "value")
-    #     # <INPUT TYPE="hidden" NAME="name" VALUE="value">
-    # 
-    #   hidden("NAME" => "name", "VALUE" => "reset", "ID" => "foo")
-    #     # <INPUT TYPE="hidden" NAME="name" VALUE="value" ID="foo">
-    def hidden(name = "", value = nil)
-      attributes = if name.kind_of?(String)
-                     { "TYPE" => "hidden", "NAME" => name, "VALUE" => value }
-                   else
-                     name["TYPE"] = "hidden"
-                     name
-                   end
-      input(attributes)
-    end
-
-    # Generate a top-level HTML element as a string.
-    #
-    # The attributes of the element are specified as a hash.  The
-    # pseudo-attribute "PRETTY" can be used to specify that the generated
-    # HTML string should be indented.  "PRETTY" can also be specified as
-    # a string as the sole argument to this method.  The pseudo-attribute
-    # "DOCTYPE", if given, is used as the leading DOCTYPE SGML tag; it
-    # should include the entire text of this tag, including angle brackets.
-    #
-    # The body of the html element is supplied as a block.
-    # 
-    #   html{ "string" }
-    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>string</HTML>
-    # 
-    #   html("LANG" => "ja") { "string" }
-    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML LANG="ja">string</HTML>
-    # 
-    #   html("DOCTYPE" => false) { "string" }
-    #     # <HTML>string</HTML>
-    # 
-    #   html("DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">') { "string" }
-    #     # <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML>string</HTML>
-    # 
-    #   html("PRETTY" => "  ") { "<BODY></BODY>" }
-    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-    #     # <HTML>
-    #     #   <BODY>
-    #     #   </BODY>
-    #     # </HTML>
-    # 
-    #   html("PRETTY" => "\t") { "<BODY></BODY>" }
-    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-    #     # <HTML>
-    #     #         <BODY>
-    #     #         </BODY>
-    #     # </HTML>
-    # 
-    #   html("PRETTY") { "<BODY></BODY>" }
-    #     # = html("PRETTY" => "  ") { "<BODY></BODY>" }
-    # 
-    #   html(if $VERBOSE then "PRETTY" end) { "HTML string" }
-    #
-    def html(attributes = {}) # :yield:
-      if nil == attributes
-        attributes = {}
-      elsif "PRETTY" == attributes
-        attributes = { "PRETTY" => true }
-      end
-      pretty = attributes.delete("PRETTY")
-      pretty = "  " if true == pretty
-      buf = ""
-
-      if attributes.has_key?("DOCTYPE")
-        if attributes["DOCTYPE"]
-          buf += attributes.delete("DOCTYPE")
-        else
-          attributes.delete("DOCTYPE")
-        end
-      else
-        buf += doctype
-      end
-
-      if block_given?
-        buf += super(attributes){ yield }
-      else
-        buf += super(attributes)
-      end
-
-      if pretty
-        CGI::pretty(buf, pretty)
-      else
-        buf
-      end
-
-    end
-
-    # Generate an Image Button Input element as a string.
-    #
-    # +src+ is the URL of the image to use for the button.  +name+ 
-    # is the input name.  +alt+ is the alternative text for the image.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    # 
-    #   image_button("url")
-    #     # <INPUT TYPE="image" SRC="url">
-    # 
-    #   image_button("url", "name", "string")
-    #     # <INPUT TYPE="image" SRC="url" NAME="name" ALT="string">
-    # 
-    #   image_button("SRC" => "url", "ATL" => "strng")
-    #     # <INPUT TYPE="image" SRC="url" ALT="string">
-    def image_button(src = "", name = nil, alt = nil)
-      attributes = if src.kind_of?(String)
-                     { "TYPE" => "image", "SRC" => src, "NAME" => name,
-                       "ALT" => alt }
-                   else
-                     src["TYPE"] = "image"
-                     src["SRC"] ||= ""
-                     src
-                   end
-      input(attributes)
-    end
-
-
-    # Generate an Image element as a string.
-    #
-    # +src+ is the URL of the image.  +alt+ is the alternative text for
-    # the image.  +width+ is the width of the image, and +height+ is
-    # its height.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   img("src", "alt", 100, 50)
-    #     # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
-    # 
-    #   img("SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50)
-    #     # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
-    def img(src = "", alt = "", width = nil, height = nil)
-      attributes = if src.kind_of?(String)
-                     { "SRC" => src, "ALT" => alt }
-                   else
-                     src
-                   end
-      attributes["WIDTH"] = width.to_s if width
-      attributes["HEIGHT"] = height.to_s if height
-      super(attributes)
-    end
-
-
-    # Generate a Form element with multipart encoding as a String.
-    #
-    # Multipart encoding is used for forms that include file uploads.
-    #
-    # +action+ is the action to perform.  +enctype+ is the encoding
-    # type, which defaults to "multipart/form-data".
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   multipart_form{ "string" }
-    #     # <FORM METHOD="post" ENCTYPE="multipart/form-data">string</FORM>
-    # 
-    #   multipart_form("url") { "string" }
-    #     # <FORM METHOD="post" ACTION="url" ENCTYPE="multipart/form-data">string</FORM>
-    def multipart_form(action = nil, enctype = "multipart/form-data")
-      attributes = if action == nil
-                     { "METHOD" => "post", "ENCTYPE" => enctype } 
-                   elsif action.kind_of?(String)
-                     { "METHOD" => "post", "ACTION" => action,
-                       "ENCTYPE" => enctype } 
-                   else
-                     unless action.has_key?("METHOD")
-                       action["METHOD"] = "post"
-                     end
-                     unless action.has_key?("ENCTYPE")
-                       action["ENCTYPE"] = enctype
-                     end
-                     action
-                   end
-      if block_given?
-        form(attributes){ yield }
-      else
-        form(attributes)
-      end
-    end
-
-
-    # Generate a Password Input element as a string.
-    #
-    # +name+ is the name of the input field.  +value+ is its default
-    # value.  +size+ is the size of the input field display.  +maxlength+
-    # is the maximum length of the inputted password.
-    #
-    # Alternatively, attributes can be specified as a hash.
-    #
-    #   password_field("name")
-    #     # <INPUT TYPE="password" NAME="name" SIZE="40">
-    # 
-    #   password_field("name", "value")
-    #     # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="40">
-    # 
-    #   password_field("password", "value", 80, 200)
-    #     # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
-    # 
-    #   password_field("NAME" => "name", "VALUE" => "value")
-    #     # <INPUT TYPE="password" NAME="name" VALUE="value">
-    def password_field(name = "", value = nil, size = 40, maxlength = nil)
-      attributes = if name.kind_of?(String)
-                     { "TYPE" => "password", "NAME" => name,
-                       "VALUE" => value, "SIZE" => size.to_s }
-                   else
-                     name["TYPE"] = "password"
-                     name
-                   end
-      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
-      input(attributes)
-    end
-
-    # Generate a Select element as a string.
-    #
-    # +name+ is the name of the element.  The +values+ are the options that
-    # can be selected from the Select menu.  Each value can be a String or
-    # a one, two, or three-element Array.  If a String or a one-element
-    # Array, this is both the value of that option and the text displayed for
-    # it.  If a three-element Array, the elements are the option value, displayed
-    # text, and a boolean value specifying whether this option starts as selected.
-    # The two-element version omits either the option value (defaults to the same
-    # as the display text) or the boolean selected specifier (defaults to false).
-    #
-    # The attributes and options can also be specified as a hash.  In this
-    # case, options are specified as an array of values as described above,
-    # with the hash key of "VALUES".
-    #
-    #   popup_menu("name", "foo", "bar", "baz")
-    #     # <SELECT NAME="name">
-    #     #   <OPTION VALUE="foo">foo</OPTION>
-    #     #   <OPTION VALUE="bar">bar</OPTION>
-    #     #   <OPTION VALUE="baz">baz</OPTION>
-    #     # </SELECT>
-    # 
-    #   popup_menu("name", ["foo"], ["bar", true], "baz")
-    #     # <SELECT NAME="name">
-    #     #   <OPTION VALUE="foo">foo</OPTION>
-    #     #   <OPTION VALUE="bar" SELECTED>bar</OPTION>
-    #     #   <OPTION VALUE="baz">baz</OPTION>
-    #     # </SELECT>
-    # 
-    #   popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
-    #     # <SELECT NAME="name">
-    #     #   <OPTION VALUE="1">Foo</OPTION>
-    #     #   <OPTION SELECTED VALUE="2">Bar</OPTION>
-    #     #   <OPTION VALUE="Baz">Baz</OPTION>
-    #     # </SELECT>
-    # 
-    #   popup_menu("NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
-    #               "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
-    #     # <SELECT NAME="name" MULTIPLE SIZE="2">
-    #     #   <OPTION VALUE="1">Foo</OPTION>
-    #     #   <OPTION SELECTED VALUE="2">Bar</OPTION>
-    #     #   <OPTION VALUE="Baz">Baz</OPTION>
-    #     # </SELECT>
-    def popup_menu(name = "", *values)
-
-      if name.kind_of?(Hash)
-        values   = name["VALUES"]
-        size     = name["SIZE"].to_s if name["SIZE"]
-        multiple = name["MULTIPLE"]
-        name     = name["NAME"]
-      else
-        size = nil
-        multiple = nil
-      end
-
-      select({ "NAME" => name, "SIZE" => size,
-               "MULTIPLE" => multiple }){
-        values.collect{|value|
-          if value.kind_of?(String)
-            option({ "VALUE" => value }){ value }
-          else
-            if value[value.size - 1] == true
-              option({ "VALUE" => value[0], "SELECTED" => true }){
-                value[value.size - 2]
-              }
-            else
-              option({ "VALUE" => value[0] }){
-                value[value.size - 1]
-              }
-            end
-          end
-        }.join
-      }
-
-    end
-
-    # Generates a radio-button Input element.
-    #
-    # +name+ is the name of the input field.  +value+ is the value of
-    # the field if checked.  +checked+ specifies whether the field
-    # starts off checked.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   radio_button("name", "value")
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="value">
-    # 
-    #   radio_button("name", "value", true)
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="value" CHECKED>
-    # 
-    #   radio_button("NAME" => "name", "VALUE" => "value", "ID" => "foo")
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="value" ID="foo">
-    def radio_button(name = "", value = nil, checked = nil)
-      attributes = if name.kind_of?(String)
-                     { "TYPE" => "radio", "NAME" => name,
-                       "VALUE" => value, "CHECKED" => checked }
-                   else
-                     name["TYPE"] = "radio"
-                     name
-                   end
-      input(attributes)
-    end
-
-    # Generate a sequence of radio button Input elements, as a String.
-    #
-    # This works the same as #checkbox_group().  However, it is not valid
-    # to have more than one radiobutton in a group checked.
-    # 
-    #   radio_group("name", "foo", "bar", "baz")
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="bar">bar
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
-    # 
-    #   radio_group("name", ["foo"], ["bar", true], "baz")
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
-    #     # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="bar">bar
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
-    # 
-    #   radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="1">Foo
-    #     # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="2">Bar
-    #     # <INPUT TYPE="radio" NAME="name" VALUE="Baz">Baz
-    # 
-    #   radio_group("NAME" => "name",
-    #                 "VALUES" => ["foo", "bar", "baz"])
-    # 
-    #   radio_group("NAME" => "name",
-    #                 "VALUES" => [["foo"], ["bar", true], "baz"])
-    # 
-    #   radio_group("NAME" => "name",
-    #                 "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
-    def radio_group(name = "", *values)
-      if name.kind_of?(Hash)
-        values = name["VALUES"]
-        name = name["NAME"]
-      end
-      values.collect{|value|
-        if value.kind_of?(String)
-          radio_button(name, value) + value
-        else
-          if value[value.size - 1] == true
-            radio_button(name, value[0], true) +
-            value[value.size - 2]
-          else
-            radio_button(name, value[0]) +
-            value[value.size - 1]
-          end
-        end
-      }.join
-    end
-
-    # Generate a reset button Input element, as a String.
-    #
-    # This resets the values on a form to their initial values.  +value+
-    # is the text displayed on the button. +name+ is the name of this button.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   reset
-    #     # <INPUT TYPE="reset">
-    # 
-    #   reset("reset")
-    #     # <INPUT TYPE="reset" VALUE="reset">
-    # 
-    #   reset("VALUE" => "reset", "ID" => "foo")
-    #     # <INPUT TYPE="reset" VALUE="reset" ID="foo">
-    def reset(value = nil, name = nil)
-      attributes = if (not value) or value.kind_of?(String)
-                     { "TYPE" => "reset", "VALUE" => value, "NAME" => name }
-                   else
-                     value["TYPE"] = "reset"
-                     value
-                   end
-      input(attributes)
-    end
-
-    alias scrolling_list popup_menu
-
-    # Generate a submit button Input element, as a String.
-    #
-    # +value+ is the text to display on the button.  +name+ is the name
-    # of the input.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   submit
-    #     # <INPUT TYPE="submit">
-    # 
-    #   submit("ok")
-    #     # <INPUT TYPE="submit" VALUE="ok">
-    # 
-    #   submit("ok", "button1")
-    #     # <INPUT TYPE="submit" VALUE="ok" NAME="button1">
-    # 
-    #   submit("VALUE" => "ok", "NAME" => "button1", "ID" => "foo")
-    #     # <INPUT TYPE="submit" VALUE="ok" NAME="button1" ID="foo">
-    def submit(value = nil, name = nil)
-      attributes = if (not value) or value.kind_of?(String)
-                     { "TYPE" => "submit", "VALUE" => value, "NAME" => name }
-                   else
-                     value["TYPE"] = "submit"
-                     value
-                   end
-      input(attributes)
-    end
-
-    # Generate a text field Input element, as a String.
-    #
-    # +name+ is the name of the input field.  +value+ is its initial
-    # value.  +size+ is the size of the input area.  +maxlength+
-    # is the maximum length of input accepted.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    #   text_field("name")
-    #     # <INPUT TYPE="text" NAME="name" SIZE="40">
-    # 
-    #   text_field("name", "value")
-    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="40">
-    # 
-    #   text_field("name", "value", 80)
-    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80">
-    # 
-    #   text_field("name", "value", 80, 200)
-    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
-    # 
-    #   text_field("NAME" => "name", "VALUE" => "value")
-    #     # <INPUT TYPE="text" NAME="name" VALUE="value">
-    def text_field(name = "", value = nil, size = 40, maxlength = nil)
-      attributes = if name.kind_of?(String)
-                     { "TYPE" => "text", "NAME" => name, "VALUE" => value,
-                       "SIZE" => size.to_s }
-                   else
-                     name["TYPE"] = "text"
-                     name
-                   end
-      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
-      input(attributes)
-    end
-
-    # Generate a TextArea element, as a String.
-    #
-    # +name+ is the name of the textarea.  +cols+ is the number of
-    # columns and +rows+ is the number of rows in the display.
-    #
-    # Alternatively, the attributes can be specified as a hash.
-    #
-    # The body is provided by the passed-in no-argument block
-    #
-    #   textarea("name")
-    #      # = textarea("NAME" => "name", "COLS" => 70, "ROWS" => 10)
-    #
-    #   textarea("name", 40, 5)
-    #      # = textarea("NAME" => "name", "COLS" => 40, "ROWS" => 5)
-    def textarea(name = "", cols = 70, rows = 10)  # :yield:
-      attributes = if name.kind_of?(String)
-                     { "NAME" => name, "COLS" => cols.to_s,
-                       "ROWS" => rows.to_s }
-                   else
-                     name
-                   end
-      if block_given?
-        super(attributes){ yield }
-      else
-        super(attributes)
-      end
-    end
-
-  end # HtmlExtension
-
-
-  # Mixin module for HTML version 3 generation methods.
-  module Html3 # :nodoc:
-
-    # The DOCTYPE declaration for this version of HTML
-    def doctype
-      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">|
-    end
-
-    # Initialise the HTML generation methods for this version.
-    def element_init
-      extend TagMaker
-      methods = ""
-      # - -
-      for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
-          DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP
-          APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE
-          STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
-          CAPTION ]
-        methods += <<-BEGIN + nn_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-
-      # - O EMPTY
-      for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
-          ISINDEX META ]
-        methods += <<-BEGIN + nOE_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-
-      # O O or - O
-      for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION tr
-          th td ]
-        methods += <<-BEGIN + nO_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-      eval(methods)
-    end
-
-  end # Html3
-
-
-  # Mixin module for HTML version 4 generation methods.
-  module Html4 # :nodoc:
-
-    # The DOCTYPE declaration for this version of HTML
-    def doctype
-      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">|
-    end
-
-    # Initialise the HTML generation methods for this version.
-    def element_init
-      extend TagMaker
-      methods = ""
-      # - -
-      for element in %w[ TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD
-        VAR CITE ABBR ACRONYM SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT
-        H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT OPTGROUP
-        FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT
-        TEXTAREA FORM A BLOCKQUOTE CAPTION ]
-        methods += <<-BEGIN + nn_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-
-      # - O EMPTY
-      for element in %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META ]
-        methods += <<-BEGIN + nOE_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-
-      # O O or - O
-      for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
-          COLGROUP TR TH TD HEAD]
-        methods += <<-BEGIN + nO_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-      eval(methods)
-    end
-
-  end # Html4
-
-
-  # Mixin module for HTML version 4 transitional generation methods.
-  module Html4Tr # :nodoc:
-
-    # The DOCTYPE declaration for this version of HTML
-    def doctype
-      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">|
-    end
-
-    # Initialise the HTML generation methods for this version.
-    def element_init
-      extend TagMaker
-      methods = ""
-      # - -
-      for element in %w[ TT I B U S STRIKE BIG SMALL EM STRONG DFN
-          CODE SAMP KBD VAR CITE ABBR ACRONYM FONT SUB SUP SPAN BDO
-          ADDRESS DIV CENTER MAP OBJECT APPLET H1 H2 H3 H4 H5 H6 PRE Q
-          INS DEL DL OL UL DIR MENU LABEL SELECT OPTGROUP FIELDSET
-          LEGEND BUTTON TABLE IFRAME NOFRAMES TITLE STYLE SCRIPT
-          NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ]
-        methods += <<-BEGIN + nn_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-
-      # - O EMPTY
-      for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
-          COL ISINDEX META ]
-        methods += <<-BEGIN + nOE_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-
-      # O O or - O
-      for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
-          COLGROUP TR TH TD HEAD ]
-        methods += <<-BEGIN + nO_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-      eval(methods)
-    end
-
-  end # Html4Tr
-
-
-  # Mixin module for generating HTML version 4 with framesets.
-  module Html4Fr # :nodoc:
-
-    # The DOCTYPE declaration for this version of HTML
-    def doctype
-      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">|
-    end
-
-    # Initialise the HTML generation methods for this version.
-    def element_init
-      methods = ""
-      # - -
-      for element in %w[ FRAMESET ]
-        methods += <<-BEGIN + nn_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-
-      # - O EMPTY
-      for element in %w[ FRAME ]
-        methods += <<-BEGIN + nOE_element_def(element) + <<-END
-          def #{element.downcase}(attributes = {})
-        BEGIN
-          end
-        END
-      end
-      eval(methods)
-    end
-
-  end # Html4Fr
-
-
-  # Creates a new CGI instance.
-  #
-  # +type+ specifies which version of HTML to load the HTML generation
-  # methods for.  The following versions of HTML are supported:
-  #
-  # html3:: HTML 3.x
-  # html4:: HTML 4.0
-  # html4Tr:: HTML 4.0 Transitional
-  # html4Fr:: HTML 4.0 with Framesets
-  #
-  # If not specified, no HTML generation methods will be loaded.
-  #
-  # If the CGI object is not created in a standard CGI call environment
-  # (that is, it can't locate REQUEST_METHOD in its environment), then
-  # it will run in "offline" mode.  In this mode, it reads its parameters
-  # from the command line or (failing that) from standard input.  Otherwise,
-  # cookies and other parameters are parsed automatically from the standard
-  # CGI locations, which varies according to the REQUEST_METHOD.
-  def initialize(type = "query")
-    if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
-      Apache.request.setup_cgi_env
-    end
-
-      (class << self; self; end).class_eval do
-        const_set(:CGI_PARAMS,  [1])
-        const_set(:CGI_COOKIES, [2])
-      end
-
-    extend QueryExtension
-    @multipart = false
-
-    initialize_query()  # set @params, @cookies
-    @output_cookies = nil
-    @output_hidden = nil
-
-    case type
-    when "html3"
-      extend Html3
-      element_init()
-      extend HtmlExtension
-    when "html4"
-      extend Html4
-      element_init()
-      extend HtmlExtension
-    when "html4Tr"
-      extend Html4Tr
-      element_init()
-      extend HtmlExtension
-    when "html4Fr"
-      extend Html4Tr
-      element_init()
-      extend Html4Fr
-      element_init()
-      extend HtmlExtension
-    end
-  end
-
-end   # class CGI
+require 'cgi/core'
+require 'cgi/cookie'
+require 'cgi/util'

Modified: MacRuby/branches/experimental/lib/cmath.rb
===================================================================
--- MacRuby/branches/experimental/lib/cmath.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/cmath.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -25,17 +25,17 @@
   alias atanh! atanh
 
   def exp(z)
-    if Complex.generic?(z)
+    if z.real?
       exp!(z)
     else
-      Complex(exp!(z.real) * cos!(z.image),
-	      exp!(z.real) * sin!(z.image))
+      Complex(exp!(z.real) * cos!(z.imag),
+	      exp!(z.real) * sin!(z.imag))
     end
   end
 
   def log(*args)
     z, b = args
-    if Complex.generic?(z) and z >= 0 and (b.nil? or b >= 0)
+    if z.real? and z >= 0 and (b.nil? or b >= 0)
       log!(*args)
     else
       r, theta = z.polar
@@ -48,7 +48,7 @@
   end
 
   def log10(z)
-    if Complex.generic?(z)
+    if z.real?
       log10!(z)
     else
       log(z) / log!(10)
@@ -56,14 +56,14 @@
   end
 
   def sqrt(z)
-    if Complex.generic?(z)
-      if z >= 0
+    if z.real?
+      if z < 0
+	Complex(0, sqrt!(-z))
+      else
 	sqrt!(z)
-      else
-	Complex(0,sqrt!(-z))
       end
     else
-      if z.image < 0
+      if z.imag < 0
 	sqrt(z.conjugate).conjugate
       else
 	r = z.abs
@@ -74,25 +74,25 @@
   end
 
   def sin(z)
-    if Complex.generic?(z)
+    if z.real?
       sin!(z)
     else
-      Complex(sin!(z.real) * cosh!(z.image),
-	      cos!(z.real) * sinh!(z.image))
+      Complex(sin!(z.real) * cosh!(z.imag),
+	      cos!(z.real) * sinh!(z.imag))
     end
   end
 
   def cos(z)
-    if Complex.generic?(z)
+    if z.real?
       cos!(z)
     else
-      Complex(cos!(z.real) * cosh!(z.image),
-	      -sin!(z.real) * sinh!(z.image))
+      Complex(cos!(z.real) * cosh!(z.imag),
+	      -sin!(z.real) * sinh!(z.imag))
     end
   end
 
   def tan(z)
-    if Complex.generic?(z)
+    if z.real?
       tan!(z)
     else
       sin(z)/cos(z)
@@ -100,25 +100,25 @@
   end
 
   def sinh(z)
-    if Complex.generic?(z)
+    if z.real?
       sinh!(z)
     else
-      Complex(sinh!(z.real) * cos!(z.image),
-	      cosh!(z.real) * sin!(z.image))
+      Complex(sinh!(z.real) * cos!(z.imag),
+	      cosh!(z.real) * sin!(z.imag))
     end
   end
 
   def cosh(z)
-    if Complex.generic?(z)
+    if z.real?
       cosh!(z)
     else
-      Complex(cosh!(z.real) * cos!(z.image),
-	      sinh!(z.real) * sin!(z.image))
+      Complex(cosh!(z.real) * cos!(z.imag),
+	      sinh!(z.real) * sin!(z.imag))
     end
   end
 
   def tanh(z)
-    if Complex.generic?(z)
+    if z.real?
       tanh!(z)
     else
       sinh(z) / cosh(z)
@@ -126,39 +126,39 @@
   end
 
   def asin(z)
-    if Complex.generic?(z) and z >= -1 and z <= 1
+    if z.real? and z >= -1 and z <= 1
       asin!(z)
     else
-      -1.0.im * log(1.0.im * z + sqrt(1.0 - z * z))
+      Complex(0, -1.0) * log(Complex(0, 1.0) * z + sqrt(1.0 - z * z))
     end
   end
 
   def acos(z)
-    if Complex.generic?(z) and z >= -1 and z <= 1
+    if z.real? and z >= -1 and z <= 1
       acos!(z)
     else
-      -1.0.im * log(z + 1.0.im * sqrt(1.0 - z * z))
+      Complex(0, -1.0) * log(z + Complex(0, 1.0) * sqrt(1.0 - z * z))
     end
   end
 
   def atan(z)
-    if Complex.generic?(z)
+    if z.real?
       atan!(z)
     else
-      1.0.im * log((1.0.im + z) / (1.0.im - z)) / 2.0
+      Complex(0, 1.0) * log((Complex(0, 1.0) + z) / (Complex(0, 1.0) - z)) / 2.0
     end
   end
 
   def atan2(y,x)
-    if Complex.generic?(y) and Complex.generic?(x)
+    if y.real? and x.real?
       atan2!(y,x)
     else
-      -1.0.im * log((x + 1.0.im * y) / sqrt(x * x + y * y))
+      Complex(0, -1.0) * log((x + Complex(0, 1.0) * y) / sqrt(x * x + y * y))
     end
   end
 
   def acosh(z)
-    if Complex.generic?(z) and z >= 1
+    if z.real? and z >= 1
       acosh!(z)
     else
       log(z + sqrt(z * z - 1.0))
@@ -166,7 +166,7 @@
   end
 
   def asinh(z)
-    if Complex.generic?(z)
+    if z.real?
       asinh!(z)
     else
       log(z + sqrt(1.0 + z * z))
@@ -174,7 +174,7 @@
   end
 
   def atanh(z)
-    if Complex.generic?(z) and z >= -1 and z <= 1
+    if z.real? and z >= -1 and z <= 1
       atanh!(z)
     else
       log((1.0 + z) / (1.0 - z)) / 2.0
@@ -220,4 +220,14 @@
   module_function :atanh!
   module_function :atanh
 
+  module_function :log2
+  module_function :cbrt
+  module_function :frexp
+  module_function :ldexp
+  module_function :hypot
+  module_function :erf
+  module_function :erfc
+  module_function :gamma
+  module_function :lgamma
+
 end

Modified: MacRuby/branches/experimental/lib/complex.rb
===================================================================
--- MacRuby/branches/experimental/lib/complex.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/complex.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,4 +1,24 @@
 require 'cmath'
 
-Object.instance_eval{remove_const :Math}
-Math = CMath
+unless defined?(Math.exp!)
+  Object.instance_eval{remove_const :Math}
+  Math = CMath
+end
+
+def Complex.generic? (other)
+  other.kind_of?(Integer) ||
+  other.kind_of?(Float)   ||
+  other.kind_of?(Rational)
+end
+
+class Complex
+
+  alias image imag
+
+end
+
+class Numeric
+
+  def im() Complex(0, self) end
+
+end

Modified: MacRuby/branches/experimental/lib/csv.rb
===================================================================
--- MacRuby/branches/experimental/lib/csv.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/csv.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,5 +1,5 @@
-#!/usr/local/bin/ruby -w
-
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
 # = csv.rb -- CSV Reading and Writing
 #
 #  Created by James Edward Gray II on 2005-10-31.
@@ -37,6 +37,7 @@
 # 
 # === CSV Parsing
 # 
+# * This parser is m17n aware.  See CSV for full details.
 # * This library has a stricter parser and will throw MalformedCSVErrors on
 #   problematic data.
 # * This library has a less liberal idea of a line ending than CSV.  What you
@@ -91,7 +92,6 @@
 
 require "forwardable"
 require "English"
-require "enumerator"
 require "date"
 require "stringio"
 
@@ -130,7 +130,7 @@
 # 
 # === To a File
 # 
-#   CSV.open("path/to/file.csv", "w") do |csv|
+#   CSV.open("path/to/file.csv", "wb") do |csv|
 #     csv << ["row", "of", "CSV", "data"]
 #     csv << ["another", "row"]
 #     # ...
@@ -155,9 +155,51 @@
 #   CSV(csv = "")   { |csv_str| csv_str << %w{my data here} }  # to a String
 #   CSV($stderr)    { |csv_err| csv_err << %w{my data here} }  # to $stderr
 # 
+# == CSV and Character Encodings (M17n or Multilingualization)
+# 
+# This new CSV parser is m17n savvy.  The parser works in the Encoding of the IO
+# or String object being read from or written to.  Your data is never transcoded
+# (unless you ask Ruby to transcode it for you) and will literally be parsed in
+# the Encoding it is in.  Thus CSV will return Arrays or Rows of Strings in the
+# Encoding of your data.  This is accomplished by transcoding the parser itself
+# into your Encoding.
+# 
+# Some transcoding must take place, of course, to accomplish this multiencoding
+# support.  For example, <tt>:col_sep</tt>, <tt>:row_sep</tt>, and
+# <tt>:quote_char</tt> must be transcoded to match your data.  Hopefully this
+# makes the entire process feel transparent, since CSV's defaults should just
+# magically work for you data.  However, you can set these values manually in
+# the target Encoding to avoid the translation.
+# 
+# It's also important to note that while all of CSV's core parser is now
+# Encoding agnostic, some features are not.  For example, the built-in
+# converters will try to transcode data to UTF-8 before making conversions.
+# Again, you can provide custom converters that are aware of your Encodings to
+# avoid this translation.  It's just too hard for me to support native
+# conversions in all of Ruby's Encodings.
+# 
+# Anyway, the practical side of this is simple:  make sure IO and String objects
+# passed into CSV have the proper Encoding set and everything should just work.
+# CSV methods that allow you to open IO objects (CSV::foreach(), CSV::open(),
+# CSV::read(), and CSV::readlines()) do allow you to specify the Encoding.
+# 
+# One minor exception comes when generating CSV into a String with an Encoding
+# that is not ASCII compatible.  There's no existing data for CSV to use to
+# prepare itself and thus you will probably need to manually specify the desired
+# Encoding for most of those cases.  It will try to guess using the fields in a
+# row of output though, when using CSV::generate_line() or Array#to_csv().
+# 
+# I try to point out any other Encoding issues in the documentation of methods
+# as they come up.
+# 
+# This has been tested to the best of my ability with all non-"dummy" Encodings
+# Ruby ships with.  However, it is brave new code and may have some bugs.
+# Please feel free to {report}[mailto:james at grayproductions.net] any issues you
+# find with it.
+# 
 class CSV
   # The version of the installed library.
-  VERSION = "2.0.0".freeze
+  VERSION = "2.4.5".freeze
   
   # 
   # A CSV::Row is part Array and part Hash.  It retains an order for the fields
@@ -188,9 +230,9 @@
       
       # handle extra headers or fields
       @row = if headers.size > fields.size
-        headers.each_with_index.map { |header, i| [header, fields[i]] }
+        headers.zip(fields)
       else
-        fields.each_with_index.map { |field, i| [headers[i], field] }
+        fields.zip(headers).map { |pair| pair.reverse }
       end
     end
     
@@ -444,6 +486,24 @@
       fields.to_csv(options)
     end
     alias_method :to_s, :to_csv
+    
+    # A summary of fields, by header, in an ASCII compatible String.
+    def inspect
+      str = ["#<", self.class.to_s]
+      each do |header, field|
+        str << " " << (header.is_a?(Symbol) ? header.to_s : header.inspect) <<
+               ":" << field.inspect
+      end
+      str << ">"
+      begin
+        str.join
+      rescue  # any encoding error
+        str.map do |s|
+          e = Encoding::Converter.asciicompat_encoding(s.encoding)
+          e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
+        end.join
+      end
+    end
   end
   
   # 
@@ -775,6 +835,11 @@
       end.join
     end
     alias_method :to_s, :to_csv
+    
+    # Shows the mode and size of this table in a US-ASCII String.
+    def inspect
+      "#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>".encode("US-ASCII")
+    end
   end
 
   # The error thrown when the parser encounters illegal CSV formatting.
@@ -799,6 +864,10 @@
   DateTimeMatcher =
     / \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} |
             \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2} )\z /x
+  
+  # The encoding used by all converters.
+  ConverterEncoding = Encoding.find("UTF-8")
+  
   # 
   # This Hash holds the built-in converters of CSV that can be accessed by name.
   # You can select Converters with CSV.convert() or through the +options+ Hash
@@ -813,22 +882,40 @@
   # <b><tt>:all</tt></b>::        All built-in converters.  A combination of 
   #                               <tt>:date_time</tt> and <tt>:numeric</tt>.
   # 
-  # This Hash is intetionally left unfrozen and users should feel free to add
+  # All built-in converters transcode field data to UTF-8 before attempting a
+  # conversion.  If your data cannot be transcoded to UTF-8 the conversion will
+  # fail and the field will remain unchanged.
+  # 
+  # This Hash is intentionally left unfrozen and users should feel free to add
   # values to it that can be accessed by all CSV objects.
   # 
   # To add a combo field, the value should be an Array of names.  Combo fields
   # can be nested with other combo fields.
   # 
-  Converters  = { :integer   => lambda { |f| Integer(f)        rescue f },
-                  :float     => lambda { |f| Float(f)          rescue f },
-                  :numeric   => [:integer, :float],
-                  :date      => lambda { |f|
-                    f =~ DateMatcher ? (Date.parse(f) rescue f) : f
+  Converters  = { integer:   lambda { |f|
+                    Integer(f.encode(ConverterEncoding)) rescue f
                   },
-                  :date_time => lambda { |f|
-                    f =~ DateTimeMatcher ? (DateTime.parse(f) rescue f) : f
+                  float:     lambda { |f|
+                    Float(f.encode(ConverterEncoding)) rescue f
                   },
-                  :all       => [:date_time, :numeric] }
+                  numeric:   [:integer, :float],
+                  date:      lambda { |f|
+                    begin
+                      e = f.encode(ConverterEncoding)
+                      e =~ DateMatcher ? Date.parse(e) : f
+                    rescue  # encoding conversion or date parse errors
+                      f
+                    end
+                  },
+                  date_time: lambda { |f|
+                    begin
+                      e = f.encode(ConverterEncoding)
+                      e =~ DateTimeMatcher ? DateTime.parse(e) : f
+                    rescue  # encoding conversion or date parse errors
+                      f
+                    end
+                  },
+                  all:       [:date_time, :numeric] }
 
   # 
   # This Hash holds the built-in header converters of CSV that can be accessed
@@ -840,6 +927,10 @@
   #                              replaced with underscores, non-word characters
   #                              are dropped, and finally to_sym() is called.
   # 
+  # All built-in header converters transcode header data to UTF-8 before
+  # attempting a conversion.  If your data cannot be transcoded to UTF-8 the
+  # conversion will fail and the header will remain unchanged.
+  # 
   # This Hash is intetionally left unfrozen and users should feel free to add
   # values to it that can be accessed by all CSV objects.
   # 
@@ -847,9 +938,10 @@
   # can be nested with other combo fields.
   # 
   HeaderConverters = {
-    :downcase => lambda { |h| h.downcase },
-    :symbol   => lambda { |h|
-      h.downcase.tr(" ", "_").delete("^a-z0-9_").to_sym
+    downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
+    symbol:   lambda { |h|
+      h.encode(ConverterEncoding).downcase.gsub(/\s+/, "_").
+                                           gsub(/\W+/, "").to_sym
     }
   }
   
@@ -859,6 +951,7 @@
   # <b><tt>:col_sep</tt></b>::            <tt>","</tt>
   # <b><tt>:row_sep</tt></b>::            <tt>:auto</tt>
   # <b><tt>:quote_char</tt></b>::         <tt>'"'</tt>
+  # <b><tt>:field_size_limit</tt></b>::   +nil+
   # <b><tt>:converters</tt></b>::         +nil+
   # <b><tt>:unconverted_fields</tt></b>:: +nil+
   # <b><tt>:headers</tt></b>::            +false+
@@ -867,18 +960,44 @@
   # <b><tt>:skip_blanks</tt></b>::        +false+
   # <b><tt>:force_quotes</tt></b>::       +false+
   # 
-  DEFAULT_OPTIONS = { :col_sep            => ",",
-                      :row_sep            => :auto,
-                      :quote_char         => '"', 
-                      :converters         => nil,
-                      :unconverted_fields => nil,
-                      :headers            => false,
-                      :return_headers     => false,
-                      :header_converters  => nil,
-                      :skip_blanks        => false,
-                      :force_quotes       => false }.freeze
+  DEFAULT_OPTIONS = { col_sep:            ",",
+                      row_sep:            :auto,
+                      quote_char:         '"', 
+                      field_size_limit:   nil,
+                      converters:         nil,
+                      unconverted_fields: nil,
+                      headers:            false,
+                      return_headers:     false,
+                      header_converters:  nil,
+                      skip_blanks:        false,
+                      force_quotes:       false }.freeze
   
   # 
+  # This method will return a CSV instance, just like CSV::new(), but the
+  # instance will be cached and returned for all future calls to this method for
+  # the same +data+ object (tested by Object#object_id()) with the same
+  # +options+.
+  # 
+  # If a block is given, the instance is passed to the block and the return
+  # value becomes the return value of the block.
+  # 
+  def self.instance(data = $stdout, options = Hash.new)
+    # create a _signature_ for this method call, data object and options
+    sig = [data.object_id] +
+          options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })
+    
+    # fetch or create the instance for this signature
+    @@instances ||= Hash.new
+    instance    =   (@@instances[sig] ||= new(data, options))
+
+    if block_given?
+      yield instance  # run block, if given, returning result
+    else
+      instance        # or return the instance
+    end
+  end
+
+  # 
   # This method allows you to serialize an Array of Ruby objects to a String or
   # File of CSV data.  This is not as powerful as Marshal or YAML, but perhaps
   # useful for spreadsheet and database interaction.
@@ -959,6 +1078,53 @@
   end
   
   # 
+  # This method is the reading counterpart to CSV::dump().  See that method for
+  # a detailed description of the process.
+  # 
+  # You can customize loading by adding a class method called csv_load() which 
+  # will be passed a Hash of meta information, an Array of headers, and an Array
+  # of fields for the object the method is expected to return.
+  # 
+  # Remember that all fields will be Strings after this load.  If you need
+  # something else, use +options+ to setup converters or provide a custom
+  # csv_load() implementation.
+  # 
+  def self.load(io_or_str, options = Hash.new)
+    csv = new(io_or_str, options)
+    
+    # load meta information
+    meta = Hash[*csv.shift]
+    cls  = meta["class".encode(csv.encoding)].split("::".encode(csv.encoding)).
+                                              inject(Object) do |c, const|
+      c.const_get(const)
+    end
+    
+    # load headers
+    headers = csv.shift
+    
+    # unserialize each object stored in the file
+    results = csv.inject(Array.new) do |all, row|
+      begin
+        obj = cls.csv_load(meta, headers, row)
+      rescue NoMethodError
+        obj = cls.allocate
+        headers.zip(row) do |name, value|
+          if name[0] == ?@
+            obj.instance_variable_set(name, value)
+          else
+            obj.send(name, value)
+          end
+        end
+      end
+      all << obj
+    end
+    
+    csv.close unless io_or_str.is_a? String
+    
+    results
+  end
+  
+  # 
   # :call-seq:
   #   filter( options = Hash.new ) { |row| ... }
   #   filter( input, options = Hash.new ) { |row| ... }
@@ -984,7 +1150,7 @@
   # 
   def self.filter(*args)
     # parse options for input, output, or both
-    in_options, out_options = Hash.new, {:row_sep => $INPUT_RECORD_SEPARATOR}
+    in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
     if args.last.is_a? Hash
       args.pop.each do |key, value|
         case key.to_s
@@ -1014,10 +1180,20 @@
   # pass a +path+ and any +options+ you wish to set for the read.  Each row of
   # file will be passed to the provided +block+ in turn.
   # 
-  # The +options+ parameter can be anything CSV::new() understands.
+  # The +options+ parameter can be anything CSV::new() understands.  This method
+  # also understands an additional <tt>:encoding</tt> parameter that you can use
+  # to specify the Encoding of the data in the file to be read. You must provide
+  # this unless your data is in Encoding::default_external().  CSV will use this
+  # to deterime how to parse the data.  You may provide a second Encoding to
+  # have the data transcoded as it is read.  For example,
+  # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
+  # but transcode it to UTF-8 before CSV parses it.
   # 
   def self.foreach(path, options = Hash.new, &block)
-    open(path, options) do |csv|
+    encoding =  options.delete(:encoding)
+    mode     =  "rb"
+    mode     << ":#{encoding}" if encoding
+    open(path, mode, options) do |csv|
       csv.each(&block)
     end
   end
@@ -1035,7 +1211,10 @@
   # Note that a passed String *is* modfied by this method.  Call dup() before
   # passing if you need a new String.
   # 
-  # The +options+ parameter can be anthing CSV::new() understands.
+  # The +options+ parameter can be anthing CSV::new() understands.  This method
+  # understands an additional <tt>:encoding</tt> parameter when not passed a
+  # String to set the base Encoding for the output.  CSV needs this hint if you
+  # plan to output non-ASCII compatible data.
   # 
   def self.generate(*args)
     # add a default empty String, if none was given
@@ -1044,7 +1223,10 @@
       io.seek(0, IO::SEEK_END)
       args.unshift(io)
     else
-      args.unshift("")
+      encoding = args.last.is_a?(Hash) ? args.last.delete(:encoding) : nil
+      str      = ""
+      str.encode!(encoding) if encoding
+      args.unshift(str)
     end
     csv = new(*args)  # wrap
     yield csv         # yield for appending
@@ -1055,122 +1237,79 @@
   # This method is a shortcut for converting a single row (Array) into a CSV 
   # String.
   # 
-  # The +options+ parameter can be anthing CSV::new() understands.
+  # The +options+ parameter can be anthing CSV::new() understands.  This method
+  # understands an additional <tt>:encoding</tt> parameter to set the base 
+  # Encoding for the output.  This method will try to guess your Encoding from
+  # the first non-+nil+ field in +row+, if possible, but you may need to use
+  # this parameter as a backup plan.
   # 
   # The <tt>:row_sep</tt> +option+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>
   # (<tt>$/</tt>) when calling this method.
   # 
   def self.generate_line(row, options = Hash.new)
-    options = {:row_sep => $INPUT_RECORD_SEPARATOR}.merge(options)
-    (new("", options) << row).string
-  end
-  
-  # 
-  # This method will return a CSV instance, just like CSV::new(), but the
-  # instance will be cached and returned for all future calls to this method for
-  # the same +data+ object (tested by Object#object_id()) with the same
-  # +options+.
-  # 
-  # If a block is given, the instance is passed to the block and the return
-  # value becomes the return value of the block.
-  # 
-  def self.instance(data = $stdout, options = Hash.new)
-    # create a _signature_ for this method call, data object and options
-    sig = [data.object_id] +
-          options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })
-    
-    # fetch or create the instance for this signature
-    @@instances ||= Hash.new
-    instance    =   (@@instances[sig] ||= new(data, options))
-
-    if block_given?
-      yield instance  # run block, if given, returning result
-    else
-      instance        # or return the instance
+    options  = {row_sep: $INPUT_RECORD_SEPARATOR}.merge(options)
+    encoding = options.delete(:encoding)
+    str      = ""
+    if encoding
+      str.force_encoding(encoding)
+    elsif field = row.find { |f| not f.nil? }
+      str.force_encoding(String(field).encoding)
     end
+    (new(str, options) << row).string
   end
   
   # 
-  # This method is the reading counterpart to CSV::dump().  See that method for
-  # a detailed description of the process.
-  # 
-  # You can customize loading by adding a class method called csv_load() which 
-  # will be passed a Hash of meta information, an Array of headers, and an Array
-  # of fields for the object the method is expected to return.
-  # 
-  # Remember that all fields will be Strings after this load.  If you need
-  # something else, use +options+ to setup converters or provide a custom
-  # csv_load() implementation.
-  # 
-  def self.load(io_or_str, options = Hash.new)
-    csv = new(io_or_str, options)
-    
-    # load meta information
-    meta = Hash[*csv.shift]
-    cls  = meta["class"].split("::").inject(Object) do |c, const|
-      c.const_get(const)
-    end
-    
-    # load headers
-    headers = csv.shift
-    
-    # unserialize each object stored in the file
-    results = csv.inject(Array.new) do |all, row|
-      begin
-        obj = cls.csv_load(meta, headers, row)
-      rescue NoMethodError
-        obj = cls.allocate
-        headers.zip(row) do |name, value|
-          if name[0] == ?@
-            obj.instance_variable_set(name, value)
-          else
-            obj.send(name, value)
-          end
-        end
-      end
-      all << obj
-    end
-    
-    csv.close unless io_or_str.is_a? String
-    
-    results
-  end
-  
-  # 
   # :call-seq:
-  #   open( filename, mode="r", options = Hash.new ) { |csv| ... }
-  #   open( filename, mode="r", options = Hash.new )
+  #   open( filename, mode = "rb", options = Hash.new ) { |faster_csv| ... }
+  #   open( filename, options = Hash.new ) { |faster_csv| ... }
+  #   open( filename, mode = "rb", options = Hash.new )
+  #   open( filename, options = Hash.new )
   # 
   # This method opens an IO object, and wraps that with CSV.  This is intended
   # as the primary interface for writing a CSV file.
   # 
-  # You may pass any +args+ Ruby's open() understands followed by an optional
-  # Hash containing any +options+ CSV::new() understands.
+  # You must pass a +filename+ and may optionally add a +mode+ for Ruby's
+  # open().  You may also pass an optional Hash containing any +options+
+  # CSV::new() understands as the final argument.
   # 
   # This method works like Ruby's open() call, in that it will pass a CSV object
-  # to a provided block and close it when the block termminates, or it will
+  # to a provided block and close it when the block terminates, or it will
   # return the CSV object when no block is provided.  (*Note*: This is different
   # from the Ruby 1.8 CSV library which passed rows to the block.  Use
   # CSV::foreach() for that behavior.)
   # 
-  # An opened CSV object will delegate to many IO methods, for convenience.  You
+  # You must provide a +mode+ with an embedded Encoding designator unless your
+  # data is in Encoding::default_external().  CSV will check the Encoding of the
+  # underlying IO object (set by the +mode+ you pass) to deterime how to parse
+  # the data.   You may provide a second Encoding to have the data transcoded as
+  # it is read just as you can with a normal call to IO::open().  For example,
+  # <tt>"rb:UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file but
+  # transcode it to UTF-8 before CSV parses it.
+  # 
+  # An opened CSV object will delegate to many IO methods for convenience.  You
   # may call:
   # 
   # * binmode()
+  # * binmode?()
   # * close()
   # * close_read()
   # * close_write()
   # * closed?()
   # * eof()
   # * eof?()
+  # * external_encoding()
   # * fcntl()
   # * fileno()
+  # * flock()
   # * flush()
   # * fsync()
+  # * internal_encoding()
   # * ioctl()
   # * isatty()
+  # * path()
   # * pid()
   # * pos()
+  # * pos=()
   # * reopen()
   # * seek()
   # * stat()
@@ -1179,11 +1318,14 @@
   # * tell()
   # * to_i()
   # * to_io()
+  # * truncate()
   # * tty?()
   # 
   def self.open(*args)
     # find the +options+ Hash
     options = if args.last.is_a? Hash then args.pop else Hash.new end
+    # default to a binary open mode
+    args << "rb" if args.size == 1
     # wrap a File opened with the remaining +args+
     csv     = new(File.open(*args), options)
     
@@ -1237,10 +1379,20 @@
   
   # 
   # Use to slurp a CSV file into an Array of Arrays.  Pass the +path+ to the 
-  # file and any +options+ CSV::new() understands.
+  # file and any +options+ CSV::new() understands.  This method also understands
+  # an additional <tt>:encoding</tt> parameter that you can use to specify the
+  # Encoding of the data in the file to be read. You must provide this unless
+  # your data is in Encoding::default_external().  CSV will use this to deterime
+  # how to parse the data.  You may provide a second Encoding to have the data
+  # transcoded as it is read.  For example,
+  # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
+  # but transcode it to UTF-8 before CSV parses it.
   # 
   def self.read(path, options = Hash.new)
-    open(path, options) { |csv| csv.read }
+    encoding =  options.delete(:encoding)
+    mode     =  "rb"
+    mode     << ":#{encoding}" if encoding
+    open(path, mode, options) { |csv| csv.read }
   end
   
   # Alias for CSV::read().
@@ -1251,14 +1403,14 @@
   # 
   # A shortcut for:
   # 
-  #   CSV.read( path, { :headers           => true,
-  #                     :converters        => :numeric,
-  #                     :header_converters => :symbol }.merge(options) )
+  #   CSV.read( path, { headers:           true,
+  #                     converters:        :numeric,
+  #                     header_converters: :symbol }.merge(options) )
   # 
   def self.table(path, options = Hash.new)
-    read( path, { :headers           => true,
-                  :converters        => :numeric,
-                  :header_converters => :symbol }.merge(options) )
+    read( path, { headers:           true,
+                  converters:        :numeric,
+                  header_converters: :symbol }.merge(options) )
   end
   
   # 
@@ -1276,6 +1428,8 @@
   # Available options are:
   # 
   # <b><tt>:col_sep</tt></b>::            The String placed between each field.
+  #                                       This String will be transcoded into
+  #                                       the data's Encoding before parsing.
   # <b><tt>:row_sep</tt></b>::            The String appended to the end of each
   #                                       row.  This can be set to the special
   #                                       <tt>:auto</tt> setting, which requests
@@ -1295,7 +1449,16 @@
   #                                       <tt>$INPUT_RECORD_SEPARATOR</tt>
   #                                       (<tt>$/</tt>) is used.  Obviously,
   #                                       discovery takes a little time.  Set
-  #                                       manually if speed is important.
+  #                                       manually if speed is important.  Also
+  #                                       note that IO objects should be opened
+  #                                       in binary mode on Windows if this
+  #                                       feature will be used as the
+  #                                       line-ending translation can cause
+  #                                       problems with resetting the document
+  #                                       position to where it was before the
+  #                                       read ahead. This String will be
+  #                                       transcoded into the data's Encoding
+  #                                       before parsing.
   # <b><tt>:quote_char</tt></b>::         The character used to quote fields.
   #                                       This has to be a single character
   #                                       String.  This is useful for
@@ -1304,16 +1467,36 @@
   #                                       instead of the correct <tt>"</tt>.
   #                                       CSV will always consider a double
   #                                       sequence this character to be an
-  #                                       escaped quote.
+  #                                       escaped quote. This String will be
+  #                                       transcoded into the data's Encoding
+  #                                       before parsing.
+  # <b><tt>:field_size_limit</tt></b>::   This is a maximum size CSV will read
+  #                                       ahead looking for the closing quote
+  #                                       for a field.  (In truth, it reads to
+  #                                       the first line ending beyond this
+  #                                       size.)  If a quote cannot be found
+  #                                       within the limit CSV will raise a
+  #                                       MalformedCSVError, assuming the data
+  #                                       is faulty.  You can use this limit to
+  #                                       prevent what are effectively DoS
+  #                                       attacks on the parser.  However, this
+  #                                       limit can cause a legitimate parse to
+  #                                       fail and thus is set to +nil+, or off,
+  #                                       by default.
   # <b><tt>:converters</tt></b>::         An Array of names from the Converters
   #                                       Hash and/or lambdas that handle custom
   #                                       conversion.  A single converter
-  #                                       doesn't have to be in an Array.
+  #                                       doesn't have to be in an Array.  All
+  #                                       built-in converters try to transcode
+  #                                       fields to UTF-8 before converting.
+  #                                       The conversion will fail if the data
+  #                                       cannot be transcoded, leaving the
+  #                                       field unchanged.
   # <b><tt>:unconverted_fields</tt></b>:: If set to +true+, an
   #                                       unconverted_fields() method will be
   #                                       added to all returned rows (Array or
   #                                       CSV::Row) that will return the fields
-  #                                       as they were before convertion.  Note
+  #                                       as they were before conversion.  Note
   #                                       that <tt>:headers</tt> supplied by
   #                                       Array or String were not fields of the
   #                                       document and thus will have an empty
@@ -1324,11 +1507,14 @@
   #                                       headers.  If set to an Array, the
   #                                       contents will be used as the headers.
   #                                       If set to a String, the String is run
-  #                                       through a call of CSV::parse_line() to
-  #                                       produce an Array of headers.  This
-  #                                       setting causes CSV.shift() to return
+  #                                       through a call of CSV::parse_line()
+  #                                       with the same <tt>:col_sep</tt>,
+  #                                       <tt>:row_sep</tt>, and
+  #                                       <tt>:quote_char</tt> as this instance
+  #                                       to produce an Array of headers.  This
+  #                                       setting causes CSV#shift() to return
   #                                       rows as CSV::Row objects instead of
-  #                                       Arrays and CSV.read() to return
+  #                                       Arrays and CSV#read() to return
   #                                       CSV::Table objects instead of an Array
   #                                       of Arrays.
   # <b><tt>:return_headers</tt></b>::     When +false+, header rows are silently
@@ -1337,10 +1523,17 @@
   #                                       with identical headers and
   #                                       fields (save that the fields do not go
   #                                       through the converters).
+  # <b><tt>:write_headers</tt></b>::      When +true+ and <tt>:headers</tt> is
+  #                                       set, a header row will be added to the
+  #                                       output.
   # <b><tt>:header_converters</tt></b>::  Identical in functionality to
   #                                       <tt>:converters</tt> save that the
   #                                       conversions are only made to header
-  #                                       rows.
+  #                                       rows.  All built-in converters try to
+  #                                       transcode headers to UTF-8 before
+  #                                       converting.  The conversion will fail
+  #                                       if the data cannot be transcoded,
+  #                                       leaving the header unchanged.
   # <b><tt>:skip_blanks</tt></b>::        When set to a +true+ value, CSV will
   #                                       skip over any rows with no content.
   # <b><tt>:force_quotes</tt></b>::       When set to a +true+ value, CSV will
@@ -1356,8 +1549,24 @@
     options = DEFAULT_OPTIONS.merge(options)
     
     # create the IO object we will read from
-    @io = if data.is_a? String then StringIO.new(data) else data end
-    
+    @io       =   if data.is_a? String then StringIO.new(data) else data end
+    # honor the IO encoding if we can, otherwise default to ASCII-8BIT
+    @encoding =   if @io.respond_to? :internal_encoding
+                    @io.internal_encoding || @io.external_encoding
+                  elsif @io.is_a? StringIO
+                    @io.string.encoding
+                  end
+    @encoding ||= Encoding.default_internal || Encoding.default_external
+    # 
+    # prepare for building safe regular expressions in the target encoding,
+    # if we can transcode the needed characters
+    # 
+    @re_esc   =   "\\".encode(@encoding) rescue ""
+    @re_chars =   %w[ \\ .  [  ]  -  ^  $  ?
+                      *  +  {  }  (  )  |  #
+                      \  \r \n \t \f \v ].
+                  map { |s| s.encode(@encoding) rescue nil }.compact
+   
     init_separators(options)
     init_parsers(options)
     init_converters(options)
@@ -1372,6 +1581,79 @@
   end
   
   # 
+  # The encoded <tt>:col_sep</tt> used in parsing and writing.  See CSV::new
+  # for details.
+  # 
+  attr_reader :col_sep
+  # 
+  # The encoded <tt>:row_sep</tt> used in parsing and writing.  See CSV::new
+  # for details.
+  # 
+  attr_reader :row_sep
+  # 
+  # The encoded <tt>:quote_char</tt> used in parsing and writing.  See CSV::new
+  # for details.
+  # 
+  attr_reader :quote_char
+  # The limit for field size, if any.  See CSV::new for details.
+  attr_reader :field_size_limit
+  # 
+  # Returns the current list of converters in effect.  See CSV::new for details.
+  # Built-in converters will be returned by name, while others will be returned
+  # as is.
+  # 
+  def converters
+    @converters.map do |converter|
+      name = Converters.rassoc(converter)
+      name ? name.first : converter
+    end
+  end
+  # 
+  # Returns +true+ if unconverted_fields() to parsed results.  See CSV::new
+  # for details.
+  # 
+  def unconverted_fields?() @unconverted_fields end
+  # 
+  # Returns +nil+ if headers will not be used, +true+ if they will but have not
+  # yet been read, or the actual headers after they have been read.  See
+  # CSV::new for details.
+  # 
+  def headers
+    @headers || true if @use_headers
+  end
+  # 
+  # Returns +true+ if headers will be returned as a row of results.
+  # See CSV::new for details.
+  # 
+  def return_headers?()     @return_headers     end
+  # Returns +true+ if headers are written in output. See CSV::new for details.
+  def write_headers?()      @write_headers      end
+  # 
+  # Returns the current list of converters in effect for headers.  See CSV::new
+  # for details.  Built-in converters will be returned by name, while others
+  # will be returned as is.
+  # 
+  def header_converters
+    @header_converters.map do |converter|
+      name = HeaderConverters.rassoc(converter)
+      name ? name.first : converter
+    end
+  end
+  # 
+  # Returns +true+ blank lines are skipped by the parser. See CSV::new
+  # for details.
+  # 
+  def skip_blanks?()        @skip_blanks        end
+  # Returns +true+ if all output fields are quoted. See CSV::new for details.
+  def force_quotes?()       @force_quotes       end
+    
+  # 
+  # The Encoding CSV is parsing or writing in.  This will be the Encoding you
+  # receive parsed data in and/or the Encoding data will be written in.
+  # 
+  attr_reader :encoding
+  
+  # 
   # The line number of the last row read from this file.  Fields with nested 
   # line-end characters will not affect this count.
   # 
@@ -1380,10 +1662,12 @@
   ### IO and StringIO Delegation ###
   
   extend Forwardable
-  def_delegators :@io, :binmode, :close, :close_read, :close_write, :closed?,
-                       :eof, :eof?, :fcntl, :fileno, :flush, :fsync, :ioctl,
-                       :isatty, :pid, :pos, :reopen, :seek, :stat, :string,
-                       :sync, :sync=, :tell, :to_i, :to_io, :tty?
+  def_delegators :@io, :binmode, :binmode?, :close, :close_read, :close_write,
+                       :closed?, :eof, :eof?, :external_encoding, :fcntl,
+                       :fileno, :flock, :flush, :fsync, :internal_encoding,
+                       :ioctl, :isatty, :path, :pid, :pos, :pos=, :reopen,
+                       :seek, :stat, :string, :sync, :sync=, :tell, :to_i,
+                       :to_io, :truncate, :tty?
   
   # Rewinds the underlying IO object and resets CSV's lineno() counter.
   def rewind
@@ -1403,12 +1687,18 @@
   # The data source must be open for writing.
   # 
   def <<(row)
+    # make sure headers have been assigned
+    if header_row? and [Array, String].include? @use_headers.class
+      parse_headers  # won't read data for Array or String
+      self << @headers if @write_headers
+    end
+    
     # handle CSV::Row objects and Hashes
     row = case row
-      when self.class::Row then row.fields
-      when Hash            then @headers.map { |header| row[header] }
-      else                      row
-    end
+          when self.class::Row then row.fields
+          when Hash            then @headers.map { |header| row[header] }
+          else                      row
+          end
 
     @headers =  row if header_row?
     @lineno  += 1
@@ -1431,7 +1721,7 @@
   # 
   # If you provide a block that takes one argument, it will be passed the field
   # and is expected to return the converted value or the field itself.  If your
-  # block takes two arguments, it will also be passed a FieldInfo Struct, 
+  # block takes two arguments, it will also be passed a CSV::FieldInfo Struct, 
   # containing details about the field.  Again, the block should return a 
   # converted field or the field itself.
   # 
@@ -1445,7 +1735,7 @@
   #   header_convert { |field| ... }
   #   header_convert { |field, field_info| ... }
   # 
-  # Identical to CSV.convert(), but for header rows.
+  # Identical to CSV#convert(), but for header rows.
   # 
   # Note that this method must be called before header rows are read to have any
   # effect.
@@ -1526,7 +1816,7 @@
       # add another read to the line
       (line += @io.gets(@row_sep)) rescue return nil
       # copy the line so we can chop it up in parsing
-      parse = line.dup
+      parse =  line.dup
       parse.sub!(@parsers[:line_end], "")
       
       # 
@@ -1566,7 +1856,7 @@
             nil               # for Ruby 1.8 CSV compatibility
           else
             # I decided to take a strict approach to CSV parsing...
-            if $2.count("\r\n").zero?  # verify correctness of field...
+            if $2.count(@parsers[:return_newline]).zero?  # verify correctness
               $2
             else
               # or throw an Exception
@@ -1603,6 +1893,10 @@
       # if we're not empty?() but at eof?(), a quoted field wasn't closed...
       if @io.eof?
         raise MalformedCSVError, "Unclosed quoted field on line #{lineno + 1}."
+      elsif parse =~ @parsers[:bad_field]
+        raise MalformedCSVError, "Illegal quoting on line #{lineno + 1}."
+      elsif @field_size_limit and parse.length >= @field_size_limit
+        raise MalformedCSVError, "Field size exceeded on line #{lineno + 1}."
       end
       # otherwise, we need to loop and pull some more data to complete the row
     end
@@ -1610,6 +1904,45 @@
   alias_method :gets,     :shift
   alias_method :readline, :shift
   
+  # 
+  # Returns a simplified description of the key FasterCSV attributes in an
+  # ASCII compatible String.
+  # 
+  def inspect
+    str = ["<#", self.class.to_s, " io_type:"]
+    # show type of wrapped IO
+    if    @io == $stdout then str << "$stdout"
+    elsif @io == $stdin  then str << "$stdin"
+    elsif @io == $stderr then str << "$stderr"
+    else                      str << @io.class.to_s
+    end
+    # show IO.path(), if available
+    if @io.respond_to?(:path) and (p = @io.path)
+      str << " io_path:" << p.inspect
+    end
+    # show encoding
+    str << " encoding:" << @encoding.name
+    # show other attributes
+    %w[ lineno     col_sep     row_sep
+        quote_char skip_blanks ].each do |attr_name|
+      if a = instance_variable_get("@#{attr_name}")
+        str << " " << attr_name << ":" << a.inspect
+      end
+    end
+    if @use_headers
+      str << " headers:" << headers.inspect
+    end
+    str << ">"
+    begin
+      str.join
+    rescue  # any encoding error
+      str.map do |s|
+        e = Encoding::Converter.asciicompat_encoding(s.encoding)
+        e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
+      end.join
+    end
+  end
+  
   private
   
   # 
@@ -1624,15 +1957,18 @@
   # 
   def init_separators(options)
     # store the selected separators
-    @col_sep    = options.delete(:col_sep)
-    @row_sep    = options.delete(:row_sep)
-    @quote_char = options.delete(:quote_char)
+    @col_sep    = options.delete(:col_sep).to_s.encode(@encoding)
+    @row_sep    = options.delete(:row_sep)  # encode after resolving :auto
+    @quote_char = options.delete(:quote_char).to_s.encode(@encoding)
 
     if @quote_char.length != 1
       raise ArgumentError, ":quote_char has to be a single character String"
     end
     
+    # 
     # automatically discover row separator when requested
+    # (not fully encoding safe)
+    # 
     if @row_sep == :auto
       if [ARGF, STDIN, STDOUT, STDERR].include?(@io) or
          (defined?(Zlib) and @io.class == Zlib::GzipWriter)
@@ -1651,11 +1987,12 @@
             end
       
             # read ahead a bit
-            sample =  @io.read(1024)
-            sample += @io.read(1) if sample[-1..-1] == "\r" and not @io.eof?
+            sample =  read_to_char(1024)
+            sample += read_to_char(1) if sample[-1..-1] == encode_str("\r") and
+                                         not @io.eof?
       
             # try to find a standard separator
-            if sample =~ /\r\n?|\n/
+            if sample =~ encode_re("\r\n?|\n")
               @row_sep = $&
               break
             end
@@ -1673,14 +2010,17 @@
         end
       end
     end
+    @row_sep = @row_sep.to_s.encode(@encoding)
     
     # establish quoting rules
-    do_quote = lambda do |field|
+    @force_quotes = options.delete(:force_quotes)
+    do_quote      = lambda do |field|
       @quote_char                                      +
       String(field).gsub(@quote_char, @quote_char * 2) +
       @quote_char
     end
-    @quote = if options.delete(:force_quotes)
+    quotable_chars = encode_str("\r\n", @col_sep, @quote_char)
+    @quote         = if @force_quotes
       do_quote
     else
       lambda do |field|
@@ -1690,7 +2030,7 @@
           field = String(field)  # Stringify fields
           # represent empty fields as empty quoted fields
           if field.empty? or
-             field.count("\r\n#{@col_sep}#{@quote_char}").nonzero?
+             field.count(quotable_chars).nonzero?
             do_quote.call(field)
           else
             field  # unquoted field
@@ -1703,27 +2043,45 @@
   # Pre-compiles parsers and stores them by name for access during reads.
   def init_parsers(options)
     # store the parser behaviors
-    @skip_blanks = options.delete(:skip_blanks)
+    @skip_blanks      = options.delete(:skip_blanks)
+    @field_size_limit = options.delete(:field_size_limit)
     
     # prebuild Regexps for faster parsing
-    esc_col_sep = Regexp.escape(@col_sep)
-    esc_row_sep = Regexp.escape(@row_sep)
-    esc_quote   = Regexp.escape(@quote_char)
+    esc_col_sep = escape_re(@col_sep)
+    esc_row_sep = escape_re(@row_sep)
+    esc_quote   = escape_re(@quote_char)
     @parsers = {
-      :leading_fields =>
-        /\A(?:#{esc_col_sep})+/,                 # for empty leading fields
-      :csv_row        =>
-        ### The Primary Parser ###
-        / \G(?:^|#{esc_col_sep})                 # anchor the match
-          (?: #{esc_quote}( (?>[^#{esc_quote}]*) # find quoted fields
-                            (?> #{esc_quote*2}
-                                [^#{esc_quote}]* )* )#{esc_quote}
-              |                                  # ... or ...
-              ([^#{esc_quote}#{esc_col_sep}]*)   # unquoted fields
-              )/x,
-        ### End Primary Parser ###
-      :line_end       =>
-        /#{esc_row_sep}\z/                       # safer than chomp!()
+      # for empty leading fields
+      leading_fields: encode_re("\\A(?:", esc_col_sep, ")+"),
+      # The Primary Parser
+      csv_row:        encode_re(
+        "\\G(?:\\A|", esc_col_sep, ")",                # anchor the match
+        "(?:", esc_quote,                              # find quoted fields
+               "((?>[^", esc_quote, "]*)",             # "unrolling the loop"
+               "(?>", esc_quote * 2,                   # double for escaping
+               "[^", esc_quote, "]*)*)",
+               esc_quote,
+               "|",                                    # ... or ...
+               "([^", esc_quote, esc_col_sep, "]*))",  # unquoted fields
+        "(?=", esc_col_sep, "|\\z)"                    # ensure field is ended
+      ),
+      # a test for unescaped quotes
+      bad_field:      encode_re(
+        "\\A", esc_col_sep, "?",                   # an optional comma
+        "(?:", esc_quote,                          # a quoted field
+               "(?>[^", esc_quote, "]*)",          # "unrolling the loop"
+               "(?>", esc_quote * 2,               # double for escaping
+               "[^", esc_quote, "]*)*",
+               esc_quote,                          # the closing quote
+               "[^", esc_quote, "]",               # an extra character
+               "|",                                # ... or ...
+               "[^", esc_quote, esc_col_sep, "]+", # an unquoted field
+               esc_quote, ")"                      # an extra quote
+      ),
+      # safer than chomp!()
+      line_end:       encode_re(esc_row_sep, "\\z"),
+      # illegal unquoted characters
+      return_newline: encode_str("\r\n")
     }
   end
   
@@ -1744,7 +2102,7 @@
 
     instance_variable_set("@#{field_name}", Array.new)
     
-    # find the correct method to add the coverters
+    # find the correct method to add the converters
     convert = method(field_name.to_s.sub(/ers\Z/, ""))
     
     # load converters
@@ -1770,6 +2128,7 @@
   def init_headers(options)
     @use_headers    = options.delete(:headers)
     @return_headers = options.delete(:return_headers)
+    @write_headers  = options.delete(:write_headers)
 
     # headers must be delayed until shift(), in case they need a row of content
     @headers = nil
@@ -1812,7 +2171,7 @@
     # see if we are converting headers or fields
     converters = headers ? @header_converters : @converters
     
-    fields.each_with_index.map do |field, index|  # map_with_index
+    fields.map.with_index do |field, index|
       converters.each do |converter|
         field = if converter.arity == 1  # straight field converter
           converter[field]
@@ -1839,10 +2198,17 @@
   def parse_headers(row = nil)
     if @headers.nil?                # header row
       @headers = case @use_headers  # save headers
-      when Array  then @use_headers                         # Array of headers
-      when String then self.class.parse_line(@use_headers)  # CSV header String
-      else             row                                  # first row headers
-      end
+                 # Array of headers
+                 when Array then @use_headers
+                 # CSV header String
+                 when String
+                   self.class.parse_line( @use_headers,
+                                          col_sep:    @col_sep,
+                                          row_sep:    @row_sep,
+                                          quote_char: @quote_char )
+                 # first row is headers
+                 else            row
+                 end
       
       # prepare converted and unconverted copies
       row      = @headers                       if row.nil?
@@ -1870,6 +2236,59 @@
     row.instance_eval { @unconverted_fields = fields }
     row
   end
+  
+  # 
+  # This method is an encoding safe version of Regexp::escape().  I will escape
+  # any characters that would change the meaning of a regular expression in the
+  # encoding of +str+.  Regular expression characters that cannot be transcoded
+  # to the target encodign will be skipped and no escaping will be performed if
+  # a backslash cannot be transcoded.
+  # 
+  def escape_re(str)
+    str.chars.map { |c| @re_chars.include?(c) ? @re_esc + c : c }.join
+  end
+  
+  # 
+  # Builds a regular expression in <tt>@encoding</tt>.  All +chunks+ will be
+  # transcoded to that encoding.
+  # 
+  def encode_re(*chunks)
+    Regexp.new(encode_str(*chunks))
+  end
+  
+  # 
+  # Builds a String in <tt>@encoding</tt>.  All +chunks+ will be transcoded to
+  # that encoding.
+  # 
+  def encode_str(*chunks)
+    chunks.map { |chunk| chunk.encode(@encoding.name) }.join
+  end
+
+  # 
+  # Reads at least +bytes+ from <tt>@io</tt>, but will read up 10 bytes ahead if
+  # needed to ensure the data read is valid in the ecoding of that data.  This
+  # should ensure that it is safe to use regular expressions on the read data,
+  # unless it is actually a broken encoding.  The read data will be returned in
+  # <tt>@encoding</tt>.
+  # 
+  def read_to_char(bytes)
+    return "" if @io.eof?
+    data = @io.read(bytes)
+    begin
+      encoded = encode_str(data)
+      raise unless encoded.valid_encoding?
+      return encoded
+    rescue  # encoding error or my invalid data raise
+      if @io.eof? or data.size >= bytes + 10
+        return data
+      else
+        data += @io.read(1) until data.valid_encoding? or
+                                  @io.eof?             or
+                                  data.size >= bytes + 10
+        retry
+      end
+    end
+  end
 end
 
 # Another name for CSV::instance().

Modified: MacRuby/branches/experimental/lib/date/format.rb
===================================================================
--- MacRuby/branches/experimental/lib/date/format.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/date/format.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,8 +1,6 @@
 # format.rb: Written by Tadayoshi Funaba 1999-2008
 # $Id: format.rb,v 2.43 2008-01-17 20:16:31+09 tadf Exp $
 
-require 'rational'
-
 class Date
 
   module Format # :nodoc:
@@ -257,13 +255,19 @@
       when 'j'; emit_n(yday, 3, f)
       when 'k'; emit_a(hour, 2, f)
       when 'L'
-	emit_n((sec_fraction / MILLISECONDS_IN_SECOND).floor, 3, f)
+	f[:p] = nil
+	w = f[:w] || 3
+	u = 10**w
+	emit_n((sec_fraction * u).floor, w, f)
       when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
       when 'M', 'OM'; emit_n(min, 2, f)
       when 'm', 'Om'; emit_n(mon, 2, f)
       when 'N'
-	emit_n((sec_fraction / NANOSECONDS_IN_SECOND).floor, 9, f)
-      when 'n'; "\n"
+	f[:p] = nil
+	w = f[:w] || 9
+	u = 10**w
+	emit_n((sec_fraction * u).floor, w, f)
+      when 'n'; emit_a("\n", 0, f)
       when 'P'; emit_ad(strftime('%p').downcase, 0, f)
       when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
       when 'Q'
@@ -281,7 +285,7 @@
 	else
 	  emit_a(strftime('%H:%M:%S'), 0, f)
 	end
-      when 't'; "\t"
+      when 't'; emit_a("\t", 0, f)
       when 'U', 'W', 'OU', 'OW'
 	emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
       when 'u', 'Ou'; emit_n(cwday, 1, f)
@@ -665,11 +669,11 @@
   private_class_method :s3e
 
   def self._parse_day(str, e) # :nodoc:
-    if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/ino, ' ')
+    if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/io, ' ')
       e.wday = Format::ABBR_DAYS[$1.downcase]
       true
 =begin
-    elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/in, ' ')
+    elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/i, ' ')
       e.wday = %w(su mo tu we th fr sa).index($1.downcase)
       true
 =end
@@ -704,7 +708,7 @@
 		     [[:alpha:]]+(?:\sdst)?\b
 		   )
 		 )?
-		/inx,
+		/ix,
 		' ')
 
       t = $1
@@ -716,7 +720,7 @@
 		  \s*:?\s*(\d+)(?:[,.](\d+))?s?
 		)?
 	      )?
-	    (?:\s*([ap])(?:m\b|\.m\.))?/inx
+	    (?:\s*([ap])(?:m\b|\.m\.))?/ix
 
       e.hour = $1.to_i
       e.min = $2.to_i if $2
@@ -761,7 +765,7 @@
 		   \s*
 		   ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
 		 )?
-		/inox,
+		/iox,
 		' ') # '
       s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
 	  $3 && $3[0,1].downcase == 'b')
@@ -780,7 +784,7 @@
 		   \s*
 		   ('?-?\d+)
 		 )?
-		/inox,
+		/iox,
 		' ') # '
       s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
 	  $3 && $3[0,1].downcase == 'b')
@@ -789,43 +793,43 @@
   end
 
   def self._parse_iso(str, e) # :nodoc:
-    if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/n, ' ')
+    if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/, ' ')
       s3e(e, $1, $2, $3)
       true
     end
   end
 
   def self._parse_iso2(str, e) # :nodoc:
-    if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/in, ' ')
+    if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/i, ' ')
       e.cwyear = $1.to_i if $1
       e.cweek = $2.to_i
       e.cwday = $3.to_i if $3
       true
-    elsif str.sub!(/-w-(\d)\b/in, ' ')
+    elsif str.sub!(/-w-(\d)\b/i, ' ')
       e.cwday = $1.to_i
       true
-    elsif str.sub!(/--(\d{2})?-(\d{2})\b/n, ' ')
+    elsif str.sub!(/--(\d{2})?-(\d{2})\b/, ' ')
       e.mon = $1.to_i if $1
       e.mday = $2.to_i
       true
-    elsif str.sub!(/--(\d{2})(\d{2})?\b/n, ' ')
+    elsif str.sub!(/--(\d{2})(\d{2})?\b/, ' ')
       e.mon = $1.to_i
       e.mday = $2.to_i if $2
       true
-    elsif /[,.](\d{2}|\d{4})-\d{3}\b/n !~ str &&
-	str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/n, ' ')
+    elsif /[,.](\d{2}|\d{4})-\d{3}\b/ !~ str &&
+	str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/, ' ')
       e.year = $1.to_i
       e.yday = $2.to_i
       true
-    elsif /\d-\d{3}\b/n !~ str &&
-	str.sub!(/\b-(\d{3})\b/n, ' ')
+    elsif /\d-\d{3}\b/ !~ str &&
+	str.sub!(/\b-(\d{3})\b/, ' ')
       e.yday = $1.to_i
       true
     end
   end
 
   def self._parse_jis(str, e) # :nodoc:
-    if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/in, ' ')
+    if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/i, ' ')
       era = { 'm'=>1867,
 	      't'=>1911,
 	      's'=>1925,
@@ -840,46 +844,46 @@
 
   def self._parse_vms(str, e) # :nodoc:
     if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
-		-('?-?\d+)/inox, ' ')
+		-('?-?\d+)/iox, ' ')
       s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
       true
     elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
-		-('?-?\d+)(?:-('?-?\d+))?/inox, ' ')
+		-('?-?\d+)(?:-('?-?\d+))?/iox, ' ')
       s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
       true
     end
   end
 
   def self._parse_sla(str, e) # :nodoc:
-    if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|n, ' ') # '
+    if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|, ' ') # '
       s3e(e, $1, $2, $3)
       true
     end
   end
 
   def self._parse_dot(str, e) # :nodoc:
-    if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|n, ' ') # '
+    if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|, ' ') # '
       s3e(e, $1, $2, $3)
       true
     end
   end
 
   def self._parse_year(str, e) # :nodoc:
-    if str.sub!(/'(\d+)\b/n, ' ')
+    if str.sub!(/'(\d+)\b/, ' ')
       e.year = $1.to_i
       true
     end
   end
 
   def self._parse_mon(str, e) # :nodoc:
-    if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/ino, ' ')
+    if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/io, ' ')
       e.mon = Format::ABBR_MONTHS[$1.downcase]
       true
     end
   end
 
   def self._parse_mday(str, e) # :nodoc:
-    if str.sub!(/(\d+)(st|nd|rd|th)\b/in, ' ')
+    if str.sub!(/(\d+)(st|nd|rd|th)\b/i, ' ')
       e.mday = $1.to_i
       true
     end
@@ -904,7 +908,7 @@
 		      \[[-+]?\d[^\]]*\]
 		    )
 		  )?
-		/inx,
+		/ix,
 		' ')
       case $2.size
       when 2
@@ -1030,7 +1034,7 @@
 
     e._comp = comp
 
-    str.gsub!(/[^-+',.\/:@[:alnum:]\[\]\x80-\xff]+/n, ' ')
+    str.gsub!(/[^-+',.\/:@[:alnum:]\[\]]+/, ' ')
 
     _parse_time(str, e) # || _parse_beat(str, e)
     _parse_day(str, e)
@@ -1048,13 +1052,13 @@
     _parse_mday(str, e)   ||
     _parse_ddd(str, e)
 
-    if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/in, ' ')
+    if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/i, ' ')
       if e.year
 	e.year = -e.year + 1
       end
     end
 
-    if str.sub!(/\A\s*(\d{1,2})\s*\z/n, ' ')
+    if str.sub!(/\A\s*(\d{1,2})\s*\z/, ' ')
       if e.hour && !e.mday
 	v = $1.to_i
 	if (1..31) === v
@@ -1096,20 +1100,20 @@
 	      -w-\d)
 	(t
 	\d{2}:\d{2}(:\d{2}([,.]\d+)?)?
-	(z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/inx =~ str
+	(z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/ix =~ str
       _parse(str)
     elsif /\A\s*(([-+]?(\d{2}|\d{4})|--)\d{2}\d{2}|
 	      ([-+]?(\d{2}|\d{4}))?\d{3}|-\d{3}|
 	      (\d{2}|\d{4})?w\d{2}\d)
 	(t?
 	\d{2}\d{2}(\d{2}([,.]\d+)?)?
-	(z|[-+]\d{2}(\d{2})?)?)?\s*\z/inx =~ str
+	(z|[-+]\d{2}(\d{2})?)?)?\s*\z/ix =~ str
       _parse(str)
     elsif /\A\s*(\d{2}:\d{2}(:\d{2}([,.]\d+)?)?
-	(z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/inx =~ str
+	(z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/ix =~ str
       _parse(str)
     elsif /\A\s*(\d{2}\d{2}(\d{2}([,.]\d+)?)?
-	(z|[-+]\d{2}(\d{2})?)?)?\s*\z/inx =~ str
+	(z|[-+]\d{2}(\d{2})?)?)?\s*\z/ix =~ str
       _parse(str)
     end
   end
@@ -1118,7 +1122,7 @@
     if /\A\s*-?\d{4}-\d{2}-\d{2} # allow minus, anyway
 	(t|\s)
 	\d{2}:\d{2}:\d{2}(\.\d+)?
-	(z|[-+]\d{2}:\d{2})\s*\z/inx =~ str
+	(z|[-+]\d{2}:\d{2})\s*\z/ix =~ str
       _parse(str)
     end
   end
@@ -1127,7 +1131,7 @@
     if /\A\s*(-?\d{4,})(?:-(\d{2})(?:-(\d{2}))?)?
 	(?:t
 	  (\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?
-	(z|[-+]\d{2}:\d{2})?\s*\z/inx =~ str
+	(z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
       e = Format::Bag.new
       e.year = $1.to_i
       e.mon = $2.to_i if $2
@@ -1142,7 +1146,7 @@
       end
       e.to_hash
     elsif /\A\s*(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?
-	(z|[-+]\d{2}:\d{2})?\s*\z/inx =~ str
+	(z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
       e = Format::Bag.new
       e.hour = $1.to_i if $1
       e.min = $2.to_i if $2
@@ -1154,7 +1158,7 @@
       end
       e.to_hash
     elsif /\A\s*(?:--(\d{2})(?:-(\d{2}))?|---(\d{2}))
-	(z|[-+]\d{2}:\d{2})?\s*\z/inx =~ str
+	(z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
       e = Format::Bag.new
       e.mon = $1.to_i if $1
       e.mday = $2.to_i if $2
@@ -1173,7 +1177,7 @@
 	(?:#{Format::ABBR_MONTHS.keys.join('|')})\s+
 	-?(\d{2,})\s+ # allow minus, anyway
 	\d{2}:\d{2}(:\d{2})?\s*
-	(?:[-+]\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\s*\z/inox =~ str
+	(?:[-+]\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\s*\z/iox =~ str
       e = _parse(str, false)
       if $1.size < 4
 	if e[:year] < 50
@@ -1194,20 +1198,20 @@
 	(#{Format::ABBR_MONTHS.keys.join('|')})\s+
 	-?\d{4}\s+ # allow minus, anyway
 	\d{2}:\d{2}:\d{2}\s+
-	gmt\s*\z/inox =~ str
+	gmt\s*\z/iox =~ str
       _rfc2822(str)
     elsif /\A\s*(#{Format::DAYS.keys.join('|')})\s*,\s+
 	\d{2}\s*-\s*
 	(#{Format::ABBR_MONTHS.keys.join('|')})\s*-\s*
 	\d{2}\s+
 	\d{2}:\d{2}:\d{2}\s+
-	gmt\s*\z/inox =~ str
+	gmt\s*\z/iox =~ str
       _parse(str)
     elsif /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s+
 	(#{Format::ABBR_MONTHS.keys.join('|')})\s+
 	\d{1,2}\s+
 	\d{2}:\d{2}:\d{2}\s+
-	\d{4}\s*\z/inox =~ str
+	\d{4}\s*\z/iox =~ str
       _parse(str)
     end
   end
@@ -1216,7 +1220,7 @@
     if /\A\s*[mtsh]?\d{2}\.\d{2}\.\d{2}
 	(t
 	(\d{2}:\d{2}(:\d{2}([,.]\d*)?)?
-	(z|[-+]\d{2}(:?\d{2})?)?)?)?\s*\z/inx =~ str
+	(z|[-+]\d{2}(:?\d{2})?)?)?)?\s*\z/ix =~ str
       if /\A\s*\d/ =~ str
 	_parse(str.sub(/\A\s*(\d)/, 'h\1'))
       else

Modified: MacRuby/branches/experimental/lib/date.rb
===================================================================
--- MacRuby/branches/experimental/lib/date.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/date.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -193,7 +193,6 @@
 #
 #     puts secs_to_new_year()
 
-require 'rational'
 require 'date/format'
 
 # Class representing a date.
@@ -1471,7 +1470,9 @@
   def hash() @ajd.hash end
 
   # Return internal object state as a programmer-readable string.
-  def inspect() format('#<%s: %s,%s,%s>', self.class, @ajd, @of, @sg) end
+  def inspect
+    format('#<%s: %s (%s,%s,%s)>', self.class, to_s, @ajd, @of, @sg)
+  end
 
   # Return the date as a human-readable string.
   #
@@ -1791,12 +1792,23 @@
   # Create a new Date object representing today.
   #
   # +sg+ specifies the Day of Calendar Reform.
-  def self.today(sg=ITALY) Time.now.to_date    .new_start(sg) end
+  def self.today(sg=ITALY)
+    t = Time.now
+    jd = civil_to_jd(t.year, t.mon, t.mday, sg)
+    new!(jd_to_ajd(jd, 0, 0), 0, sg)
+  end
 
   # Create a new DateTime object representing the current time.
   #
   # +sg+ specifies the Day of Calendar Reform.
-  def self.now  (sg=ITALY) Time.now.to_datetime.new_start(sg) end
+  def self.now(sg=ITALY)
+    t = Time.now
+    jd = civil_to_jd(t.year, t.mon, t.mday, sg)
+    fr = time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) +
+      Rational(t.nsec, 86400_000_000_000)
+    of = Rational(t.utc_offset, 86400)
+    new!(jd_to_ajd(jd, fr, of), of, sg)
+  end
 
   private_class_method :now
 

Modified: MacRuby/branches/experimental/lib/debug.rb
===================================================================
--- MacRuby/branches/experimental/lib/debug.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/debug.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -711,9 +711,6 @@
       end
       @frames.shift
 
-    when 'end'
-      @frames.shift
-
     when 'raise' 
       excn_handle(file, line, id, binding)
 
@@ -901,10 +898,10 @@
 
 stdout.printf "Debug.rb\n"
 stdout.printf "Emacs support available.\n\n"
+RubyVM::InstructionSequence.compile_option = {
+  trace_instruction: true
+}
 set_trace_func proc { |event, file, line, id, binding, klass, *rest|
   DEBUGGER__.context.trace_func event, file, line, id, binding, klass
 }
-VM::InstructionSequence.compile_option = {
-  trace_instruction: true
-}
 end

Modified: MacRuby/branches/experimental/lib/delegate.rb
===================================================================
--- MacRuby/branches/experimental/lib/delegate.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/delegate.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -115,102 +115,87 @@
 # implementation, see SimpleDelegator.
 #
 class Delegator
-  preserved = [
-    :__id__, :object_id, :__send__, :public_send, :respond_to?, :send,
-    :instance_eval, :instance_exec, :extend, :initialize
-  ]
-  instance_methods.each do |m|
-    next if preserved.include?(m)
+  [:to_s,:inspect,:=~,:!~,:===].each do |m|
     undef_method m
   end
 
-  module MethodDelegation
-    #
-    # Pass in the _obj_ to delegate method calls to.  All methods supported by
-    # _obj_ will be delegated to.
-    #
-    def initialize(obj)
-      __setobj__(obj)
-    end
+  #
+  # Pass in the _obj_ to delegate method calls to.  All methods supported by
+  # _obj_ will be delegated to.
+  #
+  def initialize(obj)
+    __setobj__(obj)
+  end
 
-    # Handles the magic of delegation through \_\_getobj\_\_.
-    def method_missing(m, *args, &block)
-      begin
-        target = self.__getobj__
-        unless target.respond_to?(m)
-          super(m, *args, &block)
-        else
-          target.__send__(m, *args, &block)
-        end
-      rescue Exception
-        $@.delete_if{|s| %r"\A#{__FILE__}:\d+:in `method_missing'\z"o =~ s}
-        ::Kernel::raise
+  # Handles the magic of delegation through \_\_getobj\_\_.
+  def method_missing(m, *args, &block)
+    begin
+      target = self.__getobj__
+      unless target.respond_to?(m)
+        super(m, *args, &block)
+      else
+        target.__send__(m, *args, &block)
       end
+    rescue Exception
+      $@.delete_if{|s| %r"\A#{__FILE__}:\d+:in `method_missing'\z"o =~ s}
+      ::Kernel::raise
     end
+  end
 
-    # 
-    # Checks for a method provided by this the delegate object by fowarding the 
-    # call through \_\_getobj\_\_.
-    # 
-    def respond_to?(m, include_private = false)
-      return true if super
-      return self.__getobj__.respond_to?(m, include_private)
-    end
+  # 
+  # Checks for a method provided by this the delegate object by fowarding the 
+  # call through \_\_getobj\_\_.
+  # 
+  def respond_to?(m, include_private = false)
+    return true if super
+    return self.__getobj__.respond_to?(m, include_private)
+  end
 
-    # 
-    # Returns true if two objects are considered same.
-    # 
-    def ==(obj)
-      return true if obj.equal?(self)
-      self.__getobj__ == obj
-    end
+  # 
+  # Returns true if two objects are considered same.
+  # 
+  def ==(obj)
+    return true if obj.equal?(self)
+    self.__getobj__ == obj
+  end
 
-    # 
-    # Returns true only if two objects are identical.
-    # 
-    def equal?(obj)
-      self.object_id == obj.object_id
-    end
+  #
+  # This method must be overridden by subclasses and should return the object
+  # method calls are being delegated to.
+  #
+  def __getobj__
+    raise NotImplementedError, "need to define `__getobj__'"
+  end
 
-    #
-    # This method must be overridden by subclasses and should return the object
-    # method calls are being delegated to.
-    #
-    def __getobj__
-      raise NotImplementedError, "need to define `__getobj__'"
-    end
+  #
+  # This method must be overridden by subclasses and change the object delegate
+  # to _obj_.
+  #
+  def __setobj__(obj)
+    raise NotImplementedError, "need to define `__setobj__'"
+  end
 
-    #
-    # This method must be overridden by subclasses and change the object delegate
-    # to _obj_.
-    #
-    def __setobj__(obj)
-      raise NotImplementedError, "need to define `__setobj__'"
-    end
+  # Serialization support for the object returned by \_\_getobj\_\_.
+  def marshal_dump
+    __getobj__
+  end
+  # Reinitializes delegation from a serialized object.
+  def marshal_load(obj)
+    __setobj__(obj)
+  end
 
-    # Serialization support for the object returned by \_\_getobj\_\_.
-    def marshal_dump
-      __getobj__
-    end
-    # Reinitializes delegation from a serialized object.
-    def marshal_load(obj)
-      __setobj__(obj)
-    end
-
-    # Clone support for the object returned by \_\_getobj\_\_.
-    def clone
-      new = super
-      new.__setobj__(__getobj__.clone)
-      new
-    end
-    # Duplication support for the object returned by \_\_getobj\_\_.
-    def dup
-      new = super
-      new.__setobj__(__getobj__.dup)
-      new
-    end
+  # Clone support for the object returned by \_\_getobj\_\_.
+  def clone
+    new = super
+    new.__setobj__(__getobj__.clone)
+    new
   end
-  include MethodDelegation
+  # Duplication support for the object returned by \_\_getobj\_\_.
+  def dup
+    new = super
+    new.__setobj__(__getobj__.dup)
+    new
+  end
 end
 
 #
@@ -249,7 +234,7 @@
 def Delegator.delegating_block(mid)
   lambda do |*args, &block|
     begin
-      @delegate_dc_obj.__send__(mid, *args, &block)
+      __getobj__.__send__(mid, *args, &block)
     rescue
       re = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:/o
       $!.backtrace.delete_if {|t| re =~ t}
@@ -264,22 +249,17 @@
 # your class.
 #
 #   class MyClass < DelegateClass( ClassToDelegateTo )    # Step 1
-#     def initiaize
+#     def initialize
 #       super(obj_of_ClassToDelegateTo)                   # Step 2
 #     end
 #   end
 #
 def DelegateClass(superclass)
-  klass = Class.new
+  klass = Class.new(Delegator)
   methods = superclass.public_instance_methods(true)
-  methods -= [
-    :__id__, :object_id, :__send__, :public_send, :respond_to?, :send,
-    :==, :equal?, :initialize, :method_missing, :__getobj__, :__setobj__,
-    :clone, :dup, :marshal_dump, :marshal_load, :instance_eval, :instance_exec,
-    :extend,
-  ]
+  methods -= ::Delegator.public_instance_methods
+  methods -= [:to_s,:inspect,:=~,:!~,:===]
   klass.module_eval {
-    include Delegator::MethodDelegation
     def __getobj__  # :nodoc:
       @delegate_dc_obj
     end

Modified: MacRuby/branches/experimental/lib/drb/drb.rb
===================================================================
--- MacRuby/branches/experimental/lib/drb/drb.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/drb/drb.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1208,6 +1208,7 @@
     end
 
     def alive?  # :nodoc:
+      return false unless @protocol
       @protocol.alive?
     end
   end

Modified: MacRuby/branches/experimental/lib/e2mmap.rb
===================================================================
--- MacRuby/branches/experimental/lib/e2mmap.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/e2mmap.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -105,7 +105,7 @@
   # {[class, exp] => message, ...}
   @MessageMap = {}
 
-  # E2MM.def_exception(k, e, m)
+  # E2MM.def_e2message(k, e, m)
   #	    k:  class to define exception under.
   #	    e:  exception
   #	    m:  message_form

Modified: MacRuby/branches/experimental/lib/erb.rb
===================================================================
--- MacRuby/branches/experimental/lib/erb.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/erb.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -10,237 +10,255 @@
 #
 # You can redistribute it and/or modify it under the same terms as Ruby.
 
-#
-# = ERB -- Ruby Templating
-#
-# == Introduction
-#
-# ERB provides an easy to use but powerful templating system for Ruby.  Using
-# ERB, actual Ruby code can be added to any plain text document for the
-# purposes of generating document information details and/or flow control.
-#
-# A very simple example is this:
-# 
-#   require 'erb'
-#
-#   x = 42
-#   template = ERB.new <<-EOF
-#     The value of x is: <%= x %>
-#   EOF
-#   puts template.result(binding)
-#
-# <em>Prints:</em> The value of x is: 42
-#
-# More complex examples are given below.
-#
-#
-# == Recognized Tags
-#
-# ERB recognizes certain tags in the provided template and converts them based
-# on the rules below:
-#
-#   <% Ruby code -- inline with output %>
-#   <%= Ruby expression -- replace with result %>
-#   <%# comment -- ignored -- useful in testing %>
-#   % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
-#   %% replaced with % if first thing on a line and % processing is used
-#   <%% or %%> -- replace with <% or %> respectively
-#
-# All other text is passed through ERB filtering unchanged.
-#
-#
-# == Options
-#
-# There are several settings you can change when you use ERB:
-# * the nature of the tags that are recognized;
-# * the value of <tt>$SAFE</tt> under which the template is run;
-# * the binding used to resolve local variables in the template.
-#
-# See the ERB.new and ERB#result methods for more detail.
-#
-#
-# == Examples
-#
-# === Plain Text
-#
-# ERB is useful for any generic templating situation.  Note that in this example, we use the
-# convenient "% at start of line" tag, and we quote the template literally with
-# <tt>%q{...}</tt> to avoid trouble with the backslash.
-#
-#   require "erb"
-#   
-#   # Create template.
-#   template = %q{
-#     From:  James Edward Gray II <james at grayproductions.net>
-#     To:  <%= to %>
-#     Subject:  Addressing Needs
-#   
-#     <%= to[/\w+/] %>:
-#   
-#     Just wanted to send a quick note assuring that your needs are being
-#     addressed.
-#   
-#     I want you to know that my team will keep working on the issues,
-#     especially:
-#   
-#     <%# ignore numerous minor requests -- focus on priorities %>
-#     % priorities.each do |priority|
-#       * <%= priority %>
-#     % end
-#   
-#     Thanks for your patience.
-#   
-#     James Edward Gray II
-#   }.gsub(/^  /, '')
-#   
-#   message = ERB.new(template, 0, "%<>")
-#   
-#   # Set up template data.
-#   to = "Community Spokesman <spokesman at ruby_community.org>"
-#   priorities = [ "Run Ruby Quiz",
-#                  "Document Modules",
-#                  "Answer Questions on Ruby Talk" ]
-#   
-#   # Produce result.
-#   email = message.result
-#   puts email
-#
-# <i>Generates:</i>
-#
-#   From:  James Edward Gray II <james at grayproductions.net>
-#   To:  Community Spokesman <spokesman at ruby_community.org>
-#   Subject:  Addressing Needs
-#   
-#   Community:
-#   
-#   Just wanted to send a quick note assuring that your needs are being addressed.
-#   
-#   I want you to know that my team will keep working on the issues, especially:
-#   
-#       * Run Ruby Quiz
-#       * Document Modules
-#       * Answer Questions on Ruby Talk
-#   
-#   Thanks for your patience.
-#   
-#   James Edward Gray II
-#
-# === Ruby in HTML
-#
-# ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby).  Notice the need in
-# this example to provide a special binding when the template is run, so that the instance
-# variables in the Product object can be resolved.
-#
-#   require "erb"
-#   
-#   # Build template data class.
-#   class Product
-#     def initialize( code, name, desc, cost )
-#       @code = code
-#       @name = name
-#       @desc = desc
-#       @cost = cost
-#        	
-#       @features = [ ]
-#     end
-#   
-#     def add_feature( feature )
-#       @features << feature
-#     end
-#   
-#     # Support templating of member data.
-#     def get_binding
-#       binding
-#     end
-#   
-#     # ...
-#   end
-#   
-#   # Create template.
-#   template = %{
-#     <html>
-#       <head><title>Ruby Toys -- <%= @name %></title></head>
-#       <body>
-#   
-#         <h1><%= @name %> (<%= @code %>)</h1>
-#         <p><%= @desc %></p>
-#   
-#         <ul>
-#           <% @features.each do |f| %>
-#             <li><b><%= f %></b></li>
-#           <% end %>
-#         </ul>
-#   
-#         <p>
-#           <% if @cost < 10 %>
-#             <b>Only <%= @cost %>!!!</b>
-#           <% else %>
-#              Call for a price, today!
-#           <% end %>
-#         </p>
-#    
-#       </body>
-#     </html>
-#   }.gsub(/^  /, '')
-#   
-#   rhtml = ERB.new(template)
-#   
-#   # Set up template data.
-#   toy = Product.new( "TZ-1002",
-#                      "Rubysapien",
-#                      "Geek's Best Friend!  Responds to Ruby commands...",
-#                      999.95 )
-#   toy.add_feature("Listens for verbal commands in the Ruby language!")
-#   toy.add_feature("Ignores Perl, Java, and all C variants.")
-#   toy.add_feature("Karate-Chop Action!!!")
-#   toy.add_feature("Matz signature on left leg.")
-#   toy.add_feature("Gem studded eyes... Rubies, of course!")
-#   
-#   # Produce result.
-#   rhtml.run(toy.get_binding)
-#
-# <i>Generates (some blank lines removed):</i>
-#
-#    <html>
-#      <head><title>Ruby Toys -- Rubysapien</title></head>
-#      <body>
-#    
-#        <h1>Rubysapien (TZ-1002)</h1>
-#        <p>Geek's Best Friend!  Responds to Ruby commands...</p>
-#    
-#        <ul>
-#            <li><b>Listens for verbal commands in the Ruby language!</b></li>
-#            <li><b>Ignores Perl, Java, and all C variants.</b></li>
-#            <li><b>Karate-Chop Action!!!</b></li>
-#            <li><b>Matz signature on left leg.</b></li>
-#            <li><b>Gem studded eyes... Rubies, of course!</b></li>
-#        </ul>
-#    
-#        <p>
-#             Call for a price, today!
-#        </p>
-#    
-#      </body>
-#    </html>
-#
-# 
-# == Notes
-#
-# There are a variety of templating solutions available in various Ruby projects:
-# * ERB's big brother, eRuby, works the same but is written in C for speed;
-# * Amrita (smart at producing HTML/XML);
-# * cs/Template (written in C for speed);
-# * RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere;
-# * and others; search the RAA.
-#
-# Rails, the web application framework, uses ERB to create views.
-#
+=begin rdoc
+= ERB -- Ruby Templating
+
+== Introduction
+
+ERB provides an easy to use but powerful templating system for Ruby.  Using
+ERB, actual Ruby code can be added to any plain text document for the
+purposes of generating document information details and/or flow control.
+
+A very simple example is this:
+
+  require 'erb'
+
+  x = 42
+  template = ERB.new <<-EOF
+    The value of x is: <%= x %>
+  EOF
+  puts template.result(binding)
+
+<em>Prints:</em> The value of x is: 42
+
+More complex examples are given below.
+
+
+== Recognized Tags
+
+ERB recognizes certain tags in the provided template and converts them based
+on the rules below:
+
+  <% Ruby code -- inline with output %>
+  <%= Ruby expression -- replace with result %>
+  <%# comment -- ignored -- useful in testing %>
+  % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
+  %% replaced with % if first thing on a line and % processing is used
+  <%% or %%> -- replace with <% or %> respectively
+
+All other text is passed through ERB filtering unchanged.
+
+
+== Options
+
+There are several settings you can change when you use ERB:
+* the nature of the tags that are recognized;
+* the value of <tt>$SAFE</tt> under which the template is run;
+* the binding used to resolve local variables in the template.
+
+See the ERB.new and ERB#result methods for more detail.
+
+== Character encodings
+
+ERB (or ruby code generated by ERB) returns a string in the same
+character encoding as the input string.  When the input string has
+a magic comment, however, it returns a string in the encoding specified
+by the magic comment.
+
+  # -*- coding: UTF-8 -*-
+  require 'erb'
+
+  template = ERB.new <<EOF
+  <%#-*- coding: Big5 -*-%>
+    \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
+  EOF
+  puts template.result
+
+<em>Prints:</em> \_\_ENCODING\_\_ is Big5.
+
+
+== Examples
+
+=== Plain Text
+
+ERB is useful for any generic templating situation.  Note that in this example, we use the
+convenient "% at start of line" tag, and we quote the template literally with
+<tt>%q{...}</tt> to avoid trouble with the backslash.
+
+  require "erb"
+  
+  # Create template.
+  template = %q{
+    From:  James Edward Gray II <james at grayproductions.net>
+    To:  <%= to %>
+    Subject:  Addressing Needs
+  
+    <%= to[/\w+/] %>:
+  
+    Just wanted to send a quick note assuring that your needs are being
+    addressed.
+  
+    I want you to know that my team will keep working on the issues,
+    especially:
+  
+    <%# ignore numerous minor requests -- focus on priorities %>
+    % priorities.each do |priority|
+      * <%= priority %>
+    % end
+  
+    Thanks for your patience.
+  
+    James Edward Gray II
+  }.gsub(/^  /, '')
+  
+  message = ERB.new(template, 0, "%<>")
+  
+  # Set up template data.
+  to = "Community Spokesman <spokesman at ruby_community.org>"
+  priorities = [ "Run Ruby Quiz",
+                 "Document Modules",
+                 "Answer Questions on Ruby Talk" ]
+  
+  # Produce result.
+  email = message.result
+  puts email
+
+<i>Generates:</i>
+
+  From:  James Edward Gray II <james at grayproductions.net>
+  To:  Community Spokesman <spokesman at ruby_community.org>
+  Subject:  Addressing Needs
+  
+  Community:
+  
+  Just wanted to send a quick note assuring that your needs are being addressed.
+  
+  I want you to know that my team will keep working on the issues, especially:
+  
+      * Run Ruby Quiz
+      * Document Modules
+      * Answer Questions on Ruby Talk
+  
+  Thanks for your patience.
+  
+  James Edward Gray II
+
+=== Ruby in HTML
+
+ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby).  Notice the need in
+this example to provide a special binding when the template is run, so that the instance
+variables in the Product object can be resolved.
+
+  require "erb"
+  
+  # Build template data class.
+  class Product
+    def initialize( code, name, desc, cost )
+      @code = code
+      @name = name
+      @desc = desc
+      @cost = cost
+       	
+      @features = [ ]
+    end
+  
+    def add_feature( feature )
+      @features << feature
+    end
+  
+    # Support templating of member data.
+    def get_binding
+      binding
+    end
+  
+    # ...
+  end
+  
+  # Create template.
+  template = %{
+    <html>
+      <head><title>Ruby Toys -- <%= @name %></title></head>
+      <body>
+  
+        <h1><%= @name %> (<%= @code %>)</h1>
+        <p><%= @desc %></p>
+  
+        <ul>
+          <% @features.each do |f| %>
+            <li><b><%= f %></b></li>
+          <% end %>
+        </ul>
+  
+        <p>
+          <% if @cost < 10 %>
+            <b>Only <%= @cost %>!!!</b>
+          <% else %>
+             Call for a price, today!
+          <% end %>
+        </p>
+   
+      </body>
+    </html>
+  }.gsub(/^  /, '')
+  
+  rhtml = ERB.new(template)
+  
+  # Set up template data.
+  toy = Product.new( "TZ-1002",
+                     "Rubysapien",
+                     "Geek's Best Friend!  Responds to Ruby commands...",
+                     999.95 )
+  toy.add_feature("Listens for verbal commands in the Ruby language!")
+  toy.add_feature("Ignores Perl, Java, and all C variants.")
+  toy.add_feature("Karate-Chop Action!!!")
+  toy.add_feature("Matz signature on left leg.")
+  toy.add_feature("Gem studded eyes... Rubies, of course!")
+  
+  # Produce result.
+  rhtml.run(toy.get_binding)
+
+<i>Generates (some blank lines removed):</i>
+
+   <html>
+     <head><title>Ruby Toys -- Rubysapien</title></head>
+     <body>
+   
+       <h1>Rubysapien (TZ-1002)</h1>
+       <p>Geek's Best Friend!  Responds to Ruby commands...</p>
+   
+       <ul>
+           <li><b>Listens for verbal commands in the Ruby language!</b></li>
+           <li><b>Ignores Perl, Java, and all C variants.</b></li>
+           <li><b>Karate-Chop Action!!!</b></li>
+           <li><b>Matz signature on left leg.</b></li>
+           <li><b>Gem studded eyes... Rubies, of course!</b></li>
+       </ul>
+   
+       <p>
+            Call for a price, today!
+       </p>
+   
+     </body>
+   </html>
+
+
+== Notes
+
+There are a variety of templating solutions available in various Ruby projects:
+* ERB's big brother, eRuby, works the same but is written in C for speed;
+* Amrita (smart at producing HTML/XML);
+* cs/Template (written in C for speed);
+* RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere;
+* and others; search the RAA.
+
+Rails, the web application framework, uses ERB to create views.
+=end
 class ERB
-  Revision = '$Date:: 2008-06-02 00:15:12 -0700#$' 	#'
+  Revision = '$Date:: 2009-01-17 07:20:08 -0500#$' 	#'
 
   # Returns revision information for the erb.rb module.
   def self.version
-    "erb.rb [2.0.4 #{ERB::Revision.split[1]}]"
+    "erb.rb [2.1.0 #{ERB::Revision.split[1]}]"
   end
 end
 
@@ -254,11 +272,13 @@
       end
       attr_reader :value
       alias :to_s :value
+
+      def empty?
+        @value.empty?
+      end
     end
 
     class Scanner # :nodoc:
-      SplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
-
       @scanner_map = {}
       def self.regist_scanner(klass, trim_mode, percent)
 	@scanner_map[[trim_mode, percent]] = klass
@@ -283,8 +303,6 @@
     end
 
     class TrimScanner < Scanner # :nodoc:
-      TrimSplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>\n)|(%>)|(\n)/
-
       def initialize(src, trim_mode, percent)
 	super
 	@trim_mode = trim_mode
@@ -308,9 +326,7 @@
 	    percent_line(line, &block)
 	  end
 	else
-	  @src.each_line do |line|
-	    @scan_line.call(line, &block)
-	  end
+          @scan_line.call(@src, &block)
 	end
 	nil
       end
@@ -329,57 +345,66 @@
       end
 
       def scan_line(line)
-	line.split(SplitRegexp).each do |token|
-	  next if token.empty?
-	  yield(token)
+        line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            yield(token)
+          end
 	end
       end
 
       def trim_line1(line)
-	line.split(TrimSplitRegexp).each do |token|
-	  next if token.empty?
-	  if token == "%>\n"
-	    yield('%>')
-	    yield(:cr)
-	    break
-	  end
-	  yield(token)
+        line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            if token == "%>\n"
+              yield('%>')
+              yield(:cr)
+            else
+              yield(token)
+            end
+          end
 	end
       end
 
       def trim_line2(line)
 	head = nil
-	line.split(TrimSplitRegexp).each do |token|
-	  next if token.empty?
-	  head = token unless head
-	  if token == "%>\n"
-	    yield('%>')
-	    if  is_erb_stag?(head)
-	      yield(:cr)
-	    else
-	      yield("\n")
-	    end
-	    break
-	  end
-	  yield(token)
+        line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            head = token unless head
+            if token == "%>\n"
+              yield('%>')
+              if is_erb_stag?(head)
+                yield(:cr)
+              else
+                yield("\n")
+              end
+              head = nil
+            else
+              yield(token)
+              head = nil if token == "\n"
+            end
+          end
 	end
       end
 
-      ExplicitTrimRegexp = /(^[ \t]*<%-)|(-%>\n?\z)|(<%-)|(-%>)|(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
       def explicit_trim_line(line)
-	line.split(ExplicitTrimRegexp).each do |token|
-	  next if token.empty?
-	  if @stag.nil? && /[ \t]*<%-/ =~ token
-	    yield('<%')
-	  elsif @stag && /-%>\n/ =~ token
-	    yield('%>')
-	    yield(:cr)
-	  elsif @stag && token == '-%>'
-	    yield('%>')
-	  else
-	    yield(token)
-	  end
-	end
+        line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            if @stag.nil? && /[ \t]*<%-/ =~ token
+              yield('<%')
+            elsif @stag && token == "-%>\n"
+              yield('%>')
+              yield(:cr)
+            elsif @stag && token == '-%>'
+              yield('%>')
+            else
+              yield(token)
+            end
+          end
+        end
       end
 
       ERB_STAG = %w(<%= <%# <%)
@@ -392,11 +417,11 @@
 
     class SimpleScanner < Scanner # :nodoc:
       def scan
-	@src.each_line do |line|
-	  line.split(SplitRegexp).each do |token|
-	    next if token.empty?
-	    yield(token)
-	  end
+        @src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+          tokens.each do |token|
+            next if token.empty?
+            yield(token)
+          end
 	end
       end
     end
@@ -407,75 +432,35 @@
       require 'strscan'
       class SimpleScanner2 < Scanner # :nodoc:
         def scan
-          stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
-          etag_reg = /(.*?)(%%>|%>|\n|\z)/
+          stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m
+          etag_reg = /(.*?)(%%>|%>|\z)/m
           scanner = StringScanner.new(@src)
           while ! scanner.eos?
             scanner.scan(@stag ? etag_reg : stag_reg)
-            text = scanner[1]
-            elem = scanner[2]
-            yield(text) unless text.empty?
-            yield(elem) unless elem.empty?
+            yield(scanner[1])
+            yield(scanner[2])
           end
         end
       end
       Scanner.regist_scanner(SimpleScanner2, nil, false)
 
-      class PercentScanner < Scanner # :nodoc:
+      class ExplicitScanner < Scanner # :nodoc:
 	def scan
-	  new_line = true
-          stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
-          etag_reg = /(.*?)(%%>|%>|\n|\z)/
+          stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m
+          etag_reg = /(.*?)(%%>|-%>|%>|\z)/m
           scanner = StringScanner.new(@src)
           while ! scanner.eos?
-	    if new_line && @stag.nil?
-	      if scanner.scan(/%%/)
-		yield('%')
-		new_line = false
-		next
-	      elsif scanner.scan(/%/)
-		yield(PercentLine.new(scanner.scan(/.*?(\n|\z)/).chomp))
-		next
-	      end
-	    end
 	    scanner.scan(@stag ? etag_reg : stag_reg)
-            text = scanner[1]
-            elem = scanner[2]
-            yield(text) unless text.empty?
-            yield(elem) unless elem.empty?
-	    new_line = (elem == "\n")
-          end
-        end
-      end
-      Scanner.regist_scanner(PercentScanner, nil, true)
+            yield(scanner[1])
 
-      class ExplicitScanner < Scanner # :nodoc:
-	def scan
-	  new_line = true
-          stag_reg = /(.*?)(<%%|<%=|<%#|<%-|<%|\n|\z)/
-          etag_reg = /(.*?)(%%>|-%>|%>|\n|\z)/
-          scanner = StringScanner.new(@src)
-          while ! scanner.eos?
-	    if new_line && @stag.nil? && scanner.scan(/[ \t]*<%-/)
-	      yield('<%')
-	      new_line = false
-	      next
-	    end
-	    scanner.scan(@stag ? etag_reg : stag_reg)
-            text = scanner[1]
             elem = scanner[2]
-	    new_line = (elem == "\n")
-            yield(text) unless text.empty?
-	    if elem == '-%>'
+            if /[ \t]*<%-/ =~ elem
+              yield('<%')
+            elsif elem == '-%>'
 	      yield('%>')
-	      if scanner.scan(/(\n|\z)/)
-		yield(:cr)
-		new_line = true
-	      end
-	    elsif elem == '<%-'
-	      yield('<%')
+	      yield(:cr) if scanner.scan(/(\n|\z)/)
 	    else
-	      yield(elem) unless elem.empty?
+	      yield(elem)
 	    end
           end
         end
@@ -486,10 +471,10 @@
     end
 
     class Buffer # :nodoc:
-      def initialize(compiler)
+      def initialize(compiler, enc=nil)
 	@compiler = compiler
 	@line = []
-	@script = ""
+        @script = enc ? "#coding:#{enc.to_s}\n" : ""
 	@compiler.pre_cmd.each do |x|
 	  push(x)
 	end
@@ -516,16 +501,31 @@
       end
     end
 
+    def content_dump(s)
+      n = s.count("\n")
+      if n > 0
+        s.dump + "\n" * n
+      else
+        s.dump
+      end
+    end
+
     def compile(s)
-      out = Buffer.new(self)
+      enc = s.encoding
+      raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy?
+      s = s.dup.force_encoding("ASCII-8BIT") # don't use constant Enoding::ASCII_8BIT for miniruby
+      enc = detect_magic_comment(s) || enc
+      out = Buffer.new(self, enc)
 
       content = ''
       scanner = make_scanner(s)
       scanner.scan do |token|
+        next if token.nil? 
+        next if token == ''
 	if scanner.stag.nil?
 	  case token
           when PercentLine
-	    out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+	    out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
 	    content = ''
             out.push(token.to_s)
             out.cr
@@ -533,12 +533,11 @@
 	    out.cr
 	  when '<%', '<%=', '<%#'
 	    scanner.stag = token
-	    out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+	    out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
 	    content = ''
 	  when "\n"
 	    content << "\n"
-	    out.push("#{@put_cmd} #{content.dump}")
-	    out.cr
+	    out.push("#{@put_cmd} #{content_dump(content)}")
 	    content = ''
 	  when '<%%'
 	    content << '<%'
@@ -560,7 +559,7 @@
 	    when '<%='
 	      out.push("#{@insert_cmd}((#{content}).to_s)")
 	    when '<%#'
-	      # out.push("# #{content.dump}")
+	      # out.push("# #{content_dump(content)}")
 	    end
 	    scanner.stag = nil
 	    content = ''
@@ -571,9 +570,9 @@
 	  end
 	end
       end
-      out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+      out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
       out.close
-      out.script
+      return out.script, enc
     end
 
     def prepare_trim_mode(mode)
@@ -613,6 +612,18 @@
     end
     attr_reader :percent, :trim_mode
     attr_accessor :put_cmd, :insert_cmd, :pre_cmd, :post_cmd
+
+    private
+    def detect_magic_comment(s)
+      if /\A<%#(.*)%>/ =~ s or (@percent and /\A%#(.*)/ =~ s)
+	comment = $1
+	comment = $1 if comment[/-\*-\s*(.*?)\s*-*-$/]
+	if %r"coding\s*[=:]\s*([[:alnum:]\-_]+)" =~ comment
+	  enc = $1.sub(/-(?:mac|dos|unix)/i, '')
+	  enc = Encoding.find(enc)
+	end
+      end
+    end
   end
 end
 
@@ -658,7 +669,7 @@
   #    
   #    def build
   #      b = binding
-  #      # create and run templates, filling member data variebles
+  #      # create and run templates, filling member data variables
   #      ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), 0, "", "@product").result b
   #        <%= PRODUCT[:name] %>
   #        <%= PRODUCT[:desc] %>
@@ -688,7 +699,7 @@
     @safe_level = safe_level
     compiler = ERB::Compiler.new(trim_mode)
     set_eoutvar(compiler, eoutvar)
-    @src = compiler.compile(str)
+    @src, @enc = *compiler.compile(str)
     @filename = nil
   end
 
@@ -714,7 +725,7 @@
     compiler.pre_cmd = cmd
 
     cmd = []
-    cmd.push(eoutvar)
+    cmd.push("#{eoutvar}.force_encoding(__ENCODING__)")
 
     compiler.post_cmd = cmd
   end
@@ -734,29 +745,62 @@
   #
   def result(b=TOPLEVEL_BINDING)
     if @safe_level
-      th = Thread.start { 
+      proc { 
 	$SAFE = @safe_level
-	eval(@src, b, (@filename || '(erb)'), 1)
-      }
-      return th.value
+	eval(@src, b, (@filename || '(erb)'), 0)
+      }.call
     else
-      return eval(@src, b, (@filename || '(erb)'), 1)
+      eval(@src, b, (@filename || '(erb)'), 0)
     end
   end
 
-  def def_method(mod, methodname, fname='(ERB)')  # :nodoc:
-    mod.module_eval("def #{methodname}\n" + self.src + "\nend\n", fname, 0)
+  # Define _methodname_ as instance method of _mod_ from compiled ruby source.
+  #
+  # example:
+  #   filename = 'example.rhtml'   # 'arg1' and 'arg2' are used in example.rhtml
+  #   erb = ERB.new(File.read(filename))
+  #   erb.def_method(MyClass, 'render(arg1, arg2)', filename)
+  #   print MyClass.new.render('foo', 123)
+  def def_method(mod, methodname, fname='(ERB)')
+    src = self.src
+    magic_comment = "#coding:#{@enc}\n"
+    mod.module_eval do
+      eval(magic_comment + "def #{methodname}\n" + src + "\nend\n", binding, fname, -2)
+    end
   end
 
-  def def_module(methodname='erb')  # :nodoc:
+  # Create unnamed module, define _methodname_ as instance method of it, and return it.
+  #
+  # example:
+  #   filename = 'example.rhtml'   # 'arg1' and 'arg2' are used in example.rhtml
+  #   erb = ERB.new(File.read(filename))
+  #   erb.filename = filename
+  #   MyModule = erb.def_module('render(arg1, arg2)')
+  #   class MyClass
+  #     include MyModule
+  #   end
+  def def_module(methodname='erb')
     mod = Module.new
-    def_method(mod, methodname)
+    def_method(mod, methodname, @filename || '(ERB)')
     mod
   end
 
-  def def_class(superklass=Object, methodname='result')  # :nodoc:
+  # Define unnamed class which has _methodname_ as instance method, and return it.
+  #
+  # example:
+  #   class MyClass_
+  #     def initialize(arg1, arg2)
+  #       @arg1 = arg1;  @arg2 = arg2
+  #     end
+  #   end
+  #   filename = 'example.rhtml'  # @arg1 and @arg2 are used in example.rhtml
+  #   erb = ERB.new(File.read(filename))
+  #   erb.filename = filename
+  #   MyClass = erb.def_class(MyClass_, 'render()')
+  #   print MyClass.new('foo', 123).render()
+  def def_class(superklass=Object, methodname='result')
     cls = Class.new(superklass)
-    def_method(cls, methodname)
+    def_method(cls, methodname, @filename || '(ERB)')
     cls
   end
 end
@@ -812,15 +856,45 @@
 #--
 # ERB::DefMethod
 class ERB
-  module DefMethod  # :nodoc:
+  # Utility module to define eRuby script as instance method.
+  #
+  # === Example
+  #
+  # example.rhtml:
+  #   <% for item in @items %>
+  #   <b><%= item %></b>
+  #   <% end %>
+  #
+  # example.rb:
+  #   require 'erb'
+  #   class MyClass
+  #     extend ERB::DefMethod
+  #     def_erb_method('render()', 'example.rhtml')
+  #     def initialize(items)
+  #       @items = items
+  #     end
+  #   end
+  #   print MyClass.new([10,20,30]).render()
+  #
+  # result:
+  #
+  #   <b>10</b>
+  #
+  #   <b>20</b>
+  #
+  #   <b>30</b>
+  #
+  module DefMethod
     public
-    def def_erb_method(methodname, erb)
-      if erb.kind_of? String
-	fname = erb
-	File.open(fname) {|f| erb = ERB.new(f.read) }
-	erb.def_method(self, methodname, fname)
+  # define _methodname_ as instance method of current module, using ERB object or eRuby file
+    def def_erb_method(methodname, erb_or_fname)
+      if erb_or_fname.kind_of? String
+        fname = erb_or_fname
+        erb = ERB.new(File.read(fname))
+        erb.def_method(self, methodname, fname)
       else
-	erb.def_method(self, methodname)
+        erb = erb_or_fname
+        erb.def_method(self, methodname, erb.filename || '(ERB)')
       end
     end
     module_function :def_erb_method

Modified: MacRuby/branches/experimental/lib/fileutils.rb
===================================================================
--- MacRuby/branches/experimental/lib/fileutils.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/fileutils.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -258,15 +258,24 @@
   def rmdir(list, options = {})
     fu_check_options options, OPT_TABLE['rmdir']
     list = fu_list(list)
-    fu_output_message "rmdir #{list.join ' '}" if options[:verbose]
+    parents = options[:parents]
+    fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if options[:verbose]
     return if options[:noop]
     list.each do |dir|
-      Dir.rmdir dir.sub(%r</\z>, '')
+      begin
+        Dir.rmdir(dir = dir.sub(%r</\z>, ''))
+        if parents
+          until (parent = File.dirname(dir)) == '.' or parent == dir
+            Dir.rmdir(dir)
+          end
+        end
+      rescue Errno::ENOTEMPTY, Errno::ENOENT
+      end
     end
   end
   module_function :rmdir
 
-  OPT_TABLE['rmdir'] = [:noop, :verbose]
+  OPT_TABLE['rmdir'] = [:parents, :noop, :verbose]
 
   #
   # Options: force noop verbose
@@ -470,7 +479,7 @@
   # +dest+ must respond to #write(str).
   #
   def copy_stream(src, dest)
-    fu_copy_stream0 src, dest, fu_stream_blksize(src, dest)
+    IO.copy_stream(src, dest)
   end
   module_function :copy_stream
 
@@ -524,7 +533,7 @@
   OPT_TABLE['move'] = [:force, :noop, :verbose, :secure]
 
   def rename_cannot_overwrite_file?   #:nodoc:
-    /djgpp|cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
+    /cygwin|mswin|mingw|bccwin|emx/ =~ RUBY_PLATFORM
   end
   private_module_function :rename_cannot_overwrite_file?
 
@@ -1041,14 +1050,11 @@
     private
 
     def fu_windows?
-      /mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
+      /mswin|mingw|bccwin|emx/ =~ RUBY_PLATFORM
     end
 
-    def fu_copy_stream0(src, dest, blksize)   #:nodoc:
-      # FIXME: readpartial?
-      while s = src.read(blksize)
-        dest.write s
-      end
+    def fu_copy_stream0(src, dest, blksize = nil)   #:nodoc:
+      IO.copy_stream(src, dest)
     end
 
     def fu_stream_blksize(*streams)
@@ -1254,12 +1260,7 @@
     end
 
     def copy_file(dest)
-      st = stat()
-      File.open(path(),  'rb') {|r|
-        File.open(dest, 'wb', st.mode) {|w|
-          fu_copy_stream0 r, w, (fu_blksize(st) || fu_default_blksize())
-        }
-      }
+      IO.copy_stream(path(),  dest)
     end
 
     def copy_metadata(path)
@@ -1507,8 +1508,7 @@
   end
 
   METHODS = singleton_methods() - [:private_module_function,
-      :commands, :options, :have_option?, :options_of, 
-      :collect_method]
+      :commands, :options, :have_option?, :options_of, :collect_method]
 
   # 
   # This module has all methods of FileUtils module, but it outputs messages

Modified: MacRuby/branches/experimental/lib/find.rb
===================================================================
--- MacRuby/branches/experimental/lib/find.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/find.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -33,6 +33,8 @@
   # See the +Find+ module documentation for an example.
   #
   def find(*paths) # :yield: path
+    block_given? or return enum_for(__method__, *paths)
+
     paths.collect!{|d| raise Errno::ENOENT unless File.exist?(d); d.dup}
     while file = paths.shift
       catch(:prune) do

Modified: MacRuby/branches/experimental/lib/forwardable.rb
===================================================================
--- MacRuby/branches/experimental/lib/forwardable.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/forwardable.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   forwardable.rb - 
 #   	$Release Version: 1.1$
-#   	$Revision: 14912 $
+#   	$Revision: 16810 $
 #   	by Keiju ISHITSUKA(keiju at ishitsuka.com)
 #	original definition by delegator.rb
 #       Revised by Daniel J. Berger with suggestions from Florian Gross.
@@ -38,7 +38,7 @@
 #       @q = [ ]    # prepare delegate object
 #     end
 #     
-#     # setup prefered interface, enq() and deq()...
+#     # setup preferred interface, enq() and deq()...
 #     def_delegator :@q, :push, :enq
 #     def_delegator :@q, :shift, :deq
 #     

Modified: MacRuby/branches/experimental/lib/gserver.rb
===================================================================
--- MacRuby/branches/experimental/lib/gserver.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/gserver.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -40,7 +40,7 @@
 #       super(port, *args)
 #     end
 #     def serve(io)
-#       io.puts(Time.now.to_i)
+#       io.puts(Time.now.to_s)
 #     end
 #   end
 #

Modified: MacRuby/branches/experimental/lib/hotcocoa/delegate_builder.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/delegate_builder.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/delegate_builder.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -19,6 +19,12 @@
       set_delegate if required_methods.empty?
     end
     
+    def delegate_to(object, *method_names)
+      method_names.each do |method_name|
+        control.send(method_name, &object.method(method_name)) if object.respond_to?(method_name)
+      end
+    end
+    
     private 
     
       def increment_method_count

Modified: MacRuby/branches/experimental/lib/hotcocoa/graphics/canvas.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/graphics/canvas.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/graphics/canvas.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -166,7 +166,7 @@
     # set the current fill (given a Color object, or RGBA values)
     def fill(r=0, g=0, b=0, a=1)
       case r
-      when Graphics::Color
+      when Color
         g = r.g
         b = r.b
         a = r.a

Modified: MacRuby/branches/experimental/lib/hotcocoa/kernel_ext.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/kernel_ext.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/kernel_ext.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -4,7 +4,7 @@
   
   def framework(name)
     if default_framework(name)
-      HotCocoa::Mappings.framework_loaded(name)
+      HotCocoa::Mappings.framework_loaded
       true
     else
       false

Modified: MacRuby/branches/experimental/lib/hotcocoa/kvo_accessors.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/kvo_accessors.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/kvo_accessors.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,48 +1,48 @@
 class Object
 
-    def self.kvo_array(key, &b)
-        key = key.to_s
-        capitalized_key = key[0].capitalize + key[1..-1]
-        signatures = { :size      => { selector: :"countOf#{capitalized_key}",                  type_signature: "i@:",   flip: false },
-                       :[]        => { selector: :"objectIn#{capitalized_key}AtIndex:",         type_signature: "@@:i",  flip: false },
-                       :insert    => { selector: :"insertObject:in#{capitalized_key}AtIndex:",  type_signature: "v@:@i", flip: true  },
-                       :delete_at => { selector: :"removeObjectFrom#{capitalized_key}AtIndex:", type_signature: "v@:i",  flip: false }
-        }
-        define_methods_with_signatures(signatures, &b)
-    end
+  def self.kvo_array(key, &b)
+    key = key.to_s
+    capitalized_key = key[0].capitalize + key[1..-1]
+    signatures = { :size      => { selector: :"countOf#{capitalized_key}",                  type_signature: "i@:",   flip: false },
+                   :[]        => { selector: :"objectIn#{capitalized_key}AtIndex:",         type_signature: "@@:i",  flip: false },
+                   :insert    => { selector: :"insertObject:in#{capitalized_key}AtIndex:",  type_signature: "v@:@i", flip: true  },
+                   :delete_at => { selector: :"removeObjectFrom#{capitalized_key}AtIndex:", type_signature: "v@:i",  flip: false }
+    }
+    define_methods_with_signatures(signatures, &b)
+  end
 
-    def self.kvo_set(key, &b)
-        key = key.to_s
-        capitalized_key = key[0].capitalize + key[1..-1]
-        signatures = { :add       => { selector: :"add#{capitalized_key}Object:",    type_signature: "v@:@", flip: false },
-                       :delete    => { selector: :"remove#{capitalized_key}Object:", type_signature: "v@:@", flip: false},
-                       :merge     => { selector: :"add#{capitalized_key}:",          type_signature: "v@:@", flip: false },
-                       :subtract  => { selector: :"remove#{capitalized_key}:",       type_signature: "v@:@", flip: false },
-                       :set       => { selector: :"#{key}",                          type_signature: "@@:",  flip: false }
-        }
-        define_methods_with_signatures(signatures, &b)
-    end
+  def self.kvo_set(key, &b)
+    key = key.to_s
+    capitalized_key = key[0].capitalize + key[1..-1]
+    signatures = { :add       => { selector: :"add#{capitalized_key}Object:",    type_signature: "v@:@", flip: false },
+                   :delete    => { selector: :"remove#{capitalized_key}Object:", type_signature: "v@:@", flip: false},
+                   :merge     => { selector: :"add#{capitalized_key}:",          type_signature: "v@:@", flip: false },
+                   :subtract  => { selector: :"remove#{capitalized_key}:",       type_signature: "v@:@", flip: false },
+                   :set       => { selector: :"#{key}",                          type_signature: "@@:",  flip: false }
+    }
+    define_methods_with_signatures(signatures, &b)
+  end
 
-    private
-    def self.define_methods_with_signatures(signatures, &b)
-        c = Module.new
-        c.module_eval &b
-        c.instance_methods.each do |m|
-            signature = signatures[m]
-            if signature
-		method = c.instance_method(m)
-		if signature[:flip]
-		    method = Proc.new { |a, b| method.bind(self).call(b, a)}
-		end
-		c.send(:define_method, signature[:selector], method)
-		c.send(:remove_method, m)
-		c.send(:method_signature, signature[:selector], signature[:type_signature])
-            elsif not Module.instance_methods.include?(m)
-                raise ArgumentError, "Method `#{m}' isn't a KVO accessor"
-            end
-        end
-
-        include c
+  private
+  
+  def self.define_methods_with_signatures(signatures, &b)
+    c = Module.new
+    c.module_eval &b
+    c.instance_methods.each do |m|
+      signature = signatures[m]
+      if signature
+      	method = c.instance_method(m)
+      	if signature[:flip]
+      	  method = Proc.new { |a, b| method.bind(self).call(b, a)}
+      	end
+      	c.send(:define_method, signature[:selector], method)
+      	c.send(:remove_method, m)
+      	c.send(:method_signature, signature[:selector], signature[:type_signature])
+      elsif not Module.instance_methods.include?(m)
+          raise ArgumentError, "Method `#{m}' isn't a KVO accessor"
+      end
     end
+    include c
+  end
 
 end

Modified: MacRuby/branches/experimental/lib/hotcocoa/layout_view.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/layout_view.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/layout_view.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -221,6 +221,8 @@
 
 class LayoutView < NSView
   
+  attr_accessor :frame_color
+  
   def initWithFrame(frame)
     super
     @mode = :vertical
@@ -272,6 +274,10 @@
     setFrame(frame)
   end
   
+  def size=(size)
+    setFrameSize(size)
+  end
+  
   def margin
     @margin
   end
@@ -291,7 +297,7 @@
     raise ArgumentError, "#{subview} is not a subview of #{self} and cannot be removed." unless subview.superview == self
     options[:needs_display] == false ? subview.removeFromSuperviewWithoutNeedingDisplay : subview.removeFromSuperview
   end
-    
+  
   def addSubview(view)
     super
     if view.respond_to?(:layout)
@@ -318,12 +324,12 @@
     relayout!
   end
 
-  if $DEBUG
-    def drawRect(frame)
-      NSColor.redColor.set
-      NSFrameRect(frame)
+  def drawRect(frame)
+    if @frame_color 
+      @frame_color.set 
+      NSFrameRect(frame) 
     end
-  end 
+  end
 
   def setFrame(frame)
     super

Modified: MacRuby/branches/experimental/lib/hotcocoa/mapper.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mapper.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mapper.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -49,15 +49,20 @@
           Views[guid] = control if guid
           inst.customize(control)
           map.each do |key, value|
-            if control.respond_to?(key) && value == true
-              if control.respond_to?("set#{key.to_s.capitalize}")
-                eval "control.set#{key.to_s.capitalize}(true)"
+            if control.respond_to?("#{key}=")
+              eval "control.#{key} = value"
+            elsif control.respond_to?(key)
+              new_key = (key.start_with?('set') ? key : "set#{key[0].capitalize}#{key[1..(key.length - 1)]}")
+              if control.respond_to?(new_key)
+                eval "control.#{new_key}(value)"
               else
                 control.send("#{key}")
               end
+            elsif control.respond_to?("set#{Mapper.camel_case(key.to_s)}")
+              eval "control.set#{Mapper.camel_case(key.to_s)}(value)"
             else
-              eval "control.#{key}= value"
-            end
+              NSLog "Unable to map #{key} as a method"
+            end            
           end
           if default_empty_rect_used
             control.sizeToFit if control.respondsToSelector(:sizeToFit) == true
@@ -71,6 +76,10 @@
           end
           control
         end
+        # make the function callable using HotCocoa.xxxx
+        HotCocoa.send(:module_function, builder_method)
+        # module_function makes the instance method private, but we want it to stay public
+        HotCocoa.send(:public, builder_method)
         self
       end
       
@@ -122,16 +131,25 @@
         unless Mapper.delegate_modules.has_key?(control_class)
           delegate_module = Module.new
           required_methods = []
-          inherited_delegate_methods.each do |delegate_method, mapping|
-            required_methods << delegate_method if mapping[:required]
-          end
-          inherited_delegate_methods.each do |delegate_method, mapping|
-            parameters = mapping[:parameters] ? ", "+mapping[:parameters].map {|param| %{"#{param}"} }.join(",") : ""
+          delegate_methods = inherited_delegate_methods
+          if delegate_methods.size > 0
+            delegate_methods.each do |delegate_method, mapping|
+              required_methods << delegate_method if mapping[:required]
+            end
+            delegate_methods.each do |delegate_method, mapping|
+              parameters = mapping[:parameters] ? ", "+mapping[:parameters].map {|param| %{"#{param}"} }.join(",") : ""
+              delegate_module.module_eval %{
+                def #{mapping[:to]}(&block)
+                  raise "Must pass in a block to use this delegate method" unless block_given?
+                  @_delegate_builder ||= HotCocoa::DelegateBuilder.new(self, #{required_methods.inspect})
+                  @_delegate_builder.add_delegated_method(block, "#{delegate_method}" #{parameters})
+                end
+              }
+            end
             delegate_module.module_eval %{
-              def #{mapping[:to]}(&block)
-                raise "Must pass in a block to use this delegate method" unless block_given?
+              def delegate_to(object)
                 @_delegate_builder ||= HotCocoa::DelegateBuilder.new(self, #{required_methods.inspect})
-                @_delegate_builder.add_delegated_method(block, "#{delegate_method}" #{parameters})
+                @_delegate_builder.delegate_to(object, #{delegate_methods.values.map {|method| ":#{method[:to]}"}.join(', ')})
               end
             }
           end
@@ -155,7 +173,7 @@
         bindings_module = Module.new
         instance.exposedBindings.each do |exposed_binding|
           bindings_module.module_eval %{
-            def #{underscore(exposed_binding)}=(value)
+            def #{Mapper.underscore(exposed_binding)}=(value)
               if value.kind_of?(Hash)
                 options = value.delete(:options)
                 bind "#{exposed_binding}", toObject:value.keys.first, withKeyPath:value.values.first, options:options
@@ -187,14 +205,23 @@
         result
       end
       
-      def underscore(camel_cased_word)
-        camel_cased_word.to_s.gsub(/::/, '/').
-          gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
-          gsub(/([a-z\d])([A-Z])/,'\1_\2').
+      def self.underscore(string)
+        string.gsub(/::/, '/').
+          gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
+          gsub(/([a-z\d])([A-Z])/, '\1_\2').
           tr("-", "_").
           downcase
       end
       
+      def self.camel_case(string)
+        if string !~ /_/ && string =~ /[A-Z]+.*/
+          string
+        else
+          string.split('_').map{ |e| e.capitalize }.join
+        end
+      end
+
+      
     end
   end
 end
\ No newline at end of file

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/alert.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/alert.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/alert.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -20,4 +20,6 @@
     
   end
   
+  delegating "alertShowHelp:", :to => :show_help?
+  
 end

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/application.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/application.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/application.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -64,7 +64,7 @@
     def on_quit(menu)
       terminate(menu)
     end
-    
+
     private
     
       def find_menu(menu, path)
@@ -79,5 +79,34 @@
       end
     
   end
+
+  delegating "application:delegateHandlesKey:",                       :to => :delegate_handles_key?,            :parameters => [:delegateHandlesKey]
+  delegating "application:openFile:",                                 :to => :open_file,                        :parameters => [:openFile]
+  delegating "application:openFiles:",                                :to => :open_files,                       :parameters => [:openFiles]
+  delegating "application:openFileWithoutUI:",                        :to => :open_file_without_ui,             :parameters => [:openFileWithoutUI]
+  delegating "application:openTempFile:",                             :to => :open_temp_file,                   :parameters => [:openTempFile]
+  delegating "application:printFile:",                                :to => :print_file
+  delegating "application:printFiles:withSettings:showPrintPanels:",  :to => :print_files
+  delegating "application:willPresentError:",                         :to => :will_present_error
+  delegating "applicationDidBecomeActive:",                           :to => :did_become_active
+  delegating "applicationDidChangeScreenParameters:",                 :to => :did_change_screen_parameters
+  delegating "applicationDidFinishLaunching:",                        :to => :did_finish_launching
+  delegating "applicationDidHide:",                                   :to => :did_hide
+  delegating "applicationDidResignActive:",                           :to => :resign_active
+  delegating "applicationDidUnhide:",                                 :to => :did_unhide
+  delegating "applicationDidUpdate:",                                 :to => :did_update
+  delegating "applicationDockMenu:",                                  :to => :dock_menu
+  delegating "applicationOpenUntitledFile:",                          :to => :open_untitled_file
+  delegating "applicationShouldHandleReopen:hasVisibleWindows:",      :to => :should_handle_reopen?,            :parameters => [:hasVisibleWindows]
+  delegating "applicationShouldOpenUntitledFile:",                    :to => :should_open_untitled_file?
+  delegating "applicationShouldTerminate:",                           :to => :should_terminate?
+  delegating "applicationShouldTerminateAfterLastWindowClosed:",      :to => :should_terminate_after_last_window_closed?
+  delegating "applicationWillBecomeActive:",                          :to => :will_become_active
+  delegating "applicationWillFinishLaunching:",                       :to => :will_finish_launching
+  delegating "applicationWillHide:",                                  :to => :will_hide
+  delegating "applicationWillResignActive:",                          :to => :will_resign_active
+  delegating "applicationWillTerminate:",                             :to => :will_terminate
+  delegating "applicationWillUnhide:",                                :to => :will_unhide
+  delegating "applicationWillUpdate:",                                :to => :will_update
   
 end

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/array_controller.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/array_controller.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/array_controller.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -10,18 +10,10 @@
 
   custom_methods do
     
-    def avoids_empty_selection=(value)
-      setAvoidsEmptySelection(value)
-    end
-    
     def avoids_empty_selection?
       avoidsEmptySelection
     end
     
-    def preserves_selection=(value)
-      setPreservesSelection(value)
-    end
-    
     def preserves_selection?
       preservesSelection
     end

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/box.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/box.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/box.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -26,26 +26,14 @@
   
   custom_methods do
     
-    def title_position=(value)
-      setTitlePosition(value)
-    end
-    
     def type=(value)
       setBoxType(value)
     end
-    
-    def corner_radius=(value)
-      setCornerRadius(value)
-    end
 
     def border=(value)
       setBorderType(value)
     end
     
-    def title_font=(value)
-      setTitleFont(value)
-    end
-    
   end
   
 end

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/button.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/button.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/button.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -30,8 +30,7 @@
      :momentary_change    => NSMomentaryChangeButton,
      :on_off              => NSOnOffButton,
      :momentary_push_in   => NSMomentaryPushInButton,
-     :momentary_push      => NSMomentaryPushButton,
-     :momentary_light     => NSMomentaryLight
+     :momentary_push      => NSMomentaryPushButton
   }
 
   constant :state, {
@@ -39,6 +38,16 @@
     :off                  => NSOffState,
     :mixed                => NSMixedState
   }
+
+  constant :image_position, {
+    :text_only            => NSNoImage,
+    :image_only           => NSImageOnly,
+    :overlaps             => NSImageOverlaps,
+    :left                 => NSImageLeft,
+    :right                => NSImageRight,
+    :below                => NSImageBelow,
+    :above                => NSImageAbove
+  }
   
   def init_with_options(button, options)
     button.initWithFrame options.delete(:frame)

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/collection_view.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/collection_view.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/collection_view.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -8,10 +8,6 @@
   
   custom_methods do
     
-    def item_prototype=(item)
-      setItemPrototype(item)
-    end
-    
     def item_prototype
       itemPrototype
     end

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/column.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/column.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/column.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -15,7 +15,7 @@
     def title=(newTitle)
       headerCell.stringValue = newTitle
     end
-    
+
   end
 
 end
\ No newline at end of file

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/combo_box.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/combo_box.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/combo_box.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -16,4 +16,9 @@
     
   end
   
+  delegating "comboBoxSelectionDidChange:",   :to => :selection_did_change
+  delegating "comboBoxSelectionIsChanging:",  :to => :selection_is_changing
+  delegating "comboBoxWillDismiss:",          :to => :will_dismiss
+  delegating "comboBoxWillPopUp:",            :to => :will_pop_up
+  
 end

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/label.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/label.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/label.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -20,10 +20,6 @@
       setAlignment(value)
     end
     
-    def text_color=(value)
-      setTextColor(value)
-    end
-
   end
   
 end

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/movie_view.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/movie_view.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/movie_view.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -22,10 +22,6 @@
       setZoomButtonsVisible(buttons.include?(:zoom))
     end
     
-    def fill_color=(color)
-      setFillColor(color)
-    end
-
   end
 
 end
\ No newline at end of file

Copied: MacRuby/branches/experimental/lib/hotcocoa/mappings/progress_indicator.rb (from rev 1886, MacRuby/trunk/lib/hotcocoa/mappings/progress_indicator.rb)
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/progress_indicator.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/progress_indicator.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,68 @@
+# Cocoa class: NSProgressIndicator
+# ================================
+# 
+# Apple Documentation: http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSProgressIndicator_Class/Reference/Reference.html
+#
+# Usage Example:
+# --------------
+#
+
+
+HotCocoa::Mappings.map :progress_indicator => :NSProgressIndicator do
+
+  defaults :layout => {}, :frame => [0,0,250,20]
+  
+  def init_with_options(progress_bar, options)
+    progress_bar.initWithFrame(options.delete(:frame))
+  end
+  
+  custom_methods do
+    
+    def to_f
+      doubleValue
+    end
+    alias :value :to_f
+    
+    def value=(value)
+      setDoubleValue(value.to_f)
+    end
+    
+    def start
+      startAnimation(nil)
+    end
+    
+    def stop
+      stopAnimation(nil)
+    end
+    
+    def show
+      setHidden(false)
+    end
+    
+    def hide
+      setHidden(true)
+    end
+    
+    def reset
+      setDoubleValue(0.0)
+    end
+    
+    def style=(style_name)
+      if style_name == :spinning
+        setStyle(NSProgressIndicatorSpinningStyle)
+      else
+        setStyle(NSProgressIndicatorBarStyle)
+      end
+    end
+    
+    def spinning_style
+      setStyle(NSProgressIndicatorSpinningStyle)
+    end
+    
+    def bar_style
+      setStyle(NSProgressIndicatorBarStyle)
+    end
+    
+  end
+  
+end
\ No newline at end of file

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/scroll_view.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/scroll_view.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/scroll_view.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -11,11 +11,7 @@
     def <<(view)
       setDocumentView(view)
     end
-    
-    def document_view=(view)
-      setDocumentView(view)
-    end
-    
+
     def background=(value)
       setDrawsBackground(value)
     end
@@ -28,10 +24,6 @@
       setHasHorizontalScroller(value)
     end
     
-    def autoresizes_subviews=(value)
-      setAutoresizesSubviews(value)
-    end
-    
   end
   
 end

Copied: MacRuby/branches/experimental/lib/hotcocoa/mappings/search_field.rb (from rev 1886, MacRuby/trunk/lib/hotcocoa/mappings/search_field.rb)
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/search_field.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/search_field.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,9 @@
+HotCocoa::Mappings.map :search_field => :NSSearchField do
+
+  defaults :layout => {}, :frame => DefaultEmptyRect
+  
+  def init_with_options(search_field, options)
+    search_field.initWithFrame options.delete(:frame)
+  end
+
+end
\ No newline at end of file

Copied: MacRuby/branches/experimental/lib/hotcocoa/mappings/sort_descriptor.rb (from rev 1886, MacRuby/trunk/lib/hotcocoa/mappings/sort_descriptor.rb)
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/sort_descriptor.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/sort_descriptor.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,13 @@
+HotCocoa::Mappings.map :sort_descriptor => :NSSortDescriptor do
+
+  defaults :ascending => true
+
+  def init_with_options(sort_descriptor, opts)
+    if opts.has_key?(:selector)
+      sort_descriptor.initWithKey(opts.delete(:key), ascending:opts.delete(:ascending))
+    else
+      sort_descriptor.initWithKey(opts.delete(:key), ascending:opts.delete(:ascending), selector:opts.delete(:selector))
+    end
+  end
+
+end
\ No newline at end of file

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/table_view.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/table_view.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/table_view.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -10,7 +10,19 @@
     :last_column_only   => NSTableViewLastColumnOnlyAutoresizingStyle,
     :first_column_only  => NSTableViewFirstColumnOnlyAutoresizingStyle
   }
+  
+  constant :grid_style, { 
+    :none               => NSTableViewGridNone, 
+    :vertical           => NSTableViewSolidVerticalGridLineMask, 
+    :horizontal         => NSTableViewSolidHorizontalGridLineMask, 
+  	:both               => NSTableViewSolidVerticalGridLineMask | NSTableViewSolidHorizontalGridLineMask 
+  }
 
+  constant :selection_style, {
+    :regular            => NSTableViewSelectionHighlightStyleRegular,
+    :source_list        => NSTableViewSelectionHighlightStyleSourceList
+  }
+
   def init_with_options(table_view, options)
     table_view.initWithFrame(options.delete(:frame))
   end
@@ -39,7 +51,60 @@
     def column_resize=(style)
       setColumnAutoresizingStyle(style)
     end
-    
+
+    def reload 
+   	  reloadData 
+   	end 
+   	
+   	def grid_style=(value) 
+   	  setGridStyleMask(value) 
+   	end
+
+    def on_double_action=(behavior)
+      if target && (
+        target.instance_variable_get("@action_behavior") || 
+        target.instance_variable_get("@double_action_behavior"))
+          object.instance_variable_set("@double_action_behavior", behavior)
+          object = target
+      else
+        object = Object.new
+        object.instance_variable_set("@double_action_behavior", behavior)
+        setTarget(object)
+      end
+      def object.perform_double_action(sender)
+        @double_action_behavior.call(sender)
+      end
+      setDoubleAction("perform_double_action:")
+    end
+   
+    def on_double_action(&behavior)
+      self.on_double_action = behavior
+      self
+    end
+
   end
 
+  delegating "tableView:willDisplayCell:forTableColumn:row:",               :to => :will_display_cell,      :parameters => [:willDisplayCell, :forTableColumn, :row]
+  delegating "tableView:dataCellForTableColumn:row:",                       :to => :data_cell,              :parameters => [:dataCellForTableColumn, :row]
+  delegating "tableView:shouldShowCellExpansionForTableColumn:row:",        :to => :expand_cell?,           :parameters => [:shouldShowCellExpansionForTableColumn, :row]
+  delegating "tableView:isGroupRow:",                                       :to => :is_group_row?,          :parameters => [:isGroupRow]
+  delegating "tableView:shouldEditTableColumn:row:",                        :to => :edit_table_column?,     :parameters => [:shouldEditTableColumn, :row]
+  delegating "tableView:heightOfRow:",                                      :to => :height_of_row,          :parameters => [:heightOfRow]
+  delegating "selectionShouldChangeInTableView:",                           :to => :change_selection?
+  delegating "tableView:shouldSelectRow:",                                  :to => :select_row?,            :parameters => [:shouldSelectRow]
+  delegating "tableView:selectionIndexesForProposedSelection:",             :to => :indexes_for_selection,  :parameters => [:selectIndexesForProposedSelection]
+  delegating "tableView:shouldSelectTableColumn:",                          :to => :select_column?,         :parameters => [:shouldSelectTableColumn]
+  delegating "tableViewSelectionIsChanging:",                               :to => :selection_changing,     :parameters => [:tableViewSelectionIsChanging]
+  delegating "tableViewSelectionDidChange:",                                :to => :selection_changed,      :parameters => [:tableViewSelectionDidChange]
+  delegating "tableView:shouldTypeSelectForEvent:withCurrentSearchString:", :to => :type_select_for_event?, :parameters => [:shouldTypeSelectForEvent, :withCurrentSearchString]
+  delegating "tableView:typeSelectStringForTableColumn:row:",               :to => :type_select_string,     :parameters => [:typeSelectStringForTableColumn, :row]
+  delegating "tableView:nextTypeSelectMatchFromRow:toRow:forString:",       :to => :find_in_range,          :parameters => [:nextTypeSelectMatchFromRow, :toRow, :forString]
+  delegating "tableView:didDragTableColumn:",                               :to => :dragged_column,         :parameters => [:didDragTableColumn]
+  delegating "tableViewColumnDidMove:",                                     :to => :column_moved,           :parameters => [:tableViewColumnDidMove]
+  delegating "tableViewColumnDidResize:",                                   :to => :column_resized,         :parameters => [:tableViewColumnDidResize]
+  delegating "tableView:didClickTableColumn:",                              :to => :clicked_column,         :parameters => [:didClickTableColumn]
+  delegating "tableView:mouseDownInHeaderOfTableColumn:",                   :to => :header_clicked,         :parameters => [:mouseDownInHeaderOfTableColumn]
+  delegating "tableView:shouldTrackCell:forTableColumn:row:",               :to => :track_cell?,            :parameters => [:shouldTrackCell, :forTableColumn, :row]
+  delegating "tableView:toolTipForCell:rect:tableColumn:row:mouseLocation:",:to => :tooltip_for_cell,       :parameters => [:toolTipForCell, :rect, :tableColumn, :row, :mouseLocation]
+
 end
\ No newline at end of file

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/text_field.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/text_field.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/text_field.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,3 +1,14 @@
+# NSTextField mappings
+# 
+# Usage example:
+#   @field = text_field(:text => "your text here", :layout => {:start => false}, :frame => [0, 0, 300, 300])
+#   @field.text = "New text"
+
+# Cocoa Documentation:
+#  http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSTextField_Class/Reference/Reference.html
+#
+#
+
 HotCocoa::Mappings.map :text_field => :NSTextField do
 
   constant :text_align, {
@@ -18,10 +29,6 @@
       setAlignment(value)
     end
     
-    def text_color=(value)
-      setTextColor(value)
-    end
-
   end
   
   delegating "control:textShouldBeginEditing:", :to => :should_begin_editing?, :parameters => [:textShouldBeginEditing]

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/web_view.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/web_view.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/web_view.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -5,7 +5,7 @@
   def init_with_options(web_view, options)
     web_view.initWithFrame(options.delete(:frame))
   end
-
+  
   custom_methods do
     
     def url=(url)

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings/window.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings/window.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings/window.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,3 +1,17 @@
+# Cocoa Reference: NSWindow
+#
+# Usage example:
+# ==============
+#
+#   window :frame => [100, 100, 604, 500], :title => "My app", :style => [:titled, :closable, :miniaturizable, :resizable] do |win|
+#     win.contentView.margin  = 0
+#     win.background_color    = color(:name => 'white')  
+#     win.will_close { exit }
+#   end
+#
+# Apple Developer Connection url: http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSWindow_Class/Reference/Reference.html
+#
+
 HotCocoa::Mappings.map :window => :NSWindow do
     
   defaults  :style => [:titled, :closable, :miniaturizable, :resizable],
@@ -32,12 +46,12 @@
                                styleMask:options.delete(:style), 
                                backing:options.delete(:backing), 
                                defer:options.delete(:defer)
+    default_layout = options.delete(:default_layout)
     if options[:view] == :layout
       options.delete(:view)
       window.setContentView(LayoutView.alloc.initWithFrame([0,0,window.contentView.frameSize.width, window.contentView.frameSize.height]))
-      window.contentView.default_layout = options.delete(:default_layout)
+      window.contentView.default_layout = default_layout
     elsif options[:view] == :nolayout
-      options.delete(:default_layout)
       options.delete(:view)
     end
     window
@@ -68,22 +82,10 @@
       orderFrontRegardless
     end
     
-    def background_color=(color)
-      setBackgroundColor(color)
-    end
-    
-    def background_color
-      backgroundColor
-    end
-    
     def has_shadow?
       hasShadow
     end
     
-    def has_shadow=(value)
-      setHasShadow(value)
-    end
-    
   end
   
   delegating "window:shouldDragDocumentWithEvent:from:withPasteboard:", :to => :should_drag_document?,    :parameters => [:shouldDragDocumentWithEvent, :from, :withPasteboard]

Modified: MacRuby/branches/experimental/lib/hotcocoa/mappings.rb
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mappings.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/hotcocoa/mappings.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,7 +3,7 @@
     
     def self.reload
       Dir.glob(File.join(File.dirname(__FILE__), "mappings", "*.rb")).each do |mapping|
-        load mapping
+        require mapping
       end
     end
     
@@ -11,12 +11,19 @@
     
     module TargetActionConvenience
       def on_action=(behavior)
-        object = Object.new
-        object.instance_variable_set("@behavior", behavior)
+        if target && (
+          target.instance_variable_get("@action_behavior") || 
+          target.instance_variable_get("@double_action_behavior"))
+            object.instance_variable_set("@action_behavior", behavior)
+            object = target
+        else
+          object = Object.new
+          object.instance_variable_set("@action_behavior", behavior)
+          setTarget(object)
+        end
         def object.perform_action(sender)
-          @behavior.call(sender)
+          @action_behavior.call(sender)
         end
-        setTarget(object)
         setAction("perform_action:")
       end
      
@@ -67,7 +74,7 @@
     
     # Registers a callback for after the specified framework has been loaded.
     def self.on_framework(name, &block)
-      (frameworks[name.to_s.downcase] ||= []) << block
+      (frameworks[name.to_s] ||= []) << block
     end
     
     # Returns the Hash of mapped frameworks.
@@ -81,19 +88,20 @@
     end
     
     # Registers a given framework as being loaded.
-    def self.framework_loaded(name)
-      name = name.to_s.downcase
-      loaded_frameworks << name
-      if frameworks[name]
-        frameworks[name].each do |mapper|
-          mapper.call
+    def self.framework_loaded
+      frameworks.keys.each do |key|
+        if loaded_framework?(key)
+          frameworks[key].each do |mapper|
+            mapper.call
+          end
+          frameworks.delete(key)
         end
       end
     end
     
     # Returns whether or not the framework has been loaded yet.
     def self.loaded_framework?(name)
-      loaded_frameworks.include?(name.to_s.downcase)
+      NSBundle.allFrameworks.map {|bundle| bundle.bundlePath.split("/").last}.select {|framework| framework.split(".")[1] == 'framework'}.map {|framework| framework.split(".")[0]}.include?(name.to_s)
     end
     
   end

Copied: MacRuby/branches/experimental/lib/hotcocoa/mvc.rb (from rev 1886, MacRuby/trunk/lib/hotcocoa/mvc.rb)
===================================================================
--- MacRuby/branches/experimental/lib/hotcocoa/mvc.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/hotcocoa/mvc.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,175 @@
+require 'hotcocoa'
+
+class HotCocoaApplication
+  attr_accessor :shared_application, :application_controller, :controllers
+  
+  include HotCocoa
+  
+  def self.instance=(instance)
+    @instance = instance
+  end
+  
+  def self.instance
+    @instance
+  end
+  
+  def initialize(application_file)
+    HotCocoaApplication.instance = self
+    @controllers = {}
+    load_controllers_and_views(directory_of(application_file))
+    @shared_application = application(ApplicationView.options[:application])
+    @shared_application.load_application_menu
+    @application_controller = controller(:application_controller)
+    shared_application.delegate_to(application_controller)
+  end
+  
+  def start
+    @shared_application.run
+  end
+  
+  def controller(controller_name)
+    controller_name_string = controller_name.to_s
+    controller_class = Object.const_get(controller_name_string !~ /_/ && controller_name_string =~ /[A-Z]+.*/ ? controller_name_string : controller_name_string.split('_').map{|e| e.capitalize}.join)
+    @controllers[controller_name] || create_controller_instance(controller_name, controller_class)
+  end
+  
+  private
+  
+    def create_controller_instance(controller_name, controller_class)
+      controller_instance = controller_class.new(self)
+      @controllers[controller_name] = controller_instance
+      controller_instance.application_window
+      controller_instance
+    end
+    
+    def directory_of(application_file)
+      File.dirname(File.expand_path(application_file))
+    end
+    
+    def load_controllers_and_views(directory)
+      Dir.glob(File.join(directory, 'controllers', '**', '*.rb')).each do |controller_file|
+        load(controller_file)
+      end
+      Dir.glob(File.join(directory, 'views', '**', '*.rb')).each do |view_file|
+        load(view_file)
+      end
+    end
+  
+end
+
+class HotCocoaController
+  
+  def self.view_instances
+    @view_instances ||= {}
+  end
+  
+  attr_reader :application
+  
+  def initialize(application)
+    @application = application
+  end
+  
+  def application_window
+    @application.application_controller.application_window
+  end
+
+end
+
+class HotCocoaApplicationController < HotCocoaController
+  
+  def initialize(application)
+    super(application)
+  end
+  
+  def application_window
+    @application_window ||= ApplicationWindow.new(self).application_window
+  end
+
+end
+
+class HotCocoaWindow
+  
+  attr_reader :application_controller, :application_window
+  
+  def initialize(application_controller)
+    @application_controller = application_controller
+    render
+  end
+  
+  def render
+    @application_window = HotCocoa.window(ApplicationView.options[:window])
+    @application_window.delegate_to(application_controller)
+    @application_window.view << application_controller.application_view
+  end
+  
+end
+
+class HotCocoaView < HotCocoa::LayoutView
+  
+  DefaultLayoutOptions = {:expand => [:width, :height]}
+  
+  module ClassMethods
+    def controller(name=nil)
+      if name
+        @name = name
+      else
+        @name || :application_controller
+      end
+    end
+    def options(options=nil)
+      if options
+        @options = options
+      else
+        @options
+      end
+    end
+  end
+  
+  def self.inherited(klass)
+    klass.extend(ClassMethods)
+    klass.send(:include, HotCocoa::Behaviors)
+    class_name = klass.name.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
+    HotCocoaController.class_eval %{
+      def #{class_name}
+        unless HotCocoaController.view_instances[:#{class_name}]
+          HotCocoaController.view_instances[:#{class_name}] = #{klass.name}.alloc.initWithFrame([0,0,0,0])
+          HotCocoaController.view_instances[:#{class_name}].setup_view
+        end
+        HotCocoaController.view_instances[:#{class_name}]
+      end
+    }, __FILE__, __LINE__
+  end
+  
+  attr_reader :controller
+
+  def setup_view
+    unless @controller
+      @controller = class_controller
+      self.layout = layout_options
+      render
+    end
+  end
+  
+  private
+  
+    def class_controller
+      HotCocoaApplication.instance.controller(self.class.controller)
+    end
+  
+    def layout_options
+      options = if self.class.options && self.class.options[:layout]
+        self.class.options[:layout]
+      else
+        DefaultLayoutOptions
+      end
+    end
+    
+end
+
+class ApplicationWindow < HotCocoaWindow
+  
+end
+
+class Application < HotCocoaApplication
+  
+end

Modified: MacRuby/branches/experimental/lib/ipaddr.rb
===================================================================
--- MacRuby/branches/experimental/lib/ipaddr.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/ipaddr.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -7,7 +7,7 @@
 #
 # You can redistribute and/or modify it under the same terms as Ruby.
 #
-# $Id: ipaddr.rb 15821 2008-03-21 12:15:06Z knu $
+# $Id: ipaddr.rb 19504 2008-09-23 21:39:21Z ryan $
 #
 # Contact:
 #   - Akinori MUSHA <knu at iDaemons.org> (current maintainer)
@@ -483,7 +483,7 @@
     if prefixlen
       mask!(prefixlen)
     else
-      @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
+      @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK
     end
   end
 
@@ -577,7 +577,6 @@
 __END__
 
 require 'test/unit'
-require 'test/unit/ui/console/testrunner'
 
 class TC_IPAddr < Test::Unit::TestCase
   def test_s_new

Modified: MacRuby/branches/experimental/lib/irb/completion.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/completion.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/completion.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   irb/completor.rb - 
 #   	$Release Version: 0.9$
-#   	$Revision: 14912 $
+#   	$Revision: 20880 $
 #   	by Keiju ISHITSUKA(keiju at ishitsuka.com)
 #       From Original Idea of shugo at ruby-lang.org
 #
@@ -11,7 +11,7 @@
 module IRB
   module InputCompletor
 
-    @RCS_ID='-$Id: completion.rb 14912 2008-01-06 15:49:38Z akr $-'
+    @RCS_ID='-$Id: completion.rb 20880 2008-12-19 11:37:41Z yugui $-'
 
     ReservedWords = [
       "BEGIN", "END",
@@ -159,7 +159,7 @@
 	    end
 	    next if name != "IRB::Context" and 
 	      /^(IRB|SLex|RubyLex|RubyToken)/ =~ name
-	    candidates.concat m.instance_methods(false).collect{|m| m.to_s}
+	    candidates.concat m.instance_methods(false).collect{|x| x.to_s}
 	  }
 	  candidates.sort!
 	  candidates.uniq!

Modified: MacRuby/branches/experimental/lib/irb/context.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/context.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/context.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   irb/context.rb - irb context
 #   	$Release Version: 0.9.5$
-#   	$Revision: 15442 $
+#   	$Revision: 19670 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -233,6 +233,7 @@
     def inspect
       array = []
       for ivar in instance_variables.sort{|e1, e2| e1 <=> e2}
+	ivar = ivar.to_s
 	name = ivar.sub(/^@(.*)$/, '\1')
 	val = instance_eval(ivar)
 	case ivar

Modified: MacRuby/branches/experimental/lib/irb/ext/change-ws.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/ext/change-ws.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/ext/change-ws.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   irb/ext/cb.rb - 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 20880 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -56,6 +56,6 @@
 #       end
 #     end
 #     alias change_workspace change_binding
-   end
+  end
 end
 

Modified: MacRuby/branches/experimental/lib/irb/ext/multi-irb.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/ext/multi-irb.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/ext/multi-irb.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   irb/multi-irb.rb - multiple irb module
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 18837 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -14,7 +14,7 @@
 module IRB
   # job management class
   class JobManager
-    @RCS_ID='-$Id: multi-irb.rb 14912 2008-01-06 15:49:38Z akr $-'
+    @RCS_ID='-$Id: multi-irb.rb 18837 2008-08-25 13:41:11Z mame $-'
 
     def initialize
       # @jobs = [[thread, irb],...]
@@ -69,7 +69,7 @@
     end    
 
     def search(key)
-      case key
+      job = case key
       when Integer
 	@jobs[key]
       when Irb
@@ -77,10 +77,10 @@
       when Thread
 	@jobs.assoc(key)
       else
-	assoc = @jobs.find{|k, v| v.context.main.equal?(key)}
-	IRB.fail NoSuchJob, key if assoc.nil?
-	assoc
+	@jobs.find{|k, v| v.context.main.equal?(key)}
       end
+      IRB.fail NoSuchJob, key if job.nil?
+      job
     end
 
     def delete(key)

Modified: MacRuby/branches/experimental/lib/irb/ext/save-history.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/ext/save-history.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/ext/save-history.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,8 +2,8 @@
 #
 #   save-history.rb - 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
-#   	by Keiju ISHITSUKAkeiju at ruby-lang.org)
+#   	$Revision: 19671 $
+#   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
 #
@@ -14,7 +14,7 @@
 
 module IRB
   module HistorySavingAbility
-    @RCS_ID='-$Id: save-history.rb 14912 2008-01-06 15:49:38Z akr $-'
+    @RCS_ID='-$Id: save-history.rb 19671 2008-10-04 03:28:19Z keiju $-'
   end
 
   class Context
@@ -52,11 +52,11 @@
     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)
+	  if history_file = IRB.conf[:HISTORY_FILE]
+	    history_file = File.expand_path(history_file)
 	  end
-	  file = IRB.rc_file("_history") unless file
-	  open(file, 'w' ) do |f|
+	  history_file = IRB.rc_file("_history") unless history_file
+	  open(history_file, 'w' ) do |f|
 	    hist = HISTORY.to_a
 	    f.puts(hist[-num..-1] || hist)
 	  end
@@ -71,10 +71,12 @@
     end
 
     def load_history
-      hist = IRB.conf[:HISTORY_FILE]
-      hist = IRB.rc_file("_history") unless hist
-      if File.exist?(hist)
-	open(hist) do |f|
+      if history_file = IRB.conf[:HISTORY_FILE]
+	history_file = File.expand_path(history_file)
+      end
+      history_file = IRB.rc_file("_history") unless history_file
+      if File.exist?(history_file)
+	open(history_file) do |f|
 	  f.each {|l| HISTORY << l.chomp}
 	end
       end

Modified: MacRuby/branches/experimental/lib/irb/extend-command.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/extend-command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/extend-command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   irb/extend-command.rb - irb extend command 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 18837 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -111,7 +111,7 @@
       end
     end
 
-    # aliases = [commans_alias, flag], ...
+    # aliases = [commands_alias, flag], ...
     def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
       case cmd_class
       when Symbol
@@ -125,9 +125,14 @@
 	eval %[
 	  def #{cmd_name}(*opts, &b)
 	    require "#{load_file}"
+	    arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
+	    args = (1..arity.abs).map {|i| "arg" + i.to_s }
+	    args << "*opts" if arity < 0
+	    args << "&block"
+	    args = args.join(", ")
 	    eval %[
-	      def #{cmd_name}(*opts, &b)
-		ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
+	      def #{cmd_name}(\#{args})
+		ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
 	      end
 	    ]
 	    send :#{cmd_name}, *opts, &b

Modified: MacRuby/branches/experimental/lib/irb/help.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/help.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/help.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
-#   irb/help.rb - print usase module
+#   irb/help.rb - print usage module
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 20882 $
 #   	by Keiju ISHITSUKA(keiju at ishitsuka.com)
 #
 # --
@@ -9,24 +9,27 @@
 #   
 #
 
+require 'irb/magic-file'
+
 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
+    IRB::MagicFile.open(path){|f|
+      f.each_line 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
-      space_line = false
-      
-      l.sub!(/#.*$/, "")
-      next if /^\s*$/ =~ l
-      lc.puts l
-    end
+    }
   end
 end
 

Modified: MacRuby/branches/experimental/lib/irb/init.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/init.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/init.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   irb/init.rb - irb initialize module
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 20882 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -139,6 +139,11 @@
       when /^-I(.+)?/
         opt = $1 || ARGV.shift
 	load_path.concat(opt.split(File::PATH_SEPARATOR)) if opt
+      when '-U'
+	set_encoding("UTF-8", "UTF-8")
+      when /^-E(.+)?/, /^--encoding(?:=(.+))?/
+	opt = $1 || ARGV.shift
+	set_encoding(*opt.split(':', 2))
       when "--inspect"
 	@CONF[:INSPECT_MODE] = true
       when "--noinspect"
@@ -155,8 +160,9 @@
 	@CONF[:VERBOSE] = true
       when "--noverbose"
 	@CONF[:VERBOSE] = false
-      when "--prompt-mode", "--prompt"
-	prompt_mode = ARGV.shift.upcase.tr("-", "_").intern
+      when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/
+	opt = $1 || ARGV.shift
+	prompt_mode = opt.upcase.tr("-", "_").intern
 	@CONF[:PROMPT_MODE] = prompt_mode
       when "--noprompt"
 	@CONF[:PROMPT_MODE] = :NULL
@@ -166,14 +172,14 @@
 	@CONF[:PROMPT_MODE] = :SIMPLE
       when "--tracer"
 	@CONF[:USE_TRACER] = true
-      when "--back-trace-limit"
-	@CONF[:BACK_TRACE_LIMIT] = ARGV.shift.to_i
-      when "--context-mode"
-	@CONF[:CONTEXT_MODE] = ARGV.shift.to_i
+      when /^--back-trace-limit(?:=(.+))?/
+	@CONF[:BACK_TRACE_LIMIT] = ($1 || ARGV.shift).to_i
+      when /^--context-mode(?:=(.+))?/
+	@CONF[:CONTEXT_MODE] = ($1 || ARGV.shift).to_i
       when "--single-irb"
 	@CONF[:SINGLE_IRB] = true
-      when "--irb_debug"
-	@CONF[:DEBUG_LEVEL] = ARGV.shift.to_i
+      when /^--irb_debug=(?:=(.+))?/
+	@CONF[:DEBUG_LEVEL] = ($1 || ARGV.shift).to_i
       when "-v", "--version"
 	print IRB.version, "\n"
 	exit 0
@@ -181,6 +187,12 @@
 	require "irb/help"
 	IRB.print_usage
 	exit 0
+      when "--"
+	if opt = ARGV.shfit
+	  @CONF[:SCRIPT] = opt
+	  $0 = opt
+	end
+        break
       when /^-/
 	IRB.fail UnrecognizedSwitch, opt
       else
@@ -195,6 +207,7 @@
       end
     end
     $LOAD_PATH.unshift(*load_path)
+
   end
 
   # running config
@@ -249,10 +262,27 @@
     for m in @CONF[:LOAD_MODULES]
       begin
 	require m
-      rescue # StandardError, ScriptError
-	print $@[0], ":", $!.class, ": ", $!, "\n"
+      rescue LoadError => err
+	warn err.backtrace[0] << ":#{err.class}: #{err}"
       end
     end
   end
 
+
+  DefaultEncodings = Struct.new(:external, :internal)
+  class << IRB
+    private
+    def set_encoding(extern, intern = nil)
+      verbose, $VERBOSE = $VERBOSE, nil
+      Encoding.default_external = extern unless extern.nil? || extern.empty?
+      Encoding.default_internal = intern unless intern.nil? || intern.empty?
+      @CONF[:ENCODINGS] = IRB::DefaultEncodings.new(extern, intern)
+      [$stdin, $stdout, $stderr].each do |io|
+	io.set_encoding(extern, intern)
+      end
+      @CONF[:LC_MESSAGES].instance_variable_set(:@encoding, extern)
+    ensure
+      $VERBOSE = verbose
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/irb/input-method.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/input-method.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/input-method.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,13 +1,16 @@
 #
 #   irb/input-method.rb - input methods used irb
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 21546 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
 #
 #   
 #
+require 'irb/src_encoding'
+require 'irb/magic-file'
+
 module IRB
   # 
   # InputMethod
@@ -17,7 +20,7 @@
   #
   STDIN_FILE_NAME = "(line)"
   class InputMethod
-    @RCS_ID='-$Id: input-method.rb 14912 2008-01-06 15:49:38Z akr $-'
+    @RCS_ID='-$Id: input-method.rb 21546 2009-01-15 15:36:57Z yugui $-'
 
     def initialize(file = STDIN_FILE_NAME)
       @file_name = file
@@ -41,15 +44,18 @@
       super
       @line_no = 0
       @line = []
+      @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+      @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
     end
 
     def gets
       print @prompt
-      @line[@line_no += 1] = $stdin.gets
+      line = @stdin.gets
+      @line[@line_no += 1] = line
     end
 
     def eof?
-      $stdin.eof?
+      @stdin.eof?
     end
 
     def readable_atfer_eof?
@@ -59,12 +65,16 @@
     def line(line_no)
       @line[line_no]
     end
+
+    def encoding
+      @stdin.external_encoding
+    end
   end
   
   class FileInputMethod < InputMethod
     def initialize(file)
       super
-      @io = open(file)
+      @io = IRB::MagicFile.open(file)
     end
     attr_reader :file_name
 
@@ -78,6 +88,10 @@
 #      print @prompt, l
       l
     end
+
+    def encoding
+      @io.external_encoding
+    end
   end
 
   begin
@@ -90,11 +104,14 @@
 	@line_no = 0
 	@line = []
 	@eof = false
+
+	@stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+	@stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
       end
 
       def gets
-        Readline.input = STDIN
-        Readline.output = STDOUT
+        Readline.input = @stdin
+        Readline.output = @stdout
 	if l = readline(@prompt, false)
 	  HISTORY.push(l) if !l.empty?
 	  @line[@line_no += 1] = l + "\n"
@@ -115,6 +132,10 @@
       def line(line_no)
 	@line[line_no]
       end
+
+      def encoding
+	@stdin.external_encoding
+      end
     end
   rescue LoadError
   end

Modified: MacRuby/branches/experimental/lib/irb/lc/help-message
===================================================================
--- MacRuby/branches/experimental/lib/irb/lc/help-message	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/lc/help-message	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,8 @@
+# -*- coding: US-ASCII -*-
 #
 #   irb/lc/help-message.rb - 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 20882 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -14,6 +15,8 @@
   -d                Set $DEBUG to true (same as `ruby -d')
   -r load-module    Same as `ruby -r'
   -I path           Specify $LOAD_PATH directory
+  -U                Same as `ruby -U`
+  -E enc            Same as `ruby -E`
   --inspect	    Use `inspect' for output (default except for bc mode)
   --noinspect	    Don't use inspect for output
   --readline	    Use Readline extension module
@@ -32,3 +35,4 @@
 		    value is 16. 
   --irb_debug n	    Set internal debug level to n (not for popular use)
   -v, --version	    Print the version of irb
+# vim:fileencoding=us-ascii

Copied: MacRuby/branches/experimental/lib/irb/lc/ja/encoding_aliases.rb (from rev 1886, MacRuby/trunk/lib/irb/lc/ja/encoding_aliases.rb)
===================================================================
--- MacRuby/branches/experimental/lib/irb/lc/ja/encoding_aliases.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/irb/lc/ja/encoding_aliases.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,8 @@
+module IRB
+  class Locale
+    @@legacy_encoding_alias_map = {
+      'ujis' => Encoding::EUC_JP,
+      'euc' => Encoding::EUC_JP
+    }.freeze
+  end
+end

Modified: MacRuby/branches/experimental/lib/irb/lc/ja/error.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/lc/ja/error.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/lc/ja/error.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
-#
+# -*- coding: utf-8 -*-
 #   irb/lc/ja/error.rb - 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 20882 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -13,14 +13,15 @@
 module IRB
   # exceptions
   extend Exception2MessageMapper
-  def_exception :UnrecognizedSwitch, '$B%9%$%C%A(B(%s)$B$,J,$j$^$;$s(B'
-  def_exception :NotImplementedError, '`%s\'$B$NDj5A$,I,MW$G$9(B'
-  def_exception :CantReturnToNormalMode, 'Normal$B%b!<%I$KLa$l$^$;$s(B.'
-  def_exception :IllegalParameter, '$B%Q%i%a!<%?(B(%s)$B$,4V0c$C$F$$$^$9(B.'
-  def_exception :IrbAlreadyDead, 'Irb$B$O4{$K;`$s$G$$$^$9(B.'
-  def_exception :IrbSwitchedToCurrentThread, '$B%+%l%s%H%9%l%C%I$K at Z$jBX$o$j$^$7$?(B.'
-  def_exception :NoSuchJob, '$B$=$N$h$&$J%8%g%V(B(%s)$B$O$"$j$^$;$s(B.'
-  def_exception :CantShiftToMultiIrbMode, 'multi-irb mode$B$K0\$l$^$;$s(B.'
-  def_exception :CantChangeBinding, '$B%P%$%s%G%#%s%0(B(%s)$B$KJQ99$G$-$^$;$s(B.'
-  def_exception :UndefinedPromptMode, '$B%W%m%s%W%H%b!<%I(B(%s)$B$ODj5A$5$l$F$$$^$;$s(B.'
+  def_exception :UnrecognizedSwitch, 'スイッチ(%s)が分りません'
+  def_exception :NotImplementedError, '`%s\'の定義が必要です'
+  def_exception :CantReturnToNormalMode, 'Normalモードに戻れません.'
+  def_exception :IllegalParameter, 'パラメータ(%s)が間違っています.'
+  def_exception :IrbAlreadyDead, 'Irbは既に死んでいます.'
+  def_exception :IrbSwitchedToCurrentThread, 'カレントスレッドに切り替わりました.'
+  def_exception :NoSuchJob, 'そのようなジョブ(%s)はありません.'
+  def_exception :CantShiftToMultiIrbMode, 'multi-irb modeに移れません.'
+  def_exception :CantChangeBinding, 'バインディング(%s)に変更できません.'
+  def_exception :UndefinedPromptMode, 'プロンプトモード(%s)は定義されていません.'
 end
+# vim:fileencoding=utf-8

Modified: MacRuby/branches/experimental/lib/irb/lc/ja/help-message
===================================================================
--- MacRuby/branches/experimental/lib/irb/lc/ja/help-message	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/lc/ja/help-message	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
-#
+# -*- coding: utf-8 -*-
 #   irb/lc/ja/help-message.rb - 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 20882 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -9,27 +9,31 @@
 #   
 #
 Usage:  irb.rb [options] [programfile] [arguments]
-  -f		    ~/.irbrc $B$rFI$_9~$^$J$$(B.
-  -m		    bc$B%b!<%I(B($BJ,?t(B, $B9TNs$N7W;;$,$G$-$k(B)
-  -d                $DEBUG $B$r(Btrue$B$K$9$k(B(ruby -d $B$HF1$8(B)
-  -r load-module    ruby -r $B$HF1$8(B.
-  -I path           $LOAD_PATH $B$K(B path $B$rDI2C$9$k(B.
-  --inspect	    $B7k2L=PNO$K(Binspect$B$rMQ$$$k(B(bc$B%b!<%I0J30$O%G%U%)%k%H(B). 
-  --noinspect	    $B7k2L=PNO$K(Binspect$B$rMQ$$$J$$(B.
-  --readline	    readline$B%i%$%V%i%j$rMxMQ$9$k(B.
-  --noreadline	    readline$B%i%$%V%i%j$rMxMQ$7$J$$(B. 
+  -f		    ~/.irbrc を読み込まない.
+  -m		    bcモード(分数, 行列の計算ができる)
+  -d                $DEBUG をtrueにする(ruby -d と同じ)
+  -r load-module    ruby -r と同じ.
+  -I path           $LOAD_PATH に path を追加する.
+  -U                ruby -U と同じ.
+  -E enc            ruby -E と同じ.
+  --inspect	    結果出力にinspectを用いる(bcモード以外はデフォルト). 
+  --noinspect	    結果出力にinspectを用いない.
+  --readline	    readlineライブラリを利用する.
+  --noreadline	    readlineライブラリを利用しない. 
   --prompt prompt-mode/--prompt-mode prompt-mode
-		    $B%W%m%s%W%H%b!<%I$r at ZBX$($^$9(B. $B8=:_Dj5A$5$l$F$$$k%W(B
-		    $B%m%s%W%H%b!<%I$O(B, default, simple, xmp, inf-ruby$B$,(B
-		    $BMQ0U$5$l$F$$$^$9(B. 
-  --inf-ruby-mode   emacs$B$N(Binf-ruby-mode$BMQ$N%W%m%s%W%HI=<($r9T$J$&(B. $BFC(B
-		    $B$K;XDj$,$J$$8B$j(B, readline$B%i%$%V%i%j$O;H$o$J$/$J$k(B.
-  --simple-prompt   $BHs>o$K%7%s%W%k$J%W%m%s%W%H$rMQ$$$k%b!<%I$G$9(B.
-  --noprompt	    $B%W%m%s%W%HI=<($r9T$J$o$J$$(B.
-  --tracer	    $B%3%^%s%I<B9T;~$K%H%l!<%9$r9T$J$&(B.
+		    プロンプトモードを切替えます. 現在定義されているプ
+		    ロンプトモードは, default, simple, xmp, inf-rubyが
+		    用意されています. 
+  --inf-ruby-mode   emacsのinf-ruby-mode用のプロンプト表示を行なう. 特
+		    に指定がない限り, readlineライブラリは使わなくなる.
+  --simple-prompt   非常にシンプルなプロンプトを用いるモードです.
+  --noprompt	    プロンプト表示を行なわない.
+  --tracer	    コマンド実行時にトレースを行なう.
   --back-trace-limit n
-		    $B%P%C%/%H%l!<%9I=<($r%P%C%/%H%l!<%9$NF,$+$i(B n, $B8e$m(B
-		    $B$+$i(Bn$B$@$19T$J$&(B. $B%G%U%)%k%H$O(B16 
-  --irb_debug n	    irb$B$N%G%P%C%0%G%P%C%0%l%Y%k$r(Bn$B$K at _Dj$9$k(B($BMxMQ$7$J(B
-		    $B$$J}$,L5Fq$G$7$g$&(B).
-  -v, --version	    irb$B$N%P!<%8%g%s$rI=<($9$k(B
+		    バックトレース表示をバックトレースの頭から n, 後ろ
+		    からnだけ行なう. デフォルトは16 
+  --irb_debug n	    irbのデバッグデバッグレベルをnに設定する(利用しな
+		    い方が無難でしょう).
+  -v, --version	    irbのバージョンを表示する
+
+# vim:fileencoding=utf-8

Modified: MacRuby/branches/experimental/lib/irb/locale.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/locale.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/locale.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,50 +1,59 @@
 #
 #   irb/locale.rb - internationalization module
 #   	$Release Version: 0.9.5$
-#   	$Revision: 15536 $
+#   	$Revision: 20889 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
 #
 #   
 #
-
-autoload :Kconv, "kconv"
-
 module IRB
   class Locale
-    @RCS_ID='-$Id: locale.rb 15536 2008-02-18 04:07:56Z akr $-'
+    @RCS_ID='-$Id: locale.rb 20889 2008-12-20 02:02:48Z yugui $-'
 
-    JPDefaultLocale = "ja"
+    LOCALE_NAME_RE = %r[
+      (?<language>[[:alpha:]]{2})
+      (?:_
+       (?<territory>[[:alpha:]]{2,3})
+       (?:\.
+	(?<codeset>[^@]+)
+       )?
+      )?
+      (?:@
+       (?<modifier>.*)
+      )?
+    ]x
     LOCALE_DIR = "/lc/"
 
+    @@legacy_encoding_alias_map = {}.freeze
+
     def initialize(locale = nil)
-      @lang = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C" 
-    end
+      @lang = @territory = @encoding_name = @modifier = nil
+      @locale = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] || "C" 
+      if m = LOCALE_NAME_RE.match(@locale)
+	@lang, @territory, @encoding_name, @modifier = m[:language], m[:territory], m[:codeset], m[:modifier]
 
-    attr_reader :lang
-
-    def lc2kconv(lang)
-      case lang
-      when "ja_JP.ujis", "ja_JP.euc", "ja_JP.eucJP", "ja_JP.EUC-JP"
-        Kconv::EUC
-      when "ja_JP.sjis", "ja_JP.SJIS"
-        Kconv::SJIS
-      when /ja_JP.utf-?8/i
-	Kconv::UTF8
+	if @encoding_name
+	  begin load 'irb/encoding_aliases.rb'; rescue LoadError; end
+	  if @encoding = @@legacy_encoding_alias_map[@encoding_name]
+	    warn "%s is obsolete. use %s" % ["#{@lang}_#{@territory}.#{@encoding_name}", "#{@lang}_#{@territory}.#{@encoding.name}"]
+	  end
+	  @encoding = Encoding.find(@encoding_name) rescue nil
+	end
       end
+      @encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
     end
-    private :lc2kconv
 
+    attr_reader :lang, :territory, :encoding, :modifieer
+
     def String(mes)
       mes = super(mes)
-      case @lang
-      when /^ja/
-	mes = Kconv::kconv(mes, lc2kconv(@lang))
+      if @encoding
+	mes.encode(@encoding) 
       else
 	mes
       end
-      mes
     end
 
     def format(*opts)
@@ -106,27 +115,20 @@
       dir = "" if dir == "."
       base = File.basename(file)
 
-      if /^ja(_JP)?$/ =~ @lang
- 	back, @lang = @lang, "C"
+      if dir[0] == ?/ #/
+	lc_path = search_file(dir, base)
+	return real_load(lc_path, priv) if lc_path
       end
-      begin
-	if dir[0] == ?/ #/
-	  lc_path = search_file(dir, base)
-	  return real_load(lc_path, priv) if lc_path
-	end
-	
-	for path in $:
-	  lc_path = search_file(path + "/" + dir, base)
-	  return real_load(lc_path, priv) if lc_path
-	end
-      ensure
-	@lang = back if back
+
+      for path in $:
+	lc_path = search_file(path + "/" + dir, base)
+	return real_load(lc_path, priv) if lc_path
       end
       raise LoadError, "No such file to load -- #{file}"
     end 
 
     def real_load(path, priv)
-      src = self.String(File.read(path))
+      src = MagicFile.open(path){|f| f.read}
       if priv
 	eval("self", TOPLEVEL_BINDING).extend(Module.new {eval(src, nil, path)})
       else
@@ -152,29 +154,39 @@
     end
 
     def search_file(path, file)
-      if File.exist?(p1 = path + lc_path(file, "C"))
-	if File.exist?(p2 = path + lc_path(file))
-	  return p2
-	else
-	end
-	return p1
-      else
+      each_sublocale do |lc|
+	full_path = path + lc_path(file, lc)
+	return full_path if File.exist?(full_path)
       end
       nil
     end
     private :search_file
 
-    def lc_path(file = "", lc = @lang)
-      case lc
-      when "C"
+    def lc_path(file = "", lc = @locale)
+      if lc.nil?
 	LOCALE_DIR + file
-      when /^ja/
-	LOCALE_DIR + "ja/" + file
       else
 	LOCALE_DIR + @lang + "/" + file
       end
     end
     private :lc_path
+
+    def each_sublocale
+      if @lang
+	if @territory
+	  if @encoding_name
+	    yield "#{@lang}_#{@territory}.#{@encoding_name}@#{@modifier}" if @modifier
+	    yield "#{@lang}_#{@territory}.#{@encoding_name}"
+	  end
+	  yield "#{@lang}_#{@territory}@#{@modifier}" if @modifier
+	  yield "#{@lang}_#{@territory}"
+	end
+	yield "#{@lang}@#{@modifier}" if @modifier
+	yield "#{@lang}"
+      end
+      yield nil
+    end
+    private :each_sublocale
   end
 end
 

Copied: MacRuby/branches/experimental/lib/irb/magic-file.rb (from rev 1886, MacRuby/trunk/lib/irb/magic-file.rb)
===================================================================
--- MacRuby/branches/experimental/lib/irb/magic-file.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/irb/magic-file.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,36 @@
+module IRB
+  class << (MagicFile = Object.new)
+    # see parser_magic_comment in parse.y
+    ENCODING_SPEC_RE = %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
+
+    def open(path)
+      io = File.open(path, 'rb')
+      line = io.gets
+      line = io.gets if line[0,2] == "#!"
+      encoding = detect_encoding(line)
+      encoding ||= default_src_encoding
+      io.rewind
+      io.set_encoding(encoding, nil)
+
+      if block_given?
+        begin
+          return (yield io)
+        ensure
+          io.close
+        end
+      else
+        return io
+      end
+    end
+
+    private
+    def detect_encoding(line)
+      return unless line[0] == ?#
+      line = line[1..-1]
+      line = $1 if line[/-\*-\s*(.*?)\s*-*-$/]
+      return nil unless ENCODING_SPEC_RE =~ line
+      encoding = $1
+      return encoding.sub(/-(?:mac|dos|unix)/i, '')
+    end
+  end
+end

Modified: MacRuby/branches/experimental/lib/irb/notifier.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/notifier.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/notifier.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
-#   notifier.rb - optput methods used by irb 
+#   notifier.rb - output methods used by irb 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 16810 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --

Modified: MacRuby/branches/experimental/lib/irb/ruby-lex.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/ruby-lex.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/ruby-lex.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
-#   irb/ruby-lex.rb - ruby lexcal analizer
+#   irb/ruby-lex.rb - ruby lexcal analyzer
 #   	$Release Version: 0.9.5$
-#   	$Revision: 15267 $
+#   	$Revision: 20882 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -14,7 +14,7 @@
 require "irb/ruby-token"
 
 class RubyLex
-  @RCS_ID='-$Id: ruby-lex.rb 15267 2008-01-27 07:43:31Z naruse $-'
+  @RCS_ID='-$Id: ruby-lex.rb 20882 2008-12-19 11:37:59Z yugui $-'
 
   extend Exception2MessageMapper
   def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
@@ -240,6 +240,7 @@
 	    end
 	  end
 	  if @line != "\n"
+      @line.force_encoding(@io.encoding)
 	    yield @line, @exp_line_no
 	  end
 	  break unless l

Modified: MacRuby/branches/experimental/lib/irb/slex.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/slex.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/slex.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
-#   irb/slex.rb - symple lex analizer
+#   irb/slex.rb - simple lex analyzer
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 16810 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -14,7 +14,7 @@
 
 module IRB
   class SLex
-    @RCS_ID='-$Id: slex.rb 14912 2008-01-06 15:49:38Z akr $-'
+    @RCS_ID='-$Id: slex.rb 16810 2008-06-04 09:37:38Z matz $-'
 
     extend Exception2MessageMapper
     def_exception :ErrNodeNothing, "node nothing"

Copied: MacRuby/branches/experimental/lib/irb/src_encoding.rb (from rev 1886, MacRuby/trunk/lib/irb/src_encoding.rb)
===================================================================
--- MacRuby/branches/experimental/lib/irb/src_encoding.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/irb/src_encoding.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,4 @@
+# DO NOT WRITE ANY MAGIC COMMENT HERE.
+def default_src_encoding
+  return __ENCODING__
+end

Modified: MacRuby/branches/experimental/lib/irb/xmp.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb/xmp.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb/xmp.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   xmp.rb - irb version of gotoken xmp
 #   	$Release Version: 0.9$
-#   	$Revision: 14912 $
+#   	$Revision: 21633 $
 #   	by Keiju ISHITSUKA(Nippon Rational Inc.)
 #
 # --
@@ -13,7 +13,7 @@
 require "irb/frame"
 
 class XMP
-  @RCS_ID='-$Id: xmp.rb 14912 2008-01-06 15:49:38Z akr $-'
+  @RCS_ID='-$Id: xmp.rb 21633 2009-01-17 12:19:53Z yugui $-'
 
   def initialize(bind = nil)
     IRB.init_config(nil)
@@ -72,8 +72,20 @@
     end
 
     def puts(exps)
+      if @encoding and exps.encoding != @encoding
+	enc = Encoding.compatible?(@exps.join("\n"), exps)
+	if enc.nil?
+	  raise Encoding::CompatibilityError, "Encoding in which the passed exression is encoded is not compatible to the preceding's one"
+	else
+	  @encoding = enc
+	end
+      else
+	@encoding = exps.encoding
+      end
       @exps.concat exps.split(/\n/)
     end
+
+    attr_reader :encoding
   end
 end
 

Modified: MacRuby/branches/experimental/lib/irb.rb
===================================================================
--- MacRuby/branches/experimental/lib/irb.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/irb.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   irb.rb - irb main module
 #   	$Release Version: 0.9.5 $
-#   	$Revision: 15689 $
+#   	$Revision: 20186 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -22,7 +22,7 @@
 STDOUT.sync = true
 
 module IRB
-  @RCS_ID='-$Id: irb.rb 15689 2008-03-04 12:37:05Z matz $-'
+  @RCS_ID='-$Id: irb.rb 20186 2008-11-11 08:41:29Z yugui $-'
 
   class Abort < Exception;end
 
@@ -107,7 +107,7 @@
 	  f = @context.prompt_c
 	elsif indent > 0
 	  f = @context.prompt_n
-	else @context.prompt_i
+	else
 	  f = @context.prompt_i
 	end
 	f = "" unless f
@@ -308,7 +308,7 @@
     def inspect
       ary = []
       for iv in instance_variables
-	case iv
+	case (iv = iv.to_s)
 	when "@signal_status"
 	  ary.push format("%s=:%s", iv, @signal_status.id2name)
 	when "@context"

Modified: MacRuby/branches/experimental/lib/logger.rb
===================================================================
--- MacRuby/branches/experimental/lib/logger.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/logger.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,4 +1,4 @@
-# logger.rb - saimple logging utility
+# logger.rb - simple logging utility
 # Copyright (C) 2000-2003, 2005  NAKAMURA, Hiroshi <nakahiro at sarion.co.jp>.
 
 require 'monitor'
@@ -12,7 +12,7 @@
 # License::
 #   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.
-# Revision:: $Id: logger.rb 12284 2007-05-16 12:52:52Z nahi $
+# Revision:: $Id: logger.rb 20321 2008-11-22 14:52:06Z yugui $
 #
 # See Logger for documentation.
 #
@@ -181,8 +181,14 @@
 
 class Logger
   VERSION = "1.2.6"
-  /: (\S+),v (\S+)/ =~ %q$Id: logger.rb 12284 2007-05-16 12:52:52Z nahi $
-  ProgName = "#{$1}/#{$2}"
+  id, name, rev = %w$Id: logger.rb 20321 2008-11-22 14:52:06Z yugui $
+  if name
+    name = name.chomp(",v")
+  else
+    name = File.basename(__FILE__)
+  end
+  rev ||= "v#{VERSION}"
+  ProgName = "#{name}/#{rev}"
 
   class Error < RuntimeError; end
   class ShiftingError < Error; end

Modified: MacRuby/branches/experimental/lib/mathn.rb
===================================================================
--- MacRuby/branches/experimental/lib/mathn.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/mathn.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -9,125 +9,56 @@
 #   
 #
 
-require "complex.rb"
-require "rational.rb"
+require "cmath.rb"
 require "matrix.rb"
+require "prime.rb"
 
-class Integer
+require "mathn/rational"
+require "mathn/complex"
 
-  def Integer.from_prime_division(pd)
-    value = 1
-    for prime, index in pd
-      value *= prime**index
-    end
-    value
-  end
-  
-  def prime_division
-    raise ZeroDivisionError if self == 0
-    ps = Prime.new
-    value = self
-    pv = []
-    for prime in ps
-      count = 0
-      while (value1, mod = value.divmod(prime)
-	     mod) == 0
-	value = value1
-	count += 1
-      end
-      if count != 0
-	pv.push [prime, count]
-      end
-      break if prime * prime  >= value
-    end
-    if value > 1
-      pv.push [value, 1]
-    end
-    return pv
-  end
+unless defined?(Math.exp!)
+  Object.instance_eval{remove_const :Math}
+  Math = CMath
 end
-  
-class Prime
-  include Enumerable
-  # These are included as class variables to cache them for later uses.  If memory
-  #   usage is a problem, they can be put in Prime#initialize as instance variables.
 
-  # There must be no primes between @@primes[-1] and @@next_to_check.
-  @@primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
-  # @@next_to_check % 6 must be 1.  
-  @@next_to_check = 103            # @@primes[-1] - @@primes[-1] % 6 + 7
-  @@ulticheck_index = 3            # @@primes.index(@@primes.reverse.find {|n|
-                                   #   n < Math.sqrt(@@next_to_check) })
-  @@ulticheck_next_squared = 121   # @@primes[@@ulticheck_index + 1] ** 2
+class Fixnum
+  remove_method :/
+  alias / quo
 
-  class << self
-    # Return the prime cache.
-    def cache
-      return @@primes
-    end
-    alias primes cache
-    alias primes_so_far cache
-  end
-  
-  def initialize
-    @index = -1
-  end
-  
-  # Return primes given by this instance so far.
-  def primes
-    return @@primes[0, @index + 1]
-  end
-  alias primes_so_far primes
-  
-  def succ
-    @index += 1
-    while @index >= @@primes.length
-      # Only check for prime factors up to the square root of the potential primes,
-      #   but without the performance hit of an actual square root calculation.
-      if @@next_to_check + 4 > @@ulticheck_next_squared
-        @@ulticheck_index += 1
-        @@ulticheck_next_squared = @@primes.at(@@ulticheck_index + 1) ** 2
-      end
-      # Only check numbers congruent to one and five, modulo six. All others
-      #   are divisible by two or three.  This also allows us to skip checking against
-      #   two and three.
-      @@primes.push @@next_to_check if @@primes[2..@@ulticheck_index].find {|prime| @@next_to_check % prime == 0 }.nil?
-      @@next_to_check += 4
-      @@primes.push @@next_to_check if @@primes[2..@@ulticheck_index].find {|prime| @@next_to_check % prime == 0 }.nil?
-      @@next_to_check += 2 
-    end
-    return @@primes[@index]
-  end
-  alias next succ
+  alias power! ** unless defined?(0.power!)
 
-  def each
-    return to_enum(:each) unless block_given?
-    loop do
-      yield succ
+  def ** (other)
+    if self < 0 && other.round != other
+      Complex(self, 0.0) ** other
+    else
+      power!(other)
     end
   end
-end
 
-class Fixnum
-  remove_method :/
-  alias / quo
 end
 
 class Bignum
   remove_method :/
   alias / quo
-end
 
-class Rational
-  Unify = true
+  alias power! ** unless defined?(0.power!)
 
-  alias power! **
+  def ** (other)
+    if self < 0 && other.round != other
+      Complex(self, 0.0) ** other
+    else
+      power!(other)
+    end
+  end
 
+end
+
+class Rational
   def ** (other)
     if other.kind_of?(Rational)
       other2 = other
       if self < 0
-	return Complex.__send__(:new!, self, 0) ** other
+	return Complex(self, 0.0) ** other
       elsif other == 0
 	return Rational(1,1)
       elsif self == 0
@@ -183,57 +114,13 @@
       x ** y
     end
   end
-
-  def power2(other)
-    if other.kind_of?(Rational)
-      if self < 0
-	return Complex.__send__(:new!, self, 0) ** other
-      elsif other == 0
-	return Rational(1,1)
-      elsif self == 0
-	return Rational(0,1)
-      elsif self == 1
-	return Rational(1,1)
-      end
-      
-      dem = nil
-      x = self.denominator.to_f.to_i
-      neard = self.denominator.to_f ** (1.0/other.denominator.to_f)
-      loop do
-	if (neard**other.denominator == self.denominator)
-	  dem = neaed
-	  break
-	end
-      end
-      nearn = self.numerator.to_f ** (1.0/other.denominator.to_f)
-      Rational(num,den)
-      
-    elsif other.kind_of?(Integer)
-      if other > 0
-	num = numerator ** other
-	den = denominator ** other
-      elsif other < 0
-	num = denominator ** -other
-	den = numerator ** -other
-      elsif other == 0
-	num = 1
-	den = 1
-      end
-      Rational(num, den)
-    elsif other.kind_of?(Float)
-      Float(self) ** other
-    else
-      x , y = other.coerce(self)
-      x ** y
-    end
-  end
 end
 
 module Math
   remove_method(:sqrt)
   def sqrt(a)
     if a.kind_of?(Complex)
-      abs = sqrt(a.real*a.real + a.image*a.image)
+      abs = sqrt(a.real*a.real + a.imag*a.imag)
 #      if not abs.kind_of?(Rational)
 #	return a**Rational(1,2)
 #      end
@@ -242,11 +129,13 @@
 #      if !(x.kind_of?(Rational) and y.kind_of?(Rational))
 #	return a**Rational(1,2)
 #      end
-      if a.image >= 0 
+      if a.imag >= 0 
 	Complex(x, y)
       else
 	Complex(x, -y)
       end
+    elsif a.respond_to?(:nan?) and a.nan?
+      a
     elsif a >= 0
       rsqrt(a)
     else
@@ -303,6 +192,15 @@
   module_function :rsqrt
 end
 
-class Complex
-  Unify = true
+class Float
+  alias power! **
+
+  def ** (other)
+    if self < 0 && other.round != other
+      Complex(self, 0.0) ** other
+    else
+      power!(other)
+    end
+  end
+
 end

Modified: MacRuby/branches/experimental/lib/matrix.rb
===================================================================
--- MacRuby/branches/experimental/lib/matrix.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/matrix.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -18,7 +18,6 @@
 # See classes Matrix and Vector for documentation. 
 #
 
-
 require "e2mmap.rb"
 
 module ExceptionForMatrix # :nodoc:
@@ -141,10 +140,8 @@
   #
   #
   def Matrix.columns(columns)
-    rows = (0 .. columns[0].size - 1).collect {
-      |i|
-      (0 .. columns.size - 1).collect {
-        |j|
+    rows = (0 .. columns[0].size - 1).collect {|i|
+      (0 .. columns.size - 1).collect {|j|
         columns[j][i]
       }
     }
@@ -160,8 +157,7 @@
   #
   def Matrix.diagonal(*values)
     size = values.size
-    rows = (0 .. size  - 1).collect {
-      |j|
+    rows = (0 .. size  - 1).collect {|j|
       row = Array.new(size).fill(0, 0, size)
       row[j] = values[j]
       row
@@ -312,13 +308,11 @@
   #
   def column(j) # :yield: e
     if block_given?
-      0.upto(row_size - 1) do
-        |i|
+      0.upto(row_size - 1) do |i|
         yield @rows[i][j]
       end
     else
-      col = (0 .. row_size - 1).collect {
-        |i|
+      col = (0 .. row_size - 1).collect {|i|
         @rows[i][j]
       }
       Vector.elements(col, false)
@@ -365,8 +359,7 @@
       Matrix.Raise ArgumentError, param.inspect
     end
     
-    rows = @rows[from_row, size_row].collect{
-      |row|
+    rows = @rows[from_row, size_row].collect{|row|
       row[from_col, size_col]
     }
     Matrix.rows(rows, false)
@@ -410,17 +403,20 @@
     
     other.compare_by_row_vectors(@rows)
   end
-  alias eql? ==
+  def eql?(other)
+    return false unless Matrix === other
+    
+    other.compare_by_row_vectors(@rows, :eql?)
+  end
   
   #
   # Not really intended for general consumption.
   #
-  def compare_by_row_vectors(rows)
+  def compare_by_row_vectors(rows, comparison = :==)
     return false unless @rows.size == rows.size
     
-    0.upto(@rows.size - 1) do
-      |i|
-      return false unless @rows[i] == rows[i]
+    0.upto(@rows.size - 1) do |i|
+      return false unless @rows[i].send(comparison, rows[i])
     end
     true
   end
@@ -459,10 +455,8 @@
   def *(m) # m is matrix or vector or number
     case(m)
     when Numeric
-      rows = @rows.collect {
-        |row|
-        row.collect {
-          |e|
+      rows = @rows.collect {|row|
+        row.collect {|e|
           e * m
         }
       }
@@ -474,13 +468,10 @@
     when Matrix
       Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
     
-      rows = (0 .. row_size - 1).collect {
-        |i|
-        (0 .. m.column_size - 1).collect {
-          |j|
+      rows = (0 .. row_size - 1).collect {|i|
+        (0 .. m.column_size - 1).collect {|j|
           vij = 0
-          0.upto(column_size - 1) do
-            |k|
+          0.upto(column_size - 1) do |k|
             vij += self[i, k] * m[k, j]
           end
           vij
@@ -513,10 +504,8 @@
     
     Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
     
-    rows = (0 .. row_size - 1).collect {
-      |i|
-      (0 .. column_size - 1).collect {
-        |j|
+    rows = (0 .. row_size - 1).collect {|i|
+      (0 .. column_size - 1).collect {|j|
         self[i, j] + m[i, j]
       }
     }
@@ -543,10 +532,8 @@
     
     Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
     
-    rows = (0 .. row_size - 1).collect {
-      |i|
-      (0 .. column_size - 1).collect {
-        |j|
+    rows = (0 .. row_size - 1).collect {|i|
+      (0 .. column_size - 1).collect {|j|
         self[i, j] - m[i, j]
       }
     }
@@ -562,10 +549,8 @@
   def /(other)
     case other
     when Numeric
-      rows = @rows.collect {
-        |row|
-        row.collect {
-          |e|
+      rows = @rows.collect {|row|
+        row.collect {|e|
           e / other
         }
       }
@@ -600,7 +585,7 @@
     for k in 0..size
       i = k
       akk = a[k][k].abs
-      for j in (k+1)..size
+      ((k+1)..size).each do |j|
         v = a[j][k].abs
         if v > akk
           i = j
@@ -619,22 +604,18 @@
         q = a[i][k].quo(akk)
         a[i][k] = 0
         
-        (k + 1).upto(size) do   
-          |j|
+	for j in (k + 1).. size
           a[i][j] -= a[k][j] * q
         end
-        0.upto(size) do
-          |j|
+        for j in 0..size
           @rows[i][j] -= @rows[k][j] * q
         end
       end
       
-      (k + 1).upto(size) do
-        |j|
+      for j in (k + 1).. size
         a[k][j] = a[k][j].quo(akk)
       end
-      0.upto(size) do
-        |j|
+      for j in 0..size
         @rows[k][j] = @rows[k][j].quo(akk)
       end
     end
@@ -698,26 +679,27 @@
     
     det = 1
     k = 0
-    begin 
+    loop do
       if (akk = a[k][k]) == 0
         i = k
-        begin
-          return 0 if (i += 1) > size
-        end while a[i][k] == 0
+        loop do
+          return 0 if (ii += 1) > size
+          break unless a[i][k] == 0
+        end
         a[i], a[k] = a[k], a[i]
         akk = a[k][k]
         det *= -1
       end
-      (k + 1).upto(size) do
-        |i|
+
+      for i in k + 1 .. size
         q = a[i][k].quo(akk)
-        (k + 1).upto(size) do
-          |j|
+        (k + 1).upto(size) do |j|
           a[i][j] -= a[k][j] * q
         end
       end
       det *= akk
-    end while (k += 1) <= size
+      break unless (k += 1) <= size
+    end
     det
   end
   alias det determinant
@@ -740,16 +722,18 @@
     
     det = 1
     k = 0
-    begin 
+    loop do
       if a[k][k].zero?
         i = k
-        begin
+        loop do
           return 0 if (i += 1) > size
-        end while a[i][k].zero?
+          break unless a[i][k].zero?
+        end
         a[i], a[k] = a[k], a[i]
         det *= -1
       end
-      (k + 1).upto(size) do |i|
+
+      for i in (k + 1)..size
         q = a[i][k].quo(a[k][k])
         k.upto(size) do |j|
           a[i][j] -= a[k][j] * q
@@ -761,7 +745,8 @@
         end
       end
       det *= a[k][k]
-    end while (k += 1) <= size
+      break unless (k += 1) <= size
+    end
     det
   end
   alias det_e determinant_e
@@ -786,31 +771,32 @@
     end
     rank = 0
     k = 0
-    begin
+    loop do
       if (akk = a[k][k]) == 0
         i = k
         exists = true
-        begin
+        loop do
           if (i += 1) > a_column_size - 1
             exists = false
             break
           end
-        end while a[i][k] == 0
+          break unless a[i][k] == 0
+        end
         if exists
           a[i], a[k] = a[k], a[i]
           akk = a[k][k]
         else
           i = k
           exists = true
-          begin
+          loop do
             if (i += 1) > a_row_size - 1
               exists = false
               break
             end
-          end while a[k][i] == 0
+            break unless a[k][i] == 0
+          end
           if exists
-            k.upto(a_column_size - 1) do
-              |j|
+            k.upto(a_column_size - 1) do |j|
               a[j][k], a[j][i] = a[j][i], a[j][k]
             end
             akk = a[k][k]
@@ -819,16 +805,16 @@
           end
         end
       end
-      (k + 1).upto(a_row_size - 1) do
-        |i|
+
+      for i in (k + 1)..(a_row_size - 1)
         q = a[i][k].quo(akk)
-        (k + 1).upto(a_column_size - 1) do
-          |j|
+	for j in (k + 1)..(a_column_size - 1)
           a[i][j] -= a[k][j] * q
         end
       end
       rank += 1
-    end while (k += 1) <= a_column_size - 1
+      break unless (k += 1) <= a_column_size - 1
+    end
     return rank
   end
 
@@ -874,8 +860,7 @@
   #
   def trace
     tr = 0
-    0.upto(column_size - 1) do
-      |i|
+    0.upto(column_size - 1) do |i|
       tr += @rows[i][i]
     end
     tr
@@ -917,8 +902,7 @@
   # Returns an array of the row vectors of the matrix.  See Vector.
   #
   def row_vectors
-    rows = (0 .. row_size - 1).collect {
-      |i|
+    rows = (0 .. row_size - 1).collect {|i|
       row(i)
     }
     rows
@@ -928,8 +912,7 @@
   # Returns an array of the column vectors of the matrix.  See Vector.
   #
   def column_vectors
-    columns = (0 .. column_size - 1).collect {
-      |i|
+    columns = (0 .. column_size - 1).collect {|i|
       column(i)
     }
     columns
@@ -962,8 +945,7 @@
   # Overrides Object#to_s
   #
   def to_s
-    "Matrix[" + @rows.collect{
-      |row|
+    "Matrix[" + @rows.collect{|row|
       "[" + row.collect{|e| e.to_s}.join(", ") + "]"
     }.join(", ")+"]"
   end
@@ -1170,8 +1152,7 @@
   #
   def each2(v) # :yield: e1, e2
     Vector.Raise ErrDimensionMismatch if size != v.size
-    0.upto(size - 1) do
-      |i|
+    0.upto(size - 1) do |i|
       yield @elements[i], v[i]
     end
   end
@@ -1182,8 +1163,7 @@
   #
   def collect2(v) # :yield: e1, e2
     Vector.Raise ErrDimensionMismatch if size != v.size
-    (0 .. size - 1).collect do
-      |i|
+    (0 .. size - 1).collect do |i|
       yield @elements[i], v[i]
     end
   end
@@ -1200,13 +1180,17 @@
     
     other.compare_by(@elements)
   end
-  alias eqn? ==
+  def eql?(other)
+    return false unless Vector === other
+    
+    other.compare_by(@elements, :eql?)
+  end
   
   #
   # For internal use.
   #
-  def compare_by(elements)
-    @elements == elements
+  def compare_by(elements, comparison = :==)
+    @elements.send(comparison, elements)
   end
   
   #
@@ -1250,8 +1234,7 @@
     case v
     when Vector
       Vector.Raise ErrDimensionMismatch if size != v.size
-      els = collect2(v) {
-        |v1, v2|
+      els = collect2(v) {|v1, v2|
         v1 + v2
       }
       Vector.elements(els, false)
@@ -1270,8 +1253,7 @@
     case v
     when Vector
       Vector.Raise ErrDimensionMismatch if size != v.size
-      els = collect2(v) {
-        |v1, v2|
+      els = collect2(v) {|v1, v2|
         v1 - v2
       }
       Vector.elements(els, false)
@@ -1295,8 +1277,7 @@
     Vector.Raise ErrDimensionMismatch if size != v.size
     
     p = 0
-    each2(v) {
-      |v1, v2|
+    each2(v) {|v1, v2|
       p += v1 * v2
     }
     p
@@ -1306,8 +1287,7 @@
   # Like Array#collect.
   #
   def collect # :yield: e
-    els = @elements.collect {
-      |v|
+    els = @elements.collect {|v|
       yield v
     }
     Vector.elements(els, false)
@@ -1318,8 +1298,7 @@
   # Like Vector#collect2, but returns a Vector instead of an Array.
   #
   def map2(v) # :yield: e1, e2
-    els = collect2(v) {
-      |v1, v2|
+    els = collect2(v) {|v1, v2|
       yield v1, v2
     }
     Vector.elements(els, false)

Deleted: MacRuby/branches/experimental/lib/minitest/autorun.rb
===================================================================
--- MacRuby/trunk/lib/minitest/autorun.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/minitest/autorun.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,9 +0,0 @@
-############################################################
-# This file is imported from a different project.
-# DO NOT make modifications in this repo.
-# File a patch instead and assign it to Ryan Davis
-############################################################
-
-require 'minitest/unit'
-
-MiniTest::Unit.autorun

Copied: MacRuby/branches/experimental/lib/minitest/autorun.rb (from rev 1886, MacRuby/trunk/lib/minitest/autorun.rb)
===================================================================
--- MacRuby/branches/experimental/lib/minitest/autorun.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/minitest/autorun.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,9 @@
+############################################################
+# This file is imported from a different project.
+# DO NOT make modifications in this repo.
+# File a patch instead and assign it to Ryan Davis
+############################################################
+
+require 'minitest/unit'
+
+MiniTest::Unit.autorun

Deleted: MacRuby/branches/experimental/lib/minitest/mock.rb
===================================================================
--- MacRuby/trunk/lib/minitest/mock.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/minitest/mock.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,37 +0,0 @@
-############################################################
-# This file is imported from a different project.
-# DO NOT make modifications in this repo.
-# File a patch instead and assign it to Ryan Davis
-############################################################
-
-class MockExpectationError < StandardError; end
-
-module MiniTest
-  class Mock
-    def initialize
-      @expected_calls = {}
-      @actual_calls = Hash.new {|h,k| h[k] = [] }
-    end
-
-    def expect(name, retval, args=[])
-      n, r, a = name, retval, args # for the closure below
-      @expected_calls[name] = { :retval => retval, :args => args }
-      self.class.__send__(:define_method, name) { |*x|
-        raise ArgumentError unless @expected_calls[n][:args].size == x.size
-        @actual_calls[n] << { :retval => r, :args => x }
-        retval
-      }
-      self
-    end
-
-    def verify
-      @expected_calls.each_key do |name|
-        expected = @expected_calls[name]
-        msg = "expected #{name}, #{expected.inspect}"
-        raise MockExpectationError, msg unless
-          @actual_calls.has_key? name and @actual_calls[name].include?(expected)
-      end
-      true
-    end
-  end
-end

Copied: MacRuby/branches/experimental/lib/minitest/mock.rb (from rev 1886, MacRuby/trunk/lib/minitest/mock.rb)
===================================================================
--- MacRuby/branches/experimental/lib/minitest/mock.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/minitest/mock.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,37 @@
+############################################################
+# This file is imported from a different project.
+# DO NOT make modifications in this repo.
+# File a patch instead and assign it to Ryan Davis
+############################################################
+
+class MockExpectationError < StandardError; end
+
+module MiniTest
+  class Mock
+    def initialize
+      @expected_calls = {}
+      @actual_calls = Hash.new {|h,k| h[k] = [] }
+    end
+
+    def expect(name, retval, args=[])
+      n, r, a = name, retval, args # for the closure below
+      @expected_calls[name] = { :retval => retval, :args => args }
+      self.class.__send__(:define_method, name) { |*x|
+        raise ArgumentError unless @expected_calls[n][:args].size == x.size
+        @actual_calls[n] << { :retval => r, :args => x }
+        retval
+      }
+      self
+    end
+
+    def verify
+      @expected_calls.each_key do |name|
+        expected = @expected_calls[name]
+        msg = "expected #{name}, #{expected.inspect}"
+        raise MockExpectationError, msg unless
+          @actual_calls.has_key? name and @actual_calls[name].include?(expected)
+      end
+      true
+    end
+  end
+end

Deleted: MacRuby/branches/experimental/lib/minitest/spec.rb
===================================================================
--- MacRuby/trunk/lib/minitest/spec.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/minitest/spec.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,89 +0,0 @@
-############################################################
-# This file is imported from a different project.
-# DO NOT make modifications in this repo.
-# File a patch instead and assign it to Ryan Davis
-############################################################
-
-#!/usr/bin/ruby -w
-
-require 'minitest/unit'
-
-class Module
-  def infect_with_assertions pos_prefix, neg_prefix, skip_re, map = {}
-    MiniTest::Assertions.public_instance_methods(false).each do |meth|
-      meth = meth.to_s
-
-      new_name = case meth
-                 when /^assert/ then
-                   meth.sub(/^assert/, pos_prefix.to_s)
-                 when /^refute/ then
-                   meth.sub(/^refute/, neg_prefix.to_s)
-                 end
-      next unless new_name
-      next if new_name =~ skip_re
-
-      regexp, replacement = map.find { |re, _| new_name =~ re }
-      new_name.sub! regexp, replacement if replacement
-
-      # warn "%-22p -> %p %p" % [meth, new_name, regexp]
-      self.class_eval <<-EOM
-        def #{new_name} *args, &block
-          return MiniTest::Spec.current.#{meth}(*args, &self)     if Proc === self
-          return MiniTest::Spec.current.#{meth}(args.first, self) if args.size == 1
-          return MiniTest::Spec.current.#{meth}(self, *args)
-        end
-      EOM
-    end
-  end
-end
-
-Object.infect_with_assertions(:must, :wont,
-                              /^(must|wont)$|wont_(throw)|
-                                 must_(block|not?_|nothing|raise$)/x,
-                              /(must_throw)s/                 => '\1',
-                              /(?!not)_same/                  => '_be_same_as',
-                              /_in_/                          => '_be_within_',
-                              /_operator/                     => '_be',
-                              /_includes/                     => '_include',
-                              /(must|wont)_(.*_of|nil|empty)/ => '\1_be_\2',
-                              /must_raises/                   => 'must_raise')
-
-class Object
-  alias :must_be_close_to :must_be_within_delta
-  alias :wont_be_close_to :wont_be_within_delta
-end
-
-module Kernel
-  def describe desc, &block
-    cls = Class.new(MiniTest::Spec)
-    Object.const_set desc.to_s.split(/\W+/).map { |s| s.capitalize }.join, cls
-
-    cls.class_eval(&block)
-  end
-  private :describe
-end
-
-class MiniTest::Spec < MiniTest::Unit::TestCase
-  def self.current
-    @@current_spec
-  end
-
-  def initialize name
-    super
-    @@current_spec = self
-  end
-
-  def self.before(type = :each, &block)
-    raise "unsupported before type: #{type}" unless type == :each
-    define_method :setup, &block
-  end
-
-  def self.after(type = :each, &block)
-    raise "unsupported after type: #{type}" unless type == :each
-    define_method :teardown, &block
-  end
-
-  def self.it desc, &block
-    define_method "test_#{desc.gsub(/\W+/, '_').downcase}", &block
-  end
-end

Copied: MacRuby/branches/experimental/lib/minitest/spec.rb (from rev 1886, MacRuby/trunk/lib/minitest/spec.rb)
===================================================================
--- MacRuby/branches/experimental/lib/minitest/spec.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/minitest/spec.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,89 @@
+############################################################
+# This file is imported from a different project.
+# DO NOT make modifications in this repo.
+# File a patch instead and assign it to Ryan Davis
+############################################################
+
+#!/usr/bin/ruby -w
+
+require 'minitest/unit'
+
+class Module
+  def infect_with_assertions pos_prefix, neg_prefix, skip_re, map = {}
+    MiniTest::Assertions.public_instance_methods(false).each do |meth|
+      meth = meth.to_s
+
+      new_name = case meth
+                 when /^assert/ then
+                   meth.sub(/^assert/, pos_prefix.to_s)
+                 when /^refute/ then
+                   meth.sub(/^refute/, neg_prefix.to_s)
+                 end
+      next unless new_name
+      next if new_name =~ skip_re
+
+      regexp, replacement = map.find { |re, _| new_name =~ re }
+      new_name.sub! regexp, replacement if replacement
+
+      # warn "%-22p -> %p %p" % [meth, new_name, regexp]
+      self.class_eval <<-EOM
+        def #{new_name} *args, &block
+          return MiniTest::Spec.current.#{meth}(*args, &self)     if Proc === self
+          return MiniTest::Spec.current.#{meth}(args.first, self) if args.size == 1
+          return MiniTest::Spec.current.#{meth}(self, *args)
+        end
+      EOM
+    end
+  end
+end
+
+Object.infect_with_assertions(:must, :wont,
+                              /^(must|wont)$|wont_(throw)|
+                                 must_(block|not?_|nothing|raise$)/x,
+                              /(must_throw)s/                 => '\1',
+                              /(?!not)_same/                  => '_be_same_as',
+                              /_in_/                          => '_be_within_',
+                              /_operator/                     => '_be',
+                              /_includes/                     => '_include',
+                              /(must|wont)_(.*_of|nil|empty)/ => '\1_be_\2',
+                              /must_raises/                   => 'must_raise')
+
+class Object
+  alias :must_be_close_to :must_be_within_delta
+  alias :wont_be_close_to :wont_be_within_delta
+end
+
+module Kernel
+  def describe desc, &block
+    cls = Class.new(MiniTest::Spec)
+    Object.const_set desc.to_s.split(/\W+/).map { |s| s.capitalize }.join, cls
+
+    cls.class_eval(&block)
+  end
+  private :describe
+end
+
+class MiniTest::Spec < MiniTest::Unit::TestCase
+  def self.current
+    @@current_spec
+  end
+
+  def initialize name
+    super
+    @@current_spec = self
+  end
+
+  def self.before(type = :each, &block)
+    raise "unsupported before type: #{type}" unless type == :each
+    define_method :setup, &block
+  end
+
+  def self.after(type = :each, &block)
+    raise "unsupported after type: #{type}" unless type == :each
+    define_method :teardown, &block
+  end
+
+  def self.it desc, &block
+    define_method "test_#{desc.gsub(/\W+/, '_').downcase}", &block
+  end
+end

Deleted: MacRuby/branches/experimental/lib/minitest/unit.rb
===================================================================
--- MacRuby/trunk/lib/minitest/unit.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/minitest/unit.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,497 +0,0 @@
-############################################################
-# This file is imported from a different project.
-# DO NOT make modifications in this repo.
-# File a patch instead and assign it to Ryan Davis
-############################################################
-
-##
-#
-# Totally minimal drop-in replacement for test-unit
-#
-# TODO: refute -> debunk, prove/rebut, show/deny... lots of possibilities
-
-module MiniTest
-  class Assertion < Exception; end
-  class Skip < Assertion; end
-
-  file = if RUBY_VERSION =~ /^1\.9/ then  # bt's expanded, but __FILE__ isn't :(
-           File.expand_path __FILE__
-         elsif  __FILE__ =~ /^[^\.]/ then # assume both relative
-           require 'pathname'
-           pwd = Pathname.new Dir.pwd
-           pn = Pathname.new File.expand_path(__FILE__)
-           pn = File.join(".", pn.relative_path_from(pwd)) unless pn.relative?
-           pn.to_s
-         else                             # assume both are expanded
-           __FILE__
-         end
-
-  # './lib' in project dir, or '/usr/local/blahblah' if installed
-  MINI_DIR = File.dirname(File.dirname(file))
-
-  def self.filter_backtrace bt
-    return ["No backtrace"] unless bt
-
-    new_bt = []
-    bt.each do |line|
-      break if line.rindex(MINI_DIR, 0)
-      new_bt << line
-    end
-
-    new_bt = bt.reject { |line| line.rindex(MINI_DIR, 0) } if new_bt.empty?
-    new_bt = bt.dup if new_bt.empty?
-    new_bt
-  end
-
-  module Assertions
-    def mu_pp(obj)
-      s = obj.inspect
-      s = s.force_encoding(Encoding.default_external) if defined? Encoding
-      s
-    end
-
-    def _assertions= n
-      @_assertions = n
-    end
-
-    def _assertions
-      @_assertions ||= 0
-    end
-
-    def assert test, msg = nil
-      msg ||= "Failed assertion, no message given."
-      self._assertions += 1
-      unless test then
-        msg = msg.call if Proc === msg
-        raise MiniTest::Assertion, msg
-      end
-      true
-    end
-
-    def assert_block msg = nil
-      msg = message(msg) { "Expected block to return true value" }
-      assert yield, msg
-    end
-
-    def assert_empty obj, msg = nil
-      msg = message(msg) { "Expected #{obj.inspect} to be empty" }
-      assert_respond_to obj, :empty?
-      assert obj.empty?, msg
-    end
-
-    def assert_equal exp, act, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(exp)}, not #{mu_pp(act)}" }
-      assert(exp == act, msg)
-    end
-
-    def assert_in_delta exp, act, delta = 0.001, msg = nil
-      n = (exp - act).abs
-      msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" }
-      assert delta >= n, msg
-    end
-
-    def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
-      assert_in_delta a, b, [a, b].min * epsilon, msg
-    end
-
-    def assert_includes collection, obj, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" }
-      assert_respond_to collection, :include?
-      assert collection.include?(obj), msg
-    end
-
-    def assert_instance_of cls, obj, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" }
-      flip = (Module === obj) && ! (Module === cls) # HACK for specs
-      obj, cls = cls, obj if flip
-      assert obj.instance_of?(cls), msg
-    end
-
-    def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
-      msg = message(msg) {
-        "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
-      flip = (Module === obj) && ! (Module === cls) # HACK for specs
-      obj, cls = cls, obj if flip
-      assert obj.kind_of?(cls), msg
-    end
-
-    def assert_match exp, act, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" }
-      assert_respond_to act, :"=~"
-      exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
-      assert exp =~ act, msg
-    end
-
-    def assert_nil obj, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
-      assert obj.nil?, msg
-    end
-
-    def assert_operator o1, op, o2, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
-      assert o1.__send__(op, o2), msg
-    end
-
-    def assert_raises *exp
-      msg = String === exp.last ? exp.pop : nil
-      should_raise = false
-      begin
-        yield
-        should_raise = true
-      rescue Exception => e
-        assert(exp.any? { |ex|
-                 ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class
-               }, exception_details(e, "#{mu_pp(exp)} exception expected, not"))
-
-        return e
-      end
-
-      exp = exp.first if exp.size == 1
-      flunk "#{mu_pp(exp)} expected but nothing was raised." if should_raise
-    end
-
-    def assert_respond_to obj, meth, msg = nil
-      msg = message(msg) {
-          "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
-        }
-      flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
-      obj, meth = meth, obj if flip
-      assert obj.respond_to?(meth), msg
-    end
-
-    def assert_same exp, act, msg = nil
-      msg = message(msg) {
-        data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
-        "Expected %s (0x%x) to be the same as %s (0x%x)" % data
-      }
-      assert exp.equal?(act), msg
-    end
-
-    def assert_send send_ary, m = nil
-      recv, msg, *args = send_ary
-      m = message(m) {
-        "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
-      assert recv.__send__(msg, *args), m
-    end
-
-    def assert_throws sym, msg = nil
-      default = "Expected #{mu_pp(sym)} to have been thrown"
-      caught = true
-      catch(sym) do
-        begin
-          yield
-        rescue ArgumentError => e     # 1.9 exception
-          default += ", not #{e.message.split(/ /).last}"
-        rescue NameError => e         # 1.8 exception
-          default += ", not #{e.name.inspect}"
-        end
-        caught = false
-      end
-
-      assert caught, message(msg) { default }
-    end
-
-    def capture_io
-      require 'stringio'
-
-      orig_stdout, orig_stderr         = $stdout, $stderr
-      captured_stdout, captured_stderr = StringIO.new, StringIO.new
-      $stdout, $stderr                 = captured_stdout, captured_stderr
-
-      yield
-
-      return captured_stdout.string, captured_stderr.string
-    ensure
-      $stdout = orig_stdout
-      $stderr = orig_stderr
-    end
-
-    def exception_details e, msg
-      "#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{MiniTest::filter_backtrace(e.backtrace).join("\n")}\n---------------"
-    end
-
-    def flunk msg = nil
-      msg ||= "Epic Fail!"
-      assert false, msg
-    end
-
-    def message msg = nil, &default
-      proc {
-        if msg then
-          msg = msg.to_s unless String === msg
-          msg += '.' unless msg.empty?
-          msg += "\n#{default.call}."
-          msg.strip
-        else
-          "#{default.call}."
-        end
-      }
-    end
-
-    # used for counting assertions
-    def pass msg = nil
-      assert true
-    end
-
-    def refute test, msg = nil
-      msg ||= "Failed refutation, no message given"
-      not assert(! test, msg)
-    end
-
-    def refute_empty obj, msg = nil
-      msg = message(msg) { "Expected #{obj.inspect} to not be empty" }
-      assert_respond_to obj, :empty?
-      refute obj.empty?, msg
-    end
-
-    def refute_equal exp, act, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" }
-      refute exp == act, msg
-    end
-
-    def refute_in_delta exp, act, delta = 0.001, msg = nil
-      n = (exp - act).abs
-      msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to not be < #{delta}" }
-      refute delta > n, msg
-    end
-
-    def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
-      refute_in_delta a, b, a * epsilon, msg
-    end
-
-    def refute_includes collection, obj, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" }
-      assert_respond_to collection, :include?
-      refute collection.include?(obj), msg
-    end
-
-    def refute_instance_of cls, obj, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" }
-      flip = (Module === obj) && ! (Module === cls) # HACK for specs
-      obj, cls = cls, obj if flip
-      refute obj.instance_of?(cls), msg
-    end
-
-    def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
-      msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
-      flip = (Module === obj) && ! (Module === cls) # HACK for specs
-      obj, cls = cls, obj if flip
-      refute obj.kind_of?(cls), msg
-    end
-
-    def refute_match exp, act, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(exp)} to not match #{mu_pp(act)}" }
-      assert_respond_to act, :"=~"
-      exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
-      refute exp =~ act, msg
-    end
-
-    def refute_nil obj, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
-      refute obj.nil?, msg
-    end
-
-    def refute_operator o1, op, o2, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" }
-      refute o1.__send__(op, o2), msg
-    end
-
-    def refute_respond_to obj, meth, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
-      flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
-      obj, meth = meth, obj if flip
-      refute obj.respond_to?(meth), msg
-    end
-
-    def refute_same exp, act, msg = nil
-      msg = message(msg) { "Expected #{mu_pp(act)} to not be the same as #{mu_pp(exp)}" }
-      refute exp.equal?(act), msg
-    end
-
-    def skip msg = nil, bt = caller
-      msg ||= "Skipped, no message given"
-      raise MiniTest::Skip, msg, bt
-    end
-  end
-
-  class Unit
-    VERSION = "1.3.1"
-
-    attr_accessor :report, :failures, :errors, :skips
-    attr_accessor :test_count, :assertion_count
-
-    @@installed_at_exit ||= false
-    @@out = $stdout
-
-    def self.autorun
-      at_exit {
-        next if $! # don't run if there was an exception
-        exit_code = MiniTest::Unit.new.run(ARGV)
-        exit false if exit_code && exit_code != 0
-      } unless @@installed_at_exit
-      @@installed_at_exit = true
-    end
-
-    def self.output= stream
-      @@out = stream
-    end
-
-    def location e
-      last_before_assertion = ""
-      e.backtrace.reverse_each do |s|
-        break if s =~ /in .(assert|refute|flunk|pass|fail|raise)/
-        last_before_assertion = s
-      end
-      last_before_assertion.sub(/:in .*$/, '')
-    end
-
-    def puke klass, meth, e
-      e = case e
-          when MiniTest::Skip then
-            @skips += 1
-            "Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
-          when MiniTest::Assertion then
-            @failures += 1
-            "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
-          else
-            @errors += 1
-            bt = MiniTest::filter_backtrace(e.backtrace).join("\n    ")
-            "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n    #{bt}\n"
-          end
-      @report << e
-      e[0, 1]
-    end
-
-    def initialize
-      @report = []
-      @errors = @failures = @skips = 0
-      @verbose = false
-    end
-
-    ##
-    # Top level driver, controls all output and filtering.
-
-    def run args = []
-      @verbose = args.delete('-v')
-
-      filter = if args.first =~ /^(-n|--name)$/ then
-                 args.shift
-                 arg = args.shift
-                 arg =~ /\/(.*)\// ? Regexp.new($1) : arg
-               else
-                 /./ # anything - ^test_ already filtered by #tests
-               end
-
-      @@out.puts "Loaded suite #{$0.sub(/\.rb$/, '')}\nStarted"
-
-      start = Time.now
-      run_test_suites filter
-
-      @@out.puts
-      @@out.puts "Finished in #{'%.6f' % (Time.now - start)} seconds."
-
-      @report.each_with_index do |msg, i|
-        @@out.puts "\n%3d) %s" % [i + 1, msg]
-      end
-
-      @@out.puts
-
-      format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
-      @@out.puts format % [test_count, assertion_count, failures, errors, skips]
-
-      return failures + errors if @test_count > 0 # or return nil...
-    end
-
-    def run_test_suites filter = /./
-      @test_count, @assertion_count = 0, 0
-      old_sync, @@out.sync = @@out.sync, true if @@out.respond_to? :sync=
-      TestCase.test_suites.each do |suite|
-        suite.test_methods.grep(filter).each do |test|
-          inst = suite.new test
-          inst._assertions = 0
-          @@out.print "#{suite}##{test}: " if @verbose
-
-          t = Time.now if @verbose
-          result = inst.run(self)
-
-          @@out.print "%.2f s: " % (Time.now - t) if @verbose
-          @@out.print result
-          @@out.puts if @verbose
-          @test_count += 1
-          @assertion_count += inst._assertions
-        end
-      end
-      @@out.sync = old_sync if @@out.respond_to? :sync=
-      [@test_count, @assertion_count]
-    end
-
-    class TestCase
-      attr_reader :name
-
-      def run runner
-        result = '.'
-        begin
-          @passed = nil
-          self.setup
-          self.__send__ self.name
-          @passed = true
-        rescue Exception => e
-          @passed = false
-          result = runner.puke(self.class, self.name, e)
-        ensure
-          begin
-            self.teardown
-          rescue Exception => e
-            result = runner.puke(self.class, self.name, e)
-          end
-        end
-        result
-      end
-
-      def initialize name
-        @name = name
-        @passed = nil
-      end
-
-      def self.reset
-        @@test_suites = {}
-      end
-
-      reset
-
-      def self.inherited klass
-        @@test_suites[klass] = true
-      end
-
-      def self.test_order
-        :random
-      end
-
-      def self.test_suites
-        @@test_suites.keys.sort_by { |ts| ts.name }
-      end
-
-      def self.test_methods
-        methods = public_instance_methods(true).grep(/^test/).map { |m|
-          m.to_s
-        }.sort
-
-        if self.test_order == :random then
-          max = methods.size
-          methods = methods.sort_by { rand(max) }
-        end
-
-        methods
-      end
-
-      def setup; end
-      def teardown; end
-
-      def passed?
-        @passed
-      end
-
-      include MiniTest::Assertions
-    end # class TestCase
-  end # class Test
-end # module Mini

Copied: MacRuby/branches/experimental/lib/minitest/unit.rb (from rev 1886, MacRuby/trunk/lib/minitest/unit.rb)
===================================================================
--- MacRuby/branches/experimental/lib/minitest/unit.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/minitest/unit.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,497 @@
+############################################################
+# This file is imported from a different project.
+# DO NOT make modifications in this repo.
+# File a patch instead and assign it to Ryan Davis
+############################################################
+
+##
+#
+# Totally minimal drop-in replacement for test-unit
+#
+# TODO: refute -> debunk, prove/rebut, show/deny... lots of possibilities
+
+module MiniTest
+  class Assertion < Exception; end
+  class Skip < Assertion; end
+
+  file = if RUBY_VERSION =~ /^1\.9/ then  # bt's expanded, but __FILE__ isn't :(
+           File.expand_path __FILE__
+         elsif  __FILE__ =~ /^[^\.]/ then # assume both relative
+           require 'pathname'
+           pwd = Pathname.new Dir.pwd
+           pn = Pathname.new File.expand_path(__FILE__)
+           pn = File.join(".", pn.relative_path_from(pwd)) unless pn.relative?
+           pn.to_s
+         else                             # assume both are expanded
+           __FILE__
+         end
+
+  # './lib' in project dir, or '/usr/local/blahblah' if installed
+  MINI_DIR = File.dirname(File.dirname(file))
+
+  def self.filter_backtrace bt
+    return ["No backtrace"] unless bt
+
+    new_bt = []
+    bt.each do |line|
+      break if line.rindex(MINI_DIR, 0)
+      new_bt << line
+    end
+
+    new_bt = bt.reject { |line| line.rindex(MINI_DIR, 0) } if new_bt.empty?
+    new_bt = bt.dup if new_bt.empty?
+    new_bt
+  end
+
+  module Assertions
+    def mu_pp(obj)
+      s = obj.inspect
+      s = s.force_encoding(Encoding.default_external) if defined? Encoding
+      s
+    end
+
+    def _assertions= n
+      @_assertions = n
+    end
+
+    def _assertions
+      @_assertions ||= 0
+    end
+
+    def assert test, msg = nil
+      msg ||= "Failed assertion, no message given."
+      self._assertions += 1
+      unless test then
+        msg = msg.call if Proc === msg
+        raise MiniTest::Assertion, msg
+      end
+      true
+    end
+
+    def assert_block msg = nil
+      msg = message(msg) { "Expected block to return true value" }
+      assert yield, msg
+    end
+
+    def assert_empty obj, msg = nil
+      msg = message(msg) { "Expected #{obj.inspect} to be empty" }
+      assert_respond_to obj, :empty?
+      assert obj.empty?, msg
+    end
+
+    def assert_equal exp, act, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(exp)}, not #{mu_pp(act)}" }
+      assert(exp == act, msg)
+    end
+
+    def assert_in_delta exp, act, delta = 0.001, msg = nil
+      n = (exp - act).abs
+      msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" }
+      assert delta >= n, msg
+    end
+
+    def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
+      assert_in_delta a, b, [a, b].min * epsilon, msg
+    end
+
+    def assert_includes collection, obj, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" }
+      assert_respond_to collection, :include?
+      assert collection.include?(obj), msg
+    end
+
+    def assert_instance_of cls, obj, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" }
+      flip = (Module === obj) && ! (Module === cls) # HACK for specs
+      obj, cls = cls, obj if flip
+      assert obj.instance_of?(cls), msg
+    end
+
+    def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
+      msg = message(msg) {
+        "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
+      flip = (Module === obj) && ! (Module === cls) # HACK for specs
+      obj, cls = cls, obj if flip
+      assert obj.kind_of?(cls), msg
+    end
+
+    def assert_match exp, act, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" }
+      assert_respond_to act, :"=~"
+      exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
+      assert exp =~ act, msg
+    end
+
+    def assert_nil obj, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
+      assert obj.nil?, msg
+    end
+
+    def assert_operator o1, op, o2, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
+      assert o1.__send__(op, o2), msg
+    end
+
+    def assert_raises *exp
+      msg = String === exp.last ? exp.pop : nil
+      should_raise = false
+      begin
+        yield
+        should_raise = true
+      rescue Exception => e
+        assert(exp.any? { |ex|
+                 ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class
+               }, exception_details(e, "#{mu_pp(exp)} exception expected, not"))
+
+        return e
+      end
+
+      exp = exp.first if exp.size == 1
+      flunk "#{mu_pp(exp)} expected but nothing was raised." if should_raise
+    end
+
+    def assert_respond_to obj, meth, msg = nil
+      msg = message(msg) {
+          "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
+        }
+      flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
+      obj, meth = meth, obj if flip
+      assert obj.respond_to?(meth), msg
+    end
+
+    def assert_same exp, act, msg = nil
+      msg = message(msg) {
+        data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
+        "Expected %s (0x%x) to be the same as %s (0x%x)" % data
+      }
+      assert exp.equal?(act), msg
+    end
+
+    def assert_send send_ary, m = nil
+      recv, msg, *args = send_ary
+      m = message(m) {
+        "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
+      assert recv.__send__(msg, *args), m
+    end
+
+    def assert_throws sym, msg = nil
+      default = "Expected #{mu_pp(sym)} to have been thrown"
+      caught = true
+      catch(sym) do
+        begin
+          yield
+        rescue ArgumentError => e     # 1.9 exception
+          default += ", not #{e.message.split(/ /).last}"
+        rescue NameError => e         # 1.8 exception
+          default += ", not #{e.name.inspect}"
+        end
+        caught = false
+      end
+
+      assert caught, message(msg) { default }
+    end
+
+    def capture_io
+      require 'stringio'
+
+      orig_stdout, orig_stderr         = $stdout, $stderr
+      captured_stdout, captured_stderr = StringIO.new, StringIO.new
+      $stdout, $stderr                 = captured_stdout, captured_stderr
+
+      yield
+
+      return captured_stdout.string, captured_stderr.string
+    ensure
+      $stdout = orig_stdout
+      $stderr = orig_stderr
+    end
+
+    def exception_details e, msg
+      "#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{MiniTest::filter_backtrace(e.backtrace).join("\n")}\n---------------"
+    end
+
+    def flunk msg = nil
+      msg ||= "Epic Fail!"
+      assert false, msg
+    end
+
+    def message msg = nil, &default
+      proc {
+        if msg then
+          msg = msg.to_s unless String === msg
+          msg += '.' unless msg.empty?
+          msg += "\n#{default.call}."
+          msg.strip
+        else
+          "#{default.call}."
+        end
+      }
+    end
+
+    # used for counting assertions
+    def pass msg = nil
+      assert true
+    end
+
+    def refute test, msg = nil
+      msg ||= "Failed refutation, no message given"
+      not assert(! test, msg)
+    end
+
+    def refute_empty obj, msg = nil
+      msg = message(msg) { "Expected #{obj.inspect} to not be empty" }
+      assert_respond_to obj, :empty?
+      refute obj.empty?, msg
+    end
+
+    def refute_equal exp, act, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" }
+      refute exp == act, msg
+    end
+
+    def refute_in_delta exp, act, delta = 0.001, msg = nil
+      n = (exp - act).abs
+      msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to not be < #{delta}" }
+      refute delta > n, msg
+    end
+
+    def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
+      refute_in_delta a, b, a * epsilon, msg
+    end
+
+    def refute_includes collection, obj, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" }
+      assert_respond_to collection, :include?
+      refute collection.include?(obj), msg
+    end
+
+    def refute_instance_of cls, obj, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" }
+      flip = (Module === obj) && ! (Module === cls) # HACK for specs
+      obj, cls = cls, obj if flip
+      refute obj.instance_of?(cls), msg
+    end
+
+    def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
+      msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
+      flip = (Module === obj) && ! (Module === cls) # HACK for specs
+      obj, cls = cls, obj if flip
+      refute obj.kind_of?(cls), msg
+    end
+
+    def refute_match exp, act, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(exp)} to not match #{mu_pp(act)}" }
+      assert_respond_to act, :"=~"
+      exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
+      refute exp =~ act, msg
+    end
+
+    def refute_nil obj, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
+      refute obj.nil?, msg
+    end
+
+    def refute_operator o1, op, o2, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" }
+      refute o1.__send__(op, o2), msg
+    end
+
+    def refute_respond_to obj, meth, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
+      flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
+      obj, meth = meth, obj if flip
+      refute obj.respond_to?(meth), msg
+    end
+
+    def refute_same exp, act, msg = nil
+      msg = message(msg) { "Expected #{mu_pp(act)} to not be the same as #{mu_pp(exp)}" }
+      refute exp.equal?(act), msg
+    end
+
+    def skip msg = nil, bt = caller
+      msg ||= "Skipped, no message given"
+      raise MiniTest::Skip, msg, bt
+    end
+  end
+
+  class Unit
+    VERSION = "1.3.1"
+
+    attr_accessor :report, :failures, :errors, :skips
+    attr_accessor :test_count, :assertion_count
+
+    @@installed_at_exit ||= false
+    @@out = $stdout
+
+    def self.autorun
+      at_exit {
+        next if $! # don't run if there was an exception
+        exit_code = MiniTest::Unit.new.run(ARGV)
+        exit false if exit_code && exit_code != 0
+      } unless @@installed_at_exit
+      @@installed_at_exit = true
+    end
+
+    def self.output= stream
+      @@out = stream
+    end
+
+    def location e
+      last_before_assertion = ""
+      e.backtrace.reverse_each do |s|
+        break if s =~ /in .(assert|refute|flunk|pass|fail|raise)/
+        last_before_assertion = s
+      end
+      last_before_assertion.sub(/:in .*$/, '')
+    end
+
+    def puke klass, meth, e
+      e = case e
+          when MiniTest::Skip then
+            @skips += 1
+            "Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
+          when MiniTest::Assertion then
+            @failures += 1
+            "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
+          else
+            @errors += 1
+            bt = MiniTest::filter_backtrace(e.backtrace).join("\n    ")
+            "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n    #{bt}\n"
+          end
+      @report << e
+      e[0, 1]
+    end
+
+    def initialize
+      @report = []
+      @errors = @failures = @skips = 0
+      @verbose = false
+    end
+
+    ##
+    # Top level driver, controls all output and filtering.
+
+    def run args = []
+      @verbose = args.delete('-v')
+
+      filter = if args.first =~ /^(-n|--name)$/ then
+                 args.shift
+                 arg = args.shift
+                 arg =~ /\/(.*)\// ? Regexp.new($1) : arg
+               else
+                 /./ # anything - ^test_ already filtered by #tests
+               end
+
+      @@out.puts "Loaded suite #{$0.sub(/\.rb$/, '')}\nStarted"
+
+      start = Time.now
+      run_test_suites filter
+
+      @@out.puts
+      @@out.puts "Finished in #{'%.6f' % (Time.now - start)} seconds."
+
+      @report.each_with_index do |msg, i|
+        @@out.puts "\n%3d) %s" % [i + 1, msg]
+      end
+
+      @@out.puts
+
+      format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
+      @@out.puts format % [test_count, assertion_count, failures, errors, skips]
+
+      return failures + errors if @test_count > 0 # or return nil...
+    end
+
+    def run_test_suites filter = /./
+      @test_count, @assertion_count = 0, 0
+      old_sync, @@out.sync = @@out.sync, true if @@out.respond_to? :sync=
+      TestCase.test_suites.each do |suite|
+        suite.test_methods.grep(filter).each do |test|
+          inst = suite.new test
+          inst._assertions = 0
+          @@out.print "#{suite}##{test}: " if @verbose
+
+          t = Time.now if @verbose
+          result = inst.run(self)
+
+          @@out.print "%.2f s: " % (Time.now - t) if @verbose
+          @@out.print result
+          @@out.puts if @verbose
+          @test_count += 1
+          @assertion_count += inst._assertions
+        end
+      end
+      @@out.sync = old_sync if @@out.respond_to? :sync=
+      [@test_count, @assertion_count]
+    end
+
+    class TestCase
+      attr_reader :name
+
+      def run runner
+        result = '.'
+        begin
+          @passed = nil
+          self.setup
+          self.__send__ self.name
+          @passed = true
+        rescue Exception => e
+          @passed = false
+          result = runner.puke(self.class, self.name, e)
+        ensure
+          begin
+            self.teardown
+          rescue Exception => e
+            result = runner.puke(self.class, self.name, e)
+          end
+        end
+        result
+      end
+
+      def initialize name
+        @name = name
+        @passed = nil
+      end
+
+      def self.reset
+        @@test_suites = {}
+      end
+
+      reset
+
+      def self.inherited klass
+        @@test_suites[klass] = true
+      end
+
+      def self.test_order
+        :random
+      end
+
+      def self.test_suites
+        @@test_suites.keys.sort_by { |ts| ts.name }
+      end
+
+      def self.test_methods
+        methods = public_instance_methods(true).grep(/^test/).map { |m|
+          m.to_s
+        }.sort
+
+        if self.test_order == :random then
+          max = methods.size
+          methods = methods.sort_by { rand(max) }
+        end
+
+        methods
+      end
+
+      def setup; end
+      def teardown; end
+
+      def passed?
+        @passed
+      end
+
+      include MiniTest::Assertions
+    end # class TestCase
+  end # class Test
+end # module Mini

Modified: MacRuby/branches/experimental/lib/mkmf.rb
===================================================================
--- MacRuby/branches/experimental/lib/mkmf.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/mkmf.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -9,11 +9,12 @@
 ORIG_LIBPATH = ENV['LIB']
 
 CXX_EXT = %w[cc cxx cpp]
-if /mswin|bccwin|mingw|msdosdjgpp|human|os2/ !~ CONFIG['build_os']
+if /mswin|bccwin|mingw|os2/ !~ CONFIG['build_os']
   CXX_EXT.concat(%w[C])
 end
 SRC_EXT = %w[c m] << CXX_EXT
-$static = $config_h = nil
+$static = nil
+$config_h = '$(arch_hdrdir)/ruby/config.h'
 $default_static = $static
 
 unless defined? $configure_args
@@ -59,10 +60,10 @@
 $bccwin = /bccwin/ =~ RUBY_PLATFORM
 $mingw = /mingw/ =~ RUBY_PLATFORM
 $cygwin = /cygwin/ =~ RUBY_PLATFORM
-$human = /human/ =~ RUBY_PLATFORM
 $netbsd = /netbsd/ =~ RUBY_PLATFORM
 $os2 = /os2/ =~ RUBY_PLATFORM
 $beos = /beos/ =~ RUBY_PLATFORM
+$haiku = /haiku/ =~ RUBY_PLATFORM
 $solaris = /solaris/ =~ RUBY_PLATFORM
 $dest_prefix_pattern = (File::PATH_SEPARATOR == ';' ? /\A([[:alpha:]]:)?/ : /\A/)
 
@@ -158,8 +159,7 @@
   $topdir = $hdrdir
   $top_srcdir = $hdrdir
   $arch_hdrdir = $hdrdir + "/$(arch)"
-elsif File.exist?(($hdrdir = ($top_srcdir ||= topdir) + "/include")  + "/ruby.h") and
-    File.exist?("#{CONFIG["EXTOUT"]}/include/#{CONFIG["arch"]}/ruby/config.h")
+elsif File.exist?(($hdrdir = ($top_srcdir ||= topdir) + "/include")  + "/ruby.h")
   $topdir ||= RbConfig::CONFIG["topdir"]
   $arch_hdrdir = "$(extout)/include/$(arch)"
 else
@@ -194,6 +194,10 @@
   FileUtils.rm_f(Dir[*files])
 end
 
+def rm_rf(*files)
+  FileUtils.rm_rf(Dir[*files])
+end
+
 # Returns time stamp of the +target+ file if it exists and is newer
 # than or equal to all of +times+.
 def modified?(target, times)
@@ -232,9 +236,13 @@
   @postpone = 0
   @quiet = $extmk
 
+  def self::log_open
+    @log ||= File::open(@logfile, 'wb')
+    @log.sync = true
+  end
+
   def self::open
-    @log ||= File::open(@logfile, 'w')
-    @log.sync = true
+    log_open
     $stderr.reopen(@log)
     $stdout.reopen(@log)
     yield
@@ -244,8 +252,7 @@
   end
 
   def self::message(*s)
-    @log ||= File::open(@logfile, 'w')
-    @log.sync = true
+    log_open
     @log.printf(*s)
   end
 
@@ -320,8 +327,11 @@
 end
 
 def create_tmpsrc(src)
+  src = "#{COMMON_HEADERS}\n#{src}"
   src = yield(src) if block_given?
-  src = src.gsub(/[ \t]+$/, '').gsub(/\A\n+|^\n+$/, '').sub(/[^\n]\z/, "\\&\n")
+  src.gsub!(/[ \t]+$/, '')
+  src.gsub!(/\A\n+|^\n+$/, '')
+  src.sub!(/[^\n]\z/, "\\&\n")
   count = 0
   begin
     open(CONFTEST_C, "wb") do |cfile|
@@ -336,11 +346,26 @@
   src
 end
 
+def have_devel?
+  unless defined? $have_devel
+    $have_devel = true
+    $have_devel = try_link(MAIN_DOES_NOTHING)
+  end
+  $have_devel
+end
+
 def try_do(src, command, &b)
+  unless have_devel?
+    raise <<MSG
+The complier failed to generate an executable file.
+You have to install development tools first.
+MSG
+  end
   src = create_tmpsrc(src, &b)
   xsystem(command)
 ensure
   log_src(src)
+  rm_rf 'conftest.dSYM'
 end
 
 def link_command(ldflags, opt="", libpath=$DEFLIBPATH|$LIBPATH)
@@ -372,7 +397,7 @@
                                 'arch_hdrdir' => "#$arch_hdrdir",
                                 'top_srcdir' => $top_srcdir.quote)
   RbConfig::expand("$(CPP) #$INCFLAGS #$CPPFLAGS #$CFLAGS #{opt} #{CONFTEST_C} #{outfile}",
-		   conf).gsub(/-arch\s+\w+/, '')
+		   conf).gsub(/-arch\s+\w+/,'')
 end
 
 def libpathflag(libpath=$DEFLIBPATH|$LIBPATH)
@@ -444,7 +469,6 @@
 def try_static_assert(expr, headers = nil, opt = "", &b)
   headers = cpp_include(headers)
   try_compile(<<SRC, opt, &b)
-#{COMMON_HEADERS}
 #{headers}
 /*top*/
 int conftest_const[(#{expr}) ? 1 : -1];
@@ -483,8 +507,7 @@
     upper = -upper if neg
     return upper
   else
-    src = %{#{COMMON_HEADERS}
-#{includes}
+    src = %{#{includes}
 #include <stdio.h>
 /*top*/
 int conftest_const = (int)(#{const});
@@ -501,16 +524,16 @@
 
 def try_func(func, libs, headers = nil, &b)
   headers = cpp_include(headers)
-  try_link(<<"SRC", libs, &b) or try_link(<<"SRC", libs, &b)
-#{COMMON_HEADERS}
+  try_link(<<"SRC", libs, &b) or
 #{headers}
 /*top*/
-int main() { return 0; }
+#{MAIN_DOES_NOTHING}
 int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
 SRC
+  try_link(<<"SRC", libs, &b)
 #{headers}
 /*top*/
-int main() { return 0; }
+#{MAIN_DOES_NOTHING}
 int t() { #{func}(); return 0; }
 SRC
 end
@@ -518,10 +541,9 @@
 def try_var(var, headers = nil, &b)
   headers = cpp_include(headers)
   try_compile(<<"SRC", &b)
-#{COMMON_HEADERS}
 #{headers}
 /*top*/
-int main() { return 0; }
+#{MAIN_DOES_NOTHING}
 int t() { const volatile void *volatile p; p = &(&#{var})[0]; return 0; }
 SRC
 end
@@ -785,7 +807,7 @@
 def have_header(header, &b)
   checking_for header do
     if try_cpp(cpp_include(header), &b)
-      # FIXME: cannot use this in MacRuby yet
+      #FIXME: cannot use this in MacRuby yet
       #$defs.push(format("-DHAVE_%s", header.tr("a-z./\055", "A-Z___")))
       str = header.tr("a-z", "A-Z").tr("./\055", "_")
       $defs.push(format("-DHAVE_%s", str))
@@ -839,10 +861,9 @@
 def have_struct_member(type, member, headers = nil, &b)
   checking_for checking_message("#{type}.#{member}", headers) do
     if try_compile(<<"SRC", &b)
-#{COMMON_HEADERS}
 #{cpp_include(headers)}
 /*top*/
-int main() { return 0; }
+#{MAIN_DOES_NOTHING}
 int s = (char *)&((#{type}*)0)->#{member} - (char *)0;
 SRC
       $defs.push(format("-DHAVE_%s_%s", type.tr_cpp, member.tr_cpp))
@@ -856,7 +877,6 @@
 
 def try_type(type, headers = nil, opt = "", &b)
   if try_compile(<<"SRC", opt, &b)
-#{COMMON_HEADERS}
 #{cpp_include(headers)}
 /*top*/
 typedef #{type} conftest_type;
@@ -911,7 +931,6 @@
 def try_const(const, headers = nil, opt = "", &b)
   const, type = *const
   if try_compile(<<"SRC", opt, &b)
-#{COMMON_HEADERS}
 #{cpp_include(headers)}
 /*top*/
 typedef #{type || 'int'} conftest_type;
@@ -976,11 +995,10 @@
 # pointer.
 def scalar_ptr_type?(type, member = nil, headers = nil, &b)
   try_compile(<<"SRC", &b)   # pointer
-#{COMMON_HEADERS}
 #{cpp_include(headers)}
 /*top*/
 volatile #{type} conftestval;
-int main() { return 0; }
+#{MAIN_DOES_NOTHING}
 int t() {return (int)(1-*(conftestval#{member ? ".#{member}" : ""}));}
 SRC
 end
@@ -989,11 +1007,10 @@
 # pointer.
 def scalar_type?(type, member = nil, headers = nil, &b)
   try_compile(<<"SRC", &b)   # pointer
-#{COMMON_HEADERS}
 #{cpp_include(headers)}
 /*top*/
 volatile #{type} conftestval;
-int main() { return 0; }
+#{MAIN_DOES_NOTHING}
 int t() {return (int)(1-(conftestval#{member ? ".#{member}" : ""}));}
 SRC
 end
@@ -1171,7 +1188,7 @@
 #
 def create_header(header = "extconf.h")
   message "creating %s\n", header
-    # FIXME: cannot use this in MacRuby yet
+    #FIXME: cannot use this in MacRuby yet
     #sym = header.tr("a-z./\055", "A-Z___")
     sym = header.tr("a-z", "A-Z").tr("./\055", "_")
   hdr = ["#ifndef #{sym}\n#define #{sym}\n"]
@@ -1287,6 +1304,29 @@
   s.tr('/', '\\')
 end
 
+# Converts native path to format acceptable in Makefile
+#
+# Internal use only.
+#
+if !CROSS_COMPILING
+  case CONFIG['build_os']
+  when 'mingw32'
+    def mkintpath(path)
+      # mingw uses make from msys and it needs special care
+      # converts from C:\some\path to /C/some/path
+      path = path.dup
+      path.tr!('\\', '/')
+      path.sub!(/\A([A-Za-z]):(?=\/)/, '/\1')
+      path
+    end
+  end
+end
+unless defined?(mkintpath)
+  def mkintpath(path)
+    path
+  end
+end
+
 def configuration(srcdir)
   mk = []
   vpath = $VPATH.dup
@@ -1296,8 +1336,6 @@
       if CONFIG['target_os'] != 'cygwin'
         vpath = vpath.map {|p| p.sub(/.*/, '$(shell cygpath -u \&)')}
       end
-    when 'msdosdjgpp', 'mingw32'
-      CONFIG['PATH_SEPARATOR'] = ';'
     end
   end
   CONFIG["hdrdir"] ||= $hdrdir
@@ -1305,14 +1343,10 @@
 SHELL = /bin/sh
 
 #### Start of system configuration section. ####
-#{
-if $extmk
-  "top_srcdir = " + $top_srcdir.sub(%r"\A#{Regexp.quote($topdir)}/", "$(topdir)/")
-end
-}
-srcdir = #{srcdir.gsub(/\$\((srcdir)\)|\$\{(srcdir)\}/) {CONFIG[$1||$2]}.quote}
-topdir = #{($extmk ? CONFIG["topdir"] : $topdir).quote}
-hdrdir = #{CONFIG["hdrdir"].quote}
+#{"top_srcdir = " + $top_srcdir.sub(%r"\A#{Regexp.quote($topdir)}/", "$(topdir)/") if $extmk}
+srcdir = #{srcdir.gsub(/\$\((srcdir)\)|\$\{(srcdir)\}/) {mkintpath(CONFIG[$1||$2])}.quote}
+topdir = #{mkintpath($extmk ? CONFIG["topdir"] : $topdir).quote}
+hdrdir = #{mkintpath(CONFIG["hdrdir"]).quote}
 arch_hdrdir = #{$arch_hdrdir}
 VPATH = #{vpath.join(CONFIG['PATH_SEPARATOR'])}
 }
@@ -1338,7 +1372,8 @@
   else
     sep = ""
   end
-  extconf_h = $extconf_h ? "-DRUBY_EXTCONF_H=\\\"$(RUBY_EXTCONF_H)\\\" " : $defs.join(" ")<<" "
+  possible_command = (proc {|s| s if /top_srcdir/ !~ s} unless $extmk)
+  extconf_h = $extconf_h ? "-DRUBY_EXTCONF_H=\\\"$(RUBY_EXTCONF_H)\\\" " : $defs.join(" ") << " "
   mk << %{
 CC = #{CONFIG['CC']}
 CXX = #{CONFIG['CXX']}
@@ -1350,6 +1385,10 @@
 COUTFLAG = #{COUTFLAG}
 
 RUBY_EXTCONF_H = #{$extconf_h}
+cflags   = #{CONFIG['cflags']}
+optflags = #{CONFIG['optflags']}
+debugflags = #{CONFIG['debugflags']}
+warnflags = #{CONFIG['warnflags']}
 CFLAGS   = #{$static ? '' : CONFIG['CCDLFLAGS']} #$CFLAGS #$ARCH_FLAG
 INCFLAGS = -I. #$INCFLAGS
 DEFS     = #{CONFIG['DEFS']}
@@ -1371,12 +1410,14 @@
 ruby_version = #{RbConfig::CONFIG['ruby_version']}
 ruby = #{$ruby}
 RUBY = $(ruby#{sep})
-RM = #{config_string('RM') || '$(RUBY) -run -e rm -- -f'}
-MAKEDIRS = #{config_string('MAKEDIRS') || '@$(RUBY) -run -e mkdir -- -p'}
-INSTALL = #{config_string('INSTALL') || '@$(RUBY) -run -e install -- -vp'}
+RM = #{config_string('RM', &possible_command) || '$(RUBY) -run -e rm -- -f'}
+RM_RF = #{'$(RUBY) -run -e rm -- -rf'}
+RMDIRS = #{config_string('RMDIRS', &possible_command) || '$(RUBY) -run -e rmdir -- -p'}
+MAKEDIRS = #{config_string('MAKEDIRS', &possible_command) || '@$(RUBY) -run -e mkdir -- -p'}
+INSTALL = #{config_string('INSTALL', &possible_command) || '@$(RUBY) -run -e install -- -vp'}
 INSTALL_PROG = #{config_string('INSTALL_PROG') || '$(INSTALL) -m 0755'}
 INSTALL_DATA = #{config_string('INSTALL_DATA') || '$(INSTALL) -m 0644'}
-COPY = #{config_string('CP') || '@$(RUBY) -run -e cp -- -v'}
+COPY = #{config_string('CP', &possible_command) || '@$(RUBY) -run -e cp -- -v'}
 
 #### End of system configuration section. ####
 
@@ -1433,7 +1474,7 @@
   end
   depend.each_line do |line|
     line.gsub!(/\.o\b/, ".#{$OBJEXT}")
-    line.gsub!(/\$\((?:hdr|top)dir\)\/config.h/, $config_h) if $config_h
+    line.gsub!(/\$\((?:hdr|top)dir\)\/config.h/, $config_h)
     line.gsub!(%r"\$\(hdrdir\)/(?!ruby(?![^:;/\s]))(?=[-\w]+\.h)", '\&ruby/')
     if $nmake && /\A\s*\$\(RM|COPY\)/ =~ line
       line.gsub!(%r"[-\w\./]{2,}"){$&.tr("/", "\\")}
@@ -1570,6 +1611,11 @@
   end
   origdef ||= ''
 
+  if $extout and $INSTALLFILES
+    $cleanfiles.concat($INSTALLFILES.collect {|files, dir|File.join(dir, files.sub(/\A\.\//, ''))})
+    $distcleandirs.concat($INSTALLFILES.collect {|files, dir| dir})
+  end
+
   if $extmk and not $extconf_h
     create_header
   end
@@ -1587,6 +1633,7 @@
 
 CLEANFILES = #{$cleanfiles.join(' ')}
 DISTCLEANFILES = #{$distcleanfiles.join(' ')}
+DISTCLEANDIRS = #{$distcleandirs.join(' ')}
 
 extout = #{$extout}
 extout_prefix = #{$extout_prefix}
@@ -1603,16 +1650,28 @@
 " #"
   # TODO: fixme
   install_dirs.each {|d| mfile.print("%-14s= %s\n" % d) if /^[[:upper:]]/ =~ d[0]}
-  n = ($extout ? '$(RUBYARCHDIR)/' : '') + '$(TARGET).'
+  n = ($extout ? '$(RUBYARCHDIR)/' : '') + '$(TARGET)'
   mfile.print "
 TARGET_SO     = #{($extout ? '$(RUBYARCHDIR)/' : '')}$(DLLIB)
-CLEANLIBS     = #{n}#{CONFIG['DLEXT']} #{n}il? #{n}tds #{n}map
-CLEANOBJS     = *.#{$OBJEXT} *.#{$LIBEXT} *.s[ol] *.pdb *.exp *.bak
+CLEANLIBS     = #{n}.#{CONFIG['DLEXT']} #{config_string('cleanlibs') {|t| t.gsub(/\$\*/) {n}}}
+CLEANOBJS     = *.#{$OBJEXT} #{config_string('cleanobjs') {|t| t.gsub(/\$\*/, '$(TARGET)')}} *.bak
 
-all:		#{$extout ? "install" : target ? "$(DLLIB)" : "Makefile"}
-static:		$(STATIC_LIB)#{$extout ? " install-rb" : ""}
+all:    #{$extout ? "install" : target ? "$(DLLIB)" : "Makefile"}
+static: $(STATIC_LIB)#{$extout ? " install-rb" : ""}
 "
   mfile.print CLEANINGS
+  fsep = config_string('BUILD_FILE_SEPARATOR') {|s| s unless s == "/"}
+  if fsep
+    sep = ":/=#{fsep}"
+    fseprepl = proc {|s|
+      s = s.gsub("/", fsep)
+      s = s.gsub(/(\$\(\w+)(\))/) {$1+sep+$2}
+      s = s.gsub(/(\$\{\w+)(\})/) {$1+sep+$2}
+    }
+  else
+    fseprepl = proc {|s| s}
+    sep = ""
+  end
   dirs = []
   mfile.print "install: install-so install-rb\n\n"
   sodir = (dir = "$(RUBYARCHDIR)").dup
@@ -1621,18 +1680,13 @@
     f = "$(DLLIB)"
     dest = "#{dir}/#{f}"
     mfile.puts dir, "install-so: #{dest}"
-    unless $extout
+    if $extout
+      mfile.print "clean-so::\n"
+      mfile.print "\t at -$(RM) #{fseprepl[dest]}\n"
+      mfile.print "\t at -$(RMDIRS) #{fseprepl[dir]}\n"
+    else
       mfile.print "#{dest}: #{f}\n"
-      if (sep = config_string('BUILD_FILE_SEPARATOR'))
-        f.gsub!("/", sep)
-        dir.gsub!("/", sep)
-        sep = ":/="+sep
-        f.gsub!(/(\$\(\w+)(\))/) {$1+sep+$2}
-        f.gsub!(/(\$\{\w+)(\})/) {$1+sep+$2}
-        dir.gsub!(/(\$\(\w+)(\))/) {$1+sep+$2}
-        dir.gsub!(/(\$\{\w+)(\})/) {$1+sep+$2}
-      end
-      mfile.print "\t$(INSTALL_PROG) #{f} #{dir}\n"
+      mfile.print "\t$(INSTALL_PROG) #{fseprepl[f]} #{fseprepl[dir]}\n"
       if defined?($installed_list)
 	mfile.print "\t at echo #{dir}/#{File.basename(f)}>>$(INSTALLED_LIST)\n"
       end
@@ -1650,31 +1704,35 @@
       unless dirs.include?(dir)
 	dirs << dir
 	mfile.print "pre-install-rb#{sfx}: #{dir}\n"
-      end if $nmake
+      end
       for f in files
 	dest = "#{dir}/#{File.basename(f)}"
 	mfile.print("install-rb#{sfx}: #{dest}\n")
         mfile.print("#{dest}: #{f}\n")
-        mfile.print("\t$(MAKEDIRS) $(@D)\n") unless $nmake
         mfile.print("\t$(#{$extout ? 'COPY' : 'INSTALL_DATA'}) ")
-	sep = config_string('BUILD_FILE_SEPARATOR')
-	if sep
-	  f = f.gsub("/", sep)
-	  sep = ":/="+sep
-	  f = f.gsub(/(\$\(\w+)(\))/) {$1+sep+$2}
-	  f = f.gsub(/(\$\{\w+)(\})/) {$1+sep+$2}
-	else
-	  sep = ""
-	end
-	mfile.print("#{f} $(@D#{sep})\n")
+	mfile.print("#{fseprepl[f]} $(@D#{sep})\n")
 	if defined?($installed_list) and !$extout
 	  mfile.print("\t at echo #{dest}>>$(INSTALLED_LIST)\n")
 	end
+        if $extout
+          mfile.print("clean-rb#{sfx}::\n")
+          mfile.print("\t at -$(RM) #{fseprepl[dest]}\n")
+        end
       end
     end
+    if $extout
+      dirs.uniq!
+      dirs.reverse!
+      unless dirs.empty?
+        mfile.print("clean-rb#{sfx}::\n")
+        for dir in dirs
+          mfile.print("\t at -$(RMDIRS) #{fseprepl[dir]}\n")
+        end
+      end
+    end
   end
   dirs.unshift(sodir) if target and !dirs.include?(sodir)
-  dirs.each {|d| mfile.print "#{d}:\n\t$(MAKEDIRS) $@\n" if $nmake || d == sodir}
+  dirs.each {|d| mfile.print "#{d}:\n\t$(MAKEDIRS) $@\n"}
 
   mfile.print <<-SITEINSTALL
 
@@ -1703,9 +1761,10 @@
     end
   end
 
-  sep = config_string('BUILD_FILE_SEPARATOR') {|s| ":/=#{s}" if s != "/"} || ""
   mfile.print "$(RUBYARCHDIR)/" if $extout
-  mfile.print "$(DLLIB): ", (makedef ? "$(DEFFILE) " : ""), "$(OBJS)\n"
+  mfile.print "$(DLLIB): "
+  mfile.print "$(DEFFILE) " if makedef
+  mfile.print "$(OBJS) Makefile\n"
   mfile.print "\t at -$(RM) $(@#{sep})\n"
   mfile.print "\t at -$(MAKEDIRS) $(@D)\n" if $extout
   link_so = LINK_SO.gsub(/^/, "\t")
@@ -1730,11 +1789,11 @@
   if File.exist?(depend)
     mfile.print("###\n", *depend_rules(File.read(depend)))
   else
-    headers = %w[ruby.h defines.h]
+    headers = %w[$(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h]
     if RULE_SUBST
       headers.each {|h| h.sub!(/.*/, &RULE_SUBST.method(:%))}
     end
-    headers << $config_h if $config_h
+    headers << $config_h
     headers << '$(RUBY_EXTCONF_H)' if $extconf_h
     mfile.print "$(OBJS): ", headers.join(' '), "\n"
   end
@@ -1756,7 +1815,9 @@
   $ARCH_FLAG = with_config("arch_flag", arg_config("ARCH_FLAG", config["ARCH_FLAG"])).dup
   $CPPFLAGS = with_config("cppflags", arg_config("CPPFLAGS", config["CPPFLAGS"])).dup
   $LDFLAGS = with_config("ldflags", arg_config("LDFLAGS", config["LDFLAGS"])).dup
-  $INCFLAGS = "-I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir)"
+  $INCFLAGS = "-I$(arch_hdrdir)"
+  $INCFLAGS << " -I$(hdrdir)/ruby/backward" unless $extmk
+  $INCFLAGS << " -I$(hdrdir) -I$(srcdir)"
   $DLDFLAGS = with_config("dldflags", arg_config("DLDFLAGS", config["DLDFLAGS"])).dup
   $LIBEXT = config['LIBEXT'].dup
   $OBJEXT = config["OBJEXT"].dup
@@ -1783,6 +1844,7 @@
   $cleanfiles = config_string('CLEANFILES') {|s| Shellwords.shellwords(s)} || []
   $cleanfiles << "mkmf.log"
   $distcleanfiles = config_string('DISTCLEANFILES') {|s| Shellwords.shellwords(s)} || []
+  $distcleandirs = config_string('DISTCLEANDIRS') {|s| Shellwords.shellwords(s)} || []
 
   $extout ||= nil
   $extout_prefix ||= nil
@@ -1844,7 +1906,7 @@
 
 EXPORT_PREFIX = config_string('EXPORT_PREFIX') {|s| s.strip}
 
-hdr = []
+hdr = ['#include "ruby.h"' "\n"]
 config_string('COMMON_MACROS') do |s|
   Shellwords.shellwords(s).each do |w|
     hdr << "#define " + w.split(/=/, 2).join(" ")
@@ -1873,17 +1935,25 @@
 LIBPATHFLAG = config_string('LIBPATHFLAG') || ' -L"%s"'
 RPATHFLAG = config_string('RPATHFLAG') || ''
 LIBARG = config_string('LIBARG') || '-l%s'
+MAIN_DOES_NOTHING = config_string('MAIN_DOES_NOTHING') || 'int main() {return 0;}'
 
 sep = config_string('BUILD_FILE_SEPARATOR') {|s| ":/=#{s}" if sep != "/"} || ""
 CLEANINGS = "
-clean:
-		@-$(RM) $(CLEANLIBS#{sep}) $(CLEANOBJS#{sep}) $(CLEANFILES#{sep})
+clean-rb-default::
+clean-rb::
+clean-so::
+clean: clean-so clean-rb-default clean-rb
+\t\t at -$(RM) $(CLEANLIBS#{sep}) $(CLEANOBJS#{sep}) $(CLEANFILES#{sep})
 
-distclean:	clean
-		@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
-		@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES#{sep})
+distclean-rb-default::
+distclean-rb::
+distclean-so::
+distclean: clean distclean-so distclean-rb-default distclean-rb
+\t\t at -$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
+\t\t at -$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES#{sep})
+\t\t at -$(RMDIRS) $(DISTCLEANDIRS#{sep})
 
-realclean:	distclean
+realclean: distclean
 "
 
 if not $extmk and /\A(extconf|makefile).rb\z/ =~ File.basename($0)

Modified: MacRuby/branches/experimental/lib/net/ftp.rb
===================================================================
--- MacRuby/branches/experimental/lib/net/ftp.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/net/ftp.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -170,9 +170,9 @@
     end
 
     def open_socket(host, port)
-      if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
+      if defined? SOCKSSocket and ENV["SOCKS_SERVER"]
 	@passive = true
-	return SOCKSsocket.open(host, port)
+	return SOCKSSocket.open(host, port)
       else
 	return TCPSocket.open(host, port)
       end
@@ -296,12 +296,9 @@
     def sendport(host, port)
       af = (@sock.peeraddr)[0]
       if af == "AF_INET"
-	hbytes = host.split(".")
-	pbytes = [port / 256, port % 256]
-	bytes = hbytes + pbytes
-	cmd = "PORT " + bytes.join(",")
+	cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",")
       elsif af == "AF_INET6"
-	cmd = "EPRT |2|" + host + "|" + sprintf("%d", port) + "|"
+	cmd = sprintf("EPRT |2|%s|%d|", host, port)
       else
 	raise FTPProtoError, host
       end
@@ -399,9 +396,11 @@
       synchronize do
 	resp = sendcmd('USER ' + user)
 	if resp[0] == ?3
+          raise FTPReplyError, resp if passwd.nil?
 	  resp = sendcmd('PASS ' + passwd)
 	end
 	if resp[0] == ?3
+          raise FTPReplyError, resp if acct.nil?
 	  resp = sendcmd('ACCT ' + acct)
 	end
       end
@@ -725,9 +724,9 @@
 	begin
 	  voidcmd("CDUP")
 	  return
-	rescue FTPPermError
-	  if $![0, 3] != "500"
-	    raise FTPPermError, $!
+	rescue FTPPermError => e
+	  if e.message[0, 3] != "500"
+	    raise e
 	  end
 	end
       end

Modified: MacRuby/branches/experimental/lib/net/http.rb
===================================================================
--- MacRuby/branches/experimental/lib/net/http.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/net/http.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -22,7 +22,7 @@
 # http://www.ruby-lang.org/ja/man/html/net_http.html
 # 
 #--
-# $Id: http.rb 16033 2008-04-15 08:12:30Z kazu $
+# $Id: http.rb 18805 2008-08-24 03:21:36Z naruse $
 #++ 
 
 require 'net/protocol'
@@ -284,7 +284,7 @@
   class HTTP < Protocol
 
     # :stopdoc:
-    Revision = %q$Revision: 16033 $.split[1]
+    Revision = %q$Revision: 18805 $.split[1]
     HTTPVersion = '1.1'
     @newimpl = true
     begin
@@ -486,6 +486,11 @@
       @enable_post_connection_check = true
       @compression = nil
       @sspi_enabled = false
+      if defined?(SSL_ATTRIBUTES)
+        SSL_ATTRIBUTES.each do |name|
+          instance_variable_set "@#{name}", nil
+        end
+      end
     end
 
     def inspect
@@ -1521,7 +1526,7 @@
     private :encode_kvpair
 
     def urlencode(str)
-      str.gsub(/[^a-zA-Z0-9_\.\-]/n) { sprintf('%%%02x', $&[0]) }
+      str.dup.force_encoding('ASCII-8BIT').gsub(/[^a-zA-Z0-9_\.\-]/){'%%%02x' % $&.ord}
     end
     private :urlencode
 
@@ -1643,7 +1648,7 @@
     private
 
     def send_request_with_body(sock, ver, path, body)
-      self.content_length = body.length
+      self.content_length = body.bytesize
       delete 'Transfer-Encoding'
       supply_default_content_type
       write_header sock, ver, path

Modified: MacRuby/branches/experimental/lib/net/https.rb
===================================================================
--- MacRuby/branches/experimental/lib/net/https.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/net/https.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -16,7 +16,7 @@
   You can get it from RAA or Ruby's CVS repository.
 
 == Version
-  $Id: https.rb 14371 2007-12-20 16:21:22Z gotoyuzo $
+  $Id: https.rb 18512 2008-08-12 05:20:09Z aamine $
   
   2001-11-06: Contiributed to Ruby/OpenSSL project.
   2004-03-06: Some code is merged in to net/http.
@@ -65,11 +65,11 @@
 
 : key, key=((|key|))
     Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
-    (This method is appeared in Michal Rokos's OpenSSL extention.)
+    (This method is appeared in Michal Rokos's OpenSSL extension.)
 
 : cert, cert=((|cert|))
     Sets an OpenSSL::X509::Certificate object as client certificate
-    (This method is appeared in Michal Rokos's OpenSSL extention).
+    (This method is appeared in Michal Rokos's OpenSSL extension).
 
 : ca_file, ca_file=((|path|))
     Sets path of a CA certification file in PEM format.
@@ -124,7 +124,7 @@
       ssl_version key cert ca_file ca_path cert_store ciphers
       verify_mode verify_callback verify_depth ssl_timeout
     )
-    attr_accessor *SSL_ATTRIBUTES
+    attr_accessor(*SSL_ATTRIBUTES)
 
     def peer_cert
       if not use_ssl? or not @socket

Modified: MacRuby/branches/experimental/lib/net/imap.rb
===================================================================
--- MacRuby/branches/experimental/lib/net/imap.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/net/imap.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -287,10 +287,16 @@
 
     # Disconnects from the server.
     def disconnect
-      if SSL::SSLSocket === @sock
-        @sock.io.shutdown
-      else
-        @sock.shutdown
+      begin
+        begin
+          # try to call SSL::SSLSocket#io.
+          @sock.io.shutdown
+        rescue NoMethodError
+          # @sock is not an SSL::SSLSocket.
+          @sock.shutdown
+        end
+      rescue Errno::ENOTCONN
+        # ignore `Errno::ENOTCONN: Socket is not connected' on some platforms.
       end
       @receiver_thread.join
       @sock.close
@@ -3210,7 +3216,7 @@
 	    ].join(':')
 	  )
 
-	  return response.keys.map { |k| qdval(k.to_s, response[k]) }.join(',')
+	  return response.keys.map {|key| qdval(key.to_s, response[key]) }.join(',')
 	when STAGE_TWO
 	  @stage = nil
 	  # if at the second stage, return an empty string
@@ -3243,7 +3249,7 @@
 	return @nc[nonce]
       end
 
-      # some reponses needs quoting
+      # some responses need quoting
       def qdval(k, v)
 	return if k.nil? or v.nil?
 	if %w"username authzid realm nonce cnonce digest-uri qop".include? k

Modified: MacRuby/branches/experimental/lib/net/pop.rb
===================================================================
--- MacRuby/branches/experimental/lib/net/pop.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/net/pop.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -15,7 +15,7 @@
 # NOTE: You can find Japanese version of this document at:
 # http://www.ruby-lang.org/ja/man/html/net_pop.html
 # 
-#   $Id: pop.rb 16033 2008-04-15 08:12:30Z kazu $
+#   $Id: pop.rb 19776 2008-10-14 02:22:46Z kazu $
 # 
 # See Net::POP3 for documentation.
 #
@@ -196,7 +196,7 @@
   # 
   class POP3 < Protocol
 
-    Revision = %q$Revision: 16033 $.split[1]
+    Revision = %q$Revision: 19776 $.split[1]
 
     #
     # Class Parameters
@@ -683,9 +683,8 @@
     end
 
     def set_all_uids   #:nodoc: internal use only (called from POPMail#uidl)
-      command().uidl.each do |num, uid|
-        @mails.find {|m| m.number == num }.uid = uid
-      end
+      uidl = command().uidl
+      @mails.each {|m| m.uid = uidl[m.number] }
     end
 
     def logging(msg)
@@ -871,9 +870,11 @@
       @socket = sock
       @error_occured = false
       res = check_response(critical { recv_response() })
-      @apop_stamp = res.slice(/<.+>/)
+      @apop_stamp = res.slice(/<[!-~]+@[!-~]+>/)
     end
 
+    attr_reader :socket
+
     def inspect
       "#<#{self.class} socket=#{@socket}>"
     end

Modified: MacRuby/branches/experimental/lib/net/smtp.rb
===================================================================
--- MacRuby/branches/experimental/lib/net/smtp.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/net/smtp.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -14,7 +14,7 @@
 # NOTE: You can find Japanese version of this document at:
 # http://www.ruby-lang.org/ja/man/html/net_smtp.html
 # 
-# $Id: smtp.rb 16033 2008-04-15 08:12:30Z kazu $
+# $Id: smtp.rb 18351 2008-08-04 05:46:53Z shyouhei $
 #
 # See Net::SMTP for documentation. 
 # 
@@ -172,7 +172,7 @@
   #
   class SMTP
 
-    Revision = %q$Revision: 16033 $.split[1]
+    Revision = %q$Revision: 18351 $.split[1]
 
     # The default SMTP port number, 25.
     def SMTP.default_port
@@ -437,7 +437,7 @@
     # +port+ is the port to connect to; it defaults to port 25.
     #
     # +helo+ is the _HELO_ _domain_ provided by the client to the
-    # server (see overview comments); it defaults to 'localhost.localdomain'. 
+    # server (see overview comments); it defaults to 'localhost'. 
     #
     # The remaining arguments are used for SMTP authentication, if required
     # or desired.  +user+ is the account name; +secret+ is your password
@@ -457,7 +457,7 @@
     # * IOError
     # * TimeoutError
     #
-    def SMTP.start(address, port = nil, helo = 'localhost.localdomain',
+    def SMTP.start(address, port = nil, helo = 'localhost',
                    user = nil, secret = nil, authtype = nil,
                    &block)   # :yield: smtp
       new(address, port).start(helo, user, secret, authtype, &block)
@@ -518,7 +518,7 @@
     # * IOError
     # * TimeoutError
     #
-    def start(helo = 'localhost.localdomain',
+    def start(helo = 'localhost',
               user = nil, secret = nil, authtype = nil)   # :yield: smtp
       if block_given?
         begin
@@ -837,7 +837,7 @@
 
     def rcptto(to_addr)
       if $SAFE > 0
-        raise SecurityError, 'tainted to_addr' if to.tainted?
+        raise SecurityError, 'tainted to_addr' if to_addr.tainted?
       end
       getok("RCPT TO:<#{to_addr}>")
     end

Modified: MacRuby/branches/experimental/lib/net/telnet.rb
===================================================================
--- MacRuby/branches/experimental/lib/net/telnet.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/net/telnet.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -164,7 +164,7 @@
     CR   = "\015"   
     LF   = "\012" 
     EOL  = CR + LF 
-    REVISION = '$Id: telnet.rb 16257 2008-05-01 14:57:40Z jeg2 $'
+    REVISION = '$Id: telnet.rb 17387 2008-06-17 14:04:48Z jeg2 $'
     # :startdoc:
 
     #
@@ -564,8 +564,8 @@
           @dumplog.log_dump('<', c) if @options.has_key?("Dump_log")
           if @options["Telnetmode"]
             c = rest + c
-            if Integer(c.rindex(/#{IAC}#{SE}/no)) <
-               Integer(c.rindex(/#{IAC}#{SB}/no))
+            if Integer(c.rindex(/#{IAC}#{SE}/no) || 0) <
+               Integer(c.rindex(/#{IAC}#{SB}/no) || 0)
               buf = preprocess(c[0 ... c.rindex(/#{IAC}#{SB}/no)])
               rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1]
             elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) ||

Modified: MacRuby/branches/experimental/lib/open-uri.rb
===================================================================
--- MacRuby/branches/experimental/lib/open-uri.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/open-uri.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -132,6 +132,11 @@
     options ||= {}
     OpenURI.check_options(options)
 
+    if /\Arb?(?:\Z|:([^:]+))/ =~ mode
+      encoding, = $1,Encoding.find($1) if $1
+      mode = nil
+    end
+
     unless mode == nil ||
            mode == 'r' || mode == 'rb' ||
            mode == File::RDONLY
@@ -139,6 +144,7 @@
     end
 
     io = open_loop(uri, options)
+    io.set_encoding(encoding) if encoding
     if block_given?
       begin
         yield io
@@ -542,7 +548,7 @@
     #    :proxy => true
     #    :proxy => false
     #    :proxy => nil
-    #   
+    #
     #  If :proxy option is specified, the value should be String, URI,
     #  boolean or nil.
     #  When String or URI is given, it is treated as proxy URI.
@@ -556,7 +562,7 @@
     #  Synopsis:
     #    :proxy_http_basic_authentication => ["http://proxy.foo.com:8000/", "proxy-user", "proxy-password"]
     #    :proxy_http_basic_authentication => [URI.parse("http://proxy.foo.com:8000/"), "proxy-user", "proxy-password"]
-    #   
+    #
     #  If :proxy option is specified, the value should be an Array with 3 elements.
     #  It should contain a proxy URI, a proxy user name and a proxy password.
     #  The proxy URI should be a String, an URI or nil.
@@ -564,7 +570,7 @@
     #
     #  If nil is given for the proxy URI, this option is just ignored.
     #
-    #  If :proxy and :proxy_http_basic_authentication is specified, 
+    #  If :proxy and :proxy_http_basic_authentication is specified,
     #  ArgumentError is raised.
     #
     # [:http_basic_authentication]
@@ -579,14 +585,14 @@
     # [:content_length_proc]
     #  Synopsis:
     #    :content_length_proc => lambda {|content_length| ... }
-    # 
+    #
     #  If :content_length_proc option is specified, the option value procedure
     #  is called before actual transfer is started.
     #  It takes one argument which is expected content length in bytes.
-    # 
+    #
     #  If two or more transfer is done by HTTP redirection, the procedure
     #  is called only one for a last transfer.
-    # 
+    #
     #  When expected content length is unknown, the procedure is called with
     #  nil.
     #  It is happen when HTTP response has no Content-Length header.
@@ -657,7 +663,7 @@
     # :redirect=>false is used to disable HTTP redirects at all.
     # OpenURI::HTTPRedirect exception raised on redirection.
     # It is true by default.
-    # The true means redirectoins between http and ftp is permitted.
+    # The true means redirections between http and ftp is permitted.
     #
     def open(*rest, &block)
       OpenURI.open_uri(self, *rest, &block)

Modified: MacRuby/branches/experimental/lib/open3.rb
===================================================================
--- MacRuby/branches/experimental/lib/open3.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/open3.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -66,7 +66,6 @@
 
     pid = spawn(*cmd, STDIN=>pw[0], STDOUT=>pr[1], STDERR=>pe[1])
     wait_thr = Process.detach(pid)
-    wait_thr[:pid] = pid
     pw[0].close
     pr[1].close
     pe[1].close

Modified: MacRuby/branches/experimental/lib/optparse/version.rb
===================================================================
--- MacRuby/branches/experimental/lib/optparse/version.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/optparse/version.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 # OptionParser internal utility
 
 class << OptionParser
-  def show_version(*pkg)
+  def show_version(*pkgs)
     progname = ARGV.options.program_name
     result = false
     show = proc do |klass, cname, version|
@@ -19,14 +19,14 @@
       puts str
       result = true
     end
-    if pkg.size == 1 and pkg[0] == "all"
+    if pkgs.size == 1 and pkgs[0] == "all"
       self.search_const(::Object, /\AV(?:ERSION|ersion)\z/) do |klass, cname, version|
         unless cname[1] == ?e and klass.const_defined?(:Version)
           show.call(klass, cname.intern, version)
         end
       end
     else
-      pkg.each do |pkg|
+      pkgs.each do |pkg|
         begin
           pkg = pkg.split(/::|\//).inject(::Object) {|m, c| m.const_get(c)}
           v = case
@@ -46,8 +46,8 @@
     result
   end
 
-  def each_const(path, klass = ::Object)
-    path.split(/::|\//).inject(klass) do |klass, name|
+  def each_const(path, base = ::Object)
+    path.split(/::|\//).inject(base) do |klass, name|
       raise NameError, path unless Module === klass
       klass.constants.grep(/#{name}/i) do |c|
         klass.const_defined?(c) or next

Modified: MacRuby/branches/experimental/lib/optparse.rb
===================================================================
--- MacRuby/branches/experimental/lib/optparse.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/optparse.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -203,7 +203,7 @@
 #
 class OptionParser
   # :stopdoc:
-  RCSID = %w$Id: optparse.rb 13823 2007-11-04 20:17:06Z nobu $[1..-1].each {|s| s.freeze}.freeze
+  RCSID = %w$Id: optparse.rb 21070 2008-12-26 11:16:16Z yugui $[1..-1].each {|s| s.freeze}.freeze
   Version = (RCSID[1].split('.').collect {|s| s.to_i}.extend(Comparable).freeze if RCSID[1])
   LastModified = (Time.gm(*RCSID[2, 2].join('-').scan(/\d+/).collect {|s| s.to_i}) if RCSID[2])
   Release = RCSID[2]
@@ -301,7 +301,8 @@
     end
 
     def self.incompatible_argument_styles(arg, t)
-      raise ArgumentError, "#{arg}: incompatible argument styles\n  #{self}, #{t}"
+      raise(ArgumentError, "#{arg}: incompatible argument styles\n  #{self}, #{t}",
+            ParseError.filter_backtrace(caller(2)))
     end
 
     def self.pattern
@@ -529,7 +530,8 @@
     #
     def accept(t, pat = /.*/nm, &block)
       if pat
-        pat.respond_to?(:match) or raise TypeError, "has no `match'"
+        pat.respond_to?(:match) or
+          raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
       else
         pat = t if t.respond_to?(:match)
       end
@@ -629,17 +631,21 @@
     # method which is called on every option.
     #
     def summarize(*args, &block)
-      list.each do |opt|
+      sum = []
+      list.reverse_each do |opt|
         if opt.respond_to?(:summarize) # perhaps OptionParser::Switch
-          opt.summarize(*args, &block)
-        elsif !opt
-          yield("")
+          s = []
+          opt.summarize(*args) {|l| s << l}
+          sum.concat(s.reverse)
+        elsif !opt or opt.empty?
+          sum << ""
         elsif opt.respond_to?(:each_line)
-          opt.each_line(&block)
+          sum.concat([*opt.each_line].reverse)
         else
-          opt.each(&block)
+          sum.concat([*opt.each].reverse)
         end
       end
+      sum.reverse_each(&block)
     end
 
     def add_banner(to)  # :nodoc:
@@ -826,7 +832,7 @@
   #
   # Directs to reject specified class argument.
   #
-  # +t+:: Argument class speficier, any object including Class.
+  # +t+:: Argument class specifier, any object including Class.
   #
   #   reject(t)
   #
@@ -962,7 +968,8 @@
   # +indent+:: Indentation, defaults to @summary_indent.
   #
   def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
-    visit(:summarize, {}, {}, width, max, indent, &(blk || proc {|l| to << l + $/}))
+    blk ||= proc {|l| to << (l.index($/, -1) ? l : l + $/)}
+    visit(:summarize, {}, {}, width, max, indent, &blk)
     to
   end
 
@@ -987,17 +994,14 @@
   #
   def notwice(obj, prv, msg)
     unless !prv or prv == obj
-      begin
-        raise ArgumentError, "argument #{msg} given twice: #{obj}"
-      rescue
-        $@[0, 2] = nil
-        raise
-      end
+      raise(ArgumentError, "argument #{msg} given twice: #{obj}",
+            ParseError.filter_backtrace(caller(2)))
     end
     obj
   end
   private :notwice
 
+  SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a}
   #
   # Creates an OptionParser::Switch from the parameters. The parsed argument
   # value is passed to the given block, where it can be processed.
@@ -1037,13 +1041,13 @@
   #     "-x[OPTIONAL]"
   #     "-x"
   #   There is also a special form which matches character range (not full
-  #   set of regural expression):
+  #   set of regular expression):
   #     "-[a-z]MANDATORY"
   #     "-[a-z][OPTIONAL]" 
   #     "-[a-z]"
   #
   # [Argument style and description:]
-  #   Instead of specifying mandatory or optional orguments directly in the
+  #   Instead of specifying mandatory or optional arguments directly in the
   #   switch parameter, this separate parameter can be used.
   #     "=MANDATORY"
   #     "=[OPTIONAL]"
@@ -1076,9 +1080,13 @@
       end
 
       # directly specified pattern(any object possible to match)
-      if !(String === o) and o.respond_to?(:match)
+      if (!(String === o || Symbol === o)) and o.respond_to?(:match)
         pattern = notwice(o, pattern, 'pattern')
-        conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
+        if pattern.respond_to?(:convert)
+          conv = pattern.method(:convert).to_proc
+        else
+          conv = SPLAT_PROC
+        end
         next
       end
 
@@ -1097,7 +1105,7 @@
         end
         o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
       when Module
-        raise ArgumentError, "unsupported argument type: #{o}"
+        raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
       when *ArgumentStyle.keys
         style = notwice(ArgumentStyle[o], style, 'style')
       when /^--no-([^\[\]=\s]*)(.+)?/
@@ -1162,7 +1170,9 @@
       s = (style || default_style).new(pattern || default_pattern,
                                        conv, sdesc, ldesc, arg, desc, block)
     elsif !block
-      raise ArgumentError, "no switch given" if style or pattern
+      if style or pattern
+        raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
+      end
       s = desc
     else
       short << pattern
@@ -1474,6 +1484,7 @@
   #
   def environment(env = File.basename($0, '.*'))
     env = ENV[env] || ENV[env.upcase] or return
+    require 'shellwords'
     parse(*Shellwords.shellwords(env))
   end
 
@@ -1604,6 +1615,17 @@
       argv
     end
 
+    def self.filter_backtrace(array)
+      unless $DEBUG
+        array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+      end
+      array
+    end
+
+    def set_backtrace(array)
+      super(self.class.filter_backtrace(array))
+    end
+
     def set_option(opt, eq)
       if eq
         @args[0] = opt

Modified: MacRuby/branches/experimental/lib/ostruct.rb
===================================================================
--- MacRuby/branches/experimental/lib/ostruct.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/ostruct.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -112,25 +112,23 @@
   def inspect
     str = "#<#{self.class}"
 
-    Thread.current[InspectKey] ||= []
-    if Thread.current[InspectKey].include?(self) then
-      str << " ..."
-    else
+    ids = (Thread.current[InspectKey] ||= [])
+    if ids.include?(object_id)
+      return str << ' ...>'
+    end
+
+    ids << object_id
+    begin
       first = true
       for k,v in @table
         str << "," unless first
         first = false
-
-        Thread.current[InspectKey] << v
-        begin
-          str << " #{k}=#{v.inspect}"
-        ensure
-          Thread.current[InspectKey].pop
-        end
+        str << " #{k}=#{v.inspect}"
       end
+      return str << '>'
+    ensure
+      ids.pop
     end
-
-    str << ">"
   end
   alias :to_s :inspect
 

Modified: MacRuby/branches/experimental/lib/pathname.rb
===================================================================
--- MacRuby/branches/experimental/lib/pathname.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/pathname.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -43,7 +43,7 @@
 #   base = p.basename          # Pathname:ruby
 #   dir, base = p.split        # [Pathname:/usr/bin, Pathname:ruby]
 #   data = p.read
-#   p.open { |f| _ } 
+#   p.open { |f| _ }
 #   p.each_line { |line| _ }
 #
 # === Example 2: Using standard Ruby
@@ -55,7 +55,7 @@
 #   base = File.basename(p)    # "ruby"
 #   dir, base = File.split(p)  # ["/usr/bin", "ruby"]
 #   data = File.read(p)
-#   File.open(p) { |f| _ } 
+#   File.open(p) { |f| _ }
 #   File.foreach(p) { |line| _ }
 #
 # === Example 3: Special features
@@ -71,7 +71,7 @@
 #   p5.cleanpath                    # Pathname:articles
 #   p5.realpath                     # Pathname:/home/gavin/articles
 #   p5.children                     # [Pathname:/home/gavin/articles/linux, ...]
-# 
+#
 # == Breakdown of functionality
 #
 # === Core methods
@@ -262,7 +262,7 @@
     SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
   end
 
-  # Return a pathname which the extention of the basename is substituted by
+  # Return a pathname which the extension of the basename is substituted by
   # <i>repl</i>.
   #
   # If self has no extension part, <i>repl</i> is appended.
@@ -452,7 +452,7 @@
   # Returns a real (absolute) pathname of +self+ in the actual filesystem.
   # The real pathname doesn't contain symlinks or useless dots.
   #
-  # No arguments should be given; the old behaviour is *obsoleted*. 
+  # No arguments should be given; the old behaviour is *obsoleted*.
   #
   def realpath
     path = @path
@@ -517,6 +517,7 @@
   #     # yields "usr", "bin", and "ruby".
   #
   def each_filename # :yield: filename
+    return to_enum(__method__) unless block_given?
     prefix, names = split_names(@path)
     names.each {|filename| yield filename }
     nil
@@ -587,7 +588,7 @@
   #   p2 = p1 + "bin/ruby"           # Pathname:/usr/bin/ruby
   #   p3 = p1 + "/etc/passwd"        # Pathname:/etc/passwd
   #
-  # This method doesn't access the file system; it is pure string manipulation. 
+  # This method doesn't access the file system; it is pure string manipulation.
   #
   def +(other)
     other = Pathname.new(other) unless Pathname === other
@@ -1062,6 +1063,10 @@
   end
 end
 
+class Pathname
+  undef =~
+end
+
 module Kernel
   # create a pathname object.
   #

Modified: MacRuby/branches/experimental/lib/pp.rb
===================================================================
--- MacRuby/branches/experimental/lib/pp.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/pp.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,10 +1,10 @@
 # == Pretty-printer for Ruby objects.
-# 
+#
 # = Which seems better?
-# 
+#
 # non-pretty-printed output by #p is:
 #   #<PP:0x81fedf0 @genspace=#<Proc:0x81feda0>, @group_queue=#<PrettyPrint::GroupQueue:0x81fed3c @queue=[[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], []]>, @buffer=[], @newline="\n", @group_stack=[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], @buffer_width=0, @indent=0, @maxwidth=79, @output_width=2, @output=#<IO:0x8114ee4>>
-# 
+#
 # pretty-printed output by #pp is:
 #   #<PP:0x81fedf0
 #    @buffer=[],
@@ -22,17 +22,17 @@
 #    @newline="\n",
 #    @output=#<IO:0x8114ee4>,
 #    @output_width=2>
-# 
+#
 # I like the latter.  If you do too, this library is for you.
-# 
+#
 # = Usage
-# 
+#
 #   pp(obj)
 #
 # output +obj+ to +$>+ in pretty printed format.
-# 
+#
 # It returns +nil+.
-# 
+#
 # = Output Customization
 # To define your customized pretty printing function for your classes,
 # redefine a method #pretty_print(+pp+) in the class.
@@ -67,10 +67,10 @@
 class PP < PrettyPrint
   # Outputs +obj+ to +out+ in pretty printed format of
   # +width+ columns in width.
-  # 
+  #
   # If +out+ is omitted, +$>+ is assumed.
   # If +width+ is omitted, 79 is assumed.
-  # 
+  #
   # PP.pp returns +out+.
   def PP.pp(obj, out=$>, width=79)
     q = PP.new(out, width)
@@ -82,7 +82,7 @@
 
   # Outputs +obj+ to +out+ like PP.pp but with no indent and
   # newline.
-  # 
+  #
   # PP.singleline_pp returns +out+.
   def PP.singleline_pp(obj, out=$>)
     q = SingleLine.new(out)
@@ -138,12 +138,12 @@
 
     # Adds +obj+ to the pretty printing buffer
     # using Object#pretty_print or Object#pretty_print_cycle.
-    # 
+    #
     # Object#pretty_print_cycle is used when +obj+ is already
     # printed, a.k.a the object reference chain has a cycle.
     def pp(obj)
       id = obj.object_id
- 
+
       if check_inspect_key(id)
         group {obj.pretty_print_cycle self}
         return
@@ -158,7 +158,7 @@
     end
 
     # A convenience method which is same as follows:
-    # 
+    #
     #   group(1, '#<' + obj.class.name, '>') { ... }
     def object_group(obj, &block) # :yield:
       group(1, '#<' + obj.class.name, '>', &block)
@@ -185,7 +185,7 @@
     end
 
     # A convenience method which is same as follows:
-    # 
+    #
     #   text ','
     #   breakable
     def comma_breakable
@@ -195,23 +195,23 @@
 
     # Adds a separated list.
     # The list is separated by comma with breakable space, by default.
-    # 
+    #
     # #seplist iterates the +list+ using +iter_method+.
     # It yields each object to the block given for #seplist.
     # The procedure +separator_proc+ is called between each yields.
-    # 
+    #
     # If the iteration is zero times, +separator_proc+ is not called at all.
-    # 
+    #
     # If +separator_proc+ is nil or not given,
     # +lambda { comma_breakable }+ is used.
     # If +iter_method+ is not given, :each is used.
-    # 
+    #
     # For example, following 3 code fragments has similar effect.
-    # 
+    #
     #   q.seplist([1,2,3]) {|v| xxx v }
-    # 
+    #
     #   q.seplist([1,2,3], lambda { q.comma_breakable }, :each) {|v| xxx v }
-    # 
+    #
     #   xxx 1
     #   q.comma_breakable
     #   xxx 2
@@ -275,11 +275,11 @@
 
     # A default pretty printing method for general objects.
     # It calls #pretty_print_instance_variables to list instance variables.
-    # 
+    #
     # If +self+ has a customized (redefined) #inspect method,
     # the result of self.inspect is used but it obviously has no
     # line break hints.
-    # 
+    #
     # This module provides predefined #pretty_print methods for some of
     # the most commonly used built-in classes for convenience.
     def pretty_print(q)
@@ -302,7 +302,7 @@
     end
 
     # Returns a sorted array of instance variable names.
-    # 
+    #
     # This method should return an array of names of instance variables as symbols or strings as:
     # +[:@a, :@b]+.
     def pretty_print_instance_variables
@@ -311,7 +311,7 @@
 
     # Is #inspect implementation using #pretty_print.
     # If you implement #pretty_print, it can be used as follows.
-    # 
+    #
     #   alias inspect pretty_print_inspect
     #
     # However, doing this requires that every class that #inspect is called on
@@ -629,7 +629,7 @@
       result = PP.pp(a, '')
       assert_equal("#{a.inspect}\n", result)
     end
-    
+
     def test_to_s_without_iv
       a = Object.new
       def a.to_s() "aaa" end

Modified: MacRuby/branches/experimental/lib/prettyprint.rb
===================================================================
--- MacRuby/branches/experimental/lib/prettyprint.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/prettyprint.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,7 +2,7 @@
 
 # This class implements a pretty printing algorithm. It finds line breaks and
 # nice indentations for grouped structure.
-# 
+#
 # By default, the class assumes that primitive elements are strings and each
 # byte in the strings have single column in width. But it can be used for
 # other situations by giving suitable arguments for some methods:
@@ -18,28 +18,28 @@
 # == Bugs
 # * Box based formatting?
 # * Other (better) model/algorithm?
-# 
+#
 # == References
 # Christian Lindig, Strictly Pretty, March 2000,
 # http://www.st.cs.uni-sb.de/~lindig/papers/#pretty
-# 
+#
 # Philip Wadler, A prettier printer, March 1998,
 # http://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
-# 
+#
 # == Author
 # Tanaka Akira <akr at m17n.org>
-# 
+#
 class PrettyPrint
 
   # This is a convenience method which is same as follows:
-  # 
+  #
   #   begin
   #     q = PrettyPrint.new(output, maxwidth, newline, &genspace)
   #     ...
   #     q.flush
   #     output
   #   end
-  # 
+  #
   def PrettyPrint.format(output='', maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n})
     q = PrettyPrint.new(output, maxwidth, newline, &genspace)
     yield q

Copied: MacRuby/branches/experimental/lib/prime.rb (from rev 1886, MacRuby/trunk/lib/prime.rb)
===================================================================
--- MacRuby/branches/experimental/lib/prime.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/prime.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,461 @@
+#
+# = prime.rb
+#
+# Prime numbers and factorization library.
+#
+# Copyright::
+#   Copyright (c) 1998-2008 Keiju ISHITSUKA(SHL Japan Inc.)
+#   Copyright (c) 2008 Yuki Sonoda (Yugui) <yugui at yugui.jp>
+#
+# Documentation::
+#   Yuki Sonoda
+#
+
+require "singleton"
+require "forwardable"
+
+class Integer
+  # Re-composes a prime factorization and returns the product.
+  #
+  # See Prime#int_from_prime_division for more details.
+  def Integer.from_prime_division(pd)
+    Prime.int_from_prime_division(pd)
+  end
+  
+  # Returns the factorization of +self+.
+  # 
+  # See Prime#prime_division for more details.
+  def prime_division(generator = Prime::Generator23.new)
+    Prime.prime_division(self, generator)
+  end
+
+  # Returns true if +self+ is a prime number, false for a composite.
+  def prime?
+    Prime.prime?(self)
+  end
+
+  # Iterates the given block over all prime numbers. 
+  #
+  # See +Prime+#each for more details.
+  def Integer.each_prime(ubound, &block) # :yields: prime
+    Prime.each(ubound, &block)
+  end
+end
+
+#
+# The set of all prime numbers.
+#
+# == Example
+#  Prime.each(100) do |prime|
+#    p prime  #=> 2, 3, 5, 7, 11, ...., 97
+#  end
+#
+# == Retrieving the instance
+# +Prime+.new is obsolete. Now +Prime+ has the default instance and you can 
+# access it as +Prime+.instance.
+#
+# For convenience, each instance method of +Prime+.instance can be accessed
+# as a class method of +Prime+. 
+#
+# e.g.
+#  Prime.instance.prime?(2)  #=> true
+#  Prime.prime?(2)           #=> true
+#
+# == Generators
+# A "generator" provides an implementation of enumerating pseudo-prime
+# numbers and it remembers the position of enumeration and upper bound.
+# Futhermore, it is a external iterator of prime enumeration which is 
+# compatible to an Enumerator.
+#
+# +Prime+::+PseudoPrimeGenerator+ is the base class for generators.
+# There are few implementations of generator.
+#
+# [+Prime+::+EratosthenesGenerator+]
+#   Uses eratosthenes's sieve. 
+# [+Prime+::+TrialDivisionGenerator+]
+#   Uses the trial division method.
+# [+Prime+::+Generator23+]
+#   Generates all positive integers which is not divided by 2 nor 3.
+#   This sequence is very bad as a pseudo-prime sequence. But this 
+#   is faster and uses much less memory than other generators. So,
+#   it is suitable for factorizing an integer which is not large but
+#   has many prime factors. e.g. for Prime#prime? .
+class Prime
+  include Enumerable
+  @the_instance = Prime.new
+
+  # obsolete. Use +Prime+::+instance+ or class methods of +Prime+.
+  def initialize
+    @generator = EratosthenesGenerator.new
+    extend OldCompatibility
+    warn "Prime::new is obsolete. use Prime::instance or class methods of Prime."
+  end
+
+  class<<self
+    extend Forwardable
+    include Enumerable
+    # Returns the default instance of Prime.
+    def instance; @the_instance end
+
+    def method_added(method) # :nodoc:
+      (class<<self;self;end).def_delegator :instance, method
+    end
+  end
+
+  # Iterates the given block over all prime numbers.
+  #
+  # == Parameters
+  # +ubound+::
+  #   Optional. An arbitrary positive number. 
+  #   The upper bound of enumeration. The method enumerates
+  #   prime numbers infinitely if +ubound+ is nil. 
+  # +generator+::
+  #   Optional. An implementation of pseudo-prime generator.
+  #
+  # == Return value
+  # An evaluated value of the given block at the last time.
+  # Or an enumerator which is compatible to an +Enumerator+
+  # if no block given. 
+  #
+  # == Description
+  # Calls +block+ once for each prime numer, passing the prime as
+  # a parameter.
+  #
+  # +ubound+::
+  #   Upper bound of prime numbers. The iterator stops after 
+  #   yields all prime numbers p <= +ubound+.
+  #
+  # == Note
+  # +Prime+.+new+ returns a object extended by +Prime+::+OldCompatibility+
+  # in order to compatibility to Ruby 1.9, and +Prime+#each is overwritten
+  # by +Prime+::+OldCompatibility+#+each+.
+  #
+  # +Prime+.+new+ is now obsolete. Use +Prime+.+instance+.+each+ or simply
+  # +Prime+.+each+.
+  def each(ubound = nil, generator = EratosthenesGenerator.new, &block)
+    generator.upper_bound = ubound
+    generator.each(&block)
+  end
+
+
+  # Returns true if +value+ is prime, false for a composite.
+  #
+  # == Parameters
+  # +value+:: an arbitrary integer to be checked.
+  # +generator+:: optional. A pseudo-prime generator.
+  def prime?(value, generator = Prime::Generator23.new)
+    for num in generator
+      q,r = value.divmod num
+      return true if q < num
+      return false if r == 0
+    end
+  end
+
+  # Re-composes a prime factorization and returns the product.
+  #
+  # == Parameters
+  # +pd+:: Array of pairs of integers. The each internal 
+  #        pair consists of a prime number -- a prime factor --
+  #        and a natural number -- an exponent. 
+  #
+  # == Example
+  # For [[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]], it returns
+  # p_1**e_1 * p_2**e_2 * .... * p_n**e_n.
+  #
+  #  Prime.int_from_prime_division([[2,2], [3,1]])  #=> 12
+  def int_from_prime_division(pd)
+    pd.inject(1){|value, (prime, index)|
+      value *= prime**index
+    }
+  end
+
+  # Returns the factorization of +value+.
+  #
+  # == Parameters
+  # +value+:: An arbitrary integer.
+  # +generator+:: Optional. A pseudo-prime generator.
+  #               +generator+.succ must return the next 
+  #               pseudo-prime number in the ascendent
+  #               order. It must generate all prime numbers,
+  #               but may generate non prime numbers.
+  #
+  # === Exceptions
+  # +ZeroDivisionError+:: when +value+ is zero.
+  #
+  # == Example
+  # For an arbitrary integer 
+  # n = p_1**e_1 * p_2**e_2 * .... * p_n**e_n,
+  # prime_division(n) returns
+  # [[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]].
+  #
+  #  Prime.prime_division(12) #=> [[2,2], [3,1]]
+  #
+  def prime_division(value, generator= Prime::Generator23.new)
+    raise ZeroDivisionError if value == 0
+    pv = []
+    for prime in generator
+      count = 0
+      while (value1, mod = value.divmod(prime)
+	     mod) == 0
+	value = value1
+	count += 1
+      end
+      if count != 0
+	pv.push [prime, count]
+      end
+      break if value1 <= prime
+    end
+    if value > 1
+      pv.push [value, 1]
+    end
+    return pv
+  end
+
+  # An abstract class for enumerating pseudo-prime numbers.
+  #
+  # Concrete subclasses should override succ, next, rewind.
+  class PseudoPrimeGenerator
+    include Enumerable
+
+    def initialize(ubound = nil)
+      @ubound = ubound
+    end
+
+    def upper_bound=(ubound)
+      @ubound = ubound
+    end
+    def upper_bound
+      @ubound
+    end
+
+    # returns the next pseudo-prime number, and move the internal
+    # position forward. 
+    #
+    # +PseudoPrimeGenerator+#succ raises +NotImplementedError+. 
+    def succ
+      raise NotImplementedError, "need to define `succ'"
+    end
+
+    # alias of +succ+.
+    def next
+      raise NotImplementedError, "need to define `next'"
+    end
+
+    # Rewinds the internal position for enumeration.
+    #
+    # See +Enumerator+#rewind.
+    def rewind
+      raise NotImplementedError, "need to define `rewind'"
+    end
+
+    # Iterates the given block for each prime numbers.
+    def each(&block)
+      return self.dup unless block
+      if @ubound
+	last_value = nil
+	loop do
+	  prime = succ
+	  break last_value if prime > @ubound
+	  last_value = block.call(prime)
+	end
+      else
+	loop do
+	  block.call(succ)
+	end
+      end
+    end
+
+    # see +Enumerator+#with_index.
+    alias with_index each_with_index
+
+    # see +Enumerator+#with_object.
+    def with_object(obj)
+      return enum_for(:with_object) unless block_given?
+      each do |prime|
+	yield prime, obj
+      end
+    end
+  end
+  
+  # An implementation of +PseudoPrimeGenerator+.
+  #
+  # Uses +EratosthenesSieve+.
+  class EratosthenesGenerator < PseudoPrimeGenerator
+    def initialize
+      @last_prime = nil
+    end
+    
+    def succ
+      @last_prime = @last_prime ? EratosthenesSieve.instance.next_to(@last_prime) : 2
+    end
+    def rewind
+      initialize
+    end
+    alias next succ
+  end
+
+  # An implementation of +PseudoPrimeGenerator+ which uses 
+  # a prime table generated by trial division.
+  class TrialDivisionGenerator<PseudoPrimeGenerator
+    def initialize
+      @index = -1
+    end
+    
+    def succ
+      TrialDivision.instance[@index += 1]
+    end
+    def rewind
+      initialize
+    end
+    alias next succ
+  end
+
+  # Generates all integer which are greater than 2 and
+  # are not divided by 2 nor 3.
+  #
+  # This is a pseudo-prime generator, suitable on 
+  # checking primality of a integer by brute force 
+  # method.
+  class Generator23<PseudoPrimeGenerator
+    def initialize
+      @prime = 1
+      @step = nil
+    end
+    
+    def succ
+      loop do
+	if (@step)
+	  @prime += @step
+	  @step = 6 - @step
+	else
+	  case @prime
+	  when 1; @prime = 2
+	  when 2; @prime = 3
+	  when 3; @prime = 5; @step = 2
+	  end
+	end
+	return @prime
+      end
+    end
+    alias next succ
+    def rewind
+      initialize
+    end
+  end
+
+
+
+
+  # Internal use. An implementation of prime table by trial division method.
+  class TrialDivision
+    include Singleton
+
+    def initialize # :nodoc:
+      # These are included as class variables to cache them for later uses.  If memory
+      #   usage is a problem, they can be put in Prime#initialize as instance variables.
+
+      # There must be no primes between @primes[-1] and @next_to_check.
+      @primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
+      # @next_to_check % 6 must be 1.  
+      @next_to_check = 103            # @primes[-1] - @primes[-1] % 6 + 7
+      @ulticheck_index = 3            # @primes.index(@primes.reverse.find {|n|
+      #   n < Math.sqrt(@@next_to_check) })
+      @ulticheck_next_squared = 121   # @primes[@ulticheck_index + 1] ** 2
+    end
+
+    # Returns the cached prime numbers.
+    def cache
+      return @primes
+    end
+    alias primes cache
+    alias primes_so_far cache
+
+    # Returns the +index+th prime number. 
+    #
+    # +index+ is a 0-based index.
+    def [](index)
+      while index >= @primes.length
+	# Only check for prime factors up to the square root of the potential primes,
+	#   but without the performance hit of an actual square root calculation.
+	if @next_to_check + 4 > @ulticheck_next_squared
+	  @ulticheck_index += 1
+	  @ulticheck_next_squared = @primes.at(@ulticheck_index + 1) ** 2
+	end
+	# Only check numbers congruent to one and five, modulo six. All others
+
+	#   are divisible by two or three.  This also allows us to skip checking against
+	#   two and three.
+	@primes.push @next_to_check if @primes[2.. at ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
+	@next_to_check += 4
+	@primes.push @next_to_check if @primes[2.. at ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
+	@next_to_check += 2 
+      end
+      return @primes[index]
+    end
+  end
+
+  # Internal use. An implementation of eratosthenes's sieve
+  class EratosthenesSieve
+    include Singleton
+
+    def initialize # :nodoc:
+      # bitmap for odd prime numbers less than 256.
+      # For an arbitrary odd number n, @table[i][j] is 1 when n is prime where i,j = n.divmod(32) .
+      @table = [0xcb6e, 0x64b4, 0x129a, 0x816d, 0x4c32, 0x864a, 0x820d, 0x2196]
+    end
+
+    # returns the least odd prime number which is greater than +n+.
+    def next_to(n)
+      n = (n-1).div(2)*2+3 # the next odd number of given n
+      i,j = n.divmod(32)
+      loop do
+	extend_table until @table.length > i
+	if !@table[i].zero?
+	  (j...32).step(2) do |k|
+	    return 32*i+k if !@table[i][k.div(2)].zero?
+	  end
+	end
+	i += 1; j = 1
+      end
+    end
+
+    private
+    def extend_table
+      orig_len = @table.length
+      new_len = [orig_len**2, orig_len+256].min
+      lbound = orig_len*32
+      ubound = new_len*32
+      @table.fill(0xFFFF, orig_len...new_len)
+      (3..Integer(Math.sqrt(ubound))).step(2) do |p|
+	i, j = p.divmod(32)
+	next if @table[i][j.div(2)].zero?
+
+	start = (lbound.div(2*p)*2+1)*p    # odd multiple of p which is greater than or equal to lbound
+	(start...ubound).step(2*p) do |n|
+	  i, j = n.divmod(32)
+	  @table[i] &= 0xFFFF ^ (1<<(j.div(2)))
+	end
+      end
+    end
+  end
+
+  # Provides a +Prime+ object with compatibility to Ruby 1.8 when instanciated via +Prime+.+new+.
+  module OldCompatibility
+    # Returns the next prime number and forwards internal pointer.
+    def succ
+      @generator.succ
+    end
+    alias next succ
+
+    # Overwrites Prime#each.
+    #
+    # Iterates the given block over all prime numbers. Note that enumeration starts from
+    # the current position of internal pointer, not rewound.
+    def each(&block)
+      return @generator.dup unless block_given?
+      loop do
+	yield succ
+      end
+    end
+  end
+end

Modified: MacRuby/branches/experimental/lib/profile.rb
===================================================================
--- MacRuby/branches/experimental/lib/profile.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/profile.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,6 +1,6 @@
 require 'profiler'
 
-VM::InstructionSequence.compile_option = {
+RubyVM::InstructionSequence.compile_option = {
   :trace_instruction => true,
   :specialized_instruction => false
 }

Modified: MacRuby/branches/experimental/lib/profiler.rb
===================================================================
--- MacRuby/branches/experimental/lib/profiler.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/profiler.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -34,7 +34,7 @@
     total = Process.times[0] - @@start
     if total == 0 then total = 0.01 end
     data = @@map.values
-    data = data.sort_by{|x| x[2]}
+    data = data.sort_by{|x| -x[2]}
     sum = 0
     f.printf "  %%   cumulative   self              self     total\n"
     f.printf " time   seconds   seconds    calls  ms/call  ms/call  name\n"

Modified: MacRuby/branches/experimental/lib/pstore.rb
===================================================================
--- MacRuby/branches/experimental/lib/pstore.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/pstore.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -13,14 +13,14 @@
 require "thread"
 
 #
-# PStore implements a file based persistance mechanism based on a Hash.  User
+# PStore implements a file based persistence mechanism based on a Hash.  User
 # code can store hierarchies of Ruby objects (values) into the data store file
 # by name (keys).  An object hierarchy may be just a single object.  User code 
 # may later read values back from the data store or even update data, as needed.
 # 
 # The transactional behavior ensures that any changes succeed or fail together.
 # This can be used to ensure that the data store is not left in a transitory
-# state, where some values were upated but others were not.
+# state, where some values were updated but others were not.
 # 
 # Behind the scenes, Ruby objects are stored to the data store file with 
 # Marshal.  That carries the usual limitations.  Proc objects cannot be 
@@ -345,9 +345,9 @@
         end
       end
     end
+    value
   ensure
     @transaction = false
-    value
   end
   
   private

Modified: MacRuby/branches/experimental/lib/racc/parser.rb
===================================================================
--- MacRuby/branches/experimental/lib/racc/parser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/racc/parser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -159,7 +159,6 @@
       reduce_n,     use_result,   * = arg
 
       _racc_init_sysvars
-      tok = nil
       act = nil
       i = nil
       nerr = 0
@@ -189,7 +188,7 @@
             ;
           end
 
-          while not (i = action_pointer[@racc_state[-1]]) or
+          while not(i = action_pointer[@racc_state[-1]]) or
                 not @racc_read_next or
                 @racc_t == 0   # $
             unless i and i += @racc_t and

Modified: MacRuby/branches/experimental/lib/rake/gempackagetask.rb
===================================================================
--- MacRuby/branches/experimental/lib/rake/gempackagetask.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rake/gempackagetask.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -9,12 +9,6 @@
 require 'rubygems/user_interaction'
 require 'rubygems/builder'
 
-begin
-  Gem.manage_gems
-rescue NoMethodError => ex
-  # Using rubygems prior to 0.6.1
-end
-
 module Rake
 
   # Create a package based upon a Gem spec.  Gem packages, as well as

Modified: MacRuby/branches/experimental/lib/rake/loaders/makefile.rb
===================================================================
--- MacRuby/branches/experimental/lib/rake/loaders/makefile.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rake/loaders/makefile.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -7,31 +7,26 @@
 
     # Load the makefile dependencies in +fn+.
     def load(fn)
-      buffer = ''
       open(fn) do |mf|
-        mf.each do |line|
-          next if line =~ /^\s*#/
-          buffer << line
-          if buffer =~ /\\$/
-            buffer.sub!(/\\\n/, ' ')
-            state = :append
-          else
-            process_line(buffer)
-            buffer = ''
-          end
+        lines = mf.read
+        lines.gsub!(/#[^\n]*\n/m, "")
+        lines.gsub!(/\\\n/, ' ')
+        lines.split("\n").each do |line|
+          process_line(line)
         end
       end
-      process_line(buffer) if buffer != ''
     end
 
     private
 
     # Process one logical line of makefile data.
     def process_line(line)
-      file_task, args = line.split(':')
+      file_tasks, args = line.split(':')
       return if args.nil?
       dependents = args.split
-      file file_task => dependents
+      file_tasks.strip.split.each do |file_task|
+        file file_task => dependents
+      end
     end
   end
 

Modified: MacRuby/branches/experimental/lib/rake/packagetask.rb
===================================================================
--- MacRuby/branches/experimental/lib/rake/packagetask.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rake/packagetask.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -44,7 +44,7 @@
   #   end
   #
   class PackageTask < TaskLib
-    # Name of the package (from the GEM Spec).
+    # Name of the package.
     attr_accessor :name
 
     # Version of the package (e.g. '1.3.2').
@@ -122,6 +122,7 @@
           task :package => ["#{package_dir}/#{file}"]
           file "#{package_dir}/#{file}" => [package_dir_path] + package_files do
             chdir(package_dir) do
+              sh %{env}
               sh %{#{@tar_command} #{flag}cvf #{file} #{package_name}}
             end
           end

Modified: MacRuby/branches/experimental/lib/rake/rdoctask.rb
===================================================================
--- MacRuby/branches/experimental/lib/rake/rdoctask.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rake/rdoctask.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -55,7 +55,7 @@
     # RDoc. (default is none)
     attr_accessor :main
 
-    # Name of template to be used by rdoc. (default is 'html')
+    # Name of template to be used by rdoc. (defaults to rdoc's default)
     attr_accessor :template
 
     # List of files to be included in the rdoc generation. (default is [])
@@ -74,7 +74,7 @@
       @rdoc_dir = 'html'
       @main = nil
       @title = nil
-      @template = 'html'
+      @template = nil
       @external = false
       @options = []
       yield self if block_given?
@@ -91,18 +91,18 @@
       task name
       
       desc "Force a rebuild of the RDOC files"
-      task paste("re", name) => [paste("clobber_", name), name]
+      task "re#{name}" => ["clobber_#{name}", name]
       
       desc "Remove rdoc products" 
-      task paste("clobber_", name) do
+      task "clobber_#{name}" do
         rm_r rdoc_dir rescue nil
       end
-
-      task :clobber => [paste("clobber_", name)]
       
+      task :clobber => ["clobber_#{name}"]
+      
       directory @rdoc_dir
       task name => [rdoc_target]
-      file rdoc_target => @rdoc_files + [$rakefile] do
+      file rdoc_target => @rdoc_files + [Rake.application.rakefile] do
         rm_r @rdoc_dir rescue nil
         args = option_list + @rdoc_files
         if @external

Modified: MacRuby/branches/experimental/lib/rake/tasklib.rb
===================================================================
--- MacRuby/branches/experimental/lib/rake/tasklib.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rake/tasklib.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,11 +6,16 @@
 
   # Base class for Task Libraries.
   class TaskLib
-
     include Cloneable
 
-    # Make a symbol by pasting two strings together. 
-    def paste(a,b)
+    # Make a symbol by pasting two strings together.
+    #
+    # NOTE: DEPRECATED! This method is kinda stupid. I don't know why
+    # I didn't just use string interpolation. But now other task
+    # libraries depend on this so I can't remove it without breaking
+    # other people's code. So for now it stays for backwards
+    # compatibility. BUT DON'T USE IT.
+    def paste(a,b)              # :nodoc:
       (a.to_s + b.to_s).intern
     end
   end

Modified: MacRuby/branches/experimental/lib/rake/testtask.rb
===================================================================
--- MacRuby/branches/experimental/lib/rake/testtask.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rake/testtask.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -136,7 +136,12 @@
     end
 
     def fix # :nodoc:
-      ''
+      case RUBY_VERSION
+      when '1.8.2'
+        find_file 'rake/ruby182_test_unit_fix'
+      else
+        nil
+      end || ''
     end
 
     def rake_loader # :nodoc:

Copied: MacRuby/branches/experimental/lib/rake/win32.rb (from rev 1886, MacRuby/trunk/lib/rake/win32.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rake/win32.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rake/win32.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,34 @@
+module Rake
+
+  # Win 32 interface methods for Rake. Windows specific functionality
+  # will be placed here to collect that knowledge in one spot.
+  module Win32
+    class << self
+      # True if running on a windows system.
+      def windows?
+        # assume other DOSish systems are extinct.
+        File::ALT_SEPARATOR == '\\'
+      end
+    end
+
+    class << self
+      # The standard directory containing system wide rake files on
+      # Win 32 systems. Try the following environment variables (in
+      # order):
+      #
+      # * APPDATA
+      # * HOME
+      # * HOMEDRIVE + HOMEPATH
+      # * USERPROFILE
+      #
+      # If the above are not defined, retruns the personal folder.
+      def win32_system_dir #:nodoc:
+        win32_shared_path = ENV['APPDATA']
+        if !win32_shared_path or win32_shared_path.empty?
+          win32_shared_path = '~'
+        end
+        File.expand_path('Rake', win32_shared_path)
+      end
+    end if windows?
+  end
+end

Modified: MacRuby/branches/experimental/lib/rake.rb
===================================================================
--- MacRuby/branches/experimental/lib/rake.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rake.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -29,15 +29,17 @@
 # as a library via a require statement, but it can be distributed
 # independently as an application.
 
-RAKEVERSION = '0.8.0'
+RAKEVERSION = '0.8.3'
 
 require 'rbconfig'
-require 'getoptlong'
 require 'fileutils'
 require 'singleton'
-require 'thread'
+require 'monitor'
+require 'optparse'
 require 'ostruct'
 
+require 'rake/win32'
+
 ######################################################################
 # Rake extensions to Module.
 #
@@ -58,7 +60,7 @@
   #   end
   #
   def rake_extension(method)
-    if instance_methods.include?(method.to_s) || instance_methods.include?(method.to_sym)
+    if method_defined?(method)
       $stderr.puts "WARNING: Possible conflict with Rake extension: #{self}##{method} already exists"
     else
       yield
@@ -82,7 +84,7 @@
       if newext != ''
         newext = (newext =~ /^\./) ? newext : ("." + newext)
       end
-      dup.sub!(%r(([^/\\])\.[^./\\]*$)) { $1 + newext } || self + newext
+      self.chomp(File.extname(self)) << newext
     end
   end
 
@@ -159,7 +161,7 @@
     #   'a/b/c/d/file.txt'.pathmap("%2d")   => 'a/b'
     #   'a/b/c/d/file.txt'.pathmap("%-2d")  => 'c/d'
     #
-    # Also the %d, %p, $f, $n, %x, and %X operators can take a
+    # Also the %d, %p, %f, %n, %x, and %X operators can take a
     # pattern/replacement argument to perform simple string substititions on a
     # particular part of the path.  The pattern and replacement are speparated
     # by a comma and are enclosed by curly braces.  The replacement spec comes
@@ -201,17 +203,13 @@
         when '%f'
           result << File.basename(self)
         when '%n'
-          result << File.basename(self).ext
+          result << File.basename(self, '.*')
         when '%d'
           result << File.dirname(self)
         when '%x'
-          result << $1 if self =~ /[^\/](\.[^.]+)$/
+          result << File.extname(self)
         when '%X'
-          if self =~ /^(.*[^\/])(\.[^.]+)$/
-            result << $1
-          else
-            result << self
-          end
+          result << self.ext
         when '%p'
           result << self
         when '%s'
@@ -239,6 +237,28 @@
 ##############################################################################
 module Rake
 
+  # Errors -----------------------------------------------------------
+
+  # Error indicating an ill-formed task declaration.
+  class TaskArgumentError < ArgumentError
+  end
+
+  # Error indicating a recursion overflow error in task selection.
+  class RuleRecursionOverflowError < StandardError
+    def initialize(*args)
+      super
+      @targets = []
+    end
+
+    def add_target(target)
+      @targets << target
+    end
+
+    def message
+      super + ": [" + @targets.reverse.join(' => ') + "]"
+    end
+  end
+
   # --------------------------------------------------------------------------
   # Rake module singleton methods.
   #
@@ -266,16 +286,22 @@
   module Cloneable
     # Clone an object by making a new object and setting all the instance
     # variables to the same values.
-    def clone
+    def dup
       sibling = self.class.new
       instance_variables.each do |ivar|
         value = self.instance_variable_get(ivar)
         new_value = value.clone rescue value
         sibling.instance_variable_set(ivar, new_value)
       end
+      sibling.taint if tainted?
       sibling
     end
-    alias dup clone
+
+    def clone
+      sibling = dup
+      sibling.freeze if frozen?
+      sibling
+    end
   end
 
   ####################################################################
@@ -286,12 +312,15 @@
 
     attr_reader :names
 
+    # Create a TaskArgument object with a list of named arguments
+    # (given by :names) and a set of associated values (given by
+    # :values).  :parent is the parent argument object.
     def initialize(names, values, parent=nil)
       @names = names
       @parent = parent
       @hash = {}
       names.each_with_index { |name, i|
-        @hash[name.to_sym] = values[i]
+        @hash[name.to_sym] = values[i] unless values[i].nil?
       }
     end
 
@@ -307,6 +336,13 @@
       lookup(index.to_sym)
     end
 
+    # Specify a hash of default values for task arguments. Use the
+    # defaults only if there is no specific value for the given
+    # argument.
+    def with_defaults(defaults)
+      @hash = defaults.merge(@hash)
+    end
+
     def each(&block)
       @hash.each(&block)
     end
@@ -342,6 +378,8 @@
     end
   end
 
+  EMPTY_TASK_ARGS = TaskArguments.new([], [])
+
   ####################################################################
   # InvocationChain tracks the chain of task invocations to detect
   # circular dependencies.
@@ -409,6 +447,9 @@
     # List of prerequisites for a task.
     attr_reader :prerequisites
 
+    # List of actions attached to a task.
+    attr_reader :actions
+
     # Application owning this task.
     attr_accessor :application
 
@@ -446,12 +487,12 @@
     # +enhance+ to add actions and prerequisites.
     def initialize(task_name, app)
       @name = task_name.to_s
-      @prerequisites = FileList[]
+      @prerequisites = []
       @actions = []
       @already_invoked = false
       @full_comment = nil
       @comment = nil
-      @lock = Mutex.new
+      @lock = Monitor.new
       @application = app
       @scope = app.current_scope
       @arg_names = nil
@@ -488,6 +529,31 @@
       @arg_names || []
     end
 
+    # Reenable the task, allowing its tasks to be executed if the task
+    # is invoked again.
+    def reenable
+      @already_invoked = false
+    end
+
+    # Clear the existing prerequisites and actions of a rake task.
+    def clear
+      clear_prerequisites
+      clear_actions
+      self
+    end
+
+    # Clear the existing prerequisites of a rake task.
+    def clear_prerequisites
+      prerequisites.clear
+      self
+    end
+
+    # Clear the existing actions on a rake task.
+    def clear_actions
+      actions.clear
+      self
+    end
+
     # Invoke the task if it is needed.  Prerequites are invoked first.
     def invoke(*args)
       task_args = TaskArguments.new(arg_names, args)
@@ -496,7 +562,7 @@
 
     # Same as invoke, but explicitly pass a call chain to detect
     # circular dependencies.
-    def invoke_with_call_chain(task_args, invocation_chain)
+    def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
       new_chain = InvocationChain.append(self, invocation_chain)
       @lock.synchronize do
         if application.options.trace
@@ -511,7 +577,7 @@
     protected :invoke_with_call_chain
 
     # Invoke all the prerequisites of a task.
-    def invoke_prerequisites(task_args, invocation_chain)
+    def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
       @prerequisites.each { |n|
         prereq = application[n, @scope]
         prereq_args = task_args.new_scope(prereq.arg_names)
@@ -529,7 +595,8 @@
     private :format_trace_flags
 
     # Execute the actions associated with this task.
-    def execute(args)
+    def execute(args=nil)
+      args ||= EMPTY_TASK_ARGS
       if application.options.dryrun
         puts "** Execute (dry run) #{name}"
         return
@@ -735,6 +802,7 @@
   # parallel using Ruby threads.
   #
   class MultiTask < Task
+    private
     def invoke_prerequisites(args, invocation_chain)
       threads = @prerequisites.collect { |p|
         Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
@@ -772,8 +840,8 @@
 #     end
 #  end
 #
-def file(args, &block)
-  Rake::FileTask.define_task(args, &block)
+def file(*args, &block)
+  Rake::FileTask.define_task(*args, &block)
 end
 
 # Declare a file creation task.
@@ -868,7 +936,8 @@
 # added to the FileUtils utility functions.
 #
 module FileUtils
-  RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
+  RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).
+    sub(/.*\s.*/m, '"\&"')
 
   OPT_TABLE['sh']  = %w(noop verbose)
   OPT_TABLE['ruby'] = %w(noop verbose)
@@ -899,14 +968,25 @@
         ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
       }
     end
+    if RakeFileUtils.verbose_flag == :default
+      options[:verbose] = false
+    else
+      options[:verbose] ||= RakeFileUtils.verbose_flag
+    end
+    options[:noop]    ||= RakeFileUtils.nowrite_flag
     rake_check_options options, :noop, :verbose
     rake_output_message cmd.join(" ") if options[:verbose]
     unless options[:noop]
-      res = system(*cmd)
+      res = rake_system(*cmd)
       block.call(res, $?)
     end
   end
 
+  def rake_system(*cmd)
+    system(*cmd)
+  end
+  private :rake_system
+
   # Run a Ruby interpreter with the given arguments.
   #
   # Example:
@@ -961,7 +1041,7 @@
   class << self
     attr_accessor :verbose_flag, :nowrite_flag
   end
-  RakeFileUtils.verbose_flag = true
+  RakeFileUtils.verbose_flag = :default
   RakeFileUtils.nowrite_flag = false
 
   $fileutils_verbose = true
@@ -969,10 +1049,10 @@
 
   FileUtils::OPT_TABLE.each do |name, opts|
     default_options = []
-    if opts.include?('verbose')
+    if opts.include?(:verbose) || opts.include?("verbose")
       default_options << ':verbose => RakeFileUtils.verbose_flag'
     end
-    if opts.include?('noop')
+    if opts.include?(:noop) || opts.include?("noop")
       default_options << ':noop => RakeFileUtils.nowrite_flag'
     end
 
@@ -1088,28 +1168,13 @@
 # other objects.
 
 include RakeFileUtils
-# FIXME: this doesn't work in MacRuby yet
+#FIXME: cannot use this in MacRuby yet
 #private(*FileUtils.instance_methods(false))
 #private(*RakeFileUtils.instance_methods(false))
 
 ######################################################################
 module Rake
 
-  class RuleRecursionOverflowError < StandardError
-    def initialize(*args)
-      super
-      @targets = []
-    end
-
-    def add_target(target)
-      @targets << target
-    end
-
-    def message
-      super + ": [" + @targets.reverse.join(' => ') + "]"
-    end
-  end
-
   # #########################################################################
   # A FileList is essentially an array with a few helper methods defined to
   # make file manipulation a bit easier.
@@ -1164,12 +1229,12 @@
     ]
 
     DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
-
+    
     # Now do the delegation.
     DELEGATING_METHODS.each_with_index do |sym, i|
       if SPECIAL_RETURN.include?(sym)
         class_eval do
-	  define_method(sym) do |*args, &block|
+	        define_method(sym) do |*args, &block|
             resolve
             result = @items.send(sym, *args, &block)
             FileList.new.import(result)
@@ -1177,7 +1242,7 @@
         end
       else
         class_eval do
-	  define_method(sym) do |*args, &block|
+	        define_method(sym) do |*args, &block|
             resolve
             result = @items.send(sym, *args, &block)
             result.object_id == @items.object_id ? self : result
@@ -1185,6 +1250,7 @@
         end
       end
     end
+    
 
     # Create a file list from the globbable patterns given.  If you wish to
     # perform multiple includes or excludes at object build time, use the
@@ -1408,9 +1474,9 @@
     # name, line number, and the matching line of text.  If no block is given,
     # a standard emac style file:linenumber:line message will be printed to
     # standard out.
-    def egrep(pattern)
+    def egrep(pattern, *opt)
       each do |fn|
-        open(fn) do |inf|
+        open(fn, "rb", *opt) do |inf|
           count = 0
           inf.each do |line|
             count += 1
@@ -1502,7 +1568,7 @@
   class << self
 
     # Yield each file or directory component.
-    def each_dir_parent(dir)
+    def each_dir_parent(dir)    # :nodoc:
       old_length = nil
       while dir != '.' && dir.length != old_length
         yield(dir)
@@ -1641,23 +1707,65 @@
     # Resolve the arguments for a task/rule.  Returns a triplet of
     # [task_name, arg_name_list, prerequisites].
     def resolve_args(args)
+      if args.last.is_a?(Hash)
+        deps = args.pop
+        resolve_args_with_dependencies(args, deps)
+      else
+        resolve_args_without_dependencies(args)
+      end
+    end
+
+    # Resolve task arguments for a task or rule when there are no
+    # dependencies declared.
+    #
+    # The patterns recognized by this argument resolving function are:
+    #
+    #   task :t
+    #   task :t, [:a]
+    #   task :t, :a                 (deprecated)
+    #
+    def resolve_args_without_dependencies(args)
       task_name = args.shift
-      arg_names = args #.map { |a| a.to_sym }
-      needs = []
-      if task_name.is_a?(Hash)
-        hash = task_name
-        task_name = hash.keys[0]
-        needs = hash[task_name]
+      if args.size == 1 && args.first.respond_to?(:to_ary)
+        arg_names = args.first.to_ary
+      else
+        arg_names = args
       end
-      if arg_names.last.is_a?(Hash)
-        hash = arg_names.pop
-        needs = hash[:needs]
-        fail "Unrecognized keys in task hash: #{hash.keys.inspect}" if hash.size > 1
+      [task_name, arg_names, []]
+    end
+    private :resolve_args_without_dependencies
+    
+    # Resolve task arguments for a task or rule when there are
+    # dependencies declared.
+    #
+    # The patterns recognized by this argument resolving function are:
+    #
+    #   task :t => [:d]
+    #   task :t, [a] => [:d]
+    #   task :t, :needs => [:d]                 (deprecated)
+    #   task :t, :a, :needs => [:d]             (deprecated)
+    #
+    def resolve_args_with_dependencies(args, hash) # :nodoc:
+      fail "Task Argument Error" if hash.size != 1
+      key, value = hash.map { |k, v| [k,v] }.first
+      if args.empty?
+        task_name = key
+        arg_names = []
+        deps = value
+      elsif key == :needs
+        task_name = args.shift
+        arg_names = args
+        deps = value
+      else
+        task_name = args.shift
+        arg_names = key
+        deps = value
       end
-      needs = [needs] unless needs.respond_to?(:to_ary)
-      [task_name, arg_names, needs]
+      deps = [deps] unless deps.respond_to?(:to_ary)
+      [task_name, arg_names, deps]
     end
-
+    private :resolve_args_with_dependencies
+    
     # If a rule can be found that matches the task name, enhance the
     # task with the prerequisites and actions from the rule.  Set the
     # source attribute of the task appropriately for the rule.  Return
@@ -1748,15 +1856,23 @@
       "_anon_#{@seed}"
     end
 
+    def trace_rule(level, message)
+      puts "#{"    "*level}#{message}" if Rake.application.options.trace_rules
+    end
+
     # Attempt to create a rule given the list of prerequisites.
     def attempt_rule(task_name, extensions, block, level)
       sources = make_sources(task_name, extensions)
       prereqs = sources.collect { |source|
+        trace_rule level, "Attempting Rule #{task_name} => #{source}"
         if File.exist?(source) || Rake::Task.task_defined?(source)
+          trace_rule level, "(#{task_name} => #{source} ... EXIST)"
           source
-        elsif parent = enhance_with_matching_rule(sources.first, level+1)
+        elsif parent = enhance_with_matching_rule(source, level+1)
+          trace_rule level, "(#{task_name} => #{source} ... ENHANCE)"
           parent.name
         else
+          trace_rule level, "(#{task_name} => #{source} ... FAIL)"
           return nil
         end
       }
@@ -1813,41 +1929,6 @@
 
     DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
 
-    OPTIONS = [     # :nodoc:
-      ['--classic-namespace', '-C', GetoptLong::NO_ARGUMENT,
-        "Put Task and FileTask in the top level namespace"],
-      ['--describe',  '-D', GetoptLong::OPTIONAL_ARGUMENT,
-        "Describe the tasks (matching optional PATTERN), then exit."],
-      ['--rakefile', '-f', GetoptLong::OPTIONAL_ARGUMENT,
-        "Use FILE as the rakefile."],
-      ['--help',     '-h', '-H', GetoptLong::NO_ARGUMENT,
-        "Display this help message."],
-      ['--libdir',   '-I', GetoptLong::REQUIRED_ARGUMENT,
-        "Include LIBDIR in the search path for required modules."],
-      ['--dry-run',  '-n', GetoptLong::NO_ARGUMENT,
-        "Do a dry run without executing actions."],
-      ['--nosearch', '-N', GetoptLong::NO_ARGUMENT,
-        "Do not search parent directories for the Rakefile."],
-      ['--prereqs',  '-P', GetoptLong::NO_ARGUMENT,
-        "Display the tasks and dependencies, then exit."],
-      ['--quiet',    '-q', GetoptLong::NO_ARGUMENT,
-        "Do not log messages to standard output."],
-      ['--require',  '-r', GetoptLong::REQUIRED_ARGUMENT,
-        "Require MODULE before executing rakefile."],
-      ['--rakelibdir', '-R', GetoptLong::REQUIRED_ARGUMENT,
-        "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')"],
-      ['--silent',   '-s', GetoptLong::NO_ARGUMENT,
-        "Like --quiet, but also suppresses the 'in directory' announcement."],
-      ['--tasks',    '-T', GetoptLong::OPTIONAL_ARGUMENT,
-        "Display the tasks (matching optional PATTERN) with descriptions, then exit."],
-      ['--trace',    '-t', GetoptLong::NO_ARGUMENT,
-        "Turn on invoke/execute tracing, enable full backtrace."],
-      ['--verbose',  '-v', GetoptLong::NO_ARGUMENT,
-        "Log message to standard output (default)."],
-      ['--version',  '-V', GetoptLong::NO_ARGUMENT,
-        "Display the program version."],
-    ]
-
     # Initialize a Rake::Application object.
     def initialize
       super
@@ -1860,8 +1941,10 @@
       @default_loader = Rake::DefaultLoader.new
       @original_dir = Dir.pwd
       @top_level_tasks = []
+      add_loader('rb', DefaultLoader.new)
       add_loader('rf', DefaultLoader.new)
       add_loader('rake', DefaultLoader.new)
+      @tty_output = STDOUT.tty?
     end
 
     # Run the Rake application.  The run method performs the following three steps:
@@ -1885,8 +1968,7 @@
     def init(app_name='rake')
       standard_exception_handling do
         @name = app_name
-        handle_options
-        collect_tasks
+        collect_tasks handle_options
       end
     end
 
@@ -1947,10 +2029,10 @@
         yield
       rescue SystemExit => ex
         # Exit silently with current status
-        exit(ex.status)
-      rescue SystemExit, GetoptLong::InvalidOption => ex
+        raise
+      rescue OptionParser::InvalidOption => ex
         # Exit silently
-        exit(1)
+        exit(false)
       rescue Exception => ex
         # Exit with error message
         $stderr.puts "rake aborted!"
@@ -1961,7 +2043,7 @@
           $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
           $stderr.puts "(See full trace by running task with --trace)"
         end
-        exit(1)
+        exit(false)
       end
     end
 
@@ -1970,30 +2052,28 @@
     def have_rakefile
       @rakefiles.each do |fn|
         if File.exist?(fn) || fn == ''
-          @rakefile = fn
-          return true
+          return fn
         end
       end
-      return false
+      return nil
     end
 
-    # Display the rake command line help.
-    def help
-      puts "rake [-f rakefile] {options} targets..."
-      puts
-      puts "Options are ..."
-      puts
-      OPTIONS.sort.each do |long, short, mode, desc|
-        if mode == GetoptLong::REQUIRED_ARGUMENT
-          if desc =~ /\b([A-Z]{2,})\b/
-            long = long + "=#{$1}"
-          end
-        end
-        printf "  %-20s (%s)\n", long, short
-        printf "      %s\n", desc
-      end
+    # True if we are outputting to TTY, false otherwise
+    def tty_output?
+      @tty_output
     end
 
+    # Override the detected TTY output state (mostly for testing)
+    def tty_output=( tty_output_state )
+      @tty_output = tty_output_state
+    end
+
+    # We will truncate output if we are outputting to a TTY or if we've been
+    # given an explicit column width to honor
+    def truncate_output?
+      tty_output? || ENV['RAKE_COLUMNS']
+    end
+
     # Display the tasks and dependencies.
     def display_tasks_and_comments
       displayable_tasks = tasks.select { |t|
@@ -2009,19 +2089,51 @@
         end
       else
         width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
-        max_column = 80 - name.size - width - 7
+        max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil
         displayable_tasks.each do |t|
           printf "#{name} %-#{width}s  # %s\n",
-            t.name_with_args, truncate(t.comment, max_column)
+            t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment
         end
       end
     end
 
+    def terminal_width
+      if ENV['RAKE_COLUMNS']
+        result = ENV['RAKE_COLUMNS'].to_i
+      else
+        result = unix? ? dynamic_width : 80
+      end
+      (result < 10) ? 80 : result
+    rescue
+      80
+    end
+
+    # Calculate the dynamic width of the 
+    def dynamic_width
+      @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
+    end
+
+    def dynamic_width_stty
+      %x{stty size 2>/dev/null}.split[1].to_i
+    end
+
+    def dynamic_width_tput
+      %x{tput cols 2>/dev/null}.to_i
+    end
+
+    def unix?
+      RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
+    end
+    
+    def windows?
+      Win32.windows?
+    end
+
     def truncate(string, width)
       if string.length <= width
         string
       else
-        string[0, width-3] + "..."
+        ( string[0, width-3] || "" ) + "..."
       end
     end
 
@@ -2033,77 +2145,141 @@
       end
     end
 
-    # Return a list of the command line options supported by the
-    # program.
-    def command_line_options
-      OPTIONS.collect { |lst| lst[0..-2] }
+    # A list of all the standard options used in rake, suitable for
+    # passing to OptionParser.
+    def standard_rake_options
+      [
+        ['--classic-namespace', '-C', "Put Task and FileTask in the top level namespace",
+          lambda { |value|
+            require 'rake/classic_namespace'
+            options.classic_namespace = true
+          }
+        ],
+        ['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
+          lambda { |value|
+            options.show_tasks = true
+            options.full_description = true
+            options.show_task_pattern = Regexp.new(value || '')
+          }
+        ],
+        ['--dry-run', '-n', "Do a dry run without executing actions.",
+          lambda { |value|
+            verbose(true)
+            nowrite(true)
+            options.dryrun = true
+            options.trace = true
+          }
+        ],
+        ['--execute',  '-e CODE', "Execute some Ruby code and exit.",
+          lambda { |value|
+            eval(value)
+            exit
+          }
+        ],
+        ['--execute-print',  '-p CODE', "Execute some Ruby code, print the result, then exit.",
+          lambda { |value|
+            puts eval(value)
+            exit
+          }
+        ],
+        ['--execute-continue',  '-E CODE',
+          "Execute some Ruby code, then continue with normal task processing.",
+          lambda { |value| eval(value) }            
+        ],
+        ['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
+          lambda { |value| $:.push(value) }
+        ],
+        ['--prereqs', '-P', "Display the tasks and dependencies, then exit.",
+          lambda { |value| options.show_prereqs = true }
+        ],
+        ['--quiet', '-q', "Do not log messages to standard output.",
+          lambda { |value| verbose(false) }
+        ],
+        ['--rakefile', '-f [FILE]', "Use FILE as the rakefile.",
+          lambda { |value| 
+            value ||= ''
+            @rakefiles.clear 
+            @rakefiles << value
+          }
+        ],
+        ['--rakelibdir', '--rakelib', '-R RAKELIBDIR',
+          "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')",
+          lambda { |value| options.rakelib = value.split(':') }
+        ],
+        ['--require', '-r MODULE', "Require MODULE before executing rakefile.",
+          lambda { |value|
+            begin
+              require value
+            rescue LoadError => ex
+              begin
+                rake_require value
+              rescue LoadError => ex2
+                raise ex
+              end
+            end
+          }
+        ],
+        ['--rules', "Trace the rules resolution.",
+          lambda { |value| options.trace_rules = true }
+        ],
+        ['--no-search', '--nosearch', '-N', "Do not search parent directories for the Rakefile.",
+          lambda { |value| options.nosearch = true }
+        ],
+        ['--silent', '-s', "Like --quiet, but also suppresses the 'in directory' announcement.",
+          lambda { |value|
+            verbose(false)
+            options.silent = true
+          }
+        ],
+        ['--system',  '-g',
+          "Using system wide (global) rakefiles (usually '~/.rake/*.rake').",
+          lambda { |value| options.load_system = true }
+        ],
+        ['--no-system', '--nosystem', '-G',
+          "Use standard project Rakefile search paths, ignore system wide rakefiles.",
+          lambda { |value| options.ignore_system = true }
+        ],
+        ['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.",
+          lambda { |value|
+            options.show_tasks = true
+            options.show_task_pattern = Regexp.new(value || '')
+            options.full_description = false
+          }
+        ],
+        ['--trace', '-t', "Turn on invoke/execute tracing, enable full backtrace.",
+          lambda { |value|
+            options.trace = true
+            verbose(true)
+          }
+        ],
+        ['--verbose', '-v', "Log message to standard output (default).",
+          lambda { |value| verbose(true) }
+        ],
+        ['--version', '-V', "Display the program version.",
+          lambda { |value|
+            puts "rake, version #{RAKEVERSION}"
+            exit
+          }
+        ]
+      ]
     end
 
-    # Do the option defined by +opt+ and +value+.
-    def do_option(opt, value)
-      case opt
-      when '--describe'
-        options.show_tasks = true
-        options.show_task_pattern = Regexp.new(value || '.')
-        options.full_description = true
-      when '--dry-run'
-        verbose(true)
-        nowrite(true)
-        options.dryrun = true
-        options.trace = true
-      when '--help'
-        help
-        exit
-      when '--libdir'
-        $:.push(value)
-      when '--nosearch'
-        options.nosearch = true
-      when '--prereqs'
-        options.show_prereqs = true
-      when '--quiet'
-        verbose(false)
-      when '--rakefile'
-        @rakefiles.clear
-        @rakefiles << value
-      when '--rakelibdir'
-        options.rakelib = value.split(':')
-      when '--require'
-        begin
-          require value
-        rescue LoadError => ex
-          begin
-            rake_require value
-          rescue LoadError => ex2
-            raise ex
-          end
-        end
-      when '--silent'
-        verbose(false)
-        options.silent = true
-      when '--tasks'
-        options.show_tasks = true
-        options.show_task_pattern = Regexp.new(value || '.')
-        options.full_description = false
-      when '--trace'
-        options.trace = true
-        verbose(true)
-      when '--verbose'
-        verbose(true)
-      when '--version'
-        puts "rake, version #{RAKEVERSION}"
-        exit
-      when '--classic-namespace'
-        require 'rake/classic_namespace'
-        options.classic_namespace = true
-      end
-    end
-
     # Read and handle the command line options.
     def handle_options
       options.rakelib = ['rakelib']
 
-      opts = GetoptLong.new(*command_line_options)
-      opts.each { |opt, value| do_option(opt, value) }
+      opts = OptionParser.new
+      opts.banner = "rake [-f rakefile] {options} targets..."
+      opts.separator ""
+      opts.separator "Options are ..."
+      
+      opts.on_tail("-h", "--help", "-H", "Display this help message.") do
+        puts opts
+        exit
+      end
+      
+      standard_rake_options.each { |args| opts.on(*args) }
+      parsed_argv = opts.parse(ARGV)
 
       # If class namespaces are requested, set the global options
       # according to the values in the options structure.
@@ -2114,12 +2290,11 @@
         $dryrun = options.dryrun
         $silent = options.silent
       end
-    rescue NoMethodError => ex
-      raise GetoptLong::InvalidOption, "While parsing options, error = #{ex.class}:#{ex.message}"
+      parsed_argv
     end
 
     # Similar to the regular Ruby +require+ command, but will check
-    # for .rake files in addition to .rb files.
+    # for *.rake files in addition to *.rb files.
     def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
       return false if loaded.include?(file_name)
       paths.each do |path|
@@ -2134,34 +2309,85 @@
       fail LoadError, "Can't find #{file_name}"
     end
 
-    def raw_load_rakefile # :nodoc:
+    def find_rakefile_location
       here = Dir.pwd
-      while ! have_rakefile
+      while ! (fn = have_rakefile)
         Dir.chdir("..")
         if Dir.pwd == here || options.nosearch
-          fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})"
+          return nil
         end
         here = Dir.pwd
       end
-      puts "(in #{Dir.pwd})" unless options.silent
-      $rakefile = @rakefile
-      load File.expand_path(@rakefile) if @rakefile != ''
-      options.rakelib.each do |rlib|
-        Dir["#{rlib}/*.rake"].each do |name| add_import name end
+      [fn, here]
+    ensure
+      Dir.chdir(Rake.original_dir)
+    end
+
+    def raw_load_rakefile # :nodoc:
+      rakefile, location = find_rakefile_location
+      if (! options.ignore_system) &&
+          (options.load_system || rakefile.nil?) &&
+          system_dir && File.directory?(system_dir)
+        puts "(in #{Dir.pwd})" unless options.silent
+        glob("#{system_dir}/*.rake") do |name|
+          add_import name
+        end
+      else
+        fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if
+          rakefile.nil?
+        @rakefile = rakefile
+        Dir.chdir(location)
+        puts "(in #{Dir.pwd})" unless options.silent
+        $rakefile = @rakefile if options.classic_namespace
+        load File.expand_path(@rakefile) if @rakefile && @rakefile != ''
+        options.rakelib.each do |rlib|
+          glob("#{rlib}/*.rake") do |name|
+            add_import name
+          end
+        end
       end
       load_imports
     end
 
+    def glob(path, &block)
+      Dir[path.gsub("\\", '/')].each(&block)
+    end
+    private :glob
+
+    # The directory path containing the system wide rakefiles.
+    def system_dir
+      @system_dir ||=
+        begin
+          if ENV['RAKE_SYSTEM']
+            ENV['RAKE_SYSTEM']
+          else
+            standard_system_dir
+          end
+        end
+    end
+    
+    # The standard directory containing system wide rake files.
+    if Win32.windows?
+      def standard_system_dir #:nodoc:
+        Win32.win32_system_dir
+      end
+    else
+      def standard_system_dir #:nodoc:
+        File.expand_path('.rake', '~')
+      end
+    end
+    private :standard_system_dir
+
     # Collect the list of tasks on the command line.  If no tasks are
     # given, return a list containing only the default task.
     # Environmental assignments are processed at this time as well.
-    def collect_tasks
+    def collect_tasks(argv)
       @top_level_tasks = []
-      ARGV.each do |arg|
+      argv.each do |arg|
         if arg =~ /^(\w+)=(.*)$/
           ENV[$1] = $2
         else
-          @top_level_tasks << arg
+          @top_level_tasks << arg unless arg =~ /^-/
         end
       end
       @top_level_tasks.push("default") if @top_level_tasks.size == 0

Modified: MacRuby/branches/experimental/lib/rational.rb
===================================================================
--- MacRuby/branches/experimental/lib/rational.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rational.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,7 +3,7 @@
   alias quof fdiv
   alias rdiv quo
 
-  alias power! **
+  alias power! ** unless defined?(0.power!)
   alias rpower **
 
 end
@@ -13,7 +13,7 @@
   alias quof fdiv
   alias rdiv quo
 
-  alias power! **
+  alias power! ** unless defined?(0.power!)
   alias rpower **
 
 end

Modified: MacRuby/branches/experimental/lib/rdoc/README
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/README	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/README	2009-06-19 22:42:24 UTC (rev 1889)
@@ -17,7 +17,7 @@
 * If you want to include extensions written in C, see RDoc::C_Parser
 * For information on the various markups available in comment blocks, see
   RDoc::Markup.
-* If you want to drive RDoc programatically, see RDoc::RDoc.
+* If you want to drive RDoc programmatically, see RDoc::RDoc.
 * If you want to use the library to format text blocks into HTML, have a look
   at RDoc::Markup.
 * If you want to try writing your own HTML output template, see
@@ -196,7 +196,7 @@
   Stop and start adding new documentation elements to the current container.
   For example, if a class has a number of constants that you don't want to
   document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
-  last.  If you don't specifiy a +:startdoc:+ by the end of the container,
+  last.  If you don't specify a +:startdoc:+ by the end of the container,
   disables documentation for the entire class or module.
 
 = Other stuff

Modified: MacRuby/branches/experimental/lib/rdoc/code_objects.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/code_objects.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/code_objects.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,8 +6,8 @@
 module RDoc
 
   ##
-  # We contain the common stuff for contexts (which are containers)
-  # and other elements (methods, attributes and so on)
+  # We contain the common stuff for contexts (which are containers) and other
+  # elements (methods, attributes and so on)
 
   class CodeObject
 
@@ -31,6 +31,13 @@
 
     attr_reader :document_self
 
+    def initialize
+      @document_self = true
+      @document_children = true
+      @force_documentation = false
+      @done_documenting = false
+    end
+
     def document_self=(val)
       @document_self = val
       if !val
@@ -64,6 +71,14 @@
     # Do we _force_ documentation, even is we wouldn't normally show the entity
     attr_accessor :force_documentation
 
+    def parent_file_name
+      @parent ? @parent.file_base_name : '(unknown)'
+    end
+
+    def parent_name
+      @parent ? @parent.name : '(unknown)'
+    end
+
     # Default callbacks to nothing, but this is overridden for classes
     # and modules
     def remove_classes_and_modules
@@ -72,13 +87,6 @@
     def remove_methods_etc
     end
 
-    def initialize
-      @document_self = true
-      @document_children = true
-      @force_documentation = false
-      @done_documenting = false
-    end
-
     # Access the code object's comment
     attr_reader :comment
 
@@ -106,15 +114,24 @@
 
   end
 
-  # A Context is something that can hold modules, classes, methods, 
-  # attributes, aliases, requires, and includes. Classes, modules, and
-  # files are all Contexts.
+  ##
+  # A Context is something that can hold modules, classes, methods,
+  # attributes, aliases, requires, and includes. Classes, modules, and files
+  # are all Contexts.
 
   class Context < CodeObject
-    attr_reader   :name, :method_list, :attributes, :aliases, :constants
-    attr_reader   :requires, :includes, :in_files, :visibility
 
-    attr_reader   :sections
+    attr_reader :aliases
+    attr_reader :attributes
+    attr_reader :constants
+    attr_reader :current_section
+    attr_reader :in_files
+    attr_reader :includes
+    attr_reader :method_list
+    attr_reader :name
+    attr_reader :requires
+    attr_reader :sections
+    attr_reader :visibility
 
     class Section
       attr_reader :title, :comment, :sequence
@@ -129,12 +146,22 @@
         set_comment(comment)
       end
 
-      private
+      def ==(other)
+        self.class === other and @sequence == other.sequence
+      end
 
-      # Set the comment for this section from the original comment block
-      # If the first line contains :section:, strip it and use the rest. Otherwise
-      # remove lines up to the line containing :section:, and look for 
-      # those lines again at the end and remove them. This lets us write
+      def inspect
+        "#<%s:0x%x %s %p>" % [
+          self.class, object_id,
+          @sequence, title
+        ]
+      end
+
+      ##
+      # Set the comment for this section from the original comment block If
+      # the first line contains :section:, strip it and use the rest.
+      # Otherwise remove lines up to the line containing :section:, and look
+      # for those lines again at the end and remove them. This lets us write
       #
       #   # ---------------------
       #   # :SECTION: The title
@@ -144,9 +171,10 @@
       def set_comment(comment)
         return unless comment
 
-        if comment =~ /^.*?:section:.*$/
+        if comment =~ /^#[ \t]*:section:.*\n/
           start = $`
           rest = $'
+
           if start.empty?
             @comment = rest
           else
@@ -157,13 +185,13 @@
         end
         @comment = nil if @comment.empty?
       end
+
     end
 
-
     def initialize
-      super()
+      super
 
-      @in_files    = []
+      @in_files = []
 
       @name    ||= "unknown"
       @comment ||= ""
@@ -177,29 +205,53 @@
       initialize_classes_and_modules
     end
 
+    ##
     # map the class hash to an array externally
+
     def classes
       @classes.values
     end
 
+    ##
     # map the module hash to an array externally
+
     def modules
       @modules.values
     end
 
+    ##
+    # return the classes Hash (only to be used internally)
+
+    def classes_hash
+      @classes
+    end
+    protected :classes_hash
+
+    ##
+    # return the modules Hash (only to be used internally)
+
+    def modules_hash
+      @modules
+    end
+    protected :modules_hash
+
+    ##
     # Change the default visibility for new methods
+
     def ongoing_visibility=(vis)
       @visibility = vis
     end
 
-    # Given an array +methods+ of method names, set the
-    # visibility of the corresponding AnyMethod object
+    ##
+    # Yields Method and Attr entries matching the list of names in +methods+.
+    # Attributes are only returned when +singleton+ is false.
 
-    def set_visibility_for(methods, vis, singleton=false)
+    def methods_matching(methods, singleton = false)
       count = 0
+
       @method_list.each do |m|
-        if methods.include?(m.name) && m.singleton == singleton
-          m.visibility = vis
+        if methods.include? m.name and m.singleton == singleton then
+          yield m
           count += 1
         end
       end
@@ -209,14 +261,23 @@
       # perhaps we need to look at attributes
 
       @attributes.each do |a|
-        if methods.include?(a.name)
-          a.visibility = vis
-          count += 1
-        end
+        yield a if methods.include? a.name
       end
     end
 
+    ##
+    # Given an array +methods+ of method names, set the visibility of the
+    # corresponding AnyMethod object
+
+    def set_visibility_for(methods, vis, singleton = false)
+      methods_matching methods, singleton do |m|
+        m.visibility = vis
+      end
+    end
+
+    ##
     # Record the file that we happen to find it in
+
     def record_location(toplevel)
       @in_files << toplevel unless @in_files.include?(toplevel)
     end
@@ -227,7 +288,24 @@
     end
 
     def add_class(class_type, name, superclass)
-      add_class_or_module(@classes, class_type, name, superclass)
+      klass = add_class_or_module @classes, class_type, name, superclass
+
+      #
+      # If the parser encounters Container::Item before encountering
+      # Container, then it assumes that Container is a module.  This
+      # may not be the case, so remove Container from the module list
+      # if present and transfer any contained classes and modules to
+      # the new class.
+      #
+      mod = @modules.delete(name)
+
+      if mod then
+        klass.classes_hash.update(mod.classes_hash)
+        klass.modules_hash.update(mod.modules_hash)
+        klass.method_list.concat(mod.method_list)
+      end
+
+      return klass
     end
 
     def add_module(class_type, name)
@@ -235,28 +313,46 @@
     end
 
     def add_method(a_method)
-      puts "Adding #@visibility method #{a_method.name} to #@name" if $DEBUG_RDOC
       a_method.visibility = @visibility
       add_to(@method_list, a_method)
+
+      unmatched_alias_list = @unmatched_alias_lists[a_method.name]
+      if unmatched_alias_list then
+        unmatched_alias_list.each do |unmatched_alias|
+          add_alias_impl unmatched_alias, a_method
+          @aliases.delete unmatched_alias
+        end
+
+        @unmatched_alias_lists.delete a_method.name
+      end
     end
 
     def add_attribute(an_attribute)
       add_to(@attributes, an_attribute)
     end
 
+    def add_alias_impl(an_alias, meth)
+      new_meth = AnyMethod.new(an_alias.text, an_alias.new_name)
+      new_meth.is_alias_for = meth
+      new_meth.singleton    = meth.singleton
+      new_meth.params       = meth.params
+      new_meth.comment = "Alias for \##{meth.name}"
+      meth.add_alias(new_meth)
+      add_method(new_meth)
+    end
+    
     def add_alias(an_alias)
       meth = find_instance_method_named(an_alias.old_name)
-      if meth
-        new_meth = AnyMethod.new(an_alias.text, an_alias.new_name)
-        new_meth.is_alias_for = meth
-        new_meth.singleton    = meth.singleton
-        new_meth.params       = meth.params
-        new_meth.comment = "Alias for \##{meth.name}"
-        meth.add_alias(new_meth)
-        add_method(new_meth)
+
+      if meth then
+        add_alias_impl(an_alias, meth)
       else
         add_to(@aliases, an_alias)
+        unmatched_alias_list = @unmatched_alias_lists[an_alias.old_name] ||= []
+        unmatched_alias_list.push(an_alias)
       end
+
+      an_alias
     end
 
     def add_include(an_include)
@@ -269,20 +365,21 @@
 
     # Requires always get added to the top-level (file) context
     def add_require(a_require)
-      if self.kind_of? TopLevel
-        add_to(@requires, a_require)
+      if TopLevel === self then
+        add_to @requires, a_require
       else
-        parent.add_require(a_require)
+        parent.add_require a_require
       end
     end
 
     def add_class_or_module(collection, class_type, name, superclass=nil)
       cls = collection[name]
-      if cls
+
+      if cls then
+        cls.superclass = superclass unless cls.module?
         puts "Reusing class/module #{name}" if $DEBUG_RDOC
       else
         cls = class_type.new(name, superclass)
-        puts "Adding class/module #{name} to #@name" if $DEBUG_RDOC
 #        collection[name] = cls if @document_self  && !@done_documenting
         collection[name] = cls if !@done_documenting
         cls.parent = self
@@ -292,7 +389,7 @@
     end
 
     def add_to(array, thing)
-      array <<  thing if @document_self  && !@done_documenting
+      array << thing if @document_self and not @done_documenting
       thing.parent = self
       thing.section = @current_section
     end
@@ -312,6 +409,10 @@
       @requires    = []
       @includes    = []
       @constants   = []
+
+      # This Hash maps a method name to a list of unmatched
+      # aliases (aliases of a method not yet encountered).
+      @unmatched_alias_lists = {}
     end
 
     # and remove classes and modules when we see a :nodoc: all
@@ -326,9 +427,12 @@
 
     # Find a named module
     def find_module_named(name)
-      return self if self.name == name
+      # First check the enclosed modules, then check the module itself,
+      # then check the enclosing modules (this mirrors the check done by
+      # the Ruby parser)
       res = @modules[name] || @classes[name]
       return res if res
+      return self if self.name == name
       find_enclosing_module_named(name)
     end
 
@@ -371,26 +475,31 @@
       name <=> other.name
     end
 
-    # Look up the given symbol. If method is non-nil, then
-    # we assume the symbol references a module that
-    # contains that method
-    def find_symbol(symbol, method=nil)
+    ##
+    # Look up +symbol+.  If +method+ is non-nil, then we assume the symbol
+    # references a module that contains that method.
+
+    def find_symbol(symbol, method = nil)
       result = nil
+
       case symbol
-      when /^::(.*)/
+      when /^::(.*)/ then
         result = toplevel.find_symbol($1)
-      when /::/
+      when /::/ then
         modules = symbol.split(/::/)
-        unless modules.empty?
+
+        unless modules.empty? then
           module_name = modules.shift
           result = find_module_named(module_name)
-          if result
+
+          if result then
             modules.each do |name|
               result = result.find_module_named(name)
               break unless result
             end
           end
         end
+
       else
         # if a method is specified, then we're definitely looking for
         # a module, otherwise it could be any symbol
@@ -408,22 +517,21 @@
           end
         end
       end
-      if result && method
-        if !result.respond_to?(:find_local_symbol)
-          #p result.name
-          #p method
-          fail
-        end
+
+      if result and method then
+        fail unless result.respond_to? :find_local_symbol
         result = result.find_local_symbol(method)
       end
+
       result
     end
-           
+
     def find_local_symbol(symbol)
       res = find_method_named(symbol) ||
             find_constant_named(symbol) ||
             find_attribute_named(symbol) ||
-            find_module_named(symbol) 
+            find_module_named(symbol) ||
+            find_file_named(symbol)
     end
 
     # Handle sections
@@ -454,7 +562,14 @@
     def find_attribute_named(name)
       @attributes.find {|m| m.name == name}
     end
-    
+
+    ##
+    # Find a named file, or return nil
+
+    def find_file_named(name)
+      toplevel.class.find_file_named(name)
+    end
+
   end
 
   ##
@@ -465,24 +580,31 @@
     attr_accessor :file_relative_name
     attr_accessor :file_absolute_name
     attr_accessor :diagram
-    
+
     @@all_classes = {}
     @@all_modules = {}
+    @@all_files   = {}
 
     def self.reset
       @@all_classes = {}
       @@all_modules = {}
+      @@all_files   = {}
     end
 
     def initialize(file_name)
       super()
       @name = "TopLevel"
-      @file_relative_name = file_name
-      @file_absolute_name = file_name
-      @file_stat          = File.stat(file_name)
-      @diagram            = nil
+      @file_relative_name    = file_name
+      @file_absolute_name    = file_name
+      @file_stat             = File.stat(file_name)
+      @diagram               = nil
+      @@all_files[file_name] = self
     end
 
+    def file_base_name
+      File.basename @file_absolute_name
+    end
+
     def full_name
       nil
     end
@@ -496,10 +618,11 @@
     def add_class_or_module(collection, class_type, name, superclass)
       cls = collection[name]
 
-      if cls
-        puts "Reusing class/module #{name}" if $DEBUG_RDOC
+      if cls then
+        cls.superclass = superclass unless cls.module?
+        puts "Reusing class/module #{cls.full_name}" if $DEBUG_RDOC
       else
-        if class_type == NormalModule
+        if class_type == NormalModule then
           all = @@all_modules
         else
           all = @@all_classes
@@ -507,13 +630,20 @@
 
         cls = all[name]
 
-        if !cls
-          cls = class_type.new(name, superclass)
+        if !cls then
+          cls = class_type.new name, superclass
           all[name] = cls unless @done_documenting
+        else
+          # If the class has been encountered already, check that its
+          # superclass has been set (it may not have been, depending on
+          # the context in which it was encountered).
+          if class_type == NormalClass
+            if !cls.superclass then
+              cls.superclass = superclass
+            end
+          end
         end
 
-        puts "Adding class/module #{name} to #{@name}" if $DEBUG_RDOC
-
         collection[name] = cls unless @done_documenting
 
         cls.parent = self
@@ -534,6 +664,10 @@
       nil
     end
 
+    def self.find_file_named(name)
+      @@all_files[name]
+    end
+
     def find_local_symbol(symbol)
       find_class_or_module_named(symbol) || super
     end
@@ -551,14 +685,23 @@
       find_class_or_module_named(name) || find_enclosing_module_named(name)
     end
 
+    def inspect
+      "#<%s:0x%x %p modules: %p classes: %p>" % [
+        self.class, object_id,
+        file_base_name,
+        @modules.map { |n,m| m },
+        @classes.map { |n,c| c }
+      ]
+    end
+
   end
 
-  # ClassModule is the base class for objects representing either a
-  # class or a module.
+  ##
+  # ClassModule is the base class for objects representing either a class or a
+  # module.
 
   class ClassModule < Context
 
-    attr_reader   :superclass
     attr_accessor :diagram
 
     def initialize(name, superclass = nil)
@@ -569,7 +712,15 @@
       super()
     end
 
+    def find_class_named(name)
+      return self if full_name == name
+      @classes.each_value {|c| return c if c.find_class_named(name) }
+      nil
+    end
+
+    ##
     # Return the fully qualified name of this class or module
+
     def full_name
       if @parent && @parent.full_name
         @parent.full_name + "::" + @name
@@ -583,49 +734,106 @@
       File.join(prefix, *path) + ".html"
     end
 
-    # Return +true+ if this object represents a module
-    def is_module?
+    ##
+    # Does this object represent a module?
+
+    def module?
       false
     end
 
-    # to_s is simply for debugging
+    ##
+    # Get the superclass of this class.  Attempts to retrieve the superclass'
+    # real name by following module nesting.
+
+    def superclass
+      raise NoMethodError, "#{full_name} is a module" if module?
+
+      scope = self
+
+      begin
+        superclass = scope.classes.find { |c| c.name == @superclass }
+
+        return superclass.full_name if superclass
+        scope = scope.parent
+      end until scope.nil? or TopLevel === scope
+
+      @superclass
+    end
+
+    ##
+    # Set the superclass of this class
+
+    def superclass=(superclass)
+      raise NoMethodError, "#{full_name} is a module" if module?
+
+      if @superclass.nil? or @superclass == 'Object' then
+        @superclass = superclass 
+      end
+    end
+
     def to_s
-      res = self.class.name + ": " + @name 
-      res << @comment.to_s
-      res << super
-      res
+      "#{self.class}: #{@name} #{@comment} #{super}"
     end
 
-    def find_class_named(name)
-      return self if full_name == name
-      @classes.each_value {|c| return c if c.find_class_named(name) }
-      nil
-    end
   end
 
+  ##
   # Anonymous classes
+
   class AnonClass < ClassModule
   end
 
+  ##
   # Normal classes
+
   class NormalClass < ClassModule
+
+    def inspect
+      superclass = @superclass ? " < #{@superclass}" : nil
+      "<%s:0x%x class %s%s includes: %p attributes: %p methods: %p aliases: %p>" % [
+        self.class, object_id,
+        @name, superclass, @includes, @attributes, @method_list, @aliases
+      ]
+    end
+
   end
 
+  ##
   # Singleton classes
+
   class SingleClass < ClassModule
   end
 
+  ##
   # Module
+
   class NormalModule < ClassModule
-    def is_module?
+
+    def comment=(comment)
+      return if comment.empty?
+      comment = @comment << "# ---\n" << comment unless @comment.empty?
+
+      super
+    end
+
+    def inspect
+      "#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [
+        self.class, object_id,
+        @name, @includes, @attributes, @method_list, @aliases
+      ]
+    end
+
+    def module?
       true
     end
+
   end
 
   ##
   # AnyMethod is the base class for objects representing methods
 
   class AnyMethod < CodeObject
+
     attr_accessor :name
     attr_accessor :visibility
     attr_accessor :block_params
@@ -663,44 +871,71 @@
       @name <=> other.name
     end
 
-    def to_s
-      res = self.class.name + ": " + @name + " (" + @text + ")\n"
-      res << @comment.to_s
-      res
+    def add_alias(method)
+      @aliases << method
     end
 
+    def inspect
+      alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
+      "#<%s:0x%x %s%s%s (%s)%s>" % [
+        self.class, object_id,
+        parent_name,
+        singleton ? '::' : '#',
+        name,
+        visibility,
+        alias_for,
+      ]
+    end
+
     def param_seq
-      p = params.gsub(/\s*\#.*/, '')
-      p = p.tr("\n", " ").squeeze(" ")
-      p = "(" + p + ")" unless p[0] == ?(
+      params = params.gsub(/\s*\#.*/, '')
+      params = params.tr("\n", " ").squeeze(" ")
+      params = "(#{params})" unless p[0] == ?(
 
-      if (block = block_params)
-        # If this method has explicit block parameters, remove any
-        # explicit &block
-$stderr.puts p
-        p.sub!(/,?\s*&\w+/)
-$stderr.puts p
+      if block = block_params then # yes, =
+        # If this method has explicit block parameters, remove any explicit
+        # &block
+        params.sub!(/,?\s*&\w+/)
 
         block.gsub!(/\s*\#.*/, '')
         block = block.tr("\n", " ").squeeze(" ")
         if block[0] == ?(
           block.sub!(/^\(/, '').sub!(/\)/, '')
         end
-        p << " {|#{block}| ...}"
+        params << " { |#{block}| ... }"
       end
-      p
+
+      params
     end
 
-    def add_alias(method)
-      @aliases << method
+    def to_s
+      res = self.class.name + ": " + @name + " (" + @text + ")\n"
+      res << @comment.to_s
+      res
     end
+
   end
 
-  # Represent an alias, which is an old_name/ new_name pair associated
-  # with a particular context
+  ##
+  # GhostMethod represents a method referenced only by a comment
+
+  class GhostMethod < AnyMethod
+  end
+
+  ##
+  # MetaMethod represents a meta-programmed method
+
+  class MetaMethod < AnyMethod
+  end
+
+  ##
+  # Represent an alias, which is an old_name/ new_name pair associated with a
+  # particular context
+
   class Alias < CodeObject
+
     attr_accessor :text, :old_name, :new_name, :comment
-    
+
     def initialize(text, old_name, new_name, comment)
       super()
       @text = text
@@ -709,12 +944,22 @@
       self.comment = comment
     end
 
+    def inspect
+      "#<%s:0x%x %s.alias_method %s, %s>" % [
+        self.class, object_id,
+        parent.name, @old_name, @new_name,
+      ]
+    end
+
     def to_s
       "alias: #{self.old_name} ->  #{self.new_name}\n#{self.comment}"
     end
+
   end
 
+  ##
   # Represent a constant
+
   class Constant < CodeObject
     attr_accessor :name, :value
 
@@ -726,7 +971,9 @@
     end
   end
 
+  ##
   # Represent attributes
+
   class Attr < CodeObject
     attr_accessor :text, :name, :rw, :visibility
 
@@ -739,16 +986,33 @@
       self.comment = comment
     end
 
+    def <=>(other)
+      self.name <=> other.name
+    end
+
+    def inspect
+      attr = case rw
+             when 'RW' then :attr_accessor
+             when 'R'  then :attr_reader
+             when 'W'  then :attr_writer
+             else
+               " (#{rw})"
+             end
+
+      "#<%s:0x%x %s.%s :%s>" % [
+        self.class, object_id,
+        parent_name, attr, @name,
+      ]
+    end
+
     def to_s
       "attr: #{self.name} #{self.rw}\n#{self.comment}"
     end
 
-    def <=>(other)
-      self.name <=> other.name
-    end
   end
 
-  # a required file
+  ##
+  # A required file
 
   class Require < CodeObject
     attr_accessor :name
@@ -759,18 +1023,39 @@
       self.comment = comment
     end
 
+    def inspect
+      "#<%s:0x%x require '%s' in %s>" % [
+        self.class,
+        object_id,
+        @name,
+        parent_file_name,
+      ]
+    end
+
   end
 
-  # an included module
+  ##
+  # An included module
+
   class Include < CodeObject
+
     attr_accessor :name
 
     def initialize(name, comment)
       super()
       @name = name
       self.comment = comment
+
     end
 
+    def inspect
+      "#<%s:0x%x %s.include %s>" % [
+        self.class,
+        object_id,
+        parent_name, @name,
+      ]
+    end
+
   end
 
 end

Modified: MacRuby/branches/experimental/lib/rdoc/diagram.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/diagram.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/diagram.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -311,28 +311,30 @@
     # inclusion on the page
 
     def wrap_in_image_map(src, dot)
-      res = %{<map id="map" name="map">\n}
+      res = ""
       dot_map = `dot -Tismap #{src}`
-      dot_map.split($/).each do |area|
-        unless area =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) ([\/\w.]+)\s*(.*)/
-          $stderr.puts "Unexpected output from dot:\n#{area}"
-          return nil
-        end
+      
+      if(!dot_map.empty?)
+        res << %{<map id="map" name="map">\n}
+        dot_map.split($/).each do |area|
+          unless area =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) ([\/\w.]+)\s*(.*)/
+            $stderr.puts "Unexpected output from dot:\n#{area}"
+            return nil
+          end
 
-        xs, ys = [$1.to_i, $3.to_i], [$2.to_i, $4.to_i]
-        url, area_name = $5, $6
+          xs, ys = [$1.to_i, $3.to_i], [$2.to_i, $4.to_i]
+          url, area_name = $5, $6
 
-        res <<  %{  <area shape="rect" coords="#{xs.min},#{ys.min},#{xs.max},#{ys.max}" }
-        res <<  %{     href="#{url}" alt="#{area_name}" />\n}
+          res <<  %{  <area shape="rect" coords="#{xs.min},#{ys.min},#{xs.max},#{ys.max}" }
+          res <<  %{     href="#{url}" alt="#{area_name}" />\n}
+        end
+        res << "</map>\n"
       end
-      res << "</map>\n"
-#      map_file = src.sub(/.dot/, '.map')
-#      system("dot -Timap #{src} -o #{map_file}")
-      res << %{<img src="#{dot}" usemap="#map" border="0" alt="#{dot}">}
+
+      res << %{<img src="#{dot}" usemap="#map" alt="#{dot}" />}
       return res
     end
 
   end
 
 end
-

Modified: MacRuby/branches/experimental/lib/rdoc/generator/chm/chm.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/chm/chm.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/chm/chm.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,6 +6,8 @@
   HTML = RDoc::Generator::HTML::HTML
 
   INDEX = HTML::INDEX
+  
+  STYLE = HTML::STYLE
 
   CLASS_INDEX = HTML::CLASS_INDEX
   CLASS_PAGE = HTML::CLASS_PAGE

Copied: MacRuby/branches/experimental/lib/rdoc/generator/html/common.rb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/html/common.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html/common.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html/common.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,24 @@
+#
+# The templates require further refactoring.  In particular,
+# * Some kind of HTML generation library should be used.
+#
+# Also, all of the templates require some TLC from a designer.
+#
+# Right now, this file contains some constants that are used by all
+# of the templates.
+#
+module RDoc::Generator::HTML::Common
+  XHTML_STRICT_PREAMBLE = <<-EOF
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+EOF
+
+  XHTML_FRAME_PREAMBLE = <<-EOF
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+EOF
+
+  HTML_ELEMENT = <<-EOF
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+EOF
+end

Copied: MacRuby/branches/experimental/lib/rdoc/generator/html/frameless.rb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/html/frameless.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html/frameless.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html/frameless.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,92 @@
+require 'rdoc/generator/html/html'
+
+##
+# = CSS2 RDoc HTML template
+#
+# This is a template for RDoc that uses XHTML 1.0 Strict and dictates a
+# bit more of the appearance of the output to cascading stylesheets than the
+# default. It was designed for clean inline code display, and uses DHTMl to
+# toggle the visbility of each method's source with each click on the '[source]'
+# link.
+#
+# Frameless basically is the html template without frames.
+#
+# == Authors
+#
+# * Michael Granger <ged at FaerieMUD.org>
+#
+# Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved.
+#
+# This work is licensed under the Creative Commons Attribution License. To view
+# a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or
+# send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California
+# 94305, USA.
+
+module RDoc::Generator::HTML::FRAMELESS
+
+  FRAMELESS = true
+
+  FONTS = RDoc::Generator::HTML::HTML::FONTS
+
+  STYLE = RDoc::Generator::HTML::HTML::STYLE
+
+  HEADER = RDoc::Generator::HTML::HTML::HEADER
+
+  FOOTER = <<-EOF
+  <div id="popupmenu" class="index">
+    <br />
+    <h1 class="index-entries section-bar">Files</h1>
+      <ul>
+<% values["file_list"].each do |file| %>
+        <li><a href="<%= file["href"] %>"><%= file["name"] %></a></li>
+<% end %>
+      </ul>
+
+    <br />
+    <h1 class="index-entries section-bar">Classes</h1>
+      <ul>
+<% values["class_list"].each do |klass| %>
+        <li><a href="<%= klass["href"] %>"><%= klass["name"] %></a></li>
+<% end %>
+      </ul>
+
+    <br />
+    <h1 class="index-entries section-bar">Methods</h1>
+      <ul>
+<% values["method_list"].each do |method| %>
+        <li><a href="<%= method["href"] %>"><%= method["name"] %></a></li>
+<% end %>
+      </ul>
+  </div>
+</body>
+</html>
+  EOF
+
+  FILE_PAGE = RDoc::Generator::HTML::HTML::FILE_PAGE
+
+  CLASS_PAGE = RDoc::Generator::HTML::HTML::CLASS_PAGE
+
+  METHOD_LIST = RDoc::Generator::HTML::HTML::METHOD_LIST
+
+  BODY = HEADER + %{
+
+<%= template_include %>  <!-- banner header -->
+
+  <div id="bodyContent">
+
+} +  METHOD_LIST + %{
+
+  </div>
+
+} + FOOTER
+
+  SRC_PAGE = RDoc::Generator::HTML::HTML::SRC_PAGE
+
+  FR_INDEX_BODY = RDoc::Generator::HTML::HTML::FR_INDEX_BODY
+
+  FILE_INDEX = RDoc::Generator::HTML::HTML::FILE_INDEX
+
+  CLASS_INDEX = RDoc::Generator::HTML::HTML::CLASS_INDEX
+
+  METHOD_INDEX = RDoc::Generator::HTML::HTML::METHOD_INDEX
+end

Modified: MacRuby/branches/experimental/lib/rdoc/generator/html/hefss.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html/hefss.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html/hefss.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,16 +1,16 @@
 require 'rdoc/generator/html'
-require 'rdoc/generator/html/html'
+require 'rdoc/generator/html/kilmerfactory'
 
 module RDoc::Generator::HTML::HEFSS
 
   FONTS = "Verdana, Arial, Helvetica, sans-serif"
 
-STYLE = <<-EOF
-body,p { font-family: Verdana, Arial, Helvetica, sans-serif;
+  CENTRAL_STYLE = <<-EOF
+body,p { font-family: <%= values["fonts"] %>;
        color: #000040; background: #BBBBBB;
 }
 
-td { font-family: Verdana, Arial, Helvetica, sans-serif;
+td { font-family: <%= values["fonts"] %>;
        color: #000040;
 }
 
@@ -21,16 +21,20 @@
 }
 
 .big-title-font { color: white;
-                  font-family: Verdana, Arial, Helvetica, sans-serif;
+                  font-family: <%= values["fonts"] %>;
                   font-size: large;
                   height: 50px}
 
 .small-title-font { color: purple;
-                    font-family: Verdana, Arial, Helvetica, sans-serif;
+                    font-family: <%= values["fonts"] %>;
                     font-size: small; }
 
 .aqua { color: purple }
 
+#diagram img {
+  border: 0;
+}
+
 .method-name, attr-name {
       font-family: monospace; font-weight: bold;
 }
@@ -75,241 +79,6 @@
   color: #0000AA;
 }
 
-.column-title {
-  font-size: medium;
-  font-weight: bold;
-  text_decoration: none;
-  padding: 3px 3px 3px 20px;
-  color: #3333CC;
-  }
-
-.variable-name {
-  font-family: monospace;
-  font-size: medium;
-  text_decoration: none;
-  padding: 3px 3px 3px 20px;
-  color: #0000AA;
-}
-
-.row-name {
-  font-size: medium;
-  font-weight: medium;
-  font-family: monospace;
-  text_decoration: none;
-  padding: 3px 3px 3px 20px;
-}
-
-.paramsig {
-   font-size: small;
-}
-
-.srcbut { float: right }
-
-  EOF
-
-  BODY = <<-EOF
-<html><head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
-  <script type="text/javascript" language="JavaScript">
-  <!--
-  function popCode(url) {
-    parent.frames.source.location = url
-  }
-  //-->
-  </script>
-</head>
-<body bgcolor="#BBBBBB">
-
-<%= template_include %>  <!-- banner header -->
-
-<% if values["diagram"] then %>
-<table width="100%"><tr><td align="center">
-<%= values["diagram"] %>
-</td></tr></table>
-<% end %>
-
-<% if values["description"] then %>
-<div class="description"><%= values["description"] %></div>
-<% end %>
-
-<% if values["requires"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Required files</td></tr>
-</table><br />
-<div class="name-list">
-<% values["requires"].each do |requires| %>
-<%= href requires["aref"], requires["name"] %>
-<% end # values["requires"] %>
-<% end %>
-</div>
-
-<% if values["sections"] then %>
-<% values["sections"].each do |sections| %>
-<% if sections["method_list"] then %>
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Subroutines and Functions</td></tr>
-</table><br />
-<div class="name-list">
-<% method_list["methods"].each do |methods| %>
-<a href="<%= methods["codeurl"] %>" target="source"><%= methods["name"] %></a>
-<% end # values["methods"] %>
-</div>
-<% end %>
-<% end # values["method_list"] %>
-<% end %>
-
-<% if sections["attributes"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Arguments</td></tr>
-</table><br />
-<table cellspacing="5">
-<% sections["attributes"].each do |attributes| %>
-     <tr valign="top">
-<% if attributes["rw"] then %>
-       <td align="center" class="attr-rw">&nbsp;[<%= attributes["rw"] %>]&nbsp;</td>
-<% end %>
-<% unless attributes["rw"] then %>
-       <td></td>
-<% end %>
-       <td class="attr-name"><%= attributes["name"] %></td>
-       <td><%= attributes["a_desc"] %></td>
-     </tr>
-<% end # values["attributes"] %>
-</table>
-<% end %>
-<% end # values["sections"] %>
-<% end %>
-
-<% if values["classlist"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Modules</td></tr>
-</table><br />
-<%= values["classlist"] %><br />
-<% end %>
-
-  <%= template_include %>  <!-- method descriptions -->
-
-</body>
-</html>
-  EOF
-
-  FILE_PAGE = <<-EOF
-<table width="100%">
- <tr class="title-row">
- <td><table width="100%"><tr>
-   <td class="big-title-font" colspan="2"><font size="-3"><b>File</b><br /></font><%= values["short_name"] %></td>
-   <td align="right"><table cellspacing="0" cellpadding="2">
-         <tr>
-           <td  class="small-title-font">Path:</td>
-           <td class="small-title-font"><%= values["full_path"] %>
-<% if values["cvsurl"] then %>
-				&nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-           </td>
-         </tr>
-         <tr>
-           <td class="small-title-font">Modified:</td>
-           <td class="small-title-font"><%= values["dtm_modified"] %></td>
-         </tr>
-        </table>
-    </td></tr></table></td>
-  </tr>
-</table><br />
-  EOF
-
-  CLASS_PAGE = <<-EOF
-<table width="100%" border="0" cellspacing="0">
- <tr class="title-row">
- <td class="big-title-font">
-   <font size="-3"><b><%= values["classmod"] %></b><br /></font><%= values["full_name"] %>
- </td>
- <td align="right">
-   <table cellspacing="0" cellpadding="2">
-     <tr valign="top">
-      <td class="small-title-font">In:</td>
-      <td class="small-title-font">
-<% values["infiles"].each do |infiles| %>
-<%= href infiles["full_path_url"], infiles["full_path"] %>
-<% if infiles["cvsurl"] then %>
-&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-<% end # values["infiles"] %>
-      </td>
-     </tr>
-<% if values["parent"] then %>
-     <tr>
-      <td class="small-title-font">Parent:</td>
-      <td class="small-title-font">
-<% if values["par_url"] then %>
-        <a href="<%= values["par_url"] %>" class="cyan">
-<% end %>
-<%= values["parent"] %>
-<% if values["par_url"] then %>
-         </a>
-<% end %>
-      </td>
-     </tr>
-<% end %>
-   </table>
-  </td>
-  </tr>
-</table><br />
-  EOF
-
-  METHOD_LIST = <<-EOF
-<% if values["includes"] then %>
-<div class="tablesubsubtitle">Uses</div><br />
-<div class="name-list">
-<% values["includes"].each do |includes| %>
-    <span class="method-name"><%= href includes["aref"], includes["name"] %></span>
-<% end # values["includes"] %>
-</div>
-<% end %>
-
-<% if values["sections"] then %>
-<% values["sections"].each do |sections| %>
-<% if sections["method_list"] then %>
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle"><%= method_list["type"] %> <%= method_list["category"] %> methods</td></tr>
-</table>
-<% method_list["methods"].each do |methods| %>
-<table width="100%" cellspacing="0" cellpadding="5" border="0">
-<tr><td class="methodtitle">
-<a name="<%= methods["aref"] %>">
-<b><%= methods["name"] %></b><%= methods["params"] %>
-<% if methods["codeurl"] then %>
-<a href="<%= methods["codeurl"] %>" target="source" class="srclink">src</a>
-<% end %>
-</a></td></tr>
-</table>
-<% if method_list["m_desc"] then %>
-<div class="description">
-<%= method_list["m_desc"] %>
-</div>
-<% end %>
-<% end # method_list["methods"] %>
-<% end %>
-<% end # sections["method_list"] %>
-<% end %>
-<% end # values["sections"] %>
-<% end %>
-  EOF
-
-  SRC_PAGE = <<-EOF
-<html>
-<head><title><%= values["title"] %></title>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style type="text/css">
-  .kw { color: #3333FF; font-weight: bold }
-  .cmt { color: green; font-style: italic }
-  .str { color: #662222; font-style: italic }
-  .re  { color: #662222; }
 .ruby-comment    { color: green; font-style: italic }
 .ruby-constant   { color: #4433aa; font-weight: bold; }
 .ruby-identifier { color: #222222;  }
@@ -319,35 +88,23 @@
 .ruby-operator   { color: #111111;  }
 .ruby-regexp     { color: #662222; }
 .ruby-value      { color: #662222; font-style: italic }
-</style>
-</head>
-<body bgcolor="#BBBBBB">
-<pre><%= values["code"] %></pre>
-</body>
-</html>
+
+.srcbut { float: right }
   EOF
 
-  FR_INDEX_BODY = %{
-<%= template_include %>
+  INDEX_STYLE = <<-EOF
+body {
+  background-color: #bbbbbb;
+  font-family: #{FONTS};
+  font-size: 11px;
+  font-style: normal;
+  line-height: 14px;
+  color: #000040;
 }
 
-  FILE_INDEX = <<-EOF
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style type="text/css">
-<!--
-  body {
-background-color: #bbbbbb;
-     font-family: #{FONTS};
-       font-size: 11px;
-      font-style: normal;
-     line-height: 14px;
-           color: #000040;
-  }
 div.banner {
   background: #bbbbcc;
-  color:      white;
+  color: white;
   padding: 1;
   margin: 0;
   font-size: 90%;
@@ -356,59 +113,38 @@
   text-align: center;
   width: 100%;
 }
+EOF
 
--->
-</style>
-<base target="docwin">
-</head>
-<body>
-<div class="banner"><%= values["list_title"] %></div>
-<% values["entries"].each do |entries| %>
-<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
-<% end # values["entries"] %>
-</body></html>
-  EOF
+  FACTORY = RDoc::Generator::HTML::
+    KilmerFactory.new(:central_css => CENTRAL_STYLE,
+                      :index_css => INDEX_STYLE,
+                      :method_list_heading => "Subroutines and Functions",
+                      :class_and_module_list_heading => "Classes and Modules",
+                      :attribute_list_heading => "Arguments")
 
-  CLASS_INDEX = FILE_INDEX
-  METHOD_INDEX = FILE_INDEX
+  STYLE = FACTORY.get_STYLE()
 
-  INDEX = <<-EOF
-<html>
-<head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-</head>
+  METHOD_LIST = FACTORY.get_METHOD_LIST()
+  
+  BODY = FACTORY.get_BODY()
+  
+  FILE_PAGE = FACTORY.get_FILE_PAGE()
 
-<frameset cols="20%,*">
-    <frameset rows="15%,35%,50%">
-        <frame src="fr_file_index.html"   title="Files" name="Files">
-        <frame src="fr_class_index.html"  name="Modules">
-        <frame src="fr_method_index.html" name="Subroutines and Functions">
-    </frameset>
-    <frameset rows="80%,20%">
-      <frame  src="<%= values["initial_page"] %>" name="docwin">
-      <frame  src="blank.html" name="source">
-    </frameset>
-    <noframes>
-          <body bgcolor="#BBBBBB">
-            Click <a href="html/index.html">here</a> for a non-frames
-            version of this page.
-          </body>
-    </noframes>
-</frameset>
+  CLASS_PAGE = FACTORY.get_CLASS_PAGE()
 
-</html>
-  EOF
+  SRC_PAGE = FACTORY.get_SRC_PAGE()
 
-  # Blank page to use as a target
-  BLANK = %{
-<html><body bgcolor="#BBBBBB"></body></html>
-}
+  FR_INDEX_BODY = FACTORY.get_FR_INDEX_BODY()
 
-  def write_extra_pages
-    template = TemplatePage.new(BLANK)
-    File.open("blank.html", "w") { |f| template.write_html_on(f, {}) }
-  end
+  FILE_INDEX = FACTORY.get_FILE_INDEX()
 
-end
+  CLASS_INDEX = FACTORY.get_CLASS_INDEX()
 
+  METHOD_INDEX = FACTORY.get_METHOD_INDEX()
+
+  INDEX = FACTORY.get_INDEX()
+
+  def self.write_extra_pages(values)
+    FACTORY.write_extra_pages(values)
+  end
+end

Modified: MacRuby/branches/experimental/lib/rdoc/generator/html/html.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html/html.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html/html.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,56 +1,78 @@
 require 'rdoc/generator/html'
-require 'rdoc/generator/html/one_page_html'
+require 'rdoc/generator/html/common'
 
 ##
 # = CSS2 RDoc HTML template
 #
-# This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a
+# This is a template for RDoc that uses XHTML 1.0 Strict and dictates a
 # bit more of the appearance of the output to cascading stylesheets than the
 # default. It was designed for clean inline code display, and uses DHTMl to
-# toggle the visbility of each method's source with each click on the '[source]'
-# link.
+# toggle the visibility of each method's source with each click on the
+# '[source]' link.
 #
+# This template *also* forms the basis of the frameless template.
+# 
 # == Authors
 #
 # * Michael Granger <ged at FaerieMUD.org>
 #
 # Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved.
 #
-# This work is licensed under the Creative Commons Attribution License. To view
-# a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or
-# send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California
-# 94305, USA.
+# This work is licensed under the Creative Commons Attribution License. To
+# view a copy of this license, visit
+# http://creativecommons.org/licenses/by/1.0/ or send a letter to Creative
+# Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
 
 module RDoc::Generator::HTML::HTML
 
+  include RDoc::Generator::HTML::Common
+
   FONTS = "Verdana,Arial,Helvetica,sans-serif"
 
   STYLE = <<-EOF
 body {
-    font-family: Verdana,Arial,Helvetica,sans-serif;
-    font-size:   90%;
-    margin: 0;
-    margin-left: 40px;
-    padding: 0;
-    background: white;
+  font-family: #{FONTS};
+  font-size: 90%;
+  margin: 0;
+  margin-left: 40px;
+  padding: 0;
+  background: white;
+  color: black;
 }
 
-h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
-h1 { font-size: 150%; }
-h2,h3,h4 { margin-top: 1em; }
+h1, h2, h3, h4 {
+  margin: 0;
+  background: transparent;
+}
 
-a { background: #eef; color: #039; text-decoration: none; }
-a:hover { background: #039; color: #eef; }
+h1 {
+  font-size: 150%;
+}
 
+h2,h3,h4 {
+  margin-top: 1em;
+}
+
+:link, :visited {
+  background: #eef;
+  color: #039;
+  text-decoration: none;
+}
+
+:link:hover, :visited:hover {
+  background: #039;
+  color: #eef;
+}
+
 /* Override the base stylesheet's Anchor inside a table cell */
-td > a {
+td > :link, td > :visited {
   background: transparent;
   color: #039;
   text-decoration: none;
 }
 
 /* and inside a section title */
-.section-title > a {
+.section-title > :link, .section-title > :visited {
   background: transparent;
   color: #eee;
   text-decoration: none;
@@ -58,181 +80,255 @@
 
 /* === Structural elements =================================== */
 
-div#index {
-    margin: 0;
-    margin-left: -40px;
-    padding: 0;
-    font-size: 90%;
+.index {
+  margin: 0;
+  margin-left: -40px;
+  padding: 0;
+  font-size: 90%;
 }
 
-
-div#index a {
-    margin-left: 0.7em;
+.index :link, .index :visited {
+  margin-left: 0.7em;
 }
 
-div#index .section-bar {
-   margin-left: 0px;
-   padding-left: 0.7em;
-   background: #ccc;
-   font-size: small;
+.index .section-bar {
+  margin-left: 0px;
+  padding-left: 0.7em;
+  background: #ccc;
+  font-size: small;
 }
 
-
-div#classHeader, div#fileHeader {
-    width: auto;
-    color: white;
-    padding: 0.5em 1.5em 0.5em 1.5em;
-    margin: 0;
-    margin-left: -40px;
-    border-bottom: 3px solid #006;
+#classHeader, #fileHeader {
+  width: auto;
+  color: white;
+  padding: 0.5em 1.5em 0.5em 1.5em;
+  margin: 0;
+  margin-left: -40px;
+  border-bottom: 3px solid #006;
 }
 
-div#classHeader a, div#fileHeader a {
-    background: inherit;
-    color: white;
+#classHeader :link, #fileHeader :link,
+#classHeader :visited, #fileHeader :visited {
+  background: inherit;
+  color: white;
 }
 
-div#classHeader td, div#fileHeader td {
-    background: inherit;
-    color: white;
+#classHeader td, #fileHeader td {
+  background: inherit;
+  color: white;
 }
 
-
-div#fileHeader {
-    background: #057;
+#fileHeader {
+  background: #057;
 }
 
-div#classHeader {
-    background: #048;
+#classHeader {
+  background: #048;
 }
 
-
 .class-name-in-header {
   font-size:  180%;
   font-weight: bold;
 }
 
+#bodyContent {
+  padding: 0 1.5em 0 1.5em;
+}
 
-div#bodyContent {
-    padding: 0 1.5em 0 1.5em;
+#description {
+  padding: 0.5em 1.5em;
+  background: #efefef;
+  border: 1px dotted #999;
 }
 
-div#description {
-    padding: 0.5em 1.5em;
-    background: #efefef;
-    border: 1px dotted #999;
+#description h1, #description h2, #description h3,
+#description h4, #description h5, #description h6 {
+  color: #125;
+  background: transparent;
 }
 
-div#description h1,h2,h3,h4,h5,h6 {
-    color: #125;;
-    background: transparent;
+#validator-badges {
+  text-align: center;
 }
 
-div#validator-badges {
-    text-align: center;
+#validator-badges img {
+  border: 0;
 }
-div#validator-badges img { border: 0; }
 
-div#copyright {
-    color: #333;
-    background: #efefef;
-    font: 0.75em sans-serif;
-    margin-top: 5em;
-    margin-bottom: 0;
-    padding: 0.5em 2em;
+#copyright {
+  color: #333;
+  background: #efefef;
+  font: 0.75em sans-serif;
+  margin-top: 5em;
+  margin-bottom: 0;
+  padding: 0.5em 2em;
 }
 
-
 /* === Classes =================================== */
 
 table.header-table {
-    color: white;
-    font-size: small;
+  color: white;
+  font-size: small;
 }
 
 .type-note {
-    font-size: small;
-    color: #DEDEDE;
+  font-size: small;
+  color: #dedede;
 }
 
-.xxsection-bar {
-    background: #eee;
-    color: #333;
-    padding: 3px;
+.section-bar {
+  color: #333;
+  border-bottom: 1px solid #999;
+  margin-left: -20px;
 }
 
-.section-bar {
-   color: #333;
-   border-bottom: 1px solid #999;
-    margin-left: -20px;
+.section-title {
+  background: #79a;
+  color: #eee;
+  padding: 3px;
+  margin-top: 2em;
+  margin-left: -30px;
+  border: 1px solid #999;
 }
 
+.top-aligned-row {
+  vertical-align: top
+}
 
-.section-title {
-    background: #79a;
-    color: #eee;
-    padding: 3px;
-    margin-top: 2em;
-    margin-left: -30px;
-    border: 1px solid #999;
+.bottom-aligned-row {
+  vertical-align: bottom
 }
 
-.top-aligned-row {  vertical-align: top }
-.bottom-aligned-row { vertical-align: bottom }
+#diagram img {
+  border: 0;
+}
 
 /* --- Context section classes ----------------------- */
 
 .context-row { }
-.context-item-name { font-family: monospace; font-weight: bold; color: black; }
-.context-item-value { font-size: small; color: #448; }
-.context-item-desc { color: #333; padding-left: 2em; }
 
+.context-item-name {
+  font-family: monospace;
+  font-weight: bold;
+  color: black;
+}
+
+.context-item-value {
+  font-size: small;
+  color: #448;
+}
+
+.context-item-desc {
+  color: #333;
+  padding-left: 2em;
+}
+
 /* --- Method classes -------------------------- */
+
 .method-detail {
-    background: #efefef;
-    padding: 0;
-    margin-top: 0.5em;
-    margin-bottom: 1em;
-    border: 1px dotted #ccc;
+  background: #efefef;
+  padding: 0;
+  margin-top: 0.5em;
+  margin-bottom: 1em;
+  border: 1px dotted #ccc;
 }
+
 .method-heading {
   color: black;
   background: #ccc;
   border-bottom: 1px solid #666;
   padding: 0.2em 0.5em 0 0.5em;
 }
-.method-signature { color: black; background: inherit; }
-.method-name { font-weight: bold; }
-.method-args { font-style: italic; }
-.method-description { padding: 0 0.5em 0 0.5em; }
 
+.method-signature {
+  color: black;
+  background: inherit;
+}
+
+.method-name {
+  font-weight: bold;
+}
+
+.method-args {
+  font-style: italic;
+}
+
+.method-description {
+  padding: 0 0.5em 0 0.5em;
+}
+
 /* --- Source code sections -------------------- */
 
-a.source-toggle { font-size: 90%; }
+:link.source-toggle, :visited.source-toggle {
+  font-size: 90%;
+}
+
 div.method-source-code {
-    background: #262626;
-    color: #ffdead;
-    margin: 1em;
-    padding: 0.5em;
-    border: 1px dashed #999;
-    overflow: hidden;
+  background: #262626;
+  color: #ffdead;
+  margin: 1em;
+  padding: 0.5em;
+  border: 1px dashed #999;
+  overflow: auto;
 }
 
-div.method-source-code pre { color: #ffdead; overflow: hidden; }
+div.method-source-code pre {
+  color: #ffdead;
+}
 
 /* --- Ruby keyword styles --------------------- */
 
-.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
+.standalone-code {
+  background: #221111;
+  color: #ffdead;
+  overflow: auto;
+}
 
-.ruby-constant  { color: #7fffd4; background: transparent; }
-.ruby-keyword { color: #00ffff; background: transparent; }
-.ruby-ivar    { color: #eedd82; background: transparent; }
-.ruby-operator  { color: #00ffee; background: transparent; }
-.ruby-identifier { color: #ffdead; background: transparent; }
-.ruby-node    { color: #ffa07a; background: transparent; }
-.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
-.ruby-regexp  { color: #ffa07a; background: transparent; }
-.ruby-value   { color: #7fffd4; background: transparent; }
+.ruby-constant {
+  color: #7fffd4;
+  background: transparent;
+}
+
+.ruby-keyword {
+  color: #00ffff;
+  background: transparent;
+}
+
+.ruby-ivar {
+  color: #eedd82;
+  background: transparent;
+}
+
+.ruby-operator {
+  color: #00ffee;
+  background: transparent;
+}
+
+.ruby-identifier {
+  color: #ffdead;
+  background: transparent;
+}
+
+.ruby-node {
+  color: #ffa07a;
+  background: transparent;
+}
+
+.ruby-comment {
+  color: #b22222;
+  font-weight: bold;
+  background: transparent;
+}
+
+.ruby-regexp {
+  color: #ffa07a;
+  background: transparent;
+}
+
+.ruby-value {
+  color: #7fffd4;
+  background: transparent;
+}
 EOF
 
 
@@ -240,15 +336,7 @@
 ### H E A D E R   T E M P L A T E
 #####################################################################
 
-  XHTML_PREAMBLE = <<-EOF
-<?xml version="1.0" encoding="<%= values["charset"] %>"?>
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-  EOF
-
-  HEADER = XHTML_PREAMBLE + <<-EOF
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  HEADER = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
@@ -281,7 +369,7 @@
   }
 
   // Make codeblocks hidden by default
-  document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }</style>" )
+  document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }<\\/style>" )
 
   // ]]>
   </script>
@@ -291,13 +379,6 @@
 EOF
 
 #####################################################################
-### C O N T E X T   C O N T E N T   T E M P L A T E
-#####################################################################
-
-  CONTEXT_CONTENT = %{
-}
-
-#####################################################################
 ### F O O T E R   T E M P L A T E
 #####################################################################
 
@@ -361,7 +442,7 @@
         &nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
 <% end %>
         <br />
-<% end # values["infiles"] %>
+<% end %><%# values["infiles"] %>
             </td>
         </tr>
 
@@ -388,39 +469,38 @@
 #####################################################################
 
   METHOD_LIST = <<-EOF
-
   <div id="contextContent">
 <% if values["diagram"] then %>
     <div id="diagram">
       <%= values["diagram"] %>
     </div>
-<% end %>
+<% end
 
-<% if values["description"] then %>
+   if values["description"] then %>
     <div id="description">
       <%= values["description"] %>
     </div>
-<% end %>
+<% end
 
-<% if values["requires"] then %>
+   if values["requires"] then %>
     <div id="requires-list">
       <h3 class="section-bar">Required files</h3>
 
       <div class="name-list">
 <% values["requires"].each do |requires| %>
         <%= href requires["aref"], requires["name"] %>&nbsp;&nbsp;
-<% end # values["requires"] %>
+<% end %><%# values["requires"] %>
       </div>
     </div>
-<% end %>
+<% end
 
-<% if values["toc"] then %>
+   if values["toc"] then %>
     <div id="contents-list">
       <h3 class="section-bar">Contents</h3>
       <ul>
 <% values["toc"].each do |toc| %>
-      <li><a href="#<%= values["href"] %>"><%= values["secname"] %></a></li>
-<% end # values["toc"] %>
+      <li><a href="#<%= toc["href"] %>"><%= toc["secname"] %></a></li>
+<% end %><%# values["toc"] %>
      </ul>
 <% end %>
    </div>
@@ -430,16 +510,14 @@
       <h3 class="section-bar">Methods</h3>
 
       <div class="name-list">
-<% values["methods"].each do |methods| %>
+<%   values["methods"].each do |methods| %>
         <%= href methods["aref"], methods["name"] %>&nbsp;&nbsp;
-<% end # values["methods"] %>
+<%   end %><%# values["methods"] %>
       </div>
     </div>
 <% end %>
-
   </div>
 
-
     <!-- if includes -->
 <% if values["includes"] then %>
     <div id="includes">
@@ -448,140 +526,137 @@
       <div id="includes-list">
 <% values["includes"].each do |includes| %>
         <span class="include-name"><%= href includes["aref"], includes["name"] %></span>
-<% end # values["includes"] %>
+<% end %><%# values["includes"] %>
       </div>
     </div>
-<% end %>
+<% end
 
-<% values["sections"].each do |sections| %>
+   values["sections"].each do |sections| %>
     <div id="section">
-<% if sections["sectitle"] then %>
+<%   if sections["sectitle"] then %>
       <h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
-<% if sections["seccomment"] then %>
+<%     if sections["seccomment"] then %>
       <div class="section-comment">
         <%= sections["seccomment"] %>
       </div>
-<% end %>
-<% end %>
+<%     end
+     end
 
-<% if values["classlist"] then %>
+     if sections["classlist"] then %>
     <div id="class-list">
       <h3 class="section-bar">Classes and Modules</h3>
 
-      <%= values["classlist"] %>
+      <%= sections["classlist"] %>
     </div>
-<% end %>
+<%   end
 
-<% if values["constants"] then %>
+     if sections["constants"] then %>
     <div id="constants-list">
       <h3 class="section-bar">Constants</h3>
 
       <div class="name-list">
         <table summary="Constants">
-<% values["constants"].each do |constants| %>
+<%     sections["constants"].each do |constants| %>
         <tr class="top-aligned-row context-row">
           <td class="context-item-name"><%= constants["name"] %></td>
           <td>=</td>
           <td class="context-item-value"><%= constants["value"] %></td>
-<% if values["desc"] then %>
-          <td width="3em">&nbsp;</td>
+<%       if constants["desc"] then %>
+          <td>&nbsp;</td>
           <td class="context-item-desc"><%= constants["desc"] %></td>
-<% end %>
+<%       end %>
         </tr>
-<% end # values["constants"] %>
+<%     end %><%# sections["constants"] %>
         </table>
       </div>
     </div>
-<% end %>
+<%   end
 
-<% if values["aliases"] then %>
+     if sections["aliases"] then %>
     <div id="aliases-list">
       <h3 class="section-bar">External Aliases</h3>
 
       <div class="name-list">
-                        <table summary="aliases">
-<% values["aliases"].each do |aliases| $stderr.puts({ :aliases => aliases }.inspect) %>
+      <table summary="aliases">
+<%     sections["aliases"].each do |aliases| %>
         <tr class="top-aligned-row context-row">
-          <td class="context-item-name"><%= values["old_name"] %></td>
+          <td class="context-item-name"><%= aliases["old_name"] %></td>
           <td>-&gt;</td>
-          <td class="context-item-value"><%= values["new_name"] %></td>
+          <td class="context-item-value"><%= aliases["new_name"] %></td>
         </tr>
-<% if values["desc"] then %>
+<%       if aliases["desc"] then %>
       <tr class="top-aligned-row context-row">
         <td>&nbsp;</td>
-        <td colspan="2" class="context-item-desc"><%= values["desc"] %></td>
+        <td colspan="2" class="context-item-desc"><%= aliases["desc"] %></td>
       </tr>
-<% end %>
-<% end # values["aliases"] %>
+<%       end
+       end %><%# sections["aliases"] %>
         </table>
       </div>
     </div>
-<% end %>
+<%   end %>
 
-
-<% if values["attributes"] then %>
+<%   if sections["attributes"] then %>
     <div id="attribute-list">
       <h3 class="section-bar">Attributes</h3>
 
       <div class="name-list">
         <table>
-<% values["attributes"].each do |attributes| $stderr.puts({ :attributes => attributes }.inspect) %>
+<%     sections["attributes"].each do |attribute| %>
         <tr class="top-aligned-row context-row">
-          <td class="context-item-name"><%= values["name"] %></td>
-<% if values["rw"] then %>
-          <td class="context-item-value">&nbsp;[<%= values["rw"] %>]&nbsp;</td>
-<% end %>
-<% unless values["rw"] then %>
+          <td class="context-item-name"><%= attribute["name"] %></td>
+<%       if attribute["rw"] then %>
+          <td class="context-item-value">&nbsp;[<%= attribute["rw"] %>]&nbsp;</td>
+<%       end
+         unless attribute["rw"] then %>
           <td class="context-item-value">&nbsp;&nbsp;</td>
-<% end %>
-          <td class="context-item-desc"><%= values["a_desc"] %></td>
+<%       end %>
+          <td class="context-item-desc"><%= attribute["a_desc"] %></td>
         </tr>
-<% end # values["attributes"] %>
+<%     end %><%# sections["attributes"] %>
         </table>
       </div>
     </div>
-<% end %>
-      
+<%   end %>
 
-
     <!-- if method_list -->
-<% if sections["method_list"] then %>
+<%   if sections["method_list"] then %>
     <div id="methods">
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
+<%     sections["method_list"].each do |method_list|
+         if method_list["methods"] then %>
       <h3 class="section-bar"><%= method_list["type"] %> <%= method_list["category"] %> methods</h3>
 
-<% method_list["methods"].each do |methods| %>
+<%         method_list["methods"].each do |methods| %>
       <div id="method-<%= methods["aref"] %>" class="method-detail">
         <a name="<%= methods["aref"] %>"></a>
 
         <div class="method-heading">
-<% if methods["codeurl"] then %>
+<%           if methods["codeurl"] then %>
           <a href="<%= methods["codeurl"] %>" target="Code" class="method-signature"
             onclick="popupCode('<%= methods["codeurl"] %>');return false;">
-<% end %>
-<% if methods["sourcecode"] then %>
+<%           end
+             if methods["sourcecode"] then %>
           <a href="#<%= methods["aref"] %>" class="method-signature">
-<% end %>
-<% if methods["callseq"] then %>
+<%           end
+             if methods["callseq"] then %>
           <span class="method-name"><%= methods["callseq"] %></span>
-<% end %>
-<% unless methods["callseq"] then %>
+<%           end
+             unless methods["callseq"] then %>
           <span class="method-name"><%= methods["name"] %></span><span class="method-args"><%= methods["params"] %></span>
-<% end %>
-<% if methods["codeurl"] then %>
+<%           end
+             if methods["codeurl"] then %>
           </a>
-<% end %>
-<% if methods["sourcecode"] then %>
+<%           end
+             if methods["sourcecode"] then %>
           </a>
-<% end %>
+<%           end %>
         </div>
 
         <div class="method-description">
-<% if methods["m_desc"] then %>
+<%           if methods["m_desc"] then %>
           <%= methods["m_desc"] %>
-<% end %>
-<% if methods["sourcecode"] then %>
+<%           end
+               if methods["sourcecode"] then %>
           <p><a class="source-toggle" href="#"
             onclick="toggleCode('<%= methods["aref"] %>-source');return false;">[Source]</a></p>
           <div class="method-source-code" id="<%= methods["aref"] %>-source">
@@ -589,17 +664,17 @@
 <%= methods["sourcecode"] %>
 </pre>
           </div>
-<% end %>
+<%           end %>
         </div>
       </div>
 
-<% end # method_list["methods"] %>
-<% end %>
-<% end # sections["method_list"] %>
+<%         end %><%# method_list["methods"] %><%
+         end
+       end %><%# sections["method_list"] %>
 
     </div>
-<% end %>
-<% end # values["sections"] %>
+<%   end %>
+<% end %><%# values["sections"] %>
   EOF
 
 #####################################################################
@@ -622,8 +697,7 @@
 ### S O U R C E   C O D E   T E M P L A T E
 #####################################################################
 
-  SRC_PAGE = XHTML_PREAMBLE + <<-EOF
-<html>
+  SRC_PAGE = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
@@ -640,30 +714,27 @@
 ### I N D E X   F I L E   T E M P L A T E S
 #####################################################################
 
-  FR_INDEX_BODY = %{
-<%= template_include %>
-}
+  FR_INDEX_BODY = %{<%= template_include %>}
 
-  FILE_INDEX = XHTML_PREAMBLE + <<-EOF
+  FILE_INDEX = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
 <!--
 
-    <%= values["list_title"] %>
+    <%= values["title"] %>
 
   -->
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
-  <title><%= values["list_title"] %></title>
+  <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
   <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" />
   <base target="docwin" />
 </head>
 <body>
-<div id="index">
+<div class="index">
   <h1 class="section-bar"><%= values["list_title"] %></h1>
   <div id="index-entries">
 <% values["entries"].each do |entries| %>
     <a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
-<% end # values["entries"] %>
+<% end %><%#  values["entries"] %>
   </div>
 </div>
 </body>
@@ -673,18 +744,12 @@
   CLASS_INDEX = FILE_INDEX
   METHOD_INDEX = FILE_INDEX
 
-  INDEX = <<-EOF
-<?xml version="1.0" encoding="<%= values["charset"] %>"?>
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
-
+  INDEX = XHTML_FRAME_PREAMBLE + HTML_ELEMENT + <<-EOF
 <!--
 
     <%= values["title"] %>
 
   -->
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />

Modified: MacRuby/branches/experimental/lib/rdoc/generator/html/kilmer.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html/kilmer.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html/kilmer.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,10 +1,11 @@
 require 'rdoc/generator/html'
+require 'rdoc/generator/html/kilmerfactory'
 
 module RDoc::Generator::HTML::KILMER
 
   FONTS = "Verdana, Arial, Helvetica, sans-serif"
 
-  STYLE = <<-EOF
+  CENTRAL_STYLE = <<-EOF
 body,td,p { font-family: <%= values["fonts"] %>;
        color: #000040;
 }
@@ -30,6 +31,10 @@
 
 .aqua { color: black }
 
+#diagram img {
+  border: 0;
+}
+
 .method-name, .attr-name {
       font-family: font-family: <%= values["fonts"] %>;
       font-weight: bold;
@@ -67,7 +72,7 @@
   font-weight: bold;
   text-decoration: none;
   color: #000033;
-  background-color: white;
+  background: #ccc;
 }
 
 .srclink {
@@ -78,232 +83,8 @@
   background-color: white;
 }
 
-.paramsig {
-   font-size: small;
-}
-
 .srcbut { float: right }
-  EOF
 
-  BODY = <<-EOF
-<html><head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
-  <script type="text/javascript" language="JavaScript">
-  <!--
-  function popCode(url) {
-    parent.frames.source.location = url
-  }
-  //-->
-  </script>
-</head>
-<body bgcolor="white">
-
-<%= template_include %>  <!-- banner header -->
-
-<% if values["diagram"] then %>
-<table width="100%"><tr><td align="center">
-<%= values["diagram"] %>
-</td></tr></table>
-<% end %>
-
-<% if values["description"] then %>
-<div class="description"><%= values["description"] %></div>
-<% end %>
-
-<% if values["requires"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Required files</td></tr>
-</table><br />
-<div class="name-list">
-<% values["requires"].each do |requires| %>
-<%= href requires["aref"], requires["name"] %>
-<% end # values["requires"] %>
-<% end %>
-</div>
-
-<% if values["methods"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Methods</td></tr>
-</table><br />
-<div class="name-list">
-<% values["methods"].each do |methods| %>
-<%= href methods["aref"], methods["name"] %>,
-<% end # values["methods"] %>
-</div>
-<% end %>
-
-
-<% values["sections"].each do |sections| %>
-    <div id="section">
-<% if sections["sectitle"] then %>
-      <h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
-<% if sections["seccomment"] then %>
-      <div class="section-comment">
-        <%= sections["seccomment"] %>
-      </div>
-<% end %>
-<% end %>
-
-<% if sections["attributes"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Attributes</td></tr>
-</table><br />
-<table cellspacing="5">
-<% sections["attributes"].each do |attributes| %>
-     <tr valign="top">
-<% if attributes["rw"] then %>
-       <td align="center" class="attr-rw">&nbsp;[<%= attributes["rw"] %>]&nbsp;</td>
-<% end %>
-<% unless attributes["rw"] then %>
-       <td></td>
-<% end %>
-       <td class="attr-name"><%= attributes["name"] %></td>
-       <td><%= attributes["a_desc"] %></td>
-     </tr>
-<% end # sections["attributes"] %>
-</table>
-<% end %>
-
-<% if sections["classlist"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Classes and Modules</td></tr>
-</table><br />
-<%= sections["classlist"] %><br />
-<% end %>
-
-  <%= template_include %>  <!-- method descriptions -->
-
-<% end # values["sections"] %>
-
-</body>
-</html>
-  EOF
-
-  FILE_PAGE = <<-EOF
-<table width="100%">
- <tr class="title-row">
- <td><table width="100%"><tr>
-   <td class="big-title-font" colspan="2"><font size="-3"><b>File</b><br /></font><%= values["short_name"] %></td>
-   <td align="right"><table cellspacing="0" cellpadding="2">
-         <tr>
-           <td  class="small-title-font">Path:</td>
-           <td class="small-title-font"><%= values["full_path"] %>
-<% if values["cvsurl"] then %>
-				&nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-           </td>
-         </tr>
-         <tr>
-           <td class="small-title-font">Modified:</td>
-           <td class="small-title-font"><%= values["dtm_modified"] %></td>
-         </tr>
-        </table>
-    </td></tr></table></td>
-  </tr>
-</table><br />
-  EOF
-
-  CLASS_PAGE = <<-EOF
-<table width="100%" border="0" cellspacing="0">
- <tr class="title-row">
- <td class="big-title-font">
-   <font size="-3"><b><%= values["classmod"] %></b><br /></font><%= values["full_name"] %>
- </td>
- <td align="right">
-   <table cellspacing="0" cellpadding="2">
-     <tr valign="top">
-      <td class="small-title-font">In:</td>
-      <td class="small-title-font">
-<% values["infiles"].each do |infiles| %>
-<%= href infiles["full_path_url"], infiles["full_path"] %>
-<% if infiles["cvsurl"] then %>
-&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-<% end # values["infiles"] %>
-      </td>
-     </tr>
-<% if values["parent"] then %>
-     <tr>
-      <td class="small-title-font">Parent:</td>
-      <td class="small-title-font">
-<% if values["par_url"] then %>
-        <a href="<%= values["par_url"] %>" class="cyan">
-<% end %>
-<%= values["parent"] %>
-<% if values["par_url"] then %>
-         </a>
-<% end %>
-      </td>
-     </tr>
-<% end %>
-   </table>
-  </td>
-  </tr>
-</table><br />
-  EOF
-
-  METHOD_LIST = <<-EOF
-<% if values["includes"] then %>
-<div class="tablesubsubtitle">Included modules</div><br />
-<div class="name-list">
-<% values["includes"].each do |includes| %>
-    <span class="method-name"><%= href includes["aref"], includes["name"] %></span>
-<% end # values["includes"] %>
-</div>
-<% end %>
-
-<% if values["method_list"] then %>
-<% values["method_list"].each do |method_list| $stderr.puts({ :method_list => method_list }.inspect) %>
-<% if values["methods"] then %>
-<table cellpadding=5 width="100%">
-<tr><td class="tablesubtitle"><%= values["type"] %> <%= values["category"] %> methods</td></tr>
-</table>
-<% values["methods"].each do |methods| $stderr.puts({ :methods => methods }.inspect) %>
-<table width="100%" cellspacing="0" cellpadding="5" border="0">
-<tr><td class="methodtitle">
-<a name="<%= values["aref"] %>">
-<% if values["callseq"] then %>
-<b><%= values["callseq"] %></b>
-<% end %>
-<% unless values["callseq"] then %>
- <b><%= values["name"] %></b><%= values["params"] %>
-<% end %>
-<% if values["codeurl"] then %>
-<a href="<%= values["codeurl"] %>" target="source" class="srclink">src</a>
-<% end %>
-</a></td></tr>
-</table>
-<% if values["m_desc"] then %>
-<div class="description">
-<%= values["m_desc"] %>
-</div>
-<% end %>
-<% if values["aka"] then %>
-<div class="aka">
-This method is also aliased as
-<% values["aka"].each do |aka| $stderr.puts({ :aka => aka }.inspect) %>
-<a href="<%= values["aref"] %>"><%= values["name"] %></a>
-<% end # values["aka"] %>
-</div>
-<% end %>
-<% if values["sourcecode"] then %>
-<pre class="source">
-<%= values["sourcecode"] %>
-</pre>
-<% end %>
-<% end # values["methods"] %>
-<% end %>
-<% end # values["method_list"] %>
-<% end %>
-  EOF
-
-  SRC_PAGE = <<-EOF
-<html>
-<head><title><%= values["title"] %></title>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style type="text/css">
 .ruby-comment    { color: green; font-style: italic }
 .ruby-constant   { color: #4433aa; font-weight: bold; }
 .ruby-identifier { color: #222222;  }
@@ -313,28 +94,9 @@
 .ruby-operator   { color: #111111;  }
 .ruby-regexp     { color: #662222; }
 .ruby-value      { color: #662222; font-style: italic }
-  .kw { color: #3333FF; font-weight: bold }
-  .cmt { color: green; font-style: italic }
-  .str { color: #662222; font-style: italic }
-  .re  { color: #662222; }
-</style>
-</head>
-<body bgcolor="white">
-<pre><%= values["code"] %></pre>
-</body>
-</html>
   EOF
 
-  FR_INDEX_BODY = %{
-<%= template_include %>
-}
-
-  FILE_INDEX = <<-EOF
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style>
-<!--
+  INDEX_STYLE = <<-EOF
 body {
   background-color: #ddddff;
   font-family: #{FONTS};
@@ -355,64 +117,35 @@
   text-align: center;
   width: 100%;
 }
+EOF
 
--->
-</style>
-<base target="docwin">
-</head>
-<body>
-<div class="banner"><%= values["list_title"] %></div>
-<% values["entries"].each do |entries| %>
-<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
-<% end # values["entries"] %>
-</body></html>
-  EOF
+  FACTORY = RDoc::Generator::HTML::
+    KilmerFactory.new(:central_css => CENTRAL_STYLE,
+                      :index_css => INDEX_STYLE)
 
-  CLASS_INDEX = FILE_INDEX
-  METHOD_INDEX = FILE_INDEX
+  STYLE = FACTORY.get_STYLE()
 
-  INDEX = <<-EOF
-<html>
-<head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-</head>
+  METHOD_LIST = FACTORY.get_METHOD_LIST()
+  
+  BODY = FACTORY.get_BODY()
+  
+  FILE_PAGE = FACTORY.get_FILE_PAGE()
 
-<frameset cols="20%,*">
-    <frameset rows="15%,35%,50%">
-        <frame src="fr_file_index.html"   title="Files" name="Files">
-        <frame src="fr_class_index.html"  name="Classes">
-        <frame src="fr_method_index.html" name="Methods">
-    </frameset>
-<% if values["inline_source"] then %>
-      <frame  src="<%= values["initial_page"] %>" name="docwin">
-<% end %>
-<% unless values["inline_source"] then %>
-    <frameset rows="80%,20%">
-      <frame  src="<%= values["initial_page"] %>" name="docwin">
-      <frame  src="blank.html" name="source">
-    </frameset>
-<% end %>
-    <noframes>
-          <body bgcolor="white">
-            Click <a href="html/index.html">here</a> for a non-frames
-            version of this page.
-          </body>
-    </noframes>
-</frameset>
+  CLASS_PAGE = FACTORY.get_CLASS_PAGE()
 
-</html>
-  EOF
+  SRC_PAGE = FACTORY.get_SRC_PAGE()
 
-  # A blank page to use as a target
-  BLANK = %{
-<html><body bgcolor="white"></body></html>
-}
+  FR_INDEX_BODY = FACTORY.get_FR_INDEX_BODY()
 
-  def write_extra_pages
-    template = TemplatePage.new(BLANK)
-    File.open("blank.html", "w") { |f| template.write_html_on(f, {}) }
-  end
+  FILE_INDEX = FACTORY.get_FILE_INDEX()
 
-end
+  CLASS_INDEX = FACTORY.get_CLASS_INDEX()
 
+  METHOD_INDEX = FACTORY.get_METHOD_INDEX()
+
+  INDEX = FACTORY.get_INDEX()
+
+  def self.write_extra_pages(values)
+    FACTORY.write_extra_pages(values)
+  end
+end

Copied: MacRuby/branches/experimental/lib/rdoc/generator/html/kilmerfactory.rb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/html/kilmerfactory.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html/kilmerfactory.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html/kilmerfactory.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,427 @@
+require 'rdoc/generator/html'
+require 'rdoc/generator/html/common'
+
+#
+# This class generates Kilmer-style templates.  Right now,
+# rdoc is shipped with two such templates:
+# * kilmer
+# * hefss
+#
+# Kilmer-style templates use frames.  The left side of the page has
+# three frames stacked on top of each other: one lists
+# files, one lists classes, and one lists methods.  If source code
+# is not inlined, an additional frame runs across the bottom of
+# the page and will be used to display method source code.
+# The central (and largest frame) display class and file
+# pages.
+#
+# The constructor of this class accepts a Hash containing stylistic
+# attributes.  Then, a get_BLAH instance method of this class returns a
+# value for the template's BLAH constant.  get_BODY, for instance, returns
+# the value of the template's BODY constant.
+#
+class RDoc::Generator::HTML::KilmerFactory
+
+  include RDoc::Generator::HTML::Common
+
+  #
+  # The contents of the stylesheet that should be used for the
+  # central frame (for the class and file pages).
+  #
+  # This must be specified in the Hash passed to the constructor.
+  #
+  attr_reader :central_css
+
+  #
+  # The contents of the stylesheet that should be used for the
+  # index pages.
+  #
+  # This must be specified in the Hash passed to the constructor.
+  #
+  attr_reader :index_css
+
+  #
+  # The heading that should be displayed before listing methods.
+  #
+  # If not supplied, this defaults to "Methods".
+  #
+  attr_reader :method_list_heading
+
+  #
+  # The heading that should be displayed before listing classes and
+  # modules.
+  #
+  # If not supplied, this defaults to "Classes and Modules".
+  #
+  attr_reader :class_and_module_list_heading
+
+  #
+  # The heading that should be displayed before listing attributes.
+  #
+  # If not supplied, this defaults to "Attributes".
+  #
+  attr_reader :attribute_list_heading
+  
+  # 
+  # ====Description:
+  # This method constructs a KilmerFactory instance, which
+  # can be used to build Kilmer-style template classes.
+  # The +style_attributes+ argument is a Hash that contains the
+  # values of the classes attributes (Symbols mapped to Strings).
+  #
+  # ====Parameters:
+  # [style_attributes]
+  #      A Hash describing the appearance of the Kilmer-style.
+  # 
+  def initialize(style_attributes)
+    @central_css = style_attributes[:central_css]
+    if(!@central_css)
+      raise ArgumentError, "did not specify a value for :central_css"
+    end
+
+    @index_css = style_attributes[:index_css]
+    if(!@index_css)
+      raise ArgumentError, "did not specify a value for :index_css"
+    end
+
+    @method_list_heading = style_attributes[:method_list_heading]
+    if(!@method_list_heading)
+      @method_list_heading = "Methods"
+    end
+
+    @class_and_module_list_heading = style_attributes[:class_and_module_list_heading]
+    if(!@class_and_module_list_heading)
+      @class_and_module_list_heading = "Classes and Modules"
+    end
+
+    @attribute_list_heading = style_attributes[:attribute_list_heading]
+    if(!@attribute_list_heading)
+      @attribute_list_heading = "Attributes"
+    end
+  end
+
+  def get_STYLE
+    return @central_css
+  end
+  
+  def get_METHOD_LIST
+    return %{
+<% if values["diagram"] then %>
+<div id="diagram">
+<table width="100%"><tr><td align="center">
+<%= values["diagram"] %>
+</td></tr></table>
+</div>
+<% end %>
+
+<% if values["description"] then %>
+<div class="description"><%= values["description"] %></div>
+<% end %>
+
+<% if values["requires"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">Required files</td></tr>
+</table><br />
+<div class="name-list">
+<% values["requires"].each do |requires| %>
+<%= href requires["aref"], requires["name"] %>
+<% end %><%# values["requires"] %>
+</div>
+<% end %>
+
+<% if values["methods"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">#{@method_list_heading}</td></tr>
+</table><br />
+<div class="name-list">
+<% values["methods"].each do |methods| %>
+<%= href methods["aref"], methods["name"] %>,
+<% end %><%# values["methods"] %>
+</div>
+<% end %>
+
+<% if values["includes"] then %>
+<div class="tablesubsubtitle">Included modules</div><br />
+<div class="name-list">
+<% values["includes"].each do |includes| %>
+    <span class="method-name"><%= href includes["aref"], includes["name"] %></span>
+<% end %><%# values["includes"] %>
+</div>
+<% end %>
+
+<% values["sections"].each do |sections| %>
+    <div id="section">
+<% if sections["sectitle"] then %>
+      <h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
+<% if sections["seccomment"] then %>
+      <div class="section-comment">
+        <%= sections["seccomment"] %>
+      </div>
+<% end %>
+<% end %>
+<% if sections["attributes"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">#{@attribute_list_heading}</td></tr>
+</table><br />
+<table cellspacing="5">
+<% sections["attributes"].each do |attributes| %>
+     <tr valign="top">
+<% if attributes["rw"] then %>
+       <td align="center" class="attr-rw">&nbsp;[<%= attributes["rw"] %>]&nbsp;</td>
+<% end %>
+<% unless attributes["rw"] then %>
+       <td></td>
+<% end %>
+       <td class="attr-name"><%= attributes["name"] %></td>
+       <td><%= attributes["a_desc"] %></td>
+     </tr>
+<% end %><%# sections["attributes"] %>
+</table>
+<% end %>
+
+<% if sections["classlist"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">#{@class_and_module_list_heading}</td></tr>
+</table><br />
+<%= sections["classlist"] %><br />
+<% end %>
+
+<% if sections["method_list"] then %>
+<% sections["method_list"].each do |method_list| %>
+<% if method_list["methods"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle"><%= method_list["type"] %> <%= method_list["category"] %> methods</td></tr>
+</table>
+<% method_list["methods"].each do |methods| %>
+<table width="100%" cellspacing="0" cellpadding="5" border="0">
+<tr><td class="methodtitle">
+<a name="<%= methods["aref"] %>">
+<% if methods["callseq"] then %>
+<b><%= methods["callseq"] %></b>
+<% end %>
+<% unless methods["callseq"] then %>
+ <b><%= methods["name"] %></b><%= methods["params"] %>
+<% end %>
+</a>
+<% if methods["codeurl"] then %>
+<a href="<%= methods["codeurl"] %>" target="source" class="srclink">src</a>
+<% end %>
+</td></tr>
+</table>
+<% if methods["m_desc"] then %>
+<div class="description">
+<%= methods["m_desc"] %>
+</div>
+<% end %>
+<% if methods["aka"] then %>
+<div class="aka">
+This method is also aliased as
+<% methods["aka"].each do |aka| %>
+<a href="<%= methods["aref"] %>"><%= methods["name"] %></a>
+<% end %><%# methods["aka"] %>
+</div>
+<% end %>
+<% if methods["sourcecode"] then %>
+<pre class="source">
+<%= methods["sourcecode"] %>
+</pre>
+<% end %>
+<% end %><%# method_list["methods"] %>
+<% end %>
+<% end %><%# sections["method_list"] %>
+<% end %>
+
+<% end %><%# values["sections"] %>
+</div>
+}
+  end
+
+  def get_BODY
+    return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head>
+  <title><%= values["title"] %></title>
+  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
+  <script type="text/javascript">
+  <!--
+  function popCode(url) {
+    parent.frames.source.location = url
+  }
+  //-->
+  </script>
+</head>
+<body>
+<div class="bodyContent">
+<%= template_include %>  <!-- banner header -->
+
+#{get_METHOD_LIST()}
+</div>
+</body>
+</html>
+}
+  end
+
+def get_FILE_PAGE
+  return %{
+<table width="100%">
+ <tr class="title-row">
+ <td><table width="100%"><tr>
+   <td class="big-title-font" colspan="2">File<br /><%= values["short_name"] %></td>
+   <td align="right"><table cellspacing="0" cellpadding="2">
+         <tr>
+           <td class="small-title-font">Path:</td>
+           <td class="small-title-font"><%= values["full_path"] %>
+<% if values["cvsurl"] then %>
+				&nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+<% end %>
+           </td>
+         </tr>
+         <tr>
+           <td class="small-title-font">Modified:</td>
+           <td class="small-title-font"><%= values["dtm_modified"] %></td>
+         </tr>
+        </table>
+    </td></tr></table></td>
+  </tr>
+</table><br />
+}
+end
+
+def get_CLASS_PAGE
+  return %{
+<table width="100%" border="0" cellspacing="0">
+ <tr class="title-row">
+ <td class="big-title-font">
+   <%= values["classmod"] %><br /><%= values["full_name"] %>
+ </td>
+ <td align="right">
+   <table cellspacing="0" cellpadding="2">
+     <tr valign="top">
+      <td class="small-title-font">In:</td>
+      <td class="small-title-font">
+<% values["infiles"].each do |infiles| %>
+<%= href infiles["full_path_url"], infiles["full_path"] %>
+<% if infiles["cvsurl"] then %>
+&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+<% end %>
+<% end %><%# values["infiles"] %>
+      </td>
+     </tr>
+<% if values["parent"] then %>
+     <tr>
+      <td class="small-title-font">Parent:</td>
+      <td class="small-title-font">
+<% if values["par_url"] then %>
+        <a href="<%= values["par_url"] %>" class="cyan">
+<% end %>
+<%= values["parent"] %>
+<% if values["par_url"] then %>
+         </a>
+<% end %>
+      </td>
+     </tr>
+<% end %>
+   </table>
+  </td>
+  </tr>
+</table><br />
+}
+end
+
+def get_SRC_PAGE
+  return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head><title><%= values["title"] %></title>
+<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+<link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
+</head>
+<body>
+<pre><%= values["code"] %></pre>
+</body>
+</html>
+}
+end
+
+def get_FR_INDEX_BODY
+  return %{<%= template_include %>}
+end
+
+def get_FILE_INDEX
+  return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head>
+<title><%= values["title"] %></title>
+<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+<style type="text/css">
+<!--
+#{@index_css}
+-->
+</style>
+<base target="docwin" />
+</head>
+<body>
+<div class="index">
+<div class="banner"><%= values["list_title"] %></div>
+<% values["entries"].each do |entries| %>
+<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
+<% end %><%# values["entries"] %>
+</div>
+</body></html>
+}
+end
+
+def get_CLASS_INDEX
+  return get_FILE_INDEX
+end
+
+def get_METHOD_INDEX
+  return get_FILE_INDEX
+end
+
+def get_INDEX
+  return XHTML_FRAME_PREAMBLE + HTML_ELEMENT + %{
+<head>
+  <title><%= values["title"] %></title>
+  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+</head>
+
+<frameset cols="20%,*">
+    <frameset rows="15%,35%,50%">
+        <frame src="fr_file_index.html"   title="Files" name="Files" />
+        <frame src="fr_class_index.html"  name="Classes" />
+        <frame src="fr_method_index.html" name="Methods" />
+    </frameset>
+<% if values["inline_source"] then %>
+      <frame  src="<%= values["initial_page"] %>" name="docwin" />
+<% end %>
+<% unless values["inline_source"] then %>
+    <frameset rows="80%,20%">
+      <frame  src="<%= values["initial_page"] %>" name="docwin" />
+      <frame  src="blank.html" name="source" />
+    </frameset>
+<% end %>
+</frameset>
+
+</html>
+}
+end
+
+def get_BLANK
+  # This will be displayed in the source code frame before
+  # any source code has been selected.
+  return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head>
+  <title>Source Code Frame <%= values["title_suffix"] %></title>
+  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
+</head>
+<body>
+</body>
+</html>
+}
+end
+
+def write_extra_pages(values)
+  template = RDoc::TemplatePage.new(get_BLANK())
+  File.open("blank.html", "w") { |f| template.write_html_on(f, values) }
+end
+
+end

Modified: MacRuby/branches/experimental/lib/rdoc/generator/html/one_page_html.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html/one_page_html.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html/one_page_html.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,10 @@
 require 'rdoc/generator/html'
+require 'rdoc/generator/html/common'
 
 module RDoc::Generator::HTML::ONE_PAGE_HTML
 
+  include RDoc::Generator::HTML::Common
+
   CONTENTS_XML = <<-EOF
 <% if defined? classes and classes["description"] then %>
 <%= classes["description"] %>
@@ -17,7 +20,7 @@
 <% unless requires["aref"] then %>
 <li><%= requires["name"] %></li>
 <% end %>
-<% end # files["requires"] %>
+<% end %><%# files["requires"] %>
 </ul>
 <% end %>
 
@@ -31,7 +34,7 @@
 <% unless includes["aref"] then %>
 <li><%= includes["name"] %></li>
 <% end %>
-<% end # classes["includes"] %>
+<% end %><%# classes["includes"] %>
 </ul>
 <% end %>
 
@@ -42,7 +45,7 @@
 <table>
 <% sections["attributes"].each do |attributes| %>
 <tr><td><%= attributes["name"] %></td><td><%= attributes["rw"] %></td><td><%= attributes["a_desc"] %></td></tr>
-<% end # sections["attributes"] %>
+<% end %><%# sections["attributes"] %>
 </table>
 <% end %>
 
@@ -68,36 +71,34 @@
 <%= methods["sourcecode"] %>
 </pre></blockquote>
 <% end %>
-<% end # method_list["methods"] %>
+<% end %><%# method_list["methods"] %>
 <% end %>
-<% end # sections["method_list"] %>
+<% end %><%# sections["method_list"] %>
 <% end %>
-<% end # classes["sections"] %>
+<% end %><%# classes["sections"] %>
 <% end %>
   EOF
 
-  ONE_PAGE = %{
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
+  ONE_PAGE = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
 </head>
 <body>
 <% values["files"].each do |files| %>
-<h2>File: <%= files["short_name"] %></h2>
+<h2>File: <a name="<%= files["href"] %>"><%= files["short_name"] %></a></h2>
 <table>
   <tr><td>Path:</td><td><%= files["full_path"] %></td></tr>
   <tr><td>Modified:</td><td><%= files["dtm_modified"] %></td></tr>
 </table>
 } + CONTENTS_XML + %{
-<% end # values["files"] %>
+<% end %><%# values["files"] %>
 
 <% if values["classes"] then %>
 <h2>Classes</h2>
 <% values["classes"].each do |classes| %>
 <% if classes["parent"] then %>
-<h3><%= classes["classmod"] %> <%= classes["full_name"] %> &lt; <%= href classes["par_url"], classes["parent"] %></h3>
+<h3><%= classes["classmod"] %> <a name="<%= classes["href"] %>"><%= classes["full_name"] %></a> &lt; <%= href classes["par_url"], classes["parent"] %></h3>
 <% end %>
 <% unless classes["parent"] then %>
 <h3><%= classes["classmod"] %> <%= classes["full_name"] %></h3>
@@ -107,11 +108,11 @@
 (in files
 <% classes["infiles"].each do |infiles| %>
 <%= href infiles["full_path_url"], infiles["full_path"] %>
-<% end # classes["infiles"] %>
+<% end %><%# classes["infiles"] %>
 )
 <% end %>
 } + CONTENTS_XML + %{
-<% end # values["classes"] %>
+<% end %><%# values["classes"] %>
 <% end %>
 </body>
 </html>

Modified: MacRuby/branches/experimental/lib/rdoc/generator/html.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/html.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/html.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -68,7 +68,6 @@
   def initialize(options) #:not-new:
     @options = options
     load_html_template
-    @main_page_path = nil
   end
 
   ##
@@ -82,7 +81,7 @@
     @classes    = []
 
     write_style_sheet
-    gen_sub_directories()
+    gen_sub_directories
     build_indices
     generate_html
   end
@@ -94,6 +93,15 @@
   # If the template name contains a slash, use it literally
 
   def load_html_template
+    #
+    # If the template is not a path, first look for it
+    # in rdoc's HTML template directory.  Perhaps this behavior should
+    # be reversed (first try to include the template and, only if that
+    # fails, try to include it in the default template directory).
+    # One danger with reversing the behavior, however, is that
+    # if something like require 'html' could load up an
+    # unrelated file in the standard library or in a gem.
+    #
     template = @options.template
 
     unless template =~ %r{/|\\} then
@@ -101,14 +109,25 @@
                            template)
     end
 
-    require template
+    begin
+      require template
 
-    @template = self.class.const_get @options.template.upcase
-    @options.template_class = @template
+      @template = self.class.const_get @options.template.upcase
+      @options.template_class = @template
+    rescue LoadError => e
+      #
+      # The template did not exist in the default template directory, so
+      # see if require can find the template elsewhere (in a gem, for
+      # instance).
+      #
+      if(e.message[template] && template != @options.template)
+        template = @options.template
+        retry
+      end
 
-  rescue LoadError
-    $stderr.puts "Could not find HTML template '#{template}'"
-    exit 99
+      $stderr.puts "Could not find HTML template '#{template}': #{e.message}"
+      exit 99
+    end
   end
 
   ##
@@ -146,17 +165,20 @@
   end
 
   def build_indices
-    @files, @classes = RDoc::Generator::Context.build_indicies(@toplevels,
-                                                               @options)
+    @files, @classes = RDoc::Generator::Context.build_indices(@toplevels,
+                                                              @options)
   end
 
   ##
   # Generate all the HTML
 
   def generate_html
+    @main_url = main_url
+
     # the individual descriptions for files and classes
     gen_into(@files)
     gen_into(@classes)
+
     # and the index files
     gen_file_index
     gen_class_index
@@ -164,18 +186,52 @@
     gen_main_index
 
     # this method is defined in the template file
-    write_extra_pages if defined? write_extra_pages
+    values = {
+      'title_suffix' => CGI.escapeHTML("[#{@options.title}]"),
+      'charset'      => @options.charset,
+      'style_url'    => style_url('', @options.css),
+    }
+
+    @template.write_extra_pages(values) if @template.respond_to?(:write_extra_pages)
   end
 
   def gen_into(list)
+    #
+    # The file, class, and method lists technically should be regenerated
+    # for every output file, in order that the relative links be correct
+    # (we are worried here about frameless templates, which need this
+    # information for every generated page).  Doing this is a bit slow,
+    # however.  For a medium-sized gem, this increased rdoc's runtime by
+    # about 5% (using the 'time' command-line utility).  While this is not
+    # necessarily a problem, I do not want to pessimize rdoc for large
+    # projects, however, and so we only regenerate the lists when the
+    # directory of the output file changes, which seems like a reasonable
+    # optimization.
+    #
+    file_list = {}
+    class_list = {}
+    method_list = {}
+    prev_op_dir = nil
+
     list.each do |item|
-      if item.document_self
-        op_file = item.path
-        FileUtils.mkdir_p(File.dirname(op_file))
-        open(op_file, "w") { |file| item.write_on(file) }
+      next unless item.document_self
+
+      op_file = item.path
+      op_dir = File.dirname(op_file)
+
+      if(op_dir != prev_op_dir)
+        file_list = index_to_links op_file, @files
+        class_list = index_to_links op_file, @classes
+        method_list = index_to_links op_file, RDoc::Generator::Method.all_methods
       end
+      prev_op_dir = op_dir
+
+      FileUtils.mkdir_p op_dir
+
+      open op_file, 'w' do |io|
+        item.write_on io, file_list, class_list, method_list
+      end
     end
-
   end
 
   def gen_file_index
@@ -203,8 +259,9 @@
 
     values = {
       "entries"    => res,
+      'title'      => CGI.escapeHTML("#{title} [#{@options.title}]"),
       'list_title' => CGI.escapeHTML(title),
-      'index_url'  => main_url,
+      'index_url'  => @main_url,
       'charset'    => @options.charset,
       'style_url'  => style_url('', @options.css),
     }
@@ -221,54 +278,105 @@
   # line.
 
   def gen_main_index
-    template = RDoc::TemplatePage.new @template::INDEX
+    if @template.const_defined? :FRAMELESS then
+      #
+      # If we're using a template without frames, then just redirect
+      # to it from index.html.
+      #
+      # One alternative to this, expanding the main page's template into
+      # index.html, is tricky because the relative URLs will be different
+      # (since index.html is located in at the site's root,
+      # rather than within a files or a classes subdirectory).
+      #
+      open 'index.html', 'w'  do |f|
+        f.puts(%{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">})
+        f.puts(%{<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+                lang="en">})
+        f.puts(%{<head>})
+        f.puts(%{<title>#{CGI.escapeHTML(@options.title)}</title>})
+        f.puts(%{<meta http-equiv="refresh" content="0; url=#{@main_url}" />})
+        f.puts(%{</head>})
+        f.puts(%{<body></body>})
+        f.puts(%{</html>})
+      end
+    else
+      main = RDoc::TemplatePage.new @template::INDEX
 
-    open 'index.html', 'w'  do |f|
-      classes = @classes.sort.map { |klass| klass.value_hash }
+      open 'index.html', 'w'  do |f|
+        style_url = style_url '', @options.css
+        
+        classes = @classes.sort.map { |klass| klass.value_hash }
+        
+        values = {
+          'initial_page'  => @main_url,
+          'style_url'     => style_url('', @options.css),
+          'title'         => CGI.escapeHTML(@options.title),
+          'charset'       => @options.charset,
+          'classes'       => classes,
+        }
+        
+        values['inline_source'] = @options.inline_source
 
-      values = {
-        'main_page'     => @main_page,
-        'initial_page'  => main_url,
-        'style_url'     => style_url('', @options.css),
-        'title'         => CGI.escapeHTML(@options.title),
-        'charset'       => @options.charset,
-        'classes'       => classes,
-      }
-
-      values['inline_source'] = @options.inline_source
-
-      template.write_html_on f, values
+        main.write_html_on f, values
+      end
     end
   end
 
+  def index_to_links(output_path, collection)
+    collection.sort.map do |f|
+      next unless f.document_self
+      { "href" => RDoc::Markup::ToHtml.gen_relative_url(output_path, f.path),
+        "name" => f.index_name }
+    end.compact
+  end
+
   ##
   # Returns the url of the main page
 
   def main_url
-    @main_page = @options.main_page
-    @main_page_ref = nil
-    if @main_page
-      @main_page_ref = RDoc::Generator::AllReferences[@main_page]
-      if @main_page_ref then
-        @main_page_path = @main_page_ref.path
+    main_page = @options.main_page
+
+    #
+    # If a main page has been specified (--main), then search for it
+    # in the AllReferences array.  This allows either files or classes
+    # to be used for the main page.
+    #
+    if main_page then
+      main_page_ref = RDoc::Generator::AllReferences[main_page]
+
+      if main_page_ref then
+        return main_page_ref.path
       else
-        $stderr.puts "Could not find main page #{@main_page}"
+        $stderr.puts "Could not find main page #{main_page}"
       end
     end
 
-    unless @main_page_path then
-      file = @files.find { |context| context.document_self }
-      @main_page_path = file.path if file
+    #
+    # No main page has been specified, so just use the README.
+    #
+    @files.each do |file|
+      if file.name =~ /^README/ then
+        return file.path
+      end
     end
 
-    unless @main_page_path then
-      $stderr.puts "Couldn't find anything to document"
-      $stderr.puts "Perhaps you've used :stopdoc: in all classes"
-      exit 1
+    #
+    # There's no README (shame! shame!).  Just use the first file
+    # that will be documented.
+    #
+    @files.each do |file|
+      if file.document_self then
+        return file.path
+      end
     end
 
-    @main_page_path
+    #
+    # There are no files to be documented...  Something seems very wrong.
+    #
+    raise RDoc::Error, "Couldn't find anything to document (perhaps :stopdoc: has been used in all classes)!"
   end
+  private :main_url
 
 end
 
@@ -314,12 +422,9 @@
       'charset' => @options.charset,
       'files'   => gen_into(@files),
       'classes' => gen_into(@classes),
-      'title'        => CGI.escapeHTML(@options.title),
+      'title'   => CGI.escapeHTML(@options.title),
     }
 
-    # this method is defined in the template file
-    write_extra_pages if defined? write_extra_pages
-
     template = RDoc::TemplatePage.new @template::ONE_PAGE
 
     if @options.op_name
@@ -337,34 +442,4 @@
     end
     res
   end
-
-  def gen_file_index
-    gen_an_index(@files, 'Files')
-  end
-
-  def gen_class_index
-    gen_an_index(@classes, 'Classes')
-  end
-
-  def gen_method_index
-    gen_an_index(RDoc::Generator::Method.all_methods, 'Methods')
-  end
-
-  def gen_an_index(collection, title)
-    res = []
-    collection.sort.each do |f|
-      if f.document_self
-        res << { "href" => f.path, "name" => f.index_name }
-      end
-    end
-
-    return {
-      "entries" => res,
-      'list_title' => title,
-      'index_url'  => main_url,
-    }
-  end
-
 end
-
-

Modified: MacRuby/branches/experimental/lib/rdoc/generator/ri.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/ri.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/ri.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -16,12 +16,8 @@
     new(options)
   end
 
-  class << self
-    protected :new
-  end
-
   ##
-  # Set up a new RDoc::Generator::RI.
+  # Set up a new ri generator
 
   def initialize(options) #:not-new:
     @options   = options
@@ -45,18 +41,19 @@
   def process_class(from_class)
     generate_class_info(from_class)
 
-    # now recure into this classes constituent classess
+    # now recurse into this class' constituent classes
     from_class.each_classmodule do |mod|
       process_class(mod)
     end
   end
 
   def generate_class_info(cls)
-    if cls === RDoc::NormalModule
+    case cls
+    when RDoc::NormalModule then
       cls_desc = RDoc::RI::ModuleDescription.new
     else
       cls_desc = RDoc::RI::ClassDescription.new
-      cls_desc.superclass  = cls.superclass
+      cls_desc.superclass = cls.superclass
     end
 
     cls_desc.name        = cls.name

Deleted: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/class.texinfo.erb
===================================================================
--- MacRuby/trunk/lib/rdoc/generator/texinfo/class.texinfo.erb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/class.texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,44 +0,0 @@
- at node <%= @v['class']['full_name'].gsub(/::/, '-') %>
- at chapter <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %>
-
-<% if @v['class']["parent"] and @v['class']['par_url'] %>
-Inherits <%= href @v['class']["par_url"], @v['class']["parent"] %><% end %>
-
-<%= @v['class']["description"] %>
-
-<% if @v['class']["includes"] %>
-Includes
-<%   @v['class']["includes"].each do |include| %>
-* <%=  href include["aref"], include["name"] %>
-<%   end # @v['class']["includes"] %>
-<% end %>
-
-<% if @v['class']["sections"] %>
-<%   @v['class']["sections"].each do |section| %>
-<%     if section["attributes"] %>
-Attributes
-<%       section["attributes"].each do |attributes| %>
-* <%=      attributes["name"] %> <%= attributes["rw"] %> <%= attributes["a_desc"] %>
-<%       end # section["attributes"] %>
-<%     end %>
-<%   end %>
-
-<%   @v['class']["sections"].each do |section| %>
-<%     if section["method_list"] %>
-Methods
- at menu
-<%     section["method_list"].each_with_index do |method_list, i| %>
-<%= i %>
-<%       (method_list["methods"] || []).each do |method| %>
-* <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix method_list %><%= method['name'] %>::<% end %>
-<% end %>
- at end menu
-
-<%     section["method_list"].each do |method_list| %>
-<%       (method_list["methods"] || []).uniq.each do |method| %>
-<%=        TexinfoTemplate.new(@v.merge({'method' => method, 'list' => method_list}),
-                               'method.texinfo.erb').render %><% end %>
-<%       end %>
-<%     end # if section["method_list"] %>
-<% end # @v['class']["sections"] %>
-<% end %>

Copied: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/class.texinfo.erb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/texinfo/class.texinfo.erb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/texinfo/class.texinfo.erb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/class.texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,44 @@
+ at node <%= @v['class']['full_name'].gsub(/::/, '-') %>
+ at chapter <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %>
+
+<% if @v['class']["parent"] and @v['class']['par_url'] %>
+Inherits <%= href @v['class']["par_url"], @v['class']["parent"] %><% end %>
+
+<%= @v['class']["description"] %>
+
+<% if @v['class']["includes"] %>
+Includes
+<%   @v['class']["includes"].each do |include| %>
+* <%=  href include["aref"], include["name"] %>
+<%   end # @v['class']["includes"] %>
+<% end %>
+
+<% if @v['class']["sections"] %>
+<%   @v['class']["sections"].each do |section| %>
+<%     if section["attributes"] %>
+Attributes
+<%       section["attributes"].each do |attributes| %>
+* <%=      attributes["name"] %> <%= attributes["rw"] %> <%= attributes["a_desc"] %>
+<%       end # section["attributes"] %>
+<%     end %>
+<%   end %>
+
+<%   @v['class']["sections"].each do |section| %>
+<%     if section["method_list"] %>
+Methods
+ at menu
+<%     section["method_list"].each_with_index do |method_list, i| %>
+<%= i %>
+<%       (method_list["methods"] || []).each do |method| %>
+* <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix method_list %><%= method['name'] %>::<% end %>
+<% end %>
+ at end menu
+
+<%     section["method_list"].each do |method_list| %>
+<%       (method_list["methods"] || []).uniq.each do |method| %>
+<%=        TexinfoTemplate.new(@v.merge({'method' => method, 'list' => method_list}),
+                               'method.texinfo.erb').render %><% end %>
+<%       end %>
+<%     end # if section["method_list"] %>
+<% end # @v['class']["sections"] %>
+<% end %>

Deleted: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/file.texinfo.erb
===================================================================
--- MacRuby/trunk/lib/rdoc/generator/texinfo/file.texinfo.erb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/file.texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,6 +0,0 @@
-<% if false %>
-<h2>File: <%= @v['file']["short_name"] %></h2>
-Path: <%= @v['file']["full_path"] %>
-
-<%= TexinfoTemplate.new(@v, 'content.texinfo.erb').render %>
-<% end %>

Copied: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/file.texinfo.erb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/texinfo/file.texinfo.erb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/texinfo/file.texinfo.erb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/file.texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,6 @@
+<% if false %>
+<h2>File: <%= @v['file']["short_name"] %></h2>
+Path: <%= @v['file']["full_path"] %>
+
+<%= TexinfoTemplate.new(@v, 'content.texinfo.erb').render %>
+<% end %>

Deleted: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/method.texinfo.erb
===================================================================
--- MacRuby/trunk/lib/rdoc/generator/texinfo/method.texinfo.erb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/method.texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,6 +0,0 @@
- at node <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
- at section <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
-<%= @v['method']["type"] %> <%= @v['method']["category"] %> method:
-<%= target @v['method']["aref"], @v['method']['callseq'] ||
-                                 @v['method']["name"] + @v['method']["params"] %>
-<%= @v['method']["m_desc"] %>

Copied: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/method.texinfo.erb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/texinfo/method.texinfo.erb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/texinfo/method.texinfo.erb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/method.texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,6 @@
+ at node <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
+ at section <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
+<%= @v['method']["type"] %> <%= @v['method']["category"] %> method:
+<%= target @v['method']["aref"], @v['method']['callseq'] ||
+                                 @v['method']["name"] + @v['method']["params"] %>
+<%= @v['method']["m_desc"] %>

Deleted: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/texinfo.erb
===================================================================
--- MacRuby/trunk/lib/rdoc/generator/texinfo/texinfo.erb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,28 +0,0 @@
-\input texinfo   @c -*-texinfo-*-
- at c %**start of header
- at setfilename <%= @v['filename'] %>
- at settitle <%= @v['title'] %>
- at c %**end of header
-
- at contents @c TODO: whitespace is a mess... =\
-
- at ifnottex
- at node Top
-
- at top <%= @v['title'] %>
- at end ifnottex
-
-<% if @f = @v['files'].detect { |f| f.name =~ /Readme/i }  %>
-<%= @f.values['description'] %><% end %>
-
- at menu
-<% @v['classes'].each do |klass| %>
-* <%= klass.name.gsub(/::/, '-') %>::<% end %>
- at c TODO: add files
- at end menu
-
-<% (@v['classes'] || []).each_with_index do |klass, i| %>
-<%= TexinfoTemplate.new(@v.merge('class' => klass.values), 
-                        'class.texinfo.erb').render %><% end %>
-
- at bye

Copied: MacRuby/branches/experimental/lib/rdoc/generator/texinfo/texinfo.erb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/texinfo/texinfo.erb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/texinfo/texinfo.erb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo/texinfo.erb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,28 @@
+\input texinfo   @c -*-texinfo-*-
+ at c %**start of header
+ at setfilename <%= @v['filename'] %>
+ at settitle <%= @v['title'] %>
+ at c %**end of header
+
+ at contents @c TODO: whitespace is a mess... =\
+
+ at ifnottex
+ at node Top
+
+ at top <%= @v['title'] %>
+ at end ifnottex
+
+<% if @f = @v['files'].detect { |f| f.name =~ /Readme/i }  %>
+<%= @f.values['description'] %><% end %>
+
+ at menu
+<% @v['classes'].each do |klass| %>
+* <%= klass.name.gsub(/::/, '-') %>::<% end %>
+ at c TODO: add files
+ at end menu
+
+<% (@v['classes'] || []).each_with_index do |klass, i| %>
+<%= TexinfoTemplate.new(@v.merge('class' => klass.values), 
+                        'class.texinfo.erb').render %><% end %>
+
+ at bye

Copied: MacRuby/branches/experimental/lib/rdoc/generator/texinfo.rb (from rev 1886, MacRuby/trunk/lib/rdoc/generator/texinfo.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/texinfo.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/generator/texinfo.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,81 @@
+require 'rdoc/rdoc'
+require 'rdoc/generator'
+require 'rdoc/markup/to_texinfo'
+
+module RDoc
+  module Generator
+    # This generates Texinfo files for viewing with GNU Info or Emacs
+    # from RDoc extracted from Ruby source files.
+    class TEXINFO
+      # What should the .info file be named by default?
+      DEFAULT_INFO_FILENAME = 'rdoc.info'
+
+      include Generator::MarkUp
+
+      # Accept some options
+      def initialize(options)
+        @options = options
+        @options.inline_source = true
+        @options.op_name ||= 'rdoc.texinfo'
+        @options.formatter = ::RDoc::Markup::ToTexInfo.new
+      end
+
+      # Generate the +texinfo+ files
+      def generate(toplevels)
+        @toplevels = toplevels
+        @files, @classes = ::RDoc::Generator::Context.build_indices(@toplevels,
+                                                                    @options)
+
+        (@files + @classes).each { |x| x.value_hash }
+
+        open(@options.op_name, 'w') do |f|
+          f.puts TexinfoTemplate.new('files' => @files,
+                                     'classes' => @classes,
+                                     'filename' => @options.op_name.gsub(/texinfo/, 'info'),
+                                     'title' => @options.title).render
+        end
+        # TODO: create info files and install?
+      end
+
+      class << self
+        # Factory? We don't need no stinkin' factory!
+        alias_method :for, :new
+      end
+    end
+
+    # Basically just a wrapper around ERB.
+    # Should probably use RDoc::TemplatePage instead
+    class TexinfoTemplate
+      BASE_DIR = ::File.expand_path(::File.dirname(__FILE__)) # have to calculate this when the file's loaded.
+
+      def initialize(values, file = 'texinfo.erb')
+        @v, @file = [values, file]
+      end
+     
+      def template
+        ::File.read(::File.join(BASE_DIR, 'texinfo', @file))
+      end
+
+      # Go!
+      def render
+        ERB.new(template).result binding
+      end
+
+      def href(location, text)
+        text # TODO: how does texinfo do hyperlinks?
+      end
+
+      def target(name, text)
+        text # TODO: how do hyperlink targets work?
+      end
+
+      # TODO: this is probably implemented elsewhere?
+      def method_prefix(section)
+        { 'Class' => '.',
+          'Module' => '::',
+          'Instance' => '#',
+        }[section['category']]
+      end
+    end
+  end
+end

Modified: MacRuby/branches/experimental/lib/rdoc/generator/xml/xml.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/xml/xml.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/xml/xml.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -17,11 +17,23 @@
                         href="<%= requires["aref"] %>"
 <% end %>
          />
-<% end # files["requires"] %>
+<% end %><%# files["requires"] %>
       </required-file-list>
 <% end %>
 <% if defined? classes and classes["sections"] then %>
 <% classes["sections"].each do |sections| %>
+<% if sections["constants"] then %>
+      <constant-list>
+<% sections["constants"].each do |constant| %>
+        <constant name="<%= constant["name"] %>">
+<% if constant["value"] then %>
+          <value><%= constant["value"] %></value>
+<% end %>
+          <description><%= constant["a_desc"] %></description>
+        </constant>
+<% end %><%# sections["constants"] %>
+      </constant-list>
+<% end %>
 <% if sections["attributes"] then %>
       <attribute-list>
 <% sections["attributes"].each do |attributes| %>
@@ -31,7 +43,7 @@
 <% end %>
           <description><%= attributes["a_desc"] %></description>
         </attribute>
-<% end # sections["attributes"] %>
+<% end %><%# sections["attributes"] %>
       </attribute-list>
 <% end %>
 <% if sections["method_list"] then %>
@@ -52,12 +64,12 @@
           </source-code-listing>
 <% end %>
         </method>
-<% end # method_list["methods"] %>
+<% end %><%# method_list["methods"] %>
 <% end %>
-<% end # sections["method_list"] %>
+<% end %><%# sections["method_list"] %>
       </method-list>
 <% end %>
-<% end # classes["sections"] %>
+<% end %><%# classes["sections"] %>
 <% end %>
 <% if defined? classes and classes["includes"] then %>
       <included-module-list>
@@ -67,7 +79,7 @@
                          href="<%= includes["aref"] %>"
 <% end %>
         />
-<% end # classes["includes"] %>
+<% end %><%# classes["includes"] %>
       </included-module-list>
 <% end %>
     </contents>
@@ -84,7 +96,7 @@
     </file-info>
 } + CONTENTS_XML + %{
   </file>
-<% end # values["files"] %>
+<% end %><%# values["files"] %>
 </file-list>
 <class-module-list>
 <% values["classes"].each do |classes| %>
@@ -94,7 +106,7 @@
       <infiles>
 <% classes["infiles"].each do |infiles|  %>
         <infile><%= href infiles["full_path_url"], infiles["full_path"] %></infile>
-<% end # classes["infiles"] %>
+<% end %><%# classes["infiles"] %>
       </infiles>
 <% end %>
 <% if classes["parent"] then %>
@@ -103,7 +115,7 @@
     </classmod-info>
 } + CONTENTS_XML + %{
   </<%= classes["classmod"] %>>
-<% end # values["classes"] %>
+<% end %><%# values["classes"] %>
 </class-module-list>
 </rdoc>
 }

Modified: MacRuby/branches/experimental/lib/rdoc/generator/xml.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator/xml.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator/xml.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -34,15 +34,15 @@
   ##
   # Generate:
   #
-  # * a list of HtmlFile objects for each TopLevel object.
-  # * a list of HtmlClass objects for each first level
+  # * a list of File objects for each TopLevel object.
+  # * a list of Class objects for each first level
   #   class or module in the TopLevel objects
   # * a complete list of all hyperlinkable terms (file,
   #   class, module, and method names)
 
   def build_indices
     @info.each do |toplevel|
-      @files << RDoc::Generator::HtmlFile.new(toplevel, @options, RDoc::Generator::FILE_DIR)
+      @files << RDoc::Generator::File.new(toplevel, @options, RDoc::Generator::FILE_DIR)
     end
 
     RDoc::TopLevel.all_classes_and_modules.each do |cls|
@@ -51,7 +51,7 @@
   end
 
   def build_class_list(from, html_file, class_dir)
-    @classes << RDoc::Generator::HtmlClass.new(from, html_file, class_dir, @options)
+    @classes << RDoc::Generator::Class.new(from, html_file, class_dir, @options)
     from.each_classmodule do |mod|
       build_class_list(mod, html_file, class_dir)
     end
@@ -68,9 +68,6 @@
       'classes' => gen_into(@classes)
     }
 
-    # this method is defined in the template file
-    write_extra_pages if defined? write_extra_pages
-
     template = RDoc::TemplatePage.new @template::ONE_PAGE
 
     if @options.op_name

Modified: MacRuby/branches/experimental/lib/rdoc/generator.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/generator.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/generator.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -7,12 +7,12 @@
 module RDoc::Generator
 
   ##
-  # Name of sub-direcory that holds file descriptions
+  # Name of sub-directory that holds file descriptions
 
   FILE_DIR  = "files"
 
   ##
-  # Name of sub-direcory that holds class descriptions
+  # Name of sub-directory that holds class descriptions
 
   CLASS_DIR = "classes"
 
@@ -22,27 +22,6 @@
   CSS_NAME  = "rdoc-style.css"
 
   ##
-  # Converts a target url to one that is relative to a given path
-
-  def self.gen_url(path, target)
-    from          = ::File.dirname path
-    to, to_file   = ::File.split target
-
-    from = from.split "/"
-    to   = to.split "/"
-
-    while from.size > 0 and to.size > 0 and from[0] == to[0] do
-      from.shift
-      to.shift
-    end
-
-    from.fill ".."
-    from.concat to
-    from << to_file
-    ::File.join(*from)
-  end
-
-  ##
   # Build a hash of all items that can be cross-referenced.  This is used when
   # we output required and included names: if the names appear in this hash,
   # we can generate an html cross reference to the appropriate description.
@@ -80,11 +59,6 @@
     def markup(str, remove_para = false)
       return '' unless str
 
-      unless defined? @formatter then
-        @formatter = RDoc::Markup::ToHtmlCrossref.new(path, self,
-                                                       @options.show_hash)
-      end
-
       # Convert leading comment markers to spaces, but only if all non-blank
       # lines have them
       if str =~ /^(?>\s*)[^\#]/ then
@@ -93,7 +67,7 @@
         content = str.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }
       end
 
-      res = @formatter.convert content
+      res = formatter.convert content
 
       if remove_para then
         res.sub!(/^<p>/, '')
@@ -114,7 +88,7 @@
       if %r{^(https?:/)?/} =~ css_name
         css_name
       else
-        RDoc::Generator.gen_url path, css_name
+        RDoc::Markup::ToHtml.gen_relative_url path, css_name
       end
     end
 
@@ -153,7 +127,7 @@
     # * a complete list of all hyperlinkable terms (file, class, module, and
     #   method names)
 
-    def self.build_indicies(toplevels, options)
+    def self.build_indices(toplevels, options)
       files = []
       classes = []
 
@@ -186,6 +160,11 @@
       @template = options.template_class
     end
 
+    def formatter
+      @formatter ||= @options.formatter ||
+        RDoc::Markup::ToHtmlCrossref.new(path, self, @options.show_hash)
+    end
+
     ##
     # convenience method to build a hyperlink
 
@@ -201,7 +180,7 @@
       if @options.all_one_file
         "#" + path
       else
-        RDoc::Generator.gen_url from_path, path
+        RDoc::Markup::ToHtml.gen_relative_url from_path, path
       end
     end
 
@@ -215,7 +194,7 @@
       list = @context.method_list
 
       unless @options.show_all then
-        list = list.find_all do |m|
+        list = list.select do |m|
           m.visibility == :public or
             m.visibility == :protected or
             m.force_documentation
@@ -230,17 +209,15 @@
     ##
     # Build a summary list of all the methods in this context
 
-    def build_method_summary_list(path_prefix="")
+    def build_method_summary_list(path_prefix = "")
       collect_methods unless @methods
-      meths = @methods.sort
-      res = []
-      meths.each do |meth|
-        res << {
+
+      @methods.sort.map do |meth|
+        {
           "name" => CGI.escapeHTML(meth.name),
-          "aref" => "#{path_prefix}\##{meth.aref}"
+          "aref" => "##{meth.aref}"
         }
       end
-      res
     end
 
     ##
@@ -248,36 +225,40 @@
     # corresponding method
 
     def build_alias_summary_list(section)
-      values = []
-      @context.aliases.each do |al|
+      @context.aliases.map do |al|
         next unless al.section == section
+
         res = {
           'old_name' => al.old_name,
           'new_name' => al.new_name,
         }
-        if al.comment && !al.comment.empty?
-          res['desc'] = markup(al.comment, true)
+
+        if al.comment and not al.comment.empty? then
+          res['desc'] = markup al.comment, true
         end
-        values << res
-      end
-      values
+
+        res
+      end.compact
     end
 
     ##
     # Build a list of constants
 
     def build_constants_summary_list(section)
-      values = []
-      @context.constants.each do |co|
+      @context.constants.map do |co|
         next unless co.section == section
+
         res = {
           'name'  => co.name,
           'value' => CGI.escapeHTML(co.value)
         }
-        res['desc'] = markup(co.comment, true) if co.comment && !co.comment.empty?
-        values << res
-      end
-      values
+
+        if co.comment and not co.comment.empty? then
+          res['desc'] = markup co.comment, true
+        end
+
+        res
+      end.compact
     end
 
     def build_requires_list(context)
@@ -339,54 +320,58 @@
     def build_method_detail_list(section)
       outer = []
 
-      methods = @methods.sort
+      methods = @methods.sort.select do |m|
+        m.document_self and m.section == section
+      end
+
       for singleton in [true, false]
         for vis in [ :public, :protected, :private ]
           res = []
           methods.each do |m|
-            if m.section == section and
-                m.document_self and
-                m.visibility == vis and
-                m.singleton == singleton
-              row = {}
-              if m.call_seq
-                row["callseq"] = m.call_seq.gsub(/->/, '&rarr;')
-              else
-                row["name"]        = CGI.escapeHTML(m.name)
-                row["params"]      = m.params
-              end
-              desc = m.description.strip
-              row["m_desc"]      = desc unless desc.empty?
-              row["aref"]        = m.aref
-              row["visibility"]  = m.visibility.to_s
+            next unless m.visibility == vis and m.singleton == singleton
 
-              alias_names = []
-              m.aliases.each do |other|
-                if other.viewer   # won't be if the alias is private
-                  alias_names << {
-                    'name' => other.name,
-                    'aref'  => other.viewer.as_href(path)
-                  }
-                end
+            row = {}
+
+            if m.call_seq then
+              row["callseq"] = m.call_seq.gsub(/->/, '&rarr;')
+            else
+              row["name"]        = CGI.escapeHTML(m.name)
+              row["params"]      = m.params
+            end
+
+            desc = m.description.strip
+            row["m_desc"]      = desc unless desc.empty?
+            row["aref"]        = m.aref
+            row["visibility"]  = m.visibility.to_s
+
+            alias_names = []
+
+            m.aliases.each do |other|
+              if other.viewer then # won't be if the alias is private
+                alias_names << {
+                  'name' => other.name,
+                  'aref'  => other.viewer.as_href(path)
+                }
               end
-              unless alias_names.empty?
-                row["aka"] = alias_names
-              end
+            end
 
-              if @options.inline_source
-                code = m.source_code
-                row["sourcecode"] = code if code
-              else
-                code = m.src_url
-                if code
-                  row["codeurl"] = code
-                  row["imgurl"]  = m.img_url
-                end
+            row["aka"] = alias_names unless alias_names.empty?
+
+            if @options.inline_source then
+              code = m.source_code
+              row["sourcecode"] = code if code
+            else
+              code = m.src_url
+              if code then
+                row["codeurl"] = code
+                row["imgurl"]  = m.img_url
               end
-              res << row
             end
+
+            res << row
           end
-          if res.size > 0
+
+          if res.size > 0 then
             outer << {
               "type"     => vis.to_s.capitalize,
               "category" => singleton ? "Class" : "Instance",
@@ -395,6 +380,7 @@
           end
         end
       end
+
       outer
     end
 
@@ -403,8 +389,8 @@
     # in this context.
 
     def build_class_list(level, from, section, infile=nil)
-      res = ""
-      prefix = "&nbsp;&nbsp;::" * level;
+      prefix = '&nbsp;&nbsp;::' * level;
+      res = ''
 
       from.modules.sort.each do |mod|
         next unless mod.section == section
@@ -412,8 +398,8 @@
         if mod.document_self
           res <<
             prefix <<
-            "Module " <<
-            href(url(mod.viewer.path), "link", mod.full_name) <<
+            'Module ' <<
+            href(url(mod.viewer.path), 'link', mod.full_name) <<
             "<br />\n" <<
             build_class_list(level + 1, mod, section, infile)
         end
@@ -421,12 +407,13 @@
 
       from.classes.sort.each do |cls|
         next unless cls.section == section
-        next if infile && !cls.defined_in?(infile)
+        next if infile and not cls.defined_in?(infile)
+
         if cls.document_self
-          res      <<
+          res <<
             prefix <<
-            "Class " <<
-            href(url(cls.viewer.path), "link", cls.full_name) <<
+            'Class ' <<
+            href(url(cls.viewer.path), 'link', cls.full_name) <<
             "<br />\n" <<
             build_class_list(level + 1, cls, section, infile)
         end
@@ -436,7 +423,7 @@
     end
 
     def url(target)
-      RDoc::Generator.gen_url path, target
+      RDoc::Markup::ToHtml.gen_relative_url path, target
     end
 
     def aref_to(target)
@@ -475,7 +462,7 @@
     def add_table_of_sections
       toc = []
       @context.sections.each do |section|
-        if section.title
+        if section.title then
           toc << {
             'secname' => section.title,
             'href'    => section.sequence
@@ -495,12 +482,14 @@
 
     attr_reader :methods
     attr_reader :path
+    attr_reader :values
 
     def initialize(context, html_file, prefix, options)
-      super(context, options)
+      super context, options
 
       @html_file = html_file
-      @is_module = context.is_module?
+      @html_class = self
+      @is_module = context.module?
       @values    = {}
 
       context.viewer = self
@@ -540,11 +529,19 @@
       name
     end
 
-    def write_on(f)
+    def write_on(f, file_list, class_list, method_list, overrides = {})
       value_hash
+
+      @values['file_list'] = file_list
+      @values['class_list'] = class_list
+      @values['method_list'] = method_list
+
+      @values.update overrides
+
       template = RDoc::TemplatePage.new(@template::BODY,
                                         @template::CLASS_PAGE,
                                         @template::METHOD_LIST)
+
       template.write_html_on(f, @values)
     end
 
@@ -561,30 +558,29 @@
       ml = build_method_summary_list @path
       @values["methods"] = ml unless ml.empty?
 
-      il = build_include_list(@context)
+      il = build_include_list @context
       @values["includes"] = il unless il.empty?
 
       @values["sections"] = @context.sections.map do |section|
-
         secdata = {
           "sectitle" => section.title,
           "secsequence" => section.sequence,
-          "seccomment" => markup(section.comment)
+          "seccomment" => markup(section.comment),
         }
 
-        al = build_alias_summary_list(section)
+        al = build_alias_summary_list section
         secdata["aliases"] = al unless al.empty?
 
-        co = build_constants_summary_list(section)
+        co = build_constants_summary_list section
         secdata["constants"] = co unless co.empty?
 
-        al = build_attribute_list(section)
+        al = build_attribute_list section
         secdata["attributes"] = al unless al.empty?
 
-        cl = build_class_list(0, @context, section)
+        cl = build_class_list 0, @context, section
         secdata["classlist"] = cl unless cl.empty?
 
-        mdl = build_method_detail_list(section)
+        mdl = build_method_detail_list section
         secdata["method_list"] = mdl unless mdl.empty?
 
         secdata
@@ -594,43 +590,45 @@
     end
 
     def build_attribute_list(section)
-      atts = @context.attributes.sort
-      res = []
-      atts.each do |att|
+      @context.attributes.sort.map do |att|
         next unless att.section == section
-        if att.visibility == :public || att.visibility == :protected || @options.show_all
+
+        if att.visibility == :public or att.visibility == :protected or
+           @options.show_all then
+
           entry = {
             "name"   => CGI.escapeHTML(att.name),
             "rw"     => att.rw,
             "a_desc" => markup(att.comment, true)
           }
-          unless att.visibility == :public || att.visibility == :protected
+
+          unless att.visibility == :public or att.visibility == :protected then
             entry["rw"] << "-"
           end
-          res << entry
+
+          entry
         end
-      end
-      res
+      end.compact
     end
 
     def class_attribute_values
       h_name = CGI.escapeHTML(name)
 
-      @values["path"]      = @path
+      @values["href"]      = @path
       @values["classmod"]  = @is_module ? "Module" : "Class"
-      @values["title"]     = "#{@values['classmod']}: #{h_name}"
+      @values["title"]     = "#{@values['classmod']}: #{h_name} [#{@options.title}]"
 
       c = @context
-      c = c.parent while c and !c.diagram
-      if c && c.diagram
+      c = c.parent while c and not c.diagram
+
+      if c and c.diagram then
         @values["diagram"] = diagram_reference(c.diagram)
       end
 
       @values["full_name"] = h_name
 
-      parent_class = @context.superclass
-
-      if parent_class
+      if not @context.module? and @context.superclass then
+        parent_class = @context.superclass
         @values["parent"] = CGI.escapeHTML(parent_class)
 
         if parent_name
@@ -680,9 +678,10 @@
 
     attr_reader :path
     attr_reader :name
+    attr_reader :values
 
     def initialize(context, options, file_dir)
-      super(context, options)
+      super context, options
 
       @values = {}
 
@@ -705,7 +704,7 @@
 
     def filename_to_label
       @context.file_relative_name.gsub(/%|\/|\?|\#/) do
-        '%%%x' % $&[0].unpack('C')
+        ('%%%x' % $&[0]).unpack('C')
       end
     end
 
@@ -755,7 +754,7 @@
         }
 
         cl = build_class_list(0, @context, section, file_context)
-        @values["classlist"] = cl unless cl.empty?
+        secdata["classlist"] = cl unless cl.empty?
 
         mdl = build_method_detail_list(section)
         secdata["method_list"] = mdl unless mdl.empty?
@@ -764,7 +763,7 @@
         secdata["aliases"] = al unless al.empty?
 
         co = build_constants_summary_list(section)
-        @values["constants"] = co unless co.empty?
+        secdata["constants"] = co unless co.empty?
 
         secdata
       end
@@ -772,9 +771,15 @@
       @values
     end
 
-    def write_on(f)
+    def write_on(f, file_list, class_list, method_list, overrides = {})
       value_hash
 
+      @values['file_list'] = file_list
+      @values['class_list'] = class_list
+      @values['method_list'] = method_list
+
+      @values.update overrides
+
       template = RDoc::TemplatePage.new(@template::BODY,
                                         @template::FILE_PAGE,
                                         @template::METHOD_LIST)
@@ -786,7 +791,7 @@
       full_path = @context.file_absolute_name
       short_name = ::File.basename full_path
 
-      @values["title"] = CGI.escapeHTML("File: #{short_name}")
+      @values["title"] = CGI.escapeHTML("File: #{short_name} [#{@options.title}]")
 
       if @context.diagram then
         @values["diagram"] = diagram_reference(@context.diagram)
@@ -816,28 +821,30 @@
     attr_reader :img_url
     attr_reader :source_code
 
-    @@seq = "M000000"
-
-    @@all_methods = []
-
     def self.all_methods
       @@all_methods
     end
 
     def self.reset
       @@all_methods = []
+      @@seq = "M000000"
     end
 
+    # Initialize the class variables.
+    self.reset
+
     def initialize(context, html_class, options)
+      # TODO: rethink the class hierarchy here...
       @context    = context
       @html_class = html_class
       @options    = options
 
+      @@seq       = @@seq.succ
+      @seq        = @@seq
+
       # HACK ugly
       @template = options.template_class
 
-      @@seq       = @@seq.succ
-      @seq        = @@seq
       @@all_methods << self
 
       context.viewer = self
@@ -846,7 +853,7 @@
         @source_code = markup_code(ts)
         unless @options.inline_source
           @src_url = create_source_code_file(@source_code)
-          @img_url = RDoc::Generator.gen_url path, 'source.png'
+          @img_url = RDoc::Markup::ToHtml.gen_relative_url path, 'source.png'
         end
       end
 
@@ -861,10 +868,32 @@
       if @options.all_one_file
         "#" + path
       else
-        RDoc::Generator.gen_url from_path, path
+        RDoc::Markup::ToHtml.gen_relative_url from_path, path
       end
     end
 
+    def formatter
+      @formatter ||= @options.formatter ||
+        RDoc::Markup::ToHtmlCrossref.new(path, self, @options.show_hash)
+    end
+
+    def inspect
+      alias_for = if @context.is_alias_for then
+                    " (alias_for #{@context.is_alias_for})"
+                  else
+                    nil
+                  end
+
+      "#<%s:0x%x %s%s%s (%s)%s>" % [
+        self.class, object_id,
+        @context.parent.name,
+        @context.singleton ? '::' : '#',
+        name,
+        @context.visibility,
+        alias_for
+      ]
+    end
+
     def name
       @context.name
     end
@@ -961,7 +990,7 @@
         template.write_html_on(f, values)
       end
 
-      RDoc::Generator.gen_url path, file_path
+      RDoc::Markup::ToHtml.gen_relative_url path, file_path
     end
 
     def <=>(other)
@@ -976,19 +1005,18 @@
       src = ""
       tokens.each do |t|
         next unless t
-        #    p t.class
 #        style = STYLE_MAP[t.class]
         style = case t
-                when RubyToken::TkCONSTANT then "ruby-constant"
-                when RubyToken::TkKW       then "ruby-keyword kw"
-                when RubyToken::TkIVAR     then "ruby-ivar"
-                when RubyToken::TkOp       then "ruby-operator"
-                when RubyToken::TkId       then "ruby-identifier"
-                when RubyToken::TkNode     then "ruby-node"
-                when RubyToken::TkCOMMENT  then "ruby-comment cmt"
-                when RubyToken::TkREGEXP   then "ruby-regexp re"
-                when RubyToken::TkSTRING   then "ruby-value str"
-                when RubyToken::TkVal      then "ruby-value"
+                when RDoc::RubyToken::TkCONSTANT then "ruby-constant"
+                when RDoc::RubyToken::TkKW       then "ruby-keyword kw"
+                when RDoc::RubyToken::TkIVAR     then "ruby-ivar"
+                when RDoc::RubyToken::TkOp       then "ruby-operator"
+                when RDoc::RubyToken::TkId       then "ruby-identifier"
+                when RDoc::RubyToken::TkNode     then "ruby-node"
+                when RDoc::RubyToken::TkCOMMENT  then "ruby-comment cmt"
+                when RDoc::RubyToken::TkREGEXP   then "ruby-regexp re"
+                when RDoc::RubyToken::TkSTRING   then "ruby-value str"
+                when RDoc::RubyToken::TkVal      then "ruby-value"
                 else
                     nil
                 end
@@ -1015,12 +1043,18 @@
         first = $1.to_i - 1
         last  = first + src.count("\n")
         size = last.to_s.length
-        real_fmt = "%#{size}d: "
-        fmt = " " * (size+2)
+        fmt = "%#{size}d: "
+        is_first_line = true
+        line_num = first
         src.gsub!(/^/) do
-          res = sprintf(fmt, first)
-          first += 1
-          fmt = real_fmt
+          if is_first_line then
+            is_first_line = false
+            res = " " * (size+2)
+          else
+            res = sprintf(fmt, line_num)
+          end
+
+          line_num += 1
           res
         end
       end

Copied: MacRuby/branches/experimental/lib/rdoc/known_classes.rb (from rev 1886, MacRuby/trunk/lib/rdoc/known_classes.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/known_classes.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/known_classes.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,68 @@
+module RDoc
+
+  ##
+  # Ruby's built-in classes, modules and exceptions
+
+  KNOWN_CLASSES = {
+    "rb_cArray"            => "Array",
+    "rb_cBignum"           => "Bignum",
+    "rb_cClass"            => "Class",
+    "rb_cData"             => "Data",
+    "rb_cDir"              => "Dir",
+    "rb_cFalseClass"       => "FalseClass",
+    "rb_cFile"             => "File",
+    "rb_cFixnum"           => "Fixnum",
+    "rb_cFloat"            => "Float",
+    "rb_cHash"             => "Hash",
+    "rb_cIO"               => "IO",
+    "rb_cInteger"          => "Integer",
+    "rb_cModule"           => "Module",
+    "rb_cNilClass"         => "NilClass",
+    "rb_cNumeric"          => "Numeric",
+    "rb_cObject"           => "Object",
+    "rb_cProc"             => "Proc",
+    "rb_cRange"            => "Range",
+    "rb_cRegexp"           => "Regexp",
+    "rb_cRubyVM"           => "RubyVM",
+    "rb_cString"           => "String",
+    "rb_cStruct"           => "Struct",
+    "rb_cSymbol"           => "Symbol",
+    "rb_cThread"           => "Thread",
+    "rb_cTime"             => "Time",
+    "rb_cTrueClass"        => "TrueClass",
+
+    "rb_eArgError"         => "ArgError",
+    "rb_eEOFError"         => "EOFError",
+    "rb_eException"        => "Exception",
+    "rb_eFatal"            => "Fatal",
+    "rb_eFloatDomainError" => "FloatDomainError",
+    "rb_eIOError"          => "IOError",
+    "rb_eIndexError"       => "IndexError",
+    "rb_eInterrupt"        => "Interrupt",
+    "rb_eLoadError"        => "LoadError",
+    "rb_eNameError"        => "NameError",
+    "rb_eNoMemError"       => "NoMemError",
+    "rb_eNotImpError"      => "NotImpError",
+    "rb_eRangeError"       => "RangeError",
+    "rb_eRuntimeError"     => "RuntimeError",
+    "rb_eScriptError"      => "ScriptError",
+    "rb_eSecurityError"    => "SecurityError",
+    "rb_eSignal"           => "Signal",
+    "rb_eStandardError"    => "StandardError",
+    "rb_eSyntaxError"      => "SyntaxError",
+    "rb_eSystemCallError"  => "SystemCallError",
+    "rb_eSystemExit"       => "SystemExit",
+    "rb_eTypeError"        => "TypeError",
+    "rb_eZeroDivError"     => "ZeroDivError",
+
+    "rb_mComparable"       => "Comparable",
+    "rb_mEnumerable"       => "Enumerable",
+    "rb_mErrno"            => "Errno",
+    "rb_mFileTest"         => "FileTest",
+    "rb_mGC"               => "GC",
+    "rb_mKernel"           => "Kernel",
+    "rb_mMath"             => "Math",
+    "rb_mProcess"          => "Process"
+  }
+
+end

Modified: MacRuby/branches/experimental/lib/rdoc/markup/attribute_manager.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/attribute_manager.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup/attribute_manager.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -64,7 +64,8 @@
 
   def copy_string(start_pos, end_pos)
     res = @str[start_pos...end_pos]
-    res.gsub!(/\000/, '')
+    # XXX this doesn't work in MacRuby yet
+    #res.gsub!(/\000/, '')
     res
   end
 
@@ -131,7 +132,8 @@
   end
 
   def unmask_protected_sequences
-    @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000")
+    #@str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000")
+    @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1")
   end
 
   def initialize
@@ -144,8 +146,6 @@
     add_html("b",  :BOLD)
     add_html("tt",   :TT)
     add_html("code", :TT)
-
-    add_special(/<!--(.*?)-->/, :COMMENT)
   end
 
   def add_word_pair(start, stop, name)
@@ -176,21 +176,16 @@
   def flow(str)
     @str = str
 
-    puts("Before flow, str='#{@str.dump}'") if $DEBUG_RDOC
     mask_protected_sequences
 
     @attrs = RDoc::Markup::AttrSpan.new @str.length
 
-    puts("After protecting, str='#{@str.dump}'") if $DEBUG_RDOC
-
     convert_attrs(@str, @attrs)
     convert_html(@str, @attrs)
     convert_specials(str, @attrs)
 
     unmask_protected_sequences
 
-    puts("After flow, str='#{@str.dump}'") if $DEBUG_RDOC
-
     return split_into_flow
   end
 
@@ -217,8 +212,6 @@
   end
 
   def split_into_flow
-    display_attributes if $DEBUG_RDOC
-
     res = []
     current_attr = 0
     str = ""

Modified: MacRuby/branches/experimental/lib/rdoc/markup/fragments.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/fragments.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup/fragments.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -11,7 +11,7 @@
     attr_reader   :level, :param, :txt
     attr_accessor :type
 
-    ######
+    ##
     # This is a simple factory system that lets us associate fragement
     # types (a string) with a subclass of fragment
 

Modified: MacRuby/branches/experimental/lib/rdoc/markup/inline.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/inline.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup/inline.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -47,7 +47,7 @@
 
   class AttrChanger
     def to_s
-      "Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}"
+      "Attr: +#{Attribute.as_string(turn_on)}/-#{Attribute.as_string(turn_on)}"
     end
   end
 

Modified: MacRuby/branches/experimental/lib/rdoc/markup/lines.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/lines.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup/lines.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -44,7 +44,8 @@
       @deleted = false
 
       # expand tabs
-      1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)}  && $~ #`
+      #1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)}  && $~ #`
+      @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)}
 
       # Strip trailing whitespace
       @text.sub!(/\s+$/, '')

Modified: MacRuby/branches/experimental/lib/rdoc/markup/preprocess.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/preprocess.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup/preprocess.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -14,21 +14,25 @@
 
   ##
   # Look for common options in a chunk of text. Options that we don't handle
-  # are passed back to our caller as |directive, param|
+  # are yielded to the caller.
 
   def handle(text)
-    text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
+    text.gsub!(/^([ \t]*#?[ \t]*):(\w+):([ \t]*)(.+)?\n/) do
+      next $& if $3.empty? and $4 and $4[0, 1] == ':'
+
       prefix    = $1
       directive = $2.downcase
-      param     = $3
+      param     = $4
 
       case directive
-      when "include"
+      when 'include' then
         filename = param.split[0]
-        include_file(filename, prefix)
+        include_file filename, prefix
 
       else
-        yield(directive, param)
+        result = yield directive, param
+        result = "#{prefix}:#{directive}: #{param}\n" unless result
+        result
       end
     end
   end

Modified: MacRuby/branches/experimental/lib/rdoc/markup/to_html.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/to_html.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup/to_html.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,6 @@
 require 'rdoc/markup/formatter'
 require 'rdoc/markup/fragments'
 require 'rdoc/markup/inline'
-require 'rdoc/generator'
 
 require 'cgi'
 
@@ -21,6 +20,11 @@
   def initialize
     super
 
+    # @in_tt - tt nested levels count
+    # @tt_bit - cache
+    @in_tt = 0
+    @tt_bit = RDoc::Markup::Attribute.bitmap_for :TT
+
     # external hyperlinks
     @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
 
@@ -31,8 +35,29 @@
   end
 
   ##
+  # Converts a target url to one that is relative to a given path
+
+  def self.gen_relative_url(path, target)
+    from        = File.dirname path
+    to, to_file = File.split target
+
+    from = from.split "/"
+    to   = to.split "/"
+
+    while from.size > 0 and to.size > 0 and from[0] == to[0] do
+      from.shift
+      to.shift
+    end
+
+    from.fill ".."
+    from.concat to
+    from << to_file
+    File.join(*from)
+  end
+
+  ##
   # Generate a hyperlink for url, labeled with text. Handle the
-  # special cases for img: and link: described under handle_special_HYPEDLINK
+  # special cases for img: and link: described under handle_special_HYPERLINK
 
   def gen_url(url, text)
     if url =~ /([A-Za-z]+):(.*)/ then
@@ -48,7 +73,7 @@
       url = if path[0, 1] == '#' then # is this meaningful?
               path
             else
-              RDoc::Generator.gen_url @from_path, path
+              self.class.gen_relative_url @from_path, path
             end
     end
 
@@ -88,6 +113,20 @@
   end
 
   ##
+  # are we currently inside <tt> tags?
+
+  def in_tt?
+    @in_tt > 0
+  end
+
+  ##
+  # is +tag+ a <tt> tag?
+
+  def tt?(tag)
+    tag.bit == @tt_bit
+  end
+
+  ##
   # Set up the standard mapping of attributes to HTML tags
 
   def init_tags
@@ -216,6 +255,7 @@
     @attr_tags.each do |tag|
       if attr_mask & tag.bit != 0
         res << annotate(tag.on)
+        @in_tt += 1 if tt?(tag)
       end
     end
   end
@@ -226,6 +266,7 @@
 
     @attr_tags.reverse_each do |tag|
       if attr_mask & tag.bit != 0
+        @in_tt -= 1 if tt?(tag)
         res << annotate(tag.off)
       end
     end
@@ -251,37 +292,45 @@
     res
   end
 
+  def convert_string(item)
+    in_tt? ? convert_string_simple(item) : convert_string_fancy(item)
+  end
+
+  def convert_string_simple(item)
+    CGI.escapeHTML item
+  end
+
   ##
   # some of these patterns are taken from SmartyPants...
 
-  def convert_string(item)
-    CGI.escapeHTML(item).
+  def convert_string_fancy(item)
+    # convert ampersand before doing anything else
+    item.gsub(/&/, '&amp;').
 
     # convert -- to em-dash, (-- to en-dash)
       gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
-
+      
     # convert ... to elipsis (and make sure .... becomes .<elipsis>)
       gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
 
     # convert single closing quote
-      gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1&#8217;').
+      gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1&#8217;'). # }
       gsub(%r{\'(?=\W|s\b)}, '&#8217;').
 
     # convert single opening quote
       gsub(/'/, '&#8216;').
 
     # convert double closing quote
-      gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}, '\1&#8221;').
+      gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}, '\1&#8221;'). # }
 
     # convert double opening quote
-      gsub(/'/, '&#8220;').
+      gsub(/"/, '&#8220;').
 
     # convert copyright
       gsub(/\(c\)/, '&#169;').
 
-    # convert and registered trademark
+    # convert registered trademark
       gsub(/\(r\)/, '&#174;')
-
   end
 
   def convert_special(special)

Modified: MacRuby/branches/experimental/lib/rdoc/markup/to_html_crossref.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/to_html_crossref.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup/to_html_crossref.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -9,25 +9,77 @@
 
   attr_accessor :context
 
+  # Regular expressions to match class and method references.
+  # 
+  # 1.) There can be a '\' in front of text to suppress
+  #     any cross-references (note, however, that the single '\'
+  #     is written as '\\\\' in order to escape it twice, once
+  #     in the Ruby String literal and once in the regexp).
+  # 2.) There can be a '::' in front of class names to reference
+  #     from the top-level namespace.
+  # 3.) The method can be followed by parenthesis,
+  #     which may or may not have things inside (this
+  #     apparently is allowed for Fortran 95, but I also think that this
+  #     is a good idea for Ruby, as it is very reasonable to want to
+  #     reference a call with arguments).
+  #
+  # NOTE: In order to support Fortran 95 properly, the [A-Z] below
+  # should be changed to [A-Za-z].  This slows down rdoc significantly,
+  # however, and the Fortran 95 support is broken in any case due to
+  # the return in handle_special_CROSSREF if the token consists
+  # entirely of lowercase letters.
+  #
+  # The markup/cross-referencing engine needs a rewrite for
+  # Fortran 95 to be supported properly.
+  CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)'
+  METHOD_REGEXP_STR = '(\w+[!?=]?)(?:\([\.\w+\*\/\+\-\=\<\>]*\))?'
+
+  # Regular expressions matching text that should potentially have
+  # cross-reference links generated are passed to add_special.
+  # Note that these expressions are meant to pick up text for which
+  # cross-references have been suppressed, since the suppression
+  # characters are removed by the code that is triggered.
+  CROSSREF_REGEXP = /(
+                      # A::B::C.meth
+                      #{CLASS_REGEXP_STR}[\.\#]#{METHOD_REGEXP_STR}
+
+                      # Stand-alone method (proceeded by a #)
+                      | \\?\##{METHOD_REGEXP_STR}
+
+                      # A::B::C
+                      # The stuff after CLASS_REGEXP_STR is a
+                      # nasty hack.  CLASS_REGEXP_STR unfortunately matches
+                      # words like dog and cat (these are legal "class"
+                      # names in Fortran 95).  When a word is flagged as a
+                      # potential cross-reference, limitations in the markup
+                      # engine suppress other processing, such as typesetting.
+                      # This is particularly noticeable for contractions.
+                      # In order that words like "can't" not
+                      # be flagged as potential cross-references, only
+                      # flag potential class cross-references if the character
+                      # after the cross-referece is a space or sentence
+                      # punctuation.
+                      | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;]|\z)
+
+                      # Things that look like filenames
+                      # The key thing is that there must be at least
+                      # one special character (period, slash, or
+                      # underscore).
+                      | [\/\w]+[_\/\.][\w\/\.]+
+
+                      # Things that have markup suppressed
+                      | \\[^\s]
+                      )/x
+
   ##
   # We need to record the html path of our caller so we can generate
   # correct relative paths for any hyperlinks that we find
 
   def initialize(from_path, context, show_hash)
+    raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
     super()
 
-    # class names, variable names, or instance variables
-    @markup.add_special(/(
-                           # A::B.meth(**) (for operator in Fortran95)
-                           \w+(::\w+)*[.\#]\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?
-                           # meth(**) (for operator in Fortran95)
-                         | \#\w+(\([.\w\*\/\+\-\=\<\>]+\))?
-                         | \b([A-Z]\w*(::\w+)*[.\#]\w+)  #    A::B.meth
-                         | \b([A-Z]\w+(::\w+)*)          #    A::B
-                         | \#\w+[!?=]?                   #    #meth_name
-                         | \\?\b\w+([_\/\.]+\w+)*[!?=]?  #    meth_name
-                         )/x,
-                        :CROSSREF)
+    @markup.add_special(CROSSREF_REGEXP, :CROSSREF)
 
     @from_path = from_path
     @context = context
@@ -47,28 +99,39 @@
   def handle_special_CROSSREF(special)
     name = special.text
 
+    # This ensures that words entirely consisting of lowercase letters will
+    # not have cross-references generated (to suppress lots of
+    # erroneous cross-references to "new" in text, for instance)
+    return name if name =~ /\A[a-z]*\z/
+
     return @seen[name] if @seen.include? name
 
-    if name[0,1] == '#' then
+    if name[0, 1] == '#' then
       lookup = name[1..-1]
       name = lookup unless @show_hash
     else
       lookup = name
     end
 
+
     # Find class, module, or method in class or module.
-    if /([A-Z]\w*)[.\#](\w+[!?=]?)/ =~ lookup then
+    #
+    # Do not, however, use an if/elsif/else chain to do so.  Instead, test
+    # each possible pattern until one matches.  The reason for this is that a
+    # string like "YAML.txt" could be the txt() class method of class YAML (in
+    # which case it would match the first pattern, which splits the string
+    # into container and method components and looks up both) or a filename
+    # (in which case it would match the last pattern, which just checks
+    # whether the string as a whole is a known symbol).
+
+    if /#{CLASS_REGEXP_STR}[\.\#]#{METHOD_REGEXP_STR}/ =~ lookup then
       container = $1
       method = $2
       ref = @context.find_symbol container, method
-    elsif /([A-Za-z]\w*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup then
-      container = $1
-      method = $2
-      ref = @context.find_symbol container, method
-    else
-      ref = @context.find_symbol lookup
     end
 
+    ref = @context.find_symbol lookup unless ref
+
     out = if lookup =~ /^\\/ then
             $'
           elsif ref and ref.document_self then
@@ -83,4 +146,3 @@
   end
 
 end
-

Copied: MacRuby/branches/experimental/lib/rdoc/markup/to_texinfo.rb (from rev 1886, MacRuby/trunk/lib/rdoc/markup/to_texinfo.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup/to_texinfo.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/markup/to_texinfo.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,69 @@
+require 'rdoc/markup/formatter'
+require 'rdoc/markup/fragments'
+require 'rdoc/markup/inline'
+
+require 'rdoc/markup'
+require 'rdoc/markup/formatter'
+
+##
+# Convert SimpleMarkup to basic TexInfo format
+#
+# TODO: WTF is AttributeManager for?
+#
+class RDoc::Markup::ToTexInfo < RDoc::Markup::Formatter
+
+  def start_accepting
+    @text = []
+  end
+
+  def end_accepting
+    @text.join("\n")
+  end
+
+  def accept_paragraph(attributes, text)
+    @text << format(text)
+  end
+
+  def accept_verbatim(attributes, text)
+    @text << "@verb{|#{format(text)}|}"
+  end
+
+  def accept_heading(attributes, text)
+    heading = ['@majorheading', '@chapheading'][text.head_level - 1] || '@heading'
+    @text << "#{heading} #{format(text)}"
+  end
+
+  def accept_list_start(attributes, text)
+    @text << '@itemize @bullet'
+  end
+
+  def accept_list_end(attributes, text)
+    @text << '@end itemize'
+  end
+
+  def accept_list_item(attributes, text)
+    @text << "@item\n#{format(text)}"
+  end
+
+  def accept_blank_line(attributes, text)
+    @text << "\n"
+  end
+
+  def accept_rule(attributes, text)
+    @text << '-----'
+  end
+
+  def format(text)
+    text.txt.
+      gsub(/@/, "@@").
+      gsub(/\{/, "@{").
+      gsub(/\}/, "@}").
+      # gsub(/,/, "@,"). # technically only required in cross-refs
+      gsub(/\+([\w]+)\+/, "@code{\\1}").
+      gsub(/\<tt\>([^<]+)\<\/tt\>/, "@code{\\1}").
+      gsub(/\*([\w]+)\*/, "@strong{\\1}").
+      gsub(/\<b\>([^<]+)\<\/b\>/, "@strong{\\1}").
+      gsub(/_([\w]+)_/, "@emph{\\1}").
+      gsub(/\<em\>([^<]+)\<\/em\>/, "@emph{\\1}")
+  end
+end

Modified: MacRuby/branches/experimental/lib/rdoc/markup.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/markup.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/markup.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -17,104 +17,9 @@
 # RDoc::Markup is intended to be the basis for a family of tools which share
 # the common requirement that simple, plain-text should be rendered in a
 # variety of different output formats and media.  It is envisaged that
-# RDoc::Markup could be the basis for formating RDoc style comment blocks,
+# RDoc::Markup could be the basis for formatting RDoc style comment blocks,
 # Wiki entries, and online FAQs.
 #
-# = Basic Formatting
-#
-# * RDoc::Markup looks for a document's natural left margin.  This is
-#   used as the initial margin for the document.
-#
-# * Consecutive lines starting at this margin are considered to be a
-#   paragraph.
-#
-# * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
-#   taken to be the start of a list.  The margin in increased to be the first
-#   non-space following the list start flag.  Subsequent lines should be
-#   indented to this \new margin until the list ends.  For example:
-#
-#      * this is a list with three paragraphs in
-#        the first item.  This is the first paragraph.
-#
-#        And this is the second paragraph.
-#
-#        1. This is an indented, numbered list.
-#        2. This is the second item in that list
-#
-#        This is the third conventional paragraph in the
-#        first list item.
-#
-#      * This is the second item in the original list
-#
-# * You can also construct labeled lists, sometimes called description
-#   or definition lists.  Do this by putting the label in square brackets
-#   and indenting the list body:
-#
-#       [cat]  a small furry mammal
-#              that seems to sleep a lot
-#
-#       [ant]  a little insect that is known
-#              to enjoy picnics
-#
-#   A minor variation on labeled lists uses two colons to separate the
-#   label from the list body:
-#
-#       cat::  a small furry mammal
-#              that seems to sleep a lot
-#
-#       ant::  a little insect that is known
-#              to enjoy picnics
-#
-#   This latter style guarantees that the list bodies' left margins are
-#   aligned: think of them as a two column table.
-#
-# * Any line that starts to the right of the current margin is treated
-#   as verbatim text.  This is useful for code listings.  The example of a
-#   list above is also verbatim text.
-#
-# * A line starting with an equals sign (=) is treated as a
-#   heading.  Level one headings have one equals sign, level two headings
-#   have two,and so on.
-#
-# * A line starting with three or more hyphens (at the current indent)
-#   generates a horizontal rule.  The more hyphens, the thicker the rule
-#   (within reason, and if supported by the output device)
-#
-# * You can use markup within text (except verbatim) to change the
-#   appearance of parts of that text.  Out of the box, RDoc::Markup
-#   supports word-based and general markup.
-#
-#   Word-based markup uses flag characters around individual words:
-#
-#   [\*word*]  displays word in a *bold* font
-#   [\_word_]  displays word in an _emphasized_ font
-#   [\+word+]  displays word in a +code+ font
-#
-#   General markup affects text between a start delimiter and and end
-#   delimiter.  Not surprisingly, these delimiters look like HTML markup.
-#
-#   [\<b>text...</b>]    displays word in a *bold* font
-#   [\<em>text...</em>]  displays word in an _emphasized_ font
-#   [\<i>text...</i>]    displays word in an _emphasized_ font
-#   [\<tt>text...</tt>]  displays word in a +code+ font
-#
-#   Unlike conventional Wiki markup, general markup can cross line
-#   boundaries.  You can turn off the interpretation of markup by
-#   preceding the first character with a backslash, so \\\<b>bold
-#   text</b> and \\\*bold* produce \<b>bold text</b> and \*bold*
-#   respectively.
-#
-# * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
-#   recognized.  An HTTP url that references an external image file is
-#   converted into an inline <IMG..>.  Hyperlinks starting 'link:' are
-#   assumed to refer to local files whose path is relative to the --op
-#   directory.
-#
-#   Hyperlinks can also be of the form <tt>label</tt>[url], in which
-#   case the label is used in the displayed text, and <tt>url</tt> is
-#   used as the target.  If <tt>label</tt> contains multiple words,
-#   put it in braces: <em>{multi word label}[</em>url<em>]</em>.
-#
 # == Synopsis
 #
 # This code converts +input_string+ to HTML.  The conversion takes place in
@@ -129,7 +34,7 @@
 #
 # You can extend the RDoc::Markup parser to recognise new markup
 # sequences, and to add special processing for text that matches a
-# regular epxression.  Here we make WikiWords significant to the parser,
+# regular expression.  Here we make WikiWords significant to the parser,
 # and also make the sequences {word} and \<no>text...</no> signify
 # strike-through text.  When then subclass the HTML output class to deal
 # with these:
@@ -197,7 +102,7 @@
 
   ##
   # Add to the sequences used to add formatting to an individual word (such
-  # as *bold*).  Matching entries will generate attibutes that the output
+  # as *bold*).  Matching entries will generate attributes that the output
   # formatters can recognize by their +name+.
 
   def add_word_pair(start, stop, name)

Modified: MacRuby/branches/experimental/lib/rdoc/options.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/options.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/options.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -39,7 +39,7 @@
   ##
   # Pattern for additional attr_... style methods
 
-  attr_reader :extra_accessors
+  attr_accessor :extra_accessors
 
   ##
   # Should we draw fileboxes in diagrams
@@ -62,6 +62,11 @@
   attr_accessor :generator
 
   ##
+  # Formatter to mark up text with
+
+  attr_accessor :formatter
+  
+  ##
   # image format for diagrams
 
   attr_reader :image_format
@@ -95,7 +100,7 @@
   ##
   # The name to use for the output
 
-  attr_reader :op_name
+  attr_accessor :op_name
 
   ##
   # Are we promiscuous about showing module contents across multiple files
@@ -103,11 +108,6 @@
   attr_reader :promiscuous
 
   ##
-  # Don't display progress as we process the files
-
-  attr_reader :quiet
-
-  ##
   # Array of directories to search for files to satisfy an :include:
 
   attr_reader :rdoc_include
@@ -145,18 +145,22 @@
   attr_reader :title
 
   ##
+  # Verbosity, zero means quiet
+
+  attr_accessor :verbosity
+
+  ##
   # URL of web cvs frontend
 
   attr_reader :webcvs
 
-  def initialize(generators) # :nodoc:
+  def initialize(generators = {}) # :nodoc:
     @op_dir = "doc"
     @op_name = nil
     @show_all = false
     @main_page = nil
     @merge = false
     @exclude = []
-    @quiet = false
     @generators = generators
     @generator_name = 'html'
     @generator = @generators[@generator_name]
@@ -175,12 +179,12 @@
     @extra_accessor_flags = {}
     @promiscuous = false
     @force_update = false
-    @title = "RDoc Documentation"
+    @verbosity = 1
 
     @css = nil
     @webcvs = nil
 
-    @charset = 'iso-8859-1'
+    @charset = 'utf-8'
   end
 
   ##
@@ -192,6 +196,7 @@
     opts = OptionParser.new do |opt|
       opt.program_name = File.basename $0
       opt.version = RDoc::VERSION
+      opt.release = nil
       opt.summary_indent = ' ' * 4
       opt.banner = <<-EOF
 Usage: #{opt.program_name} [options] [names...]
@@ -253,7 +258,7 @@
       opt.separator nil
 
       opt.on("--charset=CHARSET", "-c",
-             "Specifies the HTML character-set.") do |value|
+             "Specifies the output HTML character-set.") do |value|
         @charset = value
       end
 
@@ -279,9 +284,7 @@
 
       opt.on("--exclude=PATTERN", "-x", Regexp,
              "Do not process files or directories",
-             "matching PATTERN. Files given explicitly",
-             "on the command line will never be",
-             "excluded.") do |value|
+             "matching PATTERN.") do |value|
         @exclude << value
       end
 
@@ -420,9 +423,15 @@
 
       opt.on("--quiet", "-q",
              "Don't show progress as we parse.") do |value|
-        @quiet = value
+        @verbosity = 0
       end
 
+      opt.on("--verbose", "-v",
+             "Display extra progress as we parse.") do |value|
+        @verbosity = 2
+      end
+
+
       opt.separator nil
 
       opt.on("--ri", "-r",
@@ -513,6 +522,8 @@
       end
     end
 
+    argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']
+
     opts.parse! argv
 
     @files = argv.dup
@@ -553,6 +564,17 @@
     @title ||= string
   end
 
+  ##
+  # Don't display progress as we process the files
+
+  def quiet
+    @verbosity.zero?
+  end
+
+  def quiet=(bool)
+    @verbosity = bool ? 0 : 1
+  end
+
   private
 
   ##
@@ -571,7 +593,7 @@
     end
   end
 
-  # Check that the right version of 'dot' is available.  Unfortuately this
+  # Check that the right version of 'dot' is available.  Unfortunately this
   # doesn't work correctly under Windows NT, so we'll bypass the test under
   # Windows.
 
@@ -607,8 +629,8 @@
 
   def check_files
     @files.each do |f|
-      stat = File.stat f rescue abort("File not found: #{f}")
-      abort("File '#{f}' not readable") unless stat.readable?
+      stat = File.stat f
+      raise RDoc::Error, "file '#{f}' not readable" unless stat.readable?
     end
   end
 

Deleted: MacRuby/branches/experimental/lib/rdoc/parser/c.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/parser/c.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/parser/c.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,661 +0,0 @@
-require 'rdoc/parser'
-require 'rdoc/parser/ruby'
-require 'rdoc/known_classes'
-
-##
-# We attempt to parse C extension files. Basically we look for
-# the standard patterns that you find in extensions: <tt>rb_define_class,
-# rb_define_method</tt> and so on. We also try to find the corresponding
-# C source for the methods and extract comments, but if we fail
-# we don't worry too much.
-#
-# The comments associated with a Ruby method are extracted from the C
-# comment block associated with the routine that _implements_ that
-# method, that is to say the method whose name is given in the
-# <tt>rb_define_method</tt> call. For example, you might write:
-#
-#  /*
-#   * Returns a new array that is a one-dimensional flattening of this
-#   * array (recursively). That is, for every element that is an array,
-#   * extract its elements into the new array.
-#   *
-#   *    s = [ 1, 2, 3 ]           #=> [1, 2, 3]
-#   *    t = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
-#   *    a = [ s, t, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
-#   *    a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-#   */
-#   static VALUE
-#   rb_ary_flatten(ary)
-#       VALUE ary;
-#   {
-#       ary = rb_obj_dup(ary);
-#       rb_ary_flatten_bang(ary);
-#       return ary;
-#   }
-#
-#   ...
-#
-#   void
-#   Init_Array()
-#   {
-#     ...
-#     rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
-#
-# Here RDoc will determine from the rb_define_method line that there's a
-# method called "flatten" in class Array, and will look for the implementation
-# in the method rb_ary_flatten. It will then use the comment from that
-# method in the HTML output. This method must be in the same source file
-# as the rb_define_method.
-#
-# C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc
-# integrates C and Ruby source into one tree
-#
-# The comment blocks may include special directives:
-#
-# [Document-class: <i>name</i>]
-#   This comment block is documentation for the given class. Use this
-#   when the <tt>Init_xxx</tt> method is not named after the class.
-#
-# [Document-method: <i>name</i>]
-#   This comment documents the named method. Use when RDoc cannot
-#   automatically find the method from it's declaration
-#
-# [call-seq:  <i>text up to an empty line</i>]
-#   Because C source doesn't give descripive names to Ruby-level parameters,
-#   you need to document the calling sequence explicitly
-#
-# In addition, RDoc assumes by default that the C method implementing a
-# Ruby function is in the same source file as the rb_define_method call.
-# If this isn't the case, add the comment:
-#
-#    rb_define_method(....);  // in: filename
-#
-# As an example, we might have an extension that defines multiple classes
-# in its Init_xxx method. We could document them using
-#
-#   /*
-#    * Document-class:  MyClass
-#    *
-#    * Encapsulate the writing and reading of the configuration
-#    * file. ...
-#    */
-#   
-#   /*
-#    * Document-method: read_value
-#    *
-#    * call-seq:
-#    *   cfg.read_value(key)            -> value
-#    *   cfg.read_value(key} { |key| }  -> value
-#    *
-#    * Return the value corresponding to +key+ from the configuration.
-#    * In the second form, if the key isn't found, invoke the
-#    * block and return its value.
-#    */
-
-class RDoc::Parser::C < RDoc::Parser
-
-  parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
-
-  @@enclosure_classes = {}
-  @@known_bodies = {}
-
-  ##
-  # Prepare to parse a C file
-
-  def initialize(top_level, file_name, content, options, stats)
-    super
-
-    @known_classes = RDoc::KNOWN_CLASSES.dup
-    @content = handle_tab_width handle_ifdefs_in(@content)
-    @classes = Hash.new
-    @file_dir = File.dirname(@file_name)
-  end
-
-  def do_aliases
-    @content.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do
-      |var_name, new_name, old_name|
-      class_name = @known_classes[var_name] || var_name
-      class_obj  = find_class(var_name, class_name)
-
-      as = class_obj.add_alias RDoc::Alias.new("", old_name, new_name, "")
-
-      @stats.add_alias as
-    end
-  end
-
-  def do_classes
-    @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do 
-      |var_name, class_name|
-      handle_class_module(var_name, "module", class_name, nil, nil)
-    end
-
-    # The '.' lets us handle SWIG-generated files
-    @content.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
-              \(
-                 \s*"(\w+)",
-                 \s*(\w+)\s*
-              \)/mx) do |var_name, class_name, parent|
-      handle_class_module(var_name, "class", class_name, parent, nil)
-    end
-
-    @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
-      |var_name, class_name, parent|
-      parent = nil if parent == "0"
-      handle_class_module(var_name, "class", class_name, parent, nil)
-    end
-
-    @content.scan(/(\w+)\s* = \s*rb_define_module_under\s*
-              \(
-                 \s*(\w+),
-                 \s*"(\w+)"
-              \s*\)/mx) do |var_name, in_module, class_name|
-      handle_class_module(var_name, "module", class_name, nil, in_module)
-    end
-
-    @content.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s*
-              \(
-                 \s*(\w+),
-                 \s*"(\w+)",
-                 \s*([\w\*\s\(\)\.\->]+)\s*  # for SWIG
-              \s*\)/mx) do |var_name, in_module, class_name, parent|
-      handle_class_module(var_name, "class", class_name, parent, in_module)
-    end
-  end
-
-  def do_constants
-    @content.scan(%r{\Wrb_define_
-                   (
-                      variable |
-                      readonly_variable |
-                      const |
-                      global_const |
-                    )
-               \s*\(
-                 (?:\s*(\w+),)?
-                 \s*"(\w+)",
-                 \s*(.*?)\s*\)\s*;
-                 }xm) do |type, var_name, const_name, definition|
-      var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel"
-      handle_constants(type, var_name, const_name, definition)
-    end
-  end
-
-  ##
-  # Look for includes of the form:
-  #
-  #   rb_include_module(rb_cArray, rb_mEnumerable);
-
-  def do_includes
-    @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
-      if cls = @classes[c]
-        m = @known_classes[m] || m
-        cls.add_include RDoc::Include.new(m, "")
-      end
-    end
-  end
-
-  def do_methods
-    @content.scan(%r{rb_define_
-                   (
-                      singleton_method |
-                      method           |
-                      module_function  |
-                      private_method
-                   )
-                   \s*\(\s*([\w\.]+),
-                     \s*"([^"]+)",
-                     \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
-                     \s*(-?\w+)\s*\)
-                   (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
-                 }xm) do
-      |type, var_name, meth_name, meth_body, param_count, source_file|
-
-      # Ignore top-object and weird struct.c dynamic stuff
-      next if var_name == "ruby_top_self"
-      next if var_name == "nstr"
-      next if var_name == "envtbl"
-      next if var_name == "argf"   # it'd be nice to handle this one
-
-      var_name = "rb_cObject" if var_name == "rb_mKernel"
-      handle_method(type, var_name, meth_name,
-                    meth_body, param_count, source_file)
-    end
-
-    @content.scan(%r{rb_define_attr\(
-                             \s*([\w\.]+),
-                             \s*"([^"]+)",
-                             \s*(\d+),
-                             \s*(\d+)\s*\);
-                }xm) do |var_name, attr_name, attr_reader, attr_writer|
-      #var_name = "rb_cObject" if var_name == "rb_mKernel"
-      handle_attr(var_name, attr_name,
-                  attr_reader.to_i != 0,
-                  attr_writer.to_i != 0)
-    end
-
-    @content.scan(%r{rb_define_global_function\s*\(
-                             \s*"([^"]+)",
-                             \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
-                             \s*(-?\w+)\s*\)
-                (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
-                }xm) do |meth_name, meth_body, param_count, source_file|
-      handle_method("method", "rb_mKernel", meth_name,
-                    meth_body, param_count, source_file)
-    end
-
-    @content.scan(/define_filetest_function\s*\(
-                             \s*"([^"]+)",
-                             \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
-                             \s*(-?\w+)\s*\)/xm) do
-      |meth_name, meth_body, param_count|
-
-      handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
-      handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
-    end
-  end
-
-  def find_attr_comment(attr_name)
-    if @content =~ %r{((?>/\*.*?\*/\s+))
-                   rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi
-      $1
-    elsif @content =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m
-      $1
-    else
-      ''
-    end
-  end
-
-  ##
-  # Find the C code corresponding to a Ruby method
-
-  def find_body(class_name, meth_name, meth_obj, body, quiet = false)
-    case body
-    when %r"((?>/\*.*?\*/\s*))(?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name}
-            \s*(\([^)]*\))([^;]|$)"xm
-      comment, params = $1, $2
-      body_text = $&
-
-      remove_private_comments(comment) if comment
-
-      # see if we can find the whole body
-
-      re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
-      body_text = $& if /#{re}/m =~ body
-
-      # The comment block may have been overridden with a 'Document-method'
-      # block. This happens in the interpreter when multiple methods are
-      # vectored through to the same C method but those methods are logically
-      # distinct (for example Kernel.hash and Kernel.object_id share the same
-      # implementation
-
-      override_comment = find_override_comment(class_name, meth_obj.name)
-      comment = override_comment if override_comment
-
-      find_modifiers(comment, meth_obj) if comment
-
-#        meth_obj.params = params
-      meth_obj.start_collecting_tokens
-      meth_obj.add_token(RDoc::RubyToken::Token.new(1,1).set_text(body_text))
-      meth_obj.comment = mangle_comment(comment)
-    when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
-      comment = $1
-      find_body(class_name, $2, meth_obj, body, true)
-      find_modifiers(comment, meth_obj)
-      meth_obj.comment = mangle_comment(comment) + meth_obj.comment
-    when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
-      unless find_body(class_name, $1, meth_obj, body, true)
-        warn "No definition for #{meth_name}" unless @options.quiet
-        return false
-      end
-    else
-
-      # No body, but might still have an override comment
-      comment = find_override_comment(class_name, meth_obj.name)
-
-      if comment
-        find_modifiers(comment, meth_obj)
-        meth_obj.comment = mangle_comment(comment)
-      else
-        warn "No definition for #{meth_name}" unless @options.quiet
-        return false
-      end
-    end
-    true
-  end
-
-  def find_class(raw_name, name)
-    unless @classes[raw_name]
-      if raw_name =~ /^rb_m/
-        container = @top_level.add_module RDoc::NormalModule, name
-      else
-        container = @top_level.add_class RDoc::NormalClass, name, nil
-      end
-
-      container.record_location @top_level
-      @classes[raw_name] = container
-    end
-    @classes[raw_name]
-  end
-
-  ##
-  # Look for class or module documentation above Init_+class_name+(void),
-  # in a Document-class +class_name+ (or module) comment or above an
-  # rb_define_class (or module).  If a comment is supplied above a matching
-  # Init_ and a rb_define_class the Init_ comment is used.
-  #
-  #   /*
-  #    * This is a comment for Foo
-  #    */
-  #   Init_Foo(void) {
-  #       VALUE cFoo = rb_define_class("Foo", rb_cObject);
-  #   }
-  #
-  #   /*
-  #    * Document-class: Foo
-  #    * This is a comment for Foo
-  #    */
-  #   Init_foo(void) {
-  #       VALUE cFoo = rb_define_class("Foo", rb_cObject);
-  #   }
-  #
-  #   /*
-  #    * This is a comment for Foo
-  #    */
-  #   VALUE cFoo = rb_define_class("Foo", rb_cObject);
-
-  def find_class_comment(class_name, class_meth)
-    comment = nil
-    if @content =~ %r{((?>/\*.*?\*/\s+))
-                   (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then
-      comment = $1
-    elsif @content =~ %r{Document-(?:class|module):\s#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m
-      comment = $1
-    else
-      if @content =~ /rb_define_(class|module)/m then
-        class_name = class_name.split("::").last
-        comments = []
-        @content.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
-          comments[index] = chunk
-          if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
-            comment = comments[index-1]
-            break
-          end
-        end
-      end
-    end
-    class_meth.comment = mangle_comment(comment) if comment
-  end
-
-  ##
-  # Finds a comment matching +type+ and +const_name+ either above the
-  # comment or in the matching Document- section.
-
-  def find_const_comment(type, const_name)
-    if @content =~ %r{((?>^\s*/\*.*?\*/\s+))
-                   rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi
-      $1
-    elsif @content =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m
-      $1
-    else
-      ''
-    end
-  end
-
-  ##
-  # If the comment block contains a section that looks like:
-  #
-  #    call-seq:
-  #        Array.new
-  #        Array.new(10)
-  #
-  # use it for the parameters.
-
-  def find_modifiers(comment, meth_obj)
-    if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or
-       comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '')
-      meth_obj.document_self = false
-    end
-    if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or
-       comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '')
-      seq = $1
-      seq.gsub!(/^\s*\*\s*/, '')
-      meth_obj.call_seq = seq
-    end
-  end
-
-  def find_override_comment(class_name, meth_name)
-    name = Regexp.escape(meth_name)
-    if @content =~ %r{Document-method:\s+#{class_name}(?:\.|::|#)#{name}\s*?\n((?>.*?\*/))}m then
-      $1
-    elsif @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m then
-      $1
-    end
-  end
-
-  def handle_attr(var_name, attr_name, reader, writer)
-    rw = ''
-    if reader
-      #@stats.num_methods += 1
-      rw << 'R'
-    end
-    if writer
-      #@stats.num_methods += 1
-      rw << 'W'
-    end
-
-    class_name = @known_classes[var_name]
-
-    return unless class_name
-
-    class_obj  = find_class(var_name, class_name)
-
-    if class_obj
-      comment = find_attr_comment(attr_name)
-      unless comment.empty?
-        comment = mangle_comment(comment)
-      end
-      att = RDoc::Attr.new '', attr_name, rw, comment
-      class_obj.add_attribute(att)
-    end
-  end
-
-  def handle_class_module(var_name, class_mod, class_name, parent, in_module)
-    parent_name = @known_classes[parent] || parent
-
-    if in_module
-      enclosure = @classes[in_module] || @@enclosure_classes[in_module]
-      unless enclosure
-        if enclosure = @known_classes[in_module]
-          handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
-                              enclosure, nil, nil)
-          enclosure = @classes[in_module]
-        end
-      end
-      unless enclosure
-        warn("Enclosing class/module '#{in_module}' for " +
-              "#{class_mod} #{class_name} not known")
-        return
-      end
-    else
-      enclosure = @top_level
-    end
-
-    if class_mod == "class" then
-      full_name = enclosure.full_name.to_s + "::#{class_name}"
-      if @content =~ %r{Document-class:\s+#{full_name}\s*<\s+([:,\w]+)} then
-        parent_name = $1
-      end
-      cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name
-      @stats.add_class cm
-    else
-      cm = enclosure.add_module RDoc::NormalModule, class_name
-      @stats.add_module cm
-    end
-
-    cm.record_location(enclosure.toplevel)
-
-    find_class_comment(cm.full_name, cm)
-    @classes[var_name] = cm
-    @@enclosure_classes[var_name] = cm
-    @known_classes[var_name] = cm.full_name
-  end
-
-  ##
-  # Adds constant comments.  By providing some_value: at the start ofthe
-  # comment you can override the C value of the comment to give a friendly
-  # definition.
-  #
-  #   /* 300: The perfect score in bowling */
-  #   rb_define_const(cFoo, "PERFECT", INT2FIX(300);
-  #
-  # Will override +INT2FIX(300)+ with the value +300+ in the output RDoc.
-  # Values may include quotes and escaped colons (\:).
-
-  def handle_constants(type, var_name, const_name, definition)
-    #@stats.num_constants += 1
-    class_name = @known_classes[var_name]
-
-    return unless class_name
-
-    class_obj  = find_class(var_name, class_name)
-
-    unless class_obj
-      warn("Enclosing class/module '#{const_name}' for not known")
-      return
-    end
-
-    comment = find_const_comment(type, const_name)
-
-    # In the case of rb_define_const, the definition and comment are in
-    # "/* definition: comment */" form.  The literal ':' and '\' characters
-    # can be escaped with a backslash.
-    if type.downcase == 'const' then
-       elements = mangle_comment(comment).split(':')
-       if elements.nil? or elements.empty? then
-          con = RDoc::Constant.new(const_name, definition,
-                                   mangle_comment(comment))
-       else
-          new_definition = elements[0..-2].join(':')
-          if new_definition.empty? then # Default to literal C definition
-             new_definition = definition
-          else
-             new_definition.gsub!("\:", ":")
-             new_definition.gsub!("\\", '\\')
-          end
-          new_definition.sub!(/\A(\s+)/, '')
-          new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}"
-          con = RDoc::Constant.new(const_name, new_definition,
-                                   mangle_comment(new_comment))
-       end
-    else
-       con = RDoc::Constant.new const_name, definition, mangle_comment(comment)
-    end
-
-    class_obj.add_constant(con)
-  end
-
-  ##
-  # Removes #ifdefs that would otherwise confuse us
-
-  def handle_ifdefs_in(body)
-    body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
-  end
-
-  def handle_method(type, var_name, meth_name, meth_body, param_count,
-                    source_file = nil)
-    class_name = @known_classes[var_name]
-
-    return unless class_name
-
-    class_obj = find_class var_name, class_name
-
-    if class_obj then
-      if meth_name == "initialize" then
-        meth_name = "new"
-        type = "singleton_method"
-      end
-
-      meth_obj = RDoc::AnyMethod.new '', meth_name
-      meth_obj.singleton = %w[singleton_method module_function].include? type
-
-      p_count = (Integer(param_count) rescue -1)
-
-      if p_count < 0
-        meth_obj.params = "(...)"
-      elsif p_count == 0
-        meth_obj.params = "()"
-      else
-        meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")"
-      end
-
-      if source_file then
-        file_name = File.join(@file_dir, source_file)
-        body = (@@known_bodies[source_file] ||= File.read(file_name))
-      else
-        body = @content
-      end
-
-      if find_body(class_name, meth_body, meth_obj, body) and meth_obj.document_self then
-        class_obj.add_method meth_obj
-        @stats.add_method meth_obj
-      end
-    end
-  end
-
-  def handle_tab_width(body)
-    if /\t/ =~ body
-      tab_width = @options.tab_width
-      body.split(/\n/).map do |line|
-        1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)}  && $~ #`
-        line
-      end .join("\n")
-    else
-      body
-    end
-  end
-
-  ##
-  # Remove the /*'s and leading asterisks from C comments
-
-  def mangle_comment(comment)
-    comment.sub!(%r{/\*+}) { " " * $&.length }
-    comment.sub!(%r{\*+/}) { " " * $&.length }
-    comment.gsub!(/^[ \t]*\*/m) { " " * $&.length }
-    comment
-  end
-
-  ##
-  # Removes lines that are commented out that might otherwise get picked up
-  # when scanning for classes and methods
-
-  def remove_commented_out_lines
-    @content.gsub!(%r{//.*rb_define_}, '//')
-  end
-
-  def remove_private_comments(comment)
-     comment.gsub!(/\/?\*--\n(.*?)\/?\*\+\+/m, '')
-     comment.sub!(/\/?\*--\n.*/m, '')
-  end
-
-  ##
-  # Extract the classes/modules and methods from a C file and return the
-  # corresponding top-level object
-
-  def scan
-    remove_commented_out_lines
-    do_classes
-    do_constants
-    do_methods
-    do_includes
-    do_aliases
-    @top_level
-  end
-
-  def warn(msg)
-    $stderr.puts
-    $stderr.puts msg
-    $stderr.flush
-  end
-
-end
-

Copied: MacRuby/branches/experimental/lib/rdoc/parser/c.rb (from rev 1886, MacRuby/trunk/lib/rdoc/parser/c.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/parser/c.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/parser/c.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,661 @@
+require 'rdoc/parser'
+require 'rdoc/parser/ruby'
+require 'rdoc/known_classes'
+
+##
+# We attempt to parse C extension files. Basically we look for
+# the standard patterns that you find in extensions: <tt>rb_define_class,
+# rb_define_method</tt> and so on. We also try to find the corresponding
+# C source for the methods and extract comments, but if we fail
+# we don't worry too much.
+#
+# The comments associated with a Ruby method are extracted from the C
+# comment block associated with the routine that _implements_ that
+# method, that is to say the method whose name is given in the
+# <tt>rb_define_method</tt> call. For example, you might write:
+#
+#  /*
+#   * Returns a new array that is a one-dimensional flattening of this
+#   * array (recursively). That is, for every element that is an array,
+#   * extract its elements into the new array.
+#   *
+#   *    s = [ 1, 2, 3 ]           #=> [1, 2, 3]
+#   *    t = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
+#   *    a = [ s, t, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
+#   *    a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+#   */
+#   static VALUE
+#   rb_ary_flatten(ary)
+#       VALUE ary;
+#   {
+#       ary = rb_obj_dup(ary);
+#       rb_ary_flatten_bang(ary);
+#       return ary;
+#   }
+#
+#   ...
+#
+#   void
+#   Init_Array()
+#   {
+#     ...
+#     rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
+#
+# Here RDoc will determine from the rb_define_method line that there's a
+# method called "flatten" in class Array, and will look for the implementation
+# in the method rb_ary_flatten. It will then use the comment from that
+# method in the HTML output. This method must be in the same source file
+# as the rb_define_method.
+#
+# C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc
+# integrates C and Ruby source into one tree
+#
+# The comment blocks may include special directives:
+#
+# [Document-class: <i>name</i>]
+#   This comment block is documentation for the given class. Use this
+#   when the <tt>Init_xxx</tt> method is not named after the class.
+#
+# [Document-method: <i>name</i>]
+#   This comment documents the named method. Use when RDoc cannot
+#   automatically find the method from it's declaration
+#
+# [call-seq:  <i>text up to an empty line</i>]
+#   Because C source doesn't give descripive names to Ruby-level parameters,
+#   you need to document the calling sequence explicitly
+#
+# In addition, RDoc assumes by default that the C method implementing a
+# Ruby function is in the same source file as the rb_define_method call.
+# If this isn't the case, add the comment:
+#
+#    rb_define_method(....);  // in: filename
+#
+# As an example, we might have an extension that defines multiple classes
+# in its Init_xxx method. We could document them using
+#
+#   /*
+#    * Document-class:  MyClass
+#    *
+#    * Encapsulate the writing and reading of the configuration
+#    * file. ...
+#    */
+#   
+#   /*
+#    * Document-method: read_value
+#    *
+#    * call-seq:
+#    *   cfg.read_value(key)            -> value
+#    *   cfg.read_value(key} { |key| }  -> value
+#    *
+#    * Return the value corresponding to +key+ from the configuration.
+#    * In the second form, if the key isn't found, invoke the
+#    * block and return its value.
+#    */
+
+class RDoc::Parser::C < RDoc::Parser
+
+  parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
+
+  @@enclosure_classes = {}
+  @@known_bodies = {}
+
+  ##
+  # Prepare to parse a C file
+
+  def initialize(top_level, file_name, content, options, stats)
+    super
+
+    @known_classes = RDoc::KNOWN_CLASSES.dup
+    @content = handle_tab_width handle_ifdefs_in(@content)
+    @classes = Hash.new
+    @file_dir = File.dirname(@file_name)
+  end
+
+  def do_aliases
+    @content.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do
+      |var_name, new_name, old_name|
+      class_name = @known_classes[var_name] || var_name
+      class_obj  = find_class(var_name, class_name)
+
+      as = class_obj.add_alias RDoc::Alias.new("", old_name, new_name, "")
+
+      @stats.add_alias as
+    end
+  end
+
+  def do_classes
+    @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do 
+      |var_name, class_name|
+      handle_class_module(var_name, "module", class_name, nil, nil)
+    end
+
+    # The '.' lets us handle SWIG-generated files
+    @content.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
+              \(
+                 \s*"(\w+)",
+                 \s*(\w+)\s*
+              \)/mx) do |var_name, class_name, parent|
+      handle_class_module(var_name, "class", class_name, parent, nil)
+    end
+
+    @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
+      |var_name, class_name, parent|
+      parent = nil if parent == "0"
+      handle_class_module(var_name, "class", class_name, parent, nil)
+    end
+
+    @content.scan(/(\w+)\s* = \s*rb_define_module_under\s*
+              \(
+                 \s*(\w+),
+                 \s*"(\w+)"
+              \s*\)/mx) do |var_name, in_module, class_name|
+      handle_class_module(var_name, "module", class_name, nil, in_module)
+    end
+
+    @content.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s*
+              \(
+                 \s*(\w+),
+                 \s*"(\w+)",
+                 \s*([\w\*\s\(\)\.\->]+)\s*  # for SWIG
+              \s*\)/mx) do |var_name, in_module, class_name, parent|
+      handle_class_module(var_name, "class", class_name, parent, in_module)
+    end
+  end
+
+  def do_constants
+    @content.scan(%r{\Wrb_define_
+                   (
+                      variable |
+                      readonly_variable |
+                      const |
+                      global_const |
+                    )
+               \s*\(
+                 (?:\s*(\w+),)?
+                 \s*"(\w+)",
+                 \s*(.*?)\s*\)\s*;
+                 }xm) do |type, var_name, const_name, definition|
+      var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel"
+      handle_constants(type, var_name, const_name, definition)
+    end
+  end
+
+  ##
+  # Look for includes of the form:
+  #
+  #   rb_include_module(rb_cArray, rb_mEnumerable);
+
+  def do_includes
+    @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
+      if cls = @classes[c]
+        m = @known_classes[m] || m
+        cls.add_include RDoc::Include.new(m, "")
+      end
+    end
+  end
+
+  def do_methods
+    @content.scan(%r{rb_define_
+                   (
+                      singleton_method |
+                      method           |
+                      module_function  |
+                      private_method
+                   )
+                   \s*\(\s*([\w\.]+),
+                     \s*"([^"]+)",
+                     \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
+                     \s*(-?\w+)\s*\)
+                   (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
+                 }xm) do
+      |type, var_name, meth_name, meth_body, param_count, source_file|
+
+      # Ignore top-object and weird struct.c dynamic stuff
+      next if var_name == "ruby_top_self"
+      next if var_name == "nstr"
+      next if var_name == "envtbl"
+      next if var_name == "argf"   # it'd be nice to handle this one
+
+      var_name = "rb_cObject" if var_name == "rb_mKernel"
+      handle_method(type, var_name, meth_name,
+                    meth_body, param_count, source_file)
+    end
+
+    @content.scan(%r{rb_define_attr\(
+                             \s*([\w\.]+),
+                             \s*"([^"]+)",
+                             \s*(\d+),
+                             \s*(\d+)\s*\);
+                }xm) do |var_name, attr_name, attr_reader, attr_writer|
+      #var_name = "rb_cObject" if var_name == "rb_mKernel"
+      handle_attr(var_name, attr_name,
+                  attr_reader.to_i != 0,
+                  attr_writer.to_i != 0)
+    end
+
+    @content.scan(%r{rb_define_global_function\s*\(
+                             \s*"([^"]+)",
+                             \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
+                             \s*(-?\w+)\s*\)
+                (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
+                }xm) do |meth_name, meth_body, param_count, source_file|
+      handle_method("method", "rb_mKernel", meth_name,
+                    meth_body, param_count, source_file)
+    end
+
+    @content.scan(/define_filetest_function\s*\(
+                             \s*"([^"]+)",
+                             \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
+                             \s*(-?\w+)\s*\)/xm) do
+      |meth_name, meth_body, param_count|
+
+      handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
+      handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
+    end
+  end
+
+  def find_attr_comment(attr_name)
+    if @content =~ %r{((?>/\*.*?\*/\s+))
+                   rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi
+      $1
+    elsif @content =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m
+      $1
+    else
+      ''
+    end
+  end
+
+  ##
+  # Find the C code corresponding to a Ruby method
+
+  def find_body(class_name, meth_name, meth_obj, body, quiet = false)
+    case body
+    when %r"((?>/\*.*?\*/\s*))(?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name}
+            \s*(\([^)]*\))([^;]|$)"xm
+      comment, params = $1, $2
+      body_text = $&
+
+      remove_private_comments(comment) if comment
+
+      # see if we can find the whole body
+
+      re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
+      body_text = $& if /#{re}/m =~ body
+
+      # The comment block may have been overridden with a 'Document-method'
+      # block. This happens in the interpreter when multiple methods are
+      # vectored through to the same C method but those methods are logically
+      # distinct (for example Kernel.hash and Kernel.object_id share the same
+      # implementation
+
+      override_comment = find_override_comment(class_name, meth_obj.name)
+      comment = override_comment if override_comment
+
+      find_modifiers(comment, meth_obj) if comment
+
+#        meth_obj.params = params
+      meth_obj.start_collecting_tokens
+      meth_obj.add_token(RDoc::RubyToken::Token.new(1,1).set_text(body_text))
+      meth_obj.comment = mangle_comment(comment)
+    when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
+      comment = $1
+      find_body(class_name, $2, meth_obj, body, true)
+      find_modifiers(comment, meth_obj)
+      meth_obj.comment = mangle_comment(comment) + meth_obj.comment
+    when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
+      unless find_body(class_name, $1, meth_obj, body, true)
+        warn "No definition for #{meth_name}" unless @options.quiet
+        return false
+      end
+    else
+
+      # No body, but might still have an override comment
+      comment = find_override_comment(class_name, meth_obj.name)
+
+      if comment
+        find_modifiers(comment, meth_obj)
+        meth_obj.comment = mangle_comment(comment)
+      else
+        warn "No definition for #{meth_name}" unless @options.quiet
+        return false
+      end
+    end
+    true
+  end
+
+  def find_class(raw_name, name)
+    unless @classes[raw_name]
+      if raw_name =~ /^rb_m/
+        container = @top_level.add_module RDoc::NormalModule, name
+      else
+        container = @top_level.add_class RDoc::NormalClass, name, nil
+      end
+
+      container.record_location @top_level
+      @classes[raw_name] = container
+    end
+    @classes[raw_name]
+  end
+
+  ##
+  # Look for class or module documentation above Init_+class_name+(void),
+  # in a Document-class +class_name+ (or module) comment or above an
+  # rb_define_class (or module).  If a comment is supplied above a matching
+  # Init_ and a rb_define_class the Init_ comment is used.
+  #
+  #   /*
+  #    * This is a comment for Foo
+  #    */
+  #   Init_Foo(void) {
+  #       VALUE cFoo = rb_define_class("Foo", rb_cObject);
+  #   }
+  #
+  #   /*
+  #    * Document-class: Foo
+  #    * This is a comment for Foo
+  #    */
+  #   Init_foo(void) {
+  #       VALUE cFoo = rb_define_class("Foo", rb_cObject);
+  #   }
+  #
+  #   /*
+  #    * This is a comment for Foo
+  #    */
+  #   VALUE cFoo = rb_define_class("Foo", rb_cObject);
+
+  def find_class_comment(class_name, class_meth)
+    comment = nil
+    if @content =~ %r{((?>/\*.*?\*/\s+))
+                   (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then
+      comment = $1
+    elsif @content =~ %r{Document-(?:class|module):\s#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m
+      comment = $1
+    else
+      if @content =~ /rb_define_(class|module)/m then
+        class_name = class_name.split("::").last
+        comments = []
+        @content.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
+          comments[index] = chunk
+          if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
+            comment = comments[index-1]
+            break
+          end
+        end
+      end
+    end
+    class_meth.comment = mangle_comment(comment) if comment
+  end
+
+  ##
+  # Finds a comment matching +type+ and +const_name+ either above the
+  # comment or in the matching Document- section.
+
+  def find_const_comment(type, const_name)
+    if @content =~ %r{((?>^\s*/\*.*?\*/\s+))
+                   rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi
+      $1
+    elsif @content =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m
+      $1
+    else
+      ''
+    end
+  end
+
+  ##
+  # If the comment block contains a section that looks like:
+  #
+  #    call-seq:
+  #        Array.new
+  #        Array.new(10)
+  #
+  # use it for the parameters.
+
+  def find_modifiers(comment, meth_obj)
+    if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or
+       comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '')
+      meth_obj.document_self = false
+    end
+    if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or
+       comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '')
+      seq = $1
+      seq.gsub!(/^\s*\*\s*/, '')
+      meth_obj.call_seq = seq
+    end
+  end
+
+  def find_override_comment(class_name, meth_name)
+    name = Regexp.escape(meth_name)
+    if @content =~ %r{Document-method:\s+#{class_name}(?:\.|::|#)#{name}\s*?\n((?>.*?\*/))}m then
+      $1
+    elsif @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m then
+      $1
+    end
+  end
+
+  def handle_attr(var_name, attr_name, reader, writer)
+    rw = ''
+    if reader
+      #@stats.num_methods += 1
+      rw << 'R'
+    end
+    if writer
+      #@stats.num_methods += 1
+      rw << 'W'
+    end
+
+    class_name = @known_classes[var_name]
+
+    return unless class_name
+
+    class_obj  = find_class(var_name, class_name)
+
+    if class_obj
+      comment = find_attr_comment(attr_name)
+      unless comment.empty?
+        comment = mangle_comment(comment)
+      end
+      att = RDoc::Attr.new '', attr_name, rw, comment
+      class_obj.add_attribute(att)
+    end
+  end
+
+  def handle_class_module(var_name, class_mod, class_name, parent, in_module)
+    parent_name = @known_classes[parent] || parent
+
+    if in_module
+      enclosure = @classes[in_module] || @@enclosure_classes[in_module]
+      unless enclosure
+        if enclosure = @known_classes[in_module]
+          handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
+                              enclosure, nil, nil)
+          enclosure = @classes[in_module]
+        end
+      end
+      unless enclosure
+        warn("Enclosing class/module '#{in_module}' for " +
+              "#{class_mod} #{class_name} not known")
+        return
+      end
+    else
+      enclosure = @top_level
+    end
+
+    if class_mod == "class" then
+      full_name = enclosure.full_name.to_s + "::#{class_name}"
+      if @content =~ %r{Document-class:\s+#{full_name}\s*<\s+([:,\w]+)} then
+        parent_name = $1
+      end
+      cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name
+      @stats.add_class cm
+    else
+      cm = enclosure.add_module RDoc::NormalModule, class_name
+      @stats.add_module cm
+    end
+
+    cm.record_location(enclosure.toplevel)
+
+    find_class_comment(cm.full_name, cm)
+    @classes[var_name] = cm
+    @@enclosure_classes[var_name] = cm
+    @known_classes[var_name] = cm.full_name
+  end
+
+  ##
+  # Adds constant comments.  By providing some_value: at the start ofthe
+  # comment you can override the C value of the comment to give a friendly
+  # definition.
+  #
+  #   /* 300: The perfect score in bowling */
+  #   rb_define_const(cFoo, "PERFECT", INT2FIX(300);
+  #
+  # Will override +INT2FIX(300)+ with the value +300+ in the output RDoc.
+  # Values may include quotes and escaped colons (\:).
+
+  def handle_constants(type, var_name, const_name, definition)
+    #@stats.num_constants += 1
+    class_name = @known_classes[var_name]
+
+    return unless class_name
+
+    class_obj  = find_class(var_name, class_name)
+
+    unless class_obj
+      warn("Enclosing class/module '#{const_name}' for not known")
+      return
+    end
+
+    comment = find_const_comment(type, const_name)
+
+    # In the case of rb_define_const, the definition and comment are in
+    # "/* definition: comment */" form.  The literal ':' and '\' characters
+    # can be escaped with a backslash.
+    if type.downcase == 'const' then
+       elements = mangle_comment(comment).split(':')
+       if elements.nil? or elements.empty? then
+          con = RDoc::Constant.new(const_name, definition,
+                                   mangle_comment(comment))
+       else
+          new_definition = elements[0..-2].join(':')
+          if new_definition.empty? then # Default to literal C definition
+             new_definition = definition
+          else
+             new_definition.gsub!("\:", ":")
+             new_definition.gsub!("\\", '\\')
+          end
+          new_definition.sub!(/\A(\s+)/, '')
+          new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}"
+          con = RDoc::Constant.new(const_name, new_definition,
+                                   mangle_comment(new_comment))
+       end
+    else
+       con = RDoc::Constant.new const_name, definition, mangle_comment(comment)
+    end
+
+    class_obj.add_constant(con)
+  end
+
+  ##
+  # Removes #ifdefs that would otherwise confuse us
+
+  def handle_ifdefs_in(body)
+    body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
+  end
+
+  def handle_method(type, var_name, meth_name, meth_body, param_count,
+                    source_file = nil)
+    class_name = @known_classes[var_name]
+
+    return unless class_name
+
+    class_obj = find_class var_name, class_name
+
+    if class_obj then
+      if meth_name == "initialize" then
+        meth_name = "new"
+        type = "singleton_method"
+      end
+
+      meth_obj = RDoc::AnyMethod.new '', meth_name
+      meth_obj.singleton = %w[singleton_method module_function].include? type
+
+      p_count = (Integer(param_count) rescue -1)
+
+      if p_count < 0
+        meth_obj.params = "(...)"
+      elsif p_count == 0
+        meth_obj.params = "()"
+      else
+        meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")"
+      end
+
+      if source_file then
+        file_name = File.join(@file_dir, source_file)
+        body = (@@known_bodies[source_file] ||= File.read(file_name))
+      else
+        body = @content
+      end
+
+      if find_body(class_name, meth_body, meth_obj, body) and meth_obj.document_self then
+        class_obj.add_method meth_obj
+        @stats.add_method meth_obj
+      end
+    end
+  end
+
+  def handle_tab_width(body)
+    if /\t/ =~ body
+      tab_width = @options.tab_width
+      body.split(/\n/).map do |line|
+        1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)}  && $~ #`
+        line
+      end .join("\n")
+    else
+      body
+    end
+  end
+
+  ##
+  # Remove the /*'s and leading asterisks from C comments
+
+  def mangle_comment(comment)
+    comment.sub!(%r{/\*+}) { " " * $&.length }
+    comment.sub!(%r{\*+/}) { " " * $&.length }
+    comment.gsub!(/^[ \t]*\*/m) { " " * $&.length }
+    comment
+  end
+
+  ##
+  # Removes lines that are commented out that might otherwise get picked up
+  # when scanning for classes and methods
+
+  def remove_commented_out_lines
+    @content.gsub!(%r{//.*rb_define_}, '//')
+  end
+
+  def remove_private_comments(comment)
+     comment.gsub!(/\/?\*--\n(.*?)\/?\*\+\+/m, '')
+     comment.sub!(/\/?\*--\n.*/m, '')
+  end
+
+  ##
+  # Extract the classes/modules and methods from a C file and return the
+  # corresponding top-level object
+
+  def scan
+    remove_commented_out_lines
+    do_classes
+    do_constants
+    do_methods
+    do_includes
+    do_aliases
+    @top_level
+  end
+
+  def warn(msg)
+    $stderr.puts
+    $stderr.puts msg
+    $stderr.flush
+  end
+
+end
+

Deleted: MacRuby/branches/experimental/lib/rdoc/parser/f95.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/parser/f95.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/parser/f95.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,1835 +0,0 @@
-require 'rdoc/parser'
-
-##
-# = Fortran95 RDoc Parser
-#
-# == Overview
-#
-# This parser parses Fortran95 files with suffixes "f90", "F90", "f95" and
-# "F95". Fortran95 files are expected to be conformed to Fortran95 standards.
-#
-# == Rules
-#
-# Fundamental rules are same as that of the Ruby parser.  But comment markers
-# are '!' not '#'.
-#
-# === Correspondence between RDoc documentation and Fortran95 programs
-#
-# F95 parses main programs, modules, subroutines, functions, derived-types,
-# public variables, public constants, defined operators and defined
-# assignments.  These components are described in items of RDoc documentation,
-# as follows.
-#
-# Files :: Files (same as Ruby)
-# Classes:: Modules
-# Methods:: Subroutines, functions, variables, constants, derived-types,
-#           defined operators, defined assignments
-# Required files:: Files in which imported modules, external subroutines and
-#                  external functions are defined.
-# Included Modules:: List of imported modules
-# Attributes:: List of derived-types, List of imported modules all of whose
-#              components are published again
-#
-# Components listed in 'Methods' (subroutines, functions, ...) defined in
-# modules are described in the item of 'Classes'.  On the other hand,
-# components defined in main programs or as external procedures are described
-# in the item of 'Files'.
-#
-# === Components parsed by default
-#
-# By default, documentation on public components (subroutines, functions,
-# variables, constants, derived-types, defined operators, defined assignments)
-# are generated.
-#
-# With "--all" option, documentation on all components are generated (almost
-# same as the Ruby parser).
-#
-# === Information parsed automatically
-#
-# The following information is automatically parsed.
-#
-# * Types of arguments
-# * Types of variables and constants
-# * Types of variables in the derived types, and initial values
-# * NAMELISTs and types of variables in them, and initial values
-#
-# Aliases by interface statement are described in the item of 'Methods'.
-#
-# Components which are imported from other modules and published again are
-# described in the item of 'Methods'.
-#
-# === Format of comment blocks
-#
-# Comment blocks should be written as follows.
-#
-# Comment blocks are considered to be ended when the line without '!' appears.
-#
-# The indentation is not necessary.
-#
-#   ! (Top of file)
-#   !
-#   ! Comment blocks for the files.
-#   !
-#   !--
-#   ! The comment described in the part enclosed by
-#   ! "!--" and "!++" is ignored.
-#   !++
-#   !
-#   module hogehoge
-#     !
-#     ! Comment blocks for the modules (or the programs).
-#     !
-#   
-#     private
-#   
-#     logical            :: a     ! a private variable
-#     real, public       :: b     ! a public variable
-#     integer, parameter :: c = 0 ! a public constant
-#   
-#     public :: c
-#     public :: MULTI_ARRAY
-#     public :: hoge, foo
-#   
-#     type MULTI_ARRAY
-#       !
-#       ! Comment blocks for the derived-types.
-#       !
-#       real, pointer :: var(:) =>null() ! Comments block for the variables.
-#       integer       :: num = 0
-#     end type MULTI_ARRAY
-#   
-#   contains
-#   
-#     subroutine hoge( in,   &   ! Comment blocks between continuation lines are ignored.
-#         &            out )
-#       !
-#       ! Comment blocks for the subroutines or functions
-#       !
-#       character(*),intent(in):: in ! Comment blocks for the arguments.
-#       character(*),intent(out),allocatable,target  :: in
-#                                    ! Comment blocks can be
-#                                    ! written under Fortran statements.
-#   
-#       character(32) :: file ! This comment parsed as a variable in below NAMELIST.
-#       integer       :: id
-#   
-#       namelist /varinfo_nml/ file, id
-#               !
-#               ! Comment blocks for the NAMELISTs.
-#               ! Information about variables are described above.
-#               !
-#   
-#     ....
-#   
-#     end subroutine hoge
-#   
-#     integer function foo( in )
-#       !
-#       ! This part is considered as comment block.
-#   
-#       ! Comment blocks under blank lines are ignored.
-#       !
-#       integer, intent(in):: inA ! This part is considered as comment block.
-#   
-#                                 ! This part is ignored.
-#   
-#     end function foo
-#   
-#     subroutine hide( in,   &
-#       &              out )      !:nodoc:
-#       !
-#       ! If "!:nodoc:" is described at end-of-line in subroutine
-#       ! statement as above, the subroutine is ignored.
-#       ! This assignment can be used to modules, subroutines,
-#       ! functions, variables, constants, derived-types,
-#       ! defined operators, defined assignments,
-#       ! list of imported modules ("use" statement).
-#       !
-#   
-#     ....
-#   
-#     end subroutine hide
-#   
-#   end module hogehoge
-
-class RDoc::Parser::F95 < RDoc::Parser
-
-  parse_files_matching(/\.((f|F)9(0|5)|F)$/)
-
-  class Token
-
-    NO_TEXT = "??".freeze
-
-    def initialize(line_no, char_no)
-      @line_no = line_no
-      @char_no = char_no
-      @text    = NO_TEXT
-    end
-    # Because we're used in contexts that expect to return a token,
-    # we set the text string and then return ourselves
-    def set_text(text)
-      @text = text
-      self
-    end
-
-    attr_reader :line_no, :char_no, :text
-
-  end
-
-  @@external_aliases = []
-  @@public_methods   = []
-
-  ##
-  # "false":: Comments are below source code
-  # "true" :: Comments are upper source code
-
-  COMMENTS_ARE_UPPER  = false
-
-  ##
-  # Internal alias message
-
-  INTERNAL_ALIAS_MES = "Alias for"
-
-  ##
-  # External alias message
-
-  EXTERNAL_ALIAS_MES = "The entity is"
-
-  ##
-  # Define code constructs
-
-  def scan
-    # remove private comment
-    remaining_code = remove_private_comments(@content)
-
-    # continuation lines are united to one line
-    remaining_code = united_to_one_line(remaining_code)
-
-    # semicolons are replaced to line feed
-    remaining_code = semicolon_to_linefeed(remaining_code)
-
-    # collect comment for file entity
-    whole_comment, remaining_code = collect_first_comment(remaining_code)
-    @top_level.comment = whole_comment
-
-    # String "remaining_code" is converted to Array "remaining_lines"
-    remaining_lines = remaining_code.split("\n")
-
-    # "module" or "program" parts are parsed (new)
-    #
-    level_depth = 0
-    block_searching_flag = nil
-    block_searching_lines = []
-    pre_comment = []
-    module_program_trailing = ""
-    module_program_name = ""
-    other_block_level_depth = 0
-    other_block_searching_flag = nil
-    remaining_lines.collect!{|line|
-      if !block_searching_flag && !other_block_searching_flag
-        if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
-          block_searching_flag = :module
-          block_searching_lines << line
-          module_program_name = $1
-          module_program_trailing = find_comments($2)
-          next false
-        elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
-               line =~ /^\s*?\w/ && !block_start?(line)
-          block_searching_flag = :program
-          block_searching_lines << line
-          module_program_name = $1 || ""
-          module_program_trailing = find_comments($2)
-          next false
-
-        elsif block_start?(line)
-          other_block_searching_flag = true
-          next line
-
-        elsif line =~ /^\s*?!\s?(.*)/
-          pre_comment << line
-          next line
-        else
-          pre_comment = []
-          next line
-        end
-      elsif other_block_searching_flag
-        other_block_level_depth += 1 if block_start?(line)
-        other_block_level_depth -= 1 if block_end?(line)
-        if other_block_level_depth < 0
-          other_block_level_depth = 0
-          other_block_searching_flag = nil
-        end
-        next line
-      end
-
-      block_searching_lines << line
-      level_depth += 1 if block_start?(line)
-      level_depth -= 1 if block_end?(line)
-      if level_depth >= 0
-        next false
-      end
-
-      # "module_program_code" is formatted.
-      # ":nodoc:" flag is checked.
-      #
-      module_program_code = block_searching_lines.join("\n")
-      module_program_code = remove_empty_head_lines(module_program_code)
-      if module_program_trailing =~ /^:nodoc:/
-        # next loop to search next block
-        level_depth = 0
-        block_searching_flag = false
-        block_searching_lines = []
-        pre_comment = []
-        next false
-      end
-
-      # NormalClass is created, and added to @top_level
-      #
-      if block_searching_flag == :module
-        module_name = module_program_name
-        module_code = module_program_code
-        module_trailing = module_program_trailing
-
-        f9x_module = @top_level.add_module NormalClass, module_name
-        f9x_module.record_location @top_level
-
-        @stats.add_module f9x_module
-
-        f9x_comment = COMMENTS_ARE_UPPER ? 
-          find_comments(pre_comment.join("\n"))  + "\n" + module_trailing :
-            module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, ''))
-        f9x_module.comment = f9x_comment
-        parse_program_or_module(f9x_module, module_code)
-
-        TopLevel.all_files.each do |name, toplevel|
-          if toplevel.include_includes?(module_name, @options.ignore_case)
-            if !toplevel.include_requires?(@file_name, @options.ignore_case)
-              toplevel.add_require(Require.new(@file_name, ""))
-            end
-          end
-          toplevel.each_classmodule{|m|
-            if m.include_includes?(module_name, @options.ignore_case)
-              if !m.include_requires?(@file_name, @options.ignore_case)
-                m.add_require(Require.new(@file_name, ""))
-              end
-            end
-          }
-        end
-      elsif block_searching_flag == :program
-        program_name = module_program_name
-        program_code = module_program_code
-        program_trailing = module_program_trailing
-        # progress "p" # HACK what stats thingy does this correspond to?
-        program_comment = COMMENTS_ARE_UPPER ? 
-          find_comments(pre_comment.join("\n")) + "\n" + program_trailing : 
-            program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, ''))
-        program_comment = "\n\n= <i>Program</i> <tt>#{program_name}</tt>\n\n" \
-                          + program_comment
-        @top_level.comment << program_comment
-        parse_program_or_module(@top_level, program_code, :private)
-      end
-
-      # next loop to search next block
-      level_depth = 0
-      block_searching_flag = false
-      block_searching_lines = []
-      pre_comment = []
-      next false
-    }
-
-    remaining_lines.delete_if{ |line|
-      line == false
-    }
-
-    # External subprograms and functions are parsed
-    #
-    parse_program_or_module(@top_level, remaining_lines.join("\n"),
-                            :public, true)
-
-    @top_level
-  end  # End of scan
-
-  private
-
-  def parse_program_or_module(container, code,
-                              visibility=:public, external=nil)
-    return unless container
-    return unless code
-    remaining_lines = code.split("\n")
-    remaining_code = "#{code}"
-
-    #
-    # Parse variables before "contains" in module
-    #
-    level_depth = 0
-    before_contains_lines = []
-    before_contains_code = nil
-    before_contains_flag = nil
-    remaining_lines.each{ |line|
-      if !before_contains_flag
-        if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
-          before_contains_flag = true
-        end
-      else
-        break if line =~ /^\s*?contains\s*?(!.*?)?$/i
-        level_depth += 1 if block_start?(line)
-        level_depth -= 1 if block_end?(line)
-        break if level_depth < 0
-        before_contains_lines << line
-      end
-    }
-    before_contains_code = before_contains_lines.join("\n")
-    if before_contains_code
-      before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
-      before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
-    end
-
-    #
-    # Parse global "use"
-    #
-    use_check_code = "#{before_contains_code}"
-    cascaded_modules_list = []
-    while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
-      use_check_code = $~.pre_match
-      use_check_code << $~.post_match
-      used_mod_name = $1.strip.chomp
-      used_list = $2 || ""
-      used_trailing = $3 || ""
-      next if used_trailing =~ /!:nodoc:/
-      if !container.include_includes?(used_mod_name, @options.ignore_case)
-        # progress "." # HACK what stats thingy does this correspond to?
-        container.add_include Include.new(used_mod_name, "")
-      end
-      if ! (used_list =~ /\,\s*?only\s*?:/i )
-        cascaded_modules_list << "\#" + used_mod_name
-      end
-    end
-
-    #
-    # Parse public and private, and store information.
-    # This information is used when "add_method" and
-    # "set_visibility_for" are called.
-    #
-    visibility_default, visibility_info = 
-              parse_visibility(remaining_lines.join("\n"), visibility, container)
-    @@public_methods.concat visibility_info
-    if visibility_default == :public
-      if !cascaded_modules_list.empty?
-        cascaded_modules = 
-          Attr.new("Cascaded Modules",
-                   "Imported modules all of whose components are published again",
-                   "",
-                   cascaded_modules_list.join(", "))
-        container.add_attribute(cascaded_modules)
-      end
-    end
-
-    #
-    # Check rename elements
-    #
-    use_check_code = "#{before_contains_code}"
-    while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
-      use_check_code = $~.pre_match
-      use_check_code << $~.post_match
-      used_mod_name = $1.strip.chomp
-      used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
-      used_elements.split(",").each{ |used|
-        if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
-          local = $1
-          org = $2
-          @@public_methods.collect!{ |pub_meth|
-            if local == pub_meth["name"] ||
-                local.upcase == pub_meth["name"].upcase &&
-                @options.ignore_case
-              pub_meth["name"] = org
-              pub_meth["local_name"] = local
-            end
-            pub_meth
-          }
-        end
-      }
-    end
-
-    #
-    # Parse private "use"
-    #
-    use_check_code = remaining_lines.join("\n")
-    while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
-      use_check_code = $~.pre_match
-      use_check_code << $~.post_match
-      used_mod_name = $1.strip.chomp
-      used_trailing = $3 || ""
-      next if used_trailing =~ /!:nodoc:/
-      if !container.include_includes?(used_mod_name, @options.ignore_case)
-        # progress "." # HACK what stats thingy does this correspond to?
-        container.add_include Include.new(used_mod_name, "")
-      end
-    end
-
-    container.each_includes{ |inc|
-      TopLevel.all_files.each do |name, toplevel|
-        indicated_mod = toplevel.find_symbol(inc.name,
-                                             nil, @options.ignore_case)
-        if indicated_mod
-          indicated_name = indicated_mod.parent.file_relative_name
-          if !container.include_requires?(indicated_name, @options.ignore_case)
-            container.add_require(Require.new(indicated_name, ""))
-          end
-          break
-        end
-      end
-    }
-
-    #
-    # Parse derived-types definitions
-    #
-    derived_types_comment = ""
-    remaining_code = remaining_lines.join("\n")
-    while remaining_code =~ /^\s*?
-                                  type[\s\,]+(public|private)?\s*?(::)?\s*?
-                                  (\w+)\s*?(!.*?)?$
-                                  (.*?)
-                                  ^\s*?end\s+type.*?$
-                            /imx
-      remaining_code = $~.pre_match
-      remaining_code << $~.post_match
-      typename = $3.chomp.strip
-      type_elements = $5 || ""
-      type_code = remove_empty_head_lines($&)
-      type_trailing = find_comments($4)
-      next if type_trailing =~ /^:nodoc:/
-      type_visibility = $1
-      type_comment = COMMENTS_ARE_UPPER ? 
-        find_comments($~.pre_match) + "\n" + type_trailing :
-          type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
-      type_element_visibility_public = true
-      type_code.split("\n").each{ |line|
-        if /^\s*?private\s*?$/ =~ line
-          type_element_visibility_public = nil
-          break
-        end
-      } if type_code
-
-      args_comment = ""
-      type_args_info = nil
-
-      if @options.show_all
-        args_comment = find_arguments(nil, type_code, true)
-      else
-        type_public_args_list = []
-        type_args_info = definition_info(type_code)
-        type_args_info.each{ |arg|
-          arg_is_public = type_element_visibility_public
-          arg_is_public = true if arg.include_attr?("public")
-          arg_is_public = nil if arg.include_attr?("private")
-          type_public_args_list << arg.varname if arg_is_public
-        }
-        args_comment = find_arguments(type_public_args_list, type_code)
-      end
-
-      type = AnyMethod.new("type #{typename}", typename)
-      type.singleton = false
-      type.params = ""
-      type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
-      type.comment << args_comment if args_comment
-      type.comment << type_comment if type_comment
-
-      @stats.add_method type
-
-      container.add_method type
-
-      set_visibility(container, typename, visibility_default, @@public_methods)
-
-      if type_visibility
-        type_visibility.gsub!(/\s/,'')
-        type_visibility.gsub!(/\,/,'')
-        type_visibility.gsub!(/:/,'')
-        type_visibility.downcase!
-        if type_visibility == "public"
-          container.set_visibility_for([typename], :public)
-        elsif type_visibility == "private"
-          container.set_visibility_for([typename], :private)
-        end
-      end
-
-      check_public_methods(type, container.name)
-
-      if @options.show_all
-        derived_types_comment << ", " unless derived_types_comment.empty?
-        derived_types_comment << typename
-      else
-        if type.visibility == :public
-        derived_types_comment << ", " unless derived_types_comment.empty?
-        derived_types_comment << typename
-        end
-      end
-
-    end
-
-    if !derived_types_comment.empty?
-      derived_types_table = 
-        Attr.new("Derived Types", "Derived_Types", "", 
-                 derived_types_comment)
-      container.add_attribute(derived_types_table)
-    end
-
-    #
-    # move interface scope
-    #
-    interface_code = ""
-    while remaining_code =~ /^\s*?
-                                 interface(
-                                            \s+\w+                      |
-                                            \s+operator\s*?\(.*?\)       |
-                                            \s+assignment\s*?\(\s*?=\s*?\)
-                                          )?\s*?$
-                                 (.*?)
-                                 ^\s*?end\s+interface.*?$
-                            /imx
-      interface_code << remove_empty_head_lines($&) + "\n"
-      remaining_code = $~.pre_match
-      remaining_code << $~.post_match
-    end
-
-    #
-    # Parse global constants or variables in modules
-    #
-    const_var_defs = definition_info(before_contains_code)
-    const_var_defs.each{|defitem|
-      next if defitem.nodoc
-      const_or_var_type = "Variable"
-      const_or_var_progress = "v"
-      if defitem.include_attr?("parameter")
-        const_or_var_type = "Constant"
-        const_or_var_progress = "c"
-      end
-      const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
-      const_or_var.singleton = false
-      const_or_var.params = ""
-      self_comment = find_arguments([defitem.varname], before_contains_code)
-      const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
-      const_or_var.comment << self_comment if self_comment
-
-      @stats.add_method const_or_var_progress
-
-      container.add_method const_or_var
-
-      set_visibility(container, defitem.varname, visibility_default, @@public_methods)
-
-      if defitem.include_attr?("public")
-        container.set_visibility_for([defitem.varname], :public)
-      elsif defitem.include_attr?("private")
-        container.set_visibility_for([defitem.varname], :private)
-      end
-
-      check_public_methods(const_or_var, container.name)
-
-    } if const_var_defs
-
-    remaining_lines = remaining_code.split("\n")
-
-    # "subroutine" or "function" parts are parsed (new)
-    #
-    level_depth = 0
-    block_searching_flag = nil
-    block_searching_lines = []
-    pre_comment = []
-    procedure_trailing = ""
-    procedure_name = ""
-    procedure_params = ""
-    procedure_prefix = ""
-    procedure_result_arg = ""
-    procedure_type = ""
-    contains_lines = []
-    contains_flag = nil
-    remaining_lines.collect!{|line|
-      if !block_searching_flag
-        # subroutine
-        if line =~ /^\s*?
-                         (recursive|pure|elemental)?\s*?
-                         subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
-                   /ix
-          block_searching_flag = :subroutine
-          block_searching_lines << line
-
-          procedure_name = $2.chomp.strip
-          procedure_params = $3 || ""
-          procedure_prefix = $1 || ""
-          procedure_trailing = $4 || "!"
-          next false
-
-        # function
-        elsif line =~ /^\s*?
-                       (recursive|pure|elemental)?\s*?
-                       (
-                           character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | type\s*?\([\w\s]+?\)\s+
-                         | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | double\s+precision\s+
-                         | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                       )?
-                       function\s+(\w+)\s*?
-                       (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
-                      /ix
-          block_searching_flag = :function
-          block_searching_lines << line
-
-          procedure_prefix = $1 || ""
-          procedure_type = $2 ? $2.chomp.strip : nil
-          procedure_name = $8.chomp.strip
-          procedure_params = $9 || ""
-          procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
-          procedure_trailing = $12 || "!"
-          next false
-        elsif line =~ /^\s*?!\s?(.*)/
-          pre_comment << line
-          next line
-        else
-          pre_comment = []
-          next line
-        end
-      end
-      contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
-      block_searching_lines << line
-      contains_lines << line if contains_flag
-
-      level_depth += 1 if block_start?(line)
-      level_depth -= 1 if block_end?(line)
-      if level_depth >= 0
-        next false
-      end
-
-      # "procedure_code" is formatted.
-      # ":nodoc:" flag is checked.
-      #
-      procedure_code = block_searching_lines.join("\n")
-      procedure_code = remove_empty_head_lines(procedure_code)
-      if procedure_trailing =~ /^!:nodoc:/
-        # next loop to search next block
-        level_depth = 0
-        block_searching_flag = nil
-        block_searching_lines = []
-        pre_comment = []
-        procedure_trailing = ""
-        procedure_name = ""
-        procedure_params = ""
-        procedure_prefix = ""
-        procedure_result_arg = ""
-        procedure_type = ""
-        contains_lines = []
-        contains_flag = nil
-        next false
-      end
-
-      # AnyMethod is created, and added to container
-      #
-      subroutine_function = nil
-      if block_searching_flag == :subroutine
-        subroutine_prefix   = procedure_prefix
-        subroutine_name     = procedure_name
-        subroutine_params   = procedure_params
-        subroutine_trailing = procedure_trailing
-        subroutine_code     = procedure_code
-
-        subroutine_comment = COMMENTS_ARE_UPPER ? 
-          pre_comment.join("\n") + "\n" + subroutine_trailing : 
-            subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
-        subroutine = AnyMethod.new("subroutine", subroutine_name)
-        parse_subprogram(subroutine, subroutine_params,
-                         subroutine_comment, subroutine_code,
-                         before_contains_code, nil, subroutine_prefix)
-
-        @stats.add_method subroutine
-
-        container.add_method subroutine
-        subroutine_function = subroutine
-
-      elsif block_searching_flag == :function
-        function_prefix     = procedure_prefix
-        function_type       = procedure_type
-        function_name       = procedure_name
-        function_params_org = procedure_params
-        function_result_arg = procedure_result_arg
-        function_trailing   = procedure_trailing
-        function_code_org   = procedure_code
-
-        function_comment = COMMENTS_ARE_UPPER ?
-          pre_comment.join("\n") + "\n" + function_trailing :
-            function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
-
-        function_code = "#{function_code_org}"
-        if function_type
-          function_code << "\n" + function_type + " :: " + function_result_arg
-        end
-
-        function_params =
-          function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
-
-        function = AnyMethod.new("function", function_name)
-        parse_subprogram(function, function_params,
-                         function_comment, function_code,
-                         before_contains_code, true, function_prefix)
-
-        # Specific modification due to function
-        function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
-        function.params << " result(" + function_result_arg + ")"
-        function.start_collecting_tokens
-        function.add_token Token.new(1,1).set_text(function_code_org)
-
-        @stats.add_method function
-
-        container.add_method function
-        subroutine_function = function
-
-      end
-
-      # The visibility of procedure is specified
-      #
-      set_visibility(container, procedure_name, 
-                     visibility_default, @@public_methods)
-
-      # The alias for this procedure from external modules
-      #
-      check_external_aliases(procedure_name,
-                             subroutine_function.params,
-                             subroutine_function.comment, subroutine_function) if external
-      check_public_methods(subroutine_function, container.name)
-
-
-      # contains_lines are parsed as private procedures
-      if contains_flag
-        parse_program_or_module(container,
-                                contains_lines.join("\n"), :private)
-      end
-
-      # next loop to search next block
-      level_depth = 0
-      block_searching_flag = nil
-      block_searching_lines = []
-      pre_comment = []
-      procedure_trailing = ""
-      procedure_name = ""
-      procedure_params = ""
-      procedure_prefix = ""
-      procedure_result_arg = ""
-      contains_lines = []
-      contains_flag = nil
-      next false
-    } # End of remaining_lines.collect!{|line|
-
-    # Array remains_lines is converted to String remains_code again
-    #
-    remaining_code = remaining_lines.join("\n")
-
-    #
-    # Parse interface
-    #
-    interface_scope = false
-    generic_name = ""
-    interface_code.split("\n").each{ |line|
-      if /^\s*?
-               interface(
-                          \s+\w+|
-                          \s+operator\s*?\(.*?\)|
-                          \s+assignment\s*?\(\s*?=\s*?\)
-                        )?
-               \s*?(!.*?)?$
-         /ix =~ line
-        generic_name = $1 ? $1.strip.chomp : nil
-        interface_trailing = $2 || "!"
-        interface_scope = true
-        interface_scope = false if interface_trailing =~ /!:nodoc:/
-#        if generic_name =~ /operator\s*?\((.*?)\)/i
-#          operator_name = $1
-#          if operator_name && !operator_name.empty?
-#            generic_name = "#{operator_name}"
-#          end
-#        end
-#        if generic_name =~ /assignment\s*?\((.*?)\)/i
-#          assignment_name = $1
-#          if assignment_name && !assignment_name.empty?
-#            generic_name = "#{assignment_name}"
-#          end
-#        end
-      end
-      if /^\s*?end\s+interface/i =~ line
-        interface_scope = false
-        generic_name = nil
-      end
-      # internal alias
-      if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
-        procedures = $1.strip.chomp
-        procedures_trailing = $2 || "!"
-        next if procedures_trailing =~ /!:nodoc:/
-        procedures.split(",").each{ |proc|
-          proc.strip!
-          proc.chomp!
-          next if generic_name == proc || !generic_name
-          old_meth = container.find_symbol(proc, nil, @options.ignore_case)
-          next if !old_meth
-          nolink = old_meth.visibility == :private ? true : nil
-          nolink = nil if @options.show_all
-          new_meth = 
-             initialize_external_method(generic_name, proc, 
-                                        old_meth.params, nil, 
-                                        old_meth.comment, 
-                                        old_meth.clone.token_stream[0].text, 
-                                        true, nolink)
-          new_meth.singleton = old_meth.singleton
-
-          @stats.add_method new_meth
-
-          container.add_method new_meth
-
-          set_visibility(container, generic_name, visibility_default, @@public_methods)
-
-          check_public_methods(new_meth, container.name)
-
-        }
-      end
-
-      # external aliases
-      if interface_scope
-        # subroutine
-        proc = nil
-        params = nil
-        procedures_trailing = nil
-        if line =~ /^\s*?
-                         (recursive|pure|elemental)?\s*?
-                         subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
-                   /ix
-          proc = $2.chomp.strip
-          generic_name = proc unless generic_name
-          params = $3 || ""
-          procedures_trailing = $4 || "!"
-
-        # function
-        elsif line =~ /^\s*?
-                       (recursive|pure|elemental)?\s*?
-                       (
-                           character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | type\s*?\([\w\s]+?\)\s+
-                         | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | double\s+precision\s+
-                         | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                         | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                       )?
-                       function\s+(\w+)\s*?
-                       (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
-                      /ix
-          proc = $8.chomp.strip
-          generic_name = proc unless generic_name
-          params = $9 || ""
-          procedures_trailing = $12 || "!"
-        else
-          next
-        end
-        next if procedures_trailing =~ /!:nodoc:/
-        indicated_method = nil
-        indicated_file   = nil
-        TopLevel.all_files.each do |name, toplevel|
-          indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
-          indicated_file = name
-          break if indicated_method
-        end
-
-        if indicated_method
-          external_method = 
-            initialize_external_method(generic_name, proc, 
-                                       indicated_method.params, 
-                                       indicated_file, 
-                                       indicated_method.comment)
-
-          @stats.add_method external_method
-
-          container.add_method external_method
-          set_visibility(container, generic_name, visibility_default, @@public_methods)
-          if !container.include_requires?(indicated_file, @options.ignore_case)
-            container.add_require(Require.new(indicated_file, ""))
-          end
-          check_public_methods(external_method, container.name)
-
-        else
-          @@external_aliases << {
-            "new_name"  => generic_name,
-            "old_name"  => proc,
-            "file_or_module" => container,
-            "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
-          }
-        end
-      end
-
-    } if interface_code # End of interface_code.split("\n").each ...
-
-    #
-    # Already imported methods are removed from @@public_methods.
-    # Remainders are assumed to be imported from other modules.
-    #
-    @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
-
-    @@public_methods.each{ |pub_meth|
-      next unless pub_meth["file_or_module"].name == container.name
-      pub_meth["used_modules"].each{ |used_mod|
-        TopLevel.all_classes_and_modules.each{ |modules|
-          if modules.name == used_mod ||
-              modules.name.upcase == used_mod.upcase &&
-              @options.ignore_case
-            modules.method_list.each{ |meth|
-              if meth.name == pub_meth["name"] ||
-                  meth.name.upcase == pub_meth["name"].upcase &&
-                  @options.ignore_case
-                new_meth = initialize_public_method(meth,
-                                                    modules.name)
-                if pub_meth["local_name"]
-                  new_meth.name = pub_meth["local_name"]
-                end
-
-                @stats.add_method new_meth
-
-                container.add_method new_meth
-              end
-            }
-          end
-        }
-      }
-    }
-
-    container
-  end  # End of parse_program_or_module
-
-  ##
-  # Parse arguments, comment, code of subroutine and function.  Return
-  # AnyMethod object.
-
-  def parse_subprogram(subprogram, params, comment, code, 
-                       before_contains=nil, function=nil, prefix=nil)
-    subprogram.singleton = false
-    prefix = "" if !prefix
-    arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
-    args_comment, params_opt = 
-      find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
-                     nil, nil, true)
-    params_opt = "( " + params_opt + " ) " if params_opt
-    subprogram.params = params_opt || ""
-    namelist_comment = find_namelists(code, before_contains)
-
-    block_comment = find_comments comment
-    if function
-      subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
-    else
-      subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
-    end
-    subprogram.comment << args_comment if args_comment
-    subprogram.comment << block_comment if block_comment
-    subprogram.comment << namelist_comment if namelist_comment
-
-    # For output source code
-    subprogram.start_collecting_tokens
-    subprogram.add_token Token.new(1,1).set_text(code)
-
-    subprogram
-  end
-
-  ##
-  # Collect comment for file entity
-
-  def collect_first_comment(body)
-    comment = ""
-    not_comment = ""
-    comment_start = false
-    comment_end   = false
-    body.split("\n").each{ |line|
-      if comment_end
-        not_comment << line
-        not_comment << "\n"
-      elsif /^\s*?!\s?(.*)$/i =~ line
-        comment_start = true
-        comment << $1
-        comment << "\n"
-      elsif /^\s*?$/i =~ line
-        comment_end = true if comment_start && COMMENTS_ARE_UPPER
-      else
-        comment_end = true
-        not_comment << line
-        not_comment << "\n"
-      end
-    }
-    return comment, not_comment
-  end
-
-
-  ##
-  # Return comments of definitions of arguments
-  #
-  # If "all" argument is true, information of all arguments are returned.
-  #
-  # If "modified_params" is true, list of arguments are decorated, for
-  # example, optional arguments are parenthetic as "[arg]".
-
-  def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
-    return unless args || all
-    indent = "" unless indent
-    args = ["all"] if all
-    params = "" if modified_params
-    comma = ""
-    return unless text
-    args_rdocforms = "\n"
-    remaining_lines = "#{text}"
-    definitions = definition_info(remaining_lines)
-    args.each{ |arg|
-      arg.strip!
-      arg.chomp!
-      definitions.each { |defitem|
-        if arg == defitem.varname.strip.chomp || all
-          args_rdocforms << <<-"EOF"
-
-#{indent}<tt><b>#{defitem.varname.chomp.strip}#{defitem.arraysuffix}</b> #{defitem.inivalue}</tt> :: 
-#{indent}   <tt>#{defitem.types.chomp.strip}</tt>
-EOF
-          if !defitem.comment.chomp.strip.empty?
-            comment = ""
-            defitem.comment.split("\n").each{ |line|
-              comment << "       " + line + "\n"
-            }
-            args_rdocforms << <<-"EOF"
-
-#{indent}   <tt></tt> :: 
-#{indent}       <tt></tt>
-#{indent}       #{comment.chomp.strip}
-EOF
-          end
-
-          if modified_params
-            if defitem.include_attr?("optional")
-              params << "#{comma}[#{arg}]"
-            else
-              params << "#{comma}#{arg}"
-            end
-            comma = ", "
-          end
-        end
-      }
-    }
-    if modified_params
-      return args_rdocforms, params
-    else
-      return args_rdocforms
-    end
-  end
-
-  ##
-  # Return comments of definitions of namelists
-
-  def find_namelists(text, before_contains=nil)
-    return nil if !text
-    result = ""
-    lines = "#{text}"
-    before_contains = "" if !before_contains
-    while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i
-      lines = $~.post_match
-      nml_comment = COMMENTS_ARE_UPPER ? 
-          find_comments($~.pre_match) : find_comments($~.post_match)
-      nml_name = $1
-      nml_args = $2.split(",")
-      result << "\n\n=== NAMELIST <tt><b>" + nml_name + "</tt></b>\n\n"
-      result << nml_comment + "\n" if nml_comment
-      if lines.split("\n")[0] =~ /^\//i
-        lines = "namelist " + lines
-      end
-      result << find_arguments(nml_args, "#{text}" + "\n" + before_contains)
-    end
-    return result
-  end
-
-  ##
-  # Comments just after module or subprogram, or arguments are returned. If
-  # "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms
-  # are returnd
-
-  def find_comments text
-    return "" unless text
-    lines = text.split("\n")
-    lines.reverse! if COMMENTS_ARE_UPPER
-    comment_block = Array.new
-    lines.each do |line|
-      break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
-      if COMMENTS_ARE_UPPER
-        comment_block.unshift line.sub(/^\s*?!\s?/,"")
-      else
-        comment_block.push line.sub(/^\s*?!\s?/,"")
-      end
-    end
-    nice_lines = comment_block.join("\n").split "\n\s*?\n"
-    nice_lines[0] ||= ""
-    nice_lines.shift
-  end
-
-  ##
-  # Create method for internal alias
-
-  def initialize_public_method(method, parent)
-    return if !method || !parent
-
-    new_meth = AnyMethod.new("External Alias for module", method.name)
-    new_meth.singleton    = method.singleton
-    new_meth.params       = method.params.clone
-    new_meth.comment      = remove_trailing_alias(method.comment.clone)
-    new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
-
-    return new_meth
-  end
-
-  ##
-  # Create method for external alias
-  #
-  # If argument "internal" is true, file is ignored.
-
-  def initialize_external_method(new, old, params, file, comment, token=nil,
-                                 internal=nil, nolink=nil)
-    return nil unless new || old
-
-    if internal
-      external_alias_header = "#{INTERNAL_ALIAS_MES} "
-      external_alias_text   = external_alias_header + old 
-    elsif file
-      external_alias_header = "#{EXTERNAL_ALIAS_MES} "
-      external_alias_text   = external_alias_header + file + "#" + old
-    else
-      return nil
-    end
-    external_meth = AnyMethod.new(external_alias_text, new)
-    external_meth.singleton    = false
-    external_meth.params       = params
-    external_comment = remove_trailing_alias(comment) + "\n\n" if comment
-    external_meth.comment = external_comment || ""
-    if nolink && token
-      external_meth.start_collecting_tokens
-      external_meth.add_token Token.new(1,1).set_text(token)
-    else
-      external_meth.comment << external_alias_text
-    end
-
-    return external_meth
-  end
-
-  ##
-  # Parse visibility
-
-  def parse_visibility(code, default, container)
-    result = []
-    visibility_default = default || :public
-
-    used_modules = []
-    container.includes.each{|i| used_modules << i.name} if container
-
-    remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
-    remaining_code.split("\n").each{ |line|
-      if /^\s*?private\s*?$/ =~ line
-        visibility_default = :private
-        break
-      end
-    } if remaining_code
-
-    remaining_code.split("\n").each{ |line|
-      if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
-        methods = $2.sub(/!.*$/, '')
-        methods.split(",").each{ |meth|
-          meth.sub!(/!.*$/, '')
-          meth.gsub!(/:/, '')
-          result << {
-            "name" => meth.chomp.strip,
-            "visibility" => :private,
-            "used_modules" => used_modules.clone,
-            "file_or_module" => container,
-            "entity_is_discovered" => nil,
-            "local_name" => nil
-          }
-        }
-      elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
-        methods = $2.sub(/!.*$/, '')
-        methods.split(",").each{ |meth|
-          meth.sub!(/!.*$/, '')
-          meth.gsub!(/:/, '')
-          result << {
-            "name" => meth.chomp.strip,
-            "visibility" => :public,
-            "used_modules" => used_modules.clone,
-            "file_or_module" => container,
-            "entity_is_discovered" => nil,
-            "local_name" => nil
-          }
-        }
-      end
-    } if remaining_code
-
-    if container
-      result.each{ |vis_info|
-        vis_info["parent"] = container.name
-      }
-    end
-
-    return visibility_default, result
-  end
-
-  ##
-  # Set visibility
-  #
-  # "subname" element of "visibility_info" is deleted.
-
-  def set_visibility(container, subname, visibility_default, visibility_info)
-    return unless container || subname || visibility_default || visibility_info
-    not_found = true
-    visibility_info.collect!{ |info|
-      if info["name"] == subname ||
-          @options.ignore_case && info["name"].upcase == subname.upcase
-        if info["file_or_module"].name == container.name
-          container.set_visibility_for([subname], info["visibility"])
-          info["entity_is_discovered"] = true
-          not_found = false
-        end
-      end
-      info
-    }
-    if not_found
-      return container.set_visibility_for([subname], visibility_default)
-    else
-      return container
-    end
-  end
-
-  ##
-  # Find visibility
-
-  def find_visibility(container, subname, visibility_info)
-    return nil if !subname || !visibility_info
-    visibility_info.each{ |info|
-      if info["name"] == subname ||
-          @options.ignore_case && info["name"].upcase == subname.upcase
-        if info["parent"] == container.name
-          return info["visibility"]
-        end
-      end
-    }
-    return nil
-  end
-
-  ##
-  # Check external aliases
-
-  def check_external_aliases(subname, params, comment, test=nil)
-    @@external_aliases.each{ |alias_item|
-      if subname == alias_item["old_name"] ||
-                  subname.upcase == alias_item["old_name"].upcase &&
-                          @options.ignore_case
-
-        new_meth = initialize_external_method(alias_item["new_name"], 
-                                              subname, params, @file_name, 
-                                              comment)
-        new_meth.visibility = alias_item["visibility"]
-
-        @stats.add_method new_meth
-
-        alias_item["file_or_module"].add_method(new_meth)
-
-        if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
-          alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
-        end
-      end
-    }
-  end
-
-  ##
-  # Check public_methods
-
-  def check_public_methods(method, parent)
-    return if !method || !parent
-    @@public_methods.each{ |alias_item|
-      parent_is_used_module = nil
-      alias_item["used_modules"].each{ |used_module|
-        if used_module == parent ||
-            used_module.upcase == parent.upcase &&
-            @options.ignore_case
-          parent_is_used_module = true
-        end
-      }
-      next if !parent_is_used_module
-
-      if method.name == alias_item["name"] ||
-          method.name.upcase == alias_item["name"].upcase &&
-          @options.ignore_case
-
-        new_meth = initialize_public_method(method, parent)
-        if alias_item["local_name"]
-          new_meth.name = alias_item["local_name"]
-        end
-
-        @stats.add_method new_meth
-
-        alias_item["file_or_module"].add_method new_meth
-      end
-    }
-  end
-
-  ##
-  # Continuous lines are united.
-  #
-  # Comments in continuous lines are removed.
-
-  def united_to_one_line(f90src)
-    return "" unless f90src
-    lines = f90src.split("\n")
-    previous_continuing = false
-    now_continuing = false
-    body = ""
-    lines.each{ |line|
-      words = line.split("")
-      next if words.empty? && previous_continuing
-      commentout = false
-      brank_flag = true ; brank_char = ""
-      squote = false    ; dquote = false
-      ignore = false
-      words.collect! { |char|
-        if previous_continuing && brank_flag
-          now_continuing = true
-          ignore         = true
-          case char
-          when "!"                       ; break
-          when " " ; brank_char << char  ; next ""
-          when "&"
-            brank_flag = false
-            now_continuing = false
-            next ""
-          else 
-            brank_flag     = false
-            now_continuing = false
-            ignore         = false
-            next brank_char + char
-          end
-        end
-        ignore = false
-
-        if now_continuing
-          next ""
-        elsif !(squote) && !(dquote) && !(commentout)
-          case char
-          when "!" ; commentout = true     ; next char
-          when "\""; dquote = true         ; next char
-          when "\'"; squote = true         ; next char
-          when "&" ; now_continuing = true ; next ""
-          else next char
-          end
-        elsif commentout
-          next char
-        elsif squote
-          case char
-          when "\'"; squote = false ; next char
-          else next char
-          end
-        elsif dquote
-          case char
-          when "\""; dquote = false ; next char
-          else next char
-          end
-        end
-      }
-      if !ignore && !previous_continuing || !brank_flag
-        if previous_continuing
-          body << words.join("")
-        else
-          body << "\n" + words.join("")
-        end
-      end
-      previous_continuing = now_continuing ? true : nil
-      now_continuing = nil
-    }
-    return body
-  end
-
-
-  ##
-  # Continuous line checker
-
-  def continuous_line?(line)
-    continuous = false
-    if /&\s*?(!.*)?$/ =~ line
-      continuous = true
-      if comment_out?($~.pre_match)
-        continuous = false
-      end
-    end
-    return continuous
-  end
-
-  ##
-  # Comment out checker
-
-  def comment_out?(line)
-    return nil unless line
-    commentout = false
-    squote = false ; dquote = false
-    line.split("").each { |char|
-      if !(squote) && !(dquote)
-        case char
-        when "!" ; commentout = true ; break
-        when "\""; dquote = true
-        when "\'"; squote = true
-        else next
-        end
-      elsif squote
-        case char
-        when "\'"; squote = false
-        else next
-        end
-      elsif dquote
-        case char
-        when "\""; dquote = false
-        else next
-        end
-      end
-    }
-    return commentout
-  end
-
-  ##
-  # Semicolons are replaced to line feed.
-
-  def semicolon_to_linefeed(text)
-    return "" unless text
-    lines = text.split("\n")
-    lines.collect!{ |line|
-      words = line.split("")
-      commentout = false
-      squote = false ; dquote = false
-      words.collect! { |char|
-        if !(squote) && !(dquote) && !(commentout)
-          case char
-          when "!" ; commentout = true ; next char
-          when "\""; dquote = true     ; next char
-          when "\'"; squote = true     ; next char
-          when ";" ;                     "\n"
-          else next char
-          end
-        elsif commentout
-          next char
-        elsif squote
-          case char
-          when "\'"; squote = false ; next char
-          else next char
-          end
-        elsif dquote
-          case char
-          when "\""; dquote = false ; next char
-          else next char
-          end
-        end
-      }
-      words.join("")
-    }
-    return lines.join("\n")
-  end
-
-  ##
-  # Which "line" is start of block (module, program, block data, subroutine,
-  # function) statement ?
-
-  def block_start?(line)
-    return nil if !line
-
-    if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
-        line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
-        line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
-        line =~ \
-                /^\s*?
-                 (recursive|pure|elemental)?\s*?
-                 subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
-                /ix ||
-        line =~ \
-                /^\s*?
-                 (recursive|pure|elemental)?\s*?
-                 (
-                     character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                   | type\s*?\([\w\s]+?\)\s+
-                   | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                   | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                   | double\s+precision\s+
-                   | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                   | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
-                 )?
-                 function\s+(\w+)\s*?
-                 (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
-                /ix
-      return true
-    end
-
-    return nil
-  end
-
-  ##
-  # Which "line" is end of block (module, program, block data, subroutine,
-  # function) statement ?
-
-  def block_end?(line)
-    return nil if !line
-
-    if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
-        line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
-        line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
-        line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
-        line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
-        line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
-      return true
-    end
-
-    return nil
-  end
-
-  ##
-  # Remove "Alias for" in end of comments
-
-  def remove_trailing_alias(text)
-    return "" if !text
-    lines = text.split("\n").reverse
-    comment_block = Array.new
-    checked = false
-    lines.each do |line|
-      if !checked 
-        if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
-            /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
-          checked = true
-          next
-        end
-      end
-      comment_block.unshift line
-    end
-    nice_lines = comment_block.join("\n")
-    nice_lines ||= ""
-    return nice_lines
-  end
-
-  ##
-  # Empty lines in header are removed
-
-  def remove_empty_head_lines(text)
-    return "" unless text
-    lines = text.split("\n")
-    header = true
-    lines.delete_if{ |line|
-      header = false if /\S/ =~ line
-      header && /^\s*?$/ =~ line
-    }
-    lines.join("\n")
-  end
-
-  ##
-  # header marker "=", "==", ... are removed
-
-  def remove_header_marker(text)
-    return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
-  end
-
-  def remove_private_comments(body)
-    body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '')
-    return body
-  end
-
-  ##
-  # Information of arguments of subroutines and functions in Fortran95
-
-  class Fortran95Definition
-
-    # Name of variable
-    #
-    attr_reader   :varname
-
-    # Types of variable
-    #
-    attr_reader   :types
-
-    # Initial Value
-    #
-    attr_reader   :inivalue
-
-    # Suffix of array
-    #
-    attr_reader   :arraysuffix
-
-    # Comments
-    #
-    attr_accessor   :comment
-
-    # Flag of non documentation
-    #
-    attr_accessor   :nodoc
-
-    def initialize(varname, types, inivalue, arraysuffix, comment,
-                   nodoc=false)
-      @varname = varname
-      @types = types
-      @inivalue = inivalue
-      @arraysuffix = arraysuffix
-      @comment = comment
-      @nodoc = nodoc
-    end
-
-    def to_s
-      return <<-EOF
-<Fortran95Definition: 
-varname=#{@varname}, types=#{types},
-inivalue=#{@inivalue}, arraysuffix=#{@arraysuffix}, nodoc=#{@nodoc}, 
-comment=
-#{@comment}
->
-EOF
-    end
-
-    #
-    # If attr is included, true is returned
-    #
-    def include_attr?(attr)
-      return if !attr
-      @types.split(",").each{ |type|
-        return true if type.strip.chomp.upcase == attr.strip.chomp.upcase
-      }
-      return nil
-    end
-
-  end # End of Fortran95Definition
-
-  ##
-  # Parse string argument "text", and Return Array of Fortran95Definition
-  # object
-
-  def definition_info(text)
-    return nil unless text
-    lines = "#{text}"
-    defs = Array.new
-    comment = ""
-    trailing_comment = ""
-    under_comment_valid = false
-    lines.split("\n").each{ |line|
-      if /^\s*?!\s?(.*)/ =~ line
-        if COMMENTS_ARE_UPPER
-          comment << remove_header_marker($1)
-          comment << "\n"
-        elsif defs[-1] && under_comment_valid
-          defs[-1].comment << "\n"
-          defs[-1].comment << remove_header_marker($1)
-        end
-        next
-      elsif /^\s*?$/ =~ line
-        comment = ""
-        under_comment_valid = false
-        next
-      end
-      type = ""
-      characters = ""
-      if line =~ /^\s*?
-                  (
-                      character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
-                    | type\s*?\([\w\s]+?\)[\s\,]*
-                    | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
-                    | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
-                    | double\s+precision[\s\,]*
-                    | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
-                    | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
-                  )
-                  (.*?::)?
-                  (.+)$
-                 /ix
-        characters = $8
-        type = $1
-        type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
-      else
-        under_comment_valid = false
-        next
-      end
-      squote = false ; dquote = false ; bracket = 0
-      iniflag = false; commentflag = false
-      varname = "" ; arraysuffix = "" ; inivalue = ""
-      start_pos = defs.size
-      characters.split("").each { |char|
-        if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
-          case char
-          when "!" ; commentflag = true
-          when "(" ; bracket += 1       ; arraysuffix = char
-          when "\""; dquote = true
-          when "\'"; squote = true
-          when "=" ; iniflag = true     ; inivalue << char
-          when ","
-            defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
-            varname = "" ; arraysuffix = "" ; inivalue = ""
-            under_comment_valid = true
-          when " " ; next
-          else     ; varname << char
-          end
-        elsif commentflag
-          comment << remove_header_marker(char)
-          trailing_comment << remove_header_marker(char)
-        elsif iniflag
-          if dquote
-            case char
-            when "\"" ; dquote = false ; inivalue << char
-            else      ; inivalue << char
-            end
-          elsif squote
-            case char
-            when "\'" ; squote = false ; inivalue << char
-            else      ; inivalue << char
-            end
-          elsif bracket > 0
-            case char
-            when "(" ; bracket += 1 ; inivalue << char
-            when ")" ; bracket -= 1 ; inivalue << char
-            else     ; inivalue << char
-            end
-          else
-            case char
-            when ","
-              defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
-              varname = "" ; arraysuffix = "" ; inivalue = ""
-              iniflag = false
-              under_comment_valid = true
-            when "(" ; bracket += 1 ; inivalue << char
-            when "\""; dquote = true  ; inivalue << char
-            when "\'"; squote = true  ; inivalue << char
-            when "!" ; commentflag = true
-            else     ; inivalue << char
-            end
-          end
-        elsif !(squote) && !(dquote) && bracket > 0
-          case char
-          when "(" ; bracket += 1 ; arraysuffix << char
-          when ")" ; bracket -= 1 ; arraysuffix << char
-          else     ; arraysuffix << char
-          end
-        elsif squote
-          case char
-          when "\'"; squote = false ; inivalue << char
-          else     ; inivalue << char
-          end
-        elsif dquote
-          case char
-          when "\""; dquote = false ; inivalue << char
-          else     ; inivalue << char
-          end
-        end
-      }
-      defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
-      if trailing_comment =~ /^:nodoc:/
-        defs[start_pos..-1].collect!{ |defitem|
-          defitem.nodoc = true
-        }
-      end
-      varname = "" ; arraysuffix = "" ; inivalue = ""
-      comment = ""
-      under_comment_valid = true
-      trailing_comment = ""
-    }
-    return defs
-  end
-
-end
-

Copied: MacRuby/branches/experimental/lib/rdoc/parser/f95.rb (from rev 1886, MacRuby/trunk/lib/rdoc/parser/f95.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/parser/f95.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/parser/f95.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,1835 @@
+require 'rdoc/parser'
+
+##
+# = Fortran95 RDoc Parser
+#
+# == Overview
+#
+# This parser parses Fortran95 files with suffixes "f90", "F90", "f95" and
+# "F95". Fortran95 files are expected to be conformed to Fortran95 standards.
+#
+# == Rules
+#
+# Fundamental rules are same as that of the Ruby parser.  But comment markers
+# are '!' not '#'.
+#
+# === Correspondence between RDoc documentation and Fortran95 programs
+#
+# F95 parses main programs, modules, subroutines, functions, derived-types,
+# public variables, public constants, defined operators and defined
+# assignments.  These components are described in items of RDoc documentation,
+# as follows.
+#
+# Files :: Files (same as Ruby)
+# Classes:: Modules
+# Methods:: Subroutines, functions, variables, constants, derived-types,
+#           defined operators, defined assignments
+# Required files:: Files in which imported modules, external subroutines and
+#                  external functions are defined.
+# Included Modules:: List of imported modules
+# Attributes:: List of derived-types, List of imported modules all of whose
+#              components are published again
+#
+# Components listed in 'Methods' (subroutines, functions, ...) defined in
+# modules are described in the item of 'Classes'.  On the other hand,
+# components defined in main programs or as external procedures are described
+# in the item of 'Files'.
+#
+# === Components parsed by default
+#
+# By default, documentation on public components (subroutines, functions,
+# variables, constants, derived-types, defined operators, defined assignments)
+# are generated.
+#
+# With "--all" option, documentation on all components are generated (almost
+# same as the Ruby parser).
+#
+# === Information parsed automatically
+#
+# The following information is automatically parsed.
+#
+# * Types of arguments
+# * Types of variables and constants
+# * Types of variables in the derived types, and initial values
+# * NAMELISTs and types of variables in them, and initial values
+#
+# Aliases by interface statement are described in the item of 'Methods'.
+#
+# Components which are imported from other modules and published again are
+# described in the item of 'Methods'.
+#
+# === Format of comment blocks
+#
+# Comment blocks should be written as follows.
+#
+# Comment blocks are considered to be ended when the line without '!' appears.
+#
+# The indentation is not necessary.
+#
+#   ! (Top of file)
+#   !
+#   ! Comment blocks for the files.
+#   !
+#   !--
+#   ! The comment described in the part enclosed by
+#   ! "!--" and "!++" is ignored.
+#   !++
+#   !
+#   module hogehoge
+#     !
+#     ! Comment blocks for the modules (or the programs).
+#     !
+#   
+#     private
+#   
+#     logical            :: a     ! a private variable
+#     real, public       :: b     ! a public variable
+#     integer, parameter :: c = 0 ! a public constant
+#   
+#     public :: c
+#     public :: MULTI_ARRAY
+#     public :: hoge, foo
+#   
+#     type MULTI_ARRAY
+#       !
+#       ! Comment blocks for the derived-types.
+#       !
+#       real, pointer :: var(:) =>null() ! Comments block for the variables.
+#       integer       :: num = 0
+#     end type MULTI_ARRAY
+#   
+#   contains
+#   
+#     subroutine hoge( in,   &   ! Comment blocks between continuation lines are ignored.
+#         &            out )
+#       !
+#       ! Comment blocks for the subroutines or functions
+#       !
+#       character(*),intent(in):: in ! Comment blocks for the arguments.
+#       character(*),intent(out),allocatable,target  :: in
+#                                    ! Comment blocks can be
+#                                    ! written under Fortran statements.
+#   
+#       character(32) :: file ! This comment parsed as a variable in below NAMELIST.
+#       integer       :: id
+#   
+#       namelist /varinfo_nml/ file, id
+#               !
+#               ! Comment blocks for the NAMELISTs.
+#               ! Information about variables are described above.
+#               !
+#   
+#     ....
+#   
+#     end subroutine hoge
+#   
+#     integer function foo( in )
+#       !
+#       ! This part is considered as comment block.
+#   
+#       ! Comment blocks under blank lines are ignored.
+#       !
+#       integer, intent(in):: inA ! This part is considered as comment block.
+#   
+#                                 ! This part is ignored.
+#   
+#     end function foo
+#   
+#     subroutine hide( in,   &
+#       &              out )      !:nodoc:
+#       !
+#       ! If "!:nodoc:" is described at end-of-line in subroutine
+#       ! statement as above, the subroutine is ignored.
+#       ! This assignment can be used to modules, subroutines,
+#       ! functions, variables, constants, derived-types,
+#       ! defined operators, defined assignments,
+#       ! list of imported modules ("use" statement).
+#       !
+#   
+#     ....
+#   
+#     end subroutine hide
+#   
+#   end module hogehoge
+
+class RDoc::Parser::F95 < RDoc::Parser
+
+  parse_files_matching(/\.((f|F)9(0|5)|F)$/)
+
+  class Token
+
+    NO_TEXT = "??".freeze
+
+    def initialize(line_no, char_no)
+      @line_no = line_no
+      @char_no = char_no
+      @text    = NO_TEXT
+    end
+    # Because we're used in contexts that expect to return a token,
+    # we set the text string and then return ourselves
+    def set_text(text)
+      @text = text
+      self
+    end
+
+    attr_reader :line_no, :char_no, :text
+
+  end
+
+  @@external_aliases = []
+  @@public_methods   = []
+
+  ##
+  # "false":: Comments are below source code
+  # "true" :: Comments are upper source code
+
+  COMMENTS_ARE_UPPER  = false
+
+  ##
+  # Internal alias message
+
+  INTERNAL_ALIAS_MES = "Alias for"
+
+  ##
+  # External alias message
+
+  EXTERNAL_ALIAS_MES = "The entity is"
+
+  ##
+  # Define code constructs
+
+  def scan
+    # remove private comment
+    remaining_code = remove_private_comments(@content)
+
+    # continuation lines are united to one line
+    remaining_code = united_to_one_line(remaining_code)
+
+    # semicolons are replaced to line feed
+    remaining_code = semicolon_to_linefeed(remaining_code)
+
+    # collect comment for file entity
+    whole_comment, remaining_code = collect_first_comment(remaining_code)
+    @top_level.comment = whole_comment
+
+    # String "remaining_code" is converted to Array "remaining_lines"
+    remaining_lines = remaining_code.split("\n")
+
+    # "module" or "program" parts are parsed (new)
+    #
+    level_depth = 0
+    block_searching_flag = nil
+    block_searching_lines = []
+    pre_comment = []
+    module_program_trailing = ""
+    module_program_name = ""
+    other_block_level_depth = 0
+    other_block_searching_flag = nil
+    remaining_lines.collect!{|line|
+      if !block_searching_flag && !other_block_searching_flag
+        if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
+          block_searching_flag = :module
+          block_searching_lines << line
+          module_program_name = $1
+          module_program_trailing = find_comments($2)
+          next false
+        elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
+               line =~ /^\s*?\w/ && !block_start?(line)
+          block_searching_flag = :program
+          block_searching_lines << line
+          module_program_name = $1 || ""
+          module_program_trailing = find_comments($2)
+          next false
+
+        elsif block_start?(line)
+          other_block_searching_flag = true
+          next line
+
+        elsif line =~ /^\s*?!\s?(.*)/
+          pre_comment << line
+          next line
+        else
+          pre_comment = []
+          next line
+        end
+      elsif other_block_searching_flag
+        other_block_level_depth += 1 if block_start?(line)
+        other_block_level_depth -= 1 if block_end?(line)
+        if other_block_level_depth < 0
+          other_block_level_depth = 0
+          other_block_searching_flag = nil
+        end
+        next line
+      end
+
+      block_searching_lines << line
+      level_depth += 1 if block_start?(line)
+      level_depth -= 1 if block_end?(line)
+      if level_depth >= 0
+        next false
+      end
+
+      # "module_program_code" is formatted.
+      # ":nodoc:" flag is checked.
+      #
+      module_program_code = block_searching_lines.join("\n")
+      module_program_code = remove_empty_head_lines(module_program_code)
+      if module_program_trailing =~ /^:nodoc:/
+        # next loop to search next block
+        level_depth = 0
+        block_searching_flag = false
+        block_searching_lines = []
+        pre_comment = []
+        next false
+      end
+
+      # NormalClass is created, and added to @top_level
+      #
+      if block_searching_flag == :module
+        module_name = module_program_name
+        module_code = module_program_code
+        module_trailing = module_program_trailing
+
+        f9x_module = @top_level.add_module NormalClass, module_name
+        f9x_module.record_location @top_level
+
+        @stats.add_module f9x_module
+
+        f9x_comment = COMMENTS_ARE_UPPER ? 
+          find_comments(pre_comment.join("\n"))  + "\n" + module_trailing :
+            module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, ''))
+        f9x_module.comment = f9x_comment
+        parse_program_or_module(f9x_module, module_code)
+
+        TopLevel.all_files.each do |name, toplevel|
+          if toplevel.include_includes?(module_name, @options.ignore_case)
+            if !toplevel.include_requires?(@file_name, @options.ignore_case)
+              toplevel.add_require(Require.new(@file_name, ""))
+            end
+          end
+          toplevel.each_classmodule{|m|
+            if m.include_includes?(module_name, @options.ignore_case)
+              if !m.include_requires?(@file_name, @options.ignore_case)
+                m.add_require(Require.new(@file_name, ""))
+              end
+            end
+          }
+        end
+      elsif block_searching_flag == :program
+        program_name = module_program_name
+        program_code = module_program_code
+        program_trailing = module_program_trailing
+        # progress "p" # HACK what stats thingy does this correspond to?
+        program_comment = COMMENTS_ARE_UPPER ? 
+          find_comments(pre_comment.join("\n")) + "\n" + program_trailing : 
+            program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, ''))
+        program_comment = "\n\n= <i>Program</i> <tt>#{program_name}</tt>\n\n" \
+                          + program_comment
+        @top_level.comment << program_comment
+        parse_program_or_module(@top_level, program_code, :private)
+      end
+
+      # next loop to search next block
+      level_depth = 0
+      block_searching_flag = false
+      block_searching_lines = []
+      pre_comment = []
+      next false
+    }
+
+    remaining_lines.delete_if{ |line|
+      line == false
+    }
+
+    # External subprograms and functions are parsed
+    #
+    parse_program_or_module(@top_level, remaining_lines.join("\n"),
+                            :public, true)
+
+    @top_level
+  end  # End of scan
+
+  private
+
+  def parse_program_or_module(container, code,
+                              visibility=:public, external=nil)
+    return unless container
+    return unless code
+    remaining_lines = code.split("\n")
+    remaining_code = "#{code}"
+
+    #
+    # Parse variables before "contains" in module
+    #
+    level_depth = 0
+    before_contains_lines = []
+    before_contains_code = nil
+    before_contains_flag = nil
+    remaining_lines.each{ |line|
+      if !before_contains_flag
+        if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
+          before_contains_flag = true
+        end
+      else
+        break if line =~ /^\s*?contains\s*?(!.*?)?$/i
+        level_depth += 1 if block_start?(line)
+        level_depth -= 1 if block_end?(line)
+        break if level_depth < 0
+        before_contains_lines << line
+      end
+    }
+    before_contains_code = before_contains_lines.join("\n")
+    if before_contains_code
+      before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
+      before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
+    end
+
+    #
+    # Parse global "use"
+    #
+    use_check_code = "#{before_contains_code}"
+    cascaded_modules_list = []
+    while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
+      use_check_code = $~.pre_match
+      use_check_code << $~.post_match
+      used_mod_name = $1.strip.chomp
+      used_list = $2 || ""
+      used_trailing = $3 || ""
+      next if used_trailing =~ /!:nodoc:/
+      if !container.include_includes?(used_mod_name, @options.ignore_case)
+        # progress "." # HACK what stats thingy does this correspond to?
+        container.add_include Include.new(used_mod_name, "")
+      end
+      if ! (used_list =~ /\,\s*?only\s*?:/i )
+        cascaded_modules_list << "\#" + used_mod_name
+      end
+    end
+
+    #
+    # Parse public and private, and store information.
+    # This information is used when "add_method" and
+    # "set_visibility_for" are called.
+    #
+    visibility_default, visibility_info = 
+              parse_visibility(remaining_lines.join("\n"), visibility, container)
+    @@public_methods.concat visibility_info
+    if visibility_default == :public
+      if !cascaded_modules_list.empty?
+        cascaded_modules = 
+          Attr.new("Cascaded Modules",
+                   "Imported modules all of whose components are published again",
+                   "",
+                   cascaded_modules_list.join(", "))
+        container.add_attribute(cascaded_modules)
+      end
+    end
+
+    #
+    # Check rename elements
+    #
+    use_check_code = "#{before_contains_code}"
+    while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
+      use_check_code = $~.pre_match
+      use_check_code << $~.post_match
+      used_mod_name = $1.strip.chomp
+      used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
+      used_elements.split(",").each{ |used|
+        if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
+          local = $1
+          org = $2
+          @@public_methods.collect!{ |pub_meth|
+            if local == pub_meth["name"] ||
+                local.upcase == pub_meth["name"].upcase &&
+                @options.ignore_case
+              pub_meth["name"] = org
+              pub_meth["local_name"] = local
+            end
+            pub_meth
+          }
+        end
+      }
+    end
+
+    #
+    # Parse private "use"
+    #
+    use_check_code = remaining_lines.join("\n")
+    while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
+      use_check_code = $~.pre_match
+      use_check_code << $~.post_match
+      used_mod_name = $1.strip.chomp
+      used_trailing = $3 || ""
+      next if used_trailing =~ /!:nodoc:/
+      if !container.include_includes?(used_mod_name, @options.ignore_case)
+        # progress "." # HACK what stats thingy does this correspond to?
+        container.add_include Include.new(used_mod_name, "")
+      end
+    end
+
+    container.each_includes{ |inc|
+      TopLevel.all_files.each do |name, toplevel|
+        indicated_mod = toplevel.find_symbol(inc.name,
+                                             nil, @options.ignore_case)
+        if indicated_mod
+          indicated_name = indicated_mod.parent.file_relative_name
+          if !container.include_requires?(indicated_name, @options.ignore_case)
+            container.add_require(Require.new(indicated_name, ""))
+          end
+          break
+        end
+      end
+    }
+
+    #
+    # Parse derived-types definitions
+    #
+    derived_types_comment = ""
+    remaining_code = remaining_lines.join("\n")
+    while remaining_code =~ /^\s*?
+                                  type[\s\,]+(public|private)?\s*?(::)?\s*?
+                                  (\w+)\s*?(!.*?)?$
+                                  (.*?)
+                                  ^\s*?end\s+type.*?$
+                            /imx
+      remaining_code = $~.pre_match
+      remaining_code << $~.post_match
+      typename = $3.chomp.strip
+      type_elements = $5 || ""
+      type_code = remove_empty_head_lines($&)
+      type_trailing = find_comments($4)
+      next if type_trailing =~ /^:nodoc:/
+      type_visibility = $1
+      type_comment = COMMENTS_ARE_UPPER ? 
+        find_comments($~.pre_match) + "\n" + type_trailing :
+          type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
+      type_element_visibility_public = true
+      type_code.split("\n").each{ |line|
+        if /^\s*?private\s*?$/ =~ line
+          type_element_visibility_public = nil
+          break
+        end
+      } if type_code
+
+      args_comment = ""
+      type_args_info = nil
+
+      if @options.show_all
+        args_comment = find_arguments(nil, type_code, true)
+      else
+        type_public_args_list = []
+        type_args_info = definition_info(type_code)
+        type_args_info.each{ |arg|
+          arg_is_public = type_element_visibility_public
+          arg_is_public = true if arg.include_attr?("public")
+          arg_is_public = nil if arg.include_attr?("private")
+          type_public_args_list << arg.varname if arg_is_public
+        }
+        args_comment = find_arguments(type_public_args_list, type_code)
+      end
+
+      type = AnyMethod.new("type #{typename}", typename)
+      type.singleton = false
+      type.params = ""
+      type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
+      type.comment << args_comment if args_comment
+      type.comment << type_comment if type_comment
+
+      @stats.add_method type
+
+      container.add_method type
+
+      set_visibility(container, typename, visibility_default, @@public_methods)
+
+      if type_visibility
+        type_visibility.gsub!(/\s/,'')
+        type_visibility.gsub!(/\,/,'')
+        type_visibility.gsub!(/:/,'')
+        type_visibility.downcase!
+        if type_visibility == "public"
+          container.set_visibility_for([typename], :public)
+        elsif type_visibility == "private"
+          container.set_visibility_for([typename], :private)
+        end
+      end
+
+      check_public_methods(type, container.name)
+
+      if @options.show_all
+        derived_types_comment << ", " unless derived_types_comment.empty?
+        derived_types_comment << typename
+      else
+        if type.visibility == :public
+        derived_types_comment << ", " unless derived_types_comment.empty?
+        derived_types_comment << typename
+        end
+      end
+
+    end
+
+    if !derived_types_comment.empty?
+      derived_types_table = 
+        Attr.new("Derived Types", "Derived_Types", "", 
+                 derived_types_comment)
+      container.add_attribute(derived_types_table)
+    end
+
+    #
+    # move interface scope
+    #
+    interface_code = ""
+    while remaining_code =~ /^\s*?
+                                 interface(
+                                            \s+\w+                      |
+                                            \s+operator\s*?\(.*?\)       |
+                                            \s+assignment\s*?\(\s*?=\s*?\)
+                                          )?\s*?$
+                                 (.*?)
+                                 ^\s*?end\s+interface.*?$
+                            /imx
+      interface_code << remove_empty_head_lines($&) + "\n"
+      remaining_code = $~.pre_match
+      remaining_code << $~.post_match
+    end
+
+    #
+    # Parse global constants or variables in modules
+    #
+    const_var_defs = definition_info(before_contains_code)
+    const_var_defs.each{|defitem|
+      next if defitem.nodoc
+      const_or_var_type = "Variable"
+      const_or_var_progress = "v"
+      if defitem.include_attr?("parameter")
+        const_or_var_type = "Constant"
+        const_or_var_progress = "c"
+      end
+      const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
+      const_or_var.singleton = false
+      const_or_var.params = ""
+      self_comment = find_arguments([defitem.varname], before_contains_code)
+      const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
+      const_or_var.comment << self_comment if self_comment
+
+      @stats.add_method const_or_var_progress
+
+      container.add_method const_or_var
+
+      set_visibility(container, defitem.varname, visibility_default, @@public_methods)
+
+      if defitem.include_attr?("public")
+        container.set_visibility_for([defitem.varname], :public)
+      elsif defitem.include_attr?("private")
+        container.set_visibility_for([defitem.varname], :private)
+      end
+
+      check_public_methods(const_or_var, container.name)
+
+    } if const_var_defs
+
+    remaining_lines = remaining_code.split("\n")
+
+    # "subroutine" or "function" parts are parsed (new)
+    #
+    level_depth = 0
+    block_searching_flag = nil
+    block_searching_lines = []
+    pre_comment = []
+    procedure_trailing = ""
+    procedure_name = ""
+    procedure_params = ""
+    procedure_prefix = ""
+    procedure_result_arg = ""
+    procedure_type = ""
+    contains_lines = []
+    contains_flag = nil
+    remaining_lines.collect!{|line|
+      if !block_searching_flag
+        # subroutine
+        if line =~ /^\s*?
+                         (recursive|pure|elemental)?\s*?
+                         subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
+                   /ix
+          block_searching_flag = :subroutine
+          block_searching_lines << line
+
+          procedure_name = $2.chomp.strip
+          procedure_params = $3 || ""
+          procedure_prefix = $1 || ""
+          procedure_trailing = $4 || "!"
+          next false
+
+        # function
+        elsif line =~ /^\s*?
+                       (recursive|pure|elemental)?\s*?
+                       (
+                           character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | type\s*?\([\w\s]+?\)\s+
+                         | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | double\s+precision\s+
+                         | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                       )?
+                       function\s+(\w+)\s*?
+                       (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
+                      /ix
+          block_searching_flag = :function
+          block_searching_lines << line
+
+          procedure_prefix = $1 || ""
+          procedure_type = $2 ? $2.chomp.strip : nil
+          procedure_name = $8.chomp.strip
+          procedure_params = $9 || ""
+          procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
+          procedure_trailing = $12 || "!"
+          next false
+        elsif line =~ /^\s*?!\s?(.*)/
+          pre_comment << line
+          next line
+        else
+          pre_comment = []
+          next line
+        end
+      end
+      contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
+      block_searching_lines << line
+      contains_lines << line if contains_flag
+
+      level_depth += 1 if block_start?(line)
+      level_depth -= 1 if block_end?(line)
+      if level_depth >= 0
+        next false
+      end
+
+      # "procedure_code" is formatted.
+      # ":nodoc:" flag is checked.
+      #
+      procedure_code = block_searching_lines.join("\n")
+      procedure_code = remove_empty_head_lines(procedure_code)
+      if procedure_trailing =~ /^!:nodoc:/
+        # next loop to search next block
+        level_depth = 0
+        block_searching_flag = nil
+        block_searching_lines = []
+        pre_comment = []
+        procedure_trailing = ""
+        procedure_name = ""
+        procedure_params = ""
+        procedure_prefix = ""
+        procedure_result_arg = ""
+        procedure_type = ""
+        contains_lines = []
+        contains_flag = nil
+        next false
+      end
+
+      # AnyMethod is created, and added to container
+      #
+      subroutine_function = nil
+      if block_searching_flag == :subroutine
+        subroutine_prefix   = procedure_prefix
+        subroutine_name     = procedure_name
+        subroutine_params   = procedure_params
+        subroutine_trailing = procedure_trailing
+        subroutine_code     = procedure_code
+
+        subroutine_comment = COMMENTS_ARE_UPPER ? 
+          pre_comment.join("\n") + "\n" + subroutine_trailing : 
+            subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
+        subroutine = AnyMethod.new("subroutine", subroutine_name)
+        parse_subprogram(subroutine, subroutine_params,
+                         subroutine_comment, subroutine_code,
+                         before_contains_code, nil, subroutine_prefix)
+
+        @stats.add_method subroutine
+
+        container.add_method subroutine
+        subroutine_function = subroutine
+
+      elsif block_searching_flag == :function
+        function_prefix     = procedure_prefix
+        function_type       = procedure_type
+        function_name       = procedure_name
+        function_params_org = procedure_params
+        function_result_arg = procedure_result_arg
+        function_trailing   = procedure_trailing
+        function_code_org   = procedure_code
+
+        function_comment = COMMENTS_ARE_UPPER ?
+          pre_comment.join("\n") + "\n" + function_trailing :
+            function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
+
+        function_code = "#{function_code_org}"
+        if function_type
+          function_code << "\n" + function_type + " :: " + function_result_arg
+        end
+
+        function_params =
+          function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
+
+        function = AnyMethod.new("function", function_name)
+        parse_subprogram(function, function_params,
+                         function_comment, function_code,
+                         before_contains_code, true, function_prefix)
+
+        # Specific modification due to function
+        function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
+        function.params << " result(" + function_result_arg + ")"
+        function.start_collecting_tokens
+        function.add_token Token.new(1,1).set_text(function_code_org)
+
+        @stats.add_method function
+
+        container.add_method function
+        subroutine_function = function
+
+      end
+
+      # The visibility of procedure is specified
+      #
+      set_visibility(container, procedure_name, 
+                     visibility_default, @@public_methods)
+
+      # The alias for this procedure from external modules
+      #
+      check_external_aliases(procedure_name,
+                             subroutine_function.params,
+                             subroutine_function.comment, subroutine_function) if external
+      check_public_methods(subroutine_function, container.name)
+
+
+      # contains_lines are parsed as private procedures
+      if contains_flag
+        parse_program_or_module(container,
+                                contains_lines.join("\n"), :private)
+      end
+
+      # next loop to search next block
+      level_depth = 0
+      block_searching_flag = nil
+      block_searching_lines = []
+      pre_comment = []
+      procedure_trailing = ""
+      procedure_name = ""
+      procedure_params = ""
+      procedure_prefix = ""
+      procedure_result_arg = ""
+      contains_lines = []
+      contains_flag = nil
+      next false
+    } # End of remaining_lines.collect!{|line|
+
+    # Array remains_lines is converted to String remains_code again
+    #
+    remaining_code = remaining_lines.join("\n")
+
+    #
+    # Parse interface
+    #
+    interface_scope = false
+    generic_name = ""
+    interface_code.split("\n").each{ |line|
+      if /^\s*?
+               interface(
+                          \s+\w+|
+                          \s+operator\s*?\(.*?\)|
+                          \s+assignment\s*?\(\s*?=\s*?\)
+                        )?
+               \s*?(!.*?)?$
+         /ix =~ line
+        generic_name = $1 ? $1.strip.chomp : nil
+        interface_trailing = $2 || "!"
+        interface_scope = true
+        interface_scope = false if interface_trailing =~ /!:nodoc:/
+#        if generic_name =~ /operator\s*?\((.*?)\)/i
+#          operator_name = $1
+#          if operator_name && !operator_name.empty?
+#            generic_name = "#{operator_name}"
+#          end
+#        end
+#        if generic_name =~ /assignment\s*?\((.*?)\)/i
+#          assignment_name = $1
+#          if assignment_name && !assignment_name.empty?
+#            generic_name = "#{assignment_name}"
+#          end
+#        end
+      end
+      if /^\s*?end\s+interface/i =~ line
+        interface_scope = false
+        generic_name = nil
+      end
+      # internal alias
+      if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
+        procedures = $1.strip.chomp
+        procedures_trailing = $2 || "!"
+        next if procedures_trailing =~ /!:nodoc:/
+        procedures.split(",").each{ |proc|
+          proc.strip!
+          proc.chomp!
+          next if generic_name == proc || !generic_name
+          old_meth = container.find_symbol(proc, nil, @options.ignore_case)
+          next if !old_meth
+          nolink = old_meth.visibility == :private ? true : nil
+          nolink = nil if @options.show_all
+          new_meth = 
+             initialize_external_method(generic_name, proc, 
+                                        old_meth.params, nil, 
+                                        old_meth.comment, 
+                                        old_meth.clone.token_stream[0].text, 
+                                        true, nolink)
+          new_meth.singleton = old_meth.singleton
+
+          @stats.add_method new_meth
+
+          container.add_method new_meth
+
+          set_visibility(container, generic_name, visibility_default, @@public_methods)
+
+          check_public_methods(new_meth, container.name)
+
+        }
+      end
+
+      # external aliases
+      if interface_scope
+        # subroutine
+        proc = nil
+        params = nil
+        procedures_trailing = nil
+        if line =~ /^\s*?
+                         (recursive|pure|elemental)?\s*?
+                         subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
+                   /ix
+          proc = $2.chomp.strip
+          generic_name = proc unless generic_name
+          params = $3 || ""
+          procedures_trailing = $4 || "!"
+
+        # function
+        elsif line =~ /^\s*?
+                       (recursive|pure|elemental)?\s*?
+                       (
+                           character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | type\s*?\([\w\s]+?\)\s+
+                         | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | double\s+precision\s+
+                         | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                         | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                       )?
+                       function\s+(\w+)\s*?
+                       (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
+                      /ix
+          proc = $8.chomp.strip
+          generic_name = proc unless generic_name
+          params = $9 || ""
+          procedures_trailing = $12 || "!"
+        else
+          next
+        end
+        next if procedures_trailing =~ /!:nodoc:/
+        indicated_method = nil
+        indicated_file   = nil
+        TopLevel.all_files.each do |name, toplevel|
+          indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
+          indicated_file = name
+          break if indicated_method
+        end
+
+        if indicated_method
+          external_method = 
+            initialize_external_method(generic_name, proc, 
+                                       indicated_method.params, 
+                                       indicated_file, 
+                                       indicated_method.comment)
+
+          @stats.add_method external_method
+
+          container.add_method external_method
+          set_visibility(container, generic_name, visibility_default, @@public_methods)
+          if !container.include_requires?(indicated_file, @options.ignore_case)
+            container.add_require(Require.new(indicated_file, ""))
+          end
+          check_public_methods(external_method, container.name)
+
+        else
+          @@external_aliases << {
+            "new_name"  => generic_name,
+            "old_name"  => proc,
+            "file_or_module" => container,
+            "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
+          }
+        end
+      end
+
+    } if interface_code # End of interface_code.split("\n").each ...
+
+    #
+    # Already imported methods are removed from @@public_methods.
+    # Remainders are assumed to be imported from other modules.
+    #
+    @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
+
+    @@public_methods.each{ |pub_meth|
+      next unless pub_meth["file_or_module"].name == container.name
+      pub_meth["used_modules"].each{ |used_mod|
+        TopLevel.all_classes_and_modules.each{ |modules|
+          if modules.name == used_mod ||
+              modules.name.upcase == used_mod.upcase &&
+              @options.ignore_case
+            modules.method_list.each{ |meth|
+              if meth.name == pub_meth["name"] ||
+                  meth.name.upcase == pub_meth["name"].upcase &&
+                  @options.ignore_case
+                new_meth = initialize_public_method(meth,
+                                                    modules.name)
+                if pub_meth["local_name"]
+                  new_meth.name = pub_meth["local_name"]
+                end
+
+                @stats.add_method new_meth
+
+                container.add_method new_meth
+              end
+            }
+          end
+        }
+      }
+    }
+
+    container
+  end  # End of parse_program_or_module
+
+  ##
+  # Parse arguments, comment, code of subroutine and function.  Return
+  # AnyMethod object.
+
+  def parse_subprogram(subprogram, params, comment, code, 
+                       before_contains=nil, function=nil, prefix=nil)
+    subprogram.singleton = false
+    prefix = "" if !prefix
+    arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
+    args_comment, params_opt = 
+      find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
+                     nil, nil, true)
+    params_opt = "( " + params_opt + " ) " if params_opt
+    subprogram.params = params_opt || ""
+    namelist_comment = find_namelists(code, before_contains)
+
+    block_comment = find_comments comment
+    if function
+      subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
+    else
+      subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
+    end
+    subprogram.comment << args_comment if args_comment
+    subprogram.comment << block_comment if block_comment
+    subprogram.comment << namelist_comment if namelist_comment
+
+    # For output source code
+    subprogram.start_collecting_tokens
+    subprogram.add_token Token.new(1,1).set_text(code)
+
+    subprogram
+  end
+
+  ##
+  # Collect comment for file entity
+
+  def collect_first_comment(body)
+    comment = ""
+    not_comment = ""
+    comment_start = false
+    comment_end   = false
+    body.split("\n").each{ |line|
+      if comment_end
+        not_comment << line
+        not_comment << "\n"
+      elsif /^\s*?!\s?(.*)$/i =~ line
+        comment_start = true
+        comment << $1
+        comment << "\n"
+      elsif /^\s*?$/i =~ line
+        comment_end = true if comment_start && COMMENTS_ARE_UPPER
+      else
+        comment_end = true
+        not_comment << line
+        not_comment << "\n"
+      end
+    }
+    return comment, not_comment
+  end
+
+
+  ##
+  # Return comments of definitions of arguments
+  #
+  # If "all" argument is true, information of all arguments are returned.
+  #
+  # If "modified_params" is true, list of arguments are decorated, for
+  # example, optional arguments are parenthetic as "[arg]".
+
+  def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
+    return unless args || all
+    indent = "" unless indent
+    args = ["all"] if all
+    params = "" if modified_params
+    comma = ""
+    return unless text
+    args_rdocforms = "\n"
+    remaining_lines = "#{text}"
+    definitions = definition_info(remaining_lines)
+    args.each{ |arg|
+      arg.strip!
+      arg.chomp!
+      definitions.each { |defitem|
+        if arg == defitem.varname.strip.chomp || all
+          args_rdocforms << <<-"EOF"
+
+#{indent}<tt><b>#{defitem.varname.chomp.strip}#{defitem.arraysuffix}</b> #{defitem.inivalue}</tt> :: 
+#{indent}   <tt>#{defitem.types.chomp.strip}</tt>
+EOF
+          if !defitem.comment.chomp.strip.empty?
+            comment = ""
+            defitem.comment.split("\n").each{ |line|
+              comment << "       " + line + "\n"
+            }
+            args_rdocforms << <<-"EOF"
+
+#{indent}   <tt></tt> :: 
+#{indent}       <tt></tt>
+#{indent}       #{comment.chomp.strip}
+EOF
+          end
+
+          if modified_params
+            if defitem.include_attr?("optional")
+              params << "#{comma}[#{arg}]"
+            else
+              params << "#{comma}#{arg}"
+            end
+            comma = ", "
+          end
+        end
+      }
+    }
+    if modified_params
+      return args_rdocforms, params
+    else
+      return args_rdocforms
+    end
+  end
+
+  ##
+  # Return comments of definitions of namelists
+
+  def find_namelists(text, before_contains=nil)
+    return nil if !text
+    result = ""
+    lines = "#{text}"
+    before_contains = "" if !before_contains
+    while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i
+      lines = $~.post_match
+      nml_comment = COMMENTS_ARE_UPPER ? 
+          find_comments($~.pre_match) : find_comments($~.post_match)
+      nml_name = $1
+      nml_args = $2.split(",")
+      result << "\n\n=== NAMELIST <tt><b>" + nml_name + "</tt></b>\n\n"
+      result << nml_comment + "\n" if nml_comment
+      if lines.split("\n")[0] =~ /^\//i
+        lines = "namelist " + lines
+      end
+      result << find_arguments(nml_args, "#{text}" + "\n" + before_contains)
+    end
+    return result
+  end
+
+  ##
+  # Comments just after module or subprogram, or arguments are returned. If
+  # "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms
+  # are returnd
+
+  def find_comments text
+    return "" unless text
+    lines = text.split("\n")
+    lines.reverse! if COMMENTS_ARE_UPPER
+    comment_block = Array.new
+    lines.each do |line|
+      break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
+      if COMMENTS_ARE_UPPER
+        comment_block.unshift line.sub(/^\s*?!\s?/,"")
+      else
+        comment_block.push line.sub(/^\s*?!\s?/,"")
+      end
+    end
+    nice_lines = comment_block.join("\n").split "\n\s*?\n"
+    nice_lines[0] ||= ""
+    nice_lines.shift
+  end
+
+  ##
+  # Create method for internal alias
+
+  def initialize_public_method(method, parent)
+    return if !method || !parent
+
+    new_meth = AnyMethod.new("External Alias for module", method.name)
+    new_meth.singleton    = method.singleton
+    new_meth.params       = method.params.clone
+    new_meth.comment      = remove_trailing_alias(method.comment.clone)
+    new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
+
+    return new_meth
+  end
+
+  ##
+  # Create method for external alias
+  #
+  # If argument "internal" is true, file is ignored.
+
+  def initialize_external_method(new, old, params, file, comment, token=nil,
+                                 internal=nil, nolink=nil)
+    return nil unless new || old
+
+    if internal
+      external_alias_header = "#{INTERNAL_ALIAS_MES} "
+      external_alias_text   = external_alias_header + old 
+    elsif file
+      external_alias_header = "#{EXTERNAL_ALIAS_MES} "
+      external_alias_text   = external_alias_header + file + "#" + old
+    else
+      return nil
+    end
+    external_meth = AnyMethod.new(external_alias_text, new)
+    external_meth.singleton    = false
+    external_meth.params       = params
+    external_comment = remove_trailing_alias(comment) + "\n\n" if comment
+    external_meth.comment = external_comment || ""
+    if nolink && token
+      external_meth.start_collecting_tokens
+      external_meth.add_token Token.new(1,1).set_text(token)
+    else
+      external_meth.comment << external_alias_text
+    end
+
+    return external_meth
+  end
+
+  ##
+  # Parse visibility
+
+  def parse_visibility(code, default, container)
+    result = []
+    visibility_default = default || :public
+
+    used_modules = []
+    container.includes.each{|i| used_modules << i.name} if container
+
+    remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
+    remaining_code.split("\n").each{ |line|
+      if /^\s*?private\s*?$/ =~ line
+        visibility_default = :private
+        break
+      end
+    } if remaining_code
+
+    remaining_code.split("\n").each{ |line|
+      if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
+        methods = $2.sub(/!.*$/, '')
+        methods.split(",").each{ |meth|
+          meth.sub!(/!.*$/, '')
+          meth.gsub!(/:/, '')
+          result << {
+            "name" => meth.chomp.strip,
+            "visibility" => :private,
+            "used_modules" => used_modules.clone,
+            "file_or_module" => container,
+            "entity_is_discovered" => nil,
+            "local_name" => nil
+          }
+        }
+      elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
+        methods = $2.sub(/!.*$/, '')
+        methods.split(",").each{ |meth|
+          meth.sub!(/!.*$/, '')
+          meth.gsub!(/:/, '')
+          result << {
+            "name" => meth.chomp.strip,
+            "visibility" => :public,
+            "used_modules" => used_modules.clone,
+            "file_or_module" => container,
+            "entity_is_discovered" => nil,
+            "local_name" => nil
+          }
+        }
+      end
+    } if remaining_code
+
+    if container
+      result.each{ |vis_info|
+        vis_info["parent"] = container.name
+      }
+    end
+
+    return visibility_default, result
+  end
+
+  ##
+  # Set visibility
+  #
+  # "subname" element of "visibility_info" is deleted.
+
+  def set_visibility(container, subname, visibility_default, visibility_info)
+    return unless container || subname || visibility_default || visibility_info
+    not_found = true
+    visibility_info.collect!{ |info|
+      if info["name"] == subname ||
+          @options.ignore_case && info["name"].upcase == subname.upcase
+        if info["file_or_module"].name == container.name
+          container.set_visibility_for([subname], info["visibility"])
+          info["entity_is_discovered"] = true
+          not_found = false
+        end
+      end
+      info
+    }
+    if not_found
+      return container.set_visibility_for([subname], visibility_default)
+    else
+      return container
+    end
+  end
+
+  ##
+  # Find visibility
+
+  def find_visibility(container, subname, visibility_info)
+    return nil if !subname || !visibility_info
+    visibility_info.each{ |info|
+      if info["name"] == subname ||
+          @options.ignore_case && info["name"].upcase == subname.upcase
+        if info["parent"] == container.name
+          return info["visibility"]
+        end
+      end
+    }
+    return nil
+  end
+
+  ##
+  # Check external aliases
+
+  def check_external_aliases(subname, params, comment, test=nil)
+    @@external_aliases.each{ |alias_item|
+      if subname == alias_item["old_name"] ||
+                  subname.upcase == alias_item["old_name"].upcase &&
+                          @options.ignore_case
+
+        new_meth = initialize_external_method(alias_item["new_name"], 
+                                              subname, params, @file_name, 
+                                              comment)
+        new_meth.visibility = alias_item["visibility"]
+
+        @stats.add_method new_meth
+
+        alias_item["file_or_module"].add_method(new_meth)
+
+        if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
+          alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
+        end
+      end
+    }
+  end
+
+  ##
+  # Check public_methods
+
+  def check_public_methods(method, parent)
+    return if !method || !parent
+    @@public_methods.each{ |alias_item|
+      parent_is_used_module = nil
+      alias_item["used_modules"].each{ |used_module|
+        if used_module == parent ||
+            used_module.upcase == parent.upcase &&
+            @options.ignore_case
+          parent_is_used_module = true
+        end
+      }
+      next if !parent_is_used_module
+
+      if method.name == alias_item["name"] ||
+          method.name.upcase == alias_item["name"].upcase &&
+          @options.ignore_case
+
+        new_meth = initialize_public_method(method, parent)
+        if alias_item["local_name"]
+          new_meth.name = alias_item["local_name"]
+        end
+
+        @stats.add_method new_meth
+
+        alias_item["file_or_module"].add_method new_meth
+      end
+    }
+  end
+
+  ##
+  # Continuous lines are united.
+  #
+  # Comments in continuous lines are removed.
+
+  def united_to_one_line(f90src)
+    return "" unless f90src
+    lines = f90src.split("\n")
+    previous_continuing = false
+    now_continuing = false
+    body = ""
+    lines.each{ |line|
+      words = line.split("")
+      next if words.empty? && previous_continuing
+      commentout = false
+      brank_flag = true ; brank_char = ""
+      squote = false    ; dquote = false
+      ignore = false
+      words.collect! { |char|
+        if previous_continuing && brank_flag
+          now_continuing = true
+          ignore         = true
+          case char
+          when "!"                       ; break
+          when " " ; brank_char << char  ; next ""
+          when "&"
+            brank_flag = false
+            now_continuing = false
+            next ""
+          else 
+            brank_flag     = false
+            now_continuing = false
+            ignore         = false
+            next brank_char + char
+          end
+        end
+        ignore = false
+
+        if now_continuing
+          next ""
+        elsif !(squote) && !(dquote) && !(commentout)
+          case char
+          when "!" ; commentout = true     ; next char
+          when "\""; dquote = true         ; next char
+          when "\'"; squote = true         ; next char
+          when "&" ; now_continuing = true ; next ""
+          else next char
+          end
+        elsif commentout
+          next char
+        elsif squote
+          case char
+          when "\'"; squote = false ; next char
+          else next char
+          end
+        elsif dquote
+          case char
+          when "\""; dquote = false ; next char
+          else next char
+          end
+        end
+      }
+      if !ignore && !previous_continuing || !brank_flag
+        if previous_continuing
+          body << words.join("")
+        else
+          body << "\n" + words.join("")
+        end
+      end
+      previous_continuing = now_continuing ? true : nil
+      now_continuing = nil
+    }
+    return body
+  end
+
+
+  ##
+  # Continuous line checker
+
+  def continuous_line?(line)
+    continuous = false
+    if /&\s*?(!.*)?$/ =~ line
+      continuous = true
+      if comment_out?($~.pre_match)
+        continuous = false
+      end
+    end
+    return continuous
+  end
+
+  ##
+  # Comment out checker
+
+  def comment_out?(line)
+    return nil unless line
+    commentout = false
+    squote = false ; dquote = false
+    line.split("").each { |char|
+      if !(squote) && !(dquote)
+        case char
+        when "!" ; commentout = true ; break
+        when "\""; dquote = true
+        when "\'"; squote = true
+        else next
+        end
+      elsif squote
+        case char
+        when "\'"; squote = false
+        else next
+        end
+      elsif dquote
+        case char
+        when "\""; dquote = false
+        else next
+        end
+      end
+    }
+    return commentout
+  end
+
+  ##
+  # Semicolons are replaced to line feed.
+
+  def semicolon_to_linefeed(text)
+    return "" unless text
+    lines = text.split("\n")
+    lines.collect!{ |line|
+      words = line.split("")
+      commentout = false
+      squote = false ; dquote = false
+      words.collect! { |char|
+        if !(squote) && !(dquote) && !(commentout)
+          case char
+          when "!" ; commentout = true ; next char
+          when "\""; dquote = true     ; next char
+          when "\'"; squote = true     ; next char
+          when ";" ;                     "\n"
+          else next char
+          end
+        elsif commentout
+          next char
+        elsif squote
+          case char
+          when "\'"; squote = false ; next char
+          else next char
+          end
+        elsif dquote
+          case char
+          when "\""; dquote = false ; next char
+          else next char
+          end
+        end
+      }
+      words.join("")
+    }
+    return lines.join("\n")
+  end
+
+  ##
+  # Which "line" is start of block (module, program, block data, subroutine,
+  # function) statement ?
+
+  def block_start?(line)
+    return nil if !line
+
+    if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
+        line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
+        line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
+        line =~ \
+                /^\s*?
+                 (recursive|pure|elemental)?\s*?
+                 subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
+                /ix ||
+        line =~ \
+                /^\s*?
+                 (recursive|pure|elemental)?\s*?
+                 (
+                     character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                   | type\s*?\([\w\s]+?\)\s+
+                   | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                   | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                   | double\s+precision\s+
+                   | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                   | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
+                 )?
+                 function\s+(\w+)\s*?
+                 (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
+                /ix
+      return true
+    end
+
+    return nil
+  end
+
+  ##
+  # Which "line" is end of block (module, program, block data, subroutine,
+  # function) statement ?
+
+  def block_end?(line)
+    return nil if !line
+
+    if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
+        line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
+        line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
+        line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
+        line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
+        line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
+      return true
+    end
+
+    return nil
+  end
+
+  ##
+  # Remove "Alias for" in end of comments
+
+  def remove_trailing_alias(text)
+    return "" if !text
+    lines = text.split("\n").reverse
+    comment_block = Array.new
+    checked = false
+    lines.each do |line|
+      if !checked 
+        if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
+            /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
+          checked = true
+          next
+        end
+      end
+      comment_block.unshift line
+    end
+    nice_lines = comment_block.join("\n")
+    nice_lines ||= ""
+    return nice_lines
+  end
+
+  ##
+  # Empty lines in header are removed
+
+  def remove_empty_head_lines(text)
+    return "" unless text
+    lines = text.split("\n")
+    header = true
+    lines.delete_if{ |line|
+      header = false if /\S/ =~ line
+      header && /^\s*?$/ =~ line
+    }
+    lines.join("\n")
+  end
+
+  ##
+  # header marker "=", "==", ... are removed
+
+  def remove_header_marker(text)
+    return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
+  end
+
+  def remove_private_comments(body)
+    body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '')
+    return body
+  end
+
+  ##
+  # Information of arguments of subroutines and functions in Fortran95
+
+  class Fortran95Definition
+
+    # Name of variable
+    #
+    attr_reader   :varname
+
+    # Types of variable
+    #
+    attr_reader   :types
+
+    # Initial Value
+    #
+    attr_reader   :inivalue
+
+    # Suffix of array
+    #
+    attr_reader   :arraysuffix
+
+    # Comments
+    #
+    attr_accessor   :comment
+
+    # Flag of non documentation
+    #
+    attr_accessor   :nodoc
+
+    def initialize(varname, types, inivalue, arraysuffix, comment,
+                   nodoc=false)
+      @varname = varname
+      @types = types
+      @inivalue = inivalue
+      @arraysuffix = arraysuffix
+      @comment = comment
+      @nodoc = nodoc
+    end
+
+    def to_s
+      return <<-EOF
+<Fortran95Definition: 
+varname=#{@varname}, types=#{types},
+inivalue=#{@inivalue}, arraysuffix=#{@arraysuffix}, nodoc=#{@nodoc}, 
+comment=
+#{@comment}
+>
+EOF
+    end
+
+    #
+    # If attr is included, true is returned
+    #
+    def include_attr?(attr)
+      return if !attr
+      @types.split(",").each{ |type|
+        return true if type.strip.chomp.upcase == attr.strip.chomp.upcase
+      }
+      return nil
+    end
+
+  end # End of Fortran95Definition
+
+  ##
+  # Parse string argument "text", and Return Array of Fortran95Definition
+  # object
+
+  def definition_info(text)
+    return nil unless text
+    lines = "#{text}"
+    defs = Array.new
+    comment = ""
+    trailing_comment = ""
+    under_comment_valid = false
+    lines.split("\n").each{ |line|
+      if /^\s*?!\s?(.*)/ =~ line
+        if COMMENTS_ARE_UPPER
+          comment << remove_header_marker($1)
+          comment << "\n"
+        elsif defs[-1] && under_comment_valid
+          defs[-1].comment << "\n"
+          defs[-1].comment << remove_header_marker($1)
+        end
+        next
+      elsif /^\s*?$/ =~ line
+        comment = ""
+        under_comment_valid = false
+        next
+      end
+      type = ""
+      characters = ""
+      if line =~ /^\s*?
+                  (
+                      character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
+                    | type\s*?\([\w\s]+?\)[\s\,]*
+                    | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
+                    | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
+                    | double\s+precision[\s\,]*
+                    | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
+                    | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
+                  )
+                  (.*?::)?
+                  (.+)$
+                 /ix
+        characters = $8
+        type = $1
+        type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
+      else
+        under_comment_valid = false
+        next
+      end
+      squote = false ; dquote = false ; bracket = 0
+      iniflag = false; commentflag = false
+      varname = "" ; arraysuffix = "" ; inivalue = ""
+      start_pos = defs.size
+      characters.split("").each { |char|
+        if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
+          case char
+          when "!" ; commentflag = true
+          when "(" ; bracket += 1       ; arraysuffix = char
+          when "\""; dquote = true
+          when "\'"; squote = true
+          when "=" ; iniflag = true     ; inivalue << char
+          when ","
+            defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
+            varname = "" ; arraysuffix = "" ; inivalue = ""
+            under_comment_valid = true
+          when " " ; next
+          else     ; varname << char
+          end
+        elsif commentflag
+          comment << remove_header_marker(char)
+          trailing_comment << remove_header_marker(char)
+        elsif iniflag
+          if dquote
+            case char
+            when "\"" ; dquote = false ; inivalue << char
+            else      ; inivalue << char
+            end
+          elsif squote
+            case char
+            when "\'" ; squote = false ; inivalue << char
+            else      ; inivalue << char
+            end
+          elsif bracket > 0
+            case char
+            when "(" ; bracket += 1 ; inivalue << char
+            when ")" ; bracket -= 1 ; inivalue << char
+            else     ; inivalue << char
+            end
+          else
+            case char
+            when ","
+              defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
+              varname = "" ; arraysuffix = "" ; inivalue = ""
+              iniflag = false
+              under_comment_valid = true
+            when "(" ; bracket += 1 ; inivalue << char
+            when "\""; dquote = true  ; inivalue << char
+            when "\'"; squote = true  ; inivalue << char
+            when "!" ; commentflag = true
+            else     ; inivalue << char
+            end
+          end
+        elsif !(squote) && !(dquote) && bracket > 0
+          case char
+          when "(" ; bracket += 1 ; arraysuffix << char
+          when ")" ; bracket -= 1 ; arraysuffix << char
+          else     ; arraysuffix << char
+          end
+        elsif squote
+          case char
+          when "\'"; squote = false ; inivalue << char
+          else     ; inivalue << char
+          end
+        elsif dquote
+          case char
+          when "\""; dquote = false ; inivalue << char
+          else     ; inivalue << char
+          end
+        end
+      }
+      defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
+      if trailing_comment =~ /^:nodoc:/
+        defs[start_pos..-1].collect!{ |defitem|
+          defitem.nodoc = true
+        }
+      end
+      varname = "" ; arraysuffix = "" ; inivalue = ""
+      comment = ""
+      under_comment_valid = true
+      trailing_comment = ""
+    }
+    return defs
+  end
+
+end
+

Deleted: MacRuby/branches/experimental/lib/rdoc/parser/perl.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/parser/perl.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/parser/perl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,165 +0,0 @@
-require 'rdoc/parser'
-
-##
-#
-# This is an attamept to write a basic parser for Perl's
-# POD (Plain old Documentation) format.  Ruby code must
-# co-exist with Perl, and some tasks are easier in Perl
-# than Ruby because of existing libraries.
-#
-# One difficult is that Perl POD has no means of identifying
-# the classes (packages) and methods (subs) with which it
-# is associated, it is more like literate programming in so
-# far as it just happens to be in the same place as the code,
-# but need not be.
-#
-# We would like to support all the markup the POD provides
-# so that it will convert happily to HTML.  At the moment
-# I don't think I can do that: time constraints. 
-#
-
-class RDoc::Parser::PerlPOD < RDoc::Parser
-
-  parse_files_matching(/.p[lm]$/)
-
-  ##
-  # Prepare to parse a perl file
-
-  def initialize(top_level, file_name, content, options, stats)
-    super
-
-    preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
-
-    preprocess.handle @content do |directive, param|
-      warn "Unrecognized directive '#{directive}' in #{@file_name}"
-    end
-  end
-
-  ##
-  # Extract the Pod(-like) comments from the code.
-  # At its most basic there will ne no need to distinguish
-  # between the different types of header, etc.
-  #
-  # This uses a simple finite state machine, in a very
-  # procedural pattern. I could "replace case with polymorphism"
-  # but I think it would obscure the intent, scatter the
-  # code all over tha place.  This machine is necessary
-  # because POD requires that directives be preceded by
-  # blank lines, so reading line by line is necessary, 
-  # and preserving state about what is seen is necesary.
-
-  def scan
-
-    @top_level.comment ||= ""
-    state=:code_blank    
-    line_number = 0
-    line = nil
-
-    # This started out as a really long nested case statement,
-    # which also led to repetitive code.  I'd like to avoid that
-    # so I'm using a "table" instead.
-    
-    # Firstly we need some procs to do the transition and processing
-    # work.  Because these are procs they are closures, and they can
-    # use variables in the local scope.
-    #
-    # First, the "nothing to see here" stuff.
-    code_noop = lambda do 
-      if line =~ /^\s+$/
-	state = :code_blank
-      end
-    end
-
-    pod_noop = lambda do 
-      if line =~ /^\s+$/
-	state = :pod_blank
-      end
-      @top_level.comment += filter(line)
-    end
-
-    begin_noop = lambda do 
-      if line =~ /^\s+$/
-	state = :begin_blank
-      end
-      @top_level.comment += filter(line)
-    end
-
-    # Now for the blocks that process code and comments...
-
-    transit_to_pod = lambda do
-      case line
-      when /^=(?:pod|head\d+)/
-	state = :pod_no_blank
-	@top_level.comment += filter(line)
-      when /^=over/
-	state = :over_no_blank
-	@top_level.comment += filter(line)
-      when /^=(?:begin|for)/
-	state = :begin_no_blank
-      end
-    end
-
-    process_pod = lambda do
-      case line
-      when  /^\s*$/
-	state = :pod_blank
-	@top_level.comment += filter(line)
-      when /^=cut/
-	state = :code_no_blank
-      when /^=end/
-	$stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}"
-      else
-	@top_level.comment += filter(line)
-      end
-    end
-
-
-    process_begin = lambda do
-      case line
-      when  /^\s*$/
-	state = :begin_blank
-	@top_level.comment += filter(line)
-      when /^=end/
-	state = :code_no_blank
-      when /^=cut/
-	$stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}"
-      else
-	@top_level.comment += filter(line)
-      end
-
-    end
-
-
-    transitions = { :code_no_blank => code_noop,
-                    :code_blank => transit_to_pod,
-		    :pod_no_blank => pod_noop,
-		    :pod_blank => process_pod,
-		    :begin_no_blank => begin_noop,
-		    :begin_blank => process_begin}
-    @content.each_line do |l|
-      line = l
-      line_number += 1
-      transitions[state].call
-    end # each line
-
-    @top_level
-  end
-
-  # Filter the perl markup that does the same as the rdoc
-  # filtering.  Only basic for now. Will probably need a
-  # proper parser to cope with C<<...>> etc
-  def filter(comment)
-    return '' if comment =~ /^=pod\s*$/
-    comment.gsub!(/^=pod/, '==')
-    comment.gsub!(/^=head(\d+)/) do 
-      "=" * $1.to_i
-    end
-    comment.gsub!(/=item/, '');
-    comment.gsub!(/C<(.*?)>/, '<tt>\1</tt>');
-    comment.gsub!(/I<(.*?)>/, '<i>\1</i>');
-    comment.gsub!(/B<(.*?)>/, '<b>\1</b>');
-    comment
-  end
-
-end
-

Copied: MacRuby/branches/experimental/lib/rdoc/parser/perl.rb (from rev 1886, MacRuby/trunk/lib/rdoc/parser/perl.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/parser/perl.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/parser/perl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,165 @@
+require 'rdoc/parser'
+
+##
+#
+# This is an attamept to write a basic parser for Perl's
+# POD (Plain old Documentation) format.  Ruby code must
+# co-exist with Perl, and some tasks are easier in Perl
+# than Ruby because of existing libraries.
+#
+# One difficult is that Perl POD has no means of identifying
+# the classes (packages) and methods (subs) with which it
+# is associated, it is more like literate programming in so
+# far as it just happens to be in the same place as the code,
+# but need not be.
+#
+# We would like to support all the markup the POD provides
+# so that it will convert happily to HTML.  At the moment
+# I don't think I can do that: time constraints. 
+#
+
+class RDoc::Parser::PerlPOD < RDoc::Parser
+
+  parse_files_matching(/.p[lm]$/)
+
+  ##
+  # Prepare to parse a perl file
+
+  def initialize(top_level, file_name, content, options, stats)
+    super
+
+    preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
+
+    preprocess.handle @content do |directive, param|
+      warn "Unrecognized directive '#{directive}' in #{@file_name}"
+    end
+  end
+
+  ##
+  # Extract the Pod(-like) comments from the code.
+  # At its most basic there will ne no need to distinguish
+  # between the different types of header, etc.
+  #
+  # This uses a simple finite state machine, in a very
+  # procedural pattern. I could "replace case with polymorphism"
+  # but I think it would obscure the intent, scatter the
+  # code all over tha place.  This machine is necessary
+  # because POD requires that directives be preceded by
+  # blank lines, so reading line by line is necessary, 
+  # and preserving state about what is seen is necesary.
+
+  def scan
+
+    @top_level.comment ||= ""
+    state=:code_blank    
+    line_number = 0
+    line = nil
+
+    # This started out as a really long nested case statement,
+    # which also led to repetitive code.  I'd like to avoid that
+    # so I'm using a "table" instead.
+    
+    # Firstly we need some procs to do the transition and processing
+    # work.  Because these are procs they are closures, and they can
+    # use variables in the local scope.
+    #
+    # First, the "nothing to see here" stuff.
+    code_noop = lambda do 
+      if line =~ /^\s+$/
+	state = :code_blank
+      end
+    end
+
+    pod_noop = lambda do 
+      if line =~ /^\s+$/
+	state = :pod_blank
+      end
+      @top_level.comment += filter(line)
+    end
+
+    begin_noop = lambda do 
+      if line =~ /^\s+$/
+	state = :begin_blank
+      end
+      @top_level.comment += filter(line)
+    end
+
+    # Now for the blocks that process code and comments...
+
+    transit_to_pod = lambda do
+      case line
+      when /^=(?:pod|head\d+)/
+	state = :pod_no_blank
+	@top_level.comment += filter(line)
+      when /^=over/
+	state = :over_no_blank
+	@top_level.comment += filter(line)
+      when /^=(?:begin|for)/
+	state = :begin_no_blank
+      end
+    end
+
+    process_pod = lambda do
+      case line
+      when  /^\s*$/
+	state = :pod_blank
+	@top_level.comment += filter(line)
+      when /^=cut/
+	state = :code_no_blank
+      when /^=end/
+	$stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}"
+      else
+	@top_level.comment += filter(line)
+      end
+    end
+
+
+    process_begin = lambda do
+      case line
+      when  /^\s*$/
+	state = :begin_blank
+	@top_level.comment += filter(line)
+      when /^=end/
+	state = :code_no_blank
+      when /^=cut/
+	$stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}"
+      else
+	@top_level.comment += filter(line)
+      end
+
+    end
+
+
+    transitions = { :code_no_blank => code_noop,
+                    :code_blank => transit_to_pod,
+		    :pod_no_blank => pod_noop,
+		    :pod_blank => process_pod,
+		    :begin_no_blank => begin_noop,
+		    :begin_blank => process_begin}
+    @content.each_line do |l|
+      line = l
+      line_number += 1
+      transitions[state].call
+    end # each line
+
+    @top_level
+  end
+
+  # Filter the perl markup that does the same as the rdoc
+  # filtering.  Only basic for now. Will probably need a
+  # proper parser to cope with C<<...>> etc
+  def filter(comment)
+    return '' if comment =~ /^=pod\s*$/
+    comment.gsub!(/^=pod/, '==')
+    comment.gsub!(/^=head(\d+)/) do 
+      "=" * $1.to_i
+    end
+    comment.gsub!(/=item/, '');
+    comment.gsub!(/C<(.*?)>/, '<tt>\1</tt>');
+    comment.gsub!(/I<(.*?)>/, '<i>\1</i>');
+    comment.gsub!(/B<(.*?)>/, '<b>\1</b>');
+    comment
+  end
+
+end
+

Deleted: MacRuby/branches/experimental/lib/rdoc/parser/ruby.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/parser/ruby.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/parser/ruby.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,2829 +0,0 @@
-##
-# This file contains stuff stolen outright from:
-#
-#   rtags.rb -
-#   ruby-lex.rb - ruby lexcal analyzer
-#   ruby-token.rb - ruby tokens
-#       by Keiju ISHITSUKA (Nippon Rational Inc.)
-#
-
-require 'e2mmap'
-require 'irb/slex'
-
-require 'rdoc/code_objects'
-require 'rdoc/tokenstream'
-require 'rdoc/markup/preprocess'
-require 'rdoc/parser'
-
-$TOKEN_DEBUG ||= nil
-#$TOKEN_DEBUG = $DEBUG_RDOC
-
-##
-# Definitions of all tokens involved in the lexical analysis
-
-module RDoc::RubyToken
-
-  EXPR_BEG   = :EXPR_BEG
-  EXPR_MID   = :EXPR_MID
-  EXPR_END   = :EXPR_END
-  EXPR_ARG   = :EXPR_ARG
-  EXPR_FNAME = :EXPR_FNAME
-  EXPR_DOT   = :EXPR_DOT
-  EXPR_CLASS = :EXPR_CLASS
-
-  class Token
-    NO_TEXT = "??".freeze
-
-    attr_accessor :text
-    attr_reader :line_no
-    attr_reader :char_no
-
-    def initialize(line_no, char_no)
-      @line_no = line_no
-      @char_no = char_no
-      @text    = NO_TEXT
-    end
-
-    def ==(other)
-      self.class == other.class and
-        other.line_no == @line_no and
-        other.char_no == @char_no and
-        other.text == @text
-    end
-
-    ##
-    # Because we're used in contexts that expect to return a token, we set the
-    # text string and then return ourselves
-
-    def set_text(text)
-      @text = text
-      self
-    end
-
-  end
-
-  class TkNode < Token
-    attr :node
-  end
-
-  class TkId < Token
-    def initialize(line_no, char_no, name)
-      super(line_no, char_no)
-      @name = name
-    end
-    attr :name
-  end
-
-  class TkKW < TkId
-  end
-
-  class TkVal < Token
-    def initialize(line_no, char_no, value = nil)
-      super(line_no, char_no)
-      set_text(value)
-    end
-  end
-
-  class TkOp < Token
-    def name
-      self.class.op_name
-    end
-  end
-
-  class TkOPASGN < TkOp
-    def initialize(line_no, char_no, op)
-      super(line_no, char_no)
-      op = TkReading2Token[op] unless Symbol === op
-      @op = op
-    end
-    attr :op
-  end
-
-  class TkUnknownChar < Token
-    def initialize(line_no, char_no, id)
-      super(line_no, char_no)
-      @name = char_no.chr
-    end
-    attr :name
-  end
-
-  class TkError < Token
-  end
-
-  def set_token_position(line, char)
-    @prev_line_no = line
-    @prev_char_no = char
-  end
-
-  def Token(token, value = nil)
-    tk = nil
-    case token
-    when String, Symbol
-      source = String === token ? TkReading2Token : TkSymbol2Token
-      raise TkReading2TokenNoKey, token if (tk = source[token]).nil?
-      tk = Token(tk[0], value)
-    else
-      tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty?
-             token.new(@prev_line_no, @prev_char_no)
-           else
-             token.new(@prev_line_no, @prev_char_no, value)
-           end
-    end
-    tk
-  end
-
-  TokenDefinitions = [
-    [:TkCLASS,      TkKW,  "class",  EXPR_CLASS],
-    [:TkMODULE,     TkKW,  "module", EXPR_CLASS],
-    [:TkDEF,        TkKW,  "def",    EXPR_FNAME],
-    [:TkUNDEF,      TkKW,  "undef",  EXPR_FNAME],
-    [:TkBEGIN,      TkKW,  "begin",  EXPR_BEG],
-    [:TkRESCUE,     TkKW,  "rescue", EXPR_MID],
-    [:TkENSURE,     TkKW,  "ensure", EXPR_BEG],
-    [:TkEND,        TkKW,  "end",    EXPR_END],
-    [:TkIF,         TkKW,  "if",     EXPR_BEG, :TkIF_MOD],
-    [:TkUNLESS,     TkKW,  "unless", EXPR_BEG, :TkUNLESS_MOD],
-    [:TkTHEN,       TkKW,  "then",   EXPR_BEG],
-    [:TkELSIF,      TkKW,  "elsif",  EXPR_BEG],
-    [:TkELSE,       TkKW,  "else",   EXPR_BEG],
-    [:TkCASE,       TkKW,  "case",   EXPR_BEG],
-    [:TkWHEN,       TkKW,  "when",   EXPR_BEG],
-    [:TkWHILE,      TkKW,  "while",  EXPR_BEG, :TkWHILE_MOD],
-    [:TkUNTIL,      TkKW,  "until",  EXPR_BEG, :TkUNTIL_MOD],
-    [:TkFOR,        TkKW,  "for",    EXPR_BEG],
-    [:TkBREAK,      TkKW,  "break",  EXPR_END],
-    [:TkNEXT,       TkKW,  "next",   EXPR_END],
-    [:TkREDO,       TkKW,  "redo",   EXPR_END],
-    [:TkRETRY,      TkKW,  "retry",  EXPR_END],
-    [:TkIN,         TkKW,  "in",     EXPR_BEG],
-    [:TkDO,         TkKW,  "do",     EXPR_BEG],
-    [:TkRETURN,     TkKW,  "return", EXPR_MID],
-    [:TkYIELD,      TkKW,  "yield",  EXPR_END],
-    [:TkSUPER,      TkKW,  "super",  EXPR_END],
-    [:TkSELF,       TkKW,  "self",   EXPR_END],
-    [:TkNIL,        TkKW,  "nil",    EXPR_END],
-    [:TkTRUE,       TkKW,  "true",   EXPR_END],
-    [:TkFALSE,      TkKW,  "false",  EXPR_END],
-    [:TkAND,        TkKW,  "and",    EXPR_BEG],
-    [:TkOR,         TkKW,  "or",     EXPR_BEG],
-    [:TkNOT,        TkKW,  "not",    EXPR_BEG],
-    [:TkIF_MOD,     TkKW],
-    [:TkUNLESS_MOD, TkKW],
-    [:TkWHILE_MOD,  TkKW],
-    [:TkUNTIL_MOD,  TkKW],
-    [:TkALIAS,      TkKW,  "alias",    EXPR_FNAME],
-    [:TkDEFINED,    TkKW,  "defined?", EXPR_END],
-    [:TklBEGIN,     TkKW,  "BEGIN",    EXPR_END],
-    [:TklEND,       TkKW,  "END",      EXPR_END],
-    [:Tk__LINE__,   TkKW,  "__LINE__", EXPR_END],
-    [:Tk__FILE__,   TkKW,  "__FILE__", EXPR_END],
-
-    [:TkIDENTIFIER, TkId],
-    [:TkFID,        TkId],
-    [:TkGVAR,       TkId],
-    [:TkIVAR,       TkId],
-    [:TkCONSTANT,   TkId],
-
-    [:TkINTEGER,    TkVal],
-    [:TkFLOAT,      TkVal],
-    [:TkSTRING,     TkVal],
-    [:TkXSTRING,    TkVal],
-    [:TkREGEXP,     TkVal],
-    [:TkCOMMENT,    TkVal],
-
-    [:TkDSTRING,    TkNode],
-    [:TkDXSTRING,   TkNode],
-    [:TkDREGEXP,    TkNode],
-    [:TkNTH_REF,    TkId],
-    [:TkBACK_REF,   TkId],
-
-    [:TkUPLUS,      TkOp,   "+@"],
-    [:TkUMINUS,     TkOp,   "-@"],
-    [:TkPOW,        TkOp,   "**"],
-    [:TkCMP,        TkOp,   "<=>"],
-    [:TkEQ,         TkOp,   "=="],
-    [:TkEQQ,        TkOp,   "==="],
-    [:TkNEQ,        TkOp,   "!="],
-    [:TkGEQ,        TkOp,   ">="],
-    [:TkLEQ,        TkOp,   "<="],
-    [:TkANDOP,      TkOp,   "&&"],
-    [:TkOROP,       TkOp,   "||"],
-    [:TkMATCH,      TkOp,   "=~"],
-    [:TkNMATCH,     TkOp,   "!~"],
-    [:TkDOT2,       TkOp,   ".."],
-    [:TkDOT3,       TkOp,   "..."],
-    [:TkAREF,       TkOp,   "[]"],
-    [:TkASET,       TkOp,   "[]="],
-    [:TkLSHFT,      TkOp,   "<<"],
-    [:TkRSHFT,      TkOp,   ">>"],
-    [:TkCOLON2,     TkOp],
-    [:TkCOLON3,     TkOp],
-#   [:OPASGN,       TkOp],               # +=, -=  etc. #
-    [:TkASSOC,      TkOp,   "=>"],
-    [:TkQUESTION,   TkOp,   "?"],        #?
-    [:TkCOLON,      TkOp,   ":"],        #:
-
-    [:TkfLPAREN],         # func( #
-    [:TkfLBRACK],         # func[ #
-    [:TkfLBRACE],         # func{ #
-    [:TkSTAR],            # *arg
-    [:TkAMPER],           # &arg #
-    [:TkSYMBOL,     TkId],          # :SYMBOL
-    [:TkSYMBEG,     TkId],
-    [:TkGT,         TkOp,   ">"],
-    [:TkLT,         TkOp,   "<"],
-    [:TkPLUS,       TkOp,   "+"],
-    [:TkMINUS,      TkOp,   "-"],
-    [:TkMULT,       TkOp,   "*"],
-    [:TkDIV,        TkOp,   "/"],
-    [:TkMOD,        TkOp,   "%"],
-    [:TkBITOR,      TkOp,   "|"],
-    [:TkBITXOR,     TkOp,   "^"],
-    [:TkBITAND,     TkOp,   "&"],
-    [:TkBITNOT,     TkOp,   "~"],
-    [:TkNOTOP,      TkOp,   "!"],
-
-    [:TkBACKQUOTE,  TkOp,   "`"],
-
-    [:TkASSIGN,     Token,  "="],
-    [:TkDOT,        Token,  "."],
-    [:TkLPAREN,     Token,  "("],  #(exp)
-    [:TkLBRACK,     Token,  "["],  #[arry]
-    [:TkLBRACE,     Token,  "{"],  #{hash}
-    [:TkRPAREN,     Token,  ")"],
-    [:TkRBRACK,     Token,  "]"],
-    [:TkRBRACE,     Token,  "}"],
-    [:TkCOMMA,      Token,  ","],
-    [:TkSEMICOLON,  Token,  ";"],
-
-    [:TkRD_COMMENT],
-    [:TkSPACE],
-    [:TkNL],
-    [:TkEND_OF_SCRIPT],
-
-    [:TkBACKSLASH,  TkUnknownChar,  "\\"],
-    [:TkAT,         TkUnknownChar,  "@"],
-    [:TkDOLLAR,     TkUnknownChar,  "\$"], #"
-  ]
-
-  # {reading => token_class}
-  # {reading => [token_class, *opt]}
-  TkReading2Token = {}
-  TkSymbol2Token = {}
-
-  def self.def_token(token_n, super_token = Token, reading = nil, *opts)
-    token_n = token_n.id2name unless String === token_n
-
-    fail AlreadyDefinedToken, token_n if const_defined?(token_n)
-
-    token_c =  Class.new super_token
-    const_set token_n, token_c
-#    token_c.inspect
-
-    if reading
-      if TkReading2Token[reading]
-        fail TkReading2TokenDuplicateError, token_n, reading
-      end
-      if opts.empty?
-        TkReading2Token[reading] = [token_c]
-      else
-        TkReading2Token[reading] = [token_c].concat(opts)
-      end
-    end
-    TkSymbol2Token[token_n.intern] = token_c
-
-    if token_c <= TkOp
-      token_c.class_eval %{
-        def self.op_name; "#{reading}"; end
-      }
-    end
-  end
-
-  for defs in TokenDefinitions
-    def_token(*defs)
-  end
-
-  NEWLINE_TOKEN = TkNL.new(0,0)
-  NEWLINE_TOKEN.set_text("\n")
-
-end
-
-##
-# Lexical analyzer for Ruby source
-
-class RDoc::RubyLex
-
-  ##
-  # Read an input stream character by character. We allow for unlimited
-  # ungetting of characters just read.
-  #
-  # We simplify the implementation greatly by reading the entire input
-  # into a buffer initially, and then simply traversing it using
-  # pointers.
-  #
-  # We also have to allow for the <i>here document diversion</i>. This
-  # little gem comes about when the lexer encounters a here
-  # document. At this point we effectively need to split the input
-  # stream into two parts: one to read the body of the here document,
-  # the other to read the rest of the input line where the here
-  # document was initially encountered. For example, we might have
-  #
-  #   do_something(<<-A, <<-B)
-  #     stuff
-  #     for
-  #   A
-  #     stuff
-  #     for
-  #   B
-  #
-  # When the lexer encounters the <<A, it reads until the end of the
-  # line, and keeps it around for later. It then reads the body of the
-  # here document.  Once complete, it needs to read the rest of the
-  # original line, but then skip the here document body.
-  #
-
-  class BufferedReader
-
-    attr_reader :line_num
-
-    def initialize(content, options)
-      @options = options
-
-      if /\t/ =~ content
-        tab_width = @options.tab_width
-        content = content.split(/\n/).map do |line|
-          1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)}  && $~ #`
-          line
-        end .join("\n")
-      end
-      @content   = content
-      @content << "\n" unless @content[-1,1] == "\n"
-      @size      = @content.size
-      @offset    = 0
-      @hwm       = 0
-      @line_num  = 1
-      @read_back_offset = 0
-      @last_newline = 0
-      @newline_pending = false
-    end
-
-    def column
-      @offset - @last_newline
-    end
-
-    def getc
-      return nil if @offset >= @size
-      ch = @content[@offset, 1]
-
-      @offset += 1
-      @hwm = @offset if @hwm < @offset
-
-      if @newline_pending
-        @line_num += 1
-        @last_newline = @offset - 1
-        @newline_pending = false
-      end
-
-      if ch == "\n"
-        @newline_pending = true
-      end
-      ch
-    end
-
-    def getc_already_read
-      getc
-    end
-
-    def ungetc(ch)
-      raise "unget past beginning of file" if @offset <= 0
-      @offset -= 1
-      if @content[@offset] == ?\n
-        @newline_pending = false
-      end
-    end
-
-    def get_read
-      res = @content[@read_back_offset... at offset]
-      @read_back_offset = @offset
-      res
-    end
-
-    def peek(at)
-      pos = @offset + at
-      if pos >= @size
-        nil
-      else
-        @content[pos, 1]
-      end
-    end
-
-    def peek_equal(str)
-      @content[@offset, str.length] == str
-    end
-
-    def divert_read_from(reserve)
-      @content[@offset, 0] = reserve
-      @size      = @content.size
-    end
-  end
-
-  # end of nested class BufferedReader
-
-  extend Exception2MessageMapper
-  def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
-  def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')")
-  def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')")
-  def_exception(:TkReading2TokenDuplicateError,
-                "key duplicate(token_n='%s', key='%s')")
-  def_exception(:SyntaxError, "%s")
-
-  include RDoc::RubyToken
-  include IRB
-
-  attr_reader :continue
-  attr_reader :lex_state
-
-  def self.debug?
-    false
-  end
-
-  def initialize(content, options)
-    lex_init
-
-    @options = options
-
-    @reader = BufferedReader.new content, @options
-
-    @exp_line_no = @line_no = 1
-    @base_char_no = 0
-    @indent = 0
-
-    @ltype = nil
-    @quoted = nil
-    @lex_state = EXPR_BEG
-    @space_seen = false
-
-    @continue = false
-    @line = ""
-
-    @skip_space = false
-    @read_auto_clean_up = false
-    @exception_on_syntax_error = true
-  end
-
-  attr_accessor :skip_space
-  attr_accessor :read_auto_clean_up
-  attr_accessor :exception_on_syntax_error
-  attr_reader :indent
-
-  # io functions
-  def line_no
-    @reader.line_num
-  end
-
-  def char_no
-    @reader.column
-  end
-
-  def get_read
-    @reader.get_read
-  end
-
-  def getc
-    @reader.getc
-  end
-
-  def getc_of_rests
-    @reader.getc_already_read
-  end
-
-  def gets
-    c = getc or return
-    l = ""
-    begin
-      l.concat c unless c == "\r"
-      break if c == "\n"
-    end while c = getc
-    l
-  end
-
-
-  def ungetc(c = nil)
-    @reader.ungetc(c)
-  end
-
-  def peek_equal?(str)
-    @reader.peek_equal(str)
-  end
-
-  def peek(i = 0)
-    @reader.peek(i)
-  end
-
-  def lex
-    until (TkNL === (tk = token) or TkEND_OF_SCRIPT === tk) and
-           not @continue or tk.nil?
-    end
-
-    line = get_read
-
-    if line == "" and TkEND_OF_SCRIPT === tk or tk.nil? then
-      nil
-    else
-      line
-    end
-  end
-
-  def token
-    set_token_position(line_no, char_no)
-    begin
-      begin
-        tk = @OP.match(self)
-        @space_seen = TkSPACE === tk
-      rescue SyntaxError => e
-        raise RDoc::Error, "syntax error: #{e.message}" if
-          @exception_on_syntax_error
-
-        tk = TkError.new(line_no, char_no)
-      end
-    end while @skip_space and TkSPACE === tk
-    if @read_auto_clean_up
-      get_read
-    end
-#   throw :eof unless tk
-    tk
-  end
-
-  ENINDENT_CLAUSE = [
-    "case", "class", "def", "do", "for", "if",
-    "module", "unless", "until", "while", "begin" #, "when"
-  ]
-  DEINDENT_CLAUSE = ["end" #, "when"
-  ]
-
-  PERCENT_LTYPE = {
-    "q" => "\'",
-    "Q" => "\"",
-    "x" => "\`",
-    "r" => "/",
-    "w" => "]"
-  }
-
-  PERCENT_PAREN = {
-    "{" => "}",
-    "[" => "]",
-    "<" => ">",
-    "(" => ")"
-  }
-
-  Ltype2Token = {
-    "\'" => TkSTRING,
-    "\"" => TkSTRING,
-    "\`" => TkXSTRING,
-    "/" => TkREGEXP,
-    "]" => TkDSTRING
-  }
-  Ltype2Token.default = TkSTRING
-
-  DLtype2Token = {
-    "\"" => TkDSTRING,
-    "\`" => TkDXSTRING,
-    "/" => TkDREGEXP,
-  }
-
-  def lex_init()
-    @OP = IRB::SLex.new
-    @OP.def_rules("\0", "\004", "\032") do |chars, io|
-      Token(TkEND_OF_SCRIPT).set_text(chars)
-    end
-
-    @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io|
-      @space_seen = TRUE
-      while (ch = getc) =~ /[ \t\f\r\13]/
-        chars << ch
-      end
-      ungetc
-      Token(TkSPACE).set_text(chars)
-    end
-
-    @OP.def_rule("#") do
-      |op, io|
-      identify_comment
-    end
-
-    @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do
-      |op, io|
-      str = op
-      @ltype = "="
-
-
-      begin
-        line = ""
-        begin
-          ch = getc
-          line << ch
-        end until ch == "\n"
-        str << line
-      end until line =~ /^=end/
-
-      ungetc
-
-      @ltype = nil
-
-      if str =~ /\A=begin\s+rdoc/i
-        str.sub!(/\A=begin.*\n/, '')
-        str.sub!(/^=end.*/m, '')
-        Token(TkCOMMENT).set_text(str)
-      else
-        Token(TkRD_COMMENT)#.set_text(str)
-      end
-    end
-
-    @OP.def_rule("\n") do
-      print "\\n\n" if RDoc::RubyLex.debug?
-      case @lex_state
-      when EXPR_BEG, EXPR_FNAME, EXPR_DOT
-        @continue = TRUE
-      else
-        @continue = FALSE
-        @lex_state = EXPR_BEG
-      end
-      Token(TkNL).set_text("\n")
-    end
-
-    @OP.def_rules("*", "**",
-                  "!", "!=", "!~",
-                  "=", "==", "===",
-                  "=~", "<=>",
-                  "<", "<=",
-                  ">", ">=", ">>") do
-      |op, io|
-      @lex_state = EXPR_BEG
-      Token(op).set_text(op)
-    end
-
-    @OP.def_rules("<<") do
-      |op, io|
-      tk = nil
-      if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
-        (@lex_state != EXPR_ARG || @space_seen)
-        c = peek(0)
-        if /[-\w_\"\'\`]/ =~ c
-          tk = identify_here_document
-        end
-      end
-      if !tk
-        @lex_state = EXPR_BEG
-        tk = Token(op).set_text(op)
-      end
-      tk
-    end
-
-    @OP.def_rules("'", '"') do
-      |op, io|
-      identify_string(op)
-    end
-
-    @OP.def_rules("`") do
-      |op, io|
-      if @lex_state == EXPR_FNAME
-        Token(op).set_text(op)
-      else
-        identify_string(op)
-      end
-    end
-
-    @OP.def_rules('?') do
-      |op, io|
-      if @lex_state == EXPR_END
-        @lex_state = EXPR_BEG
-        Token(TkQUESTION).set_text(op)
-      else
-        ch = getc
-        if @lex_state == EXPR_ARG && ch !~ /\s/
-          ungetc
-          @lex_state = EXPR_BEG
-          Token(TkQUESTION).set_text(op)
-        else
-          str = op
-          str << ch
-          if (ch == '\\') #'
-            str << read_escape
-          end
-          @lex_state = EXPR_END
-          Token(TkINTEGER).set_text(str)
-        end
-      end
-    end
-
-    @OP.def_rules("&", "&&", "|", "||") do
-      |op, io|
-      @lex_state = EXPR_BEG
-      Token(op).set_text(op)
-    end
-
-    @OP.def_rules("+=", "-=", "*=", "**=",
-                  "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do
-      |op, io|
-      @lex_state = EXPR_BEG
-      op =~ /^(.*)=$/
-      Token(TkOPASGN, $1).set_text(op)
-    end
-
-    @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io|
-      Token(TkUPLUS).set_text(op)
-    end
-
-    @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io|
-      Token(TkUMINUS).set_text(op)
-    end
-
-    @OP.def_rules("+", "-") do
-      |op, io|
-      catch(:RET) do
-        if @lex_state == EXPR_ARG
-          if @space_seen and peek(0) =~ /[0-9]/
-            throw :RET, identify_number(op)
-          else
-            @lex_state = EXPR_BEG
-          end
-        elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/
-          throw :RET, identify_number(op)
-        else
-          @lex_state = EXPR_BEG
-        end
-        Token(op).set_text(op)
-      end
-    end
-
-    @OP.def_rule(".") do
-      @lex_state = EXPR_BEG
-      if peek(0) =~ /[0-9]/
-        ungetc
-        identify_number("")
-      else
-        # for obj.if
-        @lex_state = EXPR_DOT
-        Token(TkDOT).set_text(".")
-      end
-    end
-
-    @OP.def_rules("..", "...") do
-      |op, io|
-      @lex_state = EXPR_BEG
-      Token(op).set_text(op)
-    end
-
-    lex_int2
-  end
-
-  def lex_int2
-    @OP.def_rules("]", "}", ")") do
-      |op, io|
-      @lex_state = EXPR_END
-      @indent -= 1
-      Token(op).set_text(op)
-    end
-
-    @OP.def_rule(":") do
-      if @lex_state == EXPR_END || peek(0) =~ /\s/
-        @lex_state = EXPR_BEG
-        tk = Token(TkCOLON)
-      else
-        @lex_state = EXPR_FNAME
-        tk = Token(TkSYMBEG)
-      end
-      tk.set_text(":")
-    end
-
-    @OP.def_rule("::") do
-      if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen
-        @lex_state = EXPR_BEG
-        tk = Token(TkCOLON3)
-      else
-        @lex_state = EXPR_DOT
-        tk = Token(TkCOLON2)
-      end
-      tk.set_text("::")
-    end
-
-    @OP.def_rule("/") do
-      |op, io|
-      if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
-        identify_string(op)
-      elsif peek(0) == '='
-        getc
-        @lex_state = EXPR_BEG
-        Token(TkOPASGN, :/).set_text("/=") #")
-      elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
-        identify_string(op)
-      else
-        @lex_state = EXPR_BEG
-        Token("/").set_text(op)
-      end
-    end
-
-    @OP.def_rules("^") do
-      @lex_state = EXPR_BEG
-      Token("^").set_text("^")
-    end
-
-    @OP.def_rules(",", ";") do
-      |op, io|
-      @lex_state = EXPR_BEG
-      Token(op).set_text(op)
-    end
-
-    @OP.def_rule("~") do
-      @lex_state = EXPR_BEG
-      Token("~").set_text("~")
-    end
-
-    @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do
-      @lex_state = EXPR_BEG
-      Token("~").set_text("~@")
-    end
-
-    @OP.def_rule("(") do
-      @indent += 1
-      if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
-        @lex_state = EXPR_BEG
-        tk = Token(TkfLPAREN)
-      else
-        @lex_state = EXPR_BEG
-        tk = Token(TkLPAREN)
-      end
-      tk.set_text("(")
-    end
-
-    @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do
-      Token("[]").set_text("[]")
-    end
-
-    @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do
-      Token("[]=").set_text("[]=")
-    end
-
-    @OP.def_rule("[") do
-      @indent += 1
-      if @lex_state == EXPR_FNAME
-        t = Token(TkfLBRACK)
-      else
-        if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
-          t = Token(TkLBRACK)
-        elsif @lex_state == EXPR_ARG && @space_seen
-          t = Token(TkLBRACK)
-        else
-          t = Token(TkfLBRACK)
-        end
-        @lex_state = EXPR_BEG
-      end
-      t.set_text("[")
-    end
-
-    @OP.def_rule("{") do
-      @indent += 1
-      if @lex_state != EXPR_END && @lex_state != EXPR_ARG
-        t = Token(TkLBRACE)
-      else
-        t = Token(TkfLBRACE)
-      end
-      @lex_state = EXPR_BEG
-      t.set_text("{")
-    end
-
-    @OP.def_rule('\\') do   #'
-      if getc == "\n"
-        @space_seen = true
-        @continue = true
-        Token(TkSPACE).set_text("\\\n")
-      else
-        ungetc
-        Token("\\").set_text("\\")  #"
-      end
-    end
-
-    @OP.def_rule('%') do
-      |op, io|
-      if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
-        identify_quotation('%')
-      elsif peek(0) == '='
-        getc
-        Token(TkOPASGN, "%").set_text("%=")
-      elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
-        identify_quotation('%')
-      else
-        @lex_state = EXPR_BEG
-        Token("%").set_text("%")
-      end
-    end
-
-    @OP.def_rule('$') do  #'
-      identify_gvar
-    end
-
-    @OP.def_rule('@') do
-      if peek(0) =~ /[@\w_]/
-        ungetc
-        identify_identifier
-      else
-        Token("@").set_text("@")
-      end
-    end
-
-    @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do
-      throw :eof
-    end
-
-    @OP.def_rule("") do
-      |op, io|
-      printf "MATCH: start %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
-      if peek(0) =~ /[0-9]/
-        t = identify_number("")
-      elsif peek(0) =~ /[\w_]/
-        t = identify_identifier
-      end
-      printf "MATCH: end %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
-      t
-    end
-  end
-
-  def identify_gvar
-    @lex_state = EXPR_END
-    str = "$"
-
-    tk = case ch = getc
-         when /[~_*$?!@\/\\;,=:<>".]/   #"
-           str << ch
-           Token(TkGVAR, str)
-
-         when "-"
-           str << "-" << getc
-           Token(TkGVAR, str)
-
-         when "&", "`", "'", "+"
-           str << ch
-           Token(TkBACK_REF, str)
-
-         when /[1-9]/
-           str << ch
-           while (ch = getc) =~ /[0-9]/
-             str << ch
-           end
-           ungetc
-           Token(TkNTH_REF)
-         when /\w/
-           ungetc
-           ungetc
-           return identify_identifier
-         else
-           ungetc
-           Token("$")
-         end
-    tk.set_text(str)
-  end
-
-  def identify_identifier
-    token = ""
-    token.concat getc if peek(0) =~ /[$@]/
-    token.concat getc if peek(0) == "@"
-
-    while (ch = getc) =~ /\w|_/
-      print ":", ch, ":" if RDoc::RubyLex.debug?
-      token.concat ch
-    end
-    ungetc
-
-    if ch == "!" or ch == "?"
-      token.concat getc
-    end
-    # fix token
-
-    # $stderr.puts "identifier - #{token}, state = #@lex_state"
-
-    case token
-    when /^\$/
-      return Token(TkGVAR, token).set_text(token)
-    when /^\@/
-      @lex_state = EXPR_END
-      return Token(TkIVAR, token).set_text(token)
-    end
-
-    if @lex_state != EXPR_DOT
-      print token, "\n" if RDoc::RubyLex.debug?
-
-      token_c, *trans = TkReading2Token[token]
-      if token_c
-        # reserved word?
-
-        if (@lex_state != EXPR_BEG &&
-            @lex_state != EXPR_FNAME &&
-            trans[1])
-          # modifiers
-          token_c = TkSymbol2Token[trans[1]]
-          @lex_state = trans[0]
-        else
-          if @lex_state != EXPR_FNAME
-            if ENINDENT_CLAUSE.include?(token)
-              @indent += 1
-            elsif DEINDENT_CLAUSE.include?(token)
-              @indent -= 1
-            end
-            @lex_state = trans[0]
-          else
-            @lex_state = EXPR_END
-          end
-        end
-        return Token(token_c, token).set_text(token)
-      end
-    end
-
-    if @lex_state == EXPR_FNAME
-      @lex_state = EXPR_END
-      if peek(0) == '='
-        token.concat getc
-      end
-    elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
-      @lex_state = EXPR_ARG
-    else
-      @lex_state = EXPR_END
-    end
-
-    if token[0, 1] =~ /[A-Z]/
-      return Token(TkCONSTANT, token).set_text(token)
-    elsif token[token.size - 1, 1] =~ /[!?]/
-      return Token(TkFID, token).set_text(token)
-    else
-      return Token(TkIDENTIFIER, token).set_text(token)
-    end
-  end
-
-  def identify_here_document
-    ch = getc
-    if ch == "-"
-      ch = getc
-      indent = true
-    end
-    if /['"`]/ =~ ch            # '
-      lt = ch
-      quoted = ""
-      while (c = getc) && c != lt
-        quoted.concat c
-      end
-    else
-      lt = '"'
-      quoted = ch.dup
-      while (c = getc) && c =~ /\w/
-        quoted.concat c
-      end
-      ungetc
-    end
-
-    ltback, @ltype = @ltype, lt
-    reserve = ""
-
-    while ch = getc
-      reserve << ch
-      if ch == "\\"    #"
-        ch = getc
-        reserve << ch
-      elsif ch == "\n"
-        break
-      end
-    end
-
-    str = ""
-    while (l = gets)
-      l.chomp!
-      l.strip! if indent
-      break if l == quoted
-      str << l.chomp << "\n"
-    end
-
-    @reader.divert_read_from(reserve)
-
-    @ltype = ltback
-    @lex_state = EXPR_END
-    Token(Ltype2Token[lt], str).set_text(str.dump)
-  end
-
-  def identify_quotation(initial_char)
-    ch = getc
-    if lt = PERCENT_LTYPE[ch]
-      initial_char += ch
-      ch = getc
-    elsif ch =~ /\W/
-      lt = "\""
-    else
-      fail SyntaxError, "unknown type of %string ('#{ch}')"
-    end
-#     if ch !~ /\W/
-#       ungetc
-#       next
-#     end
-    #@ltype = lt
-    @quoted = ch unless @quoted = PERCENT_PAREN[ch]
-    identify_string(lt, @quoted, ch, initial_char)
-  end
-
-  def identify_number(start)
-    str = start.dup
-
-    if start == "+" or start == "-" or start == ""
-      start = getc
-      str << start
-    end
-
-    @lex_state = EXPR_END
-
-    if start == "0"
-      if peek(0) == "x"
-        ch = getc
-        str << ch
-        match = /[0-9a-f_]/
-      else
-        match = /[0-7_]/
-      end
-      while ch = getc
-        if ch !~ match
-          ungetc
-          break
-        else
-          str << ch
-        end
-      end
-      return Token(TkINTEGER).set_text(str)
-    end
-
-    type = TkINTEGER
-    allow_point = TRUE
-    allow_e = TRUE
-    while ch = getc
-      case ch
-      when /[0-9_]/
-        str << ch
-
-      when allow_point && "."
-        type = TkFLOAT
-        if peek(0) !~ /[0-9]/
-          ungetc
-          break
-        end
-        str << ch
-        allow_point = false
-
-      when allow_e && "e", allow_e && "E"
-        str << ch
-        type = TkFLOAT
-        if peek(0) =~ /[+-]/
-          str << getc
-        end
-        allow_e = false
-        allow_point = false
-      else
-        ungetc
-        break
-      end
-    end
-    Token(type).set_text(str)
-  end
-
-  def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil)
-    @ltype = ltype
-    @quoted = quoted
-    subtype = nil
-
-    str = ""
-    str << initial_char if initial_char
-    str << (opener||quoted)
-
-    nest = 0
-    begin
-      while ch = getc
-        str << ch
-        if @quoted == ch
-          if nest == 0
-            break
-          else
-            nest -= 1
-          end
-        elsif opener == ch
-          nest += 1
-        elsif @ltype != "'" && @ltype != "]" and ch == "#"
-          ch = getc
-          if ch == "{"
-            subtype = true
-            str << ch << skip_inner_expression
-          else
-            ungetc(ch)
-          end
-        elsif ch == '\\' #'
-          str << read_escape
-        end
-      end
-      if @ltype == "/"
-        if peek(0) =~ /i|o|n|e|s/
-          str << getc
-        end
-      end
-      if subtype
-        Token(DLtype2Token[ltype], str)
-      else
-        Token(Ltype2Token[ltype], str)
-      end.set_text(str)
-    ensure
-      @ltype = nil
-      @quoted = nil
-      @lex_state = EXPR_END
-    end
-  end
-
-  def skip_inner_expression
-    res = ""
-    nest = 0
-    while (ch = getc)
-      res << ch
-      if ch == '}'
-        break if nest.zero?
-        nest -= 1
-      elsif ch == '{'
-        nest += 1
-      end
-    end
-    res
-  end
-
-  def identify_comment
-    @ltype = "#"
-    comment = "#"
-    while ch = getc
-      if ch == "\\"
-        ch = getc
-        if ch == "\n"
-          ch = " "
-        else
-          comment << "\\"
-        end
-      else
-        if ch == "\n"
-          @ltype = nil
-          ungetc
-          break
-        end
-      end
-      comment << ch
-    end
-    return Token(TkCOMMENT).set_text(comment)
-  end
-
-  def read_escape
-    res = ""
-    case ch = getc
-    when /[0-7]/
-      ungetc ch
-      3.times do
-        case ch = getc
-        when /[0-7]/
-        when nil
-          break
-        else
-          ungetc
-          break
-        end
-        res << ch
-      end
-
-    when "x"
-      res << ch
-      2.times do
-        case ch = getc
-        when /[0-9a-fA-F]/
-        when nil
-          break
-        else
-          ungetc
-          break
-        end
-        res << ch
-      end
-
-    when "M"
-      res << ch
-      if (ch = getc) != '-'
-        ungetc
-      else
-        res << ch
-        if (ch = getc) == "\\" #"
-          res << ch
-          res << read_escape
-        else
-          res << ch
-        end
-      end
-
-    when "C", "c" #, "^"
-      res << ch
-      if ch == "C" and (ch = getc) != "-"
-        ungetc
-      else
-        res << ch
-        if (ch = getc) == "\\" #"
-          res << ch
-          res << read_escape
-        else
-          res << ch
-        end
-      end
-    else
-      res << ch
-    end
-    res
-  end
-end
-
-##
-# Extracts code elements from a source file returning a TopLevel object
-# containing the constituent file elements.
-#
-# This file is based on rtags
-#
-# RubyParser understands how to document:
-# * classes
-# * modules
-# * methods
-# * constants
-# * aliases
-# * private, public, protected
-# * private_class_function, public_class_function
-# * module_function
-# * attr, attr_reader, attr_writer, attr_accessor
-# * extra accessors given on the command line
-# * metaprogrammed methods
-# * require
-# * include
-#
-# == Method Arguments
-#
-#--
-# NOTE: I don't think this works, needs tests, remove the paragraph following
-# this block when known to work
-#
-# The parser extracts the arguments from the method definition.  You can
-# override this with a custom argument definition using the :args: directive:
-#
-#   ##
-#   # This method tries over and over until it is tired
-#   
-#   def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try
-#     puts thing_to_try
-#     go_go_go thing_to_try, tries - 1
-#   end
-#
-# If you have a more-complex set of overrides you can use the :call-seq:
-# directive:
-#++
-#
-# The parser extracts the arguments from the method definition.  You can
-# override this with a custom argument definition using the :call-seq:
-# directive:
-#
-#   ##
-#   # This method can be called with a range or an offset and length
-#   #
-#   # :call-seq:
-#   #   my_method(Range)
-#   #   my_method(offset, length)
-#   
-#   def my_method(*args)
-#   end
-#
-# The parser extracts +yield+ expressions from method bodies to gather the
-# yielded argument names.  If your method manually calls a block instead of
-# yielding or you want to override the discovered argument names use
-# the :yields: directive:
-#
-#   ##
-#   # My method is awesome
-#   
-#   def my_method(&block) # :yields: happy, times
-#     block.call 1, 2
-#   end
-#
-# == Metaprogrammed Methods
-#
-# To pick up a metaprogrammed method, the parser looks for a comment starting
-# with '##' before an identifier:
-#
-#   ##
-#   # This is a meta-programmed method!
-#   
-#   add_my_method :meta_method, :arg1, :arg2
-#
-# The parser looks at the token after the identifier to determine the name, in
-# this example, :meta_method.  If a name cannot be found, a warning is printed
-# and 'unknown is used.
-#
-# You can force the name of a method using the :method: directive:
-#
-#   ##
-#   # :method: woo_hoo!
-#
-# By default, meta-methods are instance methods.  To indicate that a method is
-# a singleton method instead use the :singleton-method: directive:
-#
-#   ##
-#   # :singleton-method:
-#
-# You can also use the :singleton-method: directive with a name:
-#
-#   ##
-#   # :singleton-method: woo_hoo!
-#
-# == Hidden methods
-#
-# You can provide documentation for methods that don't appear using
-# the :method: and :singleton-method: directives:
-#
-#   ##
-#   # :method: ghost_method
-#   # There is a method here, but you can't see it!
-#   
-#   ##
-#   # this is a comment for a regular method
-#   
-#   def regular_method() end
-#
-# Note that by default, the :method: directive will be ignored if there is a
-# standard rdocable item following it.
-
-class RDoc::Parser::Ruby < RDoc::Parser
-
-  parse_files_matching(/\.rbw?$/)
-
-  include RDoc::RubyToken
-  include RDoc::TokenStream
-
-  NORMAL = "::"
-  SINGLE = "<<"
-
-  def initialize(top_level, file_name, content, options, stats)
-    super
-
-    @size = 0
-    @token_listeners = nil
-    @scanner = RDoc::RubyLex.new content, @options
-    @scanner.exception_on_syntax_error = false
-
-    reset
-  end
-
-  def add_token_listener(obj)
-    @token_listeners ||= []
-    @token_listeners << obj
-  end
-
-  ##
-  # Look for the first comment in a file that isn't a shebang line.
-
-  def collect_first_comment
-    skip_tkspace
-    res = ''
-    first_line = true
-
-    tk = get_tk
-
-    while TkCOMMENT === tk
-      if first_line and tk.text =~ /\A#!/ then
-        skip_tkspace
-        tk = get_tk
-      elsif first_line and tk.text =~ /\A#\s*-\*-/ then
-        first_line = false
-        skip_tkspace
-        tk = get_tk
-      else
-        first_line = false
-        res << tk.text << "\n"
-        tk = get_tk
-
-        if TkNL === tk then
-          skip_tkspace false
-          tk = get_tk
-        end
-      end
-    end
-
-    unget_tk tk
-
-    res
-  end
-
-  def error(msg)
-    msg = make_message msg
-    $stderr.puts msg
-    exit(1)
-  end
-
-  ##
-  # Look for a 'call-seq' in the comment, and override the normal parameter
-  # stuff
-
-  def extract_call_seq(comment, meth)
-    if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '') then
-      seq = $1
-      seq.gsub!(/^\s*\#\s*/, '')
-      meth.call_seq = seq
-    end
-
-    meth
-  end
-
-  def get_bool
-    skip_tkspace
-    tk = get_tk
-    case tk
-    when TkTRUE
-      true
-    when TkFALSE, TkNIL
-      false
-    else
-      unget_tk tk
-      true
-    end
-  end
-
-  ##
-  # Look for the name of a class of module (optionally with a leading :: or
-  # with :: separated named) and return the ultimate name and container
-
-  def get_class_or_module(container)
-    skip_tkspace
-    name_t = get_tk
-
-    # class ::A -> A is in the top level
-    if TkCOLON2 === name_t then
-      name_t = get_tk
-      container = @top_level
-    end
-
-    skip_tkspace(false)
-
-    while TkCOLON2 === peek_tk do
-      prev_container = container
-      container = container.find_module_named(name_t.name)
-      if !container
-#          warn("Couldn't find module #{name_t.name}")
-        container = prev_container.add_module RDoc::NormalModule, name_t.name
-      end
-      get_tk
-      name_t = get_tk
-    end
-    skip_tkspace(false)
-    return [container, name_t]
-  end
-
-  ##
-  # Return a superclass, which can be either a constant of an expression
-
-  def get_class_specification
-    tk = get_tk
-    return "self" if TkSELF === tk
-
-    res = ""
-    while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
-      res += tk.text
-      tk = get_tk
-    end
-
-    unget_tk(tk)
-    skip_tkspace(false)
-
-    get_tkread # empty out read buffer
-
-    tk = get_tk
-
-    case tk
-    when TkNL, TkCOMMENT, TkSEMICOLON then
-      unget_tk(tk)
-      return res
-    end
-
-    res += parse_call_parameters(tk)
-    res
-  end
-
-  ##
-  # Parse a constant, which might be qualified by one or more class or module
-  # names
-
-  def get_constant
-    res = ""
-    skip_tkspace(false)
-    tk = get_tk
-
-    while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
-      res += tk.text
-      tk = get_tk
-    end
-
-#      if res.empty?
-#        warn("Unexpected token #{tk} in constant")
-#      end
-    unget_tk(tk)
-    res
-  end
-
-  ##
-  # Get a constant that may be surrounded by parens
-
-  def get_constant_with_optional_parens
-    skip_tkspace(false)
-    nest = 0
-    while TkLPAREN === (tk = peek_tk) or TkfLPAREN === tk do
-      get_tk
-      skip_tkspace(true)
-      nest += 1
-    end
-
-    name = get_constant
-
-    while nest > 0
-      skip_tkspace(true)
-      tk = get_tk
-      nest -= 1 if TkRPAREN === tk
-    end
-    name
-  end
-
-  def get_symbol_or_name
-    tk = get_tk
-    case tk
-    when  TkSYMBOL
-      tk.text.sub(/^:/, '')
-    when TkId, TkOp
-      tk.name
-    when TkSTRING
-      tk.text
-    else
-      raise "Name or symbol expected (got #{tk})"
-    end
-  end
-
-  def get_tk
-    tk = nil
-    if @tokens.empty?
-      tk = @scanner.token
-      @read.push @scanner.get_read
-      puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG
-    else
-      @read.push @unget_read.shift
-      tk = @tokens.shift
-      puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG
-    end
-
-    if TkSYMBEG === tk then
-      set_token_position(tk.line_no, tk.char_no)
-      tk1 = get_tk
-      if TkId === tk1 or TkOp === tk1 or TkSTRING === tk1 then
-        if tk1.respond_to?(:name)
-          tk = Token(TkSYMBOL).set_text(":" + tk1.name)
-        else
-          tk = Token(TkSYMBOL).set_text(":" + tk1.text)
-        end
-        # remove the identifier we just read (we're about to
-        # replace it with a symbol)
-        @token_listeners.each do |obj|
-          obj.pop_token
-        end if @token_listeners
-      else
-        warn("':' not followed by identifier or operator")
-        tk = tk1
-      end
-    end
-
-    # inform any listeners of our shiny new token
-    @token_listeners.each do |obj|
-      obj.add_token(tk)
-    end if @token_listeners
-
-    tk
-  end
-
-  def get_tkread
-    read = @read.join("")
-    @read = []
-    read
-  end
-
-  ##
-  # Look for directives in a normal comment block:
-  #
-  #   #-- - don't display comment from this point forward
-  #
-  # This routine modifies it's parameter
-
-  def look_for_directives_in(context, comment)
-    preprocess = RDoc::Markup::PreProcess.new(@file_name,
-                                              @options.rdoc_include)
-
-    preprocess.handle(comment) do |directive, param|
-      case directive
-      when 'enddoc' then
-        throw :enddoc
-      when 'main' then
-        @options.main_page = param
-        ''
-      when 'method', 'singleton-method' then
-        false # ignore
-      when 'section' then
-        context.set_current_section(param, comment)
-        comment.replace ''
-        break
-      when 'startdoc' then
-        context.start_doc
-        context.force_documentation = true
-        ''
-      when 'stopdoc' then
-        context.stop_doc
-        ''
-      when 'title' then
-        @options.title = param
-        ''
-      else
-        warn "Unrecognized directive '#{directive}'"
-        false
-      end
-    end
-
-    remove_private_comments(comment)
-  end
-
-  def make_message(msg)
-    prefix = "\n" + @file_name + ":"
-    if @scanner
-      prefix << "#{@scanner.line_no}:#{@scanner.char_no}: "
-    end
-    return prefix + msg
-  end
-
-  def parse_attr(context, single, tk, comment)
-    args = parse_symbol_arg(1)
-    if args.size > 0
-      name = args[0]
-      rw = "R"
-      skip_tkspace(false)
-      tk = get_tk
-      if TkCOMMA === tk then
-        rw = "RW" if get_bool
-      else
-        unget_tk tk
-      end
-      att = RDoc::Attr.new get_tkread, name, rw, comment
-      read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
-      if att.document_self
-        context.add_attribute(att)
-      end
-    else
-      warn("'attr' ignored - looks like a variable")
-    end
-  end
-
-  def parse_attr_accessor(context, single, tk, comment)
-    args = parse_symbol_arg
-    read = get_tkread
-    rw = "?"
-
-    # If nodoc is given, don't document any of them
-
-    tmp = RDoc::CodeObject.new
-    read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
-    return unless tmp.document_self
-
-    case tk.name
-    when "attr_reader"   then rw = "R"
-    when "attr_writer"   then rw = "W"
-    when "attr_accessor" then rw = "RW"
-    else
-      rw = @options.extra_accessor_flags[tk.name]
-      rw = '?' if rw.nil?
-    end
-
-    for name in args
-      att = RDoc::Attr.new get_tkread, name, rw, comment
-      context.add_attribute att
-    end
-  end
-
-  def parse_alias(context, single, tk, comment)
-    skip_tkspace
-    if TkLPAREN === peek_tk then
-      get_tk
-      skip_tkspace
-    end
-    new_name = get_symbol_or_name
-    @scanner.instance_eval{@lex_state = EXPR_FNAME}
-    skip_tkspace
-    if TkCOMMA === peek_tk then
-      get_tk
-      skip_tkspace
-    end
-    old_name = get_symbol_or_name
-
-    al = RDoc::Alias.new get_tkread, old_name, new_name, comment
-    read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
-    if al.document_self
-      context.add_alias(al)
-    end
-  end
-
-  def parse_call_parameters(tk)
-    end_token = case tk
-                when TkLPAREN, TkfLPAREN
-                  TkRPAREN
-                when TkRPAREN
-                  return ""
-                else
-                  TkNL
-                end
-    nest = 0
-
-    loop do
-        case tk
-        when TkSEMICOLON
-          break
-        when TkLPAREN, TkfLPAREN
-          nest += 1
-        when end_token
-          if end_token == TkRPAREN
-            nest -= 1
-            break if @scanner.lex_state == EXPR_END and nest <= 0
-          else
-            break unless @scanner.continue
-          end
-        when TkCOMMENT
-          unget_tk(tk)
-          break
-        end
-        tk = get_tk
-    end
-    res = get_tkread.tr("\n", " ").strip
-    res = "" if res == ";"
-    res
-  end
-
-  def parse_class(container, single, tk, comment)
-    container, name_t = get_class_or_module(container)
-
-    case name_t
-    when TkCONSTANT
-      name = name_t.name
-      superclass = "Object"
-
-      if TkLT === peek_tk then
-        get_tk
-        skip_tkspace(true)
-        superclass = get_class_specification
-        superclass = "<unknown>" if superclass.empty?
-      end
-
-      cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
-      cls = container.add_class cls_type, name, superclass
-
-      @stats.add_class cls
-
-      read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
-      cls.record_location @top_level
-
-      parse_statements cls
-      cls.comment = comment
-
-    when TkLSHFT
-      case name = get_class_specification
-      when "self", container.name
-        parse_statements(container, SINGLE)
-      else
-        other = RDoc::TopLevel.find_class_named(name)
-        unless other
-          #            other = @top_level.add_class(NormalClass, name, nil)
-          #            other.record_location(@top_level)
-          #            other.comment = comment
-          other = RDoc::NormalClass.new "Dummy", nil
-        end
-
-        @stats.add_class other
-
-        read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
-        parse_statements(other, SINGLE)
-      end
-
-    else
-      warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}")
-    end
-  end
-
-  def parse_constant(container, single, tk, comment)
-    name = tk.name
-    skip_tkspace(false)
-    eq_tk = get_tk
-
-    unless TkASSIGN === eq_tk then
-      unget_tk(eq_tk)
-      return
-    end
-
-
-    nest = 0
-    get_tkread
-
-    tk = get_tk
-    if TkGT === tk then
-      unget_tk(tk)
-      unget_tk(eq_tk)
-      return
-    end
-
-    loop do
-        case tk
-        when TkSEMICOLON
-          break
-        when TkLPAREN, TkfLPAREN, TkLBRACE, TkLBRACK, TkDO
-          nest += 1
-        when TkRPAREN, TkRBRACE, TkRBRACK, TkEND
-          nest -= 1
-        when TkCOMMENT
-          if nest <= 0 && @scanner.lex_state == EXPR_END
-            unget_tk(tk)
-            break
-          end
-        when TkNL
-          if (nest <= 0) && ((@scanner.lex_state == EXPR_END) || (!@scanner.continue))
-            unget_tk(tk)
-            break
-          end
-        end
-        tk = get_tk
-    end
-
-    res = get_tkread.tr("\n", " ").strip
-    res = "" if res == ";"
-
-    con = RDoc::Constant.new name, res, comment
-    read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
-
-    if con.document_self
-      container.add_constant(con)
-    end
-  end
-
-  def parse_comment(container, tk, comment)
-    line_no = tk.line_no
-    column  = tk.char_no
-
-    singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
-
-    if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
-      name = $1 unless $1.empty?
-    else
-      return nil
-    end
-
-    meth = RDoc::GhostMethod.new get_tkread, name
-    meth.singleton = singleton
-
-    @stats.add_method meth
-
-    meth.start_collecting_tokens
-    indent = TkSPACE.new 1, 1
-    indent.set_text " " * column
-
-    position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
-    meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
-
-    meth.params = ''
-
-    extract_call_seq comment, meth
-
-    container.add_method meth if meth.document_self
-
-    meth.comment = comment
-  end
-
-  def parse_include(context, comment)
-    loop do
-      skip_tkspace_comment
-
-      name = get_constant_with_optional_parens
-      context.add_include RDoc::Include.new(name, comment) unless name.empty?
-
-      return unless TkCOMMA === peek_tk
-      get_tk
-    end
-  end
-
-  ##
-  # Parses a meta-programmed method
-
-  def parse_meta_method(container, single, tk, comment)
-    line_no = tk.line_no
-    column  = tk.char_no
-
-    start_collecting_tokens
-    add_token tk
-    add_token_listener self
-
-    skip_tkspace false
-
-    singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
-
-    if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
-      name = $1 unless $1.empty?
-    end
-
-    if name.nil? then
-      name_t = get_tk
-      case name_t
-      when TkSYMBOL then
-        name = name_t.text[1..-1]
-      when TkSTRING then
-        name = name_t.text[1..-2]
-      else
-        warn "#{container.top_level.file_relative_name}:#{name_t.line_no} unknown name token #{name_t.inspect} for meta-method"
-        name = 'unknown'
-      end
-    end
-
-    meth = RDoc::MetaMethod.new get_tkread, name
-    meth.singleton = singleton
-
-    @stats.add_method meth
-
-    remove_token_listener self
-
-    meth.start_collecting_tokens
-    indent = TkSPACE.new 1, 1
-    indent.set_text " " * column
-
-    position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
-    meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
-    meth.add_tokens @token_stream
-
-    add_token_listener meth
-
-    meth.params = ''
-
-    extract_call_seq comment, meth
-
-    container.add_method meth if meth.document_self
-
-    last_tk = tk
-
-    while tk = get_tk do
-      case tk
-      when TkSEMICOLON then
-        break
-      when TkNL then
-        break unless last_tk and TkCOMMA === last_tk
-      when TkSPACE then
-        # expression continues
-      else
-        last_tk = tk
-      end
-    end
-
-    remove_token_listener meth
-
-    meth.comment = comment
-  end
-
-  ##
-  # Parses a method
-
-  def parse_method(container, single, tk, comment)
-    line_no = tk.line_no
-    column  = tk.char_no
-
-    start_collecting_tokens
-    add_token(tk)
-    add_token_listener(self)
-
-    @scanner.instance_eval do @lex_state = EXPR_FNAME end
-
-    skip_tkspace(false)
-    name_t = get_tk
-    back_tk = skip_tkspace
-    meth = nil
-    added_container = false
-
-    dot = get_tk
-    if TkDOT === dot or TkCOLON2 === dot then
-      @scanner.instance_eval do @lex_state = EXPR_FNAME end
-      skip_tkspace
-      name_t2 = get_tk
-
-      case name_t
-      when TkSELF then
-        name = name_t2.name
-      when TkCONSTANT then
-        name = name_t2.name
-        prev_container = container
-        container = container.find_module_named(name_t.name)
-        unless container then
-          added_container = true
-          obj = name_t.name.split("::").inject(Object) do |state, item|
-            state.const_get(item)
-          end rescue nil
-
-          type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
-
-          unless [Class, Module].include?(obj.class) then
-            warn("Couldn't find #{name_t.name}. Assuming it's a module")
-          end
-
-          if type == RDoc::NormalClass then
-            container = prev_container.add_class(type, name_t.name, obj.superclass.name)
-          else
-            container = prev_container.add_module(type, name_t.name)
-          end
-
-          container.record_location @top_level
-        end
-      else
-        # warn("Unexpected token '#{name_t2.inspect}'")
-        # break
-        skip_method(container)
-        return
-      end
-
-      meth = RDoc::AnyMethod.new(get_tkread, name)
-      meth.singleton = true
-    else
-      unget_tk dot
-      back_tk.reverse_each do |token|
-        unget_tk token
-      end
-      name = name_t.name
-
-      meth = RDoc::AnyMethod.new get_tkread, name
-      meth.singleton = (single == SINGLE)
-    end
-
-    @stats.add_method meth
-
-    remove_token_listener self
-
-    meth.start_collecting_tokens
-    indent = TkSPACE.new 1, 1
-    indent.set_text " " * column
-
-    token = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
-    meth.add_tokens [token, NEWLINE_TOKEN, indent]
-    meth.add_tokens @token_stream
-
-    add_token_listener meth
-
-    @scanner.instance_eval do @continue = false end
-    parse_method_parameters meth
-
-    if meth.document_self then
-      container.add_method meth
-    elsif added_container then
-      container.document_self = false
-    end
-
-    # Having now read the method parameters and documentation modifiers, we
-    # now know whether we have to rename #initialize to ::new
-
-    if name == "initialize" && !meth.singleton then
-      if meth.dont_rename_initialize then
-        meth.visibility = :protected
-      else
-        meth.singleton = true
-        meth.name = "new"
-        meth.visibility = :public
-      end
-    end
-
-    parse_statements(container, single, meth)
-
-    remove_token_listener(meth)
-
-    extract_call_seq comment, meth
-
-    meth.comment = comment
-  end
-
-  def parse_method_or_yield_parameters(method = nil,
-                                       modifiers = RDoc::METHOD_MODIFIERS)
-    skip_tkspace(false)
-    tk = get_tk
-
-    # Little hack going on here. In the statement
-    #  f = 2*(1+yield)
-    # We see the RPAREN as the next token, so we need
-    # to exit early. This still won't catch all cases
-    # (such as "a = yield + 1"
-    end_token = case tk
-                when TkLPAREN, TkfLPAREN
-                  TkRPAREN
-                when TkRPAREN
-                  return ""
-                else
-                  TkNL
-                end
-    nest = 0
-
-    loop do
-        case tk
-        when TkSEMICOLON
-          break
-        when TkLBRACE
-          nest += 1
-        when TkRBRACE
-          # we might have a.each {|i| yield i }
-          unget_tk(tk) if nest.zero?
-          nest -= 1
-          break if nest <= 0
-        when TkLPAREN, TkfLPAREN
-          nest += 1
-        when end_token
-          if end_token == TkRPAREN
-            nest -= 1
-            break if @scanner.lex_state == EXPR_END and nest <= 0
-          else
-            break unless @scanner.continue
-          end
-        when method && method.block_params.nil? && TkCOMMENT
-          unget_tk(tk)
-          read_documentation_modifiers(method, modifiers)
-        end
-      tk = get_tk
-    end
-    res = get_tkread.tr("\n", " ").strip
-    res = "" if res == ";"
-    res
-  end
-
-  ##
-  # Capture the method's parameters. Along the way, look for a comment
-  # containing:
-  #
-  #    # yields: ....
-  #
-  # and add this as the block_params for the method
-
-  def parse_method_parameters(method)
-    res = parse_method_or_yield_parameters(method)
-    res = "(" + res + ")" unless res[0] == ?(
-    method.params = res unless method.params
-    if method.block_params.nil?
-      skip_tkspace(false)
-      read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
-    end
-  end
-
-  def parse_module(container, single, tk, comment)
-    container, name_t = get_class_or_module(container)
-
-    name = name_t.name
-
-    mod = container.add_module RDoc::NormalModule, name
-    mod.record_location @top_level
-
-    @stats.add_module mod
-
-    read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
-    parse_statements(mod)
-    mod.comment = comment
-  end
-
-  def parse_require(context, comment)
-    skip_tkspace_comment
-    tk = get_tk
-    if TkLPAREN === tk then
-      skip_tkspace_comment
-      tk = get_tk
-    end
-
-    name = nil
-    case tk
-    when TkSTRING
-      name = tk.text
-      #    when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR
-      #      name = tk.name
-    when TkDSTRING
-      warn "Skipping require of dynamic string: #{tk.text}"
-      #   else
-      #     warn "'require' used as variable"
-    end
-    if name
-      context.add_require RDoc::Require.new(name, comment)
-    else
-      unget_tk(tk)
-    end
-  end
-
-  def parse_statements(container, single = NORMAL, current_method = nil,
-                       comment = '')
-    nest = 1
-    save_visibility = container.visibility
-
-    non_comment_seen = true
-
-    while tk = get_tk do
-      keep_comment = false
-
-      non_comment_seen = true unless TkCOMMENT === tk
-
-      case tk
-      when TkNL then
-        skip_tkspace true # Skip blanks and newlines
-        tk = get_tk
-
-        if TkCOMMENT === tk then
-          if non_comment_seen then
-            # Look for RDoc in a comment about to be thrown away
-            parse_comment container, tk, comment unless comment.empty?
-
-            comment = ''
-            non_comment_seen = false
-          end
-
-          while TkCOMMENT === tk do
-            comment << tk.text << "\n"
-            tk = get_tk          # this is the newline
-            skip_tkspace(false)  # leading spaces
-            tk = get_tk
-          end
-
-          unless comment.empty? then
-            look_for_directives_in container, comment
-
-            if container.done_documenting then
-              container.ongoing_visibility = save_visibility
-            end
-          end
-
-          keep_comment = true
-        else
-          non_comment_seen = true
-        end
-
-        unget_tk tk
-        keep_comment = true
-
-      when TkCLASS then
-        if container.document_children then
-          parse_class container, single, tk, comment
-        else
-          nest += 1
-        end
-
-      when TkMODULE then
-        if container.document_children then
-          parse_module container, single, tk, comment
-        else
-          nest += 1
-        end
-
-      when TkDEF then
-        if container.document_self then
-          parse_method container, single, tk, comment
-        else
-          nest += 1
-        end
-
-      when TkCONSTANT then
-        if container.document_self then
-          parse_constant container, single, tk, comment
-        end
-
-      when TkALIAS then
-        if container.document_self then
-          parse_alias container, single, tk, comment
-        end
-
-      when TkYIELD then
-        if current_method.nil? then
-          warn "Warning: yield outside of method" if container.document_self
-        else
-          parse_yield container, single, tk, current_method
-        end
-
-      # Until and While can have a 'do', which shouldn't increase the nesting.
-      # We can't solve the general case, but we can handle most occurrences by
-      # ignoring a do at the end of a line.
-
-      when  TkUNTIL, TkWHILE then
-        nest += 1
-        skip_optional_do_after_expression
-
-      # 'for' is trickier
-      when TkFOR then
-        nest += 1
-        skip_for_variable
-        skip_optional_do_after_expression
-
-      when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then
-        nest += 1
-
-      when TkIDENTIFIER then
-        if nest == 1 and current_method.nil? then
-          case tk.name
-          when 'private', 'protected', 'public', 'private_class_method',
-               'public_class_method', 'module_function' then
-            parse_visibility container, single, tk
-            keep_comment = true
-          when 'attr' then
-            parse_attr container, single, tk, comment
-          when /^attr_(reader|writer|accessor)$/, @options.extra_accessors then
-            parse_attr_accessor container, single, tk, comment
-          when 'alias_method' then
-            if container.document_self then
-              parse_alias container, single, tk, comment
-            end
-          else
-            if container.document_self and comment =~ /\A#\#$/ then
-              parse_meta_method container, single, tk, comment
-            end
-          end
-        end
-
-        case tk.name
-        when "require" then
-          parse_require container, comment
-        when "include" then
-          parse_include container, comment
-        end
-
-      when TkEND then
-        nest -= 1
-        if nest == 0 then
-          read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
-          container.ongoing_visibility = save_visibility
-          return
-        end
-
-      end
-
-      comment = '' unless keep_comment
-
-      begin
-        get_tkread
-        skip_tkspace(false)
-      end while peek_tk == TkNL
-    end
-  end
-
-  def parse_symbol_arg(no = nil)
-    args = []
-    skip_tkspace_comment
-    case tk = get_tk
-    when TkLPAREN
-      loop do
-        skip_tkspace_comment
-        if tk1 = parse_symbol_in_arg
-          args.push tk1
-          break if no and args.size >= no
-        end
-
-        skip_tkspace_comment
-        case tk2 = get_tk
-        when TkRPAREN
-          break
-        when TkCOMMA
-        else
-          warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
-          break
-        end
-      end
-    else
-      unget_tk tk
-      if tk = parse_symbol_in_arg
-        args.push tk
-        return args if no and args.size >= no
-      end
-
-      loop do
-        skip_tkspace(false)
-
-        tk1 = get_tk
-        unless TkCOMMA === tk1 then
-          unget_tk tk1
-          break
-        end
-
-        skip_tkspace_comment
-        if tk = parse_symbol_in_arg
-          args.push tk
-          break if no and args.size >= no
-        end
-      end
-    end
-    args
-  end
-
-  def parse_symbol_in_arg
-    case tk = get_tk
-    when TkSYMBOL
-      tk.text.sub(/^:/, '')
-    when TkSTRING
-      eval @read[-1]
-    else
-      warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
-      nil
-    end
-  end
-
-  def parse_toplevel_statements(container)
-    comment = collect_first_comment
-    look_for_directives_in(container, comment)
-    container.comment = comment unless comment.empty?
-    parse_statements container, NORMAL, nil, comment
-  end
-
-  def parse_visibility(container, single, tk)
-    singleton = (single == SINGLE)
-
-    vis_type = tk.name
-
-    vis = case vis_type
-          when 'private'   then :private
-          when 'protected' then :protected
-          when 'public'    then :public
-          when 'private_class_method' then
-            singleton = true
-            :private
-          when 'public_class_method' then
-            singleton = true
-            :public
-          when 'module_function' then
-            singleton = true
-            :public
-          else
-            raise "Invalid visibility: #{tk.name}"
-          end
-
-    skip_tkspace_comment false
-
-    case peek_tk
-      # Ryan Davis suggested the extension to ignore modifiers, because he
-      # often writes
-      #
-      #   protected unless $TESTING
-      #
-    when TkNL, TkUNLESS_MOD, TkIF_MOD, TkSEMICOLON then
-      container.ongoing_visibility = vis
-    else
-      if vis_type == 'module_function' then
-        args = parse_symbol_arg
-        container.set_visibility_for args, :private, false
-
-        module_functions = []
-
-        container.methods_matching args do |m|
-          s_m = m.dup
-          s_m.singleton = true if RDoc::AnyMethod === s_m
-          s_m.visibility = :public
-          module_functions << s_m
-        end
-
-        module_functions.each do |s_m|
-          case s_m
-          when RDoc::AnyMethod then
-            container.add_method s_m
-          when RDoc::Attr then
-            container.add_attribute s_m
-          end
-        end
-      else
-        args = parse_symbol_arg
-        container.set_visibility_for args, vis, singleton
-      end
-    end
-  end
-
-  def parse_yield_parameters
-    parse_method_or_yield_parameters
-  end
-
-  def parse_yield(context, single, tk, method)
-    if method.block_params.nil?
-      get_tkread
-      @scanner.instance_eval{@continue = false}
-      method.block_params = parse_yield_parameters
-    end
-  end
-
-  def peek_read
-    @read.join('')
-  end
-
-  ##
-  # Peek at the next token, but don't remove it from the stream
-
-  def peek_tk
-    unget_tk(tk = get_tk)
-    tk
-  end
-
-  ##
-  # Directives are modifier comments that can appear after class, module, or
-  # method names. For example:
-  #
-  #   def fred # :yields: a, b
-  #
-  # or:
-  #
-  #   class MyClass # :nodoc:
-  #
-  # We return the directive name and any parameters as a two element array
-
-  def read_directive(allowed)
-    tk = get_tk
-    result = nil
-    if TkCOMMENT === tk
-      if tk.text =~ /\s*:?(\w+):\s*(.*)/
-        directive = $1.downcase
-        if allowed.include?(directive)
-          result = [directive, $2]
-        end
-      end
-    else
-      unget_tk(tk)
-    end
-    result
-  end
-
-  def read_documentation_modifiers(context, allow)
-    dir = read_directive(allow)
-
-    case dir[0]
-    when "notnew", "not_new", "not-new" then
-      context.dont_rename_initialize = true
-
-    when "nodoc" then
-      context.document_self = false
-      if dir[1].downcase == "all"
-        context.document_children = false
-      end
-
-    when "doc" then
-      context.document_self = true
-      context.force_documentation = true
-
-    when "yield", "yields" then
-      unless context.params.nil?
-        context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
-      end
-
-      context.block_params = dir[1]
-
-    when "arg", "args" then
-      context.params = dir[1]
-    end if dir
-  end
-
-  def remove_private_comments(comment)
-    comment.gsub!(/^#--\n.*?^#\+\+/m, '')
-    comment.sub!(/^#--\n.*/m, '')
-  end
-
-  def remove_token_listener(obj)
-    @token_listeners.delete(obj)
-  end
-
-  def reset
-    @tokens = []
-    @unget_read = []
-    @read = []
-  end
-
-  def scan
-    reset
-
-    catch(:eof) do
-      catch(:enddoc) do
-        begin
-          parse_toplevel_statements(@top_level)
-        rescue Exception => e
-          $stderr.puts <<-EOF
-
-
-RDoc failure in #{@file_name} at or around line #{@scanner.line_no} column
-#{@scanner.char_no}
-
-Before reporting this, could you check that the file you're documenting
-compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if
-fed invalid programs.
-
-The internal error was:
-
-          EOF
-
-          e.set_backtrace(e.backtrace[0,4])
-          raise
-        end
-      end
-    end
-
-    @top_level
-  end
-
-  ##
-  # while, until, and for have an optional do
-
-  def skip_optional_do_after_expression
-    skip_tkspace(false)
-    tk = get_tk
-    case tk
-    when TkLPAREN, TkfLPAREN
-      end_token = TkRPAREN
-    else
-      end_token = TkNL
-    end
-
-    nest = 0
-    @scanner.instance_eval{@continue = false}
-
-    loop do
-      case tk
-      when TkSEMICOLON
-        break
-      when TkLPAREN, TkfLPAREN
-        nest += 1
-      when TkDO
-        break if nest.zero?
-      when end_token
-        if end_token == TkRPAREN
-          nest -= 1
-          break if @scanner.lex_state == EXPR_END and nest.zero?
-        else
-          break unless @scanner.continue
-        end
-      end
-      tk = get_tk
-    end
-    skip_tkspace(false)
-
-    get_tk if TkDO === peek_tk
-  end
-
-  ##
-  # skip the var [in] part of a 'for' statement
-
-  def skip_for_variable
-    skip_tkspace(false)
-    tk = get_tk
-    skip_tkspace(false)
-    tk = get_tk
-    unget_tk(tk) unless TkIN === tk
-  end
-
-  def skip_method(container)
-    meth = RDoc::AnyMethod.new "", "anon"
-    parse_method_parameters(meth)
-    parse_statements(container, false, meth)
-  end
-
-  ##
-  # Skip spaces
-
-  def skip_tkspace(skip_nl = true)
-    tokens = []
-
-    while TkSPACE === (tk = get_tk) or (skip_nl and TkNL === tk) do
-      tokens.push tk
-    end
-
-    unget_tk(tk)
-    tokens
-  end
-
-  ##
-  # Skip spaces until a comment is found
-
-  def skip_tkspace_comment(skip_nl = true)
-    loop do
-      skip_tkspace(skip_nl)
-      return unless TkCOMMENT === peek_tk
-      get_tk
-    end
-  end
-
-  def unget_tk(tk)
-    @tokens.unshift tk
-    @unget_read.unshift @read.pop
-
-    # Remove this token from any listeners
-    @token_listeners.each do |obj|
-      obj.pop_token
-    end if @token_listeners
-  end
-
-  def warn(msg)
-    return if @options.quiet
-    msg = make_message msg
-    $stderr.puts msg
-  end
-
-end
-

Copied: MacRuby/branches/experimental/lib/rdoc/parser/ruby.rb (from rev 1886, MacRuby/trunk/lib/rdoc/parser/ruby.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/parser/ruby.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/parser/ruby.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,2829 @@
+##
+# This file contains stuff stolen outright from:
+#
+#   rtags.rb -
+#   ruby-lex.rb - ruby lexcal analyzer
+#   ruby-token.rb - ruby tokens
+#       by Keiju ISHITSUKA (Nippon Rational Inc.)
+#
+
+require 'e2mmap'
+require 'irb/slex'
+
+require 'rdoc/code_objects'
+require 'rdoc/tokenstream'
+require 'rdoc/markup/preprocess'
+require 'rdoc/parser'
+
+$TOKEN_DEBUG ||= nil
+#$TOKEN_DEBUG = $DEBUG_RDOC
+
+##
+# Definitions of all tokens involved in the lexical analysis
+
+module RDoc::RubyToken
+
+  EXPR_BEG   = :EXPR_BEG
+  EXPR_MID   = :EXPR_MID
+  EXPR_END   = :EXPR_END
+  EXPR_ARG   = :EXPR_ARG
+  EXPR_FNAME = :EXPR_FNAME
+  EXPR_DOT   = :EXPR_DOT
+  EXPR_CLASS = :EXPR_CLASS
+
+  class Token
+    NO_TEXT = "??".freeze
+
+    attr_accessor :text
+    attr_reader :line_no
+    attr_reader :char_no
+
+    def initialize(line_no, char_no)
+      @line_no = line_no
+      @char_no = char_no
+      @text    = NO_TEXT
+    end
+
+    def ==(other)
+      self.class == other.class and
+        other.line_no == @line_no and
+        other.char_no == @char_no and
+        other.text == @text
+    end
+
+    ##
+    # Because we're used in contexts that expect to return a token, we set the
+    # text string and then return ourselves
+
+    def set_text(text)
+      @text = text
+      self
+    end
+
+  end
+
+  class TkNode < Token
+    attr :node
+  end
+
+  class TkId < Token
+    def initialize(line_no, char_no, name)
+      super(line_no, char_no)
+      @name = name
+    end
+    attr :name
+  end
+
+  class TkKW < TkId
+  end
+
+  class TkVal < Token
+    def initialize(line_no, char_no, value = nil)
+      super(line_no, char_no)
+      set_text(value)
+    end
+  end
+
+  class TkOp < Token
+    def name
+      self.class.op_name
+    end
+  end
+
+  class TkOPASGN < TkOp
+    def initialize(line_no, char_no, op)
+      super(line_no, char_no)
+      op = TkReading2Token[op] unless Symbol === op
+      @op = op
+    end
+    attr :op
+  end
+
+  class TkUnknownChar < Token
+    def initialize(line_no, char_no, id)
+      super(line_no, char_no)
+      @name = char_no.chr
+    end
+    attr :name
+  end
+
+  class TkError < Token
+  end
+
+  def set_token_position(line, char)
+    @prev_line_no = line
+    @prev_char_no = char
+  end
+
+  def Token(token, value = nil)
+    tk = nil
+    case token
+    when String, Symbol
+      source = String === token ? TkReading2Token : TkSymbol2Token
+      raise TkReading2TokenNoKey, token if (tk = source[token]).nil?
+      tk = Token(tk[0], value)
+    else
+      tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty?
+             token.new(@prev_line_no, @prev_char_no)
+           else
+             token.new(@prev_line_no, @prev_char_no, value)
+           end
+    end
+    tk
+  end
+
+  TokenDefinitions = [
+    [:TkCLASS,      TkKW,  "class",  EXPR_CLASS],
+    [:TkMODULE,     TkKW,  "module", EXPR_CLASS],
+    [:TkDEF,        TkKW,  "def",    EXPR_FNAME],
+    [:TkUNDEF,      TkKW,  "undef",  EXPR_FNAME],
+    [:TkBEGIN,      TkKW,  "begin",  EXPR_BEG],
+    [:TkRESCUE,     TkKW,  "rescue", EXPR_MID],
+    [:TkENSURE,     TkKW,  "ensure", EXPR_BEG],
+    [:TkEND,        TkKW,  "end",    EXPR_END],
+    [:TkIF,         TkKW,  "if",     EXPR_BEG, :TkIF_MOD],
+    [:TkUNLESS,     TkKW,  "unless", EXPR_BEG, :TkUNLESS_MOD],
+    [:TkTHEN,       TkKW,  "then",   EXPR_BEG],
+    [:TkELSIF,      TkKW,  "elsif",  EXPR_BEG],
+    [:TkELSE,       TkKW,  "else",   EXPR_BEG],
+    [:TkCASE,       TkKW,  "case",   EXPR_BEG],
+    [:TkWHEN,       TkKW,  "when",   EXPR_BEG],
+    [:TkWHILE,      TkKW,  "while",  EXPR_BEG, :TkWHILE_MOD],
+    [:TkUNTIL,      TkKW,  "until",  EXPR_BEG, :TkUNTIL_MOD],
+    [:TkFOR,        TkKW,  "for",    EXPR_BEG],
+    [:TkBREAK,      TkKW,  "break",  EXPR_END],
+    [:TkNEXT,       TkKW,  "next",   EXPR_END],
+    [:TkREDO,       TkKW,  "redo",   EXPR_END],
+    [:TkRETRY,      TkKW,  "retry",  EXPR_END],
+    [:TkIN,         TkKW,  "in",     EXPR_BEG],
+    [:TkDO,         TkKW,  "do",     EXPR_BEG],
+    [:TkRETURN,     TkKW,  "return", EXPR_MID],
+    [:TkYIELD,      TkKW,  "yield",  EXPR_END],
+    [:TkSUPER,      TkKW,  "super",  EXPR_END],
+    [:TkSELF,       TkKW,  "self",   EXPR_END],
+    [:TkNIL,        TkKW,  "nil",    EXPR_END],
+    [:TkTRUE,       TkKW,  "true",   EXPR_END],
+    [:TkFALSE,      TkKW,  "false",  EXPR_END],
+    [:TkAND,        TkKW,  "and",    EXPR_BEG],
+    [:TkOR,         TkKW,  "or",     EXPR_BEG],
+    [:TkNOT,        TkKW,  "not",    EXPR_BEG],
+    [:TkIF_MOD,     TkKW],
+    [:TkUNLESS_MOD, TkKW],
+    [:TkWHILE_MOD,  TkKW],
+    [:TkUNTIL_MOD,  TkKW],
+    [:TkALIAS,      TkKW,  "alias",    EXPR_FNAME],
+    [:TkDEFINED,    TkKW,  "defined?", EXPR_END],
+    [:TklBEGIN,     TkKW,  "BEGIN",    EXPR_END],
+    [:TklEND,       TkKW,  "END",      EXPR_END],
+    [:Tk__LINE__,   TkKW,  "__LINE__", EXPR_END],
+    [:Tk__FILE__,   TkKW,  "__FILE__", EXPR_END],
+
+    [:TkIDENTIFIER, TkId],
+    [:TkFID,        TkId],
+    [:TkGVAR,       TkId],
+    [:TkIVAR,       TkId],
+    [:TkCONSTANT,   TkId],
+
+    [:TkINTEGER,    TkVal],
+    [:TkFLOAT,      TkVal],
+    [:TkSTRING,     TkVal],
+    [:TkXSTRING,    TkVal],
+    [:TkREGEXP,     TkVal],
+    [:TkCOMMENT,    TkVal],
+
+    [:TkDSTRING,    TkNode],
+    [:TkDXSTRING,   TkNode],
+    [:TkDREGEXP,    TkNode],
+    [:TkNTH_REF,    TkId],
+    [:TkBACK_REF,   TkId],
+
+    [:TkUPLUS,      TkOp,   "+@"],
+    [:TkUMINUS,     TkOp,   "-@"],
+    [:TkPOW,        TkOp,   "**"],
+    [:TkCMP,        TkOp,   "<=>"],
+    [:TkEQ,         TkOp,   "=="],
+    [:TkEQQ,        TkOp,   "==="],
+    [:TkNEQ,        TkOp,   "!="],
+    [:TkGEQ,        TkOp,   ">="],
+    [:TkLEQ,        TkOp,   "<="],
+    [:TkANDOP,      TkOp,   "&&"],
+    [:TkOROP,       TkOp,   "||"],
+    [:TkMATCH,      TkOp,   "=~"],
+    [:TkNMATCH,     TkOp,   "!~"],
+    [:TkDOT2,       TkOp,   ".."],
+    [:TkDOT3,       TkOp,   "..."],
+    [:TkAREF,       TkOp,   "[]"],
+    [:TkASET,       TkOp,   "[]="],
+    [:TkLSHFT,      TkOp,   "<<"],
+    [:TkRSHFT,      TkOp,   ">>"],
+    [:TkCOLON2,     TkOp],
+    [:TkCOLON3,     TkOp],
+#   [:OPASGN,       TkOp],               # +=, -=  etc. #
+    [:TkASSOC,      TkOp,   "=>"],
+    [:TkQUESTION,   TkOp,   "?"],        #?
+    [:TkCOLON,      TkOp,   ":"],        #:
+
+    [:TkfLPAREN],         # func( #
+    [:TkfLBRACK],         # func[ #
+    [:TkfLBRACE],         # func{ #
+    [:TkSTAR],            # *arg
+    [:TkAMPER],           # &arg #
+    [:TkSYMBOL,     TkId],          # :SYMBOL
+    [:TkSYMBEG,     TkId],
+    [:TkGT,         TkOp,   ">"],
+    [:TkLT,         TkOp,   "<"],
+    [:TkPLUS,       TkOp,   "+"],
+    [:TkMINUS,      TkOp,   "-"],
+    [:TkMULT,       TkOp,   "*"],
+    [:TkDIV,        TkOp,   "/"],
+    [:TkMOD,        TkOp,   "%"],
+    [:TkBITOR,      TkOp,   "|"],
+    [:TkBITXOR,     TkOp,   "^"],
+    [:TkBITAND,     TkOp,   "&"],
+    [:TkBITNOT,     TkOp,   "~"],
+    [:TkNOTOP,      TkOp,   "!"],
+
+    [:TkBACKQUOTE,  TkOp,   "`"],
+
+    [:TkASSIGN,     Token,  "="],
+    [:TkDOT,        Token,  "."],
+    [:TkLPAREN,     Token,  "("],  #(exp)
+    [:TkLBRACK,     Token,  "["],  #[arry]
+    [:TkLBRACE,     Token,  "{"],  #{hash}
+    [:TkRPAREN,     Token,  ")"],
+    [:TkRBRACK,     Token,  "]"],
+    [:TkRBRACE,     Token,  "}"],
+    [:TkCOMMA,      Token,  ","],
+    [:TkSEMICOLON,  Token,  ";"],
+
+    [:TkRD_COMMENT],
+    [:TkSPACE],
+    [:TkNL],
+    [:TkEND_OF_SCRIPT],
+
+    [:TkBACKSLASH,  TkUnknownChar,  "\\"],
+    [:TkAT,         TkUnknownChar,  "@"],
+    [:TkDOLLAR,     TkUnknownChar,  "\$"], #"
+  ]
+
+  # {reading => token_class}
+  # {reading => [token_class, *opt]}
+  TkReading2Token = {}
+  TkSymbol2Token = {}
+
+  def self.def_token(token_n, super_token = Token, reading = nil, *opts)
+    token_n = token_n.id2name unless String === token_n
+
+    fail AlreadyDefinedToken, token_n if const_defined?(token_n)
+
+    token_c =  Class.new super_token
+    const_set token_n, token_c
+#    token_c.inspect
+
+    if reading
+      if TkReading2Token[reading]
+        fail TkReading2TokenDuplicateError, token_n, reading
+      end
+      if opts.empty?
+        TkReading2Token[reading] = [token_c]
+      else
+        TkReading2Token[reading] = [token_c].concat(opts)
+      end
+    end
+    TkSymbol2Token[token_n.intern] = token_c
+
+    if token_c <= TkOp
+      token_c.class_eval %{
+        def self.op_name; "#{reading}"; end
+      }
+    end
+  end
+
+  for defs in TokenDefinitions
+    def_token(*defs)
+  end
+
+  NEWLINE_TOKEN = TkNL.new(0,0)
+  NEWLINE_TOKEN.set_text("\n")
+
+end
+
+##
+# Lexical analyzer for Ruby source
+
+class RDoc::RubyLex
+
+  ##
+  # Read an input stream character by character. We allow for unlimited
+  # ungetting of characters just read.
+  #
+  # We simplify the implementation greatly by reading the entire input
+  # into a buffer initially, and then simply traversing it using
+  # pointers.
+  #
+  # We also have to allow for the <i>here document diversion</i>. This
+  # little gem comes about when the lexer encounters a here
+  # document. At this point we effectively need to split the input
+  # stream into two parts: one to read the body of the here document,
+  # the other to read the rest of the input line where the here
+  # document was initially encountered. For example, we might have
+  #
+  #   do_something(<<-A, <<-B)
+  #     stuff
+  #     for
+  #   A
+  #     stuff
+  #     for
+  #   B
+  #
+  # When the lexer encounters the <<A, it reads until the end of the
+  # line, and keeps it around for later. It then reads the body of the
+  # here document.  Once complete, it needs to read the rest of the
+  # original line, but then skip the here document body.
+  #
+
+  class BufferedReader
+
+    attr_reader :line_num
+
+    def initialize(content, options)
+      @options = options
+
+      if /\t/ =~ content
+        tab_width = @options.tab_width
+        content = content.split(/\n/).map do |line|
+          1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)}  && $~ #`
+          line
+        end .join("\n")
+      end
+      @content   = content
+      @content << "\n" unless @content[-1,1] == "\n"
+      @size      = @content.size
+      @offset    = 0
+      @hwm       = 0
+      @line_num  = 1
+      @read_back_offset = 0
+      @last_newline = 0
+      @newline_pending = false
+    end
+
+    def column
+      @offset - @last_newline
+    end
+
+    def getc
+      return nil if @offset >= @size
+      ch = @content[@offset, 1]
+
+      @offset += 1
+      @hwm = @offset if @hwm < @offset
+
+      if @newline_pending
+        @line_num += 1
+        @last_newline = @offset - 1
+        @newline_pending = false
+      end
+
+      if ch == "\n"
+        @newline_pending = true
+      end
+      ch
+    end
+
+    def getc_already_read
+      getc
+    end
+
+    def ungetc(ch)
+      raise "unget past beginning of file" if @offset <= 0
+      @offset -= 1
+      if @content[@offset] == ?\n
+        @newline_pending = false
+      end
+    end
+
+    def get_read
+      res = @content[@read_back_offset... at offset]
+      @read_back_offset = @offset
+      res
+    end
+
+    def peek(at)
+      pos = @offset + at
+      if pos >= @size
+        nil
+      else
+        @content[pos, 1]
+      end
+    end
+
+    def peek_equal(str)
+      @content[@offset, str.length] == str
+    end
+
+    def divert_read_from(reserve)
+      @content[@offset, 0] = reserve
+      @size      = @content.size
+    end
+  end
+
+  # end of nested class BufferedReader
+
+  extend Exception2MessageMapper
+  def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
+  def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')")
+  def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')")
+  def_exception(:TkReading2TokenDuplicateError,
+                "key duplicate(token_n='%s', key='%s')")
+  def_exception(:SyntaxError, "%s")
+
+  include RDoc::RubyToken
+  include IRB
+
+  attr_reader :continue
+  attr_reader :lex_state
+
+  def self.debug?
+    false
+  end
+
+  def initialize(content, options)
+    lex_init
+
+    @options = options
+
+    @reader = BufferedReader.new content, @options
+
+    @exp_line_no = @line_no = 1
+    @base_char_no = 0
+    @indent = 0
+
+    @ltype = nil
+    @quoted = nil
+    @lex_state = EXPR_BEG
+    @space_seen = false
+
+    @continue = false
+    @line = ""
+
+    @skip_space = false
+    @read_auto_clean_up = false
+    @exception_on_syntax_error = true
+  end
+
+  attr_accessor :skip_space
+  attr_accessor :read_auto_clean_up
+  attr_accessor :exception_on_syntax_error
+  attr_reader :indent
+
+  # io functions
+  def line_no
+    @reader.line_num
+  end
+
+  def char_no
+    @reader.column
+  end
+
+  def get_read
+    @reader.get_read
+  end
+
+  def getc
+    @reader.getc
+  end
+
+  def getc_of_rests
+    @reader.getc_already_read
+  end
+
+  def gets
+    c = getc or return
+    l = ""
+    begin
+      l.concat c unless c == "\r"
+      break if c == "\n"
+    end while c = getc
+    l
+  end
+
+
+  def ungetc(c = nil)
+    @reader.ungetc(c)
+  end
+
+  def peek_equal?(str)
+    @reader.peek_equal(str)
+  end
+
+  def peek(i = 0)
+    @reader.peek(i)
+  end
+
+  def lex
+    until (TkNL === (tk = token) or TkEND_OF_SCRIPT === tk) and
+           not @continue or tk.nil?
+    end
+
+    line = get_read
+
+    if line == "" and TkEND_OF_SCRIPT === tk or tk.nil? then
+      nil
+    else
+      line
+    end
+  end
+
+  def token
+    set_token_position(line_no, char_no)
+    begin
+      begin
+        tk = @OP.match(self)
+        @space_seen = TkSPACE === tk
+      rescue SyntaxError => e
+        raise RDoc::Error, "syntax error: #{e.message}" if
+          @exception_on_syntax_error
+
+        tk = TkError.new(line_no, char_no)
+      end
+    end while @skip_space and TkSPACE === tk
+    if @read_auto_clean_up
+      get_read
+    end
+#   throw :eof unless tk
+    tk
+  end
+
+  ENINDENT_CLAUSE = [
+    "case", "class", "def", "do", "for", "if",
+    "module", "unless", "until", "while", "begin" #, "when"
+  ]
+  DEINDENT_CLAUSE = ["end" #, "when"
+  ]
+
+  PERCENT_LTYPE = {
+    "q" => "\'",
+    "Q" => "\"",
+    "x" => "\`",
+    "r" => "/",
+    "w" => "]"
+  }
+
+  PERCENT_PAREN = {
+    "{" => "}",
+    "[" => "]",
+    "<" => ">",
+    "(" => ")"
+  }
+
+  Ltype2Token = {
+    "\'" => TkSTRING,
+    "\"" => TkSTRING,
+    "\`" => TkXSTRING,
+    "/" => TkREGEXP,
+    "]" => TkDSTRING
+  }
+  Ltype2Token.default = TkSTRING
+
+  DLtype2Token = {
+    "\"" => TkDSTRING,
+    "\`" => TkDXSTRING,
+    "/" => TkDREGEXP,
+  }
+
+  def lex_init()
+    @OP = IRB::SLex.new
+    @OP.def_rules("\0", "\004", "\032") do |chars, io|
+      Token(TkEND_OF_SCRIPT).set_text(chars)
+    end
+
+    @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io|
+      @space_seen = TRUE
+      while (ch = getc) =~ /[ \t\f\r\13]/
+        chars << ch
+      end
+      ungetc
+      Token(TkSPACE).set_text(chars)
+    end
+
+    @OP.def_rule("#") do
+      |op, io|
+      identify_comment
+    end
+
+    @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do
+      |op, io|
+      str = op
+      @ltype = "="
+
+
+      begin
+        line = ""
+        begin
+          ch = getc
+          line << ch
+        end until ch == "\n"
+        str << line
+      end until line =~ /^=end/
+
+      ungetc
+
+      @ltype = nil
+
+      if str =~ /\A=begin\s+rdoc/i
+        str.sub!(/\A=begin.*\n/, '')
+        str.sub!(/^=end.*/m, '')
+        Token(TkCOMMENT).set_text(str)
+      else
+        Token(TkRD_COMMENT)#.set_text(str)
+      end
+    end
+
+    @OP.def_rule("\n") do
+      print "\\n\n" if RDoc::RubyLex.debug?
+      case @lex_state
+      when EXPR_BEG, EXPR_FNAME, EXPR_DOT
+        @continue = TRUE
+      else
+        @continue = FALSE
+        @lex_state = EXPR_BEG
+      end
+      Token(TkNL).set_text("\n")
+    end
+
+    @OP.def_rules("*", "**",
+                  "!", "!=", "!~",
+                  "=", "==", "===",
+                  "=~", "<=>",
+                  "<", "<=",
+                  ">", ">=", ">>") do
+      |op, io|
+      @lex_state = EXPR_BEG
+      Token(op).set_text(op)
+    end
+
+    @OP.def_rules("<<") do
+      |op, io|
+      tk = nil
+      if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
+        (@lex_state != EXPR_ARG || @space_seen)
+        c = peek(0)
+        if /[-\w_\"\'\`]/ =~ c
+          tk = identify_here_document
+        end
+      end
+      if !tk
+        @lex_state = EXPR_BEG
+        tk = Token(op).set_text(op)
+      end
+      tk
+    end
+
+    @OP.def_rules("'", '"') do
+      |op, io|
+      identify_string(op)
+    end
+
+    @OP.def_rules("`") do
+      |op, io|
+      if @lex_state == EXPR_FNAME
+        Token(op).set_text(op)
+      else
+        identify_string(op)
+      end
+    end
+
+    @OP.def_rules('?') do
+      |op, io|
+      if @lex_state == EXPR_END
+        @lex_state = EXPR_BEG
+        Token(TkQUESTION).set_text(op)
+      else
+        ch = getc
+        if @lex_state == EXPR_ARG && ch !~ /\s/
+          ungetc
+          @lex_state = EXPR_BEG
+          Token(TkQUESTION).set_text(op)
+        else
+          str = op
+          str << ch
+          if (ch == '\\') #'
+            str << read_escape
+          end
+          @lex_state = EXPR_END
+          Token(TkINTEGER).set_text(str)
+        end
+      end
+    end
+
+    @OP.def_rules("&", "&&", "|", "||") do
+      |op, io|
+      @lex_state = EXPR_BEG
+      Token(op).set_text(op)
+    end
+
+    @OP.def_rules("+=", "-=", "*=", "**=",
+                  "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do
+      |op, io|
+      @lex_state = EXPR_BEG
+      op =~ /^(.*)=$/
+      Token(TkOPASGN, $1).set_text(op)
+    end
+
+    @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io|
+      Token(TkUPLUS).set_text(op)
+    end
+
+    @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io|
+      Token(TkUMINUS).set_text(op)
+    end
+
+    @OP.def_rules("+", "-") do
+      |op, io|
+      catch(:RET) do
+        if @lex_state == EXPR_ARG
+          if @space_seen and peek(0) =~ /[0-9]/
+            throw :RET, identify_number(op)
+          else
+            @lex_state = EXPR_BEG
+          end
+        elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/
+          throw :RET, identify_number(op)
+        else
+          @lex_state = EXPR_BEG
+        end
+        Token(op).set_text(op)
+      end
+    end
+
+    @OP.def_rule(".") do
+      @lex_state = EXPR_BEG
+      if peek(0) =~ /[0-9]/
+        ungetc
+        identify_number("")
+      else
+        # for obj.if
+        @lex_state = EXPR_DOT
+        Token(TkDOT).set_text(".")
+      end
+    end
+
+    @OP.def_rules("..", "...") do
+      |op, io|
+      @lex_state = EXPR_BEG
+      Token(op).set_text(op)
+    end
+
+    lex_int2
+  end
+
+  def lex_int2
+    @OP.def_rules("]", "}", ")") do
+      |op, io|
+      @lex_state = EXPR_END
+      @indent -= 1
+      Token(op).set_text(op)
+    end
+
+    @OP.def_rule(":") do
+      if @lex_state == EXPR_END || peek(0) =~ /\s/
+        @lex_state = EXPR_BEG
+        tk = Token(TkCOLON)
+      else
+        @lex_state = EXPR_FNAME
+        tk = Token(TkSYMBEG)
+      end
+      tk.set_text(":")
+    end
+
+    @OP.def_rule("::") do
+      if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen
+        @lex_state = EXPR_BEG
+        tk = Token(TkCOLON3)
+      else
+        @lex_state = EXPR_DOT
+        tk = Token(TkCOLON2)
+      end
+      tk.set_text("::")
+    end
+
+    @OP.def_rule("/") do
+      |op, io|
+      if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
+        identify_string(op)
+      elsif peek(0) == '='
+        getc
+        @lex_state = EXPR_BEG
+        Token(TkOPASGN, :/).set_text("/=") #")
+      elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
+        identify_string(op)
+      else
+        @lex_state = EXPR_BEG
+        Token("/").set_text(op)
+      end
+    end
+
+    @OP.def_rules("^") do
+      @lex_state = EXPR_BEG
+      Token("^").set_text("^")
+    end
+
+    @OP.def_rules(",", ";") do
+      |op, io|
+      @lex_state = EXPR_BEG
+      Token(op).set_text(op)
+    end
+
+    @OP.def_rule("~") do
+      @lex_state = EXPR_BEG
+      Token("~").set_text("~")
+    end
+
+    @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do
+      @lex_state = EXPR_BEG
+      Token("~").set_text("~@")
+    end
+
+    @OP.def_rule("(") do
+      @indent += 1
+      if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
+        @lex_state = EXPR_BEG
+        tk = Token(TkfLPAREN)
+      else
+        @lex_state = EXPR_BEG
+        tk = Token(TkLPAREN)
+      end
+      tk.set_text("(")
+    end
+
+    @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do
+      Token("[]").set_text("[]")
+    end
+
+    @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do
+      Token("[]=").set_text("[]=")
+    end
+
+    @OP.def_rule("[") do
+      @indent += 1
+      if @lex_state == EXPR_FNAME
+        t = Token(TkfLBRACK)
+      else
+        if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
+          t = Token(TkLBRACK)
+        elsif @lex_state == EXPR_ARG && @space_seen
+          t = Token(TkLBRACK)
+        else
+          t = Token(TkfLBRACK)
+        end
+        @lex_state = EXPR_BEG
+      end
+      t.set_text("[")
+    end
+
+    @OP.def_rule("{") do
+      @indent += 1
+      if @lex_state != EXPR_END && @lex_state != EXPR_ARG
+        t = Token(TkLBRACE)
+      else
+        t = Token(TkfLBRACE)
+      end
+      @lex_state = EXPR_BEG
+      t.set_text("{")
+    end
+
+    @OP.def_rule('\\') do   #'
+      if getc == "\n"
+        @space_seen = true
+        @continue = true
+        Token(TkSPACE).set_text("\\\n")
+      else
+        ungetc
+        Token("\\").set_text("\\")  #"
+      end
+    end
+
+    @OP.def_rule('%') do
+      |op, io|
+      if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
+        identify_quotation('%')
+      elsif peek(0) == '='
+        getc
+        Token(TkOPASGN, "%").set_text("%=")
+      elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
+        identify_quotation('%')
+      else
+        @lex_state = EXPR_BEG
+        Token("%").set_text("%")
+      end
+    end
+
+    @OP.def_rule('$') do  #'
+      identify_gvar
+    end
+
+    @OP.def_rule('@') do
+      if peek(0) =~ /[@\w_]/
+        ungetc
+        identify_identifier
+      else
+        Token("@").set_text("@")
+      end
+    end
+
+    @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do
+      throw :eof
+    end
+
+    @OP.def_rule("") do
+      |op, io|
+      printf "MATCH: start %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
+      if peek(0) =~ /[0-9]/
+        t = identify_number("")
+      elsif peek(0) =~ /[\w_]/
+        t = identify_identifier
+      end
+      printf "MATCH: end %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
+      t
+    end
+  end
+
+  def identify_gvar
+    @lex_state = EXPR_END
+    str = "$"
+
+    tk = case ch = getc
+         when /[~_*$?!@\/\\;,=:<>".]/   #"
+           str << ch
+           Token(TkGVAR, str)
+
+         when "-"
+           str << "-" << getc
+           Token(TkGVAR, str)
+
+         when "&", "`", "'", "+"
+           str << ch
+           Token(TkBACK_REF, str)
+
+         when /[1-9]/
+           str << ch
+           while (ch = getc) =~ /[0-9]/
+             str << ch
+           end
+           ungetc
+           Token(TkNTH_REF)
+         when /\w/
+           ungetc
+           ungetc
+           return identify_identifier
+         else
+           ungetc
+           Token("$")
+         end
+    tk.set_text(str)
+  end
+
+  def identify_identifier
+    token = ""
+    token.concat getc if peek(0) =~ /[$@]/
+    token.concat getc if peek(0) == "@"
+
+    while (ch = getc) =~ /\w|_/
+      print ":", ch, ":" if RDoc::RubyLex.debug?
+      token.concat ch
+    end
+    ungetc
+
+    if ch == "!" or ch == "?"
+      token.concat getc
+    end
+    # fix token
+
+    # $stderr.puts "identifier - #{token}, state = #@lex_state"
+
+    case token
+    when /^\$/
+      return Token(TkGVAR, token).set_text(token)
+    when /^\@/
+      @lex_state = EXPR_END
+      return Token(TkIVAR, token).set_text(token)
+    end
+
+    if @lex_state != EXPR_DOT
+      print token, "\n" if RDoc::RubyLex.debug?
+
+      token_c, *trans = TkReading2Token[token]
+      if token_c
+        # reserved word?
+
+        if (@lex_state != EXPR_BEG &&
+            @lex_state != EXPR_FNAME &&
+            trans[1])
+          # modifiers
+          token_c = TkSymbol2Token[trans[1]]
+          @lex_state = trans[0]
+        else
+          if @lex_state != EXPR_FNAME
+            if ENINDENT_CLAUSE.include?(token)
+              @indent += 1
+            elsif DEINDENT_CLAUSE.include?(token)
+              @indent -= 1
+            end
+            @lex_state = trans[0]
+          else
+            @lex_state = EXPR_END
+          end
+        end
+        return Token(token_c, token).set_text(token)
+      end
+    end
+
+    if @lex_state == EXPR_FNAME
+      @lex_state = EXPR_END
+      if peek(0) == '='
+        token.concat getc
+      end
+    elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
+      @lex_state = EXPR_ARG
+    else
+      @lex_state = EXPR_END
+    end
+
+    if token[0, 1] =~ /[A-Z]/
+      return Token(TkCONSTANT, token).set_text(token)
+    elsif token[token.size - 1, 1] =~ /[!?]/
+      return Token(TkFID, token).set_text(token)
+    else
+      return Token(TkIDENTIFIER, token).set_text(token)
+    end
+  end
+
+  def identify_here_document
+    ch = getc
+    if ch == "-"
+      ch = getc
+      indent = true
+    end
+    if /['"`]/ =~ ch            # '
+      lt = ch
+      quoted = ""
+      while (c = getc) && c != lt
+        quoted.concat c
+      end
+    else
+      lt = '"'
+      quoted = ch.dup
+      while (c = getc) && c =~ /\w/
+        quoted.concat c
+      end
+      ungetc
+    end
+
+    ltback, @ltype = @ltype, lt
+    reserve = ""
+
+    while ch = getc
+      reserve << ch
+      if ch == "\\"    #"
+        ch = getc
+        reserve << ch
+      elsif ch == "\n"
+        break
+      end
+    end
+
+    str = ""
+    while (l = gets)
+      l.chomp!
+      l.strip! if indent
+      break if l == quoted
+      str << l.chomp << "\n"
+    end
+
+    @reader.divert_read_from(reserve)
+
+    @ltype = ltback
+    @lex_state = EXPR_END
+    Token(Ltype2Token[lt], str).set_text(str.dump)
+  end
+
+  def identify_quotation(initial_char)
+    ch = getc
+    if lt = PERCENT_LTYPE[ch]
+      initial_char += ch
+      ch = getc
+    elsif ch =~ /\W/
+      lt = "\""
+    else
+      fail SyntaxError, "unknown type of %string ('#{ch}')"
+    end
+#     if ch !~ /\W/
+#       ungetc
+#       next
+#     end
+    #@ltype = lt
+    @quoted = ch unless @quoted = PERCENT_PAREN[ch]
+    identify_string(lt, @quoted, ch, initial_char)
+  end
+
+  def identify_number(start)
+    str = start.dup
+
+    if start == "+" or start == "-" or start == ""
+      start = getc
+      str << start
+    end
+
+    @lex_state = EXPR_END
+
+    if start == "0"
+      if peek(0) == "x"
+        ch = getc
+        str << ch
+        match = /[0-9a-f_]/
+      else
+        match = /[0-7_]/
+      end
+      while ch = getc
+        if ch !~ match
+          ungetc
+          break
+        else
+          str << ch
+        end
+      end
+      return Token(TkINTEGER).set_text(str)
+    end
+
+    type = TkINTEGER
+    allow_point = TRUE
+    allow_e = TRUE
+    while ch = getc
+      case ch
+      when /[0-9_]/
+        str << ch
+
+      when allow_point && "."
+        type = TkFLOAT
+        if peek(0) !~ /[0-9]/
+          ungetc
+          break
+        end
+        str << ch
+        allow_point = false
+
+      when allow_e && "e", allow_e && "E"
+        str << ch
+        type = TkFLOAT
+        if peek(0) =~ /[+-]/
+          str << getc
+        end
+        allow_e = false
+        allow_point = false
+      else
+        ungetc
+        break
+      end
+    end
+    Token(type).set_text(str)
+  end
+
+  def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil)
+    @ltype = ltype
+    @quoted = quoted
+    subtype = nil
+
+    str = ""
+    str << initial_char if initial_char
+    str << (opener||quoted)
+
+    nest = 0
+    begin
+      while ch = getc
+        str << ch
+        if @quoted == ch
+          if nest == 0
+            break
+          else
+            nest -= 1
+          end
+        elsif opener == ch
+          nest += 1
+        elsif @ltype != "'" && @ltype != "]" and ch == "#"
+          ch = getc
+          if ch == "{"
+            subtype = true
+            str << ch << skip_inner_expression
+          else
+            ungetc(ch)
+          end
+        elsif ch == '\\' #'
+          str << read_escape
+        end
+      end
+      if @ltype == "/"
+        if peek(0) =~ /i|o|n|e|s/
+          str << getc
+        end
+      end
+      if subtype
+        Token(DLtype2Token[ltype], str)
+      else
+        Token(Ltype2Token[ltype], str)
+      end.set_text(str)
+    ensure
+      @ltype = nil
+      @quoted = nil
+      @lex_state = EXPR_END
+    end
+  end
+
+  def skip_inner_expression
+    res = ""
+    nest = 0
+    while (ch = getc)
+      res << ch
+      if ch == '}'
+        break if nest.zero?
+        nest -= 1
+      elsif ch == '{'
+        nest += 1
+      end
+    end
+    res
+  end
+
+  def identify_comment
+    @ltype = "#"
+    comment = "#"
+    while ch = getc
+      if ch == "\\"
+        ch = getc
+        if ch == "\n"
+          ch = " "
+        else
+          comment << "\\"
+        end
+      else
+        if ch == "\n"
+          @ltype = nil
+          ungetc
+          break
+        end
+      end
+      comment << ch
+    end
+    return Token(TkCOMMENT).set_text(comment)
+  end
+
+  def read_escape
+    res = ""
+    case ch = getc
+    when /[0-7]/
+      ungetc ch
+      3.times do
+        case ch = getc
+        when /[0-7]/
+        when nil
+          break
+        else
+          ungetc
+          break
+        end
+        res << ch
+      end
+
+    when "x"
+      res << ch
+      2.times do
+        case ch = getc
+        when /[0-9a-fA-F]/
+        when nil
+          break
+        else
+          ungetc
+          break
+        end
+        res << ch
+      end
+
+    when "M"
+      res << ch
+      if (ch = getc) != '-'
+        ungetc
+      else
+        res << ch
+        if (ch = getc) == "\\" #"
+          res << ch
+          res << read_escape
+        else
+          res << ch
+        end
+      end
+
+    when "C", "c" #, "^"
+      res << ch
+      if ch == "C" and (ch = getc) != "-"
+        ungetc
+      else
+        res << ch
+        if (ch = getc) == "\\" #"
+          res << ch
+          res << read_escape
+        else
+          res << ch
+        end
+      end
+    else
+      res << ch
+    end
+    res
+  end
+end
+
+##
+# Extracts code elements from a source file returning a TopLevel object
+# containing the constituent file elements.
+#
+# This file is based on rtags
+#
+# RubyParser understands how to document:
+# * classes
+# * modules
+# * methods
+# * constants
+# * aliases
+# * private, public, protected
+# * private_class_function, public_class_function
+# * module_function
+# * attr, attr_reader, attr_writer, attr_accessor
+# * extra accessors given on the command line
+# * metaprogrammed methods
+# * require
+# * include
+#
+# == Method Arguments
+#
+#--
+# NOTE: I don't think this works, needs tests, remove the paragraph following
+# this block when known to work
+#
+# The parser extracts the arguments from the method definition.  You can
+# override this with a custom argument definition using the :args: directive:
+#
+#   ##
+#   # This method tries over and over until it is tired
+#   
+#   def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try
+#     puts thing_to_try
+#     go_go_go thing_to_try, tries - 1
+#   end
+#
+# If you have a more-complex set of overrides you can use the :call-seq:
+# directive:
+#++
+#
+# The parser extracts the arguments from the method definition.  You can
+# override this with a custom argument definition using the :call-seq:
+# directive:
+#
+#   ##
+#   # This method can be called with a range or an offset and length
+#   #
+#   # :call-seq:
+#   #   my_method(Range)
+#   #   my_method(offset, length)
+#   
+#   def my_method(*args)
+#   end
+#
+# The parser extracts +yield+ expressions from method bodies to gather the
+# yielded argument names.  If your method manually calls a block instead of
+# yielding or you want to override the discovered argument names use
+# the :yields: directive:
+#
+#   ##
+#   # My method is awesome
+#   
+#   def my_method(&block) # :yields: happy, times
+#     block.call 1, 2
+#   end
+#
+# == Metaprogrammed Methods
+#
+# To pick up a metaprogrammed method, the parser looks for a comment starting
+# with '##' before an identifier:
+#
+#   ##
+#   # This is a meta-programmed method!
+#   
+#   add_my_method :meta_method, :arg1, :arg2
+#
+# The parser looks at the token after the identifier to determine the name, in
+# this example, :meta_method.  If a name cannot be found, a warning is printed
+# and 'unknown is used.
+#
+# You can force the name of a method using the :method: directive:
+#
+#   ##
+#   # :method: woo_hoo!
+#
+# By default, meta-methods are instance methods.  To indicate that a method is
+# a singleton method instead use the :singleton-method: directive:
+#
+#   ##
+#   # :singleton-method:
+#
+# You can also use the :singleton-method: directive with a name:
+#
+#   ##
+#   # :singleton-method: woo_hoo!
+#
+# == Hidden methods
+#
+# You can provide documentation for methods that don't appear using
+# the :method: and :singleton-method: directives:
+#
+#   ##
+#   # :method: ghost_method
+#   # There is a method here, but you can't see it!
+#   
+#   ##
+#   # this is a comment for a regular method
+#   
+#   def regular_method() end
+#
+# Note that by default, the :method: directive will be ignored if there is a
+# standard rdocable item following it.
+
+class RDoc::Parser::Ruby < RDoc::Parser
+
+  parse_files_matching(/\.rbw?$/)
+
+  include RDoc::RubyToken
+  include RDoc::TokenStream
+
+  NORMAL = "::"
+  SINGLE = "<<"
+
+  def initialize(top_level, file_name, content, options, stats)
+    super
+
+    @size = 0
+    @token_listeners = nil
+    @scanner = RDoc::RubyLex.new content, @options
+    @scanner.exception_on_syntax_error = false
+
+    reset
+  end
+
+  def add_token_listener(obj)
+    @token_listeners ||= []
+    @token_listeners << obj
+  end
+
+  ##
+  # Look for the first comment in a file that isn't a shebang line.
+
+  def collect_first_comment
+    skip_tkspace
+    res = ''
+    first_line = true
+
+    tk = get_tk
+
+    while TkCOMMENT === tk
+      if first_line and tk.text =~ /\A#!/ then
+        skip_tkspace
+        tk = get_tk
+      elsif first_line and tk.text =~ /\A#\s*-\*-/ then
+        first_line = false
+        skip_tkspace
+        tk = get_tk
+      else
+        first_line = false
+        res << tk.text << "\n"
+        tk = get_tk
+
+        if TkNL === tk then
+          skip_tkspace false
+          tk = get_tk
+        end
+      end
+    end
+
+    unget_tk tk
+
+    res
+  end
+
+  def error(msg)
+    msg = make_message msg
+    $stderr.puts msg
+    exit(1)
+  end
+
+  ##
+  # Look for a 'call-seq' in the comment, and override the normal parameter
+  # stuff
+
+  def extract_call_seq(comment, meth)
+    if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '') then
+      seq = $1
+      seq.gsub!(/^\s*\#\s*/, '')
+      meth.call_seq = seq
+    end
+
+    meth
+  end
+
+  def get_bool
+    skip_tkspace
+    tk = get_tk
+    case tk
+    when TkTRUE
+      true
+    when TkFALSE, TkNIL
+      false
+    else
+      unget_tk tk
+      true
+    end
+  end
+
+  ##
+  # Look for the name of a class of module (optionally with a leading :: or
+  # with :: separated named) and return the ultimate name and container
+
+  def get_class_or_module(container)
+    skip_tkspace
+    name_t = get_tk
+
+    # class ::A -> A is in the top level
+    if TkCOLON2 === name_t then
+      name_t = get_tk
+      container = @top_level
+    end
+
+    skip_tkspace(false)
+
+    while TkCOLON2 === peek_tk do
+      prev_container = container
+      container = container.find_module_named(name_t.name)
+      if !container
+#          warn("Couldn't find module #{name_t.name}")
+        container = prev_container.add_module RDoc::NormalModule, name_t.name
+      end
+      get_tk
+      name_t = get_tk
+    end
+    skip_tkspace(false)
+    return [container, name_t]
+  end
+
+  ##
+  # Return a superclass, which can be either a constant of an expression
+
+  def get_class_specification
+    tk = get_tk
+    return "self" if TkSELF === tk
+
+    res = ""
+    while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
+      res += tk.text
+      tk = get_tk
+    end
+
+    unget_tk(tk)
+    skip_tkspace(false)
+
+    get_tkread # empty out read buffer
+
+    tk = get_tk
+
+    case tk
+    when TkNL, TkCOMMENT, TkSEMICOLON then
+      unget_tk(tk)
+      return res
+    end
+
+    res += parse_call_parameters(tk)
+    res
+  end
+
+  ##
+  # Parse a constant, which might be qualified by one or more class or module
+  # names
+
+  def get_constant
+    res = ""
+    skip_tkspace(false)
+    tk = get_tk
+
+    while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
+      res += tk.text
+      tk = get_tk
+    end
+
+#      if res.empty?
+#        warn("Unexpected token #{tk} in constant")
+#      end
+    unget_tk(tk)
+    res
+  end
+
+  ##
+  # Get a constant that may be surrounded by parens
+
+  def get_constant_with_optional_parens
+    skip_tkspace(false)
+    nest = 0
+    while TkLPAREN === (tk = peek_tk) or TkfLPAREN === tk do
+      get_tk
+      skip_tkspace(true)
+      nest += 1
+    end
+
+    name = get_constant
+
+    while nest > 0
+      skip_tkspace(true)
+      tk = get_tk
+      nest -= 1 if TkRPAREN === tk
+    end
+    name
+  end
+
+  def get_symbol_or_name
+    tk = get_tk
+    case tk
+    when  TkSYMBOL
+      tk.text.sub(/^:/, '')
+    when TkId, TkOp
+      tk.name
+    when TkSTRING
+      tk.text
+    else
+      raise "Name or symbol expected (got #{tk})"
+    end
+  end
+
+  def get_tk
+    tk = nil
+    if @tokens.empty?
+      tk = @scanner.token
+      @read.push @scanner.get_read
+      puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG
+    else
+      @read.push @unget_read.shift
+      tk = @tokens.shift
+      puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG
+    end
+
+    if TkSYMBEG === tk then
+      set_token_position(tk.line_no, tk.char_no)
+      tk1 = get_tk
+      if TkId === tk1 or TkOp === tk1 or TkSTRING === tk1 then
+        if tk1.respond_to?(:name)
+          tk = Token(TkSYMBOL).set_text(":" + tk1.name)
+        else
+          tk = Token(TkSYMBOL).set_text(":" + tk1.text)
+        end
+        # remove the identifier we just read (we're about to
+        # replace it with a symbol)
+        @token_listeners.each do |obj|
+          obj.pop_token
+        end if @token_listeners
+      else
+        warn("':' not followed by identifier or operator")
+        tk = tk1
+      end
+    end
+
+    # inform any listeners of our shiny new token
+    @token_listeners.each do |obj|
+      obj.add_token(tk)
+    end if @token_listeners
+
+    tk
+  end
+
+  def get_tkread
+    read = @read.join("")
+    @read = []
+    read
+  end
+
+  ##
+  # Look for directives in a normal comment block:
+  #
+  #   #-- - don't display comment from this point forward
+  #
+  # This routine modifies it's parameter
+
+  def look_for_directives_in(context, comment)
+    preprocess = RDoc::Markup::PreProcess.new(@file_name,
+                                              @options.rdoc_include)
+
+    preprocess.handle(comment) do |directive, param|
+      case directive
+      when 'enddoc' then
+        throw :enddoc
+      when 'main' then
+        @options.main_page = param
+        ''
+      when 'method', 'singleton-method' then
+        false # ignore
+      when 'section' then
+        context.set_current_section(param, comment)
+        comment.replace ''
+        break
+      when 'startdoc' then
+        context.start_doc
+        context.force_documentation = true
+        ''
+      when 'stopdoc' then
+        context.stop_doc
+        ''
+      when 'title' then
+        @options.title = param
+        ''
+      else
+        warn "Unrecognized directive '#{directive}'"
+        false
+      end
+    end
+
+    remove_private_comments(comment)
+  end
+
+  def make_message(msg)
+    prefix = "\n" + @file_name + ":"
+    if @scanner
+      prefix << "#{@scanner.line_no}:#{@scanner.char_no}: "
+    end
+    return prefix + msg
+  end
+
+  def parse_attr(context, single, tk, comment)
+    args = parse_symbol_arg(1)
+    if args.size > 0
+      name = args[0]
+      rw = "R"
+      skip_tkspace(false)
+      tk = get_tk
+      if TkCOMMA === tk then
+        rw = "RW" if get_bool
+      else
+        unget_tk tk
+      end
+      att = RDoc::Attr.new get_tkread, name, rw, comment
+      read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
+      if att.document_self
+        context.add_attribute(att)
+      end
+    else
+      warn("'attr' ignored - looks like a variable")
+    end
+  end
+
+  def parse_attr_accessor(context, single, tk, comment)
+    args = parse_symbol_arg
+    read = get_tkread
+    rw = "?"
+
+    # If nodoc is given, don't document any of them
+
+    tmp = RDoc::CodeObject.new
+    read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
+    return unless tmp.document_self
+
+    case tk.name
+    when "attr_reader"   then rw = "R"
+    when "attr_writer"   then rw = "W"
+    when "attr_accessor" then rw = "RW"
+    else
+      rw = @options.extra_accessor_flags[tk.name]
+      rw = '?' if rw.nil?
+    end
+
+    for name in args
+      att = RDoc::Attr.new get_tkread, name, rw, comment
+      context.add_attribute att
+    end
+  end
+
+  def parse_alias(context, single, tk, comment)
+    skip_tkspace
+    if TkLPAREN === peek_tk then
+      get_tk
+      skip_tkspace
+    end
+    new_name = get_symbol_or_name
+    @scanner.instance_eval{@lex_state = EXPR_FNAME}
+    skip_tkspace
+    if TkCOMMA === peek_tk then
+      get_tk
+      skip_tkspace
+    end
+    old_name = get_symbol_or_name
+
+    al = RDoc::Alias.new get_tkread, old_name, new_name, comment
+    read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
+    if al.document_self
+      context.add_alias(al)
+    end
+  end
+
+  def parse_call_parameters(tk)
+    end_token = case tk
+                when TkLPAREN, TkfLPAREN
+                  TkRPAREN
+                when TkRPAREN
+                  return ""
+                else
+                  TkNL
+                end
+    nest = 0
+
+    loop do
+        case tk
+        when TkSEMICOLON
+          break
+        when TkLPAREN, TkfLPAREN
+          nest += 1
+        when end_token
+          if end_token == TkRPAREN
+            nest -= 1
+            break if @scanner.lex_state == EXPR_END and nest <= 0
+          else
+            break unless @scanner.continue
+          end
+        when TkCOMMENT
+          unget_tk(tk)
+          break
+        end
+        tk = get_tk
+    end
+    res = get_tkread.tr("\n", " ").strip
+    res = "" if res == ";"
+    res
+  end
+
+  def parse_class(container, single, tk, comment)
+    container, name_t = get_class_or_module(container)
+
+    case name_t
+    when TkCONSTANT
+      name = name_t.name
+      superclass = "Object"
+
+      if TkLT === peek_tk then
+        get_tk
+        skip_tkspace(true)
+        superclass = get_class_specification
+        superclass = "<unknown>" if superclass.empty?
+      end
+
+      cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
+      cls = container.add_class cls_type, name, superclass
+
+      @stats.add_class cls
+
+      read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
+      cls.record_location @top_level
+
+      parse_statements cls
+      cls.comment = comment
+
+    when TkLSHFT
+      case name = get_class_specification
+      when "self", container.name
+        parse_statements(container, SINGLE)
+      else
+        other = RDoc::TopLevel.find_class_named(name)
+        unless other
+          #            other = @top_level.add_class(NormalClass, name, nil)
+          #            other.record_location(@top_level)
+          #            other.comment = comment
+          other = RDoc::NormalClass.new "Dummy", nil
+        end
+
+        @stats.add_class other
+
+        read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
+        parse_statements(other, SINGLE)
+      end
+
+    else
+      warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}")
+    end
+  end
+
+  def parse_constant(container, single, tk, comment)
+    name = tk.name
+    skip_tkspace(false)
+    eq_tk = get_tk
+
+    unless TkASSIGN === eq_tk then
+      unget_tk(eq_tk)
+      return
+    end
+
+
+    nest = 0
+    get_tkread
+
+    tk = get_tk
+    if TkGT === tk then
+      unget_tk(tk)
+      unget_tk(eq_tk)
+      return
+    end
+
+    loop do
+        case tk
+        when TkSEMICOLON
+          break
+        when TkLPAREN, TkfLPAREN, TkLBRACE, TkLBRACK, TkDO
+          nest += 1
+        when TkRPAREN, TkRBRACE, TkRBRACK, TkEND
+          nest -= 1
+        when TkCOMMENT
+          if nest <= 0 && @scanner.lex_state == EXPR_END
+            unget_tk(tk)
+            break
+          end
+        when TkNL
+          if (nest <= 0) && ((@scanner.lex_state == EXPR_END) || (!@scanner.continue))
+            unget_tk(tk)
+            break
+          end
+        end
+        tk = get_tk
+    end
+
+    res = get_tkread.tr("\n", " ").strip
+    res = "" if res == ";"
+
+    con = RDoc::Constant.new name, res, comment
+    read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
+
+    if con.document_self
+      container.add_constant(con)
+    end
+  end
+
+  def parse_comment(container, tk, comment)
+    line_no = tk.line_no
+    column  = tk.char_no
+
+    singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
+
+    if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
+      name = $1 unless $1.empty?
+    else
+      return nil
+    end
+
+    meth = RDoc::GhostMethod.new get_tkread, name
+    meth.singleton = singleton
+
+    @stats.add_method meth
+
+    meth.start_collecting_tokens
+    indent = TkSPACE.new 1, 1
+    indent.set_text " " * column
+
+    position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
+    meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
+
+    meth.params = ''
+
+    extract_call_seq comment, meth
+
+    container.add_method meth if meth.document_self
+
+    meth.comment = comment
+  end
+
+  def parse_include(context, comment)
+    loop do
+      skip_tkspace_comment
+
+      name = get_constant_with_optional_parens
+      context.add_include RDoc::Include.new(name, comment) unless name.empty?
+
+      return unless TkCOMMA === peek_tk
+      get_tk
+    end
+  end
+
+  ##
+  # Parses a meta-programmed method
+
+  def parse_meta_method(container, single, tk, comment)
+    line_no = tk.line_no
+    column  = tk.char_no
+
+    start_collecting_tokens
+    add_token tk
+    add_token_listener self
+
+    skip_tkspace false
+
+    singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
+
+    if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
+      name = $1 unless $1.empty?
+    end
+
+    if name.nil? then
+      name_t = get_tk
+      case name_t
+      when TkSYMBOL then
+        name = name_t.text[1..-1]
+      when TkSTRING then
+        name = name_t.text[1..-2]
+      else
+        warn "#{container.top_level.file_relative_name}:#{name_t.line_no} unknown name token #{name_t.inspect} for meta-method"
+        name = 'unknown'
+      end
+    end
+
+    meth = RDoc::MetaMethod.new get_tkread, name
+    meth.singleton = singleton
+
+    @stats.add_method meth
+
+    remove_token_listener self
+
+    meth.start_collecting_tokens
+    indent = TkSPACE.new 1, 1
+    indent.set_text " " * column
+
+    position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
+    meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
+    meth.add_tokens @token_stream
+
+    add_token_listener meth
+
+    meth.params = ''
+
+    extract_call_seq comment, meth
+
+    container.add_method meth if meth.document_self
+
+    last_tk = tk
+
+    while tk = get_tk do
+      case tk
+      when TkSEMICOLON then
+        break
+      when TkNL then
+        break unless last_tk and TkCOMMA === last_tk
+      when TkSPACE then
+        # expression continues
+      else
+        last_tk = tk
+      end
+    end
+
+    remove_token_listener meth
+
+    meth.comment = comment
+  end
+
+  ##
+  # Parses a method
+
+  def parse_method(container, single, tk, comment)
+    line_no = tk.line_no
+    column  = tk.char_no
+
+    start_collecting_tokens
+    add_token(tk)
+    add_token_listener(self)
+
+    @scanner.instance_eval do @lex_state = EXPR_FNAME end
+
+    skip_tkspace(false)
+    name_t = get_tk
+    back_tk = skip_tkspace
+    meth = nil
+    added_container = false
+
+    dot = get_tk
+    if TkDOT === dot or TkCOLON2 === dot then
+      @scanner.instance_eval do @lex_state = EXPR_FNAME end
+      skip_tkspace
+      name_t2 = get_tk
+
+      case name_t
+      when TkSELF then
+        name = name_t2.name
+      when TkCONSTANT then
+        name = name_t2.name
+        prev_container = container
+        container = container.find_module_named(name_t.name)
+        unless container then
+          added_container = true
+          obj = name_t.name.split("::").inject(Object) do |state, item|
+            state.const_get(item)
+          end rescue nil
+
+          type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
+
+          unless [Class, Module].include?(obj.class) then
+            warn("Couldn't find #{name_t.name}. Assuming it's a module")
+          end
+
+          if type == RDoc::NormalClass then
+            container = prev_container.add_class(type, name_t.name, obj.superclass.name)
+          else
+            container = prev_container.add_module(type, name_t.name)
+          end
+
+          container.record_location @top_level
+        end
+      else
+        # warn("Unexpected token '#{name_t2.inspect}'")
+        # break
+        skip_method(container)
+        return
+      end
+
+      meth = RDoc::AnyMethod.new(get_tkread, name)
+      meth.singleton = true
+    else
+      unget_tk dot
+      back_tk.reverse_each do |token|
+        unget_tk token
+      end
+      name = name_t.name
+
+      meth = RDoc::AnyMethod.new get_tkread, name
+      meth.singleton = (single == SINGLE)
+    end
+
+    @stats.add_method meth
+
+    remove_token_listener self
+
+    meth.start_collecting_tokens
+    indent = TkSPACE.new 1, 1
+    indent.set_text " " * column
+
+    token = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
+    meth.add_tokens [token, NEWLINE_TOKEN, indent]
+    meth.add_tokens @token_stream
+
+    add_token_listener meth
+
+    @scanner.instance_eval do @continue = false end
+    parse_method_parameters meth
+
+    if meth.document_self then
+      container.add_method meth
+    elsif added_container then
+      container.document_self = false
+    end
+
+    # Having now read the method parameters and documentation modifiers, we
+    # now know whether we have to rename #initialize to ::new
+
+    if name == "initialize" && !meth.singleton then
+      if meth.dont_rename_initialize then
+        meth.visibility = :protected
+      else
+        meth.singleton = true
+        meth.name = "new"
+        meth.visibility = :public
+      end
+    end
+
+    parse_statements(container, single, meth)
+
+    remove_token_listener(meth)
+
+    extract_call_seq comment, meth
+
+    meth.comment = comment
+  end
+
+  def parse_method_or_yield_parameters(method = nil,
+                                       modifiers = RDoc::METHOD_MODIFIERS)
+    skip_tkspace(false)
+    tk = get_tk
+
+    # Little hack going on here. In the statement
+    #  f = 2*(1+yield)
+    # We see the RPAREN as the next token, so we need
+    # to exit early. This still won't catch all cases
+    # (such as "a = yield + 1"
+    end_token = case tk
+                when TkLPAREN, TkfLPAREN
+                  TkRPAREN
+                when TkRPAREN
+                  return ""
+                else
+                  TkNL
+                end
+    nest = 0
+
+    loop do
+        case tk
+        when TkSEMICOLON
+          break
+        when TkLBRACE
+          nest += 1
+        when TkRBRACE
+          # we might have a.each {|i| yield i }
+          unget_tk(tk) if nest.zero?
+          nest -= 1
+          break if nest <= 0
+        when TkLPAREN, TkfLPAREN
+          nest += 1
+        when end_token
+          if end_token == TkRPAREN
+            nest -= 1
+            break if @scanner.lex_state == EXPR_END and nest <= 0
+          else
+            break unless @scanner.continue
+          end
+        when method && method.block_params.nil? && TkCOMMENT
+          unget_tk(tk)
+          read_documentation_modifiers(method, modifiers)
+        end
+      tk = get_tk
+    end
+    res = get_tkread.tr("\n", " ").strip
+    res = "" if res == ";"
+    res
+  end
+
+  ##
+  # Capture the method's parameters. Along the way, look for a comment
+  # containing:
+  #
+  #    # yields: ....
+  #
+  # and add this as the block_params for the method
+
+  def parse_method_parameters(method)
+    res = parse_method_or_yield_parameters(method)
+    res = "(" + res + ")" unless res[0] == ?(
+    method.params = res unless method.params
+    if method.block_params.nil?
+      skip_tkspace(false)
+      read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
+    end
+  end
+
+  def parse_module(container, single, tk, comment)
+    container, name_t = get_class_or_module(container)
+
+    name = name_t.name
+
+    mod = container.add_module RDoc::NormalModule, name
+    mod.record_location @top_level
+
+    @stats.add_module mod
+
+    read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
+    parse_statements(mod)
+    mod.comment = comment
+  end
+
+  def parse_require(context, comment)
+    skip_tkspace_comment
+    tk = get_tk
+    if TkLPAREN === tk then
+      skip_tkspace_comment
+      tk = get_tk
+    end
+
+    name = nil
+    case tk
+    when TkSTRING
+      name = tk.text
+      #    when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR
+      #      name = tk.name
+    when TkDSTRING
+      warn "Skipping require of dynamic string: #{tk.text}"
+      #   else
+      #     warn "'require' used as variable"
+    end
+    if name
+      context.add_require RDoc::Require.new(name, comment)
+    else
+      unget_tk(tk)
+    end
+  end
+
+  def parse_statements(container, single = NORMAL, current_method = nil,
+                       comment = '')
+    nest = 1
+    save_visibility = container.visibility
+
+    non_comment_seen = true
+
+    while tk = get_tk do
+      keep_comment = false
+
+      non_comment_seen = true unless TkCOMMENT === tk
+
+      case tk
+      when TkNL then
+        skip_tkspace true # Skip blanks and newlines
+        tk = get_tk
+
+        if TkCOMMENT === tk then
+          if non_comment_seen then
+            # Look for RDoc in a comment about to be thrown away
+            parse_comment container, tk, comment unless comment.empty?
+
+            comment = ''
+            non_comment_seen = false
+          end
+
+          while TkCOMMENT === tk do
+            comment << tk.text << "\n"
+            tk = get_tk          # this is the newline
+            skip_tkspace(false)  # leading spaces
+            tk = get_tk
+          end
+
+          unless comment.empty? then
+            look_for_directives_in container, comment
+
+            if container.done_documenting then
+              container.ongoing_visibility = save_visibility
+            end
+          end
+
+          keep_comment = true
+        else
+          non_comment_seen = true
+        end
+
+        unget_tk tk
+        keep_comment = true
+
+      when TkCLASS then
+        if container.document_children then
+          parse_class container, single, tk, comment
+        else
+          nest += 1
+        end
+
+      when TkMODULE then
+        if container.document_children then
+          parse_module container, single, tk, comment
+        else
+          nest += 1
+        end
+
+      when TkDEF then
+        if container.document_self then
+          parse_method container, single, tk, comment
+        else
+          nest += 1
+        end
+
+      when TkCONSTANT then
+        if container.document_self then
+          parse_constant container, single, tk, comment
+        end
+
+      when TkALIAS then
+        if container.document_self then
+          parse_alias container, single, tk, comment
+        end
+
+      when TkYIELD then
+        if current_method.nil? then
+          warn "Warning: yield outside of method" if container.document_self
+        else
+          parse_yield container, single, tk, current_method
+        end
+
+      # Until and While can have a 'do', which shouldn't increase the nesting.
+      # We can't solve the general case, but we can handle most occurrences by
+      # ignoring a do at the end of a line.
+
+      when  TkUNTIL, TkWHILE then
+        nest += 1
+        skip_optional_do_after_expression
+
+      # 'for' is trickier
+      when TkFOR then
+        nest += 1
+        skip_for_variable
+        skip_optional_do_after_expression
+
+      when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then
+        nest += 1
+
+      when TkIDENTIFIER then
+        if nest == 1 and current_method.nil? then
+          case tk.name
+          when 'private', 'protected', 'public', 'private_class_method',
+               'public_class_method', 'module_function' then
+            parse_visibility container, single, tk
+            keep_comment = true
+          when 'attr' then
+            parse_attr container, single, tk, comment
+          when /^attr_(reader|writer|accessor)$/, @options.extra_accessors then
+            parse_attr_accessor container, single, tk, comment
+          when 'alias_method' then
+            if container.document_self then
+              parse_alias container, single, tk, comment
+            end
+          else
+            if container.document_self and comment =~ /\A#\#$/ then
+              parse_meta_method container, single, tk, comment
+            end
+          end
+        end
+
+        case tk.name
+        when "require" then
+          parse_require container, comment
+        when "include" then
+          parse_include container, comment
+        end
+
+      when TkEND then
+        nest -= 1
+        if nest == 0 then
+          read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
+          container.ongoing_visibility = save_visibility
+          return
+        end
+
+      end
+
+      comment = '' unless keep_comment
+
+      begin
+        get_tkread
+        skip_tkspace(false)
+      end while peek_tk == TkNL
+    end
+  end
+
+  def parse_symbol_arg(no = nil)
+    args = []
+    skip_tkspace_comment
+    case tk = get_tk
+    when TkLPAREN
+      loop do
+        skip_tkspace_comment
+        if tk1 = parse_symbol_in_arg
+          args.push tk1
+          break if no and args.size >= no
+        end
+
+        skip_tkspace_comment
+        case tk2 = get_tk
+        when TkRPAREN
+          break
+        when TkCOMMA
+        else
+          warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
+          break
+        end
+      end
+    else
+      unget_tk tk
+      if tk = parse_symbol_in_arg
+        args.push tk
+        return args if no and args.size >= no
+      end
+
+      loop do
+        skip_tkspace(false)
+
+        tk1 = get_tk
+        unless TkCOMMA === tk1 then
+          unget_tk tk1
+          break
+        end
+
+        skip_tkspace_comment
+        if tk = parse_symbol_in_arg
+          args.push tk
+          break if no and args.size >= no
+        end
+      end
+    end
+    args
+  end
+
+  def parse_symbol_in_arg
+    case tk = get_tk
+    when TkSYMBOL
+      tk.text.sub(/^:/, '')
+    when TkSTRING
+      eval @read[-1]
+    else
+      warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
+      nil
+    end
+  end
+
+  def parse_toplevel_statements(container)
+    comment = collect_first_comment
+    look_for_directives_in(container, comment)
+    container.comment = comment unless comment.empty?
+    parse_statements container, NORMAL, nil, comment
+  end
+
+  def parse_visibility(container, single, tk)
+    singleton = (single == SINGLE)
+
+    vis_type = tk.name
+
+    vis = case vis_type
+          when 'private'   then :private
+          when 'protected' then :protected
+          when 'public'    then :public
+          when 'private_class_method' then
+            singleton = true
+            :private
+          when 'public_class_method' then
+            singleton = true
+            :public
+          when 'module_function' then
+            singleton = true
+            :public
+          else
+            raise "Invalid visibility: #{tk.name}"
+          end
+
+    skip_tkspace_comment false
+
+    case peek_tk
+      # Ryan Davis suggested the extension to ignore modifiers, because he
+      # often writes
+      #
+      #   protected unless $TESTING
+      #
+    when TkNL, TkUNLESS_MOD, TkIF_MOD, TkSEMICOLON then
+      container.ongoing_visibility = vis
+    else
+      if vis_type == 'module_function' then
+        args = parse_symbol_arg
+        container.set_visibility_for args, :private, false
+
+        module_functions = []
+
+        container.methods_matching args do |m|
+          s_m = m.dup
+          s_m.singleton = true if RDoc::AnyMethod === s_m
+          s_m.visibility = :public
+          module_functions << s_m
+        end
+
+        module_functions.each do |s_m|
+          case s_m
+          when RDoc::AnyMethod then
+            container.add_method s_m
+          when RDoc::Attr then
+            container.add_attribute s_m
+          end
+        end
+      else
+        args = parse_symbol_arg
+        container.set_visibility_for args, vis, singleton
+      end
+    end
+  end
+
+  def parse_yield_parameters
+    parse_method_or_yield_parameters
+  end
+
+  def parse_yield(context, single, tk, method)
+    if method.block_params.nil?
+      get_tkread
+      @scanner.instance_eval{@continue = false}
+      method.block_params = parse_yield_parameters
+    end
+  end
+
+  def peek_read
+    @read.join('')
+  end
+
+  ##
+  # Peek at the next token, but don't remove it from the stream
+
+  def peek_tk
+    unget_tk(tk = get_tk)
+    tk
+  end
+
+  ##
+  # Directives are modifier comments that can appear after class, module, or
+  # method names. For example:
+  #
+  #   def fred # :yields: a, b
+  #
+  # or:
+  #
+  #   class MyClass # :nodoc:
+  #
+  # We return the directive name and any parameters as a two element array
+
+  def read_directive(allowed)
+    tk = get_tk
+    result = nil
+    if TkCOMMENT === tk
+      if tk.text =~ /\s*:?(\w+):\s*(.*)/
+        directive = $1.downcase
+        if allowed.include?(directive)
+          result = [directive, $2]
+        end
+      end
+    else
+      unget_tk(tk)
+    end
+    result
+  end
+
+  def read_documentation_modifiers(context, allow)
+    dir = read_directive(allow)
+
+    case dir[0]
+    when "notnew", "not_new", "not-new" then
+      context.dont_rename_initialize = true
+
+    when "nodoc" then
+      context.document_self = false
+      if dir[1].downcase == "all"
+        context.document_children = false
+      end
+
+    when "doc" then
+      context.document_self = true
+      context.force_documentation = true
+
+    when "yield", "yields" then
+      unless context.params.nil?
+        context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
+      end
+
+      context.block_params = dir[1]
+
+    when "arg", "args" then
+      context.params = dir[1]
+    end if dir
+  end
+
+  def remove_private_comments(comment)
+    comment.gsub!(/^#--\n.*?^#\+\+/m, '')
+    comment.sub!(/^#--\n.*/m, '')
+  end
+
+  def remove_token_listener(obj)
+    @token_listeners.delete(obj)
+  end
+
+  def reset
+    @tokens = []
+    @unget_read = []
+    @read = []
+  end
+
+  def scan
+    reset
+
+    catch(:eof) do
+      catch(:enddoc) do
+        begin
+          parse_toplevel_statements(@top_level)
+        rescue Exception => e
+          $stderr.puts <<-EOF
+
+
+RDoc failure in #{@file_name} at or around line #{@scanner.line_no} column
+#{@scanner.char_no}
+
+Before reporting this, could you check that the file you're documenting
+compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if
+fed invalid programs.
+
+The internal error was:
+
+          EOF
+
+          e.set_backtrace(e.backtrace[0,4])
+          raise
+        end
+      end
+    end
+
+    @top_level
+  end
+
+  ##
+  # while, until, and for have an optional do
+
+  def skip_optional_do_after_expression
+    skip_tkspace(false)
+    tk = get_tk
+    case tk
+    when TkLPAREN, TkfLPAREN
+      end_token = TkRPAREN
+    else
+      end_token = TkNL
+    end
+
+    nest = 0
+    @scanner.instance_eval{@continue = false}
+
+    loop do
+      case tk
+      when TkSEMICOLON
+        break
+      when TkLPAREN, TkfLPAREN
+        nest += 1
+      when TkDO
+        break if nest.zero?
+      when end_token
+        if end_token == TkRPAREN
+          nest -= 1
+          break if @scanner.lex_state == EXPR_END and nest.zero?
+        else
+          break unless @scanner.continue
+        end
+      end
+      tk = get_tk
+    end
+    skip_tkspace(false)
+
+    get_tk if TkDO === peek_tk
+  end
+
+  ##
+  # skip the var [in] part of a 'for' statement
+
+  def skip_for_variable
+    skip_tkspace(false)
+    tk = get_tk
+    skip_tkspace(false)
+    tk = get_tk
+    unget_tk(tk) unless TkIN === tk
+  end
+
+  def skip_method(container)
+    meth = RDoc::AnyMethod.new "", "anon"
+    parse_method_parameters(meth)
+    parse_statements(container, false, meth)
+  end
+
+  ##
+  # Skip spaces
+
+  def skip_tkspace(skip_nl = true)
+    tokens = []
+
+    while TkSPACE === (tk = get_tk) or (skip_nl and TkNL === tk) do
+      tokens.push tk
+    end
+
+    unget_tk(tk)
+    tokens
+  end
+
+  ##
+  # Skip spaces until a comment is found
+
+  def skip_tkspace_comment(skip_nl = true)
+    loop do
+      skip_tkspace(skip_nl)
+      return unless TkCOMMENT === peek_tk
+      get_tk
+    end
+  end
+
+  def unget_tk(tk)
+    @tokens.unshift tk
+    @unget_read.unshift @read.pop
+
+    # Remove this token from any listeners
+    @token_listeners.each do |obj|
+      obj.pop_token
+    end if @token_listeners
+  end
+
+  def warn(msg)
+    return if @options.quiet
+    msg = make_message msg
+    $stderr.puts msg
+  end
+
+end
+

Deleted: MacRuby/branches/experimental/lib/rdoc/parser/simple.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/parser/simple.rb	2009-06-19 21:09:10 UTC (rev 1886)
+++ MacRuby/branches/experimental/lib/rdoc/parser/simple.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,38 +0,0 @@
-require 'rdoc/parser'
-
-##
-# Parse a non-source file. We basically take the whole thing as one big
-# comment. If the first character in the file is '#', we strip leading pound
-# signs.
-
-class RDoc::Parser::Simple < RDoc::Parser
-
-  parse_files_matching(//)
-
-  ##
-  # Prepare to parse a plain file
-
-  def initialize(top_level, file_name, content, options, stats)
-    super
-
-    preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
-
-    preprocess.handle @content do |directive, param|
-      warn "Unrecognized directive '#{directive}' in #{@file_name}"
-    end
-  end
-
-  ##
-  # Extract the file contents and attach them to the toplevel as a comment
-
-  def scan
-    @top_level.comment = remove_private_comments(@content)
-    @top_level
-  end
-
-  def remove_private_comments(comment)
-    comment.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '')
-  end
-
-end
-

Copied: MacRuby/branches/experimental/lib/rdoc/parser/simple.rb (from rev 1886, MacRuby/trunk/lib/rdoc/parser/simple.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/parser/simple.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/parser/simple.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,38 @@
+require 'rdoc/parser'
+
+##
+# Parse a non-source file. We basically take the whole thing as one big
+# comment. If the first character in the file is '#', we strip leading pound
+# signs.
+
+class RDoc::Parser::Simple < RDoc::Parser
+
+  parse_files_matching(//)
+
+  ##
+  # Prepare to parse a plain file
+
+  def initialize(top_level, file_name, content, options, stats)
+    super
+
+    preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
+
+    preprocess.handle @content do |directive, param|
+      warn "Unrecognized directive '#{directive}' in #{@file_name}"
+    end
+  end
+
+  ##
+  # Extract the file contents and attach them to the toplevel as a comment
+
+  def scan
+    @top_level.comment = remove_private_comments(@content)
+    @top_level
+  end
+
+  def remove_private_comments(comment)
+    comment.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '')
+  end
+
+end
+

Copied: MacRuby/branches/experimental/lib/rdoc/parser.rb (from rev 1886, MacRuby/trunk/lib/rdoc/parser.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/parser.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rdoc/parser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,146 @@
+require 'rdoc'
+require 'rdoc/code_objects'
+require 'rdoc/markup/preprocess'
+require 'rdoc/stats'
+
+##
+# A parser is simple a class that implements
+#
+#   #initialize(file_name, body, options)
+#
+# and
+#
+#   #scan
+#
+# The initialize method takes a file name to be used, the body of the file,
+# and an RDoc::Options object. The scan method is then called to return an
+# appropriately parsed TopLevel code object.
+#
+# The ParseFactory is used to redirect to the correct parser given a
+# filename extension. This magic works because individual parsers have to
+# register themselves with us as they are loaded in. The do this using the
+# following incantation
+#
+#   require "rdoc/parser"
+#   
+#   class RDoc::Parser::Xyz < RDoc::Parser
+#     parse_files_matching /\.xyz$/ # <<<<
+#   
+#     def initialize(file_name, body, options)
+#       ...
+#     end
+#   
+#     def scan
+#       ...
+#     end
+#   end
+#
+# Just to make life interesting, if we suspect a plain text file, we also
+# look for a shebang line just in case it's a potential shell script
+
+class RDoc::Parser
+
+  @parsers = []
+
+  class << self
+    attr_reader :parsers
+  end
+
+  ##
+  # Alias an extension to another extension. After this call, files ending
+  # "new_ext" will be parsed using the same parser as "old_ext"
+
+  def self.alias_extension(old_ext, new_ext)
+    old_ext = old_ext.sub(/^\.(.*)/, '\1')
+    new_ext = new_ext.sub(/^\.(.*)/, '\1')
+
+    parser = can_parse "xxx.#{old_ext}"
+    return false unless parser
+
+    RDoc::Parser.parsers.unshift [/\.#{new_ext}$/, parser]
+
+    true
+  end
+
+  ##
+  # Shamelessly stolen from the ptools gem (since RDoc cannot depend on
+  # the gem).
+
+  def self.binary?(file)
+=begin
+    # XXX: this currently doesn't work in MacRuby
+    s = (File.read(file, File.stat(file).blksize, 0, :mode => "rb") || "").split(//)
+
+    if s.size > 0 then
+      ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30
+    else
+      false
+    end
+=end
+    false
+  end
+  private_class_method :binary?
+
+  ##
+  # Return a parser that can handle a particular extension
+
+  def self.can_parse(file_name)
+    parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name }.last
+
+    #
+    # The default parser should *NOT* parse binary files.
+    #
+    if parser == RDoc::Parser::Simple then
+      if binary? file_name then
+        return nil
+      end
+    end
+
+    return parser
+  end
+
+  ##
+  # Find the correct parser for a particular file name. Return a SimpleParser
+  # for ones that we don't know
+
+  def self.for(top_level, file_name, body, options, stats)
+    # If no extension, look for shebang
+    if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)} then
+      shebang = $1
+      case shebang
+      when %r{env\s+ruby}, %r{/ruby}
+        file_name = "dummy.rb"
+      end
+    end
+
+    parser = can_parse file_name
+
+    #
+    # This method must return a parser.
+    #
+    if !parser then
+      parser = RDoc::Parser::Simple
+    end
+
+    parser.new top_level, file_name, body, options, stats
+  end
+
+  ##
+  # Record which file types this parser can understand.
+
+  def self.parse_files_matching(regexp)
+    RDoc::Parser.parsers.unshift [regexp, self]
+  end
+
+  def initialize(top_level, file_name, content, options, stats)
+    @top_level = top_level
+    @file_name = file_name
+    @content = content
+    @options = options
+    @stats = stats
+  end
+
+end
+
+require 'rdoc/parser/simple'
+

Modified: MacRuby/branches/experimental/lib/rdoc/rdoc.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/rdoc.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/rdoc.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,10 +1,14 @@
 require 'rdoc'
 
-require 'rdoc/parsers/parse_rb.rb'
-require 'rdoc/parsers/parse_c.rb'
-require 'rdoc/parsers/parse_f95.rb'
-require 'rdoc/parsers/parse_simple.rb'
+require 'rdoc/parser'
 
+# Simple must come first
+require 'rdoc/parser/simple'
+require 'rdoc/parser/ruby'
+require 'rdoc/parser/c'
+require 'rdoc/parser/f95'
+require 'rdoc/parser/perl'
+
 require 'rdoc/stats'
 require 'rdoc/options'
 
@@ -17,22 +21,25 @@
 module RDoc
 
   ##
-  # Encapsulate the production of rdoc documentation. Basically
-  # you can use this as you would invoke rdoc from the command
-  # line:
+  # Encapsulate the production of rdoc documentation. Basically you can use
+  # this as you would invoke rdoc from the command line:
   #
-  #    rdoc = RDoc::RDoc.new
-  #    rdoc.document(args)
+  #   rdoc = RDoc::RDoc.new
+  #   rdoc.document(args)
   #
-  # where _args_ is an array of strings, each corresponding to
-  # an argument you'd give rdoc on the command line. See rdoc/rdoc.rb
-  # for details.
+  # Where +args+ is an array of strings, each corresponding to an argument
+  # you'd give rdoc on the command line. See rdoc/rdoc.rb for details.
 
   class RDoc
 
     Generator = Struct.new(:file_name, :class_name, :key)
 
     ##
+    # Accessor for statistics.  Available after each call to parse_files
+
+    attr_reader :stats
+
+    ##
     # This is the list of output generator that we support
 
     GENERATORS = {}
@@ -54,7 +61,7 @@
     end
 
     def initialize
-      @stats = Stats.new
+      @stats = nil
     end
 
     ##
@@ -134,7 +141,7 @@
     # subdirectories.
     #
     # The effect of this is that if you want a file with a non-standard
-    # extension parsed, you must name it explicity.
+    # extension parsed, you must name it explicitly.
 
     def normalized_file_list(options, relative_files, force_doc = false,
                              exclude_pattern = nil)
@@ -146,7 +153,10 @@
         case type = stat.ftype
         when "file"
           next if @last_created and stat.mtime < @last_created
-          file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
+
+          if force_doc or ::RDoc::Parser.can_parse(rel_file_name) then
+            file_list << rel_file_name.sub(/^\.\//, '')
+          end
         when "directory"
           next if rel_file_name == "CVS" || rel_file_name == ".svn"
           dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
@@ -179,35 +189,40 @@
     # Parse each file on the command line, recursively entering directories.
 
     def parse_files(options)
+      @stats = Stats.new options.verbosity
+
       files = options.files
       files = ["."] if files.empty?
 
-      file_list = normalized_file_list(options, files, true)
+      file_list = normalized_file_list(options, files, true, options.exclude)
 
       return [] if file_list.empty?
 
       file_info = []
-      width = file_list.map { |name| name.length }.max + 1
 
-      file_list.each do |fn|
-        $stderr.printf("\n%*s: ", width, fn) unless options.quiet
+      file_list.each do |filename|
+        @stats.add_file filename
 
         content = if RUBY_VERSION >= '1.9' then
-                    File.open(fn, "r:ascii-8bit") { |f| f.read }
+                    File.open(filename, "r:ascii-8bit") { |f| f.read }
                   else
-                    File.read fn
+                    File.read filename
                   end
 
-        if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
-          if enc = Encoding.find($1)
-            content.force_encoding(enc)
+        if defined? Encoding then
+          if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
+            if enc = ::Encoding.find($1)
+              content.force_encoding(enc)
+            end
           end
         end
 
-        top_level = TopLevel.new(fn)
-        parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
+        top_level = ::RDoc::TopLevel.new filename
+
+        parser = ::RDoc::Parser.for top_level, filename, content, options,
+                                    @stats
+
         file_info << parser.scan
-        @stats.num_files += 1
       end
 
       file_info
@@ -241,17 +256,19 @@
 
       file_info = parse_files @options
 
+      @options.title = "RDoc Documentation"
+
       if file_info.empty?
         $stderr.puts "\nNo newer files." unless @options.quiet
       else
-        gen = @options.generator
+        @gen = @options.generator
 
-        $stderr.puts "\nGenerating #{gen.key.upcase}..." unless @options.quiet
+        $stderr.puts "\nGenerating #{@gen.key.upcase}..." unless @options.quiet
 
-        require gen.file_name
+        require @gen.file_name
 
-        gen_class = ::RDoc::Generator.const_get gen.class_name
-        gen = gen_class.for @options
+        gen_class = ::RDoc::Generator.const_get @gen.class_name
+        @gen = gen_class.for @options
 
         pwd = Dir.pwd
 
@@ -259,7 +276,7 @@
 
         begin
           Diagram.new(file_info, @options).draw if @options.diagram
-          gen.generate(file_info)
+          @gen.generate(file_info)
           update_output_dir(".", start_time)
         ensure
           Dir.chdir(pwd)
@@ -272,6 +289,5 @@
       end
     end
   end
-
 end
 

Modified: MacRuby/branches/experimental/lib/rdoc/ri/cache.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/cache.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/cache.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -14,7 +14,7 @@
     @inferior_classes = []
   end
 
-  # We found this class in more tha one place, so add
+  # We found this class in more than one place, so add
   # in the name from there.
   def add_path(path)
     @path_names << path
@@ -37,10 +37,10 @@
       if name =~ /^(.*?)-(c|i).yaml$/
         external_name = $1
         is_class_method = $2 == "c"
-        internal_name = RiWriter.external_to_internal(external_name)
+        internal_name = RDoc::RI::Writer.external_to_internal(external_name)
         list = is_class_method ? @class_methods : @instance_methods
         path = File.join(dir, name)
-        list << MethodEntry.new(path, internal_name, is_class_method, self)
+        list << RDoc::RI::MethodEntry.new(path, internal_name, is_class_method, self)
       else
         full_name = File.join(dir, name)
         if File.directory?(full_name)
@@ -48,7 +48,7 @@
           if inf_class
             inf_class.add_path(full_name)
           else
-            inf_class = ClassEntry.new(full_name, name, self)
+            inf_class = RDoc::RI::ClassEntry.new(full_name, name, self)
             @inferior_classes << inf_class
           end
           inf_class.load_from(full_name)
@@ -168,7 +168,7 @@
 end
 
 ##
-# We represent everything know about all 'ri' files accessible to this program
+# We represent everything known about all 'ri' files accessible to this program
 
 class RDoc::RI::Cache
 
@@ -185,4 +185,3 @@
   end
 
 end
-

Modified: MacRuby/branches/experimental/lib/rdoc/ri/descriptions.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/descriptions.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/descriptions.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,11 +2,10 @@
 require 'rdoc/markup/fragments'
 require 'rdoc/ri'
 
-#--
+##
 # Descriptions are created by RDoc (in ri_generator) and written out in
 # serialized form into the documentation tree. ri then reads these to generate
 # the documentation
-#++
 
 class RDoc::RI::NamedThing
   attr_reader :name
@@ -78,12 +77,14 @@
 class RDoc::RI::ModuleDescription < RDoc::RI::Description
 
   attr_accessor :class_methods
+  attr_accessor :class_method_extensions
   attr_accessor :instance_methods
+  attr_accessor :instance_method_extensions
   attr_accessor :attributes
   attr_accessor :constants
   attr_accessor :includes
 
-  # merge in another class desscription into this one
+  # merge in another class description into this one
   def merge_in(old)
     merge(@class_methods, old.class_methods)
     merge(@instance_methods, old.instance_methods)
@@ -94,8 +95,12 @@
       @comment = old.comment
     else
       unless old.comment.nil? or old.comment.empty? then
-        @comment << RDoc::Markup::Flow::RULE.new
-        @comment.concat old.comment
+        if @comment.nil? or @comment.empty? then
+          @comment = old.comment
+        else
+          @comment << RDoc::Markup::Flow::RULE.new
+          @comment.concat old.comment
+        end
       end
     end
   end
@@ -145,6 +150,7 @@
   attr_accessor :aliases
   attr_accessor :is_alias_for
   attr_accessor :params
+  attr_accessor :source_path
 
 end
 

Modified: MacRuby/branches/experimental/lib/rdoc/ri/display.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/display.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/display.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,5 +1,15 @@
 require 'rdoc/ri'
 
+# readline support might not be present, so be careful
+# when requiring it.
+begin
+  require('readline')
+  require('abbrev')
+  CAN_USE_READLINE = true # HACK use an RDoc namespace constant
+rescue LoadError
+  CAN_USE_READLINE = false
+end
+
 ##
 # This is a kind of 'flag' module. If you want to write your own 'ri' display
 # module (perhaps because you're writing an IDE), you write a class which
@@ -41,9 +51,9 @@
   # Display information about +klass+.  Fetches additional information from
   # +ri_reader+ as necessary.
 
-  def display_class_info(klass, ri_reader)
+  def display_class_info(klass)
     page do
-      superclass = klass.superclass_string
+      superclass = klass.superclass
 
       if superclass
         superclass = " < " + superclass
@@ -61,17 +71,11 @@
         @formatter.blankline
         @formatter.display_heading("Includes:", 2, "")
         incs = []
+
         klass.includes.each do |inc|
-          inc_desc = ri_reader.find_class_by_name(inc.name)
-          if inc_desc
-            str = inc.name + "("
-            str << inc_desc.instance_methods.map{|m| m.name}.join(", ")
-            str << ")"
-            incs << str
-          else
-            incs << inc.name
-          end
-      end
+          incs << inc.name
+        end
+
         @formatter.wrap(incs.sort.join(', '))
       end
 
@@ -82,42 +86,19 @@
         constants = klass.constants.sort_by { |constant| constant.name }
 
         constants.each do |constant|
+          @formatter.wrap "#{constant.name} = #{constant.value}"
           if constant.comment then
-            @formatter.wrap "#{constant.name}:"
-
             @formatter.indent do
               @formatter.display_flow constant.comment
             end
           else
-            @formatter.wrap constant.name
+            @formatter.break_to_newline
           end
         end
       end
 
-      class_data = [
-        :class_methods,
-        :class_method_extensions,
-        :instance_methods,
-        :instance_method_extensions,
-      ]
-
-      class_data.each do |data_type|
-        data = klass.send data_type
-
-        unless data.empty? then
-          @formatter.blankline
-
-          heading = data_type.to_s.split('_').join(' ').capitalize << ':'
-          @formatter.display_heading heading, 2, ''
-
-          data = data.map { |item| item.name }.sort.join ', '
-          @formatter.wrap data
-        end
-      end
-
       unless klass.attributes.empty? then
         @formatter.blankline
-
         @formatter.display_heading 'Attributes:', 2, ''
 
         attributes = klass.attributes.sort_by { |attribute| attribute.name }
@@ -130,13 +111,121 @@
             end
           else
             @formatter.wrap "#{attribute.name} (#{attribute.rw})"
+            @formatter.break_to_newline
           end
         end
       end
+
+      return display_class_method_list(klass)
     end
   end
+  
+  ##
+  # Given a Hash mapping a class' methods to method types (returned by
+  # display_class_method_list), this method allows the user to
+  # choose one of the methods.
+  
+  def get_class_method_choice(method_map)
+    if CAN_USE_READLINE
+      # prepare abbreviations for tab completion
+      abbreviations = method_map.keys.abbrev
+      Readline.completion_proc = proc do |string| 
+        abbreviations.values.uniq.grep(/^#{string}/)
+      end
+    end
+    
+    @formatter.raw_print_line "\nEnter the method name you want.\n"
+    @formatter.raw_print_line "Class methods can be preceeded by '::' and instance methods by '#'.\n"
 
+    if CAN_USE_READLINE
+      @formatter.raw_print_line "You can use tab to autocomplete.\n"
+      @formatter.raw_print_line "Enter a blank line to exit.\n"
+      
+      choice_string = Readline.readline(">> ").strip
+    else
+      @formatter.raw_print_line "Enter a blank line to exit.\n"
+      @formatter.raw_print_line ">> "
+      choice_string = $stdin.gets.strip
+    end
+    
+    if choice_string == ''
+      return nil
+    else
+      class_or_instance = method_map[choice_string]
+
+      if class_or_instance
+        # If the user's choice is not preceeded by a '::' or a '#', figure
+        # out whether they want a class or an instance method and decorate
+        # the choice appropriately.
+        if(choice_string =~ /^[a-zA-Z]/)
+          if(class_or_instance == :class)
+            choice_string = "::#{choice_string}"
+          else
+            choice_string = "##{choice_string}"
+          end
+        end
+
+        return choice_string
+      else
+        @formatter.raw_print_line "No method matched '#{choice_string}'.\n"
+        return nil
+      end
+    end
+  end
+  
+
   ##
+  # Display methods on +klass+
+  # Returns a hash mapping method name to method contents (HACK?)
+
+  def display_class_method_list(klass)
+    method_map = {}
+
+    class_data = [
+                  :class_methods,
+                  :class_method_extensions,
+                  :instance_methods,
+                  :instance_method_extensions,
+                 ]
+    
+    class_data.each do |data_type|
+      data = klass.send data_type
+      
+      unless data.nil? or data.empty? then
+        @formatter.blankline
+        
+        heading = data_type.to_s.split('_').join(' ').capitalize << ':'
+        @formatter.display_heading heading, 2, ''
+        
+        method_names = []
+        data.each do |item|
+          method_names << item.name
+
+          if(data_type == :class_methods ||
+             data_type == :class_method_extensions) then
+            method_map["::#{item.name}"] = :class
+            method_map[item.name] = :class
+          else
+            #
+            # Since we iterate over instance methods after class methods,
+            # an instance method always will overwrite the unqualified
+            # class method entry for a class method of the same name.
+            #
+            method_map["##{item.name}"] = :instance
+            method_map[item.name] = :instance
+          end
+        end
+        method_names.sort!
+
+        @formatter.wrap method_names.join(', ')
+      end
+    end
+
+    method_map
+  end
+  private :display_class_method_list
+
+  ##
   # Display an Array of RDoc::Markup::Flow objects, +flow+.
 
   def display_flow(flow)
@@ -172,10 +261,42 @@
   def display_method_list(methods)
     page do
       @formatter.wrap "More than one method matched your request.  You can refine your search by asking for information on one of:"
+      @formatter.blankline
 
+      methods.each do |method|
+        @formatter.raw_print_line "#{method.full_name} [#{method.source_path}]\n"
+      end
+    end
+  end
+  
+  ##
+  # Display a list of +methods+ and allow the user to select one of them.
+
+  def display_method_list_choice(methods)
+    page do
+      @formatter.wrap "More than one method matched your request.  Please choose one of the possible matches."
       @formatter.blankline
 
-      @formatter.wrap methods.map { |m| m.full_name }.join(", ")
+      methods.each_with_index do |method, index|
+        @formatter.raw_print_line "%3d %s [%s]\n" % [index + 1, method.full_name, method.source_path]
+      end
+      
+      @formatter.raw_print_line ">> "
+      
+      choice = $stdin.gets.strip!
+
+      if(choice == '')
+        return
+      end
+
+      choice = choice.to_i
+
+      if ((choice == 0) || (choice > methods.size)) then
+        @formatter.raw_print_line "Invalid choice!\n"
+      else
+        method = methods[choice - 1] 
+        display_method_info(method)
+      end
     end
   end
 
@@ -198,10 +319,8 @@
       @formatter.break_to_newline
     end
 
-    if method.source_path then
-      @formatter.blankline
-      @formatter.wrap("Extension from #{method.source_path}")
-    end
+    @formatter.blankline
+    @formatter.wrap("From #{method.source_path}")
   end
 
   ##
@@ -271,4 +390,3 @@
   end
 
 end
-

Modified: MacRuby/branches/experimental/lib/rdoc/ri/driver.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/driver.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/driver.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -11,25 +11,97 @@
 
 class RDoc::RI::Driver
 
-  def self.process_args(argv)
+  #
+  # This class offers both Hash and OpenStruct functionality.
+  # We convert from the Core Hash to this before calling any of
+  # the display methods, in order to give the display methods
+  # a cleaner API for accessing the data.
+  #
+  class OpenStructHash < Hash
+    #
+    # This method converts from a Hash to an OpenStructHash.
+    #
+    def self.convert(object)
+      case object
+      when Hash then
+        new_hash = new # Convert Hash -> OpenStructHash
+
+        object.each do |key, value|
+          new_hash[key] = convert(value)
+        end
+
+        new_hash
+      when Array then
+        object.map do |element|
+          convert(element)
+        end
+      else
+        object
+      end
+    end
+
+    def merge_enums(other)
+      other.each do |k, v|
+        if self[k] then
+          case v
+          when Array then
+            # HACK dunno
+            if String === self[k] and self[k].empty? then
+              self[k] = v
+            else
+              self[k] += v
+            end
+          when Hash then
+            self[k].update v
+          else
+            # do nothing
+          end
+        else
+          self[k] = v
+        end
+      end
+    end
+
+    def method_missing method, *args
+      self[method.to_s]
+    end
+  end
+
+  class Error < RDoc::RI::Error; end
+
+  class NotFoundError < Error
+    def message
+      "Nothing known about #{super}"
+    end
+  end
+
+  attr_accessor :homepath # :nodoc:
+
+  def self.default_options
     options = {}
     options[:use_stdout] = !$stdout.tty?
     options[:width] = 72
     options[:formatter] = RDoc::RI::Formatter.for 'plain'
-    options[:list_classes] = false
-    options[:list_names] = false
+    options[:interactive] = false
+    options[:use_cache] = true
 
-    # By default all paths are used.  If any of these are true, only those
-    # directories are used.
-    use_system = false
-    use_site = false
-    use_home = false
-    use_gems = false
-    doc_dirs = []
+    # By default all standard paths are used.
+    options[:use_system] = true
+    options[:use_site] = true
+    options[:use_home] = true
+    options[:use_gems] = true
+    options[:extra_doc_dirs] = []
 
+    return options
+  end
+
+  def self.process_args(argv)
+    options = default_options
+
     opts = OptionParser.new do |opt|
       opt.program_name = File.basename $0
       opt.version = RDoc::VERSION
+      opt.release = nil
       opt.summary_indent = ' ' * 4
 
       directories = [
@@ -84,88 +156,116 @@
       opt.separator "Options:"
       opt.separator nil
 
-      opt.on("--classes", "-c",
-             "Display the names of classes and modules we",
-             "know about.") do |value|
-        options[:list_classes] = value
+      opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
+             RDoc::RI::Formatter::FORMATTERS.keys,
+             "Format to use when displaying output:",
+             "   #{RDoc::RI::Formatter.list}",
+             "Use 'bs' (backspace) with most pager",
+             "programs. To use ANSI, either disable the",
+             "pager or tell the pager to allow control",
+             "characters.") do |value|
+        options[:formatter] = RDoc::RI::Formatter.for value
       end
 
       opt.separator nil
 
       opt.on("--doc-dir=DIRNAME", "-d", Array,
-             "List of directories to search for",
-             "documentation. If not specified, we search",
-             "the standard rdoc/ri directories. May be",
-             "repeated.") do |value|
+             "List of directories from which to source",
+             "documentation in addition to the standard",
+             "directories.  May be repeated.") do |value|
         value.each do |dir|
           unless File.directory? dir then
             raise OptionParser::InvalidArgument, "#{dir} is not a directory"
           end
+
+          options[:extra_doc_dirs] << File.expand_path(dir)
         end
+      end
 
-        doc_dirs.concat value
+      opt.separator nil
+
+      opt.on("--[no-]use-cache",
+             "Whether or not to use ri's cache.",
+             "True by default.") do |value|
+        options[:use_cache] = value
       end
 
       opt.separator nil
 
-      opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
-             RDoc::RI::Formatter::FORMATTERS.keys,
-             "Format to use when displaying output:",
-             "   #{RDoc::RI::Formatter.list}",
-             "Use 'bs' (backspace) with most pager",
-             "programs. To use ANSI, either disable the",
-             "pager or tell the pager to allow control",
-             "characters.") do |value|
-        options[:formatter] = RDoc::RI::Formatter.for value
+      opt.on("--no-standard-docs",
+             "Do not include documentation from",
+             "the Ruby standard library, site_lib,",
+             "installed gems, or ~/.rdoc.",
+             "Equivalent to specifying",
+             "the options --no-system, --no-site, --no-gems,",
+             "and --no-home") do
+        options[:use_system] = false
+        options[:use_site] = false
+        options[:use_gems] = false
+        options[:use_home] = false
       end
 
       opt.separator nil
 
-      unless RDoc::RI::Paths::GEMDIRS.empty? then
-        opt.on("--[no-]gems",
-               "Include documentation from RubyGems.") do |value|
-          use_gems = value
-        end
+      opt.on("--[no-]system",
+             "Include documentation from Ruby's standard",
+             "library.  Defaults to true.") do |value|
+        options[:use_system] = value
       end
 
       opt.separator nil
 
-      opt.on("--[no-]home",
-             "Include documentation stored in ~/.rdoc.") do |value|
-        use_home = value
+      opt.on("--[no-]site",
+             "Include documentation from libraries",
+             "installed in site_lib.",
+             "Defaults to true.") do |value|
+        options[:use_site] = value
       end
 
       opt.separator nil
 
-      opt.on("--[no-]list-names", "-l",
-             "List all the names known to RDoc, one per",
-             "line.") do |value|
-        options[:list_names] = value
+      opt.on("--[no-]gems",
+             "Include documentation from RubyGems.",
+             "Defaults to true.") do |value|
+        options[:use_gems] = value
       end
 
       opt.separator nil
 
-      opt.on("--no-pager", "-T",
-             "Send output directly to stdout.") do |value|
-        options[:use_stdout] = !value
+      opt.on("--[no-]home",
+             "Include documentation stored in ~/.rdoc.",
+             "Defaults to true.") do |value|
+        options[:use_home] = value
       end
 
       opt.separator nil
 
-      opt.on("--[no-]site",
-             "Include documentation from libraries",
-             "installed in site_lib.") do |value|
-        use_site = value
+      opt.on("--list-doc-dirs",
+             "List the directories from which ri will",
+             "source documentation on stdout and exit.") do
+        options[:list_doc_dirs] = true
       end
 
       opt.separator nil
 
-      opt.on("--[no-]system",
-             "Include documentation from Ruby's standard",
-             "library.") do |value|
-        use_system = value
+      opt.on("--no-pager", "-T",
+             "Send output directly to stdout,",
+             "rather than to a pager.") do
+        options[:use_stdout] = true
       end
 
+      opt.on("--interactive", "-i",
+             "This makes ri go into interactive mode.",
+             "When ri is in interactive mode it will",
+             "allow the user to disambiguate lists of",
+             "methods in case multiple methods match",
+             "against a method search string.  It also",
+             "will allow the user to enter in a method",
+             "name (with auto-completion, if readline",
+             "is supported) when viewing a class.") do
+        options[:interactive] = true
+      end
+
       opt.separator nil
 
       opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
@@ -180,10 +280,10 @@
 
     options[:names] = argv
 
-    options[:path] = RDoc::RI::Paths.path(use_system, use_site, use_home,
-                                          use_gems, *doc_dirs)
-    options[:raw_path] = RDoc::RI::Paths.raw_path(use_system, use_site,
-                                                  use_home, use_gems, *doc_dirs)
+    options[:formatter] ||= RDoc::RI::Formatter.for('plain')
+    options[:use_stdout] ||= !$stdout.tty?
+    options[:use_stdout] ||= options[:interactive]
+    options[:width] ||= 72
 
     options
 
@@ -200,22 +300,30 @@
     ri.run
   end
 
-  def initialize(options={})
-    options[:formatter] ||= RDoc::RI::Formatter.for('plain')
-    options[:use_stdout] ||= !$stdout.tty?
-    options[:width] ||= 72
+  def initialize(initial_options={})
+    options = self.class.default_options.update(initial_options)
+
     @names = options[:names]
+    @class_cache_name = 'classes'
 
-    @class_cache_name = 'classes'
-    @all_dirs = RDoc::RI::Paths.path(true, true, true, true)
+    @doc_dirs = RDoc::RI::Paths.path(options[:use_system],
+                                     options[:use_site],
+                                     options[:use_home],
+                                     options[:use_gems],
+                                     options[:extra_doc_dirs])
+
     @homepath = RDoc::RI::Paths.raw_path(false, false, true, false).first
     @homepath = @homepath.sub(/\.rdoc/, '.ri')
-    @sys_dirs = RDoc::RI::Paths.raw_path(true, false, false, false)
+    @sys_dir = RDoc::RI::Paths.raw_path(true, false, false, false).first
+    @list_doc_dirs = options[:list_doc_dirs]
 
     FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
+    @cache_doc_dirs_path = File.join cache_file_path, ".doc_dirs"
 
+    @use_cache = options[:use_cache]
     @class_cache = nil
 
+    @interactive = options[:interactive]
     @display = RDoc::RI::DefaultDisplay.new(options[:formatter],
                                             options[:width],
                                             options[:use_stdout])
@@ -224,29 +332,94 @@
   def class_cache
     return @class_cache if @class_cache
 
-    newest = map_dirs('created.rid', :all) do |f|
+    # Get the documentation directories used to make the cache in order to see
+    # whether the cache is valid for the current ri instantiation.
+    if(File.readable?(@cache_doc_dirs_path))
+      cache_doc_dirs = IO.read(@cache_doc_dirs_path).split("\n")
+    else
+      cache_doc_dirs = []
+    end
+
+    newest = map_dirs('created.rid') do |f|
       File.mtime f if test ?f, f
     end.max
 
+    # An up to date cache file must have been created more recently than
+    # the last modification of any of the documentation directories.  It also
+    # must have been created with the same documentation directories
+    # as those from which ri currently is sourcing documentation.
     up_to_date = (File.exist?(class_cache_file_path) and
-                  newest and newest < File.mtime(class_cache_file_path))
+                  newest and newest < File.mtime(class_cache_file_path) and
+                  (cache_doc_dirs == @doc_dirs))
 
-    @class_cache = if up_to_date then
-                     load_cache_for @class_cache_name
-                   else
-                     class_cache = {}
+    if up_to_date and @use_cache then
+      open class_cache_file_path, 'rb' do |fp|
+        begin
+          @class_cache = Marshal.load fp.read
+        rescue
+          #
+          # This shouldn't be necessary, since the up_to_date logic above
+          # should force the cache to be recreated when a new version of
+          # rdoc is installed.  This seems like a worthwhile enhancement
+          # to ri's robustness, however.
+          #
+          $stderr.puts "Error reading the class cache; recreating the class cache!"
+          @class_cache = create_class_cache
+        end
+      end
+    else
+      @class_cache = create_class_cache
+    end
 
-                     classes = map_dirs('**/cdesc*.yaml', :sys) { |f| Dir[f] }
-                     populate_class_cache class_cache, classes
+    @class_cache
+  end
 
-                     classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
-                     warn "Updating class cache with #{classes.size} classes..."
+  def create_class_cache
+    class_cache = OpenStructHash.new
 
-                     populate_class_cache class_cache, classes, true
-                     write_cache class_cache, class_cache_file_path
-                   end
+    if(@use_cache)
+      # Dump the documentation directories to a file in the cache, so that
+      # we only will use the cache for future instantiations with identical
+      # documentation directories.
+      File.open @cache_doc_dirs_path, "wb" do |fp|
+        fp << @doc_dirs.join("\n")
+      end
+    end
+
+    classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
+    warn "Updating class cache with #{classes.size} classes..."
+    populate_class_cache class_cache, classes
+
+    write_cache class_cache, class_cache_file_path
+
+    class_cache
   end
 
+  def populate_class_cache(class_cache, classes, extension = false)
+    classes.each do |cdesc|
+      desc = read_yaml cdesc
+      klassname = desc["full_name"]
+
+      unless class_cache.has_key? klassname then
+        desc["display_name"] = "Class"
+        desc["sources"] = [cdesc]
+        desc["instance_method_extensions"] = []
+        desc["class_method_extensions"] = []
+        class_cache[klassname] = desc
+      else
+        klass = class_cache[klassname]
+
+        if extension then
+          desc["instance_method_extensions"] = desc.delete "instance_methods"
+          desc["class_method_extensions"] = desc.delete "class_methods"
+        end
+
+        klass.merge_enums desc
+        klass["sources"] << cdesc
+      end
+    end
+  end
+
   def class_cache_file_path
     File.join cache_file_path, @class_cache_name
   end
@@ -261,133 +434,202 @@
 
   def display_class(name)
     klass = class_cache[name]
-    @display.display_class_info klass, class_cache
+    @display.display_class_info klass
   end
 
+  def display_method(method)
+    @display.display_method_info method
+  end
+
+  def get_info_for(arg)
+    @names = [arg]
+    run
+  end
+
   def load_cache_for(klassname)
     path = cache_file_for klassname
 
+    cache = nil
+
     if File.exist? path and
-       File.mtime(path) >= File.mtime(class_cache_file_path) then
-      File.open path, 'rb' do |fp|
-        Marshal.load fp.read
+       File.mtime(path) >= File.mtime(class_cache_file_path) and
+       @use_cache then
+      open path, 'rb' do |fp|
+        begin
+          cache = Marshal.load fp.read
+        rescue
+          #
+          # The cache somehow is bad.  Recreate the cache.
+          #
+          $stderr.puts "Error reading the cache for #{klassname}; recreating the cache!"
+          cache = create_cache_for klassname, path
+        end
       end
     else
-      class_cache = nil
+      cache = create_cache_for klassname, path
+    end
 
-      File.open class_cache_file_path, 'rb' do |fp|
-        class_cache = Marshal.load fp.read
-      end
+    cache
+  end
 
-      klass = class_cache[klassname]
-      return nil unless klass
+  def create_cache_for(klassname, path)
+    klass = class_cache[klassname]
+    return nil unless klass
 
-      method_files = klass["sources"]
-      cache = {}
+    method_files = klass["sources"]
+    cache = OpenStructHash.new
 
-      sys_dir = @sys_dirs.first
-      method_files.each do |f|
-        system_file = f.index(sys_dir) == 0
-        Dir[File.join(File.dirname(f), "*")].each do |yaml|
-          next unless yaml =~ /yaml$/
-          next if yaml =~ /cdesc-[^\/]+yaml$/
-          method = read_yaml yaml
-          name = method["full_name"]
-          ext_path = f
-          ext_path = "gem #{$1}" if f =~ %r%gems/[\d.]+/doc/([^/]+)%
-          method["source_path"] = ext_path unless system_file
-          cache[name] = method
+    method_files.each do |f|
+      system_file = f.index(@sys_dir) == 0
+      Dir[File.join(File.dirname(f), "*")].each do |yaml|
+        next unless yaml =~ /yaml$/
+        next if yaml =~ /cdesc-[^\/]+yaml$/
+
+        method = read_yaml yaml
+
+        if system_file then
+          method["source_path"] = "Ruby #{RDoc::RI::Paths::VERSION}"
+        else
+          if(f =~ %r%gems/[\d.]+/doc/([^/]+)%) then
+            ext_path = "gem #{$1}"
+          else
+            ext_path = f
+          end
+
+          method["source_path"] = ext_path
         end
+
+        name = method["full_name"]
+        cache[name] = method
       end
+    end
 
-      write_cache cache, path
+    write_cache cache, path
+  end
+
+  ##
+  # Finds the next ancestor of +orig_klass+ after +klass+.
+
+  def lookup_ancestor(klass, orig_klass)
+    # This is a bit hacky, but ri will go into an infinite
+    # loop otherwise, since Object has an Object ancestor
+    # for some reason.  Depending on the documentation state, I've seen
+    # Kernel as an ancestor of Object and not as an ancestor of Object.
+    if ((orig_klass == "Object") &&
+        ((klass == "Kernel") || (klass == "Object")))
+      return nil
     end
+
+    cache = class_cache[orig_klass]
+
+    return nil unless cache
+
+    ancestors = [orig_klass]
+    ancestors.push(*cache.includes.map { |inc| inc['name'] })
+    ancestors << cache.superclass
+    
+    ancestor_index = ancestors.index(klass)
+
+    if ancestor_index
+      ancestor = ancestors[ancestors.index(klass) + 1]
+      return ancestor if ancestor
+    end
+
+    lookup_ancestor klass, cache.superclass
   end
 
-  def map_dirs(file_name, system=false)
-    dirs = if system == :all then
-             @all_dirs
-           else
-             if system then
-               @sys_dirs
-             else
-               @all_dirs - @sys_dirs
-             end
-           end
+  ##
+  # Finds the method
 
-    dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
+  def lookup_method(name, klass)
+    cache = load_cache_for klass
+    return nil unless cache
+
+    method = cache[name.gsub('.', '#')]
+    method = cache[name.gsub('.', '::')] unless method
+    method
   end
 
-  def populate_class_cache(class_cache, classes, extension = false)
-    classes.each do |cdesc|
-      desc = read_yaml cdesc
-      klassname = desc["full_name"]
+  def map_dirs(file_name)
+    @doc_dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
+  end
 
-      unless class_cache.has_key? klassname then
-        desc["display_name"] = "Class"
-        desc["sources"] = [cdesc]
-        desc["instance_method_extensions"] = []
-        desc["class_method_extensions"] = []
-        class_cache[klassname] = desc
-      else
-        klass = class_cache[klassname]
+  ##
+  # Extract the class and method name parts from +name+ like Foo::Bar#baz
 
-        if extension then
-          desc["instance_method_extensions"] = desc.delete "instance_methods"
-          desc["class_method_extensions"] = desc.delete "class_methods"
-        end
+  def parse_name(name)
+    parts = name.split(/(::|\#|\.)/)
 
-        klass.merge_enums desc
-        klass["sources"] << cdesc
-      end
+    if parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
+      meth = parts.pop
+      parts.pop
     end
+
+    klass = parts.join
+
+    [klass, meth]
   end
 
   def read_yaml(path)
     data = File.read path
+
+    # Necessary to be backward-compatible with documentation generated
+    # by earliar RDoc versions.
     data = data.gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '')
     data = data.gsub(/ \!ruby\/(object|struct):SM::(\S+)/,
                      ' !ruby/\1:RDoc::Markup::\2')
-    YAML.load data
+    OpenStructHash.convert(YAML.load(data))
   end
 
-  def get_info_for(arg)
-    @names = [arg]
-    run
-  end
-
   def run
-    if @names.empty? then
+    if(@list_doc_dirs)
+      puts @doc_dirs.join("\n")
+    elsif @names.empty? then
       @display.list_known_classes class_cache.keys.sort
     else
       @names.each do |name|
-        case name
-        when /::|\#|\./ then
-          if class_cache.key? name then
-            display_class name
-          else
-            meth = nil
+        if class_cache.key? name then
+          method_map = display_class name
+          if(@interactive)
+            method_name = @display.get_class_method_choice(method_map)
 
-            parts = name.split(/::|\#|\./)
-            meth = parts.pop unless parts.last =~ /^[A-Z]/
-            klass = parts.join '::'
+            if(method_name != nil)
+              method = lookup_method "#{name}#{method_name}", name
+              display_method method
+            end
+          end
+        elsif name =~ /::|\#|\./ then
+          klass, = parse_name name
 
-            cache = load_cache_for klass
-            # HACK Does not support F.n
-            abort "Nothing known about #{name}" unless cache
-            method = cache[name.gsub(/\./, '#')]
-            abort "Nothing known about #{name}" unless method
-            @display.display_method_info method
+          orig_klass = klass
+          orig_name = name
+
+          loop do
+            method = lookup_method name, klass
+
+            break method if method
+
+            ancestor = lookup_ancestor klass, orig_klass
+
+            break unless ancestor
+
+            name = name.sub klass, ancestor
+            klass = ancestor
           end
+
+          raise NotFoundError, orig_name unless method
+
+          display_method method
         else
-          if class_cache.key? name then
-            display_class name
+          methods = select_methods(/#{name}/)
+
+          if methods.size == 0
+            raise NotFoundError, name
+          elsif methods.size == 1
+            display_method methods[0]
           else
-            methods = select_methods(/^#{name}/)
-            if methods.size == 0
-              abort "Nothing known about #{name}"
-            elsif methods.size == 1
-              @display.display_method_info methods.first
+            if(@interactive)
+              @display.display_method_list_choice methods
             else
               @display.display_method_list methods
             end
@@ -395,6 +637,8 @@
         end
       end
     end
+  rescue NotFoundError => e
+    abort e.message
   end
 
   def select_methods(pattern)
@@ -413,40 +657,13 @@
   end
 
   def write_cache(cache, path)
-    File.open path, "wb" do |cache_file|
-      Marshal.dump cache, cache_file
+    if(@use_cache)
+      File.open path, "wb" do |cache_file|
+        Marshal.dump cache, cache_file
+      end
     end
 
     cache
   end
 
 end
-
-class Hash # HACK don't add stuff to Hash.
-  def method_missing method, *args
-    self[method.to_s]
-  end
-
-  def merge_enums(other)
-    other.each do |k,v|
-      if self[k] then
-        case v
-        when Array then
-          # HACK dunno
-          if String === self[k] and self[k].empty? then
-            self[k] = v
-          else
-            self[k] += v
-          end
-        when Hash then
-          self[k].merge! v
-        else
-          # do nothing
-        end
-      else
-        self[k] = v
-      end
-    end
-  end
-end
-

Modified: MacRuby/branches/experimental/lib/rdoc/ri/formatter.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/formatter.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/formatter.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -93,7 +93,7 @@
   end
 
   def raw_print_line(txt)
-    @output.puts txt
+    @output.print txt
   end
 
   ##

Modified: MacRuby/branches/experimental/lib/rdoc/ri/paths.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/paths.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/paths.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -26,9 +26,9 @@
 
   DOC_DIR  = "doc/rdoc"
 
-  version = RbConfig::CONFIG['ruby_version']
+  VERSION = RbConfig::CONFIG['ruby_version']
 
-  base    = File.join(RbConfig::CONFIG['datadir'], "ri", version)
+  base    = File.join(RbConfig::CONFIG['datadir'], "ri", VERSION)
   SYSDIR  = File.join(base, "system")
   SITEDIR = File.join(base, "site")
   homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
@@ -39,12 +39,8 @@
     HOMEDIR = nil
   end
 
-  # This is the search path for 'ri'
-  PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)}
-
   begin
-    require 'rubygems' unless defined?(Gem) and defined?(Gem::Enable) and
-                              Gem::Enable
+    require 'rubygems'# unless defined?(Gem)
 
     # HACK dup'd from Gem.latest_partials and friends
     all_paths = []
@@ -67,7 +63,6 @@
     end
 
     GEMDIRS = ri_paths.map { |k,v| v.last }.sort
-    GEMDIRS.each { |dir| PATH << dir }
   rescue LoadError
     GEMDIRS = []
   end
@@ -85,9 +80,6 @@
   # found.
 
   def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
-    return PATH unless use_system or use_site or use_home or use_gems or
-                       not extra_dirs.empty?
-
     path = []
     path << extra_dirs unless extra_dirs.empty?
     path << SYSDIR if use_system
@@ -97,6 +89,4 @@
 
     return path.flatten.compact
   end
-
 end
-

Modified: MacRuby/branches/experimental/lib/rdoc/ri/reader.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/reader.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/reader.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -45,7 +45,7 @@
 
   def get_method(method_entry)
     path = method_entry.path_name
-    File.open(path) { |f| RI::Description.deserialize(f) }
+    File.open(path) { |f| RDoc::RI::Description.deserialize(f) }
   end
 
   ##
@@ -54,8 +54,8 @@
   def get_class(class_entry)
     result = nil
     for path in class_entry.path_names
-      path = RiWriter.class_desc_path(path, class_entry)
-      desc = File.open(path) {|f| RI::Description.deserialize(f) }
+      path = RDoc::RI::Writer.class_desc_path(path, class_entry)
+      desc = File.open(path) {|f| RDoc::RI::Description.deserialize(f) }
       if result
         result.merge_in(desc)
       else

Modified: MacRuby/branches/experimental/lib/rdoc/ri/util.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri/util.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri/util.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,5 @@
 require 'rdoc/ri'
 
-class RDoc::RI::Error < RuntimeError; end
-
 ##
 # Break argument into its constituent class or module names, an
 # optional method type, and a method name

Modified: MacRuby/branches/experimental/lib/rdoc/ri.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/ri.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/ri.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,4 +1,8 @@
 require 'rdoc'
 
-module RDoc::RI; end
+module RDoc::RI
 
+  class Error < RDoc::Error; end
+
+end
+

Modified: MacRuby/branches/experimental/lib/rdoc/stats.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc/stats.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc/stats.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -5,21 +5,111 @@
 
 class RDoc::Stats
 
-  attr_accessor :num_files, :num_classes, :num_modules, :num_methods
+  attr_reader :num_classes
+  attr_reader :num_files
+  attr_reader :num_methods
+  attr_reader :num_modules
 
-  def initialize
-    @num_files = @num_classes = @num_modules = @num_methods = 0
+  def initialize(verbosity = 1)
+    @num_classes = 0
+    @num_files   = 0
+    @num_methods = 0
+    @num_modules = 0
+
     @start = Time.now
+
+    @display = case verbosity
+               when 0 then Quiet.new
+               when 1 then Normal.new
+               else        Verbose.new
+               end
   end
 
+  def add_alias(as)
+    @display.print_alias as
+    @num_methods += 1
+  end
+
+  def add_class(klass)
+    @display.print_class klass
+    @num_classes += 1
+  end
+
+  def add_file(file)
+    @display.print_file file
+    @num_files += 1
+  end
+
+  def add_method(method)
+    @display.print_method method
+    @num_methods += 1
+  end
+
+  def add_module(mod)
+    @display.print_module mod
+    @num_modules += 1
+  end
+
   def print
     puts "Files:   #@num_files"
     puts "Classes: #@num_classes"
     puts "Modules: #@num_modules"
     puts "Methods: #@num_methods"
-    puts "Elapsed: " + sprintf("%0.3fs", Time.now - @start)
+    puts "Elapsed: " + sprintf("%0.1fs", Time.now - @start)
   end
 
+  class Quiet
+    def print_alias(*) end
+    def print_class(*) end
+    def print_file(*) end
+    def print_method(*) end
+    def print_module(*) end
+  end
+
+  class Normal
+    def print_alias(as)
+      print 'a'
+    end
+
+    def print_class(klass)
+      print 'C'
+    end
+
+    def print_file(file)
+      print "\n#{file}: "
+    end
+
+    def print_method(method)
+      print 'm'
+    end
+
+    def print_module(mod)
+      print 'M'
+    end
+  end
+
+  class Verbose
+    def print_alias(as)
+      puts "\t\talias #{as.new_name} #{as.old_name}"
+    end
+
+    def print_class(klass)
+      puts "\tclass #{klass.full_name}"
+    end
+
+    def print_file(file)
+      puts file
+    end
+
+    def print_method(method)
+      puts "\t\t#{method.singleton ? '::' : '#'}#{method.name}"
+    end
+
+    def print_module(mod)
+      puts "\tmodule #{mod.full_name}"
+    end
+  end
+
 end
 
 

Modified: MacRuby/branches/experimental/lib/rdoc.rb
===================================================================
--- MacRuby/branches/experimental/lib/rdoc.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rdoc.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,87 +1,111 @@
 $DEBUG_RDOC = nil
 
 ##
-# = RDOC - Ruby Documentation System
-# 
+# = \RDoc - Ruby Documentation System
+#
 # This package contains RDoc and RDoc::Markup.  RDoc is an application that
-# produces documentation for one or more Ruby source files.  We work similarly
+# produces documentation for one or more Ruby source files.  It works similarly
 # to JavaDoc, parsing the source, and extracting the definition for classes,
-# modules, and methods (along with includes and requires).  We associate with
+# modules, and methods (along with includes and requires).  It associates with
 # these optional documentation contained in the immediately preceding comment
-# block, and then render the result using a pluggable output formatter.
+# block, and then renders the result using a pluggable output formatter.
 # RDoc::Markup is a library that converts plain text into various output
 # formats.  The markup library is used to interpret the comment blocks that
 # RDoc uses to document methods, classes, and so on.
-# 
+#
 # == Roadmap
-# 
+#
 # * If you want to use RDoc to create documentation for your Ruby source files,
 #   read on.
-# * If you want to include extensions written in C, see RDoc::C_Parser
-# * For information on the various markups available in comment blocks, see
-#   RDoc::Markup.
-# * If you want to drive RDoc programatically, see RDoc::RDoc.
+# * If you want to include extensions written in C, see RDoc::Parser::C
+# * If you want to drive RDoc programmatically, see RDoc::RDoc.
 # * If you want to use the library to format text blocks into HTML, have a look
 #   at RDoc::Markup.
 # * If you want to try writing your own HTML output template, see
 #   RDoc::Generator::HTML
-# 
+#
 # == Summary
-# 
-# Once installed, you can create documentation using the 'rdoc' command
-# (the command is 'rdoc.bat' under Windows)
-# 
+#
+# Once installed, you can create documentation using the +rdoc+ command
+#
 #   % rdoc [options] [names...]
-# 
-# Type "rdoc --help" for an up-to-date option summary.
-# 
+#
+# For an up-to-date option summary, type
+#   % rdoc --help
+#
 # A typical use might be to generate documentation for a package of Ruby
-# source (such as rdoc itself). 
-# 
+# source (such as RDoc itself).
+#
 #   % rdoc
-# 
+#
 # This command generates documentation for all the Ruby and C source
 # files in and below the current directory.  These will be stored in a
-# documentation tree starting in the subdirectory 'doc'.
-# 
+# documentation tree starting in the subdirectory +doc+.
+#
 # You can make this slightly more useful for your readers by having the
 # index page contain the documentation for the primary file.  In our
 # case, we could type
-# 
+#
 #   % rdoc --main rdoc.rb
-# 
+#
 # You'll find information on the various formatting tricks you can use
 # in comment blocks in the documentation this generates.
-# 
+#
 # RDoc uses file extensions to determine how to process each file.  File names
-# ending +.rb+ and <tt>.rbw</tt> are assumed to be Ruby source.  Files
+# ending +.rb+ and +.rbw+ are assumed to be Ruby source.  Files
 # ending +.c+ are parsed as C files.  All other files are assumed to
 # contain just Markup-style markup (with or without leading '#' comment
 # markers).  If directory names are passed to RDoc, they are scanned
 # recursively for C and Ruby source files only.
+#
+# == \Options
+# rdoc can be passed a variety of command-line options.  In addition,
+# options can be specified via the +RDOCOPT+ environment variable, which
+# functions similarly to the +RUBYOPT+ environment variable.
+#
+#   % export RDOCOPT="-S"
+#
+# will make rdoc default to inline method source code.  Command-line options
+# always will override those in +RDOCOPT+.
+#
+# Run
 # 
-# = Markup
-# 
-# For information on how to make lists, hyperlinks, etc. with RDoc, see
-# RDoc::Markup.
-# 
-# Comment blocks can be written fairly naturally, either using '#' on
+#   % rdoc --help
+#
+# for full details on rdoc's options.
+#
+# Here are some of the most commonly used options.
+# [-d, --diagram]
+#   Generate diagrams showing modules and
+#   classes. You need dot V1.8.6 or later to
+#   use the --diagram option correctly. Dot is
+#   available from http://graphviz.org
+#
+# [-S, --inline-source]
+#   Show method source code inline, rather than via a popup link.
+#
+# [-T, --template=NAME]
+#   Set the template used when generating output.
+#
+# == Documenting Source Code
+#
+# Comment blocks can be written fairly naturally, either using +#+ on
 # successive lines of the comment, or by including the comment in
-# an =begin/=end block.  If you use the latter form, the =begin line must be
+# a =begin/=end block.  If you use the latter form, the =begin line must be
 # flagged with an RDoc tag:
-# 
+#
 #   =begin rdoc
 #   Documentation to be processed by RDoc.
 #   
 #   ...
 #   =end
-# 
+#
 # RDoc stops processing comments if it finds a comment line containing
 # a <tt>--</tt>.  This can be used to separate external from internal
 # comments, or to stop a comment being associated with a method, class, or
 # module.  Commenting can be turned back on with a line that starts with a
 # <tt>++</tt>.
-# 
+#
 #   ##
 #   # Extract the age and calculate the date-of-birth.
 #   #--
@@ -92,47 +116,141 @@
 #   def get_dob(person)
 #     # ...
 #   end
-# 
-# Names of classes, source files, and any method names containing an
+#
+# Names of classes, files, and any method names containing an
 # underscore or preceded by a hash character are automatically hyperlinked
-# from comment text to their description. 
-# 
+# from comment text to their description.
+#
 # Method parameter lists are extracted and displayed with the method
 # description.  If a method calls +yield+, then the parameters passed to yield
 # will also be displayed:
-# 
+#
 #   def fred
 #     ...
 #     yield line, address
-# 
+#
 # This will get documented as:
-# 
+#
 #   fred() { |line, address| ... }
-# 
+#
 # You can override this using a comment containing ':yields: ...' immediately
 # after the method definition
-# 
+#
 #   def fred # :yields: index, position
 #     # ...
 #   
 #     yield line, address
-# 
+#
 # which will get documented as
-# 
+#
 #    fred() { |index, position| ... }
-# 
+#
 # +:yields:+ is an example of a documentation directive.  These appear
 # immediately after the start of the document element they are modifying.
-# 
+#
+# == \Markup
+#
+# * The markup engine looks for a document's natural left margin.  This is
+#   used as the initial margin for the document.
+#
+# * Consecutive lines starting at this margin are considered to be a
+#   paragraph.
+#
+# * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
+#   taken to be the start of a list.  The margin in increased to be the first
+#   non-space following the list start flag.  Subsequent lines should be
+#   indented to this new margin until the list ends.  For example:
+#
+#      * this is a list with three paragraphs in
+#        the first item.  This is the first paragraph.
+#
+#        And this is the second paragraph.
+#
+#        1. This is an indented, numbered list.
+#        2. This is the second item in that list
+#
+#        This is the third conventional paragraph in the
+#        first list item.
+#
+#      * This is the second item in the original list
+#
+# * You can also construct labeled lists, sometimes called description
+#   or definition lists.  Do this by putting the label in square brackets
+#   and indenting the list body:
+#
+#       [cat]  a small furry mammal
+#              that seems to sleep a lot
+#
+#       [ant]  a little insect that is known
+#              to enjoy picnics
+#
+#   A minor variation on labeled lists uses two colons to separate the
+#   label from the list body:
+#
+#       cat::  a small furry mammal
+#              that seems to sleep a lot
+#
+#       ant::  a little insect that is known
+#              to enjoy picnics
+#
+#   This latter style guarantees that the list bodies' left margins are
+#   aligned: think of them as a two column table.
+#
+# * Any line that starts to the right of the current margin is treated
+#   as verbatim text.  This is useful for code listings.  The example of a
+#   list above is also verbatim text.
+#
+# * A line starting with an equals sign (=) is treated as a
+#   heading.  Level one headings have one equals sign, level two headings
+#   have two,and so on.
+#
+# * A line starting with three or more hyphens (at the current indent)
+#   generates a horizontal rule.  The more hyphens, the thicker the rule
+#   (within reason, and if supported by the output device)
+#
+# * You can use markup within text (except verbatim) to change the
+#   appearance of parts of that text.  Out of the box, RDoc::Markup
+#   supports word-based and general markup.
+#
+#   Word-based markup uses flag characters around individual words:
+#
+#   [\*word*]  displays word in a *bold* font
+#   [\_word_]  displays word in an _emphasized_ font
+#   [\+word+]  displays word in a +code+ font
+#
+#   General markup affects text between a start delimiter and and end
+#   delimiter.  Not surprisingly, these delimiters look like HTML markup.
+#
+#   [\<b>text...</b>]    displays word in a *bold* font
+#   [\<em>text...</em>]  displays word in an _emphasized_ font
+#   [\\<i>text...</i>]    displays word in an <i>italicized</i> font
+#   [\<tt>text...</tt>]  displays word in a +code+ font
+#
+#   Unlike conventional Wiki markup, general markup can cross line
+#   boundaries.  You can turn off the interpretation of markup by
+#   preceding the first character with a backslash.  This only works for
+#   simple markup, not HTML-style markup.
+#
+# * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
+#   recognized.  An HTTP url that references an external image file is
+#   converted into an inline <IMG..>.  Hyperlinks starting 'link:' are
+#   assumed to refer to local files whose path is relative to the --op
+#   directory.
+#
+#   Hyperlinks can also be of the form <tt>label</tt>[url], in which
+#   case the label is used in the displayed text, and +url+ is
+#   used as the target.  If +label+ contains multiple words,
+#   put it in braces: <em>{multi word label}[</em>url<em>]</em>.
+#
 # == Directives
-# 
+#
 # [+:nodoc:+ / +:nodoc:+ all]
-#   Don't include this element in the documentation.  For classes
-#   and modules, the methods, aliases, constants, and attributes
-#   directly within the affected class or module will also be
-#   omitted.  By default, though, modules and classes within that
-#   class of module _will_ be documented.  This is turned off by
-#   adding the +all+ modifier.
+#   This directive prevents documentation for the element from
+#   being generated.  For classes and modules, the methods, aliases,
+#   constants, and attributes directly within the affected class or
+#   module also will be omitted.  By default, though, modules and
+#   classes within that class of module _will_ be documented.  This is
+#   turned off by adding the +all+ modifier.
 #   
 #     module MyModule # :nodoc:
 #       class Input
@@ -143,27 +261,27 @@
 #       class Output
 #       end
 #     end
-#   
-#   In the above code, only class +MyModule::Input+ will be documented.
-#   :nodoc: is global across all files the class or module appears in, so use
-#   :stopdoc:/:startdoc: to only omit documentation for a particular set of
-#   methods, etc.
-# 
+#
+#   In the above code, only class <tt>MyModule::Input</tt> will be documented.
+#   The +:nodoc:+ directive is global across all files for the class or module
+#   to which it applies, so use +:stopdoc:+/+:startdoc:+ to suppress
+#   documentation only for a particular set of methods, etc.
+#
 # [+:doc:+]
-#   Force a method or attribute to be documented even if it wouldn't otherwise
-#   be.  Useful if, for example, you want to include documentation of a
+#   Forces a method or attribute to be documented even if it wouldn't be
+#   otherwise.  Useful if, for example, you want to include documentation of a
 #   particular private method.
-# 
+#
 # [+:notnew:+]
 #   Only applicable to the +initialize+ instance method.  Normally RDoc
-#   assumes   that the documentation and parameters for #initialize are
-#   actually for the ::new method, and so fakes out a ::new for the class.
-#   The :notnew: modifier stops this.  Remember that #initialize is protected,
-#   so you won't see the documentation unless you use the -a command line
+#   assumes that the documentation and parameters for +initialize+ are
+#   actually for the +new+ method, and so fakes out a +new+ for the class.
+#   The +:notnew:+ modifier stops this.  Remember that +initialize+ is private,
+#   so you won't see the documentation unless you use the +-a+ command line
 #   option.
-# 
+#
 # Comment blocks can contain other directives:
-# 
+#
 # [<tt>:section: title</tt>]
 #   Starts a new section in the output.  The title following +:section:+ is
 #   used as the section heading, and the remainder of the comment containing
@@ -178,66 +296,66 @@
 #     # This is the section that I wrote.
 #     # See it glisten in the noon-day sun.
 #     # ----------------------------------------
-# 
+#
 # [+:call-seq:+]
 #   Lines up to the next blank line in the comment are treated as the method's
 #   calling sequence, overriding the default parsing of method parameters and
 #   yield arguments.
-# 
+#
 # [+:include:+ _filename_]
 #   \Include the contents of the named file at this point.  The file will be
 #   searched for in the directories listed by the +--include+ option, or in
 #   the current directory by default.  The contents of the file will be
-#   shifted to have the same indentation as the ':' at the start of the
-#   :include: directive.
-# 
+#   shifted to have the same indentation as the ':' at the start of
+#   the :include: directive.
+#
 # [+:title:+ _text_]
 #   Sets the title for the document.  Equivalent to the <tt>--title</tt>
 #   command line parameter.  (The command line parameter overrides any :title:
 #   directive in the source).
-# 
+#
 # [+:enddoc:+]
 #   Document nothing further at the current level.
-# 
+#
 # [+:main:+ _name_]
 #   Equivalent to the <tt>--main</tt> command line parameter.
-# 
+#
 # [+:stopdoc:+ / +:startdoc:+]
 #   Stop and start adding new documentation elements to the current container.
 #   For example, if a class has a number of constants that you don't want to
 #   document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
-#   last.  If you don't specifiy a +:startdoc:+ by the end of the container,
+#   last.  If you don't specify a +:startdoc:+ by the end of the container,
 #   disables documentation for the entire class or module.
-# 
-# = Other stuff
-# 
+#
+# == Other stuff
+#
 # RDoc is currently being maintained by Eric Hodel <drbrain at segment7.net>
 #
 # Dave Thomas <dave at pragmaticprogrammer.com> is the original author of RDoc.
-# 
+#
 # == Credits
-# 
+#
 # * The Ruby parser in rdoc/parse.rb is based heavily on the outstanding
 #   work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby
 #   parser for irb and the rtags package.
-# 
+#
 # * Code to diagram classes and modules was written by Sergey A Yanovitsky
 #   (Jah) of Enticla.
-# 
+#
 # * Charset patch from MoonWolf.
-# 
+#
 # * Rich Kilmer wrote the kilmer.rb output template.
-# 
+#
 # * Dan Brickley led the design of the RDF format.
-# 
+#
 # == License
-# 
+#
 # RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers.  It
 # is free software, and may be redistributed under the terms specified
 # in the README file of the Ruby distribution.
-# 
+#
 # == Warranty
-# 
+#
 # This software is provided "as is" and without any express or implied
 # warranties, including, without limitation, the implied warranties of
 # merchantibility and fitness for a particular purpose.
@@ -254,7 +372,7 @@
   ##
   # RDoc version you are using
 
-  VERSION = "2.0.0"
+  VERSION = "2.2.2"
 
   ##
   # Name of the dotfile that contains the description of files to be processed

Modified: MacRuby/branches/experimental/lib/resolv-replace.rb
===================================================================
--- MacRuby/branches/experimental/lib/resolv-replace.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/resolv-replace.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -23,7 +23,8 @@
 class UDPSocket
   alias original_resolv_bind bind
   def bind(host, port)
-    original_resolv_bind(IPSocket.getaddress(host), port)
+    host = IPSocket.getaddress(host) if host != ""
+    original_resolv_bind(host, port)
   end
 
   alias original_resolv_connect connect

Modified: MacRuby/branches/experimental/lib/resolv.rb
===================================================================
--- MacRuby/branches/experimental/lib/resolv.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/resolv.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,29 +3,34 @@
 require 'timeout'
 require 'thread'
 
+begin
+  require 'securerandom'
+rescue LoadError
+end
+
 # Resolv is a thread-aware DNS resolver library written in Ruby.  Resolv can
 # handle multiple DNS requests concurrently without blocking.  The ruby
 # interpreter.
 #
 # See also resolv-replace.rb to replace the libc resolver with # Resolv.
-# 
+#
 # Resolv can look up various DNS resources using the DNS module directly.
-# 
+#
 # Examples:
-# 
+#
 #   p Resolv.getaddress "www.ruby-lang.org"
 #   p Resolv.getname "210.251.121.214"
-# 
+#
 #   Resolv::DNS.open do |dns|
 #     ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A
 #     p ress.map { |r| r.address }
 #     ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX
 #     p ress.map { |r| [r.exchange.to_s, r.preference] }
 #   end
-# 
-# 
+#
+#
 # == Bugs
-# 
+#
 # * NIS is not supported.
 # * /etc/nsswitch.conf is not supported.
 
@@ -33,14 +38,14 @@
 
   ##
   # Looks up the first IP address for +name+.
-  
+
   def self.getaddress(name)
     DefaultResolver.getaddress(name)
   end
 
   ##
   # Looks up all IP address for +name+.
-  
+
   def self.getaddresses(name)
     DefaultResolver.getaddresses(name)
   end
@@ -82,7 +87,7 @@
 
   ##
   # Looks up the first IP address for +name+.
-  
+
   def getaddress(name)
     each_address(name) {|address| return address}
     raise ResolvError.new("no address for #{name}")
@@ -90,7 +95,7 @@
 
   ##
   # Looks up all IP address for +name+.
-  
+
   def getaddresses(name)
     ret = []
     each_address(name) {|address| ret << address}
@@ -252,7 +257,7 @@
     end
 
     ##
-    # Iterates over all hostnames for +address+ retrived from the hosts file.
+    # Iterates over all hostnames for +address+ retrieved from the hosts file.
 
     def each_name(address, &proc)
       lazy_initialize
@@ -285,11 +290,6 @@
     UDPSize = 512
 
     ##
-    # Group of DNS resolver threads
-
-    DNSThreadGroup = ThreadGroup.new
-
-    ##
     # Creates a new DNS resolver.  See Resolv::DNS.new for argument details.
     #
     # Yields the created DNS resolver to the block, if given, otherwise
@@ -309,7 +309,7 @@
     # Creates a new DNS resolver.
     #
     # +config_info+ can be:
-    # 
+    #
     # nil:: Uses /etc/resolv.conf.
     # String:: Path to a file using /etc/resolv.conf's format.
     # Hash:: Must contain :nameserver, :search and :ndots keys.
@@ -330,13 +330,6 @@
       @mutex.synchronize {
         unless @initialized
           @config.lazy_initialize
-
-          if nameserver = @config.single?
-            @requester = Requester::ConnectedUDP.new(nameserver)
-          else
-            @requester = Requester::UnconnectedUDP.new
-          end
-
           @initialized = true
         end
       }
@@ -349,8 +342,6 @@
     def close
       @mutex.synchronize {
         if @initialized
-          @requester.close if @requester
-          @requester = nil
           @initialized = false
         end
       }
@@ -466,7 +457,7 @@
     ##
     # Looks up all +typeclass+ DNS resources for +name+.  See #getresource for
     # argument details.
-  
+
     def getresources(name, typeclass)
       ret = []
       each_resource(name, typeclass) {|resource| ret << resource}
@@ -476,10 +467,10 @@
     ##
     # Iterates over all +typeclass+ DNS resources for +name+.  See
     # #getresource for argument details.
-  
+
     def each_resource(name, typeclass, &proc)
       lazy_initialize
-      q = Queue.new
+      requester = make_requester
       senders = {}
       begin
         @config.resolv(name) {|candidate, tout, nameserver|
@@ -488,11 +479,9 @@
           msg.add_question(candidate, typeclass)
           unless sender = senders[[candidate, nameserver]]
             sender = senders[[candidate, nameserver]] =
-              @requester.sender(msg, candidate, q, nameserver)
+              requester.sender(msg, candidate, nameserver)
           end
-          sender.send
-          reply = reply_name = nil
-          timeout(tout, ResolvTimeout) { reply, reply_name = q.pop }
+          reply, reply_name = requester.request(sender, tout)
           case reply.rcode
           when RCode::NoError
             extract_resources(reply, reply_name, typeclass, &proc)
@@ -504,10 +493,18 @@
           end
         }
       ensure
-        @requester.delete(q)
+        requester.close
       end
     end
 
+    def make_requester # :nodoc:
+      if nameserver = @config.single?
+        Requester::ConnectedUDP.new(nameserver)
+      else
+        Requester::UnconnectedUDP.new
+      end
+    end
+
     def extract_resources(msg, name, typeclass) # :nodoc:
       if typeclass < Resource::ANY
         n0 = Name.create(name)
@@ -539,91 +536,145 @@
       }
     end
 
+    if defined? SecureRandom
+      def self.random(arg) # :nodoc:
+        begin
+          SecureRandom.random_number(arg)
+        rescue NotImplementedError
+          rand(arg)
+        end
+      end
+    else
+      def self.random(arg) # :nodoc:
+        rand(arg)
+      end
+    end
+
+
+    def self.rangerand(range) # :nodoc:
+      base = range.begin
+      len = range.end - range.begin
+      if !range.exclude_end?
+        len += 1
+      end
+      base + random(len)
+    end
+
+    RequestID = {}
+    RequestIDMutex = Mutex.new
+
+    def self.allocate_request_id(host, port) # :nodoc:
+      id = nil
+      RequestIDMutex.synchronize {
+        h = (RequestID[[host, port]] ||= {})
+        begin
+          id = rangerand(0x0000..0xffff)
+        end while h[id]
+        h[id] = true
+      }
+      id
+    end
+
+    def self.free_request_id(host, port, id) # :nodoc:
+      RequestIDMutex.synchronize {
+        key = [host, port]
+        if h = RequestID[key]
+          h.delete id
+          if h.empty?
+            RequestID.delete key
+          end
+        end
+      }
+    end
+
+    def self.bind_random_port(udpsock) # :nodoc:
+      begin
+        port = rangerand(1024..65535)
+        udpsock.bind("", port)
+      rescue Errno::EADDRINUSE
+        retry
+      end
+    end
+
     class Requester # :nodoc:
       def initialize
         @senders = {}
+        @sock = nil
       end
 
-      def close
-        thread, sock, @thread, @sock = @thread, @sock
-        begin
-          if thread
-            thread.kill
-            thread.join
+      def request(sender, tout)
+        timelimit = Time.now + tout
+        sender.send
+        while (now = Time.now) < timelimit
+          timeout = timelimit - now
+          if !IO.select([@sock], nil, nil, timeout)
+            raise ResolvTimeout
           end
-        ensure
-          sock.close if sock
+          reply, from = recv_reply
+          begin
+            msg = Message.decode(reply)
+          rescue DecodeError
+            next # broken DNS message ignored
+          end
+          if s = @senders[[from,msg.id]]
+            break
+          else
+            # unexpected DNS message ignored
+          end
         end
+        return msg, s.data
       end
 
-      def delete(arg)
-        case arg
-        when Sender
-          @senders.delete_if {|k, s| s == arg }
-        when Queue
-          @senders.delete_if {|k, s| s.queue == arg }
-        else
-          raise ArgumentError.new("neither Sender or Queue: #{arg}")
-        end
+      def close
+        sock = @sock
+        @sock = nil
+        sock.close if sock
       end
 
       class Sender # :nodoc:
-        def initialize(msg, data, sock, queue)
+        def initialize(msg, data, sock)
           @msg = msg
           @data = data
           @sock = sock
-          @queue = queue
         end
-        attr_reader :queue
-
-        def recv(msg)
-          @queue.push([msg, @data])
-        end
       end
 
       class UnconnectedUDP < Requester # :nodoc:
         def initialize
           super()
           @sock = UDPSocket.new
-          @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
-          @id = {}
-          @id.default = -1
-          @thread = Thread.new {
-            DNSThreadGroup.add Thread.current
-            loop {
-              reply, from = @sock.recvfrom(UDPSize)
-              msg = begin
-                Message.decode(reply)
-              rescue DecodeError
-                STDERR.print("DNS message decoding error: #{reply.inspect}\n")
-                next
-              end
-              if s = @senders[[[from[3],from[1]],msg.id]]
-                s.recv msg
-              else
-                #STDERR.print("non-handled DNS message: #{msg.inspect} from #{from.inspect}\n")
-              end
-            }
-          }
+          @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
+          DNS.bind_random_port(@sock)
         end
 
-        def sender(msg, data, queue, host, port=Port)
+        def recv_reply
+          reply, from = @sock.recvfrom(UDPSize)
+          return reply, [from[3],from[1]]
+        end
+
+        def sender(msg, data, host, port=Port)
           service = [host, port]
-          id = Thread.exclusive {
-            @id[service] = (@id[service] + 1) & 0xffff
-          }
+          id = DNS.allocate_request_id(host, port)
           request = msg.encode
           request[0,2] = [id].pack('n')
           return @senders[[service, id]] =
-            Sender.new(request, data, @sock, host, port, queue)
+            Sender.new(request, data, @sock, host, port)
         end
 
+        def close
+          super
+          @senders.each_key {|service, id|
+            DNS.free_request_id(service[0], service[1], id)
+          }
+        end
+
         class Sender < Requester::Sender # :nodoc:
-          def initialize(msg, data, sock, host, port, queue)
-            super(msg, data, sock, queue)
+          def initialize(msg, data, sock, host, port)
+            super(msg, data, sock)
             @host = host
             @port = port
           end
+          attr_reader :data
 
           def send
             @sock.send(@msg, 0, @host, @port)
@@ -637,42 +688,38 @@
           @host = host
           @port = port
           @sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET)
+          DNS.bind_random_port(@sock)
           @sock.connect(host, port)
-          @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
-          @id = -1
-          @thread = Thread.new {
-            DNSThreadGroup.add Thread.current
-            loop {
-              reply = @sock.recv(UDPSize)
-              msg = begin
-                Message.decode(reply)
-              rescue DecodeError
-                STDERR.print("DNS message decoding error: #{reply.inspect}")
-                next
-              end
-              if s = @senders[msg.id]
-                s.recv msg
-              else
-                #STDERR.print("non-handled DNS message: #{msg.inspect}")
-              end
-            }
-          }
+          @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
         end
 
-        def sender(msg, data, queue, host=@host, port=@port)
+        def recv_reply
+          reply = @sock.recv(UDPSize)
+          return reply, nil
+        end
+
+        def sender(msg, data, host=@host, port=@port)
           unless host == @host && port == @port
             raise RequestError.new("host/port don't match: #{host}:#{port}")
           end
-          id = Thread.exclusive { @id = (@id + 1) & 0xffff }
+          id = DNS.allocate_request_id(@host, @port)
           request = msg.encode
           request[0,2] = [id].pack('n')
-          return @senders[id] = Sender.new(request, data, @sock, queue)
+          return @senders[[nil,id]] = Sender.new(request, data, @sock)
         end
 
+        def close
+          super
+          @senders.each_key {|from, id|
+            DNS.free_request_id(@host, @port, id)
+          }
+        end
+
         class Sender < Requester::Sender # :nodoc:
           def send
             @sock.send(@msg, 0)
           end
+          attr_reader :data
         end
       end
 
@@ -681,39 +728,25 @@
           super()
           @host = host
           @port = port
-          @sock = TCPSocket.new
-          @sock.connect(host, port)
-          @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
-          @id = -1
+          @sock = TCPSocket.new(@host, @port)
+          @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
           @senders = {}
-          @thread = Thread.new {
-            DNSThreadGroup.add Thread.current
-            loop {
-              len = @sock.read(2).unpack('n')
-              reply = @sock.read(len)
-              msg = begin
-                Message.decode(reply)
-              rescue DecodeError
-                STDERR.print("DNS message decoding error: #{reply.inspect}")
-                next
-              end
-              if s = @senders[msg.id]
-                s.push msg
-              else
-                #STDERR.print("non-handled DNS message: #{msg.inspect}")
-              end
-            }
-          }
         end
 
-        def sender(msg, data, queue, host=@host, port=@port)
+        def recv_reply
+          len = @sock.read(2).unpack('n')[0]
+          reply = @sock.read(len)
+          return reply, nil
+        end
+
+        def sender(msg, data, host=@host, port=@port)
           unless host == @host && port == @port
             raise RequestError.new("host/port don't match: #{host}:#{port}")
           end
-          id = Thread.exclusive { @id = (@id + 1) & 0xffff }
+          id = DNS.allocate_request_id(@host, @port)
           request = msg.encode
           request[0,2] = [request.length, id].pack('nn')
-          return @senders[id] = Sender.new(request, data, @sock, queue)
+          return @senders[[nil,id]] = Sender.new(request, data, @sock)
         end
 
         class Sender < Requester::Sender # :nodoc:
@@ -721,7 +754,15 @@
             @sock.print(@msg)
             @sock.flush
           end
+          attr_reader :data
         end
+
+        def close
+          super
+          @senders.each_key {|from,id|
+            DNS.free_request_id(@host, @port, id)
+          }
+        end
       end
 
       ##
@@ -996,7 +1037,7 @@
     # A representation of a DNS name.
 
     class Name
-      
+
       ##
       # Creates a new DNS name from +arg+.  +arg+ can be:
       #
@@ -1419,11 +1460,11 @@
 
     class Query
       def encode_rdata(msg) # :nodoc:
-        raise EncodeError.new("#{self.class} is query.") 
+        raise EncodeError.new("#{self.class} is query.")
       end
 
       def self.decode_rdata(msg) # :nodoc:
-        raise DecodeError.new("#{self.class} is query.") 
+        raise DecodeError.new("#{self.class} is query.")
       end
     end
 
@@ -1898,7 +1939,7 @@
           def initialize(address)
             @address = IPv6.create(address)
           end
-          
+
           ##
           # The Resolv::IPv6 address for this AAAA.
 
@@ -1915,7 +1956,7 @@
 
         ##
         # SRV resource record defined in RFC 2782
-        # 
+        #
         # These records identify the hostname and port that a service is
         # available at.
 
@@ -2026,7 +2067,7 @@
     end
 
     ##
-    # A String reperesentation of this IPv4 address.
+    # A String representation of this IPv4 address.
 
     ##
     # The raw IPv4 address as a String.

Modified: MacRuby/branches/experimental/lib/rexml/attlistdecl.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/attlistdecl.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/attlistdecl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,60 +3,60 @@
 require 'rexml/source'
 
 module REXML
-	# This class needs:
-	# * Documentation
-	# * Work!  Not all types of attlists are intelligently parsed, so we just
-	# spew back out what we get in.  This works, but it would be better if
-	# we formatted the output ourselves.
-	#
-	# AttlistDecls provide *just* enough support to allow namespace
-	# declarations.  If you need some sort of generalized support, or have an
-	# interesting idea about how to map the hideous, terrible design of DTD
-	# AttlistDecls onto an intuitive Ruby interface, let me know.  I'm desperate
-	# for anything to make DTDs more palateable.
-	class AttlistDecl < Child
-		include Enumerable
+  # This class needs:
+  # * Documentation
+  # * Work!  Not all types of attlists are intelligently parsed, so we just
+  # spew back out what we get in.  This works, but it would be better if
+  # we formatted the output ourselves.
+  #
+  # AttlistDecls provide *just* enough support to allow namespace
+  # declarations.  If you need some sort of generalized support, or have an
+  # interesting idea about how to map the hideous, terrible design of DTD
+  # AttlistDecls onto an intuitive Ruby interface, let me know.  I'm desperate
+  # for anything to make DTDs more palateable.
+  class AttlistDecl < Child
+    include Enumerable
 
-		# What is this?  Got me.
-		attr_reader :element_name
+    # What is this?  Got me.
+    attr_reader :element_name
 
-		# Create an AttlistDecl, pulling the information from a Source.  Notice
-		# that this isn't very convenient; to create an AttlistDecl, you basically
-		# have to format it yourself, and then have the initializer parse it.
-		# Sorry, but for the forseeable future, DTD support in REXML is pretty
-		# weak on convenience.  Have I mentioned how much I hate DTDs?
-		def initialize(source)
-			super()
-			if (source.kind_of? Array)
-				@element_name, @pairs, @contents = *source
-			end
-		end
-	
-		# Access the attlist attribute/value pairs.
-		#  value = attlist_decl[ attribute_name ]
-		def [](key)
-			@pairs[key]
-		end
+    # Create an AttlistDecl, pulling the information from a Source.  Notice
+    # that this isn't very convenient; to create an AttlistDecl, you basically
+    # have to format it yourself, and then have the initializer parse it.
+    # Sorry, but for the forseeable future, DTD support in REXML is pretty
+    # weak on convenience.  Have I mentioned how much I hate DTDs?
+    def initialize(source)
+      super()
+      if (source.kind_of? Array)
+        @element_name, @pairs, @contents = *source
+      end
+    end
+  
+    # Access the attlist attribute/value pairs.
+    #  value = attlist_decl[ attribute_name ]
+    def [](key)
+      @pairs[key]
+    end
 
-		# Whether an attlist declaration includes the given attribute definition
-		#  if attlist_decl.include? "xmlns:foobar"
-		def include?(key)
-			@pairs.keys.include? key
-		end
+    # Whether an attlist declaration includes the given attribute definition
+    #  if attlist_decl.include? "xmlns:foobar"
+    def include?(key)
+      @pairs.keys.include? key
+    end
 
-		# Itterate over the key/value pairs:
-		#  attlist_decl.each { |attribute_name, attribute_value| ... }
-		def each(&block)
-			@pairs.each(&block)
-		end
+    # Iterate over the key/value pairs:
+    #  attlist_decl.each { |attribute_name, attribute_value| ... }
+    def each(&block)
+      @pairs.each(&block)
+    end
 
-		# Write out exactly what we got in.
-		def write out, indent=-1
-			out << @contents
-		end
+    # Write out exactly what we got in.
+    def write out, indent=-1
+      out << @contents
+    end
 
-		def node_type
-			:attlistdecl
-		end
-	end
+    def node_type
+      :attlistdecl
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/attribute.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/attribute.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/attribute.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,24 +2,24 @@
 require 'rexml/text'
 
 module REXML
-	# Defines an Element Attribute; IE, a attribute=value pair, as in:
-	# <element attribute="value"/>.  Attributes can be in their own
-	# namespaces.  General users of REXML will not interact with the
-	# Attribute class much.
-	class Attribute
-		include Node
-		include Namespace
+  # Defines an Element Attribute; IE, a attribute=value pair, as in:
+  # <element attribute="value"/>.  Attributes can be in their own
+  # namespaces.  General users of REXML will not interact with the
+  # Attribute class much.
+  class Attribute
+    include Node
+    include Namespace
 
-		# The element to which this attribute belongs
-		attr_reader :element
-		# The normalized value of this attribute.  That is, the attribute with
-		# entities intact.
-		attr_writer :normalized	
-		PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
+    # The element to which this attribute belongs
+    attr_reader :element
+    # The normalized value of this attribute.  That is, the attribute with
+    # entities intact.
+    attr_writer :normalized	
+    PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
 
     NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
 
-		# Constructor.
+    # Constructor.
     # FIXME: The parser doesn't catch illegal characters in attributes
     #
     # first:: 
@@ -36,137 +36,137 @@
     #   Ignored unless +first+ is a String; otherwise, may be the Element 
     #   parent of this attribute, or nil.
     #
-		#
-		#  Attribute.new( attribute_to_clone )
-		#  Attribute.new( attribute_to_clone, parent_element )
-		#  Attribute.new( "attr", "attr_value" )
-		#  Attribute.new( "attr", "attr_value", parent_element )
-		def initialize( first, second=nil, parent=nil )
-			@normalized = @unnormalized = @element = nil
-			if first.kind_of? Attribute
-				self.name = first.expanded_name
-				@unnormalized = first.value
-				if second.kind_of? Element
-					@element = second
-				else
-					@element = first.element
-				end
-			elsif first.kind_of? String
-				@element = parent
-				self.name = first
-				@normalized = second.to_s
-			else
-				raise "illegal argument #{first.class.name} to Attribute constructor"
-			end
-		end
+    #
+    #  Attribute.new( attribute_to_clone )
+    #  Attribute.new( attribute_to_clone, parent_element )
+    #  Attribute.new( "attr", "attr_value" )
+    #  Attribute.new( "attr", "attr_value", parent_element )
+    def initialize( first, second=nil, parent=nil )
+      @normalized = @unnormalized = @element = nil
+      if first.kind_of? Attribute
+        self.name = first.expanded_name
+        @unnormalized = first.value
+        if second.kind_of? Element
+          @element = second
+        else
+          @element = first.element
+        end
+      elsif first.kind_of? String
+        @element = parent
+        self.name = first
+        @normalized = second.to_s
+      else
+        raise "illegal argument #{first.class.name} to Attribute constructor"
+      end
+    end
 
-		# Returns the namespace of the attribute.
-		# 
-		#  e = Element.new( "elns:myelement" )
-		#  e.add_attribute( "nsa:a", "aval" )
-		#  e.add_attribute( "b", "bval" )
-		#  e.attributes.get_attribute( "a" ).prefix   # -> "nsa"
-		#  e.attributes.get_attribute( "b" ).prefix   # -> "elns"
-		#  a = Attribute.new( "x", "y" )
-		#  a.prefix                                   # -> ""
-		def prefix
-			pf = super
-			if pf == ""
-				pf = @element.prefix if @element
-			end
-			pf
-		end
+    # Returns the namespace of the attribute.
+    # 
+    #  e = Element.new( "elns:myelement" )
+    #  e.add_attribute( "nsa:a", "aval" )
+    #  e.add_attribute( "b", "bval" )
+    #  e.attributes.get_attribute( "a" ).prefix   # -> "nsa"
+    #  e.attributes.get_attribute( "b" ).prefix   # -> "elns"
+    #  a = Attribute.new( "x", "y" )
+    #  a.prefix                                   # -> ""
+    def prefix
+      pf = super
+      if pf == ""
+        pf = @element.prefix if @element
+      end
+      pf
+    end
 
-		# Returns the namespace URL, if defined, or nil otherwise
-		# 
-		#  e = Element.new("el")
-		#  e.add_attributes({"xmlns:ns", "http://url"})
-		#  e.namespace( "ns" )              # -> "http://url"
-		def namespace arg=nil
-			arg = prefix if arg.nil?
-			@element.namespace arg
-		end
+    # Returns the namespace URL, if defined, or nil otherwise
+    # 
+    #  e = Element.new("el")
+    #  e.add_attributes({"xmlns:ns", "http://url"})
+    #  e.namespace( "ns" )              # -> "http://url"
+    def namespace arg=nil
+      arg = prefix if arg.nil?
+      @element.namespace arg
+    end
 
-		# Returns true if other is an Attribute and has the same name and value,
-		# false otherwise.
-		def ==( other )
-			other.kind_of?(Attribute) and other.name==name and other.value==value
-		end
+    # Returns true if other is an Attribute and has the same name and value,
+    # false otherwise.
+    def ==( other )
+      other.kind_of?(Attribute) and other.name==name and other.value==value
+    end
 
-		# Creates (and returns) a hash from both the name and value
-		def hash
-			name.hash + value.hash
-		end
+    # Creates (and returns) a hash from both the name and value
+    def hash
+      name.hash + value.hash
+    end
 
-		# Returns this attribute out as XML source, expanding the name
-		#
-		#  a = Attribute.new( "x", "y" )
-		#  a.to_string     # -> "x='y'"
-		#  b = Attribute.new( "ns:x", "y" )
-		#  b.to_string     # -> "ns:x='y'"
-		def to_string
-			if @element and @element.context and @element.context[:attribute_quote] == :quote
-				%Q^#@expanded_name="#{to_s().gsub(/"/, '&quote;')}"^
-			else
-				"#@expanded_name='#{to_s().gsub(/'/, '&apos;')}'"
-			end
-		end
+    # Returns this attribute out as XML source, expanding the name
+    #
+    #  a = Attribute.new( "x", "y" )
+    #  a.to_string     # -> "x='y'"
+    #  b = Attribute.new( "ns:x", "y" )
+    #  b.to_string     # -> "ns:x='y'"
+    def to_string
+      if @element and @element.context and @element.context[:attribute_quote] == :quote
+        %Q^#@expanded_name="#{to_s().gsub(/"/, '&quote;')}"^
+      else
+        "#@expanded_name='#{to_s().gsub(/'/, '&apos;')}'"
+      end
+    end
 
     def doctype
-			if @element
-				doc = @element.document
-				doctype = doc.doctype if doc
-			end
+      if @element
+        doc = @element.document
+        doctype = doc.doctype if doc
+      end
     end
 
-		# Returns the attribute value, with entities replaced
-		def to_s
-			return @normalized if @normalized
+    # Returns the attribute value, with entities replaced
+    def to_s
+      return @normalized if @normalized
 
-			@normalized = Text::normalize( @unnormalized, doctype )
-			@unnormalized = nil
+      @normalized = Text::normalize( @unnormalized, doctype )
+      @unnormalized = nil
       @normalized
-		end
+    end
 
-		# Returns the UNNORMALIZED value of this attribute.  That is, entities
-		# have been expanded to their values
-		def value
-			return @unnormalized if @unnormalized
-			@unnormalized = Text::unnormalize( @normalized, doctype )
-			@normalized = nil
+    # Returns the UNNORMALIZED value of this attribute.  That is, entities
+    # have been expanded to their values
+    def value
+      return @unnormalized if @unnormalized
+      @unnormalized = Text::unnormalize( @normalized, doctype )
+      @normalized = nil
       @unnormalized
-		end
+    end
 
-		# Returns a copy of this attribute
-		def clone
-			Attribute.new self
-		end
+    # Returns a copy of this attribute
+    def clone
+      Attribute.new self
+    end
 
-		# Sets the element of which this object is an attribute.  Normally, this
-		# is not directly called.
-		#
-		# Returns this attribute
-		def element=( element )
-			@element = element
+    # Sets the element of which this object is an attribute.  Normally, this
+    # is not directly called.
+    #
+    # Returns this attribute
+    def element=( element )
+      @element = element
 
       if @normalized
         Text.check( @normalized, NEEDS_A_SECOND_CHECK, doctype )
       end
 
-			self
-		end
+      self
+    end
 
-		# Removes this Attribute from the tree, and returns true if successfull
-		# 
-		# This method is usually not called directly.
-		def remove
-			@element.attributes.delete self.name unless @element.nil?
-		end
+    # Removes this Attribute from the tree, and returns true if successfull
+    # 
+    # This method is usually not called directly.
+    def remove
+      @element.attributes.delete self.name unless @element.nil?
+    end
 
-		# Writes this attribute (EG, puts 'key="value"' to the output)
-		def write( output, indent=-1 )
-			output << to_string
-		end
+    # Writes this attribute (EG, puts 'key="value"' to the output)
+    def write( output, indent=-1 )
+      output << to_string
+    end
 
     def node_type
       :attribute
@@ -183,6 +183,6 @@
       path += "/@#{self.expanded_name}"
       return path
     end
-	end
+  end
 end
 #vim:ts=2 sw=2 noexpandtab:

Modified: MacRuby/branches/experimental/lib/rexml/cdata.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/cdata.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/cdata.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,39 +1,39 @@
 require "rexml/text"
 
 module REXML
-	class CData < Text
-		START = '<![CDATA['
-		STOP = ']]>'
-		ILLEGAL = /(\]\]>)/
+  class CData < Text
+    START = '<![CDATA['
+    STOP = ']]>'
+    ILLEGAL = /(\]\]>)/
 
-		#	Constructor.  CData is data between <![CDATA[ ... ]]>
-		#
-		# _Examples_
-		#  CData.new( source )
-		#  CData.new( "Here is some CDATA" )
-		#  CData.new( "Some unprocessed data", respect_whitespace_TF, parent_element )
-		def initialize( first, whitespace=true, parent=nil )
-			super( first, whitespace, parent, false, true, ILLEGAL )
-		end
+    #	Constructor.  CData is data between <![CDATA[ ... ]]>
+    #
+    # _Examples_
+    #  CData.new( source )
+    #  CData.new( "Here is some CDATA" )
+    #  CData.new( "Some unprocessed data", respect_whitespace_TF, parent_element )
+    def initialize( first, whitespace=true, parent=nil )
+      super( first, whitespace, parent, false, true, ILLEGAL )
+    end
 
-		# Make a copy of this object
-		# 
-		# _Examples_
-		#  c = CData.new( "Some text" )
-		#  d = c.clone
-		#  d.to_s        # -> "Some text"
-		def clone
-			CData.new self
-		end
+    # Make a copy of this object
+    # 
+    # _Examples_
+    #  c = CData.new( "Some text" )
+    #  d = c.clone
+    #  d.to_s        # -> "Some text"
+    def clone
+      CData.new self
+    end
 
-		# Returns the content of this CData object
-		#
-		# _Examples_
-		#  c = CData.new( "Some text" )
-		#  c.to_s        # -> "Some text"
-		def to_s
-			@string
-		end
+    # Returns the content of this CData object
+    #
+    # _Examples_
+    #  c = CData.new( "Some text" )
+    #  c.to_s        # -> "Some text"
+    def to_s
+      @string
+    end
 
     def value
       @string
@@ -42,26 +42,26 @@
     # == DEPRECATED
     # See the rexml/formatters package
     #
-		# Generates XML output of this object
-		#
-		# output::
-		#   Where to write the string.  Defaults to $stdout
-		# indent::
+    # Generates XML output of this object
+    #
+    # output::
+    #   Where to write the string.  Defaults to $stdout
+    # indent::
     #   The amount to indent this node by
-		# transitive::
+    # transitive::
     #   Ignored
-		# ie_hack::
+    # ie_hack::
     #   Ignored
-		#
-		# _Examples_
-		#  c = CData.new( " Some text " )
-		#  c.write( $stdout )     #->  <![CDATA[ Some text ]]>
-		def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
+    #
+    # _Examples_
+    #  c = CData.new( " Some text " )
+    #  c.write( $stdout )     #->  <![CDATA[ Some text ]]>
+    def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
       Kernel.warn( "#{self.class.name}.write is deprecated" )
-			indent( output, indent )
-			output << START
-			output << @string
-			output << STOP
-		end
-	end
+      indent( output, indent )
+      output << START
+      output << @string
+      output << STOP
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/child.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/child.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/child.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,96 +1,96 @@
 require "rexml/node"
 
 module REXML
-	##
-	# A Child object is something contained by a parent, and this class
-	# contains methods to support that.  Most user code will not use this
-	# class directly.
-	class Child
-		include Node
-		attr_reader :parent		# The Parent of this object
+  ##
+  # A Child object is something contained by a parent, and this class
+  # contains methods to support that.  Most user code will not use this
+  # class directly.
+  class Child
+    include Node
+    attr_reader :parent		# The Parent of this object
 
-		# Constructor.  Any inheritors of this class should call super to make
-		# sure this method is called.
-		# parent::
-		#   if supplied, the parent of this child will be set to the
-		#   supplied value, and self will be added to the parent
-		def initialize( parent = nil )
-			@parent = nil  
-			# Declare @parent, but don't define it.  The next line sets the 
-			# parent.
-			parent.add( self ) if parent
-		end
+    # Constructor.  Any inheritors of this class should call super to make
+    # sure this method is called.
+    # parent::
+    #   if supplied, the parent of this child will be set to the
+    #   supplied value, and self will be added to the parent
+    def initialize( parent = nil )
+      @parent = nil  
+      # Declare @parent, but don't define it.  The next line sets the 
+      # parent.
+      parent.add( self ) if parent
+    end
 
-		# Replaces this object with another object.  Basically, calls
-		# Parent.replace_child
-		#
-		# Returns:: self
-		def replace_with( child )
-			@parent.replace_child( self, child )
-			self
-		end
+    # Replaces this object with another object.  Basically, calls
+    # Parent.replace_child
+    #
+    # Returns:: self
+    def replace_with( child )
+      @parent.replace_child( self, child )
+      self
+    end
 
-		# Removes this child from the parent.
-		#
-		# Returns:: self
-		def remove
-			unless @parent.nil?
-				@parent.delete self
-			end
-			self
-		end
+    # Removes this child from the parent.
+    #
+    # Returns:: self
+    def remove
+      unless @parent.nil?
+        @parent.delete self
+      end
+      self
+    end
 
-		# Sets the parent of this child to the supplied argument.
-		#
-		# other::
-		#   Must be a Parent object.  If this object is the same object as the
-		#   existing parent of this child, no action is taken. Otherwise, this
-		#   child is removed from the current parent (if one exists), and is added
-		#   to the new parent.
-		# Returns:: The parent added
-		def parent=( other )
-			return @parent if @parent == other
-			@parent.delete self if defined? @parent and @parent
-			@parent = other
-		end
+    # Sets the parent of this child to the supplied argument.
+    #
+    # other::
+    #   Must be a Parent object.  If this object is the same object as the
+    #   existing parent of this child, no action is taken. Otherwise, this
+    #   child is removed from the current parent (if one exists), and is added
+    #   to the new parent.
+    # Returns:: The parent added
+    def parent=( other )
+      return @parent if @parent == other
+      @parent.delete self if defined? @parent and @parent
+      @parent = other
+    end
 
-		alias :next_sibling :next_sibling_node
-		alias :previous_sibling :previous_sibling_node
+    alias :next_sibling :next_sibling_node
+    alias :previous_sibling :previous_sibling_node
 
-		# Sets the next sibling of this child.  This can be used to insert a child
-		# after some other child.
-		#  a = Element.new("a")
-		#  b = a.add_element("b")
-		#  c = Element.new("c")
-		#  b.next_sibling = c
-		#  # => <a><b/><c/></a>
-		def next_sibling=( other )
-		  parent.insert_after self, other
-		end
+    # Sets the next sibling of this child.  This can be used to insert a child
+    # after some other child.
+    #  a = Element.new("a")
+    #  b = a.add_element("b")
+    #  c = Element.new("c")
+    #  b.next_sibling = c
+    #  # => <a><b/><c/></a>
+    def next_sibling=( other )
+      parent.insert_after self, other
+    end
 
-		# Sets the previous sibling of this child.  This can be used to insert a 
-		# child before some other child.
-		#  a = Element.new("a")
-		#  b = a.add_element("b")
-		#  c = Element.new("c")
-		#  b.previous_sibling = c
-		#  # => <a><b/><c/></a>
-		def previous_sibling=(other)
-		  parent.insert_before self, other
-		end
+    # Sets the previous sibling of this child.  This can be used to insert a 
+    # child before some other child.
+    #  a = Element.new("a")
+    #  b = a.add_element("b")
+    #  c = Element.new("c")
+    #  b.previous_sibling = c
+    #  # => <a><b/><c/></a>
+    def previous_sibling=(other)
+      parent.insert_before self, other
+    end
 
-		# Returns:: the document this child belongs to, or nil if this child
-		# belongs to no document
-		def document
-			return parent.document unless parent.nil?
-			nil
-		end
+    # Returns:: the document this child belongs to, or nil if this child
+    # belongs to no document
+    def document
+      return parent.document unless parent.nil?
+      nil
+    end
 
-		# This doesn't yet handle encodings
-		def bytes
-			encoding = document.encoding
+    # This doesn't yet handle encodings
+    def bytes
+      encoding = document.encoding
 
-			to_s
-		end
-	end
+      to_s
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/comment.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/comment.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/comment.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,80 +1,80 @@
 require "rexml/child"
 
 module REXML
-	##
-	# Represents an XML comment; that is, text between \<!-- ... -->
-	class Comment < Child
-		include Comparable
-		START = "<!--"
-		STOP = "-->"
+  ##
+  # Represents an XML comment; that is, text between \<!-- ... -->
+  class Comment < Child
+    include Comparable
+    START = "<!--"
+    STOP = "-->"
 
-		# The content text
+    # The content text
 
-		attr_accessor :string
+    attr_accessor :string
 
-		##
-		# Constructor.  The first argument can be one of three types:
-		# @param first If String, the contents of this comment are set to the 
-		# argument.  If Comment, the argument is duplicated.  If
-		# Source, the argument is scanned for a comment.
-		# @param second If the first argument is a Source, this argument 
-		# should be nil, not supplied, or a Parent to be set as the parent 
-		# of this object
-		def initialize( first, second = nil )
-			#puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}"
-			super(second)
-			if first.kind_of? String
-				@string = first
-			elsif first.kind_of? Comment
-				@string = first.string
-			end
-		end
+    ##
+    # Constructor.  The first argument can be one of three types:
+    # @param first If String, the contents of this comment are set to the 
+    # argument.  If Comment, the argument is duplicated.  If
+    # Source, the argument is scanned for a comment.
+    # @param second If the first argument is a Source, this argument 
+    # should be nil, not supplied, or a Parent to be set as the parent 
+    # of this object
+    def initialize( first, second = nil )
+      #puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}"
+      super(second)
+      if first.kind_of? String
+        @string = first
+      elsif first.kind_of? Comment
+        @string = first.string
+      end
+    end
 
-		def clone
-			Comment.new self
-		end
+    def clone
+      Comment.new self
+    end
 
     # == DEPRECATED
     # See REXML::Formatters
     #
-		# output::
-		#	 Where to write the string
-		# indent::
-		#	 An integer.	If -1, no indenting will be used; otherwise, the
-		#	 indentation will be this number of spaces, and children will be
-		#	 indented an additional amount.
-		# transitive::
-		#	 Ignored by this class.	The contents of comments are never modified.
-		# ie_hack::
-		#	 Needed for conformity to the child API, but not used by this class.
-		def write( output, indent=-1, transitive=false, ie_hack=false )
+    # output::
+    #	 Where to write the string
+    # indent::
+    #	 An integer.	If -1, no indenting will be used; otherwise, the
+    #	 indentation will be this number of spaces, and children will be
+    #	 indented an additional amount.
+    # transitive::
+    #	 Ignored by this class.	The contents of comments are never modified.
+    # ie_hack::
+    #	 Needed for conformity to the child API, but not used by this class.
+    def write( output, indent=-1, transitive=false, ie_hack=false )
       Kernel.warn("Comment.write is deprecated.  See REXML::Formatters")
-			indent( output, indent )
-			output << START
-			output << @string
-			output << STOP
-		end
+      indent( output, indent )
+      output << START
+      output << @string
+      output << STOP
+    end
 
-		alias :to_s :string
+    alias :to_s :string
 
-		##
-		# Compares this Comment to another; the contents of the comment are used
-		# in the comparison.
-		def <=>(other)
-			other.to_s <=> @string
-		end
+    ##
+    # Compares this Comment to another; the contents of the comment are used
+    # in the comparison.
+    def <=>(other)
+      other.to_s <=> @string
+    end
 
-		##
-		# Compares this Comment to another; the contents of the comment are used
-		# in the comparison.
-		def ==( other )
-			other.kind_of? Comment and
-			(other <=> self) == 0
-		end
+    ##
+    # Compares this Comment to another; the contents of the comment are used
+    # in the comparison.
+    def ==( other )
+      other.kind_of? Comment and
+      (other <=> self) == 0
+    end
 
     def node_type
       :comment
     end
-	end
+  end
 end
 #vim:ts=2 sw=2 noexpandtab:

Modified: MacRuby/branches/experimental/lib/rexml/document.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/document.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/document.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -16,58 +16,59 @@
   # Document has a single child that can be accessed by root().
   # Note that if you want to have an XML declaration written for a document
   # you create, you must add one; REXML documents do not write a default
-	# declaration for you.  See |DECLARATION| and |write|.
-	class Document < Element
-		# A convenient default XML declaration.  If you want an XML declaration,
-		# the easiest way to add one is mydoc << Document::DECLARATION
+  # declaration for you.  See |DECLARATION| and |write|.
+  class Document < Element
+    # A convenient default XML declaration.  If you want an XML declaration,
+    # the easiest way to add one is mydoc << Document::DECLARATION
     # +DEPRECATED+
     # Use: mydoc << XMLDecl.default
-		DECLARATION = XMLDecl.default
+    DECLARATION = XMLDecl.default
 
-		# Constructor
-		# @param source if supplied, must be a Document, String, or IO. 
-		# Documents have their context and Element attributes cloned.
-	  # Strings are expected to be valid XML documents.  IOs are expected
-	  # to be sources of valid XML documents.
-	  # @param context if supplied, contains the context of the document;
-	  # this should be a Hash.
-		def initialize( source = nil, context = {} )
-			super()
-			@context = context
-			return if source.nil?
-			if source.kind_of? Document
-				@context = source.context
-				super source
-			else
-				build(  source )
-			end
-		end
+    # Constructor
+    # @param source if supplied, must be a Document, String, or IO. 
+    # Documents have their context and Element attributes cloned.
+    # Strings are expected to be valid XML documents.  IOs are expected
+    # to be sources of valid XML documents.
+    # @param context if supplied, contains the context of the document;
+    # this should be a Hash.
+    def initialize( source = nil, context = {} )
+      @entity_expansion_count = 0
+      super()
+      @context = context
+      return if source.nil?
+      if source.kind_of? Document
+        @context = source.context
+        super source
+      else
+        build(  source )
+      end
+    end
 
     def node_type
       :document
     end
 
-		# Should be obvious
-		def clone
-			Document.new self
-		end
+    # Should be obvious
+    def clone
+      Document.new self
+    end
 
-		# According to the XML spec, a root node has no expanded name
-		def expanded_name
-			''
-			#d = doc_type
-			#d ? d.name : "UNDEFINED"
-		end
+    # According to the XML spec, a root node has no expanded name
+    def expanded_name
+      ''
+      #d = doc_type
+      #d ? d.name : "UNDEFINED"
+    end
 
-		alias :name :expanded_name
+    alias :name :expanded_name
 
-		# We override this, because XMLDecls and DocTypes must go at the start
-		# of the document
-		def add( child )
-			if child.kind_of? XMLDecl
-				@children.unshift child
+    # We override this, because XMLDecls and DocTypes must go at the start
+    # of the document
+    def add( child )
+      if child.kind_of? XMLDecl
+        @children.unshift child
         child.parent = self
-			elsif child.kind_of? DocType
+      elsif child.kind_of? DocType
         # Find first Element or DocType node and insert the decl right 
         # before it.  If there is no such node, just insert the child at the
         # end.  If there is a child and it is an DocType, then replace it.
@@ -85,60 +86,60 @@
         else  # Insert at end of list
           @children[insert_before_index] = child
         end
-				child.parent = self
-			else
-				rv = super
-				raise "attempted adding second root element to document" if @elements.size > 1
-				rv
-			end
-		end
-		alias :<< :add
+        child.parent = self
+      else
+        rv = super
+        raise "attempted adding second root element to document" if @elements.size > 1
+        rv
+      end
+    end
+    alias :<< :add
 
-		def add_element(arg=nil, arg2=nil)
-			rv = super
-			raise "attempted adding second root element to document" if @elements.size > 1
-			rv
-		end
+    def add_element(arg=nil, arg2=nil)
+      rv = super
+      raise "attempted adding second root element to document" if @elements.size > 1
+      rv
+    end
 
-		# @return the root Element of the document, or nil if this document
-		# has no children.
-		def root
+    # @return the root Element of the document, or nil if this document
+    # has no children.
+    def root
       elements[1]
       #self
       #@children.find { |item| item.kind_of? Element }
-		end
+    end
 
-		# @return the DocType child of the document, if one exists,
-		# and nil otherwise.
-		def doctype
-			@children.find { |item| item.kind_of? DocType }
-		end
+    # @return the DocType child of the document, if one exists,
+    # and nil otherwise.
+    def doctype
+      @children.find { |item| item.kind_of? DocType }
+    end
 
-		# @return the XMLDecl of this document; if no XMLDecl has been
-		# set, the default declaration is returned.
-		def xml_decl
-			rv = @children[0]
+    # @return the XMLDecl of this document; if no XMLDecl has been
+    # set, the default declaration is returned.
+    def xml_decl
+      rv = @children[0]
       return rv if rv.kind_of? XMLDecl
       rv = @children.unshift(XMLDecl.default)[0]
-		end
+    end
 
-		# @return the XMLDecl version of this document as a String.
-		# If no XMLDecl has been set, returns the default version.
-		def version
-			xml_decl().version
-		end
+    # @return the XMLDecl version of this document as a String.
+    # If no XMLDecl has been set, returns the default version.
+    def version
+      xml_decl().version
+    end
 
-		# @return the XMLDecl encoding of this document as a String.
-		# If no XMLDecl has been set, returns the default encoding.
-		def encoding
-			xml_decl().encoding
-		end
+    # @return the XMLDecl encoding of this document as a String.
+    # If no XMLDecl has been set, returns the default encoding.
+    def encoding
+      xml_decl().encoding
+    end
 
-		# @return the XMLDecl standalone value of this document as a String.
-		# If no XMLDecl has been set, returns the default setting.
-		def stand_alone?
-			xml_decl().stand_alone?
-		end
+    # @return the XMLDecl standalone value of this document as a String.
+    # If no XMLDecl has been set, returns the default setting.
+    def stand_alone?
+      xml_decl().stand_alone?
+    end
 
     # Write the XML tree out, optionally with indent.  This writes out the
     # entire XML document, including XML declarations, doctype declarations,
@@ -147,7 +148,7 @@
     # A controversial point is whether Document should always write the XML
     # declaration (<?xml version='1.0'?>) whether or not one is given by the
     # user (or source document).  REXML does not write one if one was not
-    # specified, because it adds unneccessary bandwidth to applications such
+    # specified, because it adds unnecessary bandwidth to applications such
     # as XML-RPC.
     #
     # See also the classes in the rexml/formatters package for the proper way
@@ -168,7 +169,7 @@
     #   indentation will be twice this number of spaces, and children will be
     #   indented an additional amount.  For a value of 3, every item will be 
     #   indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1
-    # trans::
+    # transitive::
     #   If transitive is true and indent is >= 0, then the output will be
     #   pretty-printed in such a way that the added whitespace does not affect
     #   the absolute *value* of the document -- that is, it leaves the value
@@ -185,6 +186,7 @@
       end
       formatter = if indent > -1
           if transitive
+            require "rexml/formatters/transitive"
             REXML::Formatters::Transitive.new( indent, ie_hack )
           else
             REXML::Formatters::Pretty.new( indent, ie_hack )
@@ -193,16 +195,37 @@
           REXML::Formatters::Default.new( ie_hack )
         end
       formatter.write( self, output )
-		end
+    end
 
-		
-		def Document::parse_stream( source, listener )
-			Parsers::StreamParser.new( source, listener ).parse
-		end
+    
+    def Document::parse_stream( source, listener )
+      Parsers::StreamParser.new( source, listener ).parse
+    end
 
-		private
-		def build( source )
+    @@entity_expansion_limit = 10_000
+
+    # Set the entity expansion limit. By default the limit is set to 10000.
+    def Document::entity_expansion_limit=( val )
+      @@entity_expansion_limit = val
+    end
+
+    # Get the entity expansion limit. By default the limit is set to 10000.
+    def Document::entity_expansion_limit
+      return @@entity_expansion_limit
+    end
+
+    attr_reader :entity_expansion_count
+    
+    def record_entity_expansion
+      @entity_expansion_count += 1
+      if @entity_expansion_count > @@entity_expansion_limit
+        raise "number of entity expansions exceeded, processing aborted."
+      end
+    end
+
+    private
+    def build( source )
       Parsers::TreeParser.new( source, self ).parse
-		end
-	end
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/dtd/attlistdecl.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/dtd/attlistdecl.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/dtd/attlistdecl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,10 +1,10 @@
 require "rexml/child"
 module REXML
-	module DTD
-		class AttlistDecl < Child
-			START = "<!ATTLIST"
-			START_RE = /^\s*#{START}/um
-			PATTERN_RE = /\s*(#{START}.*?>)/um
-		end
-	end
+  module DTD
+    class AttlistDecl < Child
+      START = "<!ATTLIST"
+      START_RE = /^\s*#{START}/um
+      PATTERN_RE = /\s*(#{START}.*?>)/um
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/dtd/dtd.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/dtd/dtd.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/dtd/dtd.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,46 +6,46 @@
 require "rexml/parent"
 
 module REXML
-	module DTD
-		class Parser
-			def Parser.parse( input )
-				case input
-				when String
-					parse_helper input
-				when File
-					parse_helper input.read
-				end
-			end
+  module DTD
+    class Parser
+      def Parser.parse( input )
+        case input
+        when String
+          parse_helper input
+        when File
+          parse_helper input.read
+        end
+      end
 
-			# Takes a String and parses it out
-			def Parser.parse_helper( input )
-				contents = Parent.new
-				while input.size > 0
-					case input
-					when ElementDecl.PATTERN_RE
-						match = $&
-						source = $'
-						contents << ElementDecl.new( match )
-					when AttlistDecl.PATTERN_RE
-						matchdata = $~
-						source = $'
-						contents << AttlistDecl.new( matchdata )
-					when EntityDecl.PATTERN_RE
-						matchdata = $~
-						source = $'
-						contents << EntityDecl.new( matchdata )
-					when Comment.PATTERN_RE
-						matchdata = $~
-						source = $'
-						contents << Comment.new( matchdata )
-					when NotationDecl.PATTERN_RE
-						matchdata = $~
-						source = $'
-						contents << NotationDecl.new( matchdata )
-					end
-				end
-				contents
-			end
-		end
-	end
+      # Takes a String and parses it out
+      def Parser.parse_helper( input )
+        contents = Parent.new
+        while input.size > 0
+          case input
+          when ElementDecl.PATTERN_RE
+            match = $&
+            source = $'
+            contents << ElementDecl.new( match )
+          when AttlistDecl.PATTERN_RE
+            matchdata = $~
+            source = $'
+            contents << AttlistDecl.new( matchdata )
+          when EntityDecl.PATTERN_RE
+            matchdata = $~
+            source = $'
+            contents << EntityDecl.new( matchdata )
+          when Comment.PATTERN_RE
+            matchdata = $~
+            source = $'
+            contents << Comment.new( matchdata )
+          when NotationDecl.PATTERN_RE
+            matchdata = $~
+            source = $'
+            contents << NotationDecl.new( matchdata )
+          end
+        end
+        contents
+      end
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/dtd/elementdecl.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/dtd/elementdecl.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/dtd/elementdecl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,17 +1,17 @@
 require "rexml/child"
 module REXML
-	module DTD
-		class ElementDecl < Child
-			START = "<!ELEMENT"
-			START_RE = /^\s*#{START}/um
-			PATTERN_RE = /^\s*(#{START}.*?)>/um
-			PATTERN_RE = /^\s*#{START}\s+((?:[:\w_][-\.\w_]*:)?[-!\*\.\w_]*)(.*?)>/
-			#\s*((((["']).*?\5)|[^\/'">]*)*?)(\/)?>/um, true)
+  module DTD
+    class ElementDecl < Child
+      START = "<!ELEMENT"
+      START_RE = /^\s*#{START}/um
+      PATTERN_RE = /^\s*(#{START}.*?)>/um
+      PATTERN_RE = /^\s*#{START}\s+((?:[:\w_][-\.\w_]*:)?[-!\*\.\w_]*)(.*?)>/
+      #\s*((((["']).*?\5)|[^\/'">]*)*?)(\/)?>/um, true)
 
-			def initialize match
-				@name = match[1]
-				@rest = match[2]
-			end
-		end
-	end
+      def initialize match
+        @name = match[1]
+        @rest = match[2]
+      end
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/dtd/entitydecl.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/dtd/entitydecl.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/dtd/entitydecl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,56 +1,56 @@
 require "rexml/child"
 module REXML
-	module DTD
-		class EntityDecl < Child
-			START = "<!ENTITY"
-			START_RE = /^\s*#{START}/um
-			PUBLIC = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+PUBLIC\s+((["']).*?\3)\s+((["']).*?\5)\s*>/um
-			SYSTEM = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+SYSTEM\s+((["']).*?\3)(?:\s+NDATA\s+\w+)?\s*>/um
-			PLAIN = /^\s*#{START}\s+(\w+)\s+((["']).*?\3)\s*>/um
-			PERCENT = /^\s*#{START}\s+%\s+(\w+)\s+((["']).*?\3)\s*>/um
-			# <!ENTITY name SYSTEM "...">
-			# <!ENTITY name "...">
-			def initialize src
-				super()
-				md = nil
-				if src.match( PUBLIC )
-					md = src.match( PUBLIC, true )
-					@middle = "PUBLIC"
-					@content = "#{md[2]} #{md[4]}"
-				elsif src.match( SYSTEM )
-					md = src.match( SYSTEM, true )
-					@middle = "SYSTEM"
-					@content = md[2]
-				elsif src.match( PLAIN )
-					md = src.match( PLAIN, true )
-					@middle = ""
-					@content = md[2]
-				elsif src.match( PERCENT )
-					md = src.match( PERCENT, true )
-					@middle = ""
-					@content = md[2]
-				end
-				raise ParseException.new("failed Entity match", src) if md.nil?
-				@name = md[1]
-			end
+  module DTD
+    class EntityDecl < Child
+      START = "<!ENTITY"
+      START_RE = /^\s*#{START}/um
+      PUBLIC = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+PUBLIC\s+((["']).*?\3)\s+((["']).*?\5)\s*>/um
+      SYSTEM = /^\s*#{START}\s+(?:%\s+)?(\w+)\s+SYSTEM\s+((["']).*?\3)(?:\s+NDATA\s+\w+)?\s*>/um
+      PLAIN = /^\s*#{START}\s+(\w+)\s+((["']).*?\3)\s*>/um
+      PERCENT = /^\s*#{START}\s+%\s+(\w+)\s+((["']).*?\3)\s*>/um
+      # <!ENTITY name SYSTEM "...">
+      # <!ENTITY name "...">
+      def initialize src
+        super()
+        md = nil
+        if src.match( PUBLIC )
+          md = src.match( PUBLIC, true )
+          @middle = "PUBLIC"
+          @content = "#{md[2]} #{md[4]}"
+        elsif src.match( SYSTEM )
+          md = src.match( SYSTEM, true )
+          @middle = "SYSTEM"
+          @content = md[2]
+        elsif src.match( PLAIN )
+          md = src.match( PLAIN, true )
+          @middle = ""
+          @content = md[2]
+        elsif src.match( PERCENT )
+          md = src.match( PERCENT, true )
+          @middle = ""
+          @content = md[2]
+        end
+        raise ParseException.new("failed Entity match", src) if md.nil?
+        @name = md[1]
+      end
 
-			def to_s
-				rv = "<!ENTITY #@name "
-				rv << "#@middle " if @middle.size > 0
-				rv << @content
-				rv
-			end
+      def to_s
+        rv = "<!ENTITY #@name "
+        rv << "#@middle " if @middle.size > 0
+        rv << @content
+        rv
+      end
 
-			def write( output, indent )
+      def write( output, indent )
         indent( output, indent )
-				output << to_s
-			end
+        output << to_s
+      end
 
-			def EntityDecl.parse_source source, listener
-				md = source.match( PATTERN_RE, true )
-				thing = md[0].squeeze(" \t\n\r")
-				listener.send inspect.downcase, thing 
-			end
-		end
-	end
+      def EntityDecl.parse_source source, listener
+        md = source.match( PATTERN_RE, true )
+        thing = md[0].squeeze(" \t\n\r")
+        listener.send inspect.downcase, thing 
+      end
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/dtd/notationdecl.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/dtd/notationdecl.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/dtd/notationdecl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,39 +1,39 @@
 require "rexml/child"
 module REXML
-	module DTD
-		class NotationDecl < Child
-			START = "<!NOTATION"
-			START_RE = /^\s*#{START}/um
-			PUBLIC = /^\s*#{START}\s+(\w[\w-]*)\s+(PUBLIC)\s+((["']).*?\4)\s*>/um
-			SYSTEM = /^\s*#{START}\s+(\w[\w-]*)\s+(SYSTEM)\s+((["']).*?\4)\s*>/um
-			def initialize src
-				super()
-				if src.match( PUBLIC )
-					md = src.match( PUBLIC, true )
-				elsif src.match( SYSTEM )
-					md = src.match( SYSTEM, true )
-				else
-					raise ParseException.new( "error parsing notation: no matching pattern", src )
-				end
-				@name = md[1]
-				@middle = md[2]
-				@rest = md[3]
-			end
+  module DTD
+    class NotationDecl < Child
+      START = "<!NOTATION"
+      START_RE = /^\s*#{START}/um
+      PUBLIC = /^\s*#{START}\s+(\w[\w-]*)\s+(PUBLIC)\s+((["']).*?\4)\s*>/um
+      SYSTEM = /^\s*#{START}\s+(\w[\w-]*)\s+(SYSTEM)\s+((["']).*?\4)\s*>/um
+      def initialize src
+        super()
+        if src.match( PUBLIC )
+          md = src.match( PUBLIC, true )
+        elsif src.match( SYSTEM )
+          md = src.match( SYSTEM, true )
+        else
+          raise ParseException.new( "error parsing notation: no matching pattern", src )
+        end
+        @name = md[1]
+        @middle = md[2]
+        @rest = md[3]
+      end
 
-			def to_s
-				"<!NOTATION #@name #@middle #@rest>"
-			end
+      def to_s
+        "<!NOTATION #@name #@middle #@rest>"
+      end
 
-			def write( output, indent )
+      def write( output, indent )
         indent( output, indent )
-				output << to_s
-			end
+        output << to_s
+      end
 
-			def NotationDecl.parse_source source, listener
-				md = source.match( PATTERN_RE, true )
-				thing = md[0].squeeze(" \t\n\r")
-				listener.send inspect.downcase, thing 
-			end
-		end
-	end
+      def NotationDecl.parse_source source, listener
+        md = source.match( PATTERN_RE, true )
+        thing = md[0].squeeze(" \t\n\r")
+        listener.send inspect.downcase, thing 
+      end
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/element.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/element.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/element.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -360,7 +360,7 @@
     # Iterates through the children, yielding for each Element that
     # has a particular text set.
     # text:: 
-    #   the text to search for.  If nil, or not supplied, will itterate
+    #   the text to search for.  If nil, or not supplied, will iterate
     #   over all +Element+ children that contain at least one +Text+ node.
     # max:: 
     #   (optional) causes this method to return after yielding
@@ -691,6 +691,7 @@
       Kernel.warn("#{self.class.name}.write is deprecated.  See REXML::Formatters")
       formatter = if indent > -1
           if transitive
+            require "rexml/formatters/transitive"
             REXML::Formatters::Transitive.new( indent, ie_hack )
           else
             REXML::Formatters::Pretty.new( indent, ie_hack )
@@ -1003,7 +1004,7 @@
     end
     alias :size :length
 
-    # Itterates over the attributes of an Element.  Yields actual Attribute
+    # Iterates over the attributes of an Element.  Yields actual Attribute
     # nodes, not String values.
     # 
     #  doc = Document.new '<a x="1" y="2"/>'
@@ -1020,7 +1021,7 @@
       end
     end
 
-    # Itterates over each attribute of an Element, yielding the expanded name
+    # Iterates over each attribute of an Element, yielding the expanded name
     # and value as a pair of Strings.
     #
     #  doc = Document.new '<a x="1" y="2"/>'

Modified: MacRuby/branches/experimental/lib/rexml/encodings/CP-1252.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/encodings/CP-1252.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/encodings/CP-1252.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,12 +3,12 @@
 #
 module REXML
   module Encoding
-  	register( "CP-1252" ) do |o|
-  		class << o
-  			alias encode encode_cp1252
-			alias decode decode_cp1252
-  		end
-  	end
+    register( "CP-1252" ) do |o|
+      class << o
+        alias encode encode_cp1252
+      alias decode decode_cp1252
+      end
+    end
 
     # Convert from UTF-8
     def encode_cp1252(content)

Modified: MacRuby/branches/experimental/lib/rexml/encodings/ISO-8859-15.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/encodings/ISO-8859-15.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/encodings/ISO-8859-15.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,10 +3,10 @@
 #
 module REXML
   module Encoding
-  	register("ISO-8859-15") do |o|
-  		alias encode to_iso_8859_15
+    register("ISO-8859-15") do |o|
+      alias encode to_iso_8859_15
       alias decode from_iso_8859_15
-  	end
+    end
 
     # Convert from UTF-8
     def to_iso_8859_15(content)

Modified: MacRuby/branches/experimental/lib/rexml/entity.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/entity.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/entity.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,163 +3,164 @@
 require 'rexml/xmltokens'
 
 module REXML
-	# God, I hate DTDs.  I really do.  Why this idiot standard still
-	# plagues us is beyond me.
-	class Entity < Child
-		include XMLTokens
-		PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
-		SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))}
-		PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
-		EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
-		NDATADECL = "\\s+NDATA\\s+#{NAME}"
-		PEREFERENCE = "%#{NAME};"
-		ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
-		PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
-		ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
-		PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
-		GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
-		ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
+  # God, I hate DTDs.  I really do.  Why this idiot standard still
+  # plagues us is beyond me.
+  class Entity < Child
+    include XMLTokens
+    PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
+    SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))}
+    PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
+    EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
+    NDATADECL = "\\s+NDATA\\s+#{NAME}"
+    PEREFERENCE = "%#{NAME};"
+    ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
+    PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
+    ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
+    PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
+    GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
+    ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
 
-		attr_reader :name, :external, :ref, :ndata, :pubid
+    attr_reader :name, :external, :ref, :ndata, :pubid
 
-		# Create a new entity.  Simple entities can be constructed by passing a
-		# name, value to the constructor; this creates a generic, plain entity
-		# reference. For anything more complicated, you have to pass a Source to
-		# the constructor with the entity definiton, or use the accessor methods.
-		# +WARNING+: There is no validation of entity state except when the entity
-		# is read from a stream.  If you start poking around with the accessors,
-		# you can easily create a non-conformant Entity.  The best thing to do is
-		# dump the stupid DTDs and use XMLSchema instead.
-		# 
-		#  e = Entity.new( 'amp', '&' )
-		def initialize stream, value=nil, parent=nil, reference=false
-			super(parent)
-			@ndata = @pubid = @value = @external = nil
-			if stream.kind_of? Array
-				@name = stream[1]
-				if stream[-1] == '%'
-					@reference = true 
-					stream.pop
-				else
-					@reference = false
-				end
-				if stream[2] =~ /SYSTEM|PUBLIC/
-					@external = stream[2]
-					if @external == 'SYSTEM'
-						@ref = stream[3]
-						@ndata = stream[4] if stream.size == 5
-					else
-						@pubid = stream[3]
-						@ref = stream[4]
-					end
-				else
-					@value = stream[2]
-				end
-			else
-				@reference = reference
-				@external = nil
-				@name = stream
-				@value = value
-			end
-		end
+    # Create a new entity.  Simple entities can be constructed by passing a
+    # name, value to the constructor; this creates a generic, plain entity
+    # reference. For anything more complicated, you have to pass a Source to
+    # the constructor with the entity definiton, or use the accessor methods.
+    # +WARNING+: There is no validation of entity state except when the entity
+    # is read from a stream.  If you start poking around with the accessors,
+    # you can easily create a non-conformant Entity.  The best thing to do is
+    # dump the stupid DTDs and use XMLSchema instead.
+    # 
+    #  e = Entity.new( 'amp', '&' )
+    def initialize stream, value=nil, parent=nil, reference=false
+      super(parent)
+      @ndata = @pubid = @value = @external = nil
+      if stream.kind_of? Array
+        @name = stream[1]
+        if stream[-1] == '%'
+          @reference = true 
+          stream.pop
+        else
+          @reference = false
+        end
+        if stream[2] =~ /SYSTEM|PUBLIC/
+          @external = stream[2]
+          if @external == 'SYSTEM'
+            @ref = stream[3]
+            @ndata = stream[4] if stream.size == 5
+          else
+            @pubid = stream[3]
+            @ref = stream[4]
+          end
+        else
+          @value = stream[2]
+        end
+      else
+        @reference = reference
+        @external = nil
+        @name = stream
+        @value = value
+      end
+    end
 
-		# Evaluates whether the given string matchs an entity definition,
-		# returning true if so, and false otherwise.
-		def Entity::matches? string
-			(ENTITYDECL =~ string) == 0
-		end
+    # Evaluates whether the given string matchs an entity definition,
+    # returning true if so, and false otherwise.
+    def Entity::matches? string
+      (ENTITYDECL =~ string) == 0
+    end
 
-		# Evaluates to the unnormalized value of this entity; that is, replacing
-		# all entities -- both %ent; and &ent; entities.  This differs from
-		# +value()+ in that +value+ only replaces %ent; entities.
-		def unnormalized
-			v = value()
-			return nil if v.nil?
-			@unnormalized = Text::unnormalize(v, parent)
-			@unnormalized
-		end
+    # Evaluates to the unnormalized value of this entity; that is, replacing
+    # all entities -- both %ent; and &ent; entities.  This differs from
+    # +value()+ in that +value+ only replaces %ent; entities.
+    def unnormalized
+      document.record_entity_expansion unless document.nil?
+      v = value()
+      return nil if v.nil?
+      @unnormalized = Text::unnormalize(v, parent)
+      @unnormalized
+    end
 
-		#once :unnormalized
+    #once :unnormalized
 
-		# Returns the value of this entity unprocessed -- raw.  This is the
-		# normalized value; that is, with all %ent; and &ent; entities intact
-		def normalized
-			@value
-		end
+    # Returns the value of this entity unprocessed -- raw.  This is the
+    # normalized value; that is, with all %ent; and &ent; entities intact
+    def normalized
+      @value
+    end
 
-		# Write out a fully formed, correct entity definition (assuming the Entity
-		# object itself is valid.)
+    # Write out a fully formed, correct entity definition (assuming the Entity
+    # object itself is valid.)
     #
     # out::
     #   An object implementing <TT>&lt;&lt;<TT> to which the entity will be
     #   output
     # indent::
     #   *DEPRECATED* and ignored
-		def write out, indent=-1
-			out << '<!ENTITY '
-			out << '% ' if @reference
-			out << @name
-			out << ' '
-			if @external
-				out << @external << ' '
-				if @pubid
-					q = @pubid.include?('"')?"'":'"'
-					out << q << @pubid << q << ' '
-				end
-				q = @ref.include?('"')?"'":'"'
-				out << q << @ref << q
-				out << ' NDATA ' << @ndata if @ndata
-			else
-				q = @value.include?('"')?"'":'"'
-				out << q << @value << q
-			end
-			out << '>'
-		end
+    def write out, indent=-1
+      out << '<!ENTITY '
+      out << '% ' if @reference
+      out << @name
+      out << ' '
+      if @external
+        out << @external << ' '
+        if @pubid
+          q = @pubid.include?('"')?"'":'"'
+          out << q << @pubid << q << ' '
+        end
+        q = @ref.include?('"')?"'":'"'
+        out << q << @ref << q
+        out << ' NDATA ' << @ndata if @ndata
+      else
+        q = @value.include?('"')?"'":'"'
+        out << q << @value << q
+      end
+      out << '>'
+    end
 
-		# Returns this entity as a string.  See write().
-		def to_s
-			rv = ''
-			write rv
-			rv
-		end
+    # Returns this entity as a string.  See write().
+    def to_s
+      rv = ''
+      write rv
+      rv
+    end
 
-		PEREFERENCE_RE = /#{PEREFERENCE}/um
-		# Returns the value of this entity.  At the moment, only internal entities
-		# are processed.  If the value contains internal references (IE,
-		# %blah;), those are replaced with their values.  IE, if the doctype
-		# contains:
-		#  <!ENTITY % foo "bar">
-		#  <!ENTITY yada "nanoo %foo; nanoo>
-		# then:
-		#  doctype.entity('yada').value   #-> "nanoo bar nanoo"
-		def value
-			if @value
-				matches = @value.scan(PEREFERENCE_RE)
-				rv = @value.clone
-				if @parent
-					matches.each do |entity_reference|
-						entity_value = @parent.entity( entity_reference[0] )
-						rv.gsub!( /%#{entity_reference.join};/um, entity_value )
-					end
-				end
-				return rv
-			end
-			nil
-		end
-	end
+    PEREFERENCE_RE = /#{PEREFERENCE}/um
+    # Returns the value of this entity.  At the moment, only internal entities
+    # are processed.  If the value contains internal references (IE,
+    # %blah;), those are replaced with their values.  IE, if the doctype
+    # contains:
+    #  <!ENTITY % foo "bar">
+    #  <!ENTITY yada "nanoo %foo; nanoo>
+    # then:
+    #  doctype.entity('yada').value   #-> "nanoo bar nanoo"
+    def value
+      if @value
+        matches = @value.scan(PEREFERENCE_RE)
+        rv = @value.clone
+        if @parent
+          matches.each do |entity_reference|
+            entity_value = @parent.entity( entity_reference[0] )
+            rv.gsub!( /%#{entity_reference.join};/um, entity_value )
+          end
+        end
+        return rv
+      end
+      nil
+    end
+  end
 
-	# This is a set of entity constants -- the ones defined in the XML
-	# specification.  These are +gt+, +lt+, +amp+, +quot+ and +apos+.
-	module EntityConst
-		# +>+
-		GT = Entity.new( 'gt', '>' )
-		# +<+
-		LT = Entity.new( 'lt', '<' )
-		# +&+
-		AMP = Entity.new( 'amp', '&' )
-		# +"+
-		QUOT = Entity.new( 'quot', '"' )
-		# +'+
-		APOS = Entity.new( 'apos', "'" )
-	end
+  # This is a set of entity constants -- the ones defined in the XML
+  # specification.  These are +gt+, +lt+, +amp+, +quot+ and +apos+.
+  module EntityConst
+    # +>+
+    GT = Entity.new( 'gt', '>' )
+    # +<+
+    LT = Entity.new( 'lt', '<' )
+    # +&+
+    AMP = Entity.new( 'amp', '&' )
+    # +"+
+    QUOT = Entity.new( 'quot', '"' )
+    # +'+
+    APOS = Entity.new( 'apos', "'" )
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/formatters/pretty.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/formatters/pretty.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/formatters/pretty.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -126,9 +126,10 @@
       end
 
       def wrap(string, width)
-        # Recursivly wrap string at width.
+        # Recursively wrap string at width.
         return string if string.length <= width
         place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
+        return string if place.nil?
         return string[0,place] + "\n" + wrap(string[place+1..-1], width)
       end
 

Modified: MacRuby/branches/experimental/lib/rexml/formatters/transitive.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/formatters/transitive.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/formatters/transitive.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -12,9 +12,10 @@
     # formatted.  Since this formatter does not alter whitespace nodes, the
     # results of formatting already formatted XML will be odd.
     class Transitive < Default
-      def initialize( indentation=2 )
+      def initialize( indentation=2, ie_hack=false )
         @indentation = indentation
         @level = 0
+        @ie_hack = ie_hack
       end
 
       protected
@@ -29,6 +30,7 @@
         output << "\n"
         output << ' '*@level
         if node.children.empty?
+          output << " " if @ie_hack
           output << "/" 
         else
           output << ">"

Modified: MacRuby/branches/experimental/lib/rexml/functions.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/functions.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/functions.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -235,7 +235,7 @@
       # from string then we ignore the second &
       # subsequent mappings
       #
-      # if a charactcer maps to nil then we delete it
+      # if a character maps to nil then we delete it
       # in the output.  This happens if the from
       # string is longer than the to string
       #

Modified: MacRuby/branches/experimental/lib/rexml/instruction.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/instruction.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/instruction.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,62 +2,62 @@
 require "rexml/source"
 
 module REXML
-	# Represents an XML Instruction; IE, <? ... ?>
-	# TODO: Add parent arg (3rd arg) to constructor
-	class Instruction < Child
-		START = '<\?'
-		STOP = '\?>'
+  # Represents an XML Instruction; IE, <? ... ?>
+  # TODO: Add parent arg (3rd arg) to constructor
+  class Instruction < Child
+    START = '<\?'
+    STOP = '\?>'
 
-		# target is the "name" of the Instruction; IE, the "tag" in <?tag ...?>
-		# content is everything else.
-		attr_accessor :target, :content
+    # target is the "name" of the Instruction; IE, the "tag" in <?tag ...?>
+    # content is everything else.
+    attr_accessor :target, :content
 
-		# Constructs a new Instruction
-		# @param target can be one of a number of things.  If String, then 
-		# the target of this instruction is set to this.  If an Instruction,
-		# then the Instruction is shallowly cloned (target and content are
-		# copied).  If a Source, then the source is scanned and parsed for
-		# an Instruction declaration.
-		# @param content Must be either a String, or a Parent.  Can only
-		# be a Parent if the target argument is a Source.  Otherwise, this
-		# String is set as the content of this instruction.
-		def initialize(target, content=nil)
-			if target.kind_of? String
-				super()
-				@target = target
-				@content = content
-			elsif target.kind_of? Instruction
-				super(content)
-				@target = target.target
-				@content = target.content
-			end
-			@content.strip! if @content
-		end
+    # Constructs a new Instruction
+    # @param target can be one of a number of things.  If String, then 
+    # the target of this instruction is set to this.  If an Instruction,
+    # then the Instruction is shallowly cloned (target and content are
+    # copied).  If a Source, then the source is scanned and parsed for
+    # an Instruction declaration.
+    # @param content Must be either a String, or a Parent.  Can only
+    # be a Parent if the target argument is a Source.  Otherwise, this
+    # String is set as the content of this instruction.
+    def initialize(target, content=nil)
+      if target.kind_of? String
+        super()
+        @target = target
+        @content = content
+      elsif target.kind_of? Instruction
+        super(content)
+        @target = target.target
+        @content = target.content
+      end
+      @content.strip! if @content
+    end
 
-		def clone
-			Instruction.new self
-		end
-		
+    def clone
+      Instruction.new self
+    end
+    
     # == DEPRECATED
     # See the rexml/formatters package
     #
-		def write writer, indent=-1, transitive=false, ie_hack=false
+    def write writer, indent=-1, transitive=false, ie_hack=false
       Kernel.warn( "#{self.class.name}.write is deprecated" )
-			indent(writer, indent)
-			writer << START.sub(/\\/u, '')
-			writer << @target
-			writer << ' '
-			writer << @content
-			writer << STOP.sub(/\\/u, '')
-		end
+      indent(writer, indent)
+      writer << START.sub(/\\/u, '')
+      writer << @target
+      writer << ' '
+      writer << @content
+      writer << STOP.sub(/\\/u, '')
+    end
 
-		# @return true if other is an Instruction, and the content and target
-		# of the other matches the target and content of this object.
-		def ==( other )
-			other.kind_of? Instruction and
-			other.target == @target and
-			other.content == @content
-		end
+    # @return true if other is an Instruction, and the content and target
+    # of the other matches the target and content of this object.
+    def ==( other )
+      other.kind_of? Instruction and
+      other.target == @target and
+      other.content == @content
+    end
 
     def node_type
       :processing_instruction
@@ -66,5 +66,5 @@
     def inspect
       "<?p-i #{target} ...?>"
     end
-	end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/light/node.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/light/node.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/light/node.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,195 +2,195 @@
 require 'rexml/light/node'
 
 # [ :element, parent, name, attributes, children* ]
-	# a = Node.new
-	# a << "B"		# => <a>B</a>
-	# a.b			# => <a>B<b/></a>
-	# a.b[1]			# => <a>B<b/><b/><a>
-	# a.b[1]["x"] = "y"	# => <a>B<b/><b x="y"/></a>
-	# a.b[0].c		# => <a>B<b><c/></b><b x="y"/></a>
-	# a.b.c << "D"		# => <a>B<b><c>D</c></b><b x="y"/></a>
+  # a = Node.new
+  # a << "B"		# => <a>B</a>
+  # a.b			# => <a>B<b/></a>
+  # a.b[1]			# => <a>B<b/><b/><a>
+  # a.b[1]["x"] = "y"	# => <a>B<b/><b x="y"/></a>
+  # a.b[0].c		# => <a>B<b><c/></b><b x="y"/></a>
+  # a.b.c << "D"		# => <a>B<b><c>D</c></b><b x="y"/></a>
 module REXML
-	module Light
-		# Represents a tagged XML element.  Elements are characterized by
-		# having children, attributes, and names, and can themselves be
-		# children.
-		class Node
-			NAMESPLIT = /^(?:(#{XMLTokens::NCNAME_STR}):)?(#{XMLTokens::NCNAME_STR})/u
-			PARENTS = [ :element, :document, :doctype ]
-			# Create a new element.
-			def initialize node=nil
-				@node = node
-				if node.kind_of? String
-					node = [ :text, node ]
-				elsif node.nil?
-					node = [ :document, nil, nil ]
-				elsif node[0] == :start_element
-					node[0] = :element
-				elsif node[0] == :start_doctype
-					node[0] = :doctype
-				elsif node[0] == :start_document
-					node[0] = :document
-				end
-			end
+  module Light
+    # Represents a tagged XML element.  Elements are characterized by
+    # having children, attributes, and names, and can themselves be
+    # children.
+    class Node
+      NAMESPLIT = /^(?:(#{XMLTokens::NCNAME_STR}):)?(#{XMLTokens::NCNAME_STR})/u
+      PARENTS = [ :element, :document, :doctype ]
+      # Create a new element.
+      def initialize node=nil
+        @node = node
+        if node.kind_of? String
+          node = [ :text, node ]
+        elsif node.nil?
+          node = [ :document, nil, nil ]
+        elsif node[0] == :start_element
+          node[0] = :element
+        elsif node[0] == :start_doctype
+          node[0] = :doctype
+        elsif node[0] == :start_document
+          node[0] = :document
+        end
+      end
 
-			def size
-				if PARENTS.include? @node[0]
-					@node[-1].size
-				else
-					0
-				end
-			end
+      def size
+        if PARENTS.include? @node[0]
+          @node[-1].size
+        else
+          0
+        end
+      end
 
-			def each( &block )
-				size.times { |x| yield( at(x+4) ) }
-			end
+      def each( &block )
+        size.times { |x| yield( at(x+4) ) }
+      end
 
-			def name
-				at(2)
-			end
+      def name
+        at(2)
+      end
 
-			def name=( name_str, ns=nil )
-				pfx = ''
-				pfx = "#{prefix(ns)}:" if ns
-				_old_put(2, "#{pfx}#{name_str}")
-			end
+      def name=( name_str, ns=nil )
+        pfx = ''
+        pfx = "#{prefix(ns)}:" if ns
+        _old_put(2, "#{pfx}#{name_str}")
+      end
 
-			def parent=( node )
-				_old_put(1,node)
-			end
+      def parent=( node )
+        _old_put(1,node)
+      end
 
-			def local_name
-				namesplit
-				@name
-			end
+      def local_name
+        namesplit
+        @name
+      end
 
-			def local_name=( name_str )
-				_old_put( 1, "#@prefix:#{name_str}" )
-			end
+      def local_name=( name_str )
+        _old_put( 1, "#@prefix:#{name_str}" )
+      end
 
-			def prefix( namespace=nil )
-				prefix_of( self, namespace )
-			end
+      def prefix( namespace=nil )
+        prefix_of( self, namespace )
+      end
 
-			def namespace( prefix=prefix() )
-				namespace_of( self, prefix )
-			end
+      def namespace( prefix=prefix() )
+        namespace_of( self, prefix )
+      end
 
-			def namespace=( namespace )
-				@prefix = prefix( namespace )
-				pfx = ''
-				pfx = "#@prefix:" if @prefix.size > 0
-				_old_put(1, "#{pfx}#@name")
-			end
+      def namespace=( namespace )
+        @prefix = prefix( namespace )
+        pfx = ''
+        pfx = "#@prefix:" if @prefix.size > 0
+        _old_put(1, "#{pfx}#@name")
+      end
 
-			def []( reference, ns=nil )
-				if reference.kind_of? String
-					pfx = ''
-					pfx = "#{prefix(ns)}:" if ns
-					at(3)["#{pfx}#{reference}"]
-				elsif reference.kind_of? Range
-					_old_get( Range.new(4+reference.begin, reference.end, reference.exclude_end?) )
-				else
-					_old_get( 4+reference )
-				end
-			end
+      def []( reference, ns=nil )
+        if reference.kind_of? String
+          pfx = ''
+          pfx = "#{prefix(ns)}:" if ns
+          at(3)["#{pfx}#{reference}"]
+        elsif reference.kind_of? Range
+          _old_get( Range.new(4+reference.begin, reference.end, reference.exclude_end?) )
+        else
+          _old_get( 4+reference )
+        end
+      end
 
-			def =~( path )
-				XPath.match( self, path )
-			end
+      def =~( path )
+        XPath.match( self, path )
+      end
 
-			# Doesn't handle namespaces yet
-			def []=( reference, ns, value=nil )
-				if reference.kind_of? String
-					value = ns unless value
-					at( 3 )[reference] = value
-				elsif reference.kind_of? Range
-					_old_put( Range.new(3+reference.begin, reference.end, reference.exclude_end?), ns )
-				else
-					if value
-						_old_put( 4+reference, ns, value )
-					else
-						_old_put( 4+reference, ns )
-					end
-				end
-			end
+      # Doesn't handle namespaces yet
+      def []=( reference, ns, value=nil )
+        if reference.kind_of? String
+          value = ns unless value
+          at( 3 )[reference] = value
+        elsif reference.kind_of? Range
+          _old_put( Range.new(3+reference.begin, reference.end, reference.exclude_end?), ns )
+        else
+          if value
+            _old_put( 4+reference, ns, value )
+          else
+            _old_put( 4+reference, ns )
+          end
+        end
+      end
 
-			# Append a child to this element, optionally under a provided namespace.
-			# The namespace argument is ignored if the element argument is an Element
-			# object.  Otherwise, the element argument is a string, the namespace (if
-			# provided) is the namespace the element is created in.
-			def << element
-				if node_type() == :text
-					at(-1) << element
-				else
-					newnode = Node.new( element )
-					newnode.parent = self
-					self.push( newnode )
-				end
-				at(-1)
-			end
+      # Append a child to this element, optionally under a provided namespace.
+      # The namespace argument is ignored if the element argument is an Element
+      # object.  Otherwise, the element argument is a string, the namespace (if
+      # provided) is the namespace the element is created in.
+      def << element
+        if node_type() == :text
+          at(-1) << element
+        else
+          newnode = Node.new( element )
+          newnode.parent = self
+          self.push( newnode )
+        end
+        at(-1)
+      end
 
-			def node_type
-				_old_get(0)
-			end
+      def node_type
+        _old_get(0)
+      end
 
-			def text=( foo )
-				replace = at(4).kind_of?(String)? 1 : 0
-				self._old_put(4,replace, normalizefoo)
-			end
+      def text=( foo )
+        replace = at(4).kind_of?(String)? 1 : 0
+        self._old_put(4,replace, normalizefoo)
+      end
 
-			def root
-				context = self
-				context = context.at(1) while context.at(1)
-			end
+      def root
+        context = self
+        context = context.at(1) while context.at(1)
+      end
 
-			def has_name?( name, namespace = '' )
-				at(3) == name and namespace() == namespace
-			end
+      def has_name?( name, namespace = '' )
+        at(3) == name and namespace() == namespace
+      end
 
-			def children
-				self
-			end
+      def children
+        self
+      end
 
-			def parent
-				at(1)
-			end
+      def parent
+        at(1)
+      end
 
-			def to_s
+      def to_s
 
-			end
+      end
 
-			private
+      private
 
-			def namesplit
-				return if @name.defined?
-				at(2) =~ NAMESPLIT
-				@prefix = '' || $1
-				@name = $2
-			end
+      def namesplit
+        return if @name.defined?
+        at(2) =~ NAMESPLIT
+        @prefix = '' || $1
+        @name = $2
+      end
 
-			def namespace_of( node, prefix=nil )
-				if not prefix
-					name = at(2)
-					name =~ NAMESPLIT
-					prefix = $1
-				end
-				to_find = 'xmlns'
-				to_find = "xmlns:#{prefix}" if not prefix.nil?
-				ns = at(3)[ to_find ]
-				ns ? ns : namespace_of( @node[0], prefix )
-			end
+      def namespace_of( node, prefix=nil )
+        if not prefix
+          name = at(2)
+          name =~ NAMESPLIT
+          prefix = $1
+        end
+        to_find = 'xmlns'
+        to_find = "xmlns:#{prefix}" if not prefix.nil?
+        ns = at(3)[ to_find ]
+        ns ? ns : namespace_of( @node[0], prefix )
+      end
 
-			def prefix_of( node, namespace=nil )
-				if not namespace
-					name = node.name
-					name =~ NAMESPLIT
-					$1
-				else
-					ns = at(3).find { |k,v| v == namespace }
-					ns ? ns : prefix_of( node.parent, namespace )
-				end
-			end
-		end
-	end
+      def prefix_of( node, namespace=nil )
+        if not namespace
+          name = node.name
+          name =~ NAMESPLIT
+          $1
+        else
+          ns = at(3).find { |k,v| v == namespace }
+          ns ? ns : prefix_of( node.parent, namespace )
+        end
+      end
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/namespace.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/namespace.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/namespace.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,47 +1,47 @@
 require 'rexml/xmltokens'
 
 module REXML
-	# Adds named attributes to an object.
-	module Namespace
-		# The name of the object, valid if set
-		attr_reader :name, :expanded_name
-		# The expanded name of the object, valid if name is set
-		attr_accessor :prefix
-		include XMLTokens
-		NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u
+  # Adds named attributes to an object.
+  module Namespace
+    # The name of the object, valid if set
+    attr_reader :name, :expanded_name
+    # The expanded name of the object, valid if name is set
+    attr_accessor :prefix
+    include XMLTokens
+    NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u
 
-		# Sets the name and the expanded name
-		def name=( name )
-			@expanded_name = name
-			name =~ NAMESPLIT
-			if $1
-				@prefix = $1
-			else
-				@prefix = ""
-				@namespace = ""
-			end
-			@name = $2
-		end
+    # Sets the name and the expanded name
+    def name=( name )
+      @expanded_name = name
+      name =~ NAMESPLIT
+      if $1
+        @prefix = $1
+      else
+        @prefix = ""
+        @namespace = ""
+      end
+      @name = $2
+    end
 
-		# Compares names optionally WITH namespaces
-		def has_name?( other, ns=nil )
-			if ns
-				return (namespace() == ns and name() == other)
-			elsif other.include? ":"
-				return fully_expanded_name == other
-			else
-				return name == other
-			end
-		end
+    # Compares names optionally WITH namespaces
+    def has_name?( other, ns=nil )
+      if ns
+        return (namespace() == ns and name() == other)
+      elsif other.include? ":"
+        return fully_expanded_name == other
+      else
+        return name == other
+      end
+    end
 
-		alias :local_name :name
+    alias :local_name :name
 
-		# Fully expand the name, even if the prefix wasn't specified in the
-		# source file.
-		def fully_expanded_name
-			ns = prefix
-			return "#{ns}:#@name" if ns.size > 0 
-			return @name
-		end
-	end
+    # Fully expand the name, even if the prefix wasn't specified in the
+    # source file.
+    def fully_expanded_name
+      ns = prefix
+      return "#{ns}:#@name" if ns.size > 0 
+      return @name
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/node.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/node.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/node.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,27 +3,27 @@
 require "rexml/formatters/default"
 
 module REXML
-	# Represents a node in the tree.  Nodes are never encountered except as
-	# superclasses of other objects.  Nodes have siblings.
-	module Node
-		# @return the next sibling (nil if unset)
-		def next_sibling_node
-			return nil if @parent.nil?
-			@parent[ @parent.index(self) + 1 ]
-		end
+  # Represents a node in the tree.  Nodes are never encountered except as
+  # superclasses of other objects.  Nodes have siblings.
+  module Node
+    # @return the next sibling (nil if unset)
+    def next_sibling_node
+      return nil if @parent.nil?
+      @parent[ @parent.index(self) + 1 ]
+    end
 
-		# @return the previous sibling (nil if unset)
-		def previous_sibling_node
-			return nil if @parent.nil?
-			ind = @parent.index(self)
-			return nil if ind == 0
-			@parent[ ind - 1 ]
-		end
+    # @return the previous sibling (nil if unset)
+    def previous_sibling_node
+      return nil if @parent.nil?
+      ind = @parent.index(self)
+      return nil if ind == 0
+      @parent[ ind - 1 ]
+    end
 
     # indent::
     #   *DEPRECATED* This parameter is now ignored.  See the formatters in the
     #   REXML::Formatters package for changing the output style.
-		def to_s indent=nil
+    def to_s indent=nil
       unless indent.nil?
         Kernel.warn( "#{self.class.name}.to_s(indent) parameter is deprecated" )
         f = REXML::Formatters::Pretty.new( indent )
@@ -33,33 +33,33 @@
         f.write( self, rv = "" )
       end
       return rv
-		end
+    end
 
-		def indent to, ind
+    def indent to, ind
  			if @parent and @parent.context and not @parent.context[:indentstyle].nil? then
  				indentstyle = @parent.context[:indentstyle]
  			else
  				indentstyle = '  '
  			end
  			to << indentstyle*ind unless ind<1
-		end
+    end
 
-		def parent?
-			false;
-		end
+    def parent?
+      false;
+    end
 
 
-		# Visit all subnodes of +self+ recursively
-		def each_recursive(&block) # :yields: node
-			self.elements.each {|node|
-				block.call(node)
-				node.each_recursive(&block)
-			}
-		end
+    # Visit all subnodes of +self+ recursively
+    def each_recursive(&block) # :yields: node
+      self.elements.each {|node|
+        block.call(node)
+        node.each_recursive(&block)
+      }
+    end
 
-		# Find (and return) first subnode (recursively) for which the block 
+    # Find (and return) first subnode (recursively) for which the block 
     # evaluates to true. Returns +nil+ if none was found.
-		def find_first_recursive(&block) # :yields: node
+    def find_first_recursive(&block) # :yields: node
       each_recursive {|node|
         return node if block.call(node)
       }
@@ -71,5 +71,5 @@
     def index_in_parent
       parent.index(self)+1
     end
-	end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/output.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/output.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/output.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,24 +1,24 @@
 require 'rexml/encoding'
 
 module REXML
-	class Output
-		include Encoding
+  class Output
+    include Encoding
     
     attr_reader :encoding
 
-		def initialize real_IO, encd="iso-8859-1"
-			@output = real_IO
-			self.encoding = encd
+    def initialize real_IO, encd="iso-8859-1"
+      @output = real_IO
+      self.encoding = encd
 
-			@to_utf = encd == UTF_8 ? false : true
-		end
+      @to_utf = encd == UTF_8 ? false : true
+    end
 
-		def <<( content )
-			@output << (@to_utf ? self.encode(content) : content)
-		end
+    def <<( content )
+      @output << (@to_utf ? self.encode(content) : content)
+    end
 
     def to_s
       "Output[#{encoding}]"
     end
-	end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/parsers/lightparser.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/parsers/lightparser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/parsers/lightparser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,12 +3,12 @@
 require 'rexml/light/node'
 
 module REXML
-	module Parsers
-		class LightParser
-			def initialize stream
-				@stream = stream
-				@parser = REXML::Parsers::BaseParser.new( stream )
-			end
+  module Parsers
+    class LightParser
+      def initialize stream
+        @stream = stream
+        @parser = REXML::Parsers::BaseParser.new( stream )
+      end
 
       def add_listener( listener )
         @parser.add_listener( listener )
@@ -19,42 +19,40 @@
         @parser.stream = @stream
       end
 
-			def parse
-				root = context = [ :document ]
-				while true
-					event = @parser.pull
-					case event[0]
-					when :end_document
-						break
-					when :end_doctype
-						context = context[1]
-					when :start_element, :start_doctype
-						new_node = event
-						context << new_node
-						new_node[1,0] = [context]
-						context = new_node
-					when :end_element, :end_doctype
-						context = context[1]
-					else
-						new_node = event
-						context << new_node
-						new_node[1,0] = [context]
-					end
-				end
-				root
-			end
-		end
+      def parse
+        root = context = [ :document ]
+        while true
+          event = @parser.pull
+          case event[0]
+          when :end_document
+            break
+          when :start_element, :start_doctype
+            new_node = event
+            context << new_node
+            new_node[1,0] = [context]
+            context = new_node
+          when :end_element, :end_doctype
+            context = context[1]
+          else
+            new_node = event
+            context << new_node
+            new_node[1,0] = [context]
+          end
+        end
+        root
+      end
+    end
 
-		# An element is an array.  The array contains:
-		#  0			The parent element
-		#  1			The tag name
-		#  2			A hash of attributes
-		#  3..-1	The child elements
-		# An element is an array of size > 3
-		# Text is a String
-		# PIs are [ :processing_instruction, target, data ]
-		# Comments are [ :comment, data ]
-		# DocTypes are DocType structs
-		# The root is an array with XMLDecls, Text, DocType, Array, Text
-	end
+    # An element is an array.  The array contains:
+    #  0			The parent element
+    #  1			The tag name
+    #  2			A hash of attributes
+    #  3..-1	The child elements
+    # An element is an array of size > 3
+    # Text is a String
+    # PIs are [ :processing_instruction, target, data ]
+    # Comments are [ :comment, data ]
+    # DocTypes are DocType structs
+    # The root is an array with XMLDecls, Text, DocType, Array, Text
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/parsers/sax2parser.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/parsers/sax2parser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/parsers/sax2parser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -4,158 +4,158 @@
 require 'rexml/text'
 
 module REXML
-	module Parsers
+  module Parsers
     # SAX2Parser
-		class SAX2Parser
-			def initialize source
-				@parser = BaseParser.new(source)
-				@listeners = []
-				@procs = []
-				@namespace_stack = []
-				@has_listeners = false
-				@tag_stack = []
+    class SAX2Parser
+      def initialize source
+        @parser = BaseParser.new(source)
+        @listeners = []
+        @procs = []
+        @namespace_stack = []
+        @has_listeners = false
+        @tag_stack = []
         @entities = {}
-			end
+      end
 
       def source
         @parser.source
       end
-			
+      
       def add_listener( listener )
         @parser.add_listener( listener )
       end
 
-			# Listen arguments:
-			#
-			# Symbol, Array, Block
-			# 	Listen to Symbol events on Array elements
-			# Symbol, Block
-			#   Listen to Symbol events
-			# Array, Listener
-			# 	Listen to all events on Array elements
-			# Array, Block
-			# 	Listen to :start_element events on Array elements
-			# Listener
-			# 	Listen to All events
-			#
-			# Symbol can be one of: :start_element, :end_element,
-			# :start_prefix_mapping, :end_prefix_mapping, :characters,
-			# :processing_instruction, :doctype, :attlistdecl, :elementdecl,
-			# :entitydecl, :notationdecl, :cdata, :xmldecl, :comment
+      # Listen arguments:
       #
+      # Symbol, Array, Block
+      # 	Listen to Symbol events on Array elements
+      # Symbol, Block
+      #   Listen to Symbol events
+      # Array, Listener
+      # 	Listen to all events on Array elements
+      # Array, Block
+      # 	Listen to :start_element events on Array elements
+      # Listener
+      # 	Listen to All events
+      #
+      # Symbol can be one of: :start_element, :end_element,
+      # :start_prefix_mapping, :end_prefix_mapping, :characters,
+      # :processing_instruction, :doctype, :attlistdecl, :elementdecl,
+      # :entitydecl, :notationdecl, :cdata, :xmldecl, :comment
+      #
       # There is an additional symbol that can be listened for: :progress.
       # This will be called for every event generated, passing in the current 
       # stream position.
-			#
-			# Array contains regular expressions or strings which will be matched
-			# against fully qualified element names.
-			#
-			# Listener must implement the methods in SAX2Listener
-			#
-			# Block will be passed the same arguments as a SAX2Listener method would
-			# be, where the method name is the same as the matched Symbol.
-			# See the SAX2Listener for more information.
-			def listen( *args, &blok )
-				if args[0].kind_of? Symbol
-					if args.size == 2
-						args[1].each { |match| @procs << [args[0], match, blok] }
-					else
-						add( [args[0], nil, blok] )
-					end
-				elsif args[0].kind_of? Array
-					if args.size == 2
-						args[0].each { |match| add( [nil, match, args[1]] ) }
-					else
-						args[0].each { |match| add( [ :start_element, match, blok ] ) }
-					end
-				else
-					add([nil, nil, args[0]])
-				end
-			end
-			
-			def deafen( listener=nil, &blok )
-				if listener
-					@listeners.delete_if {|item| item[-1] == listener }
-					@has_listeners = false if @listeners.size == 0
-				else
-					@procs.delete_if {|item| item[-1] == blok }
-				end
-			end
-			
-			def parse
-				@procs.each { |sym,match,block| block.call if sym == :start_document }
-				@listeners.each { |sym,match,block| 
-					block.start_document if sym == :start_document or sym.nil?
-				}
-				root = context = []
-				while true
-					event = @parser.pull
-					case event[0]
-					when :end_document
-						handle( :end_document )
-						break
+      #
+      # Array contains regular expressions or strings which will be matched
+      # against fully qualified element names.
+      #
+      # Listener must implement the methods in SAX2Listener
+      #
+      # Block will be passed the same arguments as a SAX2Listener method would
+      # be, where the method name is the same as the matched Symbol.
+      # See the SAX2Listener for more information.
+      def listen( *args, &blok )
+        if args[0].kind_of? Symbol
+          if args.size == 2
+            args[1].each { |match| @procs << [args[0], match, blok] }
+          else
+            add( [args[0], nil, blok] )
+          end
+        elsif args[0].kind_of? Array
+          if args.size == 2
+            args[0].each { |match| add( [nil, match, args[1]] ) }
+          else
+            args[0].each { |match| add( [ :start_element, match, blok ] ) }
+          end
+        else
+          add([nil, nil, args[0]])
+        end
+      end
+      
+      def deafen( listener=nil, &blok )
+        if listener
+          @listeners.delete_if {|item| item[-1] == listener }
+          @has_listeners = false if @listeners.size == 0
+        else
+          @procs.delete_if {|item| item[-1] == blok }
+        end
+      end
+      
+      def parse
+        @procs.each { |sym,match,block| block.call if sym == :start_document }
+        @listeners.each { |sym,match,block| 
+          block.start_document if sym == :start_document or sym.nil?
+        }
+        root = context = []
+        while true
+          event = @parser.pull
+          case event[0]
+          when :end_document
+            handle( :end_document )
+            break
           when :start_doctype
             handle( :doctype, *event[1..-1])
-					when :end_doctype
-						context = context[1]
-					when :start_element
-						@tag_stack.push(event[1])
-						# find the observers for namespaces
-						procs = get_procs( :start_prefix_mapping, event[1] )
-						listeners = get_listeners( :start_prefix_mapping, event[1] )
-						if procs or listeners
-							# break out the namespace declarations
-							# The attributes live in event[2]
-							event[2].each {|n, v| event[2][n] = @parser.normalize(v)}
-							nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ }
-							nsdecl.collect! { |n, value| [ n[6..-1], value ] }
-							@namespace_stack.push({})
-							nsdecl.each do |n,v|
-								@namespace_stack[-1][n] = v
-								# notify observers of namespaces
-								procs.each { |ob| ob.call( n, v ) } if procs
-								listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners
-							end
-						end
-						event[1] =~ Namespace::NAMESPLIT
-						prefix = $1
-						local = $2
-						uri = get_namespace(prefix)
-						# find the observers for start_element
-						procs = get_procs( :start_element, event[1] )
-						listeners = get_listeners( :start_element, event[1] )
-						# notify observers
-						procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs
-						listeners.each { |ob| 
-							ob.start_element( uri, local, event[1], event[2] ) 
-						} if listeners
-					when :end_element
-						@tag_stack.pop
-						event[1] =~ Namespace::NAMESPLIT
-						prefix = $1
-						local = $2
-						uri = get_namespace(prefix)
-						# find the observers for start_element
-						procs = get_procs( :end_element, event[1] )
-						listeners = get_listeners( :end_element, event[1] )
-						# notify observers
-						procs.each { |ob| ob.call( uri, local, event[1] ) } if procs
-						listeners.each { |ob| 
-							ob.end_element( uri, local, event[1] ) 
-						} if listeners
+          when :end_doctype
+            context = context[1]
+          when :start_element
+            @tag_stack.push(event[1])
+            # find the observers for namespaces
+            procs = get_procs( :start_prefix_mapping, event[1] )
+            listeners = get_listeners( :start_prefix_mapping, event[1] )
+            if procs or listeners
+              # break out the namespace declarations
+              # The attributes live in event[2]
+              event[2].each {|n, v| event[2][n] = @parser.normalize(v)}
+              nsdecl = event[2].find_all { |n, value| n =~ /^xmlns(:|$)/ }
+              nsdecl.collect! { |n, value| [ n[6..-1], value ] }
+              @namespace_stack.push({})
+              nsdecl.each do |n,v|
+                @namespace_stack[-1][n] = v
+                # notify observers of namespaces
+                procs.each { |ob| ob.call( n, v ) } if procs
+                listeners.each { |ob| ob.start_prefix_mapping(n, v) } if listeners
+              end
+            end
+            event[1] =~ Namespace::NAMESPLIT
+            prefix = $1
+            local = $2
+            uri = get_namespace(prefix)
+            # find the observers for start_element
+            procs = get_procs( :start_element, event[1] )
+            listeners = get_listeners( :start_element, event[1] )
+            # notify observers
+            procs.each { |ob| ob.call( uri, local, event[1], event[2] ) } if procs
+            listeners.each { |ob| 
+              ob.start_element( uri, local, event[1], event[2] ) 
+            } if listeners
+          when :end_element
+            @tag_stack.pop
+            event[1] =~ Namespace::NAMESPLIT
+            prefix = $1
+            local = $2
+            uri = get_namespace(prefix)
+            # find the observers for start_element
+            procs = get_procs( :end_element, event[1] )
+            listeners = get_listeners( :end_element, event[1] )
+            # notify observers
+            procs.each { |ob| ob.call( uri, local, event[1] ) } if procs
+            listeners.each { |ob| 
+              ob.end_element( uri, local, event[1] ) 
+            } if listeners
 
-						namespace_mapping = @namespace_stack.pop
-						# find the observers for namespaces
-						procs = get_procs( :end_prefix_mapping, event[1] )
-						listeners = get_listeners( :end_prefix_mapping, event[1] )
-						if procs or listeners
-							namespace_mapping.each do |ns_prefix, ns_uri|
-								# notify observers of namespaces
-								procs.each { |ob| ob.call( ns_prefix ) } if procs
-								listeners.each { |ob| ob.end_prefix_mapping(ns_prefix) } if listeners
-							end
-						end
-					when :text
+            namespace_mapping = @namespace_stack.pop
+            # find the observers for namespaces
+            procs = get_procs( :end_prefix_mapping, event[1] )
+            listeners = get_listeners( :end_prefix_mapping, event[1] )
+            if procs or listeners
+              namespace_mapping.each do |ns_prefix, ns_uri|
+                # notify observers of namespaces
+                procs.each { |ob| ob.call( ns_prefix ) } if procs
+                listeners.each { |ob| ob.end_prefix_mapping(ns_prefix) } if listeners
+              end
+            end
+          when :text
             #normalized = @parser.normalize( event[1] )
             #handle( :characters, normalized )
             copy = event[1].clone
@@ -177,71 +177,71 @@
             handle( :characters, copy )
           when :entitydecl
             @entities[ event[1] ] = event[2] if event.size == 3
-						handle( *event )
-					when :processing_instruction, :comment, :attlistdecl, 
-						:elementdecl, :cdata, :notationdecl, :xmldecl
-						handle( *event )
-					end
+            handle( *event )
+          when :processing_instruction, :comment, :attlistdecl, 
+            :elementdecl, :cdata, :notationdecl, :xmldecl
+            handle( *event )
+          end
           handle( :progress, @parser.position )
-				end
-			end
+        end
+      end
 
-			private
-			def handle( symbol, *arguments )
-				tag = @tag_stack[-1]
-				procs = get_procs( symbol, tag )
-				listeners = get_listeners( symbol, tag )
-				# notify observers
-				procs.each { |ob| ob.call( *arguments ) } if procs
-				listeners.each { |l| 
-					l.send( symbol.to_s, *arguments ) 
-				} if listeners
-			end
+      private
+      def handle( symbol, *arguments )
+        tag = @tag_stack[-1]
+        procs = get_procs( symbol, tag )
+        listeners = get_listeners( symbol, tag )
+        # notify observers
+        procs.each { |ob| ob.call( *arguments ) } if procs
+        listeners.each { |l| 
+          l.send( symbol.to_s, *arguments ) 
+        } if listeners
+      end
 
-			# The following methods are duplicates, but it is faster than using
-			# a helper
-			def get_procs( symbol, name )
-				return nil if @procs.size == 0
-				@procs.find_all do |sym, match, block|
+      # The following methods are duplicates, but it is faster than using
+      # a helper
+      def get_procs( symbol, name )
+        return nil if @procs.size == 0
+        @procs.find_all do |sym, match, block|
           #puts sym.inspect+"=="+symbol.inspect+ "\t"+match.inspect+"=="+name.inspect+ "\t"+( (sym.nil? or symbol == sym) and ((name.nil? and match.nil?) or match.nil? or ( (name == match) or (match.kind_of? Regexp and name =~ match)))).to_s
-					(
-						(sym.nil? or symbol == sym) and 
-						((name.nil? and match.nil?) or match.nil? or (
-							(name == match) or
-							(match.kind_of? Regexp and name =~ match)
-							)
-						)
-					)
-				end.collect{|x| x[-1]}
-			end
-			def get_listeners( symbol, name )
-				return nil if @listeners.size == 0
-				@listeners.find_all do |sym, match, block|
-					(
-						(sym.nil? or symbol == sym) and 
-						((name.nil? and match.nil?) or match.nil? or (
-							(name == match) or
-							(match.kind_of? Regexp and name =~ match)
-							)
-						)
-					)
-				end.collect{|x| x[-1]}
-			end
+          (
+            (sym.nil? or symbol == sym) and 
+            ((name.nil? and match.nil?) or match.nil? or (
+              (name == match) or
+              (match.kind_of? Regexp and name =~ match)
+              )
+            )
+          )
+        end.collect{|x| x[-1]}
+      end
+      def get_listeners( symbol, name )
+        return nil if @listeners.size == 0
+        @listeners.find_all do |sym, match, block|
+          (
+            (sym.nil? or symbol == sym) and 
+            ((name.nil? and match.nil?) or match.nil? or (
+              (name == match) or
+              (match.kind_of? Regexp and name =~ match)
+              )
+            )
+          )
+        end.collect{|x| x[-1]}
+      end
 
-			def add( pair )
-				if pair[-1].respond_to? :call
-					@procs << pair unless @procs.include? pair
-				else
-					@listeners << pair unless @listeners.include? pair
-					@has_listeners = true
-				end
-			end
+      def add( pair )
+        if pair[-1].respond_to? :call
+          @procs << pair unless @procs.include? pair
+        else
+          @listeners << pair unless @listeners.include? pair
+          @has_listeners = true
+        end
+      end
 
-			def get_namespace( prefix ) 
+      def get_namespace( prefix ) 
         uris = (@namespace_stack.find_all { |ns| not ns[prefix].nil? }) ||
-					(@namespace_stack.find { |ns| not ns[nil].nil? })
-				uris[-1][prefix] unless uris.nil? or 0 == uris.size
-			end
-		end
-	end
+          (@namespace_stack.find { |ns| not ns[nil].nil? })
+        uris[-1][prefix] unless uris.nil? or 0 == uris.size
+      end
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/parsers/ultralightparser.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/parsers/ultralightparser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/parsers/ultralightparser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,12 +2,12 @@
 require 'rexml/parsers/baseparser'
 
 module REXML
-	module Parsers
-		class UltraLightParser
-			def initialize stream
-				@stream = stream
-				@parser = REXML::Parsers::BaseParser.new( stream )
-			end
+  module Parsers
+    class UltraLightParser
+      def initialize stream
+        @stream = stream
+        @parser = REXML::Parsers::BaseParser.new( stream )
+      end
 
       def add_listener( listener )
         @parser.add_listener( listener )
@@ -18,39 +18,39 @@
         @parser.stream = @stream
       end
 
-			def parse
-				root = context = []
-				while true
-					event = @parser.pull
-					case event[0]
-					when :end_document
-						break
-					when :end_doctype
-						context = context[1]
-					when :start_element, :doctype
-						context << event
-						event[1,0] = [context]
-						context = event
-					when :end_element
-						context = context[1]
-					else
-						context << event
-					end
-				end
-				root
-			end
-		end
+      def parse
+        root = context = []
+        while true
+          event = @parser.pull
+          case event[0]
+          when :end_document
+            break
+          when :end_doctype
+            context = context[1]
+          when :start_element, :doctype
+            context << event
+            event[1,0] = [context]
+            context = event
+          when :end_element
+            context = context[1]
+          else
+            context << event
+          end
+        end
+        root
+      end
+    end
 
-		# An element is an array.  The array contains:
-		#  0			The parent element
-		#  1			The tag name
-		#  2			A hash of attributes
-		#  3..-1	The child elements
-		# An element is an array of size > 3
-		# Text is a String
-		# PIs are [ :processing_instruction, target, data ]
-		# Comments are [ :comment, data ]
-		# DocTypes are DocType structs
-		# The root is an array with XMLDecls, Text, DocType, Array, Text
-	end
+    # An element is an array.  The array contains:
+    #  0			The parent element
+    #  1			The tag name
+    #  2			A hash of attributes
+    #  3..-1	The child elements
+    # An element is an array of size > 3
+    # Text is a String
+    # PIs are [ :processing_instruction, target, data ]
+    # Comments are [ :comment, data ]
+    # DocTypes are DocType structs
+    # The root is an array with XMLDecls, Text, DocType, Array, Text
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/parsers/xpathparser.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/parsers/xpathparser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/parsers/xpathparser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -39,10 +39,10 @@
           case op
           when :node
           when :attribute
-						string << "/" if string.size > 0
-						string << "@"
+            string << "/" if string.size > 0
+            string << "@"
           when :child
-						string << "/" if string.size > 0
+            string << "/" if string.size > 0
           when :descendant_or_self
             string << "/"
           when :self
@@ -51,8 +51,8 @@
             string << ".."
           when :any
             string << "*"
-					when :text
-						string << "text()"
+          when :text
+            string << "text()"
           when :following, :following_sibling, 
                 :ancestor, :ancestor_or_self, :descendant, 
                 :namespace, :preceding, :preceding_sibling
@@ -70,13 +70,13 @@
             string << ']'
           when :document
             document = true
-					when :function
-						string << path.shift
-						string << "( "
-						string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
-						string << " )"
-					when :literal
-						string << %Q{ "#{path.shift}" }
+          when :function
+            string << path.shift
+            string << "( "
+            string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
+            string << " )"
+          when :literal
+            string << %Q{ "#{path.shift}" }
           else
             string << "/" unless string.size == 0
             string << "UNKNOWN("
@@ -84,7 +84,7 @@
             string << ")"
           end
         end
-				string = "/"+string if document
+        string = "/"+string if document
         return string
       end
 
@@ -653,39 +653,39 @@
       def parse_args( string )
         arguments = []
         ind = 0
-				inquot = false
-				inapos = false
+        inquot = false
+        inapos = false
         depth = 1
         begin
           case string[ind]
           when ?"
-          	inquot = !inquot unless inapos
+            inquot = !inquot unless inapos
           when ?'
-          	inapos = !inapos unless inquot
+            inapos = !inapos unless inquot
           else
-          	unless inquot or inapos
-          		case string[ind]
-							when ?(
-								depth += 1
+            unless inquot or inapos
+              case string[ind]
+              when ?(
+                depth += 1
                 if depth == 1
-                	string = string[1..-1]
-                	ind -= 1
+                  string = string[1..-1]
+                  ind -= 1
                 end
-							when ?)
-								depth -= 1
-								if depth == 0
-									s = string[0,ind].strip
-									arguments << s unless s == ""
-									string = string[ind+1..-1]
-								end
-							when ?,
-								if depth == 1
-									s = string[0,ind].strip
-									arguments << s unless s == ""
-									string = string[ind+1..-1]
-									ind = -1 
-								end
-							end
+              when ?)
+                depth -= 1
+                if depth == 0
+                  s = string[0,ind].strip
+                  arguments << s unless s == ""
+                  string = string[ind+1..-1]
+                end
+              when ?,
+                if depth == 1
+                  s = string[0,ind].strip
+                  arguments << s unless s == ""
+                  string = string[ind+1..-1]
+                  ind = -1 
+                end
+              end
             end
           end
           ind += 1

Modified: MacRuby/branches/experimental/lib/rexml/quickpath.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/quickpath.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/quickpath.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,262 +2,262 @@
 require 'rexml/xmltokens'
 
 module REXML
-	class QuickPath
-		include Functions
-		include XMLTokens
+  class QuickPath
+    include Functions
+    include XMLTokens
 
-		EMPTY_HASH = {}
+    EMPTY_HASH = {}
 
-		def QuickPath::first element, path, namespaces=EMPTY_HASH
-			match(element, path, namespaces)[0]
-		end
+    def QuickPath::first element, path, namespaces=EMPTY_HASH
+      match(element, path, namespaces)[0]
+    end
 
-		def QuickPath::each element, path, namespaces=EMPTY_HASH, &block
-			path = "*" unless path
-			match(element, path, namespaces).each( &block )
-		end
+    def QuickPath::each element, path, namespaces=EMPTY_HASH, &block
+      path = "*" unless path
+      match(element, path, namespaces).each( &block )
+    end
 
-		def QuickPath::match element, path, namespaces=EMPTY_HASH
-			raise "nil is not a valid xpath" unless path
-			results = nil
-			Functions::namespace_context = namespaces
-			case path
-			when /^\/([^\/]|$)/u
-				# match on root
-				path = path[1..-1]
-				return [element.root.parent] if path == ''
-				results = filter([element.root], path)
-			when /^[-\w]*::/u
-				results = filter([element], path)
-			when /^\*/u
-				results = filter(element.to_a, path)
-			when /^[\[!\w:]/u
-				# match on child
-				matches = []
-				children = element.to_a
-				results = filter(children, path)
-			else
-				results = filter([element], path)
-			end
-			return results
-		end
+    def QuickPath::match element, path, namespaces=EMPTY_HASH
+      raise "nil is not a valid xpath" unless path
+      results = nil
+      Functions::namespace_context = namespaces
+      case path
+      when /^\/([^\/]|$)/u
+        # match on root
+        path = path[1..-1]
+        return [element.root.parent] if path == ''
+        results = filter([element.root], path)
+      when /^[-\w]*::/u
+        results = filter([element], path)
+      when /^\*/u
+        results = filter(element.to_a, path)
+      when /^[\[!\w:]/u
+        # match on child
+        matches = []
+        children = element.to_a
+        results = filter(children, path)
+      else
+        results = filter([element], path)
+      end
+      return results
+    end
 
-		# Given an array of nodes it filters the array based on the path. The
-		# result is that when this method returns, the array will contain elements
-		# which match the path
-		def QuickPath::filter elements, path
-			return elements if path.nil? or path == '' or elements.size == 0
-			case path
-			when /^\/\//u											# Descendant
-				return axe( elements, "descendant-or-self", $' )
-			when /^\/?\b(\w[-\w]*)\b::/u							# Axe
-				axe_name = $1
-				rest = $'
-				return axe( elements, $1, $' )
-			when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u	# Child
-				rest = $'
-				results = []
-				elements.each do |element|
-					results |= filter( element.to_a, rest )
-				end
-				return results
-			when /^\/?(\w[-\w]*)\(/u							# / Function
-				return function( elements, $1, $' )
-			when Namespace::NAMESPLIT		# Element name
-				name = $2
-				ns = $1
-				rest = $'
-				elements.delete_if do |element|
-					!(element.kind_of? Element and 
-						(element.expanded_name == name or
-						 (element.name == name and
-						  element.namespace == Functions.namespace_context[ns])))
-				end
-				return filter( elements, rest )
-			when /^\/\[/u
-				matches = []
-				elements.each do |element|
-					matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
-				end
-				return matches
-			when /^\[/u												# Predicate
-				return predicate( elements, path )
-			when /^\/?\.\.\./u										# Ancestor
-				return axe( elements, "ancestor", $' )
-			when /^\/?\.\./u											# Parent
-				return filter( elements.collect{|e|e.parent}, $' )
-			when /^\/?\./u												# Self
-				return filter( elements, $' )
-			when /^\*/u													# Any
-				results = []
-				elements.each do |element|
-					results |= filter( [element], $' ) if element.kind_of? Element
-					#if element.kind_of? Element
-					#	children = element.to_a
-					#	children.delete_if { |child| !child.kind_of?(Element) }
-					#	results |= filter( children, $' )
-					#end
-				end
-				return results
-			end
-			return []
-		end
+    # Given an array of nodes it filters the array based on the path. The
+    # result is that when this method returns, the array will contain elements
+    # which match the path
+    def QuickPath::filter elements, path
+      return elements if path.nil? or path == '' or elements.size == 0
+      case path
+      when /^\/\//u											# Descendant
+        return axe( elements, "descendant-or-self", $' )
+      when /^\/?\b(\w[-\w]*)\b::/u							# Axe
+        axe_name = $1
+        rest = $'
+        return axe( elements, $1, $' )
+      when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u	# Child
+        rest = $'
+        results = []
+        elements.each do |element|
+          results |= filter( element.to_a, rest )
+        end
+        return results
+      when /^\/?(\w[-\w]*)\(/u							# / Function
+        return function( elements, $1, $' )
+      when Namespace::NAMESPLIT		# Element name
+        name = $2
+        ns = $1
+        rest = $'
+        elements.delete_if do |element|
+          !(element.kind_of? Element and 
+            (element.expanded_name == name or
+             (element.name == name and
+              element.namespace == Functions.namespace_context[ns])))
+        end
+        return filter( elements, rest )
+      when /^\/\[/u
+        matches = []
+        elements.each do |element|
+          matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
+        end
+        return matches
+      when /^\[/u												# Predicate
+        return predicate( elements, path )
+      when /^\/?\.\.\./u										# Ancestor
+        return axe( elements, "ancestor", $' )
+      when /^\/?\.\./u											# Parent
+        return filter( elements.collect{|e|e.parent}, $' )
+      when /^\/?\./u												# Self
+        return filter( elements, $' )
+      when /^\*/u													# Any
+        results = []
+        elements.each do |element|
+          results |= filter( [element], $' ) if element.kind_of? Element
+          #if element.kind_of? Element
+          #	children = element.to_a
+          #	children.delete_if { |child| !child.kind_of?(Element) }
+          #	results |= filter( children, $' )
+          #end
+        end
+        return results
+      end
+      return []
+    end
 
-		def QuickPath::axe( elements, axe_name, rest )
-			matches = []
-			matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u
-			case axe_name
-			when /^descendant/u
-				elements.each do |element|
-					matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element
-				end
-			when /^ancestor/u
-				elements.each do |element|
-					while element.parent
-						matches << element.parent
-						element = element.parent
-					end
-				end
-				matches = filter( matches, rest )
-			when "self"
-				matches = filter( elements, rest )
-			when "child"
-				elements.each do |element|
-					matches |= filter( element.to_a, rest ) if element.kind_of? Element
-				end
-			when "attribute"
-				elements.each do |element|
-					matches << element.attributes[ rest ] if element.kind_of? Element
-				end
-			when "parent"
-				matches = filter(elements.collect{|element| element.parent}.uniq, rest)
-			when "following-sibling"
-				matches = filter(elements.collect{|element| element.next_sibling}.uniq,
-					rest)
-			when "previous-sibling"
-				matches = filter(elements.collect{|element| 
-					element.previous_sibling}.uniq, rest )
-			end
-			return matches.uniq
-		end
+    def QuickPath::axe( elements, axe_name, rest )
+      matches = []
+      matches = filter( elements.dup, rest ) if axe_name =~ /-or-self$/u
+      case axe_name
+      when /^descendant/u
+        elements.each do |element|
+          matches |= filter( element.to_a, "descendant-or-self::#{rest}" ) if element.kind_of? Element
+        end
+      when /^ancestor/u
+        elements.each do |element|
+          while element.parent
+            matches << element.parent
+            element = element.parent
+          end
+        end
+        matches = filter( matches, rest )
+      when "self"
+        matches = filter( elements, rest )
+      when "child"
+        elements.each do |element|
+          matches |= filter( element.to_a, rest ) if element.kind_of? Element
+        end
+      when "attribute"
+        elements.each do |element|
+          matches << element.attributes[ rest ] if element.kind_of? Element
+        end
+      when "parent"
+        matches = filter(elements.collect{|element| element.parent}.uniq, rest)
+      when "following-sibling"
+        matches = filter(elements.collect{|element| element.next_sibling}.uniq,
+          rest)
+      when "previous-sibling"
+        matches = filter(elements.collect{|element| 
+          element.previous_sibling}.uniq, rest )
+      end
+      return matches.uniq
+    end
 
-		# A predicate filters a node-set with respect to an axis to produce a
-		# new node-set. For each node in the node-set to be filtered, the 
-		# PredicateExpr is evaluated with that node as the context node, with 
-		# the number of nodes in the node-set as the context size, and with the 
-		# proximity position of the node in the node-set with respect to the
-		# axis as the context position; if PredicateExpr evaluates to true for
-		# that node, the node is included in the new node-set; otherwise, it is
-		# not included.
-		#
-		# A PredicateExpr is evaluated by evaluating the Expr and converting
-		# the result to a boolean. If the result is a number, the result will
-		# be converted to true if the number is equal to the context position
-		# and will be converted to false otherwise; if the result is not a
-		# number, then the result will be converted as if by a call to the
-		# boolean function. Thus a location path para[3] is equivalent to
-		# para[position()=3].
-		def QuickPath::predicate( elements, path ) 
-			ind = 1
-			bcount = 1
-			while bcount > 0
-				bcount += 1 if path[ind] == ?[
-				bcount -= 1 if path[ind] == ?]
-				ind += 1
-			end
-			ind -= 1
-			predicate = path[1..ind-1]
-			rest = path[ind+1..-1]
+    # A predicate filters a node-set with respect to an axis to produce a
+    # new node-set. For each node in the node-set to be filtered, the 
+    # PredicateExpr is evaluated with that node as the context node, with 
+    # the number of nodes in the node-set as the context size, and with the 
+    # proximity position of the node in the node-set with respect to the
+    # axis as the context position; if PredicateExpr evaluates to true for
+    # that node, the node is included in the new node-set; otherwise, it is
+    # not included.
+    #
+    # A PredicateExpr is evaluated by evaluating the Expr and converting
+    # the result to a boolean. If the result is a number, the result will
+    # be converted to true if the number is equal to the context position
+    # and will be converted to false otherwise; if the result is not a
+    # number, then the result will be converted as if by a call to the
+    # boolean function. Thus a location path para[3] is equivalent to
+    # para[position()=3].
+    def QuickPath::predicate( elements, path ) 
+      ind = 1
+      bcount = 1
+      while bcount > 0
+        bcount += 1 if path[ind] == ?[
+        bcount -= 1 if path[ind] == ?]
+        ind += 1
+      end
+      ind -= 1
+      predicate = path[1..ind-1]
+      rest = path[ind+1..-1]
 
-			# have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
-			predicate.gsub!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u,
-				'\1 \2 \3 and \3 \4 \5' )
-			# Let's do some Ruby trickery to avoid some work:
-			predicate.gsub!( /&/u, "&&" )
-			predicate.gsub!( /=/u, "==" )
-			predicate.gsub!( /@(\w[-\w.]*)/u, 'attribute("\1")' ) 
-			predicate.gsub!( /\bmod\b/u, "%" )
-			predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
-				fname = $1
-				fname.gsub( /-/u, "_" )
-			}
-			
-			Functions.pair = [ 0, elements.size ]
-			results = []
-			elements.each do |element|
-				Functions.pair[0] += 1
-				Functions.node = element
-				res = eval( predicate )
-				case res
-				when true
-					results << element
-				when Fixnum
-					results << element if Functions.pair[0] == res
-				when String
-					results << element
-				end
-			end
-			return filter( results, rest )
-		end
+      # have to change 'a [=<>] b [=<>] c' into 'a [=<>] b and b [=<>] c'
+      predicate.gsub!( /([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)\s*([<>=])\s*([^\s(and)(or)<>=]+)/u,
+        '\1 \2 \3 and \3 \4 \5' )
+      # Let's do some Ruby trickery to avoid some work:
+      predicate.gsub!( /&/u, "&&" )
+      predicate.gsub!( /=/u, "==" )
+      predicate.gsub!( /@(\w[-\w.]*)/u, 'attribute("\1")' ) 
+      predicate.gsub!( /\bmod\b/u, "%" )
+      predicate.gsub!( /\b(\w[-\w.]*\()/u ) {
+        fname = $1
+        fname.gsub( /-/u, "_" )
+      }
+      
+      Functions.pair = [ 0, elements.size ]
+      results = []
+      elements.each do |element|
+        Functions.pair[0] += 1
+        Functions.node = element
+        res = eval( predicate )
+        case res
+        when true
+          results << element
+        when Fixnum
+          results << element if Functions.pair[0] == res
+        when String
+          results << element
+        end
+      end
+      return filter( results, rest )
+    end
 
-		def QuickPath::attribute( name )
-			return Functions.node.attributes[name] if Functions.node.kind_of? Element
-		end
+    def QuickPath::attribute( name )
+      return Functions.node.attributes[name] if Functions.node.kind_of? Element
+    end
 
-		def QuickPath::name()
-			return Functions.node.name if Functions.node.kind_of? Element
-		end
+    def QuickPath::name()
+      return Functions.node.name if Functions.node.kind_of? Element
+    end
 
-		def QuickPath::method_missing( id, *args )
-			begin
-				Functions.send( id.id2name, *args )
-			rescue Exception
-				raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}"
-			end
-		end
+    def QuickPath::method_missing( id, *args )
+      begin
+        Functions.send( id.id2name, *args )
+      rescue Exception
+        raise "METHOD: #{id.id2name}(#{args.join ', '})\n#{$!.message}"
+      end
+    end
 
-		def QuickPath::function( elements, fname, rest )
-			args = parse_args( elements, rest )
-			Functions.pair = [0, elements.size]
-			results = []
-			elements.each do |element|
-				Functions.pair[0] += 1
-				Functions.node = element
-				res = Functions.send( fname, *args )
-				case res
-				when true
-					results << element
-				when Fixnum
-					results << element if Functions.pair[0] == res
-				end
-			end
-			return results
-		end
+    def QuickPath::function( elements, fname, rest )
+      args = parse_args( elements, rest )
+      Functions.pair = [0, elements.size]
+      results = []
+      elements.each do |element|
+        Functions.pair[0] += 1
+        Functions.node = element
+        res = Functions.send( fname, *args )
+        case res
+        when true
+          results << element
+        when Fixnum
+          results << element if Functions.pair[0] == res
+        end
+      end
+      return results
+    end
 
-		def QuickPath::parse_args( element, string )
-			# /.*?(?:\)|,)/
-			arguments = []
-			buffer = ""
-			while string and string != ""
-				c = string[0]
-				string.sub!(/^./u, "")
-				case c
-				when ?,
-					# if depth = 1, then we start a new argument
-					arguments << evaluate( buffer )
-					#arguments << evaluate( string[0..count] )
-				when ?(
-					# start a new method call
-					function( element, buffer, string )
-					buffer = ""
-				when ?)
-					# close the method call and return arguments
-					return arguments
-				else
-					buffer << c
-				end
-			end
-			""
-		end
-	end
+    def QuickPath::parse_args( element, string )
+      # /.*?(?:\)|,)/
+      arguments = []
+      buffer = ""
+      while string and string != ""
+        c = string[0]
+        string.sub!(/^./u, "")
+        case c
+        when ?,
+          # if depth = 1, then we start a new argument
+          arguments << evaluate( buffer )
+          #arguments << evaluate( string[0..count] )
+        when ?(
+          # start a new method call
+          function( element, buffer, string )
+          buffer = ""
+        when ?)
+          # close the method call and return arguments
+          return arguments
+        else
+          buffer << c
+        end
+      end
+      ""
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/sax2listener.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/sax2listener.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/sax2listener.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,97 +1,97 @@
 module REXML
-	# A template for stream parser listeners.
-	# Note that the declarations (attlistdecl, elementdecl, etc) are trivially
-	# processed; REXML doesn't yet handle doctype entity declarations, so you 
-	# have to parse them out yourself.
-	# === Missing methods from SAX2
-	#  ignorable_whitespace
-	# === Methods extending SAX2 
-	# +WARNING+
-	# These methods are certainly going to change, until DTDs are fully
-	# supported.  Be aware of this.
-	#  start_document
-	#  end_document
-	#  doctype
-	#  elementdecl
-	#  attlistdecl
-	#  entitydecl
-	#  notationdecl
-	#  cdata
-	#  xmldecl
-	#  comment
-	module SAX2Listener
-		def start_document
-		end
-		def end_document
-		end
-		def start_prefix_mapping prefix, uri
-		end
-		def end_prefix_mapping prefix
-		end
-		def start_element uri, localname, qname, attributes
-		end
-		def end_element uri, localname, qname
-		end
-		def characters text
-		end
-		def processing_instruction target, data
-		end
-		# Handles a doctype declaration. Any attributes of the doctype which are
-		# not supplied will be nil.  # EG, <!DOCTYPE me PUBLIC "foo" "bar">
-		# @p name the name of the doctype; EG, "me"
-		# @p pub_sys "PUBLIC", "SYSTEM", or nil.  EG, "PUBLIC"
-		# @p long_name the supplied long name, or nil.  EG, "foo"
-		# @p uri the uri of the doctype, or nil.  EG, "bar"
-		def doctype name, pub_sys, long_name, uri
-		end
-		# If a doctype includes an ATTLIST declaration, it will cause this
-		# method to be called.  The content is the declaration itself, unparsed.
-		# EG, <!ATTLIST el attr CDATA #REQUIRED> will come to this method as "el
-		# attr CDATA #REQUIRED".  This is the same for all of the .*decl
-		# methods.
-		def attlistdecl(element, pairs, contents)
-		end
-		# <!ELEMENT ...>
-		def elementdecl content
-		end
-		# <!ENTITY ...>
-		# The argument passed to this method is an array of the entity
-		# declaration.  It can be in a number of formats, but in general it
-		# returns (example, result):
-		#  <!ENTITY % YN '"Yes"'>  
-		#  ["%", "YN", "'\"Yes\"'", "\""]
-		#  <!ENTITY % YN 'Yes'>
-		#  ["%", "YN", "'Yes'", "s"]
-		#  <!ENTITY WhatHeSaid "He said %YN;">
-		#  ["WhatHeSaid", "\"He said %YN;\"", "YN"]
-		#  <!ENTITY open-hatch SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
-		#  ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
-		#  <!ENTITY open-hatch PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" "http://www.textuality.com/boilerplate/OpenHatch.xml">
-		#  ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
-		#  <!ENTITY hatch-pic SYSTEM "../grafix/OpenHatch.gif" NDATA gif>
-		#  ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"]
-		def entitydecl name, decl
-		end
-		# <!NOTATION ...>
-		def notationdecl content
-		end
-		# Called when <![CDATA[ ... ]]> is encountered in a document.
-		# @p content "..."
-		def cdata content
-		end
-		# Called when an XML PI is encountered in the document.
-		# EG: <?xml version="1.0" encoding="utf"?>
-		# @p version the version attribute value.  EG, "1.0"
-		# @p encoding the encoding attribute value, or nil.  EG, "utf"
-		# @p standalone the standalone attribute value, or nil.  EG, nil
+  # A template for stream parser listeners.
+  # Note that the declarations (attlistdecl, elementdecl, etc) are trivially
+  # processed; REXML doesn't yet handle doctype entity declarations, so you 
+  # have to parse them out yourself.
+  # === Missing methods from SAX2
+  #  ignorable_whitespace
+  # === Methods extending SAX2 
+  # +WARNING+
+  # These methods are certainly going to change, until DTDs are fully
+  # supported.  Be aware of this.
+  #  start_document
+  #  end_document
+  #  doctype
+  #  elementdecl
+  #  attlistdecl
+  #  entitydecl
+  #  notationdecl
+  #  cdata
+  #  xmldecl
+  #  comment
+  module SAX2Listener
+    def start_document
+    end
+    def end_document
+    end
+    def start_prefix_mapping prefix, uri
+    end
+    def end_prefix_mapping prefix
+    end
+    def start_element uri, localname, qname, attributes
+    end
+    def end_element uri, localname, qname
+    end
+    def characters text
+    end
+    def processing_instruction target, data
+    end
+    # Handles a doctype declaration. Any attributes of the doctype which are
+    # not supplied will be nil.  # EG, <!DOCTYPE me PUBLIC "foo" "bar">
+    # @p name the name of the doctype; EG, "me"
+    # @p pub_sys "PUBLIC", "SYSTEM", or nil.  EG, "PUBLIC"
+    # @p long_name the supplied long name, or nil.  EG, "foo"
+    # @p uri the uri of the doctype, or nil.  EG, "bar"
+    def doctype name, pub_sys, long_name, uri
+    end
+    # If a doctype includes an ATTLIST declaration, it will cause this
+    # method to be called.  The content is the declaration itself, unparsed.
+    # EG, <!ATTLIST el attr CDATA #REQUIRED> will come to this method as "el
+    # attr CDATA #REQUIRED".  This is the same for all of the .*decl
+    # methods.
+    def attlistdecl(element, pairs, contents)
+    end
+    # <!ELEMENT ...>
+    def elementdecl content
+    end
+    # <!ENTITY ...>
+    # The argument passed to this method is an array of the entity
+    # declaration.  It can be in a number of formats, but in general it
+    # returns (example, result):
+    #  <!ENTITY % YN '"Yes"'>  
+    #  ["%", "YN", "'\"Yes\"'", "\""]
+    #  <!ENTITY % YN 'Yes'>
+    #  ["%", "YN", "'Yes'", "s"]
+    #  <!ENTITY WhatHeSaid "He said %YN;">
+    #  ["WhatHeSaid", "\"He said %YN;\"", "YN"]
+    #  <!ENTITY open-hatch SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
+    #  ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
+    #  <!ENTITY open-hatch PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" "http://www.textuality.com/boilerplate/OpenHatch.xml">
+    #  ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
+    #  <!ENTITY hatch-pic SYSTEM "../grafix/OpenHatch.gif" NDATA gif>
+    #  ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"]
+    def entitydecl name, decl
+    end
+    # <!NOTATION ...>
+    def notationdecl content
+    end
+    # Called when <![CDATA[ ... ]]> is encountered in a document.
+    # @p content "..."
+    def cdata content
+    end
+    # Called when an XML PI is encountered in the document.
+    # EG: <?xml version="1.0" encoding="utf"?>
+    # @p version the version attribute value.  EG, "1.0"
+    # @p encoding the encoding attribute value, or nil.  EG, "utf"
+    # @p standalone the standalone attribute value, or nil.  EG, nil
     # @p spaced the declaration is followed by a line break
-		def xmldecl version, encoding, standalone
-		end
-		# Called when a comment is encountered.
-		# @p comment The content of the comment
-		def comment comment
-		end
+    def xmldecl version, encoding, standalone
+    end
+    # Called when a comment is encountered.
+    # @p comment The content of the comment
+    def comment comment
+    end
     def progress position
     end
-	end	
+  end	
 end

Modified: MacRuby/branches/experimental/lib/rexml/streamlistener.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/streamlistener.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/streamlistener.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,92 +1,92 @@
 module REXML
-	# A template for stream parser listeners.
-	# Note that the declarations (attlistdecl, elementdecl, etc) are trivially
-	# processed; REXML doesn't yet handle doctype entity declarations, so you 
-	# have to parse them out yourself.
-	module StreamListener
-		# Called when a tag is encountered.
-		# @p name the tag name
-		# @p attrs an array of arrays of attribute/value pairs, suitable for
-		# use with assoc or rassoc.  IE, <tag attr1="value1" attr2="value2">
-		# will result in 
-		# tag_start( "tag", # [["attr1","value1"],["attr2","value2"]])
-		def tag_start name, attrs
-		end
-		# Called when the end tag is reached.  In the case of <tag/>, tag_end
-		# will be called immidiately after tag_start
-		# @p the name of the tag
-		def tag_end name
-		end
-		# Called when text is encountered in the document
-		# @p text the text content.
-		def text text
-		end
-		# Called when an instruction is encountered.  EG: <?xsl sheet='foo'?>
-		# @p name the instruction name; in the example, "xsl"
-		# @p instruction the rest of the instruction.  In the example,
-		# "sheet='foo'"
-		def instruction name, instruction
-		end
-		# Called when a comment is encountered.
-		# @p comment The content of the comment
-		def comment comment
-		end
-		# Handles a doctype declaration. Any attributes of the doctype which are
-		# not supplied will be nil.  # EG, <!DOCTYPE me PUBLIC "foo" "bar">
-		# @p name the name of the doctype; EG, "me"
-		# @p pub_sys "PUBLIC", "SYSTEM", or nil.  EG, "PUBLIC"
-		# @p long_name the supplied long name, or nil.  EG, "foo"
-		# @p uri the uri of the doctype, or nil.  EG, "bar"
-		def doctype name, pub_sys, long_name, uri
-		end
-		# Called when the doctype is done
-		def doctype_end
-		end
-		# If a doctype includes an ATTLIST declaration, it will cause this
-		# method to be called.  The content is the declaration itself, unparsed.
-		# EG, <!ATTLIST el attr CDATA #REQUIRED> will come to this method as "el
-		# attr CDATA #REQUIRED".  This is the same for all of the .*decl
-		# methods.
-		def attlistdecl element_name, attributes, raw_content
-		end
-		# <!ELEMENT ...>
-		def elementdecl content
-		end
-		# <!ENTITY ...>
-		# The argument passed to this method is an array of the entity
-		# declaration.  It can be in a number of formats, but in general it
-		# returns (example, result):
-		#  <!ENTITY % YN '"Yes"'>  
-		#  ["%", "YN", "'\"Yes\"'", "\""]
-		#  <!ENTITY % YN 'Yes'>
-		#  ["%", "YN", "'Yes'", "s"]
-		#  <!ENTITY WhatHeSaid "He said %YN;">
-		#  ["WhatHeSaid", "\"He said %YN;\"", "YN"]
-		#  <!ENTITY open-hatch SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
-		#  ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
-		#  <!ENTITY open-hatch PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" "http://www.textuality.com/boilerplate/OpenHatch.xml">
-		#  ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
-		#  <!ENTITY hatch-pic SYSTEM "../grafix/OpenHatch.gif" NDATA gif>
-		#  ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"]
-		def entitydecl content
-		end
-		# <!NOTATION ...>
-		def notationdecl content
-		end
-		# Called when %foo; is encountered in a doctype declaration.
-		# @p content "foo"
-		def entity content
-		end
-		# Called when <![CDATA[ ... ]]> is encountered in a document.
-		# @p content "..."
-		def cdata content
-		end
-		# Called when an XML PI is encountered in the document.
-		# EG: <?xml version="1.0" encoding="utf"?>
-		# @p version the version attribute value.  EG, "1.0"
-		# @p encoding the encoding attribute value, or nil.  EG, "utf"
-		# @p standalone the standalone attribute value, or nil.  EG, nil
-		def xmldecl version, encoding, standalone
-		end
-	end
+  # A template for stream parser listeners.
+  # Note that the declarations (attlistdecl, elementdecl, etc) are trivially
+  # processed; REXML doesn't yet handle doctype entity declarations, so you 
+  # have to parse them out yourself.
+  module StreamListener
+    # Called when a tag is encountered.
+    # @p name the tag name
+    # @p attrs an array of arrays of attribute/value pairs, suitable for
+    # use with assoc or rassoc.  IE, <tag attr1="value1" attr2="value2">
+    # will result in 
+    # tag_start( "tag", # [["attr1","value1"],["attr2","value2"]])
+    def tag_start name, attrs
+    end
+    # Called when the end tag is reached.  In the case of <tag/>, tag_end
+    # will be called immidiately after tag_start
+    # @p the name of the tag
+    def tag_end name
+    end
+    # Called when text is encountered in the document
+    # @p text the text content.
+    def text text
+    end
+    # Called when an instruction is encountered.  EG: <?xsl sheet='foo'?>
+    # @p name the instruction name; in the example, "xsl"
+    # @p instruction the rest of the instruction.  In the example,
+    # "sheet='foo'"
+    def instruction name, instruction
+    end
+    # Called when a comment is encountered.
+    # @p comment The content of the comment
+    def comment comment
+    end
+    # Handles a doctype declaration. Any attributes of the doctype which are
+    # not supplied will be nil.  # EG, <!DOCTYPE me PUBLIC "foo" "bar">
+    # @p name the name of the doctype; EG, "me"
+    # @p pub_sys "PUBLIC", "SYSTEM", or nil.  EG, "PUBLIC"
+    # @p long_name the supplied long name, or nil.  EG, "foo"
+    # @p uri the uri of the doctype, or nil.  EG, "bar"
+    def doctype name, pub_sys, long_name, uri
+    end
+    # Called when the doctype is done
+    def doctype_end
+    end
+    # If a doctype includes an ATTLIST declaration, it will cause this
+    # method to be called.  The content is the declaration itself, unparsed.
+    # EG, <!ATTLIST el attr CDATA #REQUIRED> will come to this method as "el
+    # attr CDATA #REQUIRED".  This is the same for all of the .*decl
+    # methods.
+    def attlistdecl element_name, attributes, raw_content
+    end
+    # <!ELEMENT ...>
+    def elementdecl content
+    end
+    # <!ENTITY ...>
+    # The argument passed to this method is an array of the entity
+    # declaration.  It can be in a number of formats, but in general it
+    # returns (example, result):
+    #  <!ENTITY % YN '"Yes"'>  
+    #  ["%", "YN", "'\"Yes\"'", "\""]
+    #  <!ENTITY % YN 'Yes'>
+    #  ["%", "YN", "'Yes'", "s"]
+    #  <!ENTITY WhatHeSaid "He said %YN;">
+    #  ["WhatHeSaid", "\"He said %YN;\"", "YN"]
+    #  <!ENTITY open-hatch SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
+    #  ["open-hatch", "SYSTEM", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
+    #  <!ENTITY open-hatch PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" "http://www.textuality.com/boilerplate/OpenHatch.xml">
+    #  ["open-hatch", "PUBLIC", "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\"", "\"http://www.textuality.com/boilerplate/OpenHatch.xml\""]
+    #  <!ENTITY hatch-pic SYSTEM "../grafix/OpenHatch.gif" NDATA gif>
+    #  ["hatch-pic", "SYSTEM", "\"../grafix/OpenHatch.gif\"", "\n\t\t\t\t\t\t\tNDATA gif", "gif"]
+    def entitydecl content
+    end
+    # <!NOTATION ...>
+    def notationdecl content
+    end
+    # Called when %foo; is encountered in a doctype declaration.
+    # @p content "foo"
+    def entity content
+    end
+    # Called when <![CDATA[ ... ]]> is encountered in a document.
+    # @p content "..."
+    def cdata content
+    end
+    # Called when an XML PI is encountered in the document.
+    # EG: <?xml version="1.0" encoding="utf"?>
+    # @p version the version attribute value.  EG, "1.0"
+    # @p encoding the encoding attribute value, or nil.  EG, "utf"
+    # @p standalone the standalone attribute value, or nil.  EG, nil
+    def xmldecl version, encoding, standalone
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/text.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/text.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/text.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -150,7 +150,7 @@
       end
 
       # context sensitive
-      string.scan(pattern).each do
+      string.scan(pattern) do
         if $1[-1] != ?;
           raise "Illegal character '#{$1}' in raw string \"#{string}\""
         elsif $1[0] == ?&
@@ -261,7 +261,7 @@
     end
  
      def wrap(string, width, addnewline=false)
-       # Recursivly wrap string at width.
+       # Recursively wrap string at width.
        return string if string.length <= width
        place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
        if addnewline then

Modified: MacRuby/branches/experimental/lib/rexml/validation/relaxng.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/validation/relaxng.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/validation/relaxng.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -436,7 +436,7 @@
 
             arry[-1][-1].event_arg = evt[1]
             @value = false
-          end
+         end
         else
           arry << [] if evt[0] == :start_element
           arry[-1] << generate_event( evt )

Modified: MacRuby/branches/experimental/lib/rexml/xmldecl.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/xmldecl.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/xmldecl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,40 +2,40 @@
 require 'rexml/source'
 
 module REXML
-	# NEEDS DOCUMENTATION
-	class XMLDecl < Child
-		include Encoding
+  # NEEDS DOCUMENTATION
+  class XMLDecl < Child
+    include Encoding
 
-		DEFAULT_VERSION = "1.0";
-		DEFAULT_ENCODING = "UTF-8";
-		DEFAULT_STANDALONE = "no";
-		START = '<\?xml';
-		STOP = '\?>';
+    DEFAULT_VERSION = "1.0";
+    DEFAULT_ENCODING = "UTF-8";
+    DEFAULT_STANDALONE = "no";
+    START = '<\?xml';
+    STOP = '\?>';
 
-		attr_accessor :version, :standalone
+    attr_accessor :version, :standalone
     attr_reader :writeencoding, :writethis
 
-		def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil)
+    def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil)
       @writethis = true
       @writeencoding = !encoding.nil?
-			if version.kind_of? XMLDecl
-				super()
-				@version = version.version
-				self.encoding = version.encoding
+      if version.kind_of? XMLDecl
+        super()
+        @version = version.version
+        self.encoding = version.encoding
         @writeencoding = version.writeencoding
-				@standalone = version.standalone
-			else
-				super()
-				@version = version
-				self.encoding = encoding
-				@standalone = standalone
-			end
-			@version = DEFAULT_VERSION if @version.nil?
-		end
+        @standalone = version.standalone
+      else
+        super()
+        @version = version
+        self.encoding = encoding
+        @standalone = standalone
+      end
+      @version = DEFAULT_VERSION if @version.nil?
+    end
 
-		def clone
-			XMLDecl.new(self)
-		end
+    def clone
+      XMLDecl.new(self)
+    end
 
     # indent::
     #   Ignored.  There must be no whitespace before an XML declaration
@@ -43,35 +43,35 @@
     #   Ignored
     # ie_hack::
     #   Ignored
-		def write(writer, indent=-1, transitive=false, ie_hack=false)
+    def write(writer, indent=-1, transitive=false, ie_hack=false)
       return nil unless @writethis or writer.kind_of? Output
-			writer << START.sub(/\\/u, '')
+      writer << START.sub(/\\/u, '')
       if writer.kind_of? Output
         writer << " #{content writer.encoding}"
       else
         writer << " #{content encoding}"
       end
-			writer << STOP.sub(/\\/u, '')
-		end
+      writer << STOP.sub(/\\/u, '')
+    end
 
-		def ==( other )
-		  other.kind_of?(XMLDecl) and
-		  other.version == @version and
-		  other.encoding == self.encoding and
-		  other.standalone == @standalone
-		end
+    def ==( other )
+      other.kind_of?(XMLDecl) and
+      other.version == @version and
+      other.encoding == self.encoding and
+      other.standalone == @standalone
+    end
 
-		def xmldecl version, encoding, standalone
-			@version = version
-			self.encoding = encoding
-			@standalone = standalone
-		end
+    def xmldecl version, encoding, standalone
+      @version = version
+      self.encoding = encoding
+      @standalone = standalone
+    end
 
-		def node_type
-			:xmldecl
-		end
+    def node_type
+      :xmldecl
+    end
 
-		alias :stand_alone? :standalone
+    alias :stand_alone? :standalone
     alias :old_enc= :encoding=
 
     def encoding=( enc )
@@ -108,12 +108,12 @@
       START.sub(/\\/u, '') + " ... " + STOP.sub(/\\/u, '')
     end
 
-		private
-		def content(enc)
-			rv = "version='#@version'"
-			rv << " encoding='#{enc}'" if @writeencoding || enc !~ /utf-8/i
-			rv << " standalone='#@standalone'" if @standalone
-			rv
-		end
-	end
+    private
+    def content(enc)
+      rv = "version='#@version'"
+      rv << " encoding='#{enc}'" if @writeencoding || enc !~ /utf-8/i
+      rv << " standalone='#@standalone'" if @standalone
+      rv
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/xmltokens.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/xmltokens.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/xmltokens.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,18 +1,18 @@
 module REXML
-	# Defines a number of tokens used for parsing XML.  Not for general
-	# consumption.
-	module XMLTokens
-		NCNAME_STR= '[\w:][\-\w\d.]*'
-		NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
+  # Defines a number of tokens used for parsing XML.  Not for general
+  # consumption.
+  module XMLTokens
+    NCNAME_STR= '[\w:][\-\w\d.]*'
+    NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
 
-		NAMECHAR = '[\-\w\d\.:]'
-		NAME = "([\\w:]#{NAMECHAR}*)"
-		NMTOKEN = "(?:#{NAMECHAR})+"
-		NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
-		REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)"
+    NAMECHAR = '[\-\w\d\.:]'
+    NAME = "([\\w:]#{NAMECHAR}*)"
+    NMTOKEN = "(?:#{NAMECHAR})+"
+    NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
+    REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)"
 
-		#REFERENCE = "(?:#{ENTITYREF}|#{CHARREF})"
-		#ENTITYREF = "&#{NAME};"
-		#CHARREF = "&#\\d+;|&#x[0-9a-fA-F]+;"
-	end
+    #REFERENCE = "(?:#{ENTITYREF}|#{CHARREF})"
+    #ENTITYREF = "&#{NAME};"
+    #CHARREF = "&#\\d+;|&#x[0-9a-fA-F]+;"
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/xpath.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/xpath.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/xpath.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,65 +2,76 @@
 require 'rexml/xpath_parser'
 
 module REXML
-	# Wrapper class.  Use this class to access the XPath functions.
-	class XPath
-		include Functions
-		EMPTY_HASH = {}
+  # Wrapper class.  Use this class to access the XPath functions.
+  class XPath
+    include Functions
+    EMPTY_HASH = {}
 
-		# Finds and returns the first node that matches the supplied xpath.
-		# element::
-		# 	The context element
-		# path::
-		# 	The xpath to search for.  If not supplied or nil, returns the first
-		# 	node matching '*'.
-		# namespaces::
-		# 	If supplied, a Hash which defines a namespace mapping.
-		#
-		#  XPath.first( node )
-		#  XPath.first( doc, "//b"} )
-		#  XPath.first( node, "a/x:b", { "x"=>"http://doofus" } )
+    # Finds and returns the first node that matches the supplied xpath.
+    # element::
+    # 	The context element
+    # path::
+    # 	The xpath to search for.  If not supplied or nil, returns the first
+    # 	node matching '*'.
+    # namespaces::
+    # 	If supplied, a Hash which defines a namespace mapping.
+    # variables::
+    #   If supplied, a Hash which maps $variables in the query
+    #   to values. This can be used to avoid XPath injection attacks
+    #   or to automatically handle escaping string values.
+    #
+    #  XPath.first( node )
+    #  XPath.first( doc, "//b"} )
+    #  XPath.first( node, "a/x:b", { "x"=>"http://doofus" } )
+    #  XPath.first( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"})
     def XPath::first element, path=nil, namespaces=nil, variables={}
       raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
       raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
-			parser = XPathParser.new
-			parser.namespaces = namespaces
-			parser.variables = variables
-			path = "*" unless path
-			element = [element] unless element.kind_of? Array
-			parser.parse(path, element).flatten[0]
-		end
+      parser = XPathParser.new
+      parser.namespaces = namespaces
+      parser.variables = variables
+      path = "*" unless path
+      element = [element] unless element.kind_of? Array
+      parser.parse(path, element).flatten[0]
+    end
 
-		# Itterates over nodes that match the given path, calling the supplied
-		# block with the match.
-		# element::
-		#   The context element
-		# path::
-		#   The xpath to search for.  If not supplied or nil, defaults to '*'
-		# namespaces::
-		# 	If supplied, a Hash which defines a namespace mapping
-		#
-		#  XPath.each( node ) { |el| ... }
-		#  XPath.each( node, '/*[@attr='v']' ) { |el| ... }
-		#  XPath.each( node, 'ancestor::x' ) { |el| ... }
-		def XPath::each element, path=nil, namespaces=nil, variables={}, &block
+    # Iterates over nodes that match the given path, calling the supplied
+    # block with the match.
+    # element::
+    #   The context element
+    # path::
+    #   The xpath to search for.  If not supplied or nil, defaults to '*'
+    # namespaces::
+    # 	If supplied, a Hash which defines a namespace mapping
+    # variables::
+    #   If supplied, a Hash which maps $variables in the query
+    #   to values. This can be used to avoid XPath injection attacks
+    #   or to automatically handle escaping string values.
+    #
+    #  XPath.each( node ) { |el| ... }
+    #  XPath.each( node, '/*[@attr='v']' ) { |el| ... }
+    #  XPath.each( node, 'ancestor::x' ) { |el| ... }
+    #  XPath.each( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"}) \
+    #    {|el| ... }
+    def XPath::each element, path=nil, namespaces=nil, variables={}, &block
       raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
       raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
-			parser = XPathParser.new
-			parser.namespaces = namespaces
-			parser.variables = variables
-			path = "*" unless path
-			element = [element] unless element.kind_of? Array
-			parser.parse(path, element).each( &block )
-		end
+      parser = XPathParser.new
+      parser.namespaces = namespaces
+      parser.variables = variables
+      path = "*" unless path
+      element = [element] unless element.kind_of? Array
+      parser.parse(path, element).each( &block )
+    end
 
-		# Returns an array of nodes matching a given XPath.  
-		def XPath::match element, path=nil, namespaces=nil, variables={}
-			parser = XPathParser.new
-			parser.namespaces = namespaces
-			parser.variables = variables
-			path = "*" unless path
-			element = [element] unless element.kind_of? Array
-			parser.parse(path,element)
-		end
-	end
+    # Returns an array of nodes matching a given XPath.  
+    def XPath::match element, path=nil, namespaces=nil, variables={}
+      parser = XPathParser.new
+      parser.namespaces = namespaces
+      parser.variables = variables
+      path = "*" unless path
+      element = [element] unless element.kind_of? Array
+      parser.parse(path,element)
+    end
+  end
 end

Modified: MacRuby/branches/experimental/lib/rexml/xpath_parser.rb
===================================================================
--- MacRuby/branches/experimental/lib/rexml/xpath_parser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rexml/xpath_parser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -419,10 +419,10 @@
           return @variables[ var_name ]
 
         # :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq
-				# TODO: Special case for :or and :and -- not evaluate the right
-				# operand if the left alone determines result (i.e. is true for
-				# :or and false for :and).
-        when :eq, :neq, :lt, :lteq, :gt, :gteq, :and, :or
+        # TODO: Special case for :or and :and -- not evaluate the right
+        # operand if the left alone determines result (i.e. is true for
+        # :or and false for :and).
+        when :eq, :neq, :lt, :lteq, :gt, :gteq, :or
           left = expr( path_stack.shift, nodeset.dup, context )
           #puts "LEFT => #{left.inspect} (#{left.class.name})"
           right = expr( path_stack.shift, nodeset.dup, context )
@@ -675,7 +675,7 @@
     def equality_relational_compare( set1, op, set2 )
       #puts "EQ_REL_COMP(#{set1.inspect} #{op.inspect} #{set2.inspect})"
       if set1.kind_of? Array and set2.kind_of? Array
-			  #puts "#{set1.size} & #{set2.size}"
+        #puts "#{set1.size} & #{set2.size}"
         if set1.size == 1 and set2.size == 1
           set1 = set1[0]
           set2 = set2[0]
@@ -696,7 +696,7 @@
           return res
         end
       end
-		  #puts "EQ_REL_COMP: #{set1.inspect} (#{set1.class.name}), #{op}, #{set2.inspect} (#{set2.class.name})"
+      #puts "EQ_REL_COMP: #{set1.inspect} (#{set1.class.name}), #{op}, #{set2.inspect} (#{set2.class.name})"
       #puts "COMPARING VALUES"
       # If one is nodeset and other is number, compare number to each item
       # in nodeset s.t. number op number(string(item))
@@ -705,7 +705,7 @@
       # If one is nodeset and other is boolean, compare boolean to each item
       # in nodeset s.t. boolean op boolean(item)
       if set1.kind_of? Array or set2.kind_of? Array
-			  #puts "ISA ARRAY"
+        #puts "ISA ARRAY"
         if set1.kind_of? Array
           a = set1
           b = set2
@@ -724,7 +724,7 @@
           #puts "B = #{b.inspect}"
           return a.collect {|v| compare( Functions::number(v), op, b )}
         else
-				  #puts "Functions::string( #{b}(#{b.class.name}) ) = #{Functions::string(b)}"
+          #puts "Functions::string( #{b}(#{b.class.name}) ) = #{Functions::string(b)}"
           b = Functions::string( b )
           return a.collect { |v| compare( Functions::string(v), op, b ) }
         end

Modified: MacRuby/branches/experimental/lib/rinda/ring.rb
===================================================================
--- MacRuby/branches/experimental/lib/rinda/ring.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rinda/ring.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -19,7 +19,7 @@
   # 1. A RingServer begins listening on the broadcast UDP address.
   # 2. A RingFinger sends a UDP packet containing the DRb URI where it will
   #    listen for a reply.
-  # 3. The RingServer recieves the UDP packet and connects back to the
+  # 3. The RingServer receives the UDP packet and connects back to the
   #    provided DRb URI with the DRb service.
 
   class RingServer
@@ -119,7 +119,7 @@
     end
 
     ##
-    # Contains all discoverd TupleSpaces except for the primary.
+    # Contains all discovered TupleSpaces except for the primary.
 
     def self.to_a
       finger.to_a
@@ -256,15 +256,15 @@
     $stdin.gets
   when 'w'
     finger = Rinda::RingFinger.new(nil)
-    finger.lookup_ring do |ts|
-      p ts
-      ts.write([:hello, :world])
+    finger.lookup_ring do |ts2|
+      p ts2
+      ts2.write([:hello, :world])
     end
   when 'r'
     finger = Rinda::RingFinger.new(nil)
-    finger.lookup_ring do |ts|
-      p ts
-      p ts.take([nil, nil])
+    finger.lookup_ring do |ts2|
+      p ts2
+      p ts2.take([nil, nil])
     end
   end
 end

Modified: MacRuby/branches/experimental/lib/rinda/tuplespace.rb
===================================================================
--- MacRuby/branches/experimental/lib/rinda/tuplespace.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rinda/tuplespace.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,6 +2,8 @@
 require 'thread'
 require 'drb/drb'
 require 'rinda/rinda'
+require 'enumerator'
+require 'forwardable'
 
 module Rinda
 
@@ -286,45 +288,70 @@
   # of Tuplespace.
 
   class TupleBag
+    class TupleBin
+      extend Forwardable
+      def_delegators '@bin', :find_all, :delete_if, :each, :empty?
 
+      def initialize
+        @bin = []
+      end
+      
+      def add(tuple)
+        @bin.push(tuple)
+      end
+      
+      def delete(tuple)
+        idx = @bin.rindex(tuple)
+        @bin.delete_at(idx) if idx
+      end
+      
+      def find(&blk)
+        @bin.reverse_each do |x|
+          return x if yield(x)
+        end
+        nil
+      end
+    end
+
     def initialize # :nodoc:
       @hash = {}
+      @enum = enum_for(:each_entry)
     end
 
     ##
     # +true+ if the TupleBag to see if it has any expired entries.
 
     def has_expires?
-      @hash.each do |k, v|
-        v.each do |tuple|
-          return true if tuple.expires
-        end
+      @enum.find do |tuple|
+        tuple.expires
       end
-      false
     end
 
     ##
-    # Add +ary+ to the TupleBag.
+    # Add +tuple+ to the TupleBag.
 
-    def push(ary)
-      size = ary.size
-      @hash[size] ||= []
-      @hash[size].push(ary)
+    def push(tuple)
+      key = bin_key(tuple)
+      @hash[key] ||= TupleBin.new
+      @hash[key].add(tuple)
     end
 
     ##
-    # Removes +ary+ from the TupleBag.
+    # Removes +tuple+ from the TupleBag.
 
-    def delete(ary)
-      size = ary.size
-      @hash.fetch(size, []).delete(ary)
+    def delete(tuple)
+      key = bin_key(tuple)
+      bin = @hash[key]
+      return nil unless bin
+      bin.delete(tuple)
+      @hash.delete(key) if bin.empty?
+      tuple
     end
 
     ##
     # Finds all live tuples that match +template+.
-
     def find_all(template)
-      @hash.fetch(template.size, []).find_all do |tuple|
+      bin_for_find(template).find_all do |tuple|
         tuple.alive? && template.match(tuple)
       end
     end
@@ -333,7 +360,7 @@
     # Finds a live tuple that matches +template+.
 
     def find(template)
-      @hash.fetch(template.size, []).find do |tuple|
+      bin_for_find(template).find do |tuple|
         tuple.alive? && template.match(tuple)
       end
     end
@@ -343,7 +370,7 @@
     # +tuple+ and are alive.
 
     def find_all_template(tuple)
-      @hash.fetch(tuple.size, []).find_all do |template|
+      @enum.find_all do |template|
         template.alive? && template.match(tuple)
       end
     end
@@ -354,20 +381,39 @@
 
     def delete_unless_alive
       deleted = []
-      @hash.keys.each do |size|
-        ary = []
-        @hash[size].each do |tuple|
+      @hash.each do |key, bin|
+        bin.delete_if do |tuple|
           if tuple.alive?
-            ary.push(tuple)
+            false
           else
             deleted.push(tuple)
+            true
           end
         end
-        @hash[size] = ary
       end
       deleted
     end
 
+    private
+    def each_entry(&blk)
+      @hash.each do |k, v|
+        v.each(&blk)
+      end
+    end
+
+    def bin_key(tuple)
+      head = tuple[0]
+      if head.class == Symbol
+        return head
+      else
+        false
+      end
+    end
+
+    def bin_for_find(template)
+      key = bin_key(template)
+      key ? @hash.fetch(key, []) : @enum
+    end
   end
 
   ##
@@ -403,8 +449,7 @@
     # Adds +tuple+
 
     def write(tuple, sec=nil)
-      entry = TupleEntry.new(tuple, sec)
-      start_keeper
+      entry = create_entry(tuple, sec)
       synchronize do
         if entry.expired?
           @read_waiter.find_all_template(entry).each do |template|
@@ -414,6 +459,7 @@
           notify_event('delete', entry.value)
         else
           @bag.push(entry)
+          start_keeper if entry.expires
           @read_waiter.find_all_template(entry).each do |template|
             template.read(tuple)
           end
@@ -439,7 +485,6 @@
     def move(port, tuple, sec=nil)
       template = WaitTemplateEntry.new(self, tuple, sec)
       yield(template) if block_given?
-      start_keeper
       synchronize do
         entry = @bag.find(template)
         if entry
@@ -452,6 +497,7 @@
 
         begin
           @take_waiter.push(template)
+          start_keeper if template.expires
           while true
             raise RequestCanceledError if template.canceled?
             raise RequestExpiredError if template.expired?
@@ -476,7 +522,6 @@
     def read(tuple, sec=nil)
       template = WaitTemplateEntry.new(self, tuple, sec)
       yield(template) if block_given?
-      start_keeper
       synchronize do
         entry = @bag.find(template)
         return entry.value if entry
@@ -484,6 +529,7 @@
 
         begin
           @read_waiter.push(template)
+          start_keeper if template.expires
           template.wait
           raise RequestCanceledError if template.canceled?
           raise RequestExpiredError if template.expired?
@@ -529,6 +575,10 @@
 
     private
 
+    def create_entry(tuple, sec)
+      TupleEntry.new(tuple, sec)
+    end
+
     ##
     # Removes dead tuples.
 
@@ -566,9 +616,12 @@
     def start_keeper
       return if @keeper && @keeper.alive?
       @keeper = Thread.new do
-        while need_keeper?
-          keep_clean
+        while true
           sleep(@period)
+          synchronize do
+            break unless need_keeper?
+            keep_clean
+          end
         end
       end
     end

Modified: MacRuby/branches/experimental/lib/rss/converter.rb
===================================================================
--- MacRuby/branches/experimental/lib/rss/converter.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rss/converter.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -7,6 +7,10 @@
     include Utils
 
     def initialize(to_enc, from_enc=nil)
+      if "".respond_to?(:encode)
+        @to_encoding = to_enc
+        return
+      end
       normalized_to_enc = to_enc.downcase.gsub(/-/, '_')
       from_enc ||= 'utf-8'
       normalized_from_enc = from_enc.downcase.gsub(/-/, '_')
@@ -23,7 +27,11 @@
     end
 
     def convert(value)
-      value
+      if value.is_a?(String) and value.respond_to?(:encode)
+        value.encode(@to_encoding)
+      else
+        value
+      end
     end
 
     def def_convert(depth=0)

Modified: MacRuby/branches/experimental/lib/rss/maker/base.rb
===================================================================
--- MacRuby/branches/experimental/lib/rss/maker/base.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rss/maker/base.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -31,7 +31,9 @@
           self::OTHER_ELEMENTS << variable_name
         end
 
-        def add_need_initialize_variable(variable_name, init_value="nil")
+        def add_need_initialize_variable(variable_name, init_value=nil,
+                                         &init_block)
+          init_value ||= init_block
           self::NEED_INITIALIZE_VARIABLES << [variable_name, init_value]
         end
 
@@ -45,7 +47,7 @@
           def_delegators("@#{plural}", :push, :pop, :shift, :unshift)
           def_delegators("@#{plural}", :each, :size, :empty?, :clear)
 
-          add_need_initialize_variable(plural, "[]")
+          add_need_initialize_variable(plural) {[]}
 
           module_eval(<<-EOC, __FILE__, __LINE__ + 1)
             def new_#{name}
@@ -74,7 +76,9 @@
         def def_classed_element_without_accessor(name, class_name=nil)
           class_name ||= Utils.to_class_name(name)
           add_other_element(name)
-          add_need_initialize_variable(name, "make_#{name}")
+          add_need_initialize_variable(name) do |object|
+            object.send("make_#{name}")
+          end
           module_eval(<<-EOC, __FILE__, __LINE__ + 1)
             private
             def setup_#{name}(feed, current)
@@ -185,7 +189,19 @@
       private
       def initialize_variables
         self.class.need_initialize_variables.each do |variable_name, init_value|
-          instance_eval("@#{variable_name} = #{init_value}", __FILE__, __LINE__)
+          if init_value.nil?
+            value = nil
+          else
+            if init_value.respond_to?(:call)
+              value = init_value.call(self)
+            elsif init_value.is_a?(String)
+              # just for backward compatibility
+              value = instance_eval(init_value, __FILE__, __LINE__)
+            else
+              value = init_value
+            end
+          end
+          instance_variable_set("@#{variable_name}", value)
         end
       end
 
@@ -238,7 +254,8 @@
 
       def variables
         self.class.need_initialize_variables.find_all do |name, init|
-          "nil" == init
+          # init == "nil" is just for backward compatibility
+          init.nil? or init == "nil"
         end.collect do |name, init|
           name
         end
@@ -364,7 +381,9 @@
 
       %w(xml_stylesheets channel image items textinput).each do |element|
         attr_reader element
-        add_need_initialize_variable(element, "make_#{element}")
+        add_need_initialize_variable(element) do |object|
+          object.send("make_#{element}")
+        end
         module_eval(<<-EOC, __FILE__, __LINE__)
           private
           def setup_#{element}(feed)
@@ -392,12 +411,8 @@
       end
       
       def make
-        if block_given?
-          yield(self)
-          to_feed
-        else
-          nil
-        end
+        yield(self)
+        to_feed
       end
 
       def to_feed
@@ -405,11 +420,8 @@
         setup_xml_stylesheets(feed)
         setup_elements(feed)
         setup_other_elements(feed)
-        if feed.valid?
-          feed
-        else
-          nil
-        end
+        feed.validate
+        feed
       end
       
       private

Modified: MacRuby/branches/experimental/lib/rss/maker/itunes.rb
===================================================================
--- MacRuby/branches/experimental/lib/rss/maker/itunes.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rss/maker/itunes.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -176,7 +176,7 @@
 
         %w(hour minute second).each do |name|
           attr_reader(name)
-          add_need_initialize_variable(name, '0')
+          add_need_initialize_variable(name, 0)
         end
 
         def content=(content)

Modified: MacRuby/branches/experimental/lib/rss/parser.rb
===================================================================
--- MacRuby/branches/experimental/lib/rss/parser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rss/parser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -8,6 +8,10 @@
 
   class NotWellFormedError < Error
     attr_reader :line, :element
+
+    # Create a new NotWellFormedError for an error at +line+
+    # in +element+.  If a block is given the return value of
+    # the block ends up in the error message.
     def initialize(line=nil, element=nil)
       message = "This is not well formed XML"
       if element or line
@@ -22,15 +26,16 @@
 
   class XMLParserNotFound < Error
     def initialize
-      super("available XML parser does not found in " <<
+      super("available XML parser was not found in " <<
             "#{AVAILABLE_PARSER_LIBRARIES.inspect}.")
     end
   end
 
   class NotValidXMLParser < Error
     def initialize(parser)
-      super("#{parser} is not available XML parser. " <<
-            "available XML parser is " <<
+      super("#{parser} is not an available XML parser. " <<
+            "Available XML parser" <<
+            (AVAILABLE_PARSERS.size > 1 ? "s are " : " is ") <<
             "#{AVAILABLE_PARSERS.inspect}.")
     end
   end
@@ -56,6 +61,8 @@
         @@default_parser || AVAILABLE_PARSERS.first
       end
 
+      # Set @@default_parser to new_value if it is one of the
+      # available parsers. Else raise NotValidXMLParser error.
       def default_parser=(new_value)
         if AVAILABLE_PARSERS.include?(new_value)
           @@default_parser = new_value
@@ -83,6 +90,10 @@
     end
 
     private
+
+    # Try to get the XML associated with +rss+.
+    # Return +rss+ if it already looks like XML, or treat it as a URI,
+    # or a file to get the XML,
     def normalize_rss(rss)
       return rss if maybe_xml?(rss)
 
@@ -97,10 +108,13 @@
       end
     end
 
+    # maybe_xml? tests if source is a string that looks like XML.
     def maybe_xml?(source)
       source.is_a?(String) and /</ =~ source
     end
 
+    # Attempt to convert rss to a URI, but just return it if
+    # there's a ::URI::Error
     def to_uri(rss)
       return rss if rss.is_a?(::URI::Generic)
 
@@ -164,6 +178,7 @@
       @@registered_uris = {}
       @@class_names = {}
 
+      # return the setter for the uri, tag_name pair, or nil.
       def setter(uri, tag_name)
         _getter = getter(uri, tag_name)
         if _getter
@@ -177,29 +192,35 @@
         (@@accessor_bases[uri] || {})[tag_name]
       end
 
+      # return the tag_names for setters associated with uri
       def available_tags(uri)
         (@@accessor_bases[uri] || {}).keys
       end
       
+      # register uri against this name.
       def register_uri(uri, name)
         @@registered_uris[name] ||= {}
         @@registered_uris[name][uri] = nil
       end
       
+      # test if this uri is registered against this name
       def uri_registered?(uri, name)
         @@registered_uris[name].has_key?(uri)
       end
 
+      # record class_name for the supplied uri and tag_name
       def install_class_name(uri, tag_name, class_name)
         @@class_names[uri] ||= {}
         @@class_names[uri][tag_name] = class_name
       end
 
+      # retrieve class_name for the supplied uri and tag_name
+      # If it doesn't exist, capitalize the tag_name
       def class_name(uri, tag_name)
         name = (@@class_names[uri] || {})[tag_name]
         return name if name
 
-        tag_name.gsub!(/[_\-]([a-z]?)/){$1.upcase}
+        tag_name = tag_name.gsub(/[_\-]([a-z]?)/) {$1.upcase}
         tag_name[0, 1].upcase + tag_name[1..-1]
       end
 
@@ -213,6 +234,7 @@
       end
     
       private
+      # set the accessor for the uri, tag_name pair
       def install_accessor_base(uri, tag_name, accessor_base)
         @@accessor_bases[uri] ||= {}
         @@accessor_bases[uri][tag_name] = accessor_base.chomp("=")
@@ -258,6 +280,7 @@
       @last_xml_element = nil
     end
     
+    # set instance vars for version, encoding, standalone
     def xmldecl(version, encoding, standalone)
       @version, @encoding, @standalone = version, encoding, standalone
     end
@@ -350,6 +373,9 @@
     end
 
     CONTENT_PATTERN = /\s*([^=]+)=(["'])([^\2]+?)\2/
+    # Extract the first name="value" pair from content.
+    # Works with single quotes according to the constant
+    # CONTENT_PATTERN. Return a Hash.
     def parse_pi_content(content)
       params = {}
       content.scan(CONTENT_PATTERN) do |name, quote, value|
@@ -361,9 +387,7 @@
     def start_else_element(local, prefix, attrs, ns)
       class_name = self.class.class_name(_ns(ns, prefix), local)
       current_class = @last_element.class
-      if class_name and
-          (current_class.const_defined?(class_name, false) or
-           current_class.constants.include?(class_name.to_sym))
+      if known_class?(current_class, class_name)
         next_class = current_class.const_get(class_name)
         start_have_something_element(local, prefix, attrs, ns, next_class)
       else
@@ -379,6 +403,20 @@
       end
     end
 
+    if Module.method(:const_defined?).arity == -1
+      def known_class?(target_class, class_name)
+        class_name and
+          (target_class.const_defined?(class_name, false) or
+           target_class.constants.include?(class_name.to_sym))
+      end
+    else
+      def known_class?(target_class, class_name)
+        class_name and
+          (target_class.const_defined?(class_name) or
+           target_class.constants.include?(class_name))
+      end
+    end
+
     NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/
     def split_name(name)
       name =~ NAMESPLIT

Modified: MacRuby/branches/experimental/lib/rss/rss.rb
===================================================================
--- MacRuby/branches/experimental/lib/rss/rss.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rss/rss.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -53,7 +53,7 @@
 
 module RSS
 
-  VERSION = "0.2.4"
+  VERSION = "0.2.5"
 
   URI = "http://purl.org/rss/1.0/"
 

Modified: MacRuby/branches/experimental/lib/rss/utils.rb
===================================================================
--- MacRuby/branches/experimental/lib/rss/utils.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rss/utils.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,6 +1,8 @@
 module RSS
   module Utils
     module_function
+
+    # Convert a name_with_underscores to CamelCase.
     def to_class_name(name)
       name.split(/[_\-]/).collect do |part|
         "#{part[0, 1].upcase}#{part[1..-1]}"
@@ -14,11 +16,14 @@
       [file, line]
     end
 
+    # escape '&', '"', '<' and '>' for use in HTML.
     def html_escape(s)
       s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
     end
     alias h html_escape
     
+    # If +value+ is an instance of class +klass+, return it, else
+    # create a new instance of +klass+ with value +value+.
     def new_with_value_if_need(klass, value)
       if value.is_a?(klass)
         value

Modified: MacRuby/branches/experimental/lib/rubygems/command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -342,7 +342,7 @@
 
     add_common_option('-V', '--[no-]verbose',
                       'Set the verbose level of output') do |value, options|
-      # Set us to "really verbose" so the progess meter works
+      # Set us to "really verbose" so the progress meter works
       if Gem.configuration.verbose and value then
         Gem.configuration.verbose = 1
       else

Modified: MacRuby/branches/experimental/lib/rubygems/command_manager.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/command_manager.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/command_manager.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -16,7 +16,7 @@
   class CommandManager
     include UserInteraction
     
-    # Return the authoratative instance of the command manager.
+    # Return the authoritative instance of the command manager.
     def self.instance
       @command_manager ||= CommandManager.new
     end
@@ -46,6 +46,7 @@
       register_command :server
       register_command :sources
       register_command :specification
+      register_command :stale
       register_command :uninstall
       register_command :unpack
       register_command :update
@@ -69,7 +70,7 @@
       @commands.keys.collect {|key| key.to_s}.sort
     end
     
-    # Run the config specificed by +args+.
+    # Run the config specified by +args+.
     def run(args)
       process_args(args)
     rescue StandardError, Timeout::Error => ex

Modified: MacRuby/branches/experimental/lib/rubygems/commands/cert_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/cert_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/cert_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -19,7 +19,7 @@
       Dir::glob(glob_str) do |path|
         begin
           cert = OpenSSL::X509::Certificate.new(File.read(path))
-          # this could proably be formatted more gracefully
+          # this could probably be formatted more gracefully
           say cert.subject.to_s
         rescue OpenSSL::X509::CertificateError
           next

Modified: MacRuby/branches/experimental/lib/rubygems/commands/check_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/check_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/check_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -31,7 +31,8 @@
   def execute
     if options[:test]
       version = options[:version] || Gem::Requirement.default
-      gem_spec = Gem::SourceIndex.from_installed_gems.search(get_one_gem_name, version).first
+      dep = Gem::Dependency.new get_one_gem_name, version
+      gem_spec = Gem::SourceIndex.from_installed_gems.search(dep).first
       Gem::Validator.new.unit_test(gem_spec)
     end
 

Modified: MacRuby/branches/experimental/lib/rubygems/commands/contents_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/contents_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/contents_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -51,7 +51,7 @@
 
     si = Gem::SourceIndex.from_gems_in(*s)
 
-    gem_spec = si.search(/\A#{gem}\z/, version).last
+    gem_spec = si.find_name(gem, version).last
 
     unless gem_spec then
       say "Unable to find gem '#{gem}' in #{path_kind}"

Modified: MacRuby/branches/experimental/lib/rubygems/commands/dependency_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/dependency_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/dependency_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -43,40 +43,77 @@
   end
 
   def execute
-    options[:args] << '.' if options[:args].empty?
+    options[:args] << '' if options[:args].empty?
     specs = {}
 
-    source_indexes = []
+    source_indexes = Hash.new do |h, source_uri|
+      h[source_uri] = Gem::SourceIndex.new
+    end
 
-    if local? then
-      source_indexes << Gem::SourceIndex.from_installed_gems
+    pattern = if options[:args].length == 1 and
+                 options[:args].first =~ /\A\/(.*)\/(i)?\z/m then
+                flags = $2 ? Regexp::IGNORECASE : nil
+                Regexp.new $1, flags
+              else
+                /\A#{Regexp.union(*options[:args])}/
+              end
+
+    dependency = Gem::Dependency.new pattern, options[:version]
+
+    if options[:reverse_dependencies] and remote? and not local? then
+      alert_error 'Only reverse dependencies for local gems are supported.'
+      terminate_interaction 1
     end
 
-    if remote? then
-      Gem::SourceInfoCache.cache_data.map do |_, sice|
-        source_indexes << sice.source_index
+    if local? then
+      Gem.source_index.search(dependency).each do |spec|
+        source_indexes[:local].add_spec spec
       end
     end
 
-    options[:args].each do |name|
-      new_specs = nil
-      source_indexes.each do |source_index|
-        new_specs =  find_gems(name, source_index)
+    if remote? and not options[:reverse_dependencies] then
+      fetcher = Gem::SpecFetcher.fetcher
+
+      begin
+        fetcher.find_matching(dependency).each do |spec_tuple, source_uri|
+          spec = fetcher.fetch_spec spec_tuple, URI.parse(source_uri)
+
+          source_indexes[source_uri].add_spec spec
+        end
+      rescue Gem::RemoteFetcher::FetchError => e
+        raise unless fetcher.warn_legacy e do
+          require 'rubygems/source_info_cache'
+
+          specs = Gem::SourceInfoCache.search_with_source dependency, false
+
+          specs.each do |spec, source_uri|
+            source_indexes[source_uri].add_spec spec
+          end
+        end
       end
+    end
 
-      say "No match found for #{name} (#{options[:version]})" if
-        new_specs.empty?
+    if source_indexes.empty? then
+      patterns = options[:args].join ','
+      say "No gems found matching #{patterns} (#{options[:version]})" if
+        Gem.configuration.verbose
 
-      specs = specs.merge new_specs
+      terminate_interaction 1
     end
 
-    terminate_interaction 1 if specs.empty?
+    specs = {}
 
+    source_indexes.values.each do |source_index|
+      source_index.gems.each do |name, spec|
+        specs[spec.full_name] = [source_index, spec]
+      end
+    end
+
     reverse = Hash.new { |h, k| h[k] = [] }
 
     if options[:reverse_dependencies] then
-      specs.values.each do |source_index, spec|
-        reverse[spec.full_name] = find_reverse_dependencies spec, source_index
+      specs.values.each do |_, spec|
+        reverse[spec.full_name] = find_reverse_dependencies spec
       end
     end
 
@@ -118,10 +155,10 @@
   end
 
   # Retuns list of [specification, dep] that are satisfied by spec.
-  def find_reverse_dependencies(spec, source_index)
+  def find_reverse_dependencies(spec)
     result = []
 
-    source_index.each do |name, sp|
+    Gem.source_index.each do |name, sp|
       sp.dependencies.each do |dep|
         dep = Gem::Dependency.new(*dep) unless Gem::Dependency === dep
 
@@ -146,5 +183,6 @@
 
     specs
   end
+
 end
 

Modified: MacRuby/branches/experimental/lib/rubygems/commands/environment_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/environment_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/environment_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -18,6 +18,46 @@
     return args.gsub(/^\s+/, '')
   end
 
+  def description # :nodoc:
+    <<-EOF
+The RubyGems environment can be controlled through command line arguments,
+gemrc files, environment variables and built-in defaults.
+
+Command line argument defaults and some RubyGems defaults can be set in
+~/.gemrc file for individual users and a /etc/gemrc for all users.  A gemrc
+is a YAML file with the following YAML keys:
+
+  :sources: A YAML array of remote gem repositories to install gems from
+  :verbose: Verbosity of the gem command.  false, true, and :really are the
+            levels
+  :update_sources: Enable/disable automatic updating of repository metadata
+  :backtrace: Print backtrace when RubyGems encounters an error
+  :bulk_threshold: Switch to a bulk update when this many sources are out of
+                   date (legacy setting)
+  :gempath: The paths in which to look for gems
+  gem_command: A string containing arguments for the specified gem command
+
+Example:
+
+  :verbose: false
+  install: --no-wrappers
+  update: --no-wrappers
+
+RubyGems' default local repository can be overriden with the GEM_PATH and
+GEM_HOME environment variables.  GEM_HOME sets the default repository to
+install into.  GEM_PATH allows multiple local repositories to be searched for
+gems.
+
+If you are behind a proxy server, RubyGems uses the HTTP_PROXY,
+HTTP_PROXY_USER and HTTP_PROXY_PASS environment variables to discover the
+proxy server.
+
+If you are packaging RubyGems all of RubyGems' defaults are in
+lib/rubygems/defaults.rb.  You may override these in
+lib/rubygems/defaults/operating_system.rb
+    EOF
+  end
+
   def usage # :nodoc:
     "#{program_name} [arg]"
   end
@@ -51,6 +91,8 @@
 
       out << "  - RUBY EXECUTABLE: #{Gem.ruby}\n"
 
+      out << "  - EXECUTABLE DIRECTORY: #{Gem.bindir}\n"
+
       out << "  - RUBYGEMS PLATFORMS:\n"
       Gem.platforms.each do |platform|
         out << "    - #{platform}\n"

Modified: MacRuby/branches/experimental/lib/rubygems/commands/fetch_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/fetch_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/fetch_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -33,13 +33,15 @@
 
   def execute
     version = options[:version] || Gem::Requirement.default
+    all = Gem::Requirement.default
 
     gem_names = get_all_gem_names
 
     gem_names.each do |gem_name|
       dep = Gem::Dependency.new gem_name, version
-      specs_and_sources = Gem::SourceInfoCache.search_with_source dep, true
 
+      specs_and_sources = Gem::SpecFetcher.fetcher.fetch dep, all
+
       specs_and_sources.sort_by { |spec,| spec.version }
 
       spec, source_uri = specs_and_sources.last

Modified: MacRuby/branches/experimental/lib/rubygems/commands/help_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/help_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/help_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -20,9 +20,9 @@
     gem install --remote rake --test --rdoc --ri
 
 * Install 'rake', but only version 0.3.1, even if dependencies
-  are not met, and into a specific directory:
+  are not met, and into a user-specific directory:
 
-    gem install rake --version 0.3.1 --force --install-dir $HOME/.gems
+    gem install rake --version 0.3.1 --force --user-install
 
 * List local gems whose name begins with 'D':
 

Modified: MacRuby/branches/experimental/lib/rubygems/commands/install_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/install_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/install_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -16,7 +16,6 @@
     defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
       :generate_rdoc => true,
       :generate_ri   => true,
-      :install_dir => Gem.dir,
       :format_executable => false,
       :test => false,
       :version => Gem::Requirement.default,
@@ -39,6 +38,19 @@
     "--no-test --install-dir #{Gem.dir}"
   end
 
+  def description # :nodoc:
+    <<-EOF
+The install command installs local or remote gem into a gem repository.
+
+For gems with executables ruby installs a wrapper file into the executable
+directory by deault.  This can be overridden with the --no-wrappers option.
+The wrapper allows you to choose among alternate gem versions using _version_.
+
+For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer
+version is also installed.
+    EOF
+  end
+
   def usage # :nodoc:
     "#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags"
   end
@@ -51,7 +63,7 @@
 
     installed_gems = []
 
-    ENV['GEM_PATH'] = options[:install_dir] # HACK what does this do?
+    ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9'
 
     install_options = {
       :env_shebang => options[:env_shebang],
@@ -62,7 +74,8 @@
       :install_dir => options[:install_dir],
       :security_policy => options[:security_policy],
       :wrappers => options[:wrappers],
-      :bin_dir => options[:bin_dir]
+      :bin_dir => options[:bin_dir],
+      :development => options[:development],
     }
 
     exit_code = 0
@@ -106,6 +119,8 @@
       installed_gems.each do |gem|
         Gem::DocManager.new(gem, options[:rdoc_args]).generate_ri
       end
+
+      Gem::DocManager.update_ri_cache
     end
 
     if options[:generate_rdoc] then

Modified: MacRuby/branches/experimental/lib/rubygems/commands/list_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/list_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/list_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,33 +1,35 @@
 require 'rubygems/command'
 require 'rubygems/commands/query_command'
 
-module Gem
-  module Commands
-    class ListCommand < QueryCommand
+##
+# An alternate to Gem::Commands::QueryCommand that searches for gems starting
+# with the the supplied argument.
 
-      def initialize
-        super 'list', 'Display gems whose name starts with STRING'
+class Gem::Commands::ListCommand < Gem::Commands::QueryCommand
 
-        remove_option('--name-matches')
-      end
+  def initialize
+    super 'list', 'Display gems whose name starts with STRING'
 
-      def arguments # :nodoc:
-        "STRING        start of gem name to look for"
-      end
+    remove_option('--name-matches')
+  end
 
-      def defaults_str # :nodoc:
-        "--local --no-details"
-      end
+  def arguments # :nodoc:
+    "STRING        start of gem name to look for"
+  end
 
-      def usage # :nodoc:
-        "#{program_name} [STRING]"
-      end
+  def defaults_str # :nodoc:
+    "--local --no-details"
+  end
 
-      def execute
-        string = get_one_optional_argument || ''
-        options[:name] = /^#{string}/i
-        super
-      end
-    end
+  def usage # :nodoc:
+    "#{program_name} [STRING]"
   end
+
+  def execute
+    string = get_one_optional_argument || ''
+    options[:name] = /^#{string}/i
+    super
+  end
+
 end
+

Modified: MacRuby/branches/experimental/lib/rubygems/commands/lock_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/lock_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/lock_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -58,15 +58,15 @@
   end
 
   def complain(message)
-    if options.strict then
-      raise message
+    if options[:strict] then
+      raise Gem::Exception, message
     else
       say "# #{message}"
     end
   end
 
   def execute
-    say 'require "rubygems"'
+    say "require 'rubygems'"
 
     locked = {}
 
@@ -77,15 +77,20 @@
 
       spec = Gem::SourceIndex.load_specification spec_path(full_name)
 
+      if spec.nil? then
+        complain "Could not find gem #{full_name}, try using the full name"
+        next
+      end
+
       say "gem '#{spec.name}', '= #{spec.version}'" unless locked[spec.name]
       locked[spec.name] = true
 
-      spec.dependencies.each do |dep|
+      spec.runtime_dependencies.each do |dep|
         next if locked[dep.name]
-        candidates = Gem.source_index.search dep.name, dep.requirement_list
+        candidates = Gem.source_index.search dep
 
         if candidates.empty? then
-          complain "Unable to satisfy '#{dep}' from currently installed gems."
+          complain "Unable to satisfy '#{dep}' from currently installed gems"
         else
           pending << candidates.last.full_name
         end
@@ -94,7 +99,11 @@
   end
 
   def spec_path(gem_full_name)
-    File.join Gem.path, "specifications", "#{gem_full_name }.gemspec"
+    gemspecs = Gem.path.map do |path|
+      File.join path, "specifications", "#{gem_full_name}.gemspec"
+    end
+
+    gemspecs.find { |gemspec| File.exist? gemspec }
   end
 
 end

Modified: MacRuby/branches/experimental/lib/rubygems/commands/outdated_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/outdated_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/outdated_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,6 +1,6 @@
 require 'rubygems/command'
 require 'rubygems/local_remote_options'
-require 'rubygems/source_info_cache'
+require 'rubygems/spec_fetcher'
 require 'rubygems/version_option'
 
 class Gem::Commands::OutdatedCommand < Gem::Command
@@ -19,9 +19,12 @@
     locals = Gem::SourceIndex.from_installed_gems
 
     locals.outdated.sort.each do |name|
-      local = locals.search(/^#{name}$/).last
-      remotes = Gem::SourceInfoCache.search_with_source(/^#{name}$/, true)
+      local = locals.find_name(name).last
+
+      dep = Gem::Dependency.new local.name, ">= #{local.version}"
+      remotes = Gem::SpecFetcher.fetcher.fetch dep
       remote = remotes.last.first
+
       say "#{local.name} (#{local.version} < #{remote.version})"
     end
   end

Modified: MacRuby/branches/experimental/lib/rubygems/commands/pristine_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/pristine_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/pristine_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -57,7 +57,7 @@
               end
             else
               gem_name = get_one_gem_name
-              Gem::SourceIndex.from_installed_gems.search(gem_name,
+              Gem::SourceIndex.from_installed_gems.find_name(gem_name,
                                                           options[:version])
             end
 
@@ -82,51 +82,10 @@
       end
 
       # TODO use installer options
-      installer = Gem::Installer.new gem, :wrappers => true
+      installer = Gem::Installer.new gem, :wrappers => true, :force => true
+      installer.install
 
-      gem_file = File.join install_dir, "cache", "#{spec.full_name}.gem"
-
-      security_policy = nil # TODO use installer option
-
-      format = Gem::Format.from_file_by_path gem_file, security_policy
-
-      target_directory = File.join(install_dir, "gems", format.spec.full_name)
-      target_directory.untaint
-
-      pristine_files = format.file_entries.collect { |data| data[0]["path"] }
-      file_map = {}
-
-      format.file_entries.each do |entry, file_data|
-        file_map[entry["path"]] = file_data
-      end
-
-      Dir.chdir target_directory do
-        deployed_files = Dir.glob(File.join("**", "*")) +
-                         Dir.glob(File.join("**", ".*"))
-
-        pristine_files = pristine_files.map { |f| File.expand_path f }
-        deployed_files = deployed_files.map { |f| File.expand_path f }
-
-        to_redeploy = (pristine_files - deployed_files)
-        to_redeploy = to_redeploy.map { |path| path.untaint}
-
-        if to_redeploy.length > 0 then
-          say "Restoring #{to_redeploy.length} file#{to_redeploy.length == 1 ? "" : "s"} to #{spec.full_name}..."
-
-          to_redeploy.each do |path|
-            say "  #{path}"
-            FileUtils.mkdir_p File.dirname(path)
-            File.open(path, "wb") do |out|
-              out.write file_map[path]
-            end
-          end
-        else
-          say "#{spec.full_name} is in pristine condition"
-        end
-      end
-
-      installer.generate_bin
-      installer.build_extensions
+      say "Restored #{spec.full_name}"
     end
   end
 

Modified: MacRuby/branches/experimental/lib/rubygems/commands/query_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/query_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/query_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,6 +1,6 @@
 require 'rubygems/command'
 require 'rubygems/local_remote_options'
-require 'rubygems/source_info_cache'
+require 'rubygems/spec_fetcher'
 require 'rubygems/version_option'
 
 class Gem::Commands::QueryCommand < Gem::Command
@@ -59,7 +59,7 @@
       if name.source.empty? then
         alert_error "You must specify a gem name"
         exit_code |= 4
-      elsif installed? name.source, options[:version] then
+      elsif installed? name, options[:version] then
         say "true"
       else
         say "false"
@@ -69,28 +69,52 @@
       raise Gem::SystemExitException, exit_code
     end
 
+    dep = Gem::Dependency.new name, Gem::Requirement.default
+
     if local? then
-      say
-      say "*** LOCAL GEMS ***"
-      say
+      if ui.outs.tty? or both? then
+        say
+        say "*** LOCAL GEMS ***"
+        say
+      end
 
-      output_query_results Gem.source_index.search(name)
+      specs = Gem.source_index.search dep
+
+      spec_tuples = specs.map do |spec|
+        [[spec.name, spec.version, spec.original_platform, spec], :local]
+      end
+
+      output_query_results spec_tuples
     end
 
     if remote? then
-      say
-      say "*** REMOTE GEMS ***"
-      say
+      if ui.outs.tty? or both? then
+        say
+        say "*** REMOTE GEMS ***"
+        say
+      end
 
       all = options[:all]
 
       begin
-        Gem::SourceInfoCache.cache all
-      rescue Gem::RemoteFetcher::FetchError
-        # no network
+        fetcher = Gem::SpecFetcher.fetcher
+        spec_tuples = fetcher.find_matching dep, all, false
+      rescue Gem::RemoteFetcher::FetchError => e
+        raise unless fetcher.warn_legacy e do
+          require 'rubygems/source_info_cache'
+
+          dep.name = '' if dep.name == //
+
+          specs = Gem::SourceInfoCache.search_with_source dep, false, all
+
+          spec_tuples = specs.map do |spec, source_uri|
+            [[spec.name, spec.version, spec.original_platform, spec],
+             source_uri]
+          end
+        end
       end
 
-      output_query_results Gem::SourceInfoCache.search(name, false, all)
+      output_query_results spec_tuples
     end
   end
 
@@ -104,28 +128,30 @@
     !Gem.source_index.search(dep).empty?
   end
 
-  def output_query_results(gemspecs)
+  def output_query_results(spec_tuples)
     output = []
-    gem_list_with_version = {}
+    versions = Hash.new { |h,name| h[name] = [] }
 
-    gemspecs.flatten.each do |gemspec|
-      gem_list_with_version[gemspec.name] ||= []
-      gem_list_with_version[gemspec.name] << gemspec
+    spec_tuples.each do |spec_tuple, source_uri|
+      versions[spec_tuple.first] << [spec_tuple, source_uri]
     end
 
-    gem_list_with_version = gem_list_with_version.sort_by do |name, spec|
+    versions = versions.sort_by do |(name,_),_|
       name.downcase
     end
 
-    gem_list_with_version.each do |gem_name, list_of_matching|
-      list_of_matching = list_of_matching.sort_by { |x| x.version.to_ints }.reverse
-      seen_versions = {}
+    versions.each do |gem_name, matching_tuples|
+      matching_tuples = matching_tuples.sort_by do |(name, version,_),_|
+        version
+      end.reverse
 
-      list_of_matching.delete_if do |item|
-        if seen_versions[item.version] then
+      seen = {}
+
+      matching_tuples.delete_if do |(name, version,_),_|
+        if seen[version] then
           true
         else
-          seen_versions[item.version] = true
+          seen[version] = true
           false
         end
       end
@@ -133,12 +159,50 @@
       entry = gem_name.dup
 
       if options[:versions] then
-        versions = list_of_matching.map { |s| s.version }.uniq
+        versions = matching_tuples.map { |(name, version,_),_| version }.uniq
         entry << " (#{versions.join ', '})"
       end
 
-      entry << "\n" << format_text(list_of_matching[0].summary, 68, 4) if
-        options[:details]
+      if options[:details] then
+        detail_tuple = matching_tuples.first
+
+        spec = if detail_tuple.first.length == 4 then
+                 detail_tuple.first.last
+               else
+                 uri = URI.parse detail_tuple.last
+                 Gem::SpecFetcher.fetcher.fetch_spec detail_tuple.first, uri
+               end
+
+        entry << "\n"
+        authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
+        authors << spec.authors.join(', ')
+        entry << format_text(authors, 68, 4)
+
+        if spec.rubyforge_project and not spec.rubyforge_project.empty? then
+          rubyforge = "Rubyforge: http://rubyforge.org/projects/#{spec.rubyforge_project}"
+          entry << "\n" << format_text(rubyforge, 68, 4)
+        end
+
+        if spec.homepage and not spec.homepage.empty? then
+          entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
+        end
+
+        if spec.loaded_from then
+          if matching_tuples.length == 1 then
+            loaded_from = File.dirname File.dirname(spec.loaded_from)
+            entry << "\n" << "    Installed at: #{loaded_from}"
+          else
+            label = 'Installed at'
+            matching_tuples.each do |(_,version,_,s),|
+              loaded_from = File.dirname File.dirname(s.loaded_from)
+              entry << "\n" << "    #{label} (#{version}): #{loaded_from}"
+              label = ' ' * label.length
+            end
+          end
+        end
+
+        entry << "\n\n" << format_text(spec.summary, 68, 4)
+      end
       output << entry
     end
 

Modified: MacRuby/branches/experimental/lib/rubygems/commands/rdoc_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/rdoc_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/rdoc_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -59,11 +59,15 @@
         if specs.empty?
           fail "Failed to find gem #{gem_name} to generate RDoc for #{options[:version]}"
         end
+
         if options[:include_ri]
           specs.each do |spec|
             Gem::DocManager.new(spec).generate_ri
           end
+
+          Gem::DocManager.update_ri_cache
         end
+
         if options[:include_rdoc]
           specs.each do |spec|
             Gem::DocManager.new(spec).generate_rdoc
@@ -73,6 +77,6 @@
         true
       end
     end
-    
+
   end
 end

Modified: MacRuby/branches/experimental/lib/rubygems/commands/sources_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/sources_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/sources_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,8 @@
+require 'fileutils'
 require 'rubygems/command'
 require 'rubygems/remote_fetcher'
 require 'rubygems/source_info_cache'
-require 'rubygems/source_info_cache_entry'
+require 'rubygems/spec_fetcher'
 
 class Gem::Commands::SourcesCommand < Gem::Command
 
@@ -21,14 +22,14 @@
       options[:remove] = value
     end
 
-    add_option '-u', '--update', 'Update source cache' do |value, options|
-      options[:update] = value
-    end
-
     add_option '-c', '--clear-all',
                'Remove all sources (clear the cache)' do |value, options|
       options[:clear_all] = value
     end
+
+    add_option '-u', '--update', 'Update source cache' do |value, options|
+      options[:update] = value
+    end
   end
 
   def defaults_str
@@ -36,9 +37,23 @@
   end
 
   def execute
-    options[:list] = !(options[:add] || options[:remove] || options[:clear_all] || options[:update])
+    options[:list] = !(options[:add] ||
+                       options[:clear_all] ||
+                       options[:remove] ||
+                       options[:update])
 
     if options[:clear_all] then
+      path = Gem::SpecFetcher.fetcher.dir
+      FileUtils.rm_rf path
+
+      if not File.exist?(path) then
+        say "*** Removed specs cache ***"
+      elsif not File.writable?(path) then
+        say "*** Unable to remove source cache (write protected) ***"
+      else
+        say "*** Unable to remove source cache ***"
+      end
+
       sic = Gem::SourceInfoCache
       remove_cache_file 'user',          sic.user_cache_file
       remove_cache_file 'latest user',   sic.latest_user_cache_file
@@ -48,15 +63,10 @@
 
     if options[:add] then
       source_uri = options[:add]
+      uri = URI.parse source_uri
 
-      sice = Gem::SourceInfoCacheEntry.new nil, nil
       begin
-        sice.refresh source_uri, true
-
-        Gem::SourceInfoCache.cache_data[source_uri] = sice
-        Gem::SourceInfoCache.cache.update
-        Gem::SourceInfoCache.cache.flush
-
+        Gem::SpecFetcher.fetcher.load_specs uri, 'specs'
         Gem.sources << source_uri
         Gem.configuration.write
 
@@ -64,15 +74,24 @@
       rescue URI::Error, ArgumentError
         say "#{source_uri} is not a URI"
       rescue Gem::RemoteFetcher::FetchError => e
-        say "Error fetching #{source_uri}:\n\t#{e.message}"
-      end
-    end
+        yaml_uri = uri + 'yaml'
+        gem_repo = Gem::RemoteFetcher.fetcher.fetch_size yaml_uri rescue false
 
-    if options[:update] then
-      Gem::SourceInfoCache.cache true
-      Gem::SourceInfoCache.cache.flush
+        if e.uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ and
+           gem_repo then
 
-      say "source cache successfully updated"
+          alert_warning <<-EOF
+RubyGems 1.2+ index not found for:
+\t#{source_uri}
+
+Will cause RubyGems to revert to legacy indexes, degrading performance.
+          EOF
+
+          say "#{source_uri} added to sources"
+        else
+          say "Error fetching #{source_uri}:\n\t#{e.message}"
+        end
+      end
     end
 
     if options[:remove] then
@@ -81,14 +100,6 @@
       unless Gem.sources.include? source_uri then
         say "source #{source_uri} not present in cache"
       else
-        begin # HACK figure out how to get the cache w/o update
-          Gem::SourceInfoCache.cache
-        rescue Gem::RemoteFetcher::FetchError
-        end
-
-        Gem::SourceInfoCache.cache_data.delete source_uri
-        Gem::SourceInfoCache.cache.update
-        Gem::SourceInfoCache.cache.flush
         Gem.sources.delete source_uri
         Gem.configuration.write
 
@@ -96,6 +107,23 @@
       end
     end
 
+    if options[:update] then
+      fetcher = Gem::SpecFetcher.fetcher
+
+      if fetcher.legacy_repos.empty? then
+        Gem.sources.each do |update_uri|
+          update_uri = URI.parse update_uri
+          fetcher.load_specs update_uri, 'specs'
+          fetcher.load_specs update_uri, 'latest_specs'
+        end
+      else
+        Gem::SourceInfoCache.cache true
+        Gem::SourceInfoCache.cache.flush
+      end
+
+      say "source cache successfully updated"
+    end
+
     if options[:list] then
       say "*** CURRENT SOURCES ***"
       say

Modified: MacRuby/branches/experimental/lib/rubygems/commands/specification_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/specification_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/specification_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -40,6 +40,7 @@
   def execute
     specs = []
     gem = get_one_gem_name
+    dep = Gem::Dependency.new gem, options[:version]
 
     if local? then
       if File.exist? gem then
@@ -47,14 +48,14 @@
       end
 
       if specs.empty? then
-        specs.push(*Gem.source_index.search(/\A#{gem}\z/, options[:version]))
+        specs.push(*Gem.source_index.search(dep))
       end
     end
 
     if remote? then
-      Gem::SourceInfoCache.cache_data.each do |_,sice|
-        specs.push(*sice.source_index.search(gem, options[:version]))
-      end
+      found = Gem::SpecFetcher.fetcher.fetch dep
+
+      specs.push(*found.map { |spec,| spec })
     end
 
     if specs.empty? then

Copied: MacRuby/branches/experimental/lib/rubygems/commands/stale_command.rb (from rev 1886, MacRuby/trunk/lib/rubygems/commands/stale_command.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/stale_command.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rubygems/commands/stale_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,27 @@
+require 'rubygems/command'
+
+class Gem::Commands::StaleCommand < Gem::Command
+  def initialize
+    super('stale', 'List gems along with access times')
+  end
+
+  def usage # :nodoc:
+    "#{program_name}"
+  end
+
+  def execute
+    gem_to_atime = {}
+    Gem.source_index.each do |name, spec|
+      Dir["#{spec.full_gem_path}/**/*.*"].each do |file|
+        next if File.directory?(file)
+        stat = File.stat(file)
+        gem_to_atime[name] ||= stat.atime
+        gem_to_atime[name] = stat.atime if gem_to_atime[name] < stat.atime
+      end
+    end
+
+    gem_to_atime.sort_by { |_, atime| atime }.each do |name, atime|
+      say "#{name} at #{atime.strftime '%c'}"
+    end
+  end
+end

Modified: MacRuby/branches/experimental/lib/rubygems/commands/unpack_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/unpack_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/unpack_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -43,7 +43,7 @@
       basename = File.basename(path).sub(/\.gem$/, '')
       target_dir = File.expand_path File.join(options[:target], basename)
       FileUtils.mkdir_p target_dir
-      Gem::Installer.new(path).unpack target_dir
+      Gem::Installer.new(path, :unpack => true).unpack target_dir
       say "Unpacked gem: '#{target_dir}'"
     else
       alert_error "Gem '#{gemname}' not installed."
@@ -68,7 +68,7 @@
   def get_path(gemname, version_req)
     return gemname if gemname =~ /\.gem$/i
 
-    specs = Gem::source_index.search(/\A#{gemname}\z/, version_req)
+    specs = Gem::source_index.find_name gemname, version_req
 
     selected = specs.sort_by { |s| s.version }.last
 

Modified: MacRuby/branches/experimental/lib/rubygems/commands/update_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/update_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/update_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,7 +2,7 @@
 require 'rubygems/command_manager'
 require 'rubygems/install_update_options'
 require 'rubygems/local_remote_options'
-require 'rubygems/source_info_cache'
+require 'rubygems/spec_fetcher'
 require 'rubygems/version_option'
 require 'rubygems/commands/install_command'
 
@@ -15,11 +15,10 @@
   def initialize
     super 'update',
           'Update the named gems (or all installed gems) in the local repository',
-      :generate_rdoc => true, 
-      :generate_ri => true, 
-      :force => false, 
-      :test => false,
-      :install_dir => Gem.dir
+      :generate_rdoc => true,
+      :generate_ri => true,
+      :force => false,
+      :test => false
 
     add_install_update_options
 
@@ -46,6 +45,8 @@
   end
 
   def execute
+    hig = {}
+
     if options[:system] then
       say "Updating RubyGems"
 
@@ -53,29 +54,26 @@
         fail "No gem names are allowed with the --system option"
       end
 
-      options[:args] = ["rubygems-update"]
+      rubygems_update = Gem::Specification.new
+      rubygems_update.name = 'rubygems-update'
+      rubygems_update.version = Gem::Version.new Gem::RubyGemsVersion
+      hig['rubygems-update'] = rubygems_update
+
+      options[:user_install] = false
     else
       say "Updating installed gems"
-    end
 
-    hig = {} # highest installed gems
+      hig = {} # highest installed gems
 
-    Gem::SourceIndex.from_installed_gems.each do |name, spec|
-      if hig[spec.name].nil? or hig[spec.name].version < spec.version then
-        hig[spec.name] = spec
+      Gem.source_index.each do |name, spec|
+        if hig[spec.name].nil? or hig[spec.name].version < spec.version then
+          hig[spec.name] = spec
+        end
       end
     end
 
-    pattern = if options[:args].empty? then
-                //
-              else
-                Regexp.union(*options[:args])
-              end
+    gems_to_update = which_to_update hig, options[:args]
 
-    remote_gemspecs = Gem::SourceInfoCache.search pattern
-
-    gems_to_update = which_to_update hig, remote_gemspecs
-
     updated = []
 
     installer = Gem::DependencyInstaller.new options
@@ -93,15 +91,15 @@
     end
 
     if gems_to_update.include? "rubygems-update" then
-      latest_ruby_gem = remote_gemspecs.select do |s|
-        s.name == 'rubygems-update'
-      end
+      Gem.source_index.refresh!
 
-      latest_ruby_gem = latest_ruby_gem.sort_by { |s| s.version }.last
+      update_gems = Gem.source_index.search 'rubygems-update'
 
-      say "Updating version of RubyGems to #{latest_ruby_gem.version}"
-      installed = do_rubygems_update latest_ruby_gem.version
+      latest_update_gem = update_gems.sort_by { |s| s.version }.last
 
+      say "Updating RubyGems to #{latest_update_gem.version}"
+      installed = do_rubygems_update latest_update_gem.version
+
       say "RubyGems system software updated" if installed
     else
       if updated.empty? then
@@ -112,6 +110,9 @@
     end
   end
 
+  ##
+  # Update the RubyGems software to +version+.
+
   def do_rubygems_update(version)
     args = []
     args.push '--prefix', Gem.prefix unless Gem.prefix.nil?
@@ -121,8 +122,6 @@
 
     update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}"
 
-    success = false
-
     Dir.chdir update_dir do
       say "Installing RubyGems #{version}"
       setup_cmd = "#{Gem.ruby} setup.rb #{args.join ' '}"
@@ -135,20 +134,42 @@
     end
   end
 
-  def which_to_update(highest_installed_gems, remote_gemspecs)
+  def which_to_update(highest_installed_gems, gem_names)
     result = []
 
     highest_installed_gems.each do |l_name, l_spec|
-      matching_gems = remote_gemspecs.select do |spec|
-        spec.name == l_name and Gem.platforms.any? do |platform|
-          platform == spec.platform
+      next if not gem_names.empty? and
+              gem_names.all? { |name| /#{name}/ !~ l_spec.name }
+
+      dependency = Gem::Dependency.new l_spec.name, "> #{l_spec.version}"
+
+      begin
+        fetcher = Gem::SpecFetcher.fetcher
+        spec_tuples = fetcher.find_matching dependency
+      rescue Gem::RemoteFetcher::FetchError => e
+        raise unless fetcher.warn_legacy e do
+          require 'rubygems/source_info_cache'
+
+          dependency.name = '' if dependency.name == //
+
+          specs = Gem::SourceInfoCache.search_with_source dependency
+
+          spec_tuples = specs.map do |spec, source_uri|
+            [[spec.name, spec.version, spec.original_platform], source_uri]
+          end
         end
       end
 
-      highest_remote_gem = matching_gems.sort_by { |spec| spec.version }.last
+      matching_gems = spec_tuples.select do |(name, version, platform),|
+        name == l_name and Gem::Platform.match platform
+      end
 
+      highest_remote_gem = matching_gems.sort_by do |(name, version),|
+        version
+      end.last
+
       if highest_remote_gem and
-         l_spec.version < highest_remote_gem.version then
+         l_spec.version < highest_remote_gem.first[1] then
         result << l_name
       end
     end

Modified: MacRuby/branches/experimental/lib/rubygems/commands/which_command.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/commands/which_command.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/commands/which_command.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,10 +3,10 @@
 
 class Gem::Commands::WhichCommand < Gem::Command
 
-  EXT = %w[.rb .rbw .so .dll] # HACK
+  EXT = %w[.rb .rbw .so .dll .bundle] # HACK
 
   def initialize
-    super 'which', 'Find the location of a library',
+    super 'which', 'Find the location of a library file you can require',
           :search_gems_first => false, :show_all => false
 
     add_option '-a', '--[no-]all', 'show all matching files' do |show_all, options|
@@ -52,7 +52,7 @@
       paths = find_paths arg, dirs
 
       if paths.empty? then
-        say "Can't find #{arg}"
+        say "Can't find ruby library file or shared library #{arg}"
       else
         say paths
       end
@@ -84,3 +84,4 @@
   end
 
 end
+

Modified: MacRuby/branches/experimental/lib/rubygems/config_file.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/config_file.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/config_file.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -18,9 +18,42 @@
   DEFAULT_VERBOSITY = true
   DEFAULT_UPDATE_SOURCES = true
 
+  ##
+  # For Ruby packagers to set configuration defaults.  Set in
+  # rubygems/defaults/operating_system.rb
+
+  OPERATING_SYSTEM_DEFAULTS = {}
+
+  ##
+  # For Ruby implementers to set configuration defaults.  Set in
+  # rubygems/defaults/#{RUBY_ENGINE}.rb
+
+  PLATFORM_DEFAULTS = {}
+
+  system_config_path = 
+    begin
+      require 'Win32API'
+
+      CSIDL_COMMON_APPDATA = 0x0023
+      path = 0.chr * 260
+      SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'LLLLP', 'L'
+      SHGetFolderPath.call 0, CSIDL_COMMON_APPDATA, 0, 1, path
+
+      path.strip
+    rescue LoadError
+      '/etc'
+    end
+
+  SYSTEM_WIDE_CONFIG_FILE = File.join system_config_path, 'gemrc'
+  
   # List of arguments supplied to the config file object.
   attr_reader :args
 
+  # Where to look for gems
+  attr_accessor :path
+
+  attr_accessor :home
+
   # True if we print backtraces on errors.
   attr_writer :backtrace
 
@@ -63,6 +96,7 @@
     arg_list = arg_list.map do |arg|
       if need_config_file_name then
         @config_file_name = arg
+        need_config_file_name = false
         nil
       elsif arg =~ /^--config-file=(.*)/ then
         @config_file_name = $1
@@ -81,30 +115,38 @@
     @verbose = DEFAULT_VERBOSITY
     @update_sources = DEFAULT_UPDATE_SOURCES
 
-    begin
-      # HACK $SAFE ok?
-      @hash = open(config_file_name.dup.untaint) {|f| YAML.load(f) }
-    rescue ArgumentError
-      warn "Failed to load #{config_file_name}"
-    rescue Errno::ENOENT
-      # Ignore missing config file error.
-    rescue Errno::EACCES
-      warn "Failed to load #{config_file_name} due to permissions problem."
-    end
+    operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS)
+    platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
+    system_config = load_file SYSTEM_WIDE_CONFIG_FILE
+    user_config = load_file config_file_name.dup.untaint
 
-    @hash ||= {}
+    @hash = operating_system_config.merge platform_config
+    @hash = @hash.merge system_config
+    @hash = @hash.merge user_config
 
     # HACK these override command-line args, which is bad
     @backtrace = @hash[:backtrace] if @hash.key? :backtrace
     @benchmark = @hash[:benchmark] if @hash.key? :benchmark
     @bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
-    Gem.sources.replace @hash[:sources] if @hash.key? :sources
+    Gem.sources = @hash[:sources] if @hash.key? :sources
     @verbose = @hash[:verbose] if @hash.key? :verbose
     @update_sources = @hash[:update_sources] if @hash.key? :update_sources
+    @path = @hash[:gempath] if @hash.key? :gempath
+    @home = @hash[:gemhome] if @hash.key? :gemhome
 
     handle_arguments arg_list
   end
 
+  def load_file(filename)
+    begin
+      YAML.load(File.read(filename)) if filename and File.exist?(filename)
+    rescue ArgumentError
+      warn "Failed to load #{config_file_name}"
+    rescue Errno::EACCES
+      warn "Failed to load #{config_file_name} due to permissions problem."
+    end or {}
+  end
+
   # True if the backtrace option has been specified, or debug is on.
   def backtrace
     @backtrace or $DEBUG

Modified: MacRuby/branches/experimental/lib/rubygems/custom_require.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/custom_require.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/custom_require.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -7,12 +7,16 @@
 require 'rubygems'
 
 module Kernel
-  alias gem_original_require require # :nodoc:
 
+  ##
+  # The Kernel#require from before RubyGems was loaded.
+
+  alias gem_original_require require
+
+  ##
+  # When RubyGems is required, Kernel#require is replaced with our own which
+  # is capable of loading gems on demand.
   #
-  # We replace Ruby's require with our own, which is capable of
-  # loading gems on demand.
-  #
   # When you call <tt>require 'x'</tt>, this is what happens:
   # * If the file can be loaded from the existing Ruby loadpath, it
   #   is.
@@ -22,11 +26,11 @@
   #
   # The normal <tt>require</tt> functionality of returning false if
   # that file has already been loaded is preserved.
-  #
-  def require(path) # :nodoc:
+
+  def require(path) # :doc:
     gem_original_require path
   rescue LoadError => load_error
-    if load_error.message =~ /\A[Nn]o such file to load -- #{Regexp.escape path}\z/ and
+    if load_error.message =~ /#{Regexp.escape path}\z/ and
        spec = Gem.searcher.find(path) then
       Gem.activate(spec.name, "= #{spec.version}")
       gem_original_require path
@@ -34,5 +38,9 @@
       raise load_error
     end
   end
-end  # module Kernel
 
+  private :require
+  private :gem_original_require
+
+end
+

Modified: MacRuby/branches/experimental/lib/rubygems/defaults.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/defaults.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/defaults.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,36 +1,56 @@
 module Gem
 
-  # An Array of the default sources that come with RubyGems.
+  @post_install_hooks   ||= []
+  @post_uninstall_hooks ||= []
+  @pre_uninstall_hooks  ||= []
+  @pre_install_hooks    ||= []
+
+  ##
+  # An Array of the default sources that come with RubyGems
+
   def self.default_sources
-    %w[http://gems.rubyforge.org]
+    %w[http://gems.rubyforge.org/]
   end
 
+  ##
   # Default home directory path to be used if an alternate value is not
-  # specified in the environment.
+  # specified in the environment
+
   def self.default_dir
     if defined? RUBY_FRAMEWORK_VERSION then
       File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
                 ConfigMap[:ruby_version]
-    elsif defined? RUBY_ENGINE then
-      File.join ConfigMap[:libdir], RUBY_ENGINE, 'gems',
-                ConfigMap[:ruby_version]
     else
-      File.join ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version]
+      ConfigMap[:sitelibdir].sub(%r'/site_ruby/(?=[^/]+)', '/gems/')
     end
   end
 
-  # Default gem path.
+  ##
+  # Path for gems in the user's home directory
+
+  def self.user_dir
+    File.join(Gem.user_home, '.gem', ruby_engine,
+              ConfigMap[:ruby_version])
+  end
+
+  ##
+  # Default gem load path
+
   def self.default_path
-    default_dir
+    [user_dir, default_dir]
   end
 
-  # Deduce Ruby's --program-prefix and --program-suffix from its install name.
+  ##
+  # Deduce Ruby's --program-prefix and --program-suffix from its install name
+
   def self.default_exec_format
     baseruby = ConfigMap[:BASERUBY] || 'ruby'
     ConfigMap[:RUBY_INSTALL_NAME].sub(baseruby, '%s') rescue '%s'
   end
 
+  ##
   # The default directory for binaries
+
   def self.default_bindir
     if defined? RUBY_FRAMEWORK_VERSION then # mac framework support
       '/usr/bin'
@@ -39,15 +59,30 @@
     end
   end
 
-  # The default system-wide source info cache directory.
+  ##
+  # The default system-wide source info cache directory
+
   def self.default_system_source_cache_dir
     File.join Gem.dir, 'source_cache'
   end
 
-  # The default user-specific source info cache directory.
+  ##
+  # The default user-specific source info cache directory
+
   def self.default_user_source_cache_dir
     File.join Gem.user_home, '.gem', 'source_cache'
   end
 
+  ##
+  # A wrapper around RUBY_ENGINE const that may not be defined
+
+  def self.ruby_engine
+    if defined? RUBY_ENGINE then
+      RUBY_ENGINE
+    else
+      'ruby'
+    end
+  end
+
 end
 

Modified: MacRuby/branches/experimental/lib/rubygems/dependency.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/dependency.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/dependency.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -8,24 +8,54 @@
 
 ##
 # The Dependency class holds a Gem name and a Gem::Requirement
+
 class Gem::Dependency
 
+  ##
+  # Valid dependency types.
+  #--
+  # When this list is updated, be sure to change
+  # Gem::Specification::CURRENT_SPECIFICATION_VERSION as well.
+
+  TYPES = [
+    :development,
+    :runtime,
+  ]
+
+  ##
+  # Dependency name or regular expression.
+
   attr_accessor :name
 
+  ##
+  # Dependency type.
+
+  attr_reader :type
+
+  ##
+  # Dependent versions.
+
   attr_writer :version_requirements
 
+  ##
+  # Orders dependencies by name only.
+
   def <=>(other)
     [@name] <=> [other.name]
   end
 
   ##
-  # Constructs the dependency
-  #
-  # name:: [String] name of the Gem
-  # version_requirements:: [String Array] version requirement (e.g. ["> 1.2"])
-  #
-  def initialize(name, version_requirements)
+  # Constructs a dependency with +name+ and +requirements+.
+
+  def initialize(name, version_requirements, type=:runtime)
     @name = name
+
+    unless TYPES.include? type
+      raise ArgumentError, "Valid types are #{TYPES.inspect}, not #{@type.inspect}"
+    end
+
+    @type = type
+
     @version_requirements = Gem::Requirement.create version_requirements
     @version_requirement = nil   # Avoid warnings.
   end
@@ -48,18 +78,42 @@
   end
 
   def to_s # :nodoc:
-    "#{name} (#{version_requirements})"
+    "#{name} (#{version_requirements}, #{@type || :runtime})"
   end
 
   def ==(other) # :nodoc:
     self.class === other &&
       self.name == other.name &&
+      self.type == other.type &&
       self.version_requirements == other.version_requirements
   end
 
-  def hash
-    name.hash + version_requirements.hash
+  ##
+  # Uses this dependency as a pattern to compare to the dependency +other+.
+  # This dependency will match if the name matches the other's name, and other
+  # has only an equal version requirement that satisfies this dependency.
+
+  def =~(other)
+    return false unless self.class === other
+
+    pattern = @name
+    pattern = /\A#{@name}\Z/ unless Regexp === pattern
+
+    return false unless pattern =~ other.name
+
+    reqs = other.version_requirements.requirements
+
+    return false unless reqs.length == 1
+    return false unless reqs.first.first == '='
+
+    version = reqs.first.last
+
+    version_requirements.satisfied_by? version
   end
 
+  def hash # :nodoc:
+    name.hash + type.hash + version_requirements.hash
+  end
+
 end
 

Modified: MacRuby/branches/experimental/lib/rubygems/dependency_installer.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/dependency_installer.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/dependency_installer.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,9 +1,12 @@
 require 'rubygems'
 require 'rubygems/dependency_list'
 require 'rubygems/installer'
-require 'rubygems/source_info_cache'
+require 'rubygems/spec_fetcher'
 require 'rubygems/user_interaction'
 
+##
+# Installs a gem along with all its dependencies from local and remote gems.
+
 class Gem::DependencyInstaller
 
   include Gem::UserInteraction
@@ -25,36 +28,52 @@
   # Creates a new installer instance.
   #
   # Options are:
-  # :env_shebang:: See Gem::Installer::new.
+  # :cache_dir:: Alternate repository path to store .gem files in.
   # :domain:: :local, :remote, or :both.  :local only searches gems in the
   #           current directory.  :remote searches only gems in Gem::sources.
   #           :both searches both.
+  # :env_shebang:: See Gem::Installer::new.
   # :force:: See Gem::Installer#install.
   # :format_executable:: See Gem::Installer#initialize.
-  # :ignore_dependencies: Don't install any dependencies.
-  # :install_dir: See Gem::Installer#install.
-  # :security_policy: See Gem::Installer::new and Gem::Security.
-  # :wrappers: See Gem::Installer::new
+  # :ignore_dependencies:: Don't install any dependencies.
+  # :install_dir:: See Gem::Installer#install.
+  # :security_policy:: See Gem::Installer::new and Gem::Security.
+  # :user_install:: See Gem::Installer.new
+  # :wrappers:: See Gem::Installer::new
+
   def initialize(options = {})
+    if options[:install_dir] then
+      spec_dir = options[:install_dir], 'specifications'
+      @source_index = Gem::SourceIndex.from_gems_in spec_dir
+    else
+      @source_index = Gem.source_index
+    end
+
     options = DEFAULT_OPTIONS.merge options
+
+    @bin_dir = options[:bin_dir]
+    @development = options[:development]
+    @domain = options[:domain]
     @env_shebang = options[:env_shebang]
-    @domain = options[:domain]
     @force = options[:force]
     @format_executable = options[:format_executable]
     @ignore_dependencies = options[:ignore_dependencies]
-    @install_dir = options[:install_dir] || Gem.dir
     @security_policy = options[:security_policy]
+    @user_install = options[:user_install]
     @wrappers = options[:wrappers]
-    @bin_dir = options[:bin_dir]
 
     @installed_gems = []
+
+    @install_dir = options[:install_dir] || Gem.dir
+    @cache_dir = options[:cache_dir] || @install_dir
   end
 
   ##
   # Returns a list of pairs of gemspecs and source_uris that match
   # Gem::Dependency +dep+ from both local (Dir.pwd) and remote (Gem.sources)
   # sources.  Gems are sorted with newer gems prefered over older gems, and
-  # local gems prefered over remote gems.
+  # local gems preferred over remote gems.
+
   def find_gems_with_sources(dep)
     gems_and_sources = []
 
@@ -74,8 +93,7 @@
         all = requirements.length > 1 ||
                 (requirements.first != ">=" and requirements.first != ">")
 
-        found = Gem::SourceInfoCache.search_with_source dep, true, all
-
+        found = Gem::SpecFetcher.fetcher.fetch dep, all
         gems_and_sources.push(*found)
 
       rescue Gem::RemoteFetcher::FetchError => e
@@ -95,6 +113,7 @@
   ##
   # Gathers all dependencies necessary for the installation from local and
   # remote sources unless the ignore_dependencies was given.
+
   def gather_dependencies
     specs = @specs_and_sources.map { |spec,_| spec }
 
@@ -110,14 +129,25 @@
         next if spec.nil? or seen[spec.name]
         seen[spec.name] = true
 
-        spec.dependencies.each do |dep|
-          results = find_gems_with_sources(dep).reverse # local gems first
+        deps = spec.runtime_dependencies
+        deps |= spec.development_dependencies if @development
 
+        deps.each do |dep|
+          results = find_gems_with_sources(dep).reverse
+
+          results.reject! do |dep_spec,|
+            to_do.push dep_spec
+
+            @source_index.any? do |_, installed_spec|
+              dep.name == installed_spec.name and
+                dep.version_requirements.satisfied_by? installed_spec.version
+            end
+          end
+
           results.each do |dep_spec, source_uri|
             next if seen[dep_spec.name]
             @specs_and_sources << [dep_spec, source_uri]
             dependency_list.add dep_spec
-            to_do.push dep_spec
           end
         end
       end
@@ -126,6 +156,11 @@
     @gems_to_install = dependency_list.dependency_order.reverse
   end
 
+  ##
+  # Finds a spec and the source_uri it came from for gem +gem_name+ and
+  # +version+.  Returns an Array of specs and sources required for
+  # installation of the gem.
+
   def find_spec_by_name_and_version gem_name, version = Gem::Requirement.default
     spec_and_source = nil
 
@@ -160,14 +195,16 @@
 
     if spec_and_source.nil? then
       raise Gem::GemNotFoundException,
-        "could not find #{gem_name} locally or in a repository"
+        "could not find gem #{gem_name} locally or in a repository"
     end
 
     @specs_and_sources = [spec_and_source]
   end
 
   ##
-  # Installs the gem and all its dependencies.
+  # Installs the gem and all its dependencies.  Returns an Array of installed
+  # gems specifications.
+
   def install dep_or_name, version = Gem::Requirement.default
     if String === dep_or_name then
       find_spec_by_name_and_version dep_or_name, version
@@ -175,15 +212,14 @@
       @specs_and_sources = [find_gems_with_sources(dep_or_name).last]
     end
 
+    @installed_gems = []
+
     gather_dependencies
 
-    spec_dir = File.join @install_dir, 'specifications'
-    source_index = Gem::SourceIndex.from_gems_in spec_dir
-
     @gems_to_install.each do |spec|
       last = spec == @gems_to_install.last
       # HACK is this test for full_name acceptable?
-      next if source_index.any? { |n,_| n == spec.full_name } and not last
+      next if @source_index.any? { |n,_| n == spec.full_name } and not last
 
       # TODO: make this sorta_verbose so other users can benefit from it
       say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose
@@ -191,26 +227,31 @@
       _, source_uri = @specs_and_sources.assoc spec
       begin
         local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri,
-                                                             @install_dir
+                                                             @cache_dir
       rescue Gem::RemoteFetcher::FetchError
         next if @force
         raise
       end
 
       inst = Gem::Installer.new local_gem_path,
-                                :env_shebang => @env_shebang,
-                                :force => @force,
-                                :format_executable => @format_executable,
+                                :bin_dir             => @bin_dir,
+                                :development         => @development,
+                                :env_shebang         => @env_shebang,
+                                :force               => @force,
+                                :format_executable   => @format_executable,
                                 :ignore_dependencies => @ignore_dependencies,
-                                :install_dir => @install_dir,
-                                :security_policy => @security_policy,
-                                :wrappers => @wrappers,
-                                :bin_dir => @bin_dir
+                                :install_dir         => @install_dir,
+                                :security_policy     => @security_policy,
+                                :source_index        => @source_index,
+                                :user_install        => @user_install,
+                                :wrappers            => @wrappers
 
       spec = inst.install
 
       @installed_gems << spec
     end
+
+    @installed_gems
   end
 
 end

Modified: MacRuby/branches/experimental/lib/rubygems/dependency_list.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/dependency_list.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/dependency_list.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -69,7 +69,7 @@
   # Are all the dependencies in the list satisfied?
   def ok?
     @specs.all? do |spec|
-      spec.dependencies.all? do |dep|
+      spec.runtime_dependencies.all? do |dep|
         @specs.find { |s| s.satisfies_requirement? dep }
       end
     end

Modified: MacRuby/branches/experimental/lib/rubygems/doc_manager.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/doc_manager.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/doc_manager.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -5,133 +5,195 @@
 #++
 
 require 'fileutils'
+require 'rubygems'
 
-module Gem
+##
+# The documentation manager generates RDoc and RI for RubyGems.
 
-  class DocManager
-  
-    include UserInteraction
-  
-    # Create a document manager for the given gem spec.
-    #
-    # spec::      The Gem::Specification object representing the gem.
-    # rdoc_args:: Optional arguments for RDoc (template etc.) as a String.
-    #
-    def initialize(spec, rdoc_args="")
-      @spec = spec
-      @doc_dir = File.join(spec.installation_path, "doc", spec.full_name)
-      @rdoc_args = rdoc_args.nil? ? [] : rdoc_args.split
+class Gem::DocManager
+
+  include Gem::UserInteraction
+
+  @configured_args = []
+
+  def self.configured_args
+    @configured_args ||= []
+  end
+
+  def self.configured_args=(args)
+    case args
+    when Array
+      @configured_args = args
+    when String
+      @configured_args = args.split
     end
-    
-    # Is the RDoc documentation installed?
-    def rdoc_installed?
-      return File.exist?(File.join(@doc_dir, "rdoc"))
+  end
+
+  ##
+  # Load RDoc from a gem if it is available, otherwise from Ruby's stdlib
+
+  def self.load_rdoc
+    begin
+      gem 'rdoc'
+    rescue Gem::LoadError
+      # use built-in RDoc
     end
-    
-    # Generate the RI documents for this gem spec.
-    #
-    # Note that if both RI and RDoc documents are generated from the
-    # same process, the RI docs should be done first (a likely bug in
-    # RDoc will cause RI docs generation to fail if run after RDoc).
-    def generate_ri
-      if @spec.has_rdoc then
-        load_rdoc
-        install_ri # RDoc bug, ri goes first
-      end
 
-      FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+    begin
+      require 'rdoc/rdoc'
+    rescue LoadError => e
+      raise Gem::DocumentError,
+          "ERROR: RDoc documentation generator not installed!"
     end
+  end
 
-    # Generate the RDoc documents for this gem spec.
-    #
-    # Note that if both RI and RDoc documents are generated from the
-    # same process, the RI docs should be done first (a likely bug in
-    # RDoc will cause RI docs generation to fail if run after RDoc).
-    def generate_rdoc
-      if @spec.has_rdoc then
-        load_rdoc
-        install_rdoc
-      end
+  ##
+  # Updates the RI cache for RDoc 2 if it is installed
 
-      FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
-    end
+  def self.update_ri_cache
+    load_rdoc rescue return
 
-    # Load the RDoc documentation generator library.
-    def load_rdoc
-      if File.exist?(@doc_dir) && !File.writable?(@doc_dir) then
-        raise Gem::FilePermissionError.new(@doc_dir)
-      end
+    return unless defined? RDoc::VERSION # RDoc 1 does not have VERSION
 
-      FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+    require 'rdoc/ri/driver'
 
-      begin
-        gem 'rdoc'
-      rescue Gem::LoadError
-        # use built-in RDoc
-      end
+    options = {
+      :use_cache => true,
+      :use_system => true,
+      :use_site => true,
+      :use_home => true,
+      :use_gems => true,
+      :formatter => RDoc::RI::Formatter,
+    }
 
-      begin
-        require 'rdoc/rdoc'
-      rescue LoadError => e
-        raise Gem::DocumentError,
-          "ERROR: RDoc documentation generator not installed!"
-      end
-    end
+    driver = RDoc::RI::Driver.new(options).class_cache
+  end
 
-    def install_rdoc
-      rdoc_dir = File.join @doc_dir, 'rdoc'
+  ##
+  # Create a document manager for +spec+. +rdoc_args+ contains arguments for
+  # RDoc (template etc.) as a String.
 
-      FileUtils.rm_rf rdoc_dir
+  def initialize(spec, rdoc_args="")
+    @spec = spec
+    @doc_dir = File.join(spec.installation_path, "doc", spec.full_name)
+    @rdoc_args = rdoc_args.nil? ? [] : rdoc_args.split
+  end
 
-      say "Installing RDoc documentation for #{@spec.full_name}..."
-      run_rdoc '--op', rdoc_dir
+  ##
+  # Is the RDoc documentation installed?
+
+  def rdoc_installed?
+    File.exist?(File.join(@doc_dir, "rdoc"))
+  end
+
+  ##
+  # Generate the RI documents for this gem spec.
+  #
+  # Note that if both RI and RDoc documents are generated from the same
+  # process, the RI docs should be done first (a likely bug in RDoc will cause
+  # RI docs generation to fail if run after RDoc).
+
+  def generate_ri
+    if @spec.has_rdoc then
+      setup_rdoc
+      install_ri # RDoc bug, ri goes first
     end
 
-    def install_ri
-      ri_dir = File.join @doc_dir, 'ri'
+    FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+  end
 
-      FileUtils.rm_rf ri_dir
+  ##
+  # Generate the RDoc documents for this gem spec.
+  #
+  # Note that if both RI and RDoc documents are generated from the same
+  # process, the RI docs should be done first (a likely bug in RDoc will cause
+  # RI docs generation to fail if run after RDoc).
 
-      say "Installing ri documentation for #{@spec.full_name}..."
-      run_rdoc '--ri', '--op', ri_dir
+  def generate_rdoc
+    if @spec.has_rdoc then
+      setup_rdoc
+      install_rdoc
     end
 
-    def run_rdoc(*args)
-      args << @spec.rdoc_options
-      args << DocManager.configured_args
-      args << '--quiet'
-      args << @spec.require_paths.clone
-      args << @spec.extra_rdoc_files
-      args.flatten!
+    FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
+  end
 
-      r = RDoc::RDoc.new
+  ##
+  # Generate and install RDoc into the documentation directory
 
-      old_pwd = Dir.pwd
-      Dir.chdir(@spec.full_gem_path)
-      begin
-        r.document args
-      rescue Errno::EACCES => e
-        dirname = File.dirname e.message.split("-")[1].strip
-        raise Gem::FilePermissionError.new(dirname)
-      rescue RuntimeError => ex
-        alert_error "While generating documentation for #{@spec.full_name}"
-        ui.errs.puts "... MESSAGE:   #{ex}"
-        ui.errs.puts "... RDOC args: #{args.join(' ')}"
-        ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
-          Gem.configuration.backtrace
-        ui.errs.puts "(continuing with the rest of the installation)"
-      ensure
-        Dir.chdir(old_pwd)
-      end
+  def install_rdoc
+    rdoc_dir = File.join @doc_dir, 'rdoc'
+
+    FileUtils.rm_rf rdoc_dir
+
+    say "Installing RDoc documentation for #{@spec.full_name}..."
+    run_rdoc '--op', rdoc_dir
+  end
+
+  ##
+  # Generate and install RI into the documentation directory
+
+  def install_ri
+    ri_dir = File.join @doc_dir, 'ri'
+
+    FileUtils.rm_rf ri_dir
+
+    say "Installing ri documentation for #{@spec.full_name}..."
+    run_rdoc '--ri', '--op', ri_dir
+  end
+
+  ##
+  # Run RDoc with +args+, which is an ARGV style argument list
+
+  def run_rdoc(*args)
+    args << @spec.rdoc_options
+    args << self.class.configured_args
+    args << '--quiet'
+    args << @spec.require_paths.clone
+    args << @spec.extra_rdoc_files
+    args = args.flatten.map do |arg| arg.to_s end
+
+    r = RDoc::RDoc.new
+
+    old_pwd = Dir.pwd
+    Dir.chdir(@spec.full_gem_path)
+    begin
+      r.document args
+    rescue Errno::EACCES => e
+      dirname = File.dirname e.message.split("-")[1].strip
+      raise Gem::FilePermissionError.new(dirname)
+    rescue RuntimeError => ex
+      alert_error "While generating documentation for #{@spec.full_name}"
+      ui.errs.puts "... MESSAGE:   #{ex}"
+      ui.errs.puts "... RDOC args: #{args.join(' ')}"
+      ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
+      Gem.configuration.backtrace
+      ui.errs.puts "(continuing with the rest of the installation)"
+    ensure
+      Dir.chdir(old_pwd)
     end
+  end
 
-    def uninstall_doc
-      raise Gem::FilePermissionError.new(@spec.installation_path) unless
-        File.writable? @spec.installation_path
+  def setup_rdoc
+    if File.exist?(@doc_dir) && !File.writable?(@doc_dir) then
+      raise Gem::FilePermissionError.new(@doc_dir)
+    end
 
-      original_name = [
-        @spec.name, @spec.version, @spec.original_platform].join '-'
+    FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
 
+    self.class.load_rdoc
+  end
+
+  ##
+  # Remove RDoc and RI documentation
+
+  def uninstall_doc
+    raise Gem::FilePermissionError.new(@spec.installation_path) unless
+    File.writable? @spec.installation_path
+
+    original_name = [
+      @spec.name, @spec.version, @spec.original_platform].join '-'
+
       doc_dir = File.join @spec.installation_path, 'doc', @spec.full_name
       unless File.directory? doc_dir then
         doc_dir = File.join @spec.installation_path, 'doc', original_name
@@ -146,22 +208,7 @@
       end
 
       FileUtils.rm_rf ri_dir
-    end
+  end
 
-    class << self
-      def configured_args
-        @configured_args ||= []
-      end
+end
 
-      def configured_args=(args)
-        case args
-        when Array
-          @configured_args = args
-        when String
-          @configured_args = args.split
-        end
-      end
-    end
-    
-  end
-end

Modified: MacRuby/branches/experimental/lib/rubygems/ext/builder.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/ext/builder.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/ext/builder.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -35,7 +35,7 @@
       results << `#{cmd} #{redirector}`
 
       raise Gem::InstallError, "make#{target} failed:\n\n#{results}" unless
-        $?.exitstatus.zero?
+        $?.success?
     end
   end
 
@@ -47,7 +47,7 @@
     results << command
     results << `#{command} #{redirector}`
 
-    unless $?.exitstatus.zero? then
+    unless $?.success? then
       raise Gem::InstallError, "#{class_name} failed:\n\n#{results.join "\n"}"
     end
   end

Modified: MacRuby/branches/experimental/lib/rubygems/ext/rake_builder.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/ext/rake_builder.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/ext/rake_builder.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -16,7 +16,7 @@
     end
 
     cmd = ENV['rake'] || 'rake'
-    cmd << " RUBYARCHDIR=#{dest_path} RUBYLIBDIR=#{dest_path}"
+    cmd += " RUBYARCHDIR=#{dest_path} RUBYLIBDIR=#{dest_path}" # ENV is frozen
 
     run cmd, results
 

Modified: MacRuby/branches/experimental/lib/rubygems/gem_openssl.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/gem_openssl.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/gem_openssl.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -17,7 +17,7 @@
       @ssl_available
     end
 
-    # Set the value of the ssl_avilable flag.
+    # Set the value of the ssl_available flag.
     attr_writer :ssl_available
 
     # Ensure that SSL is available.  Throw an exception if it is not.

Modified: MacRuby/branches/experimental/lib/rubygems/gem_path_searcher.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/gem_path_searcher.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/gem_path_searcher.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,15 +6,15 @@
 
 require 'rubygems'
 
-#
+##
 # GemPathSearcher has the capability to find loadable files inside
 # gems.  It generates data up front to speed up searches later.
-#
+
 class Gem::GemPathSearcher
 
-  #
+  ##
   # Initialise the data we need to make searches later.
-  #
+
   def initialize
     # We want a record of all the installed gemspecs, in the order
     # we wish to examine them.
@@ -27,7 +27,7 @@
     end
   end
 
-  # 
+  ##
   # Look in all the installed gems until a matching _path_ is found.
   # Return the _gemspec_ of the gem where it was found.  If no match
   # is found, return nil.
@@ -46,36 +46,52 @@
   # others), which may or may not already be attached to _file_.
   # This method doesn't care about the full filename that matches;
   # only that there is a match.
-  # 
+
   def find(path)
-    @gemspecs.each do |spec|
-      return spec if matching_file(spec, path)
+    @gemspecs.find do |spec| matching_file? spec, path end
+  end
+
+  ##
+  # Works like #find, but finds all gemspecs matching +path+.
+
+  def find_all(path)
+    @gemspecs.select do |spec|
+      matching_file? spec, path
     end
-    nil
   end
 
-  private
+  ##
+  # Attempts to find a matching path using the require_paths of the given
+  # +spec+.
 
-  # Attempts to find a matching path using the require_paths of the
-  # given _spec_.
-  #
-  # Some of the intermediate results are cached in @lib_dirs for
-  # speed.
-  def matching_file(spec, path)  # :doc:
+  def matching_file?(spec, path)
+    !matching_files(spec, path).empty?
+  end
+
+  ##
+  # Returns files matching +path+ in +spec+.
+  #--
+  # Some of the intermediate results are cached in @lib_dirs for speed.
+
+  def matching_files(spec, path)
     glob = File.join @lib_dirs[spec.object_id], "#{path}#{Gem.suffix_pattern}"
-    return true unless Dir[glob].select { |f| File.file?(f.untaint) }.empty?
+    Dir[glob].select { |f| File.file? f.untaint }
   end
 
-  # Return a list of all installed gemspecs, sorted by alphabetical
-  # order and in reverse version order.
+  ##
+  # Return a list of all installed gemspecs, sorted by alphabetical order and
+  # in reverse version order.
+
   def init_gemspecs
     Gem.source_index.map { |_, spec| spec }.sort { |a,b|
       (a.name <=> b.name).nonzero? || (b.version <=> a.version)
     }
   end
 
+  ##
   # Returns library directories glob for a gemspec.  For example,
   #   '/usr/local/lib/ruby/gems/1.8/gems/foobar-1.0/{lib,ext}'
+
   def lib_dirs_for(spec)
     "#{spec.full_gem_path}/{#{spec.require_paths.join(',')}}"
   end

Modified: MacRuby/branches/experimental/lib/rubygems/indexer.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/indexer.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/indexer.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,5 +1,6 @@
 require 'fileutils'
 require 'tmpdir'
+require 'zlib'
 
 require 'rubygems'
 require 'rubygems/format'
@@ -40,125 +41,324 @@
 
     marshal_name = "Marshal.#{Gem.marshal_version}"
 
-    @master_index = Gem::Indexer::MasterIndexBuilder.new "yaml", @directory
-    @marshal_index = Gem::Indexer::MarshalIndexBuilder.new marshal_name, @directory
-    @quick_index = Gem::Indexer::QuickIndexBuilder.new 'index', @directory
+    @master_index = File.join @directory, 'yaml'
+    @marshal_index = File.join @directory, marshal_name
 
-    quick_dir = File.join @directory, 'quick'
-    @latest_index = Gem::Indexer::LatestIndexBuilder.new 'latest_index', quick_dir
+    @quick_dir = File.join @directory, 'quick'
+
+    @quick_marshal_dir = File.join @quick_dir, marshal_name
+
+    @quick_index = File.join @quick_dir, 'index'
+    @latest_index = File.join @quick_dir, 'latest_index'
+
+    @specs_index = File.join @directory, "specs.#{Gem.marshal_version}"
+    @latest_specs_index = File.join @directory,
+                                    "latest_specs.#{Gem.marshal_version}"
+
+    files = [
+      @specs_index,
+      "#{@specs_index}.gz",
+      @latest_specs_index,
+      "#{@latest_specs_index}.gz",
+      @quick_dir,
+      @master_index,
+      "#{@master_index}.Z",
+      @marshal_index,
+      "#{@marshal_index}.Z",
+    ]
+
+    @files = files.map do |path|
+      path.sub @directory, ''
+    end
   end
 
   ##
-  # Build the index.
+  # Abbreviate the spec for downloading.  Abbreviated specs are only used for
+  # searching, downloading and related activities and do not need deployment
+  # specific information (e.g. list of files).  So we abbreviate the spec,
+  # making it much smaller for quicker downloads.
 
-  def build_index
-    @master_index.build do
-      @quick_index.build do
-        @marshal_index.build do
-          @latest_index.build do
-            progress = ui.progress_reporter gem_file_list.size,
-                                          "Generating index for #{gem_file_list.size} gems in #{@dest_directory}",
-                                          "Loaded all gems"
+  def abbreviate(spec)
+    spec.files = []
+    spec.test_files = []
+    spec.rdoc_options = []
+    spec.extra_rdoc_files = []
+    spec.cert_chain = []
+    spec
+  end
 
-                                          gem_file_list.each do |gemfile|
-              if File.size(gemfile.to_s) == 0 then
-                alert_warning "Skipping zero-length gem: #{gemfile}"
-                next
-              end
+  ##
+  # Build various indicies
 
-              begin
-                spec = Gem::Format.from_file_by_path(gemfile).spec
+  def build_indicies(index)
+    progress = ui.progress_reporter index.size,
+                                    "Generating quick index gemspecs for #{index.size} gems",
+                                    "Complete"
 
-                unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
-                  alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
-                  next
-                end
+    index.each do |original_name, spec|
+      spec_file_name = "#{original_name}.gemspec.rz"
+      yaml_name = File.join @quick_dir, spec_file_name
+      marshal_name = File.join @quick_marshal_dir, spec_file_name
 
-                abbreviate spec
-                sanitize spec
+      yaml_zipped = Gem.deflate spec.to_yaml
+      open yaml_name, 'wb' do |io| io.write yaml_zipped end
 
-                @master_index.add spec
-                @quick_index.add spec
-                @marshal_index.add spec
-                @latest_index.add spec
+      marshal_zipped = Gem.deflate Marshal.dump(spec)
+      open marshal_name, 'wb' do |io| io.write marshal_zipped end
 
-                progress.updated spec.original_name
+      progress.updated original_name
+    end
 
-              rescue SignalException => e
-                alert_error "Received signal, exiting"
-                raise
-              rescue Exception => e
-                alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
-              end
-                                          end
+    progress.done
 
-            progress.done
+    say "Generating specs index"
 
-            say "Generating master indexes (this may take a while)"
-          end
+    open @specs_index, 'wb' do |io|
+      specs = index.sort.map do |_, spec|
+        platform = spec.original_platform
+        platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
+        [spec.name, spec.version, platform]
+      end
+
+      specs = compact_specs specs
+
+      Marshal.dump specs, io
+    end
+
+    say "Generating latest specs index"
+
+    open @latest_specs_index, 'wb' do |io|
+      specs = index.latest_specs.sort.map do |spec|
+        platform = spec.original_platform
+        platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
+        [spec.name, spec.version, platform]
+      end
+
+      specs = compact_specs specs
+
+      Marshal.dump specs, io
+    end
+
+    say "Generating quick index"
+
+    quick_index = File.join @quick_dir, 'index'
+    open quick_index, 'wb' do |io|
+      io.puts index.sort.map { |_, spec| spec.original_name }
+    end
+
+    say "Generating latest index"
+
+    latest_index = File.join @quick_dir, 'latest_index'
+    open latest_index, 'wb' do |io|
+      io.puts index.latest_specs.sort.map { |spec| spec.original_name }
+    end
+
+    say "Generating Marshal master index"
+
+    open @marshal_index, 'wb' do |io|
+      io.write index.dump
+    end
+
+    progress = ui.progress_reporter index.size,
+                                    "Generating YAML master index for #{index.size} gems (this may take a while)",
+                                    "Complete"
+
+    open @master_index, 'wb' do |io|
+      io.puts "--- !ruby/object:#{index.class}"
+      io.puts "gems:"
+
+      gems = index.sort_by { |name, gemspec| gemspec.sort_obj }
+      gems.each do |original_name, gemspec|
+        yaml = gemspec.to_yaml.gsub(/^/, '    ')
+        yaml = yaml.sub(/\A    ---/, '') # there's a needed extra ' ' here
+        io.print "  #{original_name}:"
+        io.puts yaml
+
+        progress.updated original_name
+      end
+    end
+
+    progress.done
+
+    say "Compressing indicies"
+    # use gzip for future files.
+
+    compress quick_index, 'rz'
+    paranoid quick_index, 'rz'
+
+    compress latest_index, 'rz'
+    paranoid latest_index, 'rz'
+
+    compress @marshal_index, 'Z'
+    paranoid @marshal_index, 'Z'
+
+    compress @master_index, 'Z'
+    paranoid @master_index, 'Z'
+
+    gzip @specs_index
+    gzip @latest_specs_index
+  end
+
+  ##
+  # Collect specifications from .gem files from the gem directory.
+
+  def collect_specs
+    index = Gem::SourceIndex.new
+
+    progress = ui.progress_reporter gem_file_list.size,
+                                    "Loading #{gem_file_list.size} gems from #{@dest_directory}",
+                                    "Loaded all gems"
+
+    gem_file_list.each do |gemfile|
+      if File.size(gemfile.to_s) == 0 then
+        alert_warning "Skipping zero-length gem: #{gemfile}"
+        next
+      end
+
+      begin
+        spec = Gem::Format.from_file_by_path(gemfile).spec
+
+        unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
+          alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
+          next
         end
+
+        abbreviate spec
+        sanitize spec
+
+        index.gems[spec.original_name] = spec
+
+        progress.updated spec.original_name
+
+      rescue SignalException => e
+        alert_error "Received signal, exiting"
+        raise
+      rescue Exception => e
+        alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
       end
     end
+
+    progress.done
+
+    index
   end
 
-  def install_index
+  ##
+  # Compacts Marshal output for the specs index data source by using identical
+  # objects as much as possible.
+
+  def compact_specs(specs)
+    names = {}
+    versions = {}
+    platforms = {}
+
+    specs.map do |(name, version, platform)|
+      names[name] = name unless names.include? name
+      versions[version] = version unless versions.include? version
+      platforms[platform] = platform unless platforms.include? platform
+
+      [names[name], versions[version], platforms[platform]]
+    end
+  end
+
+  ##
+  # Compress +filename+ with +extension+.
+
+  def compress(filename, extension)
+    data = Gem.read_binary filename
+
+    zipped = Gem.deflate data
+
+    open "#{filename}.#{extension}", 'wb' do |io|
+      io.write zipped
+    end
+  end
+
+  ##
+  # List of gem file names to index.
+
+  def gem_file_list
+    Dir.glob(File.join(@dest_directory, "gems", "*.gem"))
+  end
+
+  ##
+  # Builds and installs indexicies.
+
+  def generate_index
+    make_temp_directories
+    index = collect_specs
+    build_indicies index
+    install_indicies
+  rescue SignalException
+  ensure
+    FileUtils.rm_rf @directory
+  end
+
+   ##
+  # Zlib::GzipWriter wrapper that gzips +filename+ on disk.
+
+  def gzip(filename)
+    Zlib::GzipWriter.open "#{filename}.gz" do |io|
+      io.write Gem.read_binary(filename)
+    end
+  end
+
+  ##
+  # Install generated indicies into the destination directory.
+
+  def install_indicies
     verbose = Gem.configuration.really_verbose
 
     say "Moving index into production dir #{@dest_directory}" if verbose
 
-    files = @master_index.files + @quick_index.files + @marshal_index.files +
-            @latest_index.files
-
-    files.each do |file|
+    @files.each do |file|
       src_name = File.join @directory, file
       dst_name = File.join @dest_directory, file
 
       FileUtils.rm_rf dst_name, :verbose => verbose
-      FileUtils.mv src_name, @dest_directory, :verbose => verbose
+      FileUtils.mv src_name, @dest_directory, :verbose => verbose,
+                   :force => true
     end
   end
 
-  def generate_index
+  ##
+  # Make directories for index generation
+
+  def make_temp_directories
     FileUtils.rm_rf @directory
     FileUtils.mkdir_p @directory, :mode => 0700
-
-    build_index
-    install_index
-  rescue SignalException
-  ensure
-    FileUtils.rm_rf @directory
+    FileUtils.mkdir_p @quick_marshal_dir
   end
 
-  # List of gem file names to index.
-  def gem_file_list
-    Dir.glob(File.join(@dest_directory, "gems", "*.gem"))
-  end
+  ##
+  # Ensure +path+ and path with +extension+ are identical.
 
-  # Abbreviate the spec for downloading.  Abbreviated specs are only
-  # used for searching, downloading and related activities and do not
-  # need deployment specific information (e.g. list of files).  So we
-  # abbreviate the spec, making it much smaller for quicker downloads.
-  def abbreviate(spec)
-    spec.files = []
-    spec.test_files = []
-    spec.rdoc_options = []
-    spec.extra_rdoc_files = []
-    spec.cert_chain = []
-    spec
+  def paranoid(path, extension)
+    data = Gem.read_binary path
+    compressed_data = Gem.read_binary "#{path}.#{extension}"
+
+    unless data == Gem.inflate(compressed_data) then
+      raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
+    end
   end
 
+  ##
   # Sanitize the descriptive fields in the spec.  Sometimes non-ASCII
   # characters will garble the site index.  Non-ASCII characters will
   # be replaced by their XML entity equivalent.
+
   def sanitize(spec)
     spec.summary = sanitize_string(spec.summary)
     spec.description = sanitize_string(spec.description)
     spec.post_install_message = sanitize_string(spec.post_install_message)
     spec.authors = spec.authors.collect { |a| sanitize_string(a) }
+
     spec
   end
 
+  ##
   # Sanitize a single string.
+
   def sanitize_string(string)
     # HACK the #to_s is in here because RSpec has an Array of Arrays of
     # Strings for authors.  Need a way to disallow bad values on gempsec
@@ -168,9 +368,3 @@
 
 end
 
-require 'rubygems/indexer/abstract_index_builder'
-require 'rubygems/indexer/master_index_builder'
-require 'rubygems/indexer/quick_index_builder'
-require 'rubygems/indexer/marshal_index_builder'
-require 'rubygems/indexer/latest_index_builder'
-

Modified: MacRuby/branches/experimental/lib/rubygems/install_update_options.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/install_update_options.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/install_update_options.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -89,6 +89,19 @@
                'foo_exec18') do |value, options|
       options[:format_executable] = value
     end
+
+    add_option(:"Install/Update",       '--[no-]user-install',
+               'Install in user\'s home directory instead',
+               'of GEM_HOME. Defaults to using home directory',
+               'only if GEM_HOME is not writable.') do |value, options|
+      options[:user_install] = value
+    end
+
+    add_option(:"Install/Update", "--development",
+                "Install any additional development",
+                "dependencies") do |value, options|
+      options[:development] = true
+    end
   end
 
   # Default options for the gem install command.

Modified: MacRuby/branches/experimental/lib/rubygems/installer.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/installer.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/installer.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -20,6 +20,7 @@
 # filesystem including unpacking the gem into its gem dir, installing the
 # gemspec in the specifications dir, storing the cached gem in the cache dir,
 # and installing either wrappers or symlinks for executables.
+
 class Gem::Installer
 
   ##
@@ -31,8 +32,36 @@
 
   include Gem::RequirePathsBuilder
 
+  ##
+  # The directory a gem's executables will be installed into
+
+  attr_reader :bin_dir
+
+  ##
+  # The gem repository the gem will be installed into
+
+  attr_reader :gem_home
+
+  ##
+  # The Gem::Specification for the gem being installed
+
+  attr_reader :spec
+
+  @home_install_warning = false
+  @path_warning = false
+
   class << self
 
+    ##
+    # True if we've warned about ~/.gems install
+
+    attr_accessor :home_install_warning
+
+    ##
+    # True if we've warned about PATH not including Gem.bindir
+
+    attr_accessor :path_warning
+
     attr_writer :exec_format
 
     # Defaults to use Ruby's program prefix and suffix.
@@ -56,15 +85,17 @@
   #                      foo_exec18.
   # :security_policy:: Use the specified security policy.  See Gem::Security
   # :wrappers:: Install wrappers if true, symlinks if false.
+
   def initialize(gem, options={})
     @gem = gem
 
     options = {
-      :force => false,
-      :install_dir => Gem.dir,
-      :exec_format => false,
-      :env_shebang => false,
-      :bin_dir => nil
+      :bin_dir      => nil,
+      :env_shebang  => false,
+      :exec_format  => false,
+      :force        => false,
+      :install_dir  => Gem.dir,
+      :source_index => Gem.source_index,
     }.merge options
 
     @env_shebang = options[:env_shebang]
@@ -76,6 +107,8 @@
     @security_policy = options[:security_policy]
     @wrappers = options[:wrappers]
     @bin_dir = options[:bin_dir]
+    @development = options[:development]
+    @source_index = options[:source_index]
 
     begin
       @format = Gem::Format.from_file_by_path @gem, @security_policy
@@ -83,6 +116,43 @@
       raise Gem::InstallError, "invalid gem format for #{@gem}"
     end
 
+    begin
+      FileUtils.mkdir_p @gem_home
+    rescue Errno::EACCES, Errno::ENOTDIR
+      # We'll divert to ~/.gem below
+    end
+
+    if not File.writable? @gem_home or
+        # TODO: Shouldn't have to test for existence of bindir; tests need it.
+        (@gem_home.to_s == Gem.dir and File.exist? Gem.bindir and
+         not File.writable? Gem.bindir) then
+      if options[:user_install] == false then # You don't want to use ~
+        raise Gem::FilePermissionError, @gem_home
+      elsif options[:user_install].nil? then
+        unless self.class.home_install_warning then
+          alert_warning "Installing to ~/.gem since #{@gem_home} and\n\t  #{Gem.bindir} aren't both writable."
+          self.class.home_install_warning = true
+        end
+      end
+      options[:user_install] = true
+    end
+
+    if options[:user_install] and not options[:unpack] then
+      @gem_home = Gem.user_dir
+
+      user_bin_dir = File.join(@gem_home, 'bin')
+      unless ENV['PATH'].split(File::PATH_SEPARATOR).include? user_bin_dir then
+        unless self.class.path_warning then
+          alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t  gem executables will not run."
+          self.class.path_warning = true
+        end
+      end
+
+      FileUtils.mkdir_p @gem_home unless File.directory? @gem_home
+      # If it's still not writable, you've got issues.
+      raise Gem::FilePermissionError, @gem_home unless File.writable? @gem_home
+    end
+
     @spec = @format.spec
 
     @gem_dir = File.join(@gem_home, "gems", @spec.full_name).untaint
@@ -98,6 +168,7 @@
   #     cache/<gem-version>.gem #=> a cached copy of the installed gem
   #     gems/<gem-version>/... #=> extracted files
   #     specifications/<gem-version>.gemspec #=> the Gem::Specification
+
   def install
     # If we're forcing the install then disable security unless the security
     # policy says that we only install singed gems.
@@ -119,14 +190,20 @@
       end
 
       unless @ignore_dependencies then
-        @spec.dependencies.each do |dep_gem|
+        deps = @spec.runtime_dependencies
+        deps |= @spec.development_dependencies if @development
+
+        deps.each do |dep_gem|
           ensure_dependency @spec, dep_gem
         end
       end
     end
 
+    Gem.pre_install_hooks.each do |hook|
+      hook.call self
+    end
+
     FileUtils.mkdir_p @gem_home unless File.directory? @gem_home
-    raise Gem::FilePermissionError, @gem_home unless File.writable? @gem_home
 
     Gem.ensure_gem_subdirectories @gem_home
 
@@ -150,6 +227,12 @@
     @spec.loaded_from = File.join(@gem_home, 'specifications',
                                   "#{@spec.full_name}.gemspec")
 
+    @source_index.add_spec @spec
+
+    Gem.post_install_hooks.each do |hook|
+      hook.call self
+    end
+
     return @spec
   rescue Zlib::GzipFile::Error
     raise Gem::InstallError, "gzip error installing #{@gem}"
@@ -161,6 +244,7 @@
   #
   # spec       :: Gem::Specification
   # dependency :: Gem::Dependency
+
   def ensure_dependency(spec, dependency)
     unless installation_satisfies_dependency? dependency then
       raise Gem::InstallError, "#{spec.name} requires #{dependency}"
@@ -170,17 +254,15 @@
   end
 
   ##
-  # True if the current installed gems satisfy the given dependency.
-  #
-  # dependency :: Gem::Dependency
+  # True if the gems in the source_index satisfy +dependency+.
+
   def installation_satisfies_dependency?(dependency)
-    current_index = Gem::SourceIndex.from_installed_gems
-    current_index.find_name(dependency.name, dependency.version_requirements).size > 0
+    @source_index.find_name(dependency.name, dependency.version_requirements).size > 0
   end
 
   ##
   # Unpacks the gem into the given directory.
-  #
+
   def unpack(directory)
     @gem_dir = directory
     @format = Gem::Format.from_file_by_path @gem, @security_policy
@@ -188,17 +270,15 @@
   end
 
   ##
-  # Writes the .gemspec specification (in Ruby) to the supplied
-  # spec_path.
-  #
-  # spec:: [Gem::Specification] The Gem specification to output
-  # spec_path:: [String] The location (path) to write the gemspec to
-  #
+  # Writes the .gemspec specification (in Ruby) to the gem home's
+  # specifications directory.
+
   def write_spec
     rubycode = @spec.to_ruby
 
     file_name = File.join @gem_home, 'specifications',
                           "#{@spec.full_name}.gemspec"
+
     file_name.untaint
 
     File.open(file_name, "w") do |file|
@@ -208,7 +288,7 @@
 
   ##
   # Creates windows .bat files for easy running of commands
-  #
+
   def generate_windows_script(bindir, filename)
     if Gem.win_platform? then
       script_name = filename + ".bat"
@@ -227,7 +307,7 @@
     # If the user has asked for the gem to be installed in a directory that is
     # the system gem directory, then use the system bin directory, else create
     # (or use) a new bin dir under the gem_home.
-    bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
+    bindir = @bin_dir ? @bin_dir : Gem.bindir(@gem_home)
 
     Dir.mkdir bindir unless File.exist? bindir
     raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
@@ -252,7 +332,7 @@
   # The Windows script is generated in addition to the regular one due to a
   # bug or misfeature in the Windows shell's pipe.  See
   # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379
-  #
+
   def generate_bin_script(filename, bindir)
     bin_script_path = File.join bindir, formatted_program_filename(filename)
 
@@ -260,6 +340,8 @@
 
     # HACK some gems don't have #! in their executables, restore 2008/06
     #if File.read(exec_path, 2) == '#!' then
+      FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
+
       File.open bin_script_path, 'w', 0755 do |file|
         file.print app_script_text(filename)
       end
@@ -277,7 +359,7 @@
   ##
   # Creates the symlinks to run the applications in the gem.  Moves
   # the symlink if the gem being installed has a newer version.
-  #
+
   def generate_bin_symlink(filename, bindir)
     if Gem.win_platform? then
       alert_warning "Unable to use symlinks on Windows, installing wrapper"
@@ -303,6 +385,7 @@
   ##
   # Generates a #! line for +bin_file_name+'s wrapper copying arguments if
   # necessary.
+
   def shebang(bin_file_name)
     if @env_shebang then
       "#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
@@ -324,7 +407,9 @@
     end
   end
 
+  ##
   # Return the text for an application file.
+
   def app_script_text(bin_file_name)
     <<-TEXT
 #{shebang bin_file_name}
@@ -349,7 +434,9 @@
 TEXT
   end
 
+  ##
   # return the stub script text used to launch the true ruby script
+
   def windows_stub_script(bindir, bin_file_name)
     <<-TEXT
 @ECHO OFF
@@ -361,8 +448,10 @@
 TEXT
   end
 
+  ##
   # Builds extensions.  Valid types of extensions are extconf.rb files,
   # configure scripts and rakefiles or mkrf_conf files.
+
   def build_extensions
     return if @spec.extensions.empty?
     say "Building native extensions.  This could take a while..."
@@ -418,6 +507,7 @@
   # Reads the file index and extracts each file into the gem directory.
   #
   # Ensures that files can't be installed outside the gem directory.
+
   def extract_files
     expand_and_validate_gem_dir
 
@@ -445,11 +535,15 @@
         out.write file_data
       end
 
+      FileUtils.chmod entry['mode'], path
+
       say path if Gem.configuration.really_verbose
     end
   end
 
+  ##
   # Prefix and suffix the program filename the same as ruby.
+
   def formatted_program_filename(filename)
     if @format_executable then
       self.class.exec_format % File.basename(filename)
@@ -460,7 +554,9 @@
 
   private
 
+  ##
   # HACK Pathname is broken on windows.
+
   def absolute_path? pathname
     pathname.absolute? or (Gem.win_platform? and pathname.to_s =~ /\A[a-z]:/i)
   end

Modified: MacRuby/branches/experimental/lib/rubygems/local_remote_options.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/local_remote_options.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/local_remote_options.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -4,27 +4,34 @@
 # See LICENSE.txt for permissions.
 #++
 
+require 'uri'
 require 'rubygems'
 
+##
 # Mixin methods for local and remote Gem::Command options.
+
 module Gem::LocalRemoteOptions
 
+  ##
   # Allows OptionParser to handle HTTP URIs.
+
   def accept_uri_http
     OptionParser.accept URI::HTTP do |value|
       begin
-        value = URI.parse value
+        uri = URI.parse value
       rescue URI::InvalidURIError
         raise OptionParser::InvalidArgument, value
       end
 
-      raise OptionParser::InvalidArgument, value unless value.scheme == 'http'
+      raise OptionParser::InvalidArgument, value unless uri.scheme == 'http'
 
       value
     end
   end
 
+  ##
   # Add local/remote options to the command line parser.
+
   def add_local_remote_options
     add_option(:"Local/Remote", '-l', '--local',
                'Restrict operations to the LOCAL domain') do |value, options|
@@ -47,7 +54,9 @@
     add_update_sources_option
   end
 
+  ##
   # Add the --bulk-threshold option
+
   def add_bulk_threshold_option
     add_option(:"Local/Remote", '-B', '--bulk-threshold COUNT',
                "Threshold for switching to bulk",
@@ -57,7 +66,9 @@
     end
   end
 
+  ##
   # Add the --http-proxy option
+
   def add_proxy_option
     accept_uri_http
 
@@ -68,22 +79,28 @@
     end
   end
 
+  ##
   # Add the --source option
+
   def add_source_option
     accept_uri_http
 
     add_option(:"Local/Remote", '--source URL', URI::HTTP,
-               'Use URL as the remote source for gems') do |value, options|
+               'Use URL as the remote source for gems') do |source, options|
+      source << '/' if source !~ /\/\z/
+
       if options[:added_source] then
-        Gem.sources << value
+        Gem.sources << source
       else
         options[:added_source] = true
-        Gem.sources.replace [value]
+        Gem.sources.replace [source]
       end
     end
   end
 
-  # Add the --source option
+  ##
+  # Add the --update-source option
+
   def add_update_sources_option
 
     add_option(:"Local/Remote", '-u', '--[no-]update-sources',
@@ -92,12 +109,23 @@
     end
   end
 
+  ##
+  # Is fetching of local and remote information enabled?
+
+  def both?
+    options[:domain] == :both
+  end
+
+  ##
   # Is local fetching enabled?
+
   def local?
     options[:domain] == :local || options[:domain] == :both
   end
 
+  ##
   # Is remote fetching enabled?
+
   def remote?
     options[:domain] == :remote || options[:domain] == :both
   end

Modified: MacRuby/branches/experimental/lib/rubygems/package/tar_reader.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/package/tar_reader.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/package/tar_reader.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -46,17 +46,17 @@
       yield entry
 
       skip = (512 - (size % 512)) % 512
+      pending = size - entry.bytes_read
 
-      if @io.respond_to? :seek then
+      begin
         # avoid reading...
-        @io.seek(size - entry.bytes_read, IO::SEEK_CUR)
-      else
-        pending = size - entry.bytes_read
-
+        @io.seek pending, IO::SEEK_CUR
+        pending = 0
+      rescue Errno::EINVAL, NameError
         while pending > 0 do
-          bread = @io.read([pending, 4096].min).size
+          bytes_read = @io.read([pending, 4096].min).size
           raise UnexpectedEOF if @io.eof?
-          pending -= bread
+          pending -= bytes_read
         end
       end
 

Modified: MacRuby/branches/experimental/lib/rubygems/platform.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/platform.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/platform.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,8 @@
 require 'rubygems'
 
+##
 # Available list of platforms for targeting Gem installations.
-#
+
 class Gem::Platform
 
   @local = nil
@@ -12,23 +13,6 @@
 
   attr_accessor :version
 
-  DEPRECATED_CONSTS = [
-    :DARWIN,
-    :LINUX_586,
-    :MSWIN32,
-    :PPC_DARWIN,
-    :WIN32,
-    :X86_LINUX
-  ]
-
-  def self.const_missing(name) # TODO remove six months from 2007/12
-    if DEPRECATED_CONSTS.include? name then
-      raise NameError, "#{name} has been removed, use CURRENT instead"
-    else
-      super
-    end
-  end
-
   def self.local
     arch = Gem::ConfigMap[:arch]
     arch = "#{arch}_60" if arch =~ /mswin32$/
@@ -72,7 +56,7 @@
              else cpu
              end
 
-      if arch.length == 2 and arch.last =~ /^\d+$/ then # for command-line
+      if arch.length == 2 and arch.last =~ /^\d+(\.\d+)?$/ then # for command-line
         @os, @version = arch
         return
       end
@@ -122,11 +106,20 @@
     to_a.compact.join '-'
   end
 
+  ##
+  # Is +other+ equal to this platform?  Two platforms are equal if they have
+  # the same CPU, OS and version.
+
   def ==(other)
     self.class === other and
       @cpu == other.cpu and @os == other.os and @version == other.version
   end
 
+  ##
+  # Does +other+ match this platform?  Two platforms match if they have the
+  # same CPU, or either has a CPU of 'universal', they have the same OS, and
+  # they have the same version, or either has no version.
+
   def ===(other)
     return nil unless Gem::Platform === other
 
@@ -140,6 +133,10 @@
     (@version.nil? or other.version.nil? or @version == other.version)
   end
 
+  ##
+  # Does +other+ match this platform?  If +other+ is a String it will be
+  # converted to a Gem::Platform first.  See #=== for matching rules.
+
   def =~(other)
     case other
     when Gem::Platform then # nop

Modified: MacRuby/branches/experimental/lib/rubygems/remote_fetcher.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/remote_fetcher.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/remote_fetcher.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,4 +1,6 @@
 require 'net/http'
+require 'stringio'
+require 'time'
 require 'uri'
 
 require 'rubygems'
@@ -11,15 +13,38 @@
 
   include Gem::UserInteraction
 
-  class FetchError < Gem::Exception; end
+  ##
+  # A FetchError exception wraps up the various possible IO and HTTP failures
+  # that could happen while downloading from the internet.
 
+  class FetchError < Gem::Exception
+
+    ##
+    # The URI which was being accessed when the exception happened.
+
+    attr_accessor :uri
+
+    def initialize(message, uri)
+      super message
+      @uri = uri
+    end
+
+    def to_s # :nodoc:
+      "#{super} (#{uri})"
+    end
+
+  end
+
   @fetcher = nil
 
+  ##
   # Cached RemoteFetcher instance.
+
   def self.fetcher
     @fetcher ||= self.new Gem.configuration[:http_proxy]
   end
 
+  ##
   # Initialize a remote fetcher using the source URI and possible proxy
   # information.
   #
@@ -29,6 +54,7 @@
   # * nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER,
   #        HTTP_PROXY_PASS)
   # * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
+
   def initialize(proxy)
     Socket.do_not_reverse_lookup = true
 
@@ -47,11 +73,18 @@
   # Moves the gem +spec+ from +source_uri+ to the cache dir unless it is
   # already there.  If the source_uri is local the gem cache dir copy is
   # always replaced.
+
   def download(spec, source_uri, install_dir = Gem.dir)
+    if File.writable?(install_dir)
+      cache_dir = File.join install_dir, 'cache'
+    else
+      cache_dir = File.join(Gem.user_dir, 'cache')
+    end
+
     gem_file_name = "#{spec.full_name}.gem"
-    local_gem_path = File.join install_dir, 'cache', gem_file_name
+    local_gem_path = File.join cache_dir, gem_file_name
 
-    Gem.ensure_gem_subdirectories install_dir
+    FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
 
     source_uri = URI.parse source_uri unless URI::Generic === source_uri
     scheme = source_uri.scheme
@@ -60,7 +93,7 @@
     scheme = nil if scheme =~ /^[a-z]$/i
 
     case scheme
-    when 'http' then
+    when 'http', 'https' then
       unless File.exist? local_gem_path then
         begin
           say "Downloading gem #{gem_file_name}" if
@@ -102,56 +135,30 @@
     local_gem_path
   end
 
-  # Downloads +uri+.
-  def fetch_path(uri)
-    open_uri_or_path(uri) do |input|
-      input.read
-    end
+  ##
+  # Downloads +uri+ and returns it as a String.
+
+  def fetch_path(uri, mtime = nil, head = false)
+    data = open_uri_or_path uri, mtime, head
+    data = Gem.gunzip data if data and not head and uri.to_s =~ /gz$/
+    data
+  rescue FetchError
+    raise
   rescue Timeout::Error
-    raise FetchError, "timed out fetching #{uri}"
+    raise FetchError.new('timed out', uri)
   rescue IOError, SocketError, SystemCallError => e
-    raise FetchError, "#{e.class}: #{e} reading #{uri}"
-  rescue => e
-    message = "#{e.class}: #{e} reading #{uri}"
-    raise FetchError, message
+    raise FetchError.new("#{e.class}: #{e}", uri)
   end
 
+  ##
   # Returns the size of +uri+ in bytes.
-  def fetch_size(uri)
-    return File.size(get_file_uri_path(uri)) if file_uri? uri
 
-    uri = URI.parse uri unless URI::Generic === uri
+  def fetch_size(uri) # TODO: phase this out
+    response = fetch_path(uri, nil, true)
 
-    raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
-
-    http = connect_to uri.host, uri.port
-
-    request = Net::HTTP::Head.new uri.request_uri
-
-    request.basic_auth unescape(uri.user), unescape(uri.password) unless
-      uri.user.nil? or uri.user.empty?
-
-    resp = http.request request
-
-    if resp.code !~ /^2/ then
-      raise Gem::RemoteSourceException,
-            "HTTP Response #{resp.code} fetching #{uri}"
-    end
-
-    if resp['content-length'] then
-      return resp['content-length'].to_i
-    else
-      resp = http.get uri.request_uri
-      return resp.body.size
-    end
-
-  rescue SocketError, SystemCallError, Timeout::Error => e
-    raise Gem::RemoteFetcher::FetchError,
-          "#{e.message} (#{e.class})\n\tgetting size of #{uri}"
+    response['content-length'].to_i
   end
 
-  private
-
   def escape(str)
     return unless str
     URI.escape(str)
@@ -162,7 +169,9 @@
     URI.unescape(str)
   end
 
+  ##
   # Returns an HTTP proxy URI if one is set in the environment variables.
+
   def get_proxy_from_env
     env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
 
@@ -179,23 +188,49 @@
     uri
   end
 
+  ##
   # Normalize the URI by adding "http://" if it is missing.
+
   def normalize_uri(uri)
     (uri =~ /^(https?|ftp|file):/) ? uri : "http://#{uri}"
   end
 
-  # Connect to the source host/port, using a proxy if needed.
-  def connect_to(host, port)
-    if @proxy_uri
-      Net::HTTP::Proxy(@proxy_uri.host, @proxy_uri.port, unescape(@proxy_uri.user), unescape(@proxy_uri.password)).new(host, port)
-    else
-      Net::HTTP.new(host, port)
+  ##
+  # Creates or an HTTP connection based on +uri+, or retrieves an existing
+  # connection, using a proxy if needed.
+
+  def connection_for(uri)
+    net_http_args = [uri.host, uri.port]
+
+    if @proxy_uri then
+      net_http_args += [
+        @proxy_uri.host,
+        @proxy_uri.port,
+        @proxy_uri.user,
+        @proxy_uri.password
+      ]
     end
+
+    connection_id = net_http_args.join ':'
+    @connections[connection_id] ||= Net::HTTP.new(*net_http_args)
+    connection = @connections[connection_id]
+
+    if uri.scheme == 'https' and not connection.started? then
+      require 'net/https'
+      connection.use_ssl = true
+      connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
+    end
+
+    connection.start unless connection.started?
+
+    connection
   end
 
+  ##
   # Read the data from the (source based) URI, but if it is a file:// URI,
   # read from the filesystem instead.
-  def open_uri_or_path(uri, depth = 0, &block)
+
+  def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0)
     if RUBY_ENGINE == 'macruby'
       # XXX we are taking a _much faster_ code path here, this change should be
       # removed once we re-implement the IO subsystem (and therefore Net::HTTP)
@@ -203,93 +238,117 @@
       url = NSURL.URLWithString(uri.to_s)
       data = NSMutableData.dataWithContentsOfURL(url)
       if data.nil?
-	raise Gem::RemoteFetcher::FetchError, "error when fetching data from #{uri}"
+	      raise Gem::RemoteFetcher::FetchError, "error when fetching data from #{uri}"
       end
       string = String.__new_bytestring__(data)
       #block.call(string) if block
       return string
+    end    
+    raise "block is dead" if block_given?
+
+    return open(get_file_uri_path(uri)) if file_uri? uri
+
+    uri = URI.parse uri unless URI::Generic === uri
+    raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
+
+    fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
+    response   = request uri, fetch_type, last_modified
+
+    case response
+    when Net::HTTPOK, Net::HTTPNotModified then
+      head ? response : response.body
+    when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
+         Net::HTTPTemporaryRedirect then
+      raise FetchError.new('too many redirects', uri) if depth > 10
+
+      open_uri_or_path(response['Location'], last_modified, head, depth + 1)
+    else
+      raise FetchError.new("bad response #{response.message} #{response.code}", uri)
     end
-    if file_uri?(uri)
-      open(get_file_uri_path(uri), &block)
-    else
-      uri = URI.parse uri unless URI::Generic === uri
-      net_http_args = [uri.host, uri.port]
+  end
 
-      if @proxy_uri then
-        net_http_args += [  @proxy_uri.host,
-                            @proxy_uri.port,
-                            @proxy_uri.user,
-                            @proxy_uri.password
-        ]
-      end
+  ##
+  # Performs a Net::HTTP request of type +request_class+ on +uri+ returning
+  # a Net::HTTP response object.  request maintains a table of persistent
+  # connections to reduce connect overhead.
 
-      connection_id = net_http_args.join ':'
-      @connections[connection_id] ||= Net::HTTP.new(*net_http_args)
-      connection = @connections[connection_id]
+  def request(uri, request_class, last_modified = nil)
+    request = request_class.new uri.request_uri
 
-      if uri.scheme == 'https' && ! connection.started?
-        http_obj.use_ssl = true
-        http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
-      end
+    unless uri.nil? || uri.user.nil? || uri.user.empty? then
+      request.basic_auth uri.user, uri.password
+    end
 
-      connection.start unless connection.started?
+    ua = "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
+    ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
+    ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+    ua << ")"
 
-      request = Net::HTTP::Get.new(uri.request_uri)
-      unless uri.nil? || uri.user.nil? || uri.user.empty? then
-        request.basic_auth(uri.user, uri.password)
-      end
+    request.add_field 'User-Agent', ua
+    request.add_field 'Connection', 'keep-alive'
+    request.add_field 'Keep-Alive', '30'
 
-      ua = "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
-      ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
-      ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
-      ua << ")"
+    if last_modified then
+      last_modified = last_modified.utc
+      request.add_field 'If-Modified-Since', last_modified.rfc2822
+    end
 
-      request.add_field 'User-Agent', ua
-      request.add_field 'Connection', 'keep-alive'
-      request.add_field 'Keep-Alive', '30'
+    connection = connection_for uri
 
-      # HACK work around EOFError bug in Net::HTTP
-      # NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
-      # to install gems.
-      retried = false
-      begin
-        @requests[connection_id] += 1
-        response = connection.request(request)
-      rescue EOFError, Errno::ECONNABORTED
-        requests = @requests[connection_id]
-        say "connection reset after #{requests} requests, retrying" if
-          Gem.configuration.really_verbose
+    retried = false
+    bad_response = false
 
-        raise Gem::RemoteFetcher::FetchError, 'too many connection resets' if
-          retried
+    begin
+      @requests[connection.object_id] += 1
+      response = connection.request request
+      say "#{request.method} #{response.code} #{response.message}: #{uri}" if
+        Gem.configuration.really_verbose
+    rescue Net::HTTPBadResponse
+      reset connection
 
-        @requests[connection_id] = 0
+      raise FetchError.new('too many bad responses', uri) if bad_response
 
-        connection.finish
-        connection.start
-        retried = true
-        retry
-      end
+      bad_response = true
+      retry
+    # HACK work around EOFError bug in Net::HTTP
+    # NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
+    # to install gems.
+    rescue EOFError, Errno::ECONNABORTED, Errno::ECONNRESET
+      requests = @requests[connection.object_id]
+      say "connection reset after #{requests} requests, retrying" if
+        Gem.configuration.really_verbose
 
-      case response
-      when Net::HTTPOK then
-        block.call(StringIO.new(response.body)) if block
-      when Net::HTTPRedirection then
-        raise Gem::RemoteFetcher::FetchError, "too many redirects" if depth > 10
-        open_uri_or_path(response['Location'], depth + 1, &block)
-      else
-        raise Gem::RemoteFetcher::FetchError,
-              "bad response #{response.message} #{response.code}"
-      end
+      raise FetchError.new('too many connection resets', uri) if retried
+
+      reset connection
+
+      retried = true
+      retry
     end
+
+    response
   end
 
+  ##
+  # Resets HTTP connection +connection+.
+
+  def reset(connection)
+    @requests.delete connection.object_id
+
+    connection.finish
+    connection.start
+  end
+
+  ##
   # Checks if the provided string is a file:// URI.
+
   def file_uri?(uri)
     uri =~ %r{\Afile://}
   end
 
+  ##
   # Given a file:// URI, returns its local path.
+
   def get_file_uri_path(uri)
     uri.sub(%r{\Afile://}, '')
   end

Modified: MacRuby/branches/experimental/lib/rubygems/requirement.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/requirement.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/requirement.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -12,6 +12,7 @@
 #
 # A Requirement object can actually contain multiple, er,
 # requirements, as in (> 1.2, < 2.0).
+
 class Gem::Requirement
 
   include Comparable
@@ -35,7 +36,7 @@
   # Version, a String, or nil.  Intended to simplify client code.
   #
   # If the input is "weird", the default version requirement is returned.
-  #
+
   def self.create(input)
     case input
     when Gem::Requirement then
@@ -57,6 +58,7 @@
   # This comment once said:
   #
   # "A default "version requirement" can surely _only_ be '> 0'."
+
   def self.default
     self.new ['>= 0']
   end
@@ -65,6 +67,7 @@
   # Constructs a Requirement from +requirements+ which can be a String, a
   # Gem::Version, or an Array of those.  See parse for details on the
   # formatting of requirement strings.
+
   def initialize(requirements)
     @requirements = case requirements
                     when Array then
@@ -81,14 +84,18 @@
     @requirements = values['requirements']
     @version = nil
   end
+  
+  ##
+  # Marshal raw requirements, rather than the full object
 
-  # Marshal raw requirements, rather than the full object
-  def marshal_dump
+  def marshal_dump # :nodoc:
     [@requirements]
   end
 
+  ##
   # Load custom marshal format
-  def marshal_load(array)
+
+  def marshal_load(array) # :nodoc:
     @requirements = array[0]
     @version = nil
   end
@@ -113,20 +120,16 @@
   end
 
   ##
-  # Is the requirement satifised by +version+.
-  #
-  # version:: [Gem::Version] the version to compare against
-  # return:: [Boolean] true if this requirement is satisfied by
-  #          the version, otherwise false
-  #
+  # True if this requirement satisfied by the Gem::Version +version+.
+
   def satisfied_by?(version)
     normalize
     @requirements.all? { |op, rv| satisfy?(op, version, rv) }
   end
 
   ##
-  # Is "version op required_version" satisfied?
-  #
+  # Is "+version+ +op+ +required_version+" satisfied?
+
   def satisfy?(op, version, required_version)
     OPS[op].call(version, required_version)
   end
@@ -137,6 +140,7 @@
   # The requirement can be a String or a Gem::Version.  A String can be an
   # operator (<, <=, =, =>, >, !=, ~>), a version number, or both, operator
   # first.
+
   def parse(obj)
     case obj
     when /^\s*(#{OP_RE})\s*([0-9.]+)\s*$/o then
@@ -152,7 +156,7 @@
     end
   end
 
-  def <=>(other)
+  def <=>(other) # :nodoc:
     to_s <=> other.to_s
   end
 

Modified: MacRuby/branches/experimental/lib/rubygems/rubygems_version.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/rubygems_version.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/rubygems_version.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -2,5 +2,5 @@
 # This file is auto-generated by build scripts.
 # See:  rake update_version
 module Gem
-  RubyGemsVersion = '1.1.1'
+  RubyGemsVersion = '1.3.1'
 end

Modified: MacRuby/branches/experimental/lib/rubygems/security.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/security.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/security.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -557,7 +557,7 @@
   #
   # Medium security policy: verify the signing certificate, verify the signing
   # certificate chain all the way to the root certificate, and only trust root
-  # certificates that we have explicity allowed trust for.
+  # certificates that we have explicitly allowed trust for.
   #
   # This security policy is reasonable, but it allows unsigned packages, so a
   # malicious person could simply delete the package signature and pass the
@@ -576,7 +576,7 @@
   # High security policy: only allow signed gems to be installed, verify the
   # signing certificate, verify the signing certificate chain all the way to
   # the root certificate, and only trust root certificates that we have
-  # explicity allowed trust for.
+  # explicitly allowed trust for.
   #
   # This security policy is significantly more difficult to bypass, and offers
   # a reasonable guarantee that the contents of the gem have not been altered.

Modified: MacRuby/branches/experimental/lib/rubygems/server.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/server.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/server.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -4,25 +4,32 @@
 require 'erb'
 
 require 'rubygems'
+require 'rubygems/doc_manager'
 
 ##
 # Gem::Server and allows users to serve gems for consumption by
 # `gem --remote-install`.
 #
-# gem_server starts an HTTP server on the given port and serves the folowing:
+# gem_server starts an HTTP server on the given port and serves the following:
 # * "/" - Browsing of gem spec files for installed gems
-# * "/Marshal" - Full SourceIndex dump of metadata for installed gems
-# * "/yaml" - YAML dump of metadata for installed gems - deprecated
+# * "/specs.#{Gem.marshal_version}.gz" - specs name/version/platform index
+# * "/latest_specs.#{Gem.marshal_version}.gz" - latest specs
+#   name/version/platform index
+# * "/quick/" - Individual gemspecs
 # * "/gems" - Direct access to download the installable gems
+# * legacy indexes:
+#   * "/Marshal.#{Gem.marshal_version}" - Full SourceIndex dump of metadata
+#     for installed gems
+#   * "/yaml" - YAML dump of metadata for installed gems - deprecated
 #
 # == Usage
 #
-#   gem server [-p portnum] [-d gem_path]
+#   gem_server = Gem::Server.new Gem.dir, 8089, false
+#   gem_server.run
 #
-# port_num:: The TCP port the HTTP server will bind to
-# gem_path::
-#   Root gem directory containing both "cache" and "specifications"
-#   subdirectories.
+#--
+# TODO Refactor into a real WEBrick servlet to remove code duplication.
+
 class Gem::Server
 
   include Gem::UserInteraction
@@ -36,7 +43,6 @@
   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
   <head>
     <title>RubyGems Documentation Index</title>
-    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
     <link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
   </head>
   <body>
@@ -325,32 +331,99 @@
     new(options[:gemdir], options[:port], options[:daemon]).run
   end
 
-  def initialize(gemdir, port, daemon)
+  def initialize(gem_dir, port, daemon)
     Socket.do_not_reverse_lookup = true
 
-    @gemdir = gemdir
+    @gem_dir = gem_dir
     @port = port
     @daemon = daemon
     logger = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
     @server = WEBrick::HTTPServer.new :DoNotListen => true, :Logger => logger
 
-    @spec_dir = File.join @gemdir, "specifications"
+    @spec_dir = File.join @gem_dir, 'specifications'
+
+    unless File.directory? @spec_dir then
+      raise ArgumentError, "#{@gem_dir} does not appear to be a gem repository"
+    end
+
     @source_index = Gem::SourceIndex.from_gems_in @spec_dir
   end
 
+  def Marshal(req, res)
+    @source_index.refresh!
+
+    res['date'] = File.stat(@spec_dir).mtime
+
+    index = Marshal.dump @source_index
+
+    if req.request_method == 'HEAD' then
+      res['content-length'] = index.length
+      return
+    end
+
+    if req.path =~ /Z$/ then
+      res['content-type'] = 'application/x-deflate'
+      index = Gem.deflate index
+    else
+      res['content-type'] = 'application/octet-stream'
+    end
+
+    res.body << index
+  end
+
+  def latest_specs(req, res)
+    @source_index.refresh!
+
+    res['content-type'] = 'application/x-gzip'
+
+    res['date'] = File.stat(@spec_dir).mtime
+
+    specs = @source_index.latest_specs.sort.map do |spec|
+      platform = spec.original_platform
+      platform = Gem::Platform::RUBY if platform.nil?
+      [spec.name, spec.version, platform]
+    end
+
+    specs = Marshal.dump specs
+
+    if req.path =~ /\.gz$/ then
+      specs = Gem.gzip specs
+      res['content-type'] = 'application/x-gzip'
+    else
+      res['content-type'] = 'application/octet-stream'
+    end
+
+    if req.request_method == 'HEAD' then
+      res['content-length'] = specs.length
+    else
+      res.body << specs
+    end
+  end
+
   def quick(req, res)
+    @source_index.refresh!
+
     res['content-type'] = 'text/plain'
     res['date'] = File.stat(@spec_dir).mtime
 
-    case req.request_uri.request_uri
+    case req.request_uri.path
     when '/quick/index' then
-      res.body << @source_index.map { |name,_| name }.join("\n")
+      res.body << @source_index.map { |name,| name }.sort.join("\n")
     when '/quick/index.rz' then
-      index = @source_index.map { |name,_| name }.join("\n")
-      res.body << Zlib::Deflate.deflate(index)
+      index = @source_index.map { |name,| name }.sort.join("\n")
+      res['content-type'] = 'application/x-deflate'
+      res.body << Gem.deflate(index)
+    when '/quick/latest_index' then
+      index = @source_index.latest_specs.map { |spec| spec.full_name }
+      res.body << index.sort.join("\n")
+    when '/quick/latest_index.rz' then
+      index = @source_index.latest_specs.map { |spec| spec.full_name }
+      res['content-type'] = 'application/x-deflate'
+      res.body << Gem.deflate(index.sort.join("\n"))
     when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+)(-.*?)?\.gemspec\.rz$| then
       dep = Gem::Dependency.new $2, $3
       specs = @source_index.search dep
+      marshal_format = $1
 
       selector = [$2, $3, $4].map { |s| s.inspect }.join ' '
 
@@ -368,126 +441,133 @@
       elsif specs.length > 1 then
         res.status = 500
         res.body = "Multiple gems found matching #{selector}"
-      elsif $1 then # marshal quickindex instead of YAML
-        res.body << Zlib::Deflate.deflate(Marshal.dump(specs.first))
+      elsif marshal_format then
+        res['content-type'] = 'application/x-deflate'
+        res.body << Gem.deflate(Marshal.dump(specs.first))
       else # deprecated YAML format
-        res.body << Zlib::Deflate.deflate(specs.first.to_yaml)
+        res['content-type'] = 'application/x-deflate'
+        res.body << Gem.deflate(specs.first.to_yaml)
       end
     else
-      res.status = 404
-      res.body = "#{req.request_uri} not found"
+      raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
     end
   end
 
-  def run
-    @server.listen nil, @port
+  def root(req, res)
+    @source_index.refresh!
+    res['date'] = File.stat(@spec_dir).mtime
 
-    say "Starting gem server on http://localhost:#{@port}/"
+    raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless
+      req.path == '/'
 
-    WEBrick::Daemon.start if @daemon
+    specs = []
+    total_file_count = 0
 
-    @server.mount_proc("/yaml") do |req, res|
-      res['content-type'] = 'text/plain'
-      res['date'] = File.stat(@spec_dir).mtime
-      if req.request_method == 'HEAD' then
-        res['content-length'] = @source_index.to_yaml.length
-      else
-        res.body << @source_index.to_yaml
+    @source_index.each do |path, spec|
+      total_file_count += spec.files.size
+      deps = spec.dependencies.map do |dep|
+        { "name"    => dep.name,
+          "type"    => dep.type,
+          "version" => dep.version_requirements.to_s, }
       end
-    end
 
-    @server.mount_proc("/Marshal") do |req, res|
-      res['content-type'] = 'text/plain'
-      res['date'] = File.stat(@spec_dir).mtime
-      if req.request_method == 'HEAD' then
-        res['content-length'] = Marshal.dump(@source_index).length
-      else
-        res.body << Marshal.dump(@source_index)
-      end
+      deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
+      deps.last["is_last"] = true unless deps.empty?
+
+      # executables
+      executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
+      executables = nil if executables.empty?
+      executables.last["is_last"] = true if executables
+
+      specs << {
+        "authors"             => spec.authors.sort.join(", "),
+        "date"                => spec.date.to_s,
+        "dependencies"        => deps,
+        "doc_path"            => "/doc_root/#{spec.full_name}/rdoc/index.html",
+        "executables"         => executables,
+        "only_one_executable" => (executables && executables.size == 1),
+        "full_name"           => spec.full_name,
+        "has_deps"            => !deps.empty?,
+        "homepage"            => spec.homepage,
+        "name"                => spec.name,
+        "rdoc_installed"      => Gem::DocManager.new(spec).rdoc_installed?,
+        "summary"             => spec.summary,
+        "version"             => spec.version.to_s,
+      }
     end
 
-    @server.mount_proc("/quick/", &method(:quick))
+    specs << {
+      "authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
+      "dependencies" => [],
+      "doc_path" => "/doc_root/rubygems-#{Gem::RubyGemsVersion}/rdoc/index.html",
+      "executables" => [{"executable" => 'gem', "is_last" => true}],
+      "only_one_executable" => true,
+      "full_name" => "rubygems-#{Gem::RubyGemsVersion}",
+      "has_deps" => false,
+      "homepage" => "http://rubygems.org/",
+      "name" => 'rubygems',
+      "rdoc_installed" => true,
+      "summary" => "RubyGems itself",
+      "version" => Gem::RubyGemsVersion,
+    }
 
-    @server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
-      res['content-type'] = 'text/css'
-      res['date'] = File.stat(@spec_dir).mtime
-      res.body << RDOC_CSS
+    specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
+    specs.last["is_last"] = true
+
+    # tag all specs with first_name_entry
+    last_spec = nil
+    specs.each do |spec|
+      is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
+      spec["first_name_entry"] = is_first
+      last_spec = spec
     end
 
-    @server.mount_proc("/") do |req, res|
-      specs = []
-      total_file_count = 0
+    # create page from template
+    template = ERB.new(DOC_TEMPLATE)
+    res['content-type'] = 'text/html'
 
-      @source_index.each do |path, spec|
-        total_file_count += spec.files.size
-        deps = spec.dependencies.collect { |dep|
-          { "name"    => dep.name, 
-            "version" => dep.version_requirements.to_s, }
-        }
-        deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
-        deps.last["is_last"] = true unless deps.empty?
+    values = { "gem_count" => specs.size.to_s, "specs" => specs,
+               "total_file_count" => total_file_count.to_s }
 
-        # executables
-        executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
-        executables = nil if executables.empty?
-        executables.last["is_last"] = true if executables
+    result = template.result binding
+    res.body = result
+  end
 
-        specs << {
-          "authors"        => spec.authors.sort.join(", "),
-          "date"           => spec.date.to_s,
-          "dependencies"   => deps,
-          "doc_path"       => ('/doc_root/' + spec.full_name + '/rdoc/index.html'),
-          "executables"    => executables,
-          "only_one_executable" => (executables && executables.size==1),
-          "full_name"      => spec.full_name,
-          "has_deps"       => !deps.empty?,
-          "homepage"       => spec.homepage,
-          "name"           => spec.name,
-          "rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
-          "summary"        => spec.summary,
-          "version"        => spec.version.to_s,
-        }
-      end
+  def run
+    @server.listen nil, @port
 
-      specs << {
-        "authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
-        "dependencies" => [],
-        "doc_path" => "/doc_root/rubygems-#{Gem::RubyGemsVersion}/rdoc/index.html",
-        "executables" => [{"executable" => 'gem', "is_last" => true}],
-        "only_one_executable" => true,
-        "full_name" => "rubygems-#{Gem::RubyGemsVersion}",
-        "has_deps" => false,
-        "homepage" => "http://rubygems.org/",
-        "name" => 'rubygems',
-        "rdoc_installed" => true,
-        "summary" => "RubyGems itself",
-        "version" => Gem::RubyGemsVersion,
-      }
+    say "Starting gem server on http://localhost:#{@port}/"
 
-      specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
-      specs.last["is_last"] = true
+    WEBrick::Daemon.start if @daemon
 
-      # tag all specs with first_name_entry 
-      last_spec = nil
-      specs.each do |spec|
-        is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
-        spec["first_name_entry"] = is_first
-        last_spec = spec
-      end
+    @server.mount_proc "/yaml", method(:yaml)
+    @server.mount_proc "/yaml.Z", method(:yaml)
 
-      # create page from template
-      template = ERB.new(DOC_TEMPLATE)
-      res['content-type'] = 'text/html'
-      values = { "gem_count" => specs.size.to_s, "specs" => specs,
-                             "total_file_count" => total_file_count.to_s }
-      result = template.result binding
-      res.body = result
+    @server.mount_proc "/Marshal.#{Gem.marshal_version}", method(:Marshal)
+    @server.mount_proc "/Marshal.#{Gem.marshal_version}.Z", method(:Marshal)
+
+    @server.mount_proc "/specs.#{Gem.marshal_version}", method(:specs)
+    @server.mount_proc "/specs.#{Gem.marshal_version}.gz", method(:specs)
+
+    @server.mount_proc "/latest_specs.#{Gem.marshal_version}",
+                       method(:latest_specs)
+    @server.mount_proc "/latest_specs.#{Gem.marshal_version}.gz",
+                       method(:latest_specs)
+
+    @server.mount_proc "/quick/", method(:quick)
+
+    @server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
+      res['content-type'] = 'text/css'
+      res['date'] = File.stat(@spec_dir).mtime
+      res.body << RDOC_CSS
     end
 
+    @server.mount_proc "/", method(:root)
+
     paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
     paths.each do |mount_point, mount_dir|
       @server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
-              File.join(@gemdir, mount_dir), true)
+                    File.join(@gem_dir, mount_dir), true)
     end
 
     trap("INT") { @server.shutdown; exit! }
@@ -496,5 +576,54 @@
     @server.start
   end
 
+  def specs(req, res)
+    @source_index.refresh!
+
+    res['date'] = File.stat(@spec_dir).mtime
+
+    specs = @source_index.sort.map do |_, spec|
+      platform = spec.original_platform
+      platform = Gem::Platform::RUBY if platform.nil?
+      [spec.name, spec.version, platform]
+    end
+
+    specs = Marshal.dump specs
+
+    if req.path =~ /\.gz$/ then
+      specs = Gem.gzip specs
+      res['content-type'] = 'application/x-gzip'
+    else
+      res['content-type'] = 'application/octet-stream'
+    end
+
+    if req.request_method == 'HEAD' then
+      res['content-length'] = specs.length
+    else
+      res.body << specs
+    end
+  end
+
+  def yaml(req, res)
+    @source_index.refresh!
+
+    res['date'] = File.stat(@spec_dir).mtime
+
+    index = @source_index.to_yaml
+
+    if req.path =~ /Z$/ then
+      res['content-type'] = 'application/x-deflate'
+      index = Gem.deflate index
+    else
+      res['content-type'] = 'text/plain'
+    end
+
+    if req.request_method == 'HEAD' then
+      res['content-length'] = index.length
+      return
+    end
+
+    res.body << index
+  end
+
 end
 

Modified: MacRuby/branches/experimental/lib/rubygems/source_index.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/source_index.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/source_index.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -7,6 +7,9 @@
 require 'rubygems'
 require 'rubygems/user_interaction'
 require 'rubygems/specification'
+module Gem
+  autoload(:SpecFetcher, 'rubygems/spec_fetcher')
+end
 
 ##
 # The SourceIndex object indexes all the gems available from a
@@ -27,6 +30,11 @@
 
   attr_reader :gems # :nodoc:
 
+  ##
+  # Directories to use to refresh this SourceIndex when calling refresh!
+
+  attr_accessor :spec_dirs
+
   class << self
     include Gem::UserInteraction
 
@@ -39,7 +47,7 @@
     #   +from_gems_in+.  This argument is deprecated and is provided
     #   just for backwards compatibility, and should not generally
     #   be used.
-    # 
+    #
     # return::
     #   SourceIndex instance
 
@@ -63,7 +71,9 @@
     # +spec_dirs+.
 
     def from_gems_in(*spec_dirs)
-      self.new.load_gems_in(*spec_dirs)
+      source_index = new
+      source_index.spec_dirs = spec_dirs
+      source_index.refresh!
     end
 
     ##
@@ -72,18 +82,26 @@
 
     def load_specification(file_name)
       begin
-        spec_code = File.read(file_name).untaint
+        spec_code = if RUBY_VERSION < '1.9' then
+                      File.read file_name
+                    else
+                      File.read file_name, :encoding => 'UTF-8'
+                    end.untaint
+
         gemspec = eval spec_code, binding, file_name
+
         if gemspec.is_a?(Gem::Specification)
           gemspec.loaded_from = file_name
           return gemspec
         end
         alert_warning "File '#{file_name}' does not evaluate to a gem specification"
+      rescue SignalException, SystemExit
+        raise
       rescue SyntaxError => e
         alert_warning e
         alert_warning spec_code
       rescue Exception => e
-        alert_warning(e.inspect.to_s + "\n" + spec_code)
+        alert_warning "#{e.inspect}\n#{spec_code}"
         alert_warning "Invalid .gemspec format in '#{file_name}'"
       end
       return nil
@@ -100,6 +118,7 @@
 
   def initialize(specifications={})
     @gems = specifications
+    @spec_dirs = nil
   end
 
   ##
@@ -121,8 +140,8 @@
   end
 
   ##
-  # Returns a Hash of name => Specification of the latest versions of each
-  # gem in this index.
+  # Returns an Array specifications for the latest versions of each gem in
+  # this index.
 
   def latest_specs
     result = Hash.new { |h,k| h[k] = [] }
@@ -219,7 +238,8 @@
   # Find a gem by an exact match on the short name.
 
   def find_name(gem_name, version_requirement = Gem::Requirement.default)
-    search(/^#{gem_name}$/, version_requirement)
+    dep = Gem::Dependency.new(/^#{gem_name}$/, version_requirement)
+    search dep
   end
 
   ##
@@ -235,13 +255,20 @@
     version_requirement = nil
     only_platform = false
 
-    case gem_pattern # TODO warn after 2008/03, remove three months after
+    # TODO - Remove support and warning for legacy arguments after 2008/11
+    unless Gem::Dependency === gem_pattern
+      warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated"
+    end
+
+    case gem_pattern
     when Regexp then
       version_requirement = platform_only || Gem::Requirement.default
     when Gem::Dependency then
       only_platform = platform_only
       version_requirement = gem_pattern.version_requirements
-      gem_pattern = if gem_pattern.name.empty? then
+      gem_pattern = if Regexp === gem_pattern.name then
+                      gem_pattern.name
+                    elsif gem_pattern.name.empty? then
                       //
                     else
                       /^#{Regexp.escape gem_pattern.name}$/
@@ -257,7 +284,7 @@
 
     specs = @gems.values.select do |spec|
       spec.name =~ gem_pattern and
-      version_requirement.satisfied_by? spec.version
+        version_requirement.satisfied_by? spec.version
     end
 
     if only_platform then
@@ -271,29 +298,41 @@
 
   ##
   # Replaces the gems in the source index from specifications in the
-  # installed_spec_directories,
+  # directories this source index was created from.  Raises an exception if
+  # this source index wasn't created from a directory (via from_gems_in or
+  # from_installed_gems, or having spec_dirs set).
 
   def refresh!
-    load_gems_in(*self.class.installed_spec_directories)
+    raise 'source index not created from disk' if @spec_dirs.nil?
+    load_gems_in(*@spec_dirs)
   end
 
   ##
   # Returns an Array of Gem::Specifications that are not up to date.
 
   def outdated
-    dep = Gem::Dependency.new '', Gem::Requirement.default
-
-    remotes = Gem::SourceInfoCache.search dep, true
-
     outdateds = []
 
     latest_specs.each do |local|
-      name = local.name
-      remote = remotes.select { |spec| spec.name == name }.
-        sort_by { |spec| spec.version.to_ints }.
-        last
+      dependency = Gem::Dependency.new local.name, ">= #{local.version}"
 
-      outdateds << name if remote and local.version < remote.version
+      begin
+        fetcher = Gem::SpecFetcher.fetcher
+        remotes = fetcher.find_matching dependency
+        remotes = remotes.map { |(name, version,_),_| version }
+      rescue Gem::RemoteFetcher::FetchError => e
+        raise unless fetcher.warn_legacy e do
+          require 'rubygems/source_info_cache'
+
+          specs = Gem::SourceInfoCache.search_with_source dependency, true
+
+          remotes = specs.map { |spec,| spec.version }
+        end
+      end
+
+      latest = remotes.sort.last
+
+      outdateds << local.name if latest and local.version < latest
     end
 
     outdateds
@@ -387,7 +426,8 @@
   end
 
   def fetch_bulk_index(source_uri)
-    say "Bulk updating Gem source index for: #{source_uri}"
+    say "Bulk updating Gem source index for: #{source_uri}" if
+      Gem.configuration.verbose
 
     index = fetch_index_from(source_uri)
     if index.nil? then
@@ -447,7 +487,7 @@
 
   def unzip(string)
     require 'zlib'
-    Zlib::Inflate.inflate(string)
+    Gem.inflate string
   end
 
   ##
@@ -513,7 +553,7 @@
   # objects to load properly.
   Cache = SourceIndex
 
-  # :starddoc:
+  # :startdoc:
 
 end
 

Modified: MacRuby/branches/experimental/lib/rubygems/source_info_cache.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/source_info_cache.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/source_info_cache.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -8,7 +8,7 @@
 # SourceInfoCache stores a copy of the gem index for each gem source.
 #
 # There are two possible cache locations, the system cache and the user cache:
-# * The system cache is prefered if it is writable or can be created.
+# * The system cache is preferred if it is writable or can be created.
 # * The user cache is used otherwise
 #
 # Once a cache is selected, it will be used for all operations.
@@ -284,6 +284,10 @@
 
     cache_data.map do |source_uri, sic_entry|
       next unless Gem.sources.include? source_uri
+      # TODO - Remove this gunk after 2008/11
+      unless pattern.kind_of?(Gem::Dependency)
+        pattern = Gem::Dependency.new(pattern, Gem::Requirement.default) 
+      end
       sic_entry.source_index.search pattern, platform_only
     end.flatten.compact
   end
@@ -300,6 +304,11 @@
     cache_data.map do |source_uri, sic_entry|
       next unless Gem.sources.include? source_uri
 
+      # TODO - Remove this gunk after 2008/11
+      unless pattern.kind_of?(Gem::Dependency)
+        pattern = Gem::Dependency.new(pattern, Gem::Requirement.default) 
+      end
+
       sic_entry.source_index.search(pattern, only_platform).each do |spec|
         results << [spec, source_uri]
       end

Copied: MacRuby/branches/experimental/lib/rubygems/spec_fetcher.rb (from rev 1886, MacRuby/trunk/lib/rubygems/spec_fetcher.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/spec_fetcher.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rubygems/spec_fetcher.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,249 @@
+require 'zlib'
+
+require 'rubygems'
+require 'rubygems/remote_fetcher'
+require 'rubygems/user_interaction'
+
+##
+# SpecFetcher handles metadata updates from remote gem repositories.
+
+class Gem::SpecFetcher
+
+  include Gem::UserInteraction
+
+  ##
+  # The SpecFetcher cache dir.
+
+  attr_reader :dir # :nodoc:
+
+  ##
+  # Cache of latest specs
+
+  attr_reader :latest_specs # :nodoc:
+
+  ##
+  # Cache of all spces
+
+  attr_reader :specs # :nodoc:
+
+  @fetcher = nil
+
+  def self.fetcher
+    @fetcher ||= new
+  end
+
+  def self.fetcher=(fetcher) # :nodoc:
+    @fetcher = fetcher
+  end
+
+  def initialize
+    @dir = File.join Gem.user_home, '.gem', 'specs'
+    @update_cache = File.stat(Gem.user_home).uid == Process.uid
+
+    @specs = {}
+    @latest_specs = {}
+
+    @fetcher = Gem::RemoteFetcher.fetcher
+  end
+
+  ##
+  # Retuns the local directory to write +uri+ to.
+
+  def cache_dir(uri)
+    File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
+  end
+
+  ##
+  # Fetch specs matching +dependency+.  If +all+ is true, all matching
+  # versions are returned.  If +matching_platform+ is false, all platforms are
+  # returned.
+
+  def fetch(dependency, all = false, matching_platform = true)
+    specs_and_sources = find_matching dependency, all, matching_platform
+
+    specs_and_sources.map do |spec_tuple, source_uri|
+      [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
+    end
+
+  rescue Gem::RemoteFetcher::FetchError => e
+    raise unless warn_legacy e do
+      require 'rubygems/source_info_cache'
+
+      return Gem::SourceInfoCache.search_with_source(dependency,
+                                                     matching_platform, all)
+    end
+  end
+
+  def fetch_spec(spec, source_uri)
+    spec = spec - [nil, 'ruby', '']
+    spec_file_name = "#{spec.join '-'}.gemspec"
+
+    uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
+
+    cache_dir = cache_dir uri
+
+    local_spec = File.join cache_dir, spec_file_name
+
+    if File.exist? local_spec then
+      spec = Gem.read_binary local_spec
+    else
+      uri.path << '.rz'
+
+      spec = @fetcher.fetch_path uri
+      spec = Gem.inflate spec
+
+      if @update_cache then
+        FileUtils.mkdir_p cache_dir
+
+        open local_spec, 'wb' do |io|
+          io.write spec
+        end
+      end
+    end
+
+    # TODO: Investigate setting Gem::Specification#loaded_from to a URI
+    Marshal.load spec
+  end
+
+  ##
+  # Find spec names that match +dependency+.  If +all+ is true, all matching
+  # versions are returned.  If +matching_platform+ is false, gems for all
+  # platforms are returned.
+
+  def find_matching(dependency, all = false, matching_platform = true)
+    found = {}
+
+    list(all).each do |source_uri, specs|
+      found[source_uri] = specs.select do |spec_name, version, spec_platform|
+        dependency =~ Gem::Dependency.new(spec_name, version) and
+          (not matching_platform or Gem::Platform.match(spec_platform))
+      end
+    end
+
+    specs_and_sources = []
+
+    found.each do |source_uri, specs|
+      uri_str = source_uri.to_s
+      specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
+    end
+
+    specs_and_sources
+  end
+
+  ##
+  # Returns Array of gem repositories that were generated with RubyGems less
+  # than 1.2.
+
+  def legacy_repos
+    Gem.sources.reject do |source_uri|
+      source_uri = URI.parse source_uri
+      spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
+
+      begin
+        @fetcher.fetch_size spec_path
+      rescue Gem::RemoteFetcher::FetchError
+        begin
+          @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
+        rescue Gem::RemoteFetcher::FetchError
+          alert_error "#{source_uri} does not appear to be a repository"
+          raise
+        end
+        false
+      end
+    end
+  end
+
+  ##
+  # Returns a list of gems available for each source in Gem::sources.  If
+  # +all+ is true, all versions are returned instead of only latest versions.
+
+  def list(all = false)
+    list = {}
+
+    file = all ? 'specs' : 'latest_specs'
+
+    Gem.sources.each do |source_uri|
+      source_uri = URI.parse source_uri
+
+      if all and @specs.include? source_uri then
+        list[source_uri] = @specs[source_uri]
+      elsif not all and @latest_specs.include? source_uri then
+        list[source_uri] = @latest_specs[source_uri]
+      else
+        specs = load_specs source_uri, file
+
+        cache = all ? @specs : @latest_specs
+
+        cache[source_uri] = specs
+        list[source_uri] = specs
+      end
+    end
+
+    list
+  end
+
+  ##
+  # Loads specs in +file+, fetching from +source_uri+ if the on-disk cache is
+  # out of date.
+
+  def load_specs(source_uri, file)
+    file_name  = "#{file}.#{Gem.marshal_version}"
+    spec_path  = source_uri + "#{file_name}.gz"
+    cache_dir  = cache_dir spec_path
+    local_file = File.join(cache_dir, file_name)
+    loaded     = false
+
+    if File.exist? local_file then
+      spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
+
+      if spec_dump.nil? then
+        spec_dump = Gem.read_binary local_file
+      else
+        loaded = true
+      end
+    else
+      spec_dump = @fetcher.fetch_path spec_path
+      loaded = true
+    end
+
+    specs = Marshal.load spec_dump
+
+    if loaded and @update_cache then
+      begin
+        FileUtils.mkdir_p cache_dir
+
+        open local_file, 'wb' do |io|
+          Marshal.dump specs, io
+        end
+      rescue
+      end
+    end
+
+    specs
+  end
+
+  ##
+  # Warn about legacy repositories if +exception+ indicates only legacy
+  # repositories are available, and yield to the block.  Returns false if the
+  # exception indicates some other FetchError.
+
+  def warn_legacy(exception)
+    uri = exception.uri.to_s
+    if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
+      alert_warning <<-EOF
+RubyGems 1.2+ index not found for:
+\t#{legacy_repos.join "\n\t"}
+
+RubyGems will revert to legacy indexes degrading performance.
+      EOF
+
+      yield
+
+      return true
+    end
+
+    false
+  end
+
+end
+

Modified: MacRuby/branches/experimental/lib/rubygems/specification.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/specification.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/specification.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,6 +6,7 @@
 
 require 'rubygems'
 require 'rubygems/version'
+require 'rubygems/requirement'
 require 'rubygems/platform'
 
 # :stopdoc:
@@ -16,10 +17,14 @@
     t - ((t.to_f + t.gmt_offset) % 86400)
   end unless defined? Time.today
 end
+
+class Date; end # for ruby_code if date.rb wasn't required
+
 # :startdoc:
 
 module Gem
 
+  ##
   # == Gem::Specification
   #
   # The Specification class contains the metadata for a Gem.  Typically
@@ -34,25 +39,35 @@
   #
   # There are many <em>gemspec attributes</em>, and the best place to learn
   # about them in the "Gemspec Reference" linked from the RubyGems wiki.
-  #
+
   class Specification
 
+    ##
     # Allows deinstallation of gems with legacy platforms.
+
     attr_accessor :original_platform # :nodoc:
 
-    # ------------------------- Specification version contstants.
-
+    ##
     # The the version number of a specification that does not specify one
     # (i.e. RubyGems 0.7 or earlier).
+
     NONEXISTENT_SPECIFICATION_VERSION = -1
 
+    ##
     # The specification version applied to any new Specification instances
     # created.  This should be bumped whenever something in the spec format
     # changes.
+    #--
+    # When updating this number, be sure to also update #to_ruby.
+    #
+    # NOTE RubyGems < 1.2 cannot load specification versions > 2.
+
     CURRENT_SPECIFICATION_VERSION = 2
 
+    ##
     # An informal list of changes to the specification.  The highest-valued
     # key should be equal to the CURRENT_SPECIFICATION_VERSION.
+
     SPECIFICATION_VERSION_HISTORY = {
       -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
       1  => [
@@ -72,77 +87,98 @@
     TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
     # :startdoc:
 
-    # ------------------------- Class variables.
+    ##
+    # List of Specification instances.
 
-    # List of Specification instances.
     @@list = []
 
+    ##
     # Optional block used to gather newly defined instances.
+
     @@gather = nil
 
+    ##
     # List of attribute names: [:name, :version, ...]
     @@required_attributes = []
 
-    # List of _all_ attributes and default values: [[:name, nil], [:bindir, 'bin'], ...]
+    ##
+    # List of _all_ attributes and default values:
+    #
+    #   [[:name, nil],
+    #    [:bindir, 'bin'],
+    #    ...]
+
     @@attributes = []
 
     @@nil_attributes = []
     @@non_nil_attributes = [:@original_platform]
 
+    ##
     # List of array attributes
+
     @@array_attributes = []
 
+    ##
     # Map of attribute names to default values.
+
     @@default_value = {}
 
-    # ------------------------- Convenience class methods.
+    ##
+    # Names of all specification attributes
 
     def self.attribute_names
       @@attributes.map { |name, default| name }
     end
 
+    ##
+    # Default values for specification attributes
+
     def self.attribute_defaults
       @@attributes.dup
     end
 
+    ##
+    # The default value for specification attribute +name+
+
     def self.default_value(name)
       @@default_value[name]
     end
 
+    ##
+    # Required specification attributes
+
     def self.required_attributes
       @@required_attributes.dup
     end
 
+    ##
+    # Is +name+ a required attribute?
+
     def self.required_attribute?(name)
       @@required_attributes.include? name.to_sym
     end
 
+    ##
+    # Specification attributes that are arrays (appendable and so-forth)
+
     def self.array_attributes
       @@array_attributes.dup
     end
 
-    # ------------------------- Infrastructure class methods.
+    ##
+    # A list of Specification instances that have been defined in this Ruby
+    # instance.
 
-    # A list of Specification instances that have been defined in this Ruby instance.
     def self.list
       @@list
     end
 
-    # Used to specify the name and default value of a specification
-    # attribute.  The side effects are:
-    # * the name and default value are added to the @@attributes list
-    #   and @@default_value map
-    # * a standard _writer_ method (<tt>attribute=</tt>) is created
-    # * a non-standard _reader method (<tt>attribute</tt>) is created
+    ##
+    # Specifies the +name+ and +default+ for a specification attribute, and
+    # creates a reader and writer method like Module#attr_accessor.
     #
-    # The reader method behaves like this:
-    #   def attribute
-    #     @attribute ||= (copy of default value)
-    #   end
-    #
-    # This allows lazy initialization of attributes to their default
-    # values. 
-    #
+    # The reader method returns the default if the value hasn't been set.
+
     def self.attribute(name, default=nil)
       ivar_name = "@#{name}".intern
       if default.nil? then
@@ -156,8 +192,10 @@
       attr_accessor(name)
     end
 
-    # Same as :attribute, but ensures that values assigned to the
-    # attribute are array values by applying :to_a to the value.
+    ##
+    # Same as :attribute, but ensures that values assigned to the attribute
+    # are array values by applying :to_a to the value.
+
     def self.array_attribute(name)
       @@non_nil_attributes << ["@#{name}".intern, []]
 
@@ -176,51 +214,60 @@
       module_eval code, __FILE__, __LINE__ - 9
     end
 
+    ##
     # Same as attribute above, but also records this attribute as mandatory.
+
     def self.required_attribute(*args)
       @@required_attributes << args.first
       attribute(*args)
     end
 
-    # Sometimes we don't want the world to use a setter method for a particular attribute.
+    ##
+    # Sometimes we don't want the world to use a setter method for a
+    # particular attribute.
+    #
     # +read_only+ makes it private so we can still use it internally.
+
     def self.read_only(*names)
       names.each do |name|
         private "#{name}="
       end
     end
 
-    # Shortcut for creating several attributes at once (each with a default value of
-    # +nil+).
+    # Shortcut for creating several attributes at once (each with a default
+    # value of +nil+).
+
     def self.attributes(*args)
       args.each do |arg|
         attribute(arg, nil)
       end
     end
 
-    # Some attributes require special behaviour when they are accessed.  This allows for
-    # that.
+    ##
+    # Some attributes require special behaviour when they are accessed.  This
+    # allows for that.
+
     def self.overwrite_accessor(name, &block)
       remove_method name
       define_method(name, &block)
     end
 
-    # Defines a _singular_ version of an existing _plural_ attribute
-    # (i.e. one whose value is expected to be an array).  This means
-    # just creating a helper method that takes a single value and
-    # appends it to the array.  These are created for convenience, so
-    # that in a spec, one can write 
+    ##
+    # Defines a _singular_ version of an existing _plural_ attribute (i.e. one
+    # whose value is expected to be an array).  This means just creating a
+    # helper method that takes a single value and appends it to the array.
+    # These are created for convenience, so that in a spec, one can write 
     #
     #   s.require_path = 'mylib'
     #
-    # instead of
+    # instead of:
     #
     #   s.require_paths = ['mylib']
     #
-    # That above convenience is available courtesy of
+    # That above convenience is available courtesy of:
     #
     #   attribute_alias_singular :require_path, :require_paths 
-    #
+
     def self.attribute_alias_singular(singular, plural)
       define_method("#{singular}=") { |val|
         send("#{plural}=", [val])
@@ -231,10 +278,12 @@
       }
     end
 
+    ##
     # Dump only crucial instance variables.
-    #
+    #--
     # MAINTAIN ORDER!
-    def _dump(limit) # :nodoc:
+
+    def _dump(limit)
       Marshal.dump [
         @rubygems_version,
         @specification_version,
@@ -256,7 +305,9 @@
       ]
     end
 
+    ##
     # Load custom marshal format, re-initializing defaults as needed
+
     def self._load(str)
       array = Marshal.load str
 
@@ -300,182 +351,46 @@
       spec
     end
 
-    # REQUIRED gemspec attributes ------------------------------------
-    
-    required_attribute :rubygems_version, Gem::RubyGemsVersion
-    required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
-    required_attribute :name
-    required_attribute :version
-    required_attribute :date, TODAY
-    required_attribute :summary
-    required_attribute :require_paths, ['lib']
+    ##
+    # List of depedencies that will automatically be activated at runtime.
 
-    # OPTIONAL gemspec attributes ------------------------------------
-    
-    attributes :email, :homepage, :rubyforge_project, :description
-    attributes :autorequire, :default_executable
+    def runtime_dependencies
+      dependencies.select { |d| d.type == :runtime || d.type == nil }
+    end
 
-    attribute :bindir,                     'bin'
-    attribute :has_rdoc,                   false
-    attribute :required_ruby_version,      Gem::Requirement.default
-    attribute :required_rubygems_version,  Gem::Requirement.default
-    attribute :platform,                   Gem::Platform::RUBY
+    ##
+    # List of dependencies that are used for development
 
-    attribute :signing_key,            nil
-    attribute :cert_chain,             []
-    attribute :post_install_message,   nil
+    def development_dependencies
+      dependencies.select { |d| d.type == :development }
+    end
 
-    array_attribute :authors
-    array_attribute :files
-    array_attribute :test_files
-    array_attribute :rdoc_options
-    array_attribute :extra_rdoc_files
-    array_attribute :executables
-
-    # Array of extensions to build.  See Gem::Installer#build_extensions for
-    # valid values.
-
-    array_attribute :extensions
-    array_attribute :requirements
-    array_attribute :dependencies
-
-    read_only :dependencies
-
-    # ALIASED gemspec attributes -------------------------------------
-    
-    attribute_alias_singular :executable,   :executables
-    attribute_alias_singular :author,   :authors
-    attribute_alias_singular :require_path, :require_paths
-    attribute_alias_singular :test_file,    :test_files
-
-    # DEPRECATED gemspec attributes ----------------------------------
-    
-    def test_suite_file
+    def test_suite_file # :nodoc:
       warn 'test_suite_file deprecated, use test_files'
       test_files.first
     end
 
-    def test_suite_file=(val)
+    def test_suite_file=(val) # :nodoc:
       warn 'test_suite_file= deprecated, use test_files='
       @test_files = [] unless defined? @test_files
       @test_files << val
     end
 
+    ##
     # true when this gemspec has been loaded from a specifications directory.
     # This attribute is not persisted.
 
-    attr_writer :loaded
+    attr_accessor :loaded
 
+    ##
     # Path this gemspec was loaded from.  This attribute is not persisted.
+
     attr_accessor :loaded_from
 
-    # Special accessor behaviours (overwriting default) --------------
-    
-    overwrite_accessor :version= do |version|
-      @version = Version.create(version)
-    end
+    ##
+    # Returns an array with bindir attached to each executable in the
+    # executables list
 
-    overwrite_accessor :platform do
-      @new_platform
-    end
-
-    overwrite_accessor :platform= do |platform|
-      if @original_platform.nil? or
-         @original_platform == Gem::Platform::RUBY then
-        @original_platform = platform
-      end
-
-      case platform
-      when Gem::Platform::CURRENT then
-        @new_platform = Gem::Platform.local
-        @original_platform = @new_platform.to_s
-
-      when Gem::Platform then
-        @new_platform = platform
-
-      # legacy constants
-      when nil, Gem::Platform::RUBY then
-        @new_platform = Gem::Platform::RUBY
-      when 'mswin32' then # was Gem::Platform::WIN32
-        @new_platform = Gem::Platform.new 'x86-mswin32'
-      when 'i586-linux' then # was Gem::Platform::LINUX_586
-        @new_platform = Gem::Platform.new 'x86-linux'
-      when 'powerpc-darwin' then # was Gem::Platform::DARWIN
-        @new_platform = Gem::Platform.new 'ppc-darwin'
-      else
-        @new_platform = Gem::Platform.new platform
-      end
-
-      @platform = @new_platform.to_s
-
-      @new_platform
-    end
-
-    overwrite_accessor :required_ruby_version= do |value|
-      @required_ruby_version = Gem::Requirement.create(value)
-    end
-
-    overwrite_accessor :required_rubygems_version= do |value|
-      @required_rubygems_version = Gem::Requirement.create(value)
-    end
-
-    overwrite_accessor :date= do |date|
-      # We want to end up with a Time object with one-day resolution.
-      # This is the cleanest, most-readable, faster-than-using-Date
-      # way to do it.
-      case date
-      when String then
-        @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
-                  Time.local($1.to_i, $2.to_i, $3.to_i)
-                else
-                  require 'time'
-                  Time.parse date
-                end
-      when Time then
-        @date = Time.local(date.year, date.month, date.day)
-      when Date then
-        @date = Time.local(date.year, date.month, date.day)
-      else
-        @date = TODAY
-      end
-    end
-
-    overwrite_accessor :date do
-      self.date = nil if @date.nil?  # HACK Sets the default value for date
-      @date
-    end
-
-    overwrite_accessor :summary= do |str|
-      @summary = if str then
-                   str.strip.
-                   gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
-                   gsub(/\n[ \t]*/, " ")
-                 end
-    end
-
-    overwrite_accessor :description= do |str|
-      @description = if str then
-                       str.strip.
-                       gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
-                       gsub(/\n[ \t]*/, " ")
-                     end
-    end
-
-    overwrite_accessor :default_executable do
-      begin
-        if defined?(@default_executable) and @default_executable
-          result = @default_executable
-        elsif @executables and @executables.size == 1
-          result = Array(@executables).first
-        else
-          result = nil
-        end
-        result
-      rescue
-        nil
-      end
-    end
-
     def add_bindir(executables)
       return nil if executables.nil?
 
@@ -488,17 +403,9 @@
       return nil
     end
 
-    overwrite_accessor :files do
-      result = []
-      result.push(*@files) if defined?(@files)
-      result.push(*@test_files) if defined?(@test_files)
-      result.push(*(add_bindir(@executables)))
-      result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
-      result.push(*@extensions) if defined?(@extensions)
-      result.uniq.compact
-    end
+    ##
+    # Files in the Gem under one of the require_paths
 
-    # Files in the Gem under one of the require_paths
     def lib_files
       @files.select do |file|
         require_paths.any? do |path|
@@ -507,34 +414,25 @@
       end
     end
 
-    overwrite_accessor :test_files do
-      # Handle the possibility that we have @test_suite_file but not
-      # @test_files.  This will happen when an old gem is loaded via
-      # YAML.
-      if defined? @test_suite_file then
-        @test_files = [@test_suite_file].flatten
-        @test_suite_file = nil
-      end
-      if defined?(@test_files) and @test_files then
-        @test_files
-      else
-        @test_files = []
-      end
+    ##
+    # True if this gem was loaded from disk
+
+    alias :loaded? :loaded
+
+    ##
+    # True if this gem has files in test_files
+
+    def has_unit_tests?
+      not test_files.empty?
     end
 
-    # Predicates -----------------------------------------------------
+    alias has_test_suite? has_unit_tests? # :nodoc: deprecated
     
-    def loaded?; @loaded ? true : false ; end
-    def has_rdoc?; has_rdoc ? true : false ; end
-    def has_unit_tests?; not test_files.empty?; end
-    alias has_test_suite? has_unit_tests?               # (deprecated)
-    
-    # Constructors ---------------------------------------------------
-    
+    ##
     # Specification constructor.  Assigns the default values to the
     # attributes, adds this spec to the list of loaded specs (see
     # Specification.list), and yields itself for further initialization.
-    #
+
     def initialize
       @new_platform = nil
       assign_defaults
@@ -547,11 +445,13 @@
       @@gather.call(self) if @@gather
     end
 
-    # Each attribute has a default value (possibly nil).  Here, we
-    # initialize all attributes to their default value.  This is
-    # done through the accessor methods, so special behaviours will
-    # be honored.  Furthermore, we take a _copy_ of the default so
-    # each specification instance has its own empty arrays, etc.
+    ##
+    # Each attribute has a default value (possibly nil).  Here, we initialize
+    # all attributes to their default value.  This is done through the
+    # accessor methods, so special behaviours will be honored.  Furthermore,
+    # we take a _copy_ of the default so each specification instance has its
+    # own empty arrays, etc.
+
     def assign_defaults
       @@nil_attributes.each do |name|
         instance_variable_set name, nil
@@ -570,13 +470,14 @@
       instance_variable_set :@new_platform, Gem::Platform::RUBY
     end
 
-    # Special loader for YAML files.  When a Specification object is
-    # loaded from a YAML file, it bypasses the normal Ruby object
-    # initialization routine (#initialize).  This method makes up for
-    # that and deals with gems of different ages.
+    ##
+    # Special loader for YAML files.  When a Specification object is loaded
+    # from a YAML file, it bypasses the normal Ruby object initialization
+    # routine (#initialize).  This method makes up for that and deals with
+    # gems of different ages.
     #
     # 'input' can be anything that YAML.load() accepts: String or IO. 
-    #
+
     def self.from_yaml(input)
       input = normalize_yaml_input input
       spec = YAML.load input
@@ -599,6 +500,9 @@
       spec
     end 
 
+    ##
+    # Loads ruby format gemspec from +filename+
+
     def self.load(filename)
       gemspec = nil
       fail "NESTED Specification.load calls not allowed!" if @@gather
@@ -610,22 +514,25 @@
       @@gather = nil
     end
 
-    # Make sure the yaml specification is properly formatted with dashes.
+    ##
+    # Make sure the YAML specification is properly formatted with dashes
+
     def self.normalize_yaml_input(input)
       result = input.respond_to?(:read) ? input.read : input
       result = "--- " + result unless result =~ /^--- /
       result
     end
     
-    # Instance methods -----------------------------------------------
-    
-    # Sets the rubygems_version to Gem::RubyGemsVersion.
-    #
+    ##
+    # Sets the rubygems_version to the current RubyGems version
+
     def mark_version
       @rubygems_version = RubyGemsVersion
     end
 
-    # Ignore unknown attributes if the 
+    ##
+    # Ignore unknown attributes while loading
+
     def method_missing(sym, *a, &b) # :nodoc:
       if @specification_version > CURRENT_SPECIFICATION_VERSION and
          sym.to_s =~ /=$/ then
@@ -635,31 +542,39 @@
       end
     end
 
-    # Adds a dependency to this Gem.  For example,
+    ##
+    # Adds a development dependency named +gem+ with +requirements+ to this
+    # Gem.  For example:
     #
-    #   spec.add_dependency('jabber4r', '> 0.1', '<= 0.5')
+    #   spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'
     #
-    # gem:: [String or Gem::Dependency] The Gem name/dependency.
-    # requirements:: [default=">= 0"] The version requirements.
+    # Development dependencies aren't installed by default and aren't
+    # activated when a gem is required.
+
+    def add_development_dependency(gem, *requirements)
+      add_dependency_with_type(gem, :development, *requirements)
+    end
+
+    ##
+    # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
+    # For example:
     #
-    def add_dependency(gem, *requirements)
-      requirements = if requirements.empty? then
-                       Gem::Requirement.default
-                     else
-                       requirements.flatten
-                     end
+    #   spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
 
-      unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
-        gem = Dependency.new(gem, requirements)
-      end
+    def add_runtime_dependency(gem, *requirements)
+      add_dependency_with_type(gem, :runtime, *requirements)
+    end
 
-      dependencies << gem
-    end
-    
+    ##
+    # Adds a runtime dependency
+
+    alias add_dependency add_runtime_dependency
+
+    ##
     # Returns the full name (name-version) of this Gem.  Platform information
-    # is included (name-version-platform) if it is specified (and not the
-    # default Ruby platform).
-    #
+    # is included (name-version-platform) if it is specified and not the
+    # default Ruby platform.
+
     def full_name
       if platform == Gem::Platform::RUBY or platform.nil? then
         "#{@name}-#{@version}"
@@ -668,9 +583,10 @@
       end
     end
 
+    ##
     # Returns the full name (name-version) of this gemspec using the original
-    # platform.
-    #
+    # platform.  For use with legacy gems.
+
     def original_name # :nodoc:
       if platform == Gem::Platform::RUBY or platform.nil? then
         "#{@name}-#{@version}"
@@ -679,42 +595,41 @@
       end
     end
 
+    ##
     # The full path to the gem (install path + full name).
-    #
-    # return:: [String] the full gem path
-    #
+
     def full_gem_path
       path = File.join installation_path, 'gems', full_name
       return path if File.directory? path
       File.join installation_path, 'gems', original_name
     end
-    
+
+    ##
     # The default (generated) file name of the gem.
+
     def file_name
       full_name + ".gem"
     end
-    
-    # The root directory that the gem was installed into.
-    #
-    # return:: [String] the installation path
-    #
+
+    ##
+    # The directory that this gem was installed into.
+
     def installation_path
-      (File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]).
-        join(File::SEPARATOR)
+      path = File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]
+      path = path.join File::SEPARATOR
+      File.expand_path path
     end
-    
-    # Checks if this Specification meets the requirement of the supplied
-    # dependency.
-    # 
-    # dependency:: [Gem::Dependency] the dependency to check
-    # return:: [Boolean] true if dependency is met, otherwise false
-    #
+
+    ##
+    # Checks if this specification meets the requirement of +dependency+.
+
     def satisfies_requirement?(dependency)
       return @name == dependency.name && 
         dependency.version_requirements.satisfied_by?(@version)
     end
 
-    # Comparison methods ---------------------------------------------
+    ##
+    # Returns an object you can use to sort specifications in #sort_by.
 
     def sort_obj
       [@name, @version.to_ints, @new_platform == Gem::Platform::RUBY ? -1 : 1]
@@ -724,19 +639,25 @@
       sort_obj <=> other.sort_obj
     end
 
+    ##
     # Tests specs for equality (across all attributes).
+
     def ==(other) # :nodoc:
       self.class === other && same_attributes?(other)
     end
 
     alias eql? == # :nodoc:
 
+    ##
+    # True if this gem has the same attributes as +other+.
+
     def same_attributes?(other)
       @@attributes.each do |name, default|
         return false unless self.send(name) == other.send(name)
       end
       true
     end
+
     private :same_attributes?
 
     def hash # :nodoc:
@@ -746,8 +667,6 @@
       } / @@attributes.length # XXX because NSObject#hash is 'unsigned long' and this returns a bignum
     end
 
-    # Export methods (YAML and Ruby code) ----------------------------
-
     def to_yaml(opts = {}) # :nodoc:
       mark_version
 
@@ -784,12 +703,16 @@
       self.platform = Gem::Platform.new @platform
     end
 
+    ##
     # Returns a Ruby code representation of this specification, such that it
     # can be eval'ed and reconstruct the same specification later.  Attributes
     # that still have their default values are omitted.
+
     def to_ruby
       mark_version
       result = []
+      result << "# -*- encoding: utf-8 -*-"
+      result << nil
       result << "Gem::Specification.new do |s|"
 
       result << "  s.name = #{ruby_code name}"
@@ -798,8 +721,6 @@
         result << "  s.platform = #{ruby_code original_platform}"
       end
       result << ""
-      result << "  s.specification_version = #{specification_version} if s.respond_to? :specification_version="
-      result << ""
       result << "  s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
 
       handled = [
@@ -822,29 +743,55 @@
         end
       end
 
-      result << "" unless dependencies.empty?
+      result << nil
+      result << "  if s.respond_to? :specification_version then"
+      result << "    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION"
+      result << "    s.specification_version = #{specification_version}"
+      result << nil
 
-      dependencies.each do |dep|
-        version_reqs_param = dep.requirements_list.inspect
-        result << "  s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
+      result << "    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
+
+      unless dependencies.empty? then
+        dependencies.each do |dep|
+          version_reqs_param = dep.requirements_list.inspect
+          dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
+          result << "      s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
+        end
       end
 
+      result << "    else"
+
+      unless dependencies.empty? then
+        dependencies.each do |dep|
+          version_reqs_param = dep.requirements_list.inspect
+          result << "      s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
+        end
+      end
+
+      result << '    end'
+
+      result << "  else"
+        dependencies.each do |dep|
+          version_reqs_param = dep.requirements_list.inspect
+          result << "    s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
+        end
+      result << "  end"
+
       result << "end"
-      result << ""
+      result << nil
 
       result.join "\n"
     end
 
-    # Validation and normalization methods ---------------------------
+    ##
+    # Checks that the specification contains all required fields, and does a
+    # very basic sanity check.
+    #
+    # Raises InvalidSpecificationException if the spec does not pass the
+    # checks..
 
-    # Checks that the specification contains all required fields, and
-    # does a very basic sanity check.
-    #
-    # Raises InvalidSpecificationException if the spec does not pass
-    # the checks..
     def validate
       extend Gem::UserInteraction
-
       normalize
 
       if rubygems_version != RubyGemsVersion then
@@ -899,13 +846,14 @@
       true
     end
 
+    ##
     # Normalize the list of files so that:
     # * All file lists have redundancies removed.
-    # * Files referenced in the extra_rdoc_files are included in the
-    #   package file list. 
+    # * Files referenced in the extra_rdoc_files are included in the package
+    #   file list. 
     #
-    # Also, the summary and description are converted to a normal
-    # format. 
+    # Also, the summary and description are converted to a normal format. 
+
     def normalize
       if defined?(@extra_rdoc_files) and @extra_rdoc_files then
         @extra_rdoc_files.uniq!
@@ -915,15 +863,12 @@
       @files.uniq! if @files
     end
 
-    # Dependency methods ---------------------------------------------
-    
-    # Return a list of all gems that have a dependency on this
-    # gemspec.  The list is structured with entries that conform to:
+    ##
+    # Return a list of all gems that have a dependency on this gemspec.  The
+    # list is structured with entries that conform to:
     #
     #   [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
-    #
-    # return:: [Array] [[dependent_gem, dependency, [list_of_satisfiers]]]
-    #
+
     def dependent_gems
       out = []
       Gem.source_index.each do |name,gem|
@@ -944,8 +889,24 @@
       "#<Gem::Specification name=#{@name} version=#{@version}>"
     end
 
-    private
+    def add_dependency_with_type(dependency, type, *requirements)
+      requirements = if requirements.empty? then
+                       Gem::Requirement.default
+                     else
+                       requirements.flatten
+                     end
 
+      unless dependency.respond_to?(:name) &&
+        dependency.respond_to?(:version_requirements)
+
+        dependency = Dependency.new(dependency, requirements, type)
+      end
+
+      dependencies << dependency
+    end
+
+    private :add_dependency_with_type
+
     def find_all_satisfiers(dep)
       Gem.source_index.each do |name,gem|
         if(gem.satisfies_requirement?(dep)) then
@@ -954,8 +915,12 @@
       end
     end
 
-    # Return a string containing a Ruby code representation of the
-    # given object.
+    private :find_all_satisfiers
+
+    ##
+    # Return a string containing a Ruby code representation of the given
+    # object.
+
     def ruby_code(obj)
       case obj
       when String            then '%q{' + obj + '}'
@@ -970,7 +935,327 @@
       else raise Exception, "ruby_code case not handled: #{obj.class}"
       end
     end
+    
+    private :ruby_code
 
+    # :section: Required gemspec attributes
+    
+    ##
+    # The version of RubyGems used to create this gem
+
+    required_attribute :rubygems_version, Gem::RubyGemsVersion
+
+    ##
+    # The Gem::Specification version of this gemspec
+
+    required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
+
+    ##
+    # This gem's name
+
+    required_attribute :name
+
+    ##
+    # This gem's version
+
+    required_attribute :version
+
+    ##
+    # The date this gem was created
+
+    required_attribute :date, TODAY
+
+    ##
+    # A short summary of this gem's description.  Displayed in `gem list -d`.
+
+    required_attribute :summary
+
+    ##
+    # Paths in the gem to add to $LOAD_PATH when this gem is activated
+
+    required_attribute :require_paths, ['lib']
+
+    # :section: Optional gemspec attributes
+
+    ##
+    # A contact email for this gem
+    
+    attribute :email
+
+    ##
+    # The URL of this gem's home page
+
+    attribute :homepage
+
+    ##
+    # The rubyforge project this gem lives under.  i.e. RubyGems'
+    # rubyforge_project is "rubygems".
+    
+    attribute :rubyforge_project
+
+    ##
+    # A long description of this gem
+
+    attribute :description
+
+    ##
+    # Autorequire was used by old RubyGems to automatically require a file.
+    # It no longer is supported.
+
+    attribute :autorequire
+
+    ##
+    # The default executable for this gem.
+
+    attribute :default_executable
+
+    ##
+    # The path in the gem for executable scripts
+
+    attribute :bindir, 'bin'
+
+    ##
+    # True if this gem is RDoc-compliant
+
+    attribute :has_rdoc, false
+
+    ##
+    # True if this gem supports RDoc
+
+    alias :has_rdoc? :has_rdoc
+
+    ##
+    # The ruby of version required by this gem
+
+    attribute :required_ruby_version, Gem::Requirement.default
+
+    ##
+    # The RubyGems version required by this gem
+
+    attribute :required_rubygems_version, Gem::Requirement.default
+
+    ##
+    # The platform this gem runs on.  See Gem::Platform for details.
+
+    attribute :platform, Gem::Platform::RUBY
+
+    ##
+    # The key used to sign this gem.  See Gem::Security for details.
+
+    attribute :signing_key, nil
+
+    ##
+    # The certificate chain used to sign this gem.  See Gem::Security for
+    # details.
+
+    attribute :cert_chain, []
+
+    ##
+    # A message that gets displayed after the gem is installed
+
+    attribute :post_install_message, nil
+
+    ##
+    # The list of authors who wrote this gem
+
+    array_attribute :authors
+
+    ##
+    # Files included in this gem
+
+    array_attribute :files
+
+    ##
+    # Test files included in this gem
+
+    array_attribute :test_files
+
+    ##
+    # An ARGV-style array of options to RDoc
+
+    array_attribute :rdoc_options
+
+    ##
+    # Extra files to add to RDoc
+
+    array_attribute :extra_rdoc_files
+
+    ##
+    # Executables included in the gem
+
+    array_attribute :executables
+
+    ##
+    # Extensions to build when installing the gem.  See
+    # Gem::Installer#build_extensions for valid values.
+
+    array_attribute :extensions
+
+    ##
+    # An array or things required by this gem.  Not used by anything
+    # presently.
+
+    array_attribute :requirements
+
+    ##
+    # A list of Gem::Dependency objects this gem depends on.  Only appendable.
+
+    array_attribute :dependencies
+
+    read_only :dependencies
+
+    # :section: Aliased gemspec attributes
+
+    ##
+    # Singular accessor for executables
+    
+    attribute_alias_singular :executable, :executables
+
+    ##
+    # Singular accessor for authors
+
+    attribute_alias_singular :author, :authors
+
+    ##
+    # Singular accessor for require_paths
+
+    attribute_alias_singular :require_path, :require_paths
+
+    ##
+    # Singular accessor for test_files
+
+    attribute_alias_singular :test_file, :test_files
+
+    overwrite_accessor :version= do |version|
+      @version = Version.create(version)
+    end
+
+    overwrite_accessor :platform do
+      @new_platform
+    end
+
+    overwrite_accessor :platform= do |platform|
+      if @original_platform.nil? or
+         @original_platform == Gem::Platform::RUBY then
+        @original_platform = platform
+      end
+
+      case platform
+      when Gem::Platform::CURRENT then
+        @new_platform = Gem::Platform.local
+        @original_platform = @new_platform.to_s
+
+      when Gem::Platform then
+        @new_platform = platform
+
+      # legacy constants
+      when nil, Gem::Platform::RUBY then
+        @new_platform = Gem::Platform::RUBY
+      when 'mswin32' then # was Gem::Platform::WIN32
+        @new_platform = Gem::Platform.new 'x86-mswin32'
+      when 'i586-linux' then # was Gem::Platform::LINUX_586
+        @new_platform = Gem::Platform.new 'x86-linux'
+      when 'powerpc-darwin' then # was Gem::Platform::DARWIN
+        @new_platform = Gem::Platform.new 'ppc-darwin'
+      else
+        @new_platform = Gem::Platform.new platform
+      end
+
+      @platform = @new_platform.to_s
+
+      @new_platform
+    end
+
+    overwrite_accessor :required_ruby_version= do |value|
+      @required_ruby_version = Gem::Requirement.create(value)
+    end
+
+    overwrite_accessor :required_rubygems_version= do |value|
+      @required_rubygems_version = Gem::Requirement.create(value)
+    end
+
+    overwrite_accessor :date= do |date|
+      # We want to end up with a Time object with one-day resolution.
+      # This is the cleanest, most-readable, faster-than-using-Date
+      # way to do it.
+      case date
+      when String then
+        @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
+                  Time.local($1.to_i, $2.to_i, $3.to_i)
+                else
+                  require 'time'
+                  Time.parse date
+                end
+      when Time then
+        @date = Time.local(date.year, date.month, date.day)
+      when Date then
+        @date = Time.local(date.year, date.month, date.day)
+      else
+        @date = TODAY
+      end
+    end
+
+    overwrite_accessor :date do
+      self.date = nil if @date.nil?  # HACK Sets the default value for date
+      @date
+    end
+
+    overwrite_accessor :summary= do |str|
+      @summary = if str then
+                   str.strip.
+                   gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
+                   gsub(/\n[ \t]*/, " ")
+                 end
+    end
+
+    overwrite_accessor :description= do |str|
+      @description = if str then
+                       str.strip.
+                       gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
+                       gsub(/\n[ \t]*/, " ")
+                     end
+    end
+
+    overwrite_accessor :default_executable do
+      begin
+        if defined?(@default_executable) and @default_executable
+          result = @default_executable
+        elsif @executables and @executables.size == 1
+          result = Array(@executables).first
+        else
+          result = nil
+        end
+        result
+      rescue
+        nil
+      end
+    end
+
+    overwrite_accessor :test_files do
+      # Handle the possibility that we have @test_suite_file but not
+      # @test_files.  This will happen when an old gem is loaded via
+      # YAML.
+      if defined? @test_suite_file then
+        @test_files = [@test_suite_file].flatten
+        @test_suite_file = nil
+      end
+      if defined?(@test_files) and @test_files then
+        @test_files
+      else
+        @test_files = []
+      end
+    end
+
+    overwrite_accessor :files do
+      result = []
+      result.push(*@files) if defined?(@files)
+      result.push(*@test_files) if defined?(@test_files)
+      result.push(*(add_bindir(@executables)))
+      result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
+      result.push(*@extensions) if defined?(@extensions)
+      result.uniq.compact
+    end
+
   end
 
 end

Copied: MacRuby/branches/experimental/lib/rubygems/test_utilities.rb (from rev 1886, MacRuby/trunk/lib/rubygems/test_utilities.rb)
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/test_utilities.rb	                        (rev 0)
+++ MacRuby/branches/experimental/lib/rubygems/test_utilities.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -0,0 +1,131 @@
+require 'tempfile'
+require 'rubygems'
+require 'rubygems/remote_fetcher'
+
+##
+# A fake Gem::RemoteFetcher for use in tests or to avoid real live HTTP
+# requests when testing code that uses RubyGems.
+#
+# Example:
+#
+#   @fetcher = Gem::FakeFetcher.new
+#   @fetcher.data['http://gems.example.com/yaml'] = source_index.to_yaml
+#   Gem::RemoteFetcher.fetcher = @fetcher
+#   
+#   # invoke RubyGems code
+#   
+#   paths = @fetcher.paths
+#   assert_equal 'http://gems.example.com/yaml', paths.shift
+#   assert paths.empty?, paths.join(', ')
+#
+# See RubyGems' tests for more examples of FakeFetcher.
+
+class Gem::FakeFetcher
+
+  attr_reader :data
+  attr_accessor :paths
+
+  def initialize
+    @data = {}
+    @paths = []
+  end
+
+  def fetch_path path, mtime = nil
+    path = path.to_s
+    @paths << path
+    raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
+
+    unless @data.key? path then
+      raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path)
+    end
+
+    data = @data[path]
+
+    if data.respond_to?(:call) then
+      data.call
+    else
+      if path.to_s =~ /gz$/ and not data.nil? and not data.empty? then
+        data = Gem.gunzip data
+      end
+
+      data
+    end
+  end
+
+  def fetch_size(path)
+    path = path.to_s
+    @paths << path
+
+    raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
+
+    unless @data.key? path then
+      raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path)
+    end
+
+    data = @data[path]
+
+    data.respond_to?(:call) ? data.call : data.length
+  end
+
+  def download spec, source_uri, install_dir = Gem.dir
+    name = "#{spec.full_name}.gem"
+    path = File.join(install_dir, 'cache', name)
+
+    Gem.ensure_gem_subdirectories install_dir
+
+    if source_uri =~ /^http/ then
+      File.open(path, "wb") do |f|
+        f.write fetch_path(File.join(source_uri, "gems", name))
+      end
+    else
+      FileUtils.cp source_uri, path
+    end
+
+    path
+  end
+
+end
+
+# :stopdoc:
+class Gem::RemoteFetcher
+
+  def self.fetcher=(fetcher)
+    @fetcher = fetcher
+  end
+
+end
+# :startdoc:
+
+##
+# A StringIO duck-typed class that uses Tempfile instead of String as the
+# backing store.
+#--
+# This class was added to flush out problems in Rubinius' IO implementation.
+
+class TempIO
+
+  @@count = 0
+
+  def initialize(string = '')
+    @tempfile = Tempfile.new "TempIO-#{@@count += 1}"
+    @tempfile.binmode
+    @tempfile.write string
+    @tempfile.rewind
+  end
+
+  def method_missing(meth, *args, &block)
+    @tempfile.send(meth, *args, &block)
+  end
+
+  def respond_to?(meth)
+    @tempfile.respond_to? meth
+  end
+
+  def string
+    @tempfile.flush
+
+    Gem.read_binary @tempfile.path
+  end
+
+end
+

Modified: MacRuby/branches/experimental/lib/rubygems/uninstaller.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/uninstaller.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/uninstaller.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -18,10 +18,24 @@
   include Gem::UserInteraction
 
   ##
-  # Constructs an Uninstaller instance
-  #
-  # gem:: [String] The Gem name to uninstall
+  # The directory a gem's executables will be installed into
 
+  attr_reader :bin_dir
+
+  ##
+  # The gem repository the gem will be installed into
+
+  attr_reader :gem_home
+
+  ##
+  # The Gem::Specification for the gem being uninstalled, only set during
+  # #uninstall_gem
+
+  attr_reader :spec
+
+  ##
+  # Constructs an uninstaller that will uninstall +gem+
+
   def initialize(gem, options = {})
     @gem = gem
     @version = options[:version] || Gem::Requirement.default
@@ -30,43 +44,64 @@
     @force_executables = options[:executables]
     @force_all = options[:all]
     @force_ignore = options[:ignore]
-    @bin_dir = options[:bin_dir] 
+    @bin_dir = options[:bin_dir]
+
+    spec_dir = File.join @gem_home, 'specifications'
+    @source_index = Gem::SourceIndex.from_gems_in spec_dir
   end
 
   ##
-  # Performs the uninstall of the Gem.  This removes the spec, the
-  # Gem directory, and the cached .gem file,
+  # Performs the uninstall of the gem.  This removes the spec, the Gem
+  # directory, and the cached .gem file.
 
   def uninstall
-    list = Gem.source_index.search(/^#{@gem}$/, @version)
+    list = @source_index.find_name @gem, @version
 
     if list.empty? then
-      raise Gem::InstallError, "Unknown gem #{@gem}-#{@version}"
-    elsif list.size > 1 && @force_all
-      remove_all(list.dup) 
-      remove_executables(list.last)
-    elsif list.size > 1 
-      say 
+      raise Gem::InstallError, "Unknown gem #{@gem} #{@version}"
+
+    elsif list.size > 1 and @force_all then
+      remove_all list.dup
+
+    elsif list.size > 1 then
       gem_names = list.collect {|gem| gem.full_name} + ["All versions"]
-      gem_name, index =
-        choose_from_list("Select gem to uninstall:", gem_names)
-      if index == list.size
-        remove_all(list.dup) 
-        remove_executables(list.last)
-      elsif index >= 0 && index < list.size
-        to_remove = list[index]
-        remove(to_remove, list)
-        remove_executables(to_remove)
+
+      say
+      gem_name, index = choose_from_list "Select gem to uninstall:", gem_names
+
+      if index == list.size then
+        remove_all list.dup
+      elsif index >= 0 && index < list.size then
+        uninstall_gem list[index], list.dup
       else
         say "Error: must enter a number [1-#{list.size+1}]"
       end
     else
-      remove(list[0], list.dup)
-      remove_executables(list.last)
+      uninstall_gem list.first, list.dup
     end
   end
-  
+
   ##
+  # Uninstalls gem +spec+
+
+  def uninstall_gem(spec, specs)
+    @spec = spec
+
+    Gem.pre_uninstall_hooks.each do |hook|
+      hook.call self
+    end
+
+    specs.each { |s| remove_executables s }
+    remove spec, specs
+
+    Gem.post_uninstall_hooks.each do |hook|
+      hook.call self
+    end
+
+    @spec = nil
+  end
+
+  ##
   # Removes installed executables and batch files (windows only) for
   # +gemspec+.
 
@@ -76,7 +111,7 @@
     if gemspec.executables.size > 0 then
       bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
 
-      list = Gem.source_index.search(gemspec.name).delete_if { |spec|
+      list = @source_index.find_name(gemspec.name).delete_if { |spec|
         spec.version == gemspec.version
       }
 
@@ -111,14 +146,14 @@
       end
     end
   end
-  
+
   ##
   # Removes all gems in +list+.
   #
   # NOTE: removes uninstalled gems from +list+.
 
   def remove_all(list)
-    list.dup.each { |spec| remove spec, list }
+    list.dup.each { |spec| uninstall_gem spec, list }
   end
 
   ##
@@ -176,16 +211,16 @@
   end
 
   def path_ok?(spec)
-    match_path = File.join @gem_home, 'gems', spec.full_name
+    full_path = File.join @gem_home, 'gems', spec.full_name
+    original_path = File.join @gem_home, 'gems', spec.original_name
 
-    match_path == spec.full_gem_path
+    full_path == spec.full_gem_path || original_path == spec.full_gem_path
   end
 
   def dependencies_ok?(spec)
     return true if @force_ignore
 
-    source_index = Gem::SourceIndex.from_installed_gems
-    deplist = Gem::DependencyList.from_source_index source_index
+    deplist = Gem::DependencyList.from_source_index @source_index
     deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
   end
 

Modified: MacRuby/branches/experimental/lib/rubygems/user_interaction.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/user_interaction.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/user_interaction.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,54 +6,71 @@
 
 module Gem
 
-  ####################################################################
-  # Module that defines the default UserInteraction.  Any class
-  # including this module will have access to the +ui+ method that
-  # returns the default UI.
+  ##
+  # Module that defines the default UserInteraction.  Any class including this
+  # module will have access to the +ui+ method that returns the default UI.
+
   module DefaultUserInteraction
 
+    ##
+    # The default UI is a class variable of the singleton class for this
+    # module.
+
+    @ui = nil
+
+    ##
     # Return the default UI.
+
+    def self.ui
+      @ui ||= Gem::ConsoleUI.new
+    end
+
+    ##
+    # Set the default UI.  If the default UI is never explicitly set, a simple
+    # console based UserInteraction will be used automatically.
+
+    def self.ui=(new_ui)
+      @ui = new_ui
+    end
+
+    ##
+    # Use +new_ui+ for the duration of +block+.
+
+    def self.use_ui(new_ui)
+      old_ui = @ui
+      @ui = new_ui
+      yield
+    ensure
+      @ui = old_ui
+    end
+
+    ##
+    # See DefaultUserInteraction::ui
+
     def ui
       DefaultUserInteraction.ui
     end
 
-    # Set the default UI.  If the default UI is never explicity set, a
-    # simple console based UserInteraction will be used automatically.
+    ##
+    # See DefaultUserInteraction::ui=
+
     def ui=(new_ui)
       DefaultUserInteraction.ui = new_ui
     end
 
+    ##
+    # See DefaultUserInteraction::use_ui
+
     def use_ui(new_ui, &block)
       DefaultUserInteraction.use_ui(new_ui, &block)
     end
 
-    # The default UI is a class variable of the singleton class for
-    # this module.
-
-    @ui = nil
-
-    class << self
-      def ui
-        @ui ||= Gem::ConsoleUI.new
-      end
-      def ui=(new_ui)
-        @ui = new_ui
-      end
-      def use_ui(new_ui)
-        old_ui = @ui
-        @ui = new_ui
-        yield
-      ensure
-        @ui = old_ui
-      end
-    end
   end
 
-  ####################################################################
+  ##
   # Make the default UI accessable without the "ui." prefix.  Classes
-  # including this module may use the interaction methods on the
-  # default UI directly.  Classes may also reference the +ui+ and
-  # <tt>ui=</tt> methods.
+  # including this module may use the interaction methods on the default UI
+  # directly.  Classes may also reference the ui and ui= methods.
   #
   # Example:
   #
@@ -64,22 +81,30 @@
   #       n = ask("What is the meaning of life?")
   #     end
   #   end
+
   module UserInteraction
+
     include DefaultUserInteraction
-    [
-      :choose_from_list, :ask, :ask_yes_no, :say, :alert, :alert_warning,
-      :alert_error, :terminate_interaction
-    ].each do |methname|
+
+    [:alert,
+     :alert_error,
+     :alert_warning,
+     :ask,
+     :ask_yes_no,
+     :choose_from_list,
+     :say,
+     :terminate_interaction ].each do |methname|
       class_eval %{
         def #{methname}(*args)
           ui.#{methname}(*args)
         end
-      }
+      }, __FILE__, __LINE__
     end
   end
 
-  ####################################################################
+  ##
   # StreamUI implements a simple stream based user interface.
+
   class StreamUI
 
     attr_reader :ins, :outs, :errs
@@ -89,15 +114,19 @@
       @outs = out_stream
       @errs = err_stream
     end
-    
-    # Choose from a list of options.  +question+ is a prompt displayed
-    # above the list.  +list+ is a list of option strings.  Returns
-    # the pair [option_name, option_index].
+
+    ##
+    # Choose from a list of options.  +question+ is a prompt displayed above
+    # the list.  +list+ is a list of option strings.  Returns the pair
+    # [option_name, option_index].
+
     def choose_from_list(question, list)
       @outs.puts question
+
       list.each_with_index do |item, index|
         @outs.puts " #{index+1}. #{item}"
       end
+
       @outs.print "> "
       @outs.flush
 
@@ -109,28 +138,32 @@
       return list[result], result
     end
 
-    # Ask a question.  Returns a true for yes, false for no.  If not
-    # connected to a tty, raises an exception if default is nil,
-    # otherwise returns default.
+    ##
+    # Ask a question.  Returns a true for yes, false for no.  If not connected
+    # to a tty, raises an exception if default is nil, otherwise returns
+    # default.
+
     def ask_yes_no(question, default=nil)
-      if not @ins.tty? then
+      unless @ins.tty? then
         if default.nil? then
-          raise(
-              Gem::OperationNotSupportedError,
-              "Not connected to a tty and no default specified")
+          raise Gem::OperationNotSupportedError,
+                "Not connected to a tty and no default specified"
         else
           return default
         end
       end
+
       qstr = case default
-      when nil
-        'yn'
-      when true
-        'Yn'
-      else
-        'yN'
-      end
+             when nil
+               'yn'
+             when true
+               'Yn'
+             else
+               'yN'
+             end
+
       result = nil
+
       while result.nil?
         result = ask("#{question} [#{qstr}]")
         result = case result
@@ -144,51 +177,68 @@
           nil
         end
       end
+
       return result
     end
-    
-    # Ask a question.  Returns an answer if connected to a tty, nil
-    # otherwise.
+
+    ##
+    # Ask a question.  Returns an answer if connected to a tty, nil otherwise.
+
     def ask(question)
       return nil if not @ins.tty?
+
       @outs.print(question + "  ")
       @outs.flush
+
       result = @ins.gets
       result.chomp! if result
       result
     end
-    
+
+    ##
     # Display a statement.
+
     def say(statement="")
       @outs.puts statement
     end
-    
-    # Display an informational alert.
+
+    ##
+    # Display an informational alert.  Will ask +question+ if it is not nil.
+
     def alert(statement, question=nil)
       @outs.puts "INFO:  #{statement}"
-      return ask(question) if question 
+      ask(question) if question
     end
-    
-    # Display a warning in a location expected to get error messages.
+
+    ##
+    # Display a warning in a location expected to get error messages.  Will
+    # ask +question+ if it is not nil.
+
     def alert_warning(statement, question=nil)
       @errs.puts "WARNING:  #{statement}"
-      ask(question) if question 
+      ask(question) if question
     end
-    
-    # Display an error message in a location expected to get error
-    # messages.
+
+    ##
+    # Display an error message in a location expected to get error messages.
+    # Will ask +question+ if it is not nil.
+
     def alert_error(statement, question=nil)
       @errs.puts "ERROR:  #{statement}"
       ask(question) if question
     end
 
-    # Terminate the appliation normally, running any exit handlers
-    # that might have been defined.
+    ##
+    # Terminate the application with exit code +status+, running any exit
+    # handlers that might have been defined.
+
     def terminate_interaction(status = 0)
       raise Gem::SystemExitException, status
     end
 
-    # Return a progress reporter object
+    ##
+    # Return a progress reporter object chosen from the current verbosity.
+
     def progress_reporter(*args)
       case Gem.configuration.verbose
       when nil, false
@@ -200,6 +250,9 @@
       end
     end
 
+    ##
+    # An absolutely silent progress reporter.
+
     class SilentProgressReporter
       attr_reader :count
 
@@ -213,6 +266,9 @@
       end
     end
 
+    ##
+    # A basic dotted progress reporter.
+
     class SimpleProgressReporter
       include DefaultUserInteraction
 
@@ -228,17 +284,27 @@
         @out.puts initial_message
       end
 
+      ##
+      # Prints out a dot and ignores +message+.
+
       def updated(message)
         @count += 1
         @out.print "."
         @out.flush
       end
 
+      ##
+      # Prints out the terminal message.
+
       def done
         @out.puts "\n#{@terminal_message}"
       end
+
     end
 
+    ##
+    # A progress reporter that prints out messages about the current progress.
+
     class VerboseProgressReporter
       include DefaultUserInteraction
 
@@ -254,32 +320,41 @@
         @out.puts initial_message
       end
 
+      ##
+      # Prints out the position relative to the total and the +message+.
+
       def updated(message)
         @count += 1
         @out.puts "#{@count}/#{@total}: #{message}"
       end
 
+      ##
+      # Prints out the terminal message.
+
       def done
         @out.puts @terminal_message
       end
     end
   end
 
-  ####################################################################
-  # Subclass of StreamUI that instantiates the user interaction using
-  # standard in, out and error.
+  ##
+  # Subclass of StreamUI that instantiates the user interaction using STDIN,
+  # STDOUT, and STDERR.
+
   class ConsoleUI < StreamUI
     def initialize
       super(STDIN, STDOUT, STDERR)
     end
   end
 
-  ####################################################################
+  ##
   # SilentUI is a UI choice that is absolutely silent.
+
   class SilentUI
     def method_missing(sym, *args, &block)
       self
     end
   end
+
 end
 

Modified: MacRuby/branches/experimental/lib/rubygems/validator.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/validator.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/validator.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -10,118 +10,130 @@
 require 'rubygems/format'
 require 'rubygems/installer'
 
-module Gem
+##
+# Validator performs various gem file and gem database validation
 
-  ##
-  # Validator performs various gem file and gem database validation
-  class Validator
-    include UserInteraction
+class Gem::Validator
 
-    ##
-    # Given a gem file's contents, validates against its own MD5 checksum
-    # gem_data:: [String] Contents of the gem file
-    def verify_gem(gem_data)
-      raise VerificationError, 'empty gem file' if gem_data.size == 0
+  include Gem::UserInteraction
 
-      unless gem_data =~ /MD5SUM/ then
-        return # Don't worry about it...this sucks.  Need to fix MD5 stuff for
-               # new format
-               # FIXME
-      end
+  ##
+  # Given a gem file's contents, validates against its own MD5 checksum
+  # gem_data:: [String] Contents of the gem file
 
-      sum_data = gem_data.gsub(/MD5SUM = "([a-z0-9]+)"/,
-                               "MD5SUM = \"#{"F" * 32}\"")
+  def verify_gem(gem_data)
+    raise Gem::VerificationError, 'empty gem file' if gem_data.size == 0
 
-      unless Gem::MD5.hexdigest(sum_data) == $1.to_s then
-        raise VerificationError, 'invalid checksum for gem file'
-      end
+    unless gem_data =~ /MD5SUM/ then
+      return # Don't worry about it...this sucks.  Need to fix MD5 stuff for
+      # new format
+      # FIXME
     end
 
-    ##
-    # Given the path to a gem file, validates against its own MD5 checksum
-    # 
-    # gem_path:: [String] Path to gem file
-    def verify_gem_file(gem_path)
-      File.open gem_path, 'rb' do |file|
-        gem_data = file.read
-        verify_gem gem_data
-      end
-    rescue Errno::ENOENT
-      raise Gem::VerificationError.new("missing gem file #{gem_path}")
+    sum_data = gem_data.gsub(/MD5SUM = "([a-z0-9]+)"/,
+                             "MD5SUM = \"#{"F" * 32}\"")
+
+    unless Gem::MD5.hexdigest(sum_data) == $1.to_s then
+      raise Gem::VerificationError, 'invalid checksum for gem file'
     end
+  end
 
-    private
-    def find_files_for_gem(gem_directory)
-      installed_files = []
-      Find.find(gem_directory) {|file_name|
-        fn = file_name.slice((gem_directory.size)..(file_name.size-1)).sub(/^\//, "")
-        if(!(fn =~ /CVS/ || File.directory?(fn) || fn == "")) then 
-          installed_files << fn
-        end
-        
-      }
-      installed_files
+  ##
+  # Given the path to a gem file, validates against its own MD5 checksum
+  #
+  # gem_path:: [String] Path to gem file
+
+  def verify_gem_file(gem_path)
+    open gem_path, Gem.binary_mode do |file|
+      gem_data = file.read
+      verify_gem gem_data
     end
- 
+  rescue Errno::ENOENT
+    raise Gem::VerificationError, "missing gem file #{gem_path}"
+  end
 
-    public 
-    ErrorData = Struct.new(:path, :problem)
+  private
 
-    ##
-    # Checks the gem directory for the following potential 
-    # inconsistencies/problems:
-    # * Checksum gem itself
-    # * For each file in each gem, check consistency of installed versions
-    # * Check for files that aren't part of the gem but are in the gems directory
-    # * 1 cache - 1 spec - 1 directory.  
-    # 
-    # returns a hash of ErrorData objects, keyed on the problem gem's name.
-    def alien
-      errors = {}
-      Gem::SourceIndex.from_installed_gems.each do |gem_name, gem_spec|
-        errors[gem_name] ||= []
-        gem_path = File.join(Gem.dir, "cache", gem_spec.full_name) + ".gem"
-        spec_path = File.join(Gem.dir, "specifications", gem_spec.full_name) + ".gemspec"
-        gem_directory = File.join(Gem.dir, "gems", gem_spec.full_name)
-        installed_files = find_files_for_gem(gem_directory)
-    
-        if(!File.exist?(spec_path)) then
-          errors[gem_name] << ErrorData.new(spec_path, "Spec file doesn't exist for installed gem")
-        end
-    
-        begin
-          verify_gem_file(gem_path)
-          File.open(gem_path, 'rb') do |file|
-            format = Gem::Format.from_file_by_path(gem_path)
-            format.file_entries.each do |entry, data|
-              # Found this file.  Delete it from list
-              installed_files.delete remove_leading_dot_dir(entry['path'])
+  def find_files_for_gem(gem_directory)
+    installed_files = []
+    Find.find(gem_directory) {|file_name|
+      fn = file_name.slice((gem_directory.size)..(file_name.size-1)).sub(/^\//, "")
+      if(!(fn =~ /CVS/ || File.directory?(fn) || fn == "")) then
+        installed_files << fn
+      end
 
-              next unless data # HACK `gem check -a mkrf`
+    }
+    installed_files
+  end
 
-              File.open(File.join(gem_directory, entry['path']), 'rb') do |f|
-                unless Gem::MD5.hexdigest(f.read).to_s ==
-                       Gem::MD5.hexdigest(data).to_s then
-                  errors[gem_name] << ErrorData.new(entry['path'], "installed file doesn't match original from gem")
-                end
+  public
+
+  ErrorData = Struct.new :path, :problem
+
+  ##
+  # Checks the gem directory for the following potential
+  # inconsistencies/problems:
+  #
+  # * Checksum gem itself
+  # * For each file in each gem, check consistency of installed versions
+  # * Check for files that aren't part of the gem but are in the gems directory
+  # * 1 cache - 1 spec - 1 directory.
+  #
+  # returns a hash of ErrorData objects, keyed on the problem gem's name.
+
+  def alien
+    errors = {}
+
+    Gem::SourceIndex.from_installed_gems.each do |gem_name, gem_spec|
+      errors[gem_name] ||= []
+
+      gem_path = File.join(Gem.dir, "cache", gem_spec.full_name) + ".gem"
+      spec_path = File.join(Gem.dir, "specifications", gem_spec.full_name) + ".gemspec"
+      gem_directory = File.join(Gem.dir, "gems", gem_spec.full_name)
+
+      installed_files = find_files_for_gem(gem_directory)
+
+      unless File.exist? spec_path then
+        errors[gem_name] << ErrorData.new(spec_path, "Spec file doesn't exist for installed gem")
+      end
+
+      begin
+        verify_gem_file(gem_path)
+
+        open gem_path, Gem.binary_mode do |file|
+          format = Gem::Format.from_file_by_path(gem_path)
+          format.file_entries.each do |entry, data|
+            # Found this file.  Delete it from list
+            installed_files.delete remove_leading_dot_dir(entry['path'])
+
+            next unless data # HACK `gem check -a mkrf`
+
+            open File.join(gem_directory, entry['path']), Gem.binary_mode do |f|
+              unless Gem::MD5.hexdigest(f.read).to_s ==
+                Gem::MD5.hexdigest(data).to_s then
+                errors[gem_name] << ErrorData.new(entry['path'], "installed file doesn't match original from gem")
               end
             end
           end
-        rescue VerificationError => e
-          errors[gem_name] << ErrorData.new(gem_path, e.message)
         end
-        # Clean out directories that weren't explicitly included in the gemspec
-        # FIXME: This still allows arbitrary incorrect directories.
-        installed_files.delete_if {|potential_directory|        
-          File.directory?(File.join(gem_directory, potential_directory))
-        }
-        if(installed_files.size > 0) then
-          errors[gem_name] << ErrorData.new(gem_path, "Unmanaged files in gem: #{installed_files.inspect}")
-        end
+      rescue Gem::VerificationError => e
+        errors[gem_name] << ErrorData.new(gem_path, e.message)
       end
-      errors
+
+      # Clean out directories that weren't explicitly included in the gemspec
+      # FIXME: This still allows arbitrary incorrect directories.
+      installed_files.delete_if {|potential_directory|
+        File.directory?(File.join(gem_directory, potential_directory))
+      }
+      if(installed_files.size > 0) then
+        errors[gem_name] << ErrorData.new(gem_path, "Unmanaged files in gem: #{installed_files.inspect}")
+      end
     end
 
+    errors
+  end
+
+  if RUBY_VERSION < '1.9' then
     class TestRunner
       def initialize(suite, ui)
         @suite = suite
@@ -147,40 +159,51 @@
     end
 
     autoload :TestRunner, 'test/unit/ui/testrunnerutilities'
-   
-    ##
-    # Runs unit tests for a given gem specification
-    def unit_test(gem_spec)
-     start_dir = Dir.pwd
-     Dir.chdir(gem_spec.full_gem_path)
-      $: << File.join(Gem.dir, "gems", gem_spec.full_name)
-        # XXX: why do we need this gem_spec when we've already got 'spec'?
-      test_files = gem_spec.test_files
-      if test_files.empty?
-        say "There are no unit tests to run for #{gem_spec.full_name}"
-        require 'test/unit/ui/console/testrunner'
-        return Test::Unit::TestResult.new
-      end
-      gem gem_spec.name, "= #{gem_spec.version.version}"
-      test_files.each do |f| require f end
+  end
+
+  ##
+  # Runs unit tests for a given gem specification
+
+  def unit_test(gem_spec)
+    start_dir = Dir.pwd
+    Dir.chdir(gem_spec.full_gem_path)
+    $: << File.join(Gem.dir, "gems", gem_spec.full_name)
+    # XXX: why do we need this gem_spec when we've already got 'spec'?
+    test_files = gem_spec.test_files
+
+    if test_files.empty? then
+      say "There are no unit tests to run for #{gem_spec.full_name}"
+      return nil
+    end
+
+    gem gem_spec.name, "= #{gem_spec.version.version}"
+
+    test_files.each do |f| require f end
+
+    if RUBY_VERSION < '1.9' then
       suite = Test::Unit::TestSuite.new("#{gem_spec.name}-#{gem_spec.version}")
+
       ObjectSpace.each_object(Class) do |klass|
         suite << klass.suite if (klass < Test::Unit::TestCase)
       end
-      result = TestRunner.run(suite, ui())
-      unless result.passed?
-        alert_error(result.to_s)
-        #unless ask_yes_no(result.to_s + "...keep Gem?", true) then
-          #Gem::Uninstaller.new(gem_spec.name, gem_spec.version.version).uninstall
-        #end
-      end
-      result
-    ensure
-      Dir.chdir(start_dir)
+
+      result = TestRunner.run suite, ui
+
+      alert_error result.to_s unless result.passed?
+    else
+      result = MiniTest::Unit.new
+      result.run
     end
 
-    def remove_leading_dot_dir(path)
-      path.sub(/^\.\//, "")
-    end
+    result
+  ensure
+    Dir.chdir(start_dir)
   end
+
+  private
+  def remove_leading_dot_dir(path)
+    path.sub(/^\.\//, "")
+  end
+
 end
+

Modified: MacRuby/branches/experimental/lib/rubygems/version.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems/version.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems/version.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -8,6 +8,7 @@
 
 ##
 # The Version class processes string versions into comparable values
+
 class Gem::Version
 
   include Comparable
@@ -17,11 +18,8 @@
   attr_reader :version
 
   ##
-  # Checks if version string is valid format
-  #
-  # str:: [String] the version string
-  # return:: [Boolean] true if the string format is correct, otherwise false
-  #
+  # Returns true if +version+ is a valid version string.
+
   def self.correct?(version)
     case version
     when Integer, /\A\s*(\d+(\.\d+)*)*\s*\z/ then true
@@ -36,7 +34,7 @@
   #   ver1 = Version.create('1.3.17')   # -> (Version object)
   #   ver2 = Version.create(ver1)       # -> (ver1)
   #   ver3 = Version.create(nil)        # -> nil
-  #
+
   def self.create(input)
     if input.respond_to? :version then
       input
@@ -48,10 +46,9 @@
   end
 
   ##
-  # Constructs a version from the supplied string
-  #
-  # version:: [String] The version string.  Format is digit.digit...
-  #
+  # Constructs a Version from the +version+ string.  A version string is a
+  # series of digits separated by dots.
+
   def initialize(version)
     raise ArgumentError, "Malformed version number string #{version}" unless
       self.class.correct?(version)
@@ -73,7 +70,9 @@
     self.version = array[0]
   end
 
+  ##
   # Strip ignored trailing zeros.
+
   def normalize
     @ints = build_array_from_version_string
 
@@ -94,10 +93,8 @@
   end
 
   ##
-  # Convert version to integer array
-  #
-  # return:: [Array] list of integers
-  #
+  # Returns an integer array representation of this Version.
+
   def to_ints
     normalize unless @ints
     @ints
@@ -117,20 +114,25 @@
   end
 
   ##
-  # Compares two versions
-  #
-  # other:: [Version or .ints] other version to compare to
-  # return:: [Fixnum] -1, 0, 1
-  #
+  # Compares this version with +other+ returning -1, 0, or 1 if the other
+  # version is larger, the same, or smaller than this one.
+
   def <=>(other)
+    return nil unless self.class === other
     return 1 unless other
     @ints <=> other.ints
   end
 
-  alias eql? == # :nodoc:
+  ##
+  # A Version is only eql? to another version if it has the same version
+  # string.  "1.0" is not the same version as "1".
 
+  def eql?(other)
+    self.class === other and @version == other.version
+  end
+
   def hash # :nodoc:
-    to_ints.inject { |hash_code, n| hash_code + n }
+    @version.hash
   end
 
   # Return a new version object where the next to the last revision

Modified: MacRuby/branches/experimental/lib/rubygems.rb
===================================================================
--- MacRuby/branches/experimental/lib/rubygems.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/rubygems.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -43,12 +43,14 @@
   #
   #   GEM_SKIP=libA:libB ruby -I../libA -I../libB ./mycode.rb
 
-  def gem(gem_name, *version_requirements)
+  def gem(gem_name, *version_requirements) # :doc:
     skip_list = (ENV['GEM_SKIP'] || "").split(/:/)
     raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name
     Gem.activate(gem_name, *version_requirements)
   end
 
+  private :gem
+
 end
 
 ##
@@ -67,11 +69,14 @@
     :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
     :arch => RbConfig::CONFIG["arch"],
     :bindir => RbConfig::CONFIG["bindir"],
+    :datadir => RbConfig::CONFIG["datadir"],
     :libdir => RbConfig::CONFIG["libdir"],
     :ruby_install_name => RbConfig::CONFIG["ruby_install_name"],
     :ruby_version => RbConfig::CONFIG["ruby_version"],
     :sitedir => RbConfig::CONFIG["sitedir"],
-    :sitelibdir => RbConfig::CONFIG["sitelibdir"]
+    :sitelibdir => RbConfig::CONFIG["sitelibdir"],
+    :vendordir => RbConfig::CONFIG["vendordir"] ,
+    :vendorlibdir => RbConfig::CONFIG["vendorlibdir"]
   )
 
   DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES)
@@ -101,6 +106,11 @@
   @ruby = nil
   @sources = []
 
+  @post_install_hooks   ||= []
+  @post_uninstall_hooks ||= []
+  @pre_uninstall_hooks  ||= []
+  @pre_install_hooks    ||= []
+
   ##
   # Activates an installed gem matching +gem+.  The gem must satisfy
   # +version_requirements+.
@@ -137,7 +147,7 @@
 
       unless matches.any? { |spec| spec.version == existing_spec.version } then
         raise Gem::Exception,
-              "can't activate #{gem}, already activated #{existing_spec.full_name}]"
+              "can't activate #{gem}, already activated #{existing_spec.full_name}"
       end
 
       return false
@@ -151,7 +161,7 @@
     @loaded_specs[spec.name] = spec
 
     # Load dependent gems first
-    spec.dependencies.each do |dep_gem|
+    spec.runtime_dependencies.each do |dep_gem|
       activate dep_gem
     end
 
@@ -204,6 +214,20 @@
   private_class_method :all_partials
 
   ##
+  # See if a given gem is available.
+
+  def self.available?(gem, *requirements)
+    requirements = Gem::Requirement.default if requirements.empty?
+
+    unless gem.respond_to?(:name) and
+           gem.respond_to?(:version_requirements) then
+      gem = Gem::Dependency.new gem, requirements
+    end
+
+    !Gem.source_index.search(gem).empty?
+  end
+
+  ##
   # The mode needed to read a file as straight binary.
 
   def self.binary_mode
@@ -227,7 +251,10 @@
   def self.clear_paths
     @gem_home = nil
     @gem_path = nil
+    @user_home = nil
+
     @@source_index = nil
+
     MUTEX.synchronize do
       @searcher = nil
     end
@@ -244,9 +271,7 @@
   # The standard configuration object for gems.
 
   def self.configuration
-    return @configuration if @configuration
-    require 'rubygems/config_file'
-    @configuration = Gem::ConfigFile.new []
+    @configuration ||= Gem::ConfigFile.new []
   end
 
   ##
@@ -268,11 +293,19 @@
   end
 
   ##
+  # A Zlib::Deflate.deflate wrapper
+
+  def self.deflate(data)
+    require 'zlib'
+    Zlib::Deflate.deflate data
+  end
+
+  ##
   # The path where gems are to be installed.
 
   def self.dir
     @gem_home ||= nil
-    set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
+    set_home(ENV['GEM_HOME'] || Gem.configuration.home || default_dir) unless @gem_home
     @gem_home
   end
 
@@ -313,6 +346,22 @@
   end
 
   ##
+  # Returns a list of paths matching +file+ that can be used by a gem to pick
+  # up features from other gems.  For example:
+  #
+  #   Gem.find_files('rdoc/discover').each do |path| load path end
+  #
+  # find_files does not search $LOAD_PATH for files, only gems.
+
+  def self.find_files(path)
+    specs = searcher.find_all path
+
+    specs.map do |spec|
+      searcher.matching_files spec, path
+    end.flatten
+  end
+
+  ##
   # Finds the user's home directory.
   #--
   # Some comments from the ruby-talk list regarding finding the home
@@ -329,7 +378,7 @@
     end
 
     if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
-      return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
+      return "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}"
     end
 
     begin
@@ -346,6 +395,38 @@
   private_class_method :find_home
 
   ##
+  # Zlib::GzipReader wrapper that unzips +data+.
+
+  def self.gunzip(data)
+    require 'stringio'
+    require 'zlib'
+    data = StringIO.new data
+
+    Zlib::GzipReader.new(data).read
+  end
+
+  ##
+  # Zlib::GzipWriter wrapper that zips +data+.
+
+  def self.gzip(data)
+    require 'stringio'
+    require 'zlib'
+    zipped = StringIO.new
+
+    Zlib::GzipWriter.wrap zipped do |io| io.write data end
+
+    zipped.string
+  end
+
+  ##
+  # A Zlib::Inflate#inflate wrapper
+
+  def self.inflate(data)
+    require 'zlib'
+    Zlib::Inflate.inflate data
+  end
+
+  ##
   # Return a list of all possible load paths for the latest version for all
   # gems in the Gem installation.
 
@@ -406,22 +487,20 @@
   # The file name and line number of the caller of the caller of this method.
 
   def self.location_of_caller
-    file, lineno = caller[1].split(':')
-    lineno = lineno.to_i
+    caller[1] =~ /(.*?):(\d+)$/i
+    file = $1
+    lineno = $2.to_i
+
     [file, lineno]
   end
 
-  private_class_method :location_of_caller
-
   ##
   # manage_gems is useless and deprecated.  Don't call it anymore.
-  #--
-  # TODO warn w/ RubyGems 1.2.x release.
 
-  def self.manage_gems
-    #file, lineno = location_of_caller
+  def self.manage_gems # :nodoc:
+    file, lineno = location_of_caller
 
-    #warn "#{file}:#{lineno}:Warning: Gem#manage_gems is deprecated and will be removed on or after September 2008."
+    warn "#{file}:#{lineno}:Warning: Gem::manage_gems is deprecated and will be removed on or after March 2009."
   end
 
   ##
@@ -438,7 +517,7 @@
     @gem_path ||= nil
 
     unless @gem_path then
-      paths = [ENV['GEM_PATH']] || [default_path]
+      paths = [ENV['GEM_PATH'] || Gem.configuration.path || default_path]
 
       if defined?(APPLE_GEM_HOME) and not ENV['GEM_PATH'] then
         paths << APPLE_GEM_HOME
@@ -459,7 +538,7 @@
 
   ##
   # Array of platforms this RubyGems supports.
-  
+
   def self.platforms
     @platforms ||= []
     if @platforms.empty?
@@ -469,6 +548,40 @@
   end
 
   ##
+  # Adds a post-install hook that will be passed an Gem::Installer instance
+  # when Gem::Installer#install is called
+
+  def self.post_install(&hook)
+    @post_install_hooks << hook
+  end
+
+  ##
+  # Adds a post-uninstall hook that will be passed a Gem::Uninstaller instance
+  # and the spec that was uninstalled when Gem::Uninstaller#uninstall is
+  # called
+
+  def self.post_uninstall(&hook)
+    @post_uninstall_hooks << hook
+  end
+
+  ##
+  # Adds a pre-install hook that will be passed an Gem::Installer instance
+  # when Gem::Installer#install is called
+
+  def self.pre_install(&hook)
+    @pre_install_hooks << hook
+  end
+
+  ##
+  # Adds a pre-uninstall hook that will be passed an Gem::Uninstaller instance
+  # and the spec that will be uninstalled when Gem::Uninstaller#uninstall is
+  # called
+
+  def self.pre_uninstall(&hook)
+    @pre_uninstall_hooks << hook
+  end
+
+  ##
   # The directory prefix this RubyGems was installed at.
 
   def self.prefix
@@ -545,6 +658,9 @@
       @ruby = File.join(ConfigMap[:bindir],
                         ConfigMap[:ruby_install_name])
       @ruby << ConfigMap[:EXEEXT]
+
+      # escape string in case path to ruby executable contain spaces.
+      @ruby.sub!(/.*\s.*/m, '"\&"')
     end
 
     @ruby
@@ -586,20 +702,30 @@
   def self.set_paths(gpaths)
     if gpaths
       @gem_path = gpaths.split(File::PATH_SEPARATOR)
-      
+
       if File::ALT_SEPARATOR then
         @gem_path.map! do |path|
           path.gsub File::ALT_SEPARATOR, File::SEPARATOR
         end
       end
-      
+
       @gem_path << Gem.dir
     else
+      # TODO: should this be Gem.default_path instead?
       @gem_path = [Gem.dir]
     end
 
     @gem_path.uniq!
-    @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
+    @gem_path.each do |path|
+      if 0 == File.expand_path(path).index(Gem.user_home)
+        next unless File.directory? Gem.user_home
+        unless win_platform? then
+          # only create by matching user
+          next if Etc.getpwuid.uid != File::Stat.new(Gem.user_home).uid
+        end
+      end
+      ensure_gem_subdirectories path
+    end
   end
 
   private_class_method :set_paths
@@ -630,6 +756,14 @@
   end
 
   ##
+  # Need to be able to set the sources without calling
+  # Gem.sources.replace since that would cause an infinite loop.
+
+  def self.sources=(new_sources)
+    @sources = new_sources
+  end
+
+  ##
   # Glob pattern for require-able path suffixes.
 
   def self.suffix_pattern
@@ -675,6 +809,27 @@
 
     attr_reader :loaded_specs
 
+    ##
+    # The list of hooks to be run before Gem::Install#install does any work
+
+    attr_reader :post_install_hooks
+
+    ##
+    # The list of hooks to be run before Gem::Uninstall#uninstall does any
+    # work
+
+    attr_reader :post_uninstall_hooks
+
+    ##
+    # The list of hooks to be run after Gem::Install#install is finished
+
+    attr_reader :pre_install_hooks
+
+    ##
+    # The list of hooks to be run after Gem::Uninstall#uninstall is finished
+
+    attr_reader :pre_uninstall_hooks
+
     # :stopdoc:
 
     alias cache source_index # an alias for the old name
@@ -683,24 +838,25 @@
 
   end
 
-end
+  MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/"
 
-# Modify the non-gem version of datadir to handle gem package names.
+  YAML_SPEC_DIR = 'quick/'
 
-require 'rbconfig/datadir'
+end
 
-module Config # :nodoc:
+module Config
+  # :stopdoc:
   class << self
-    alias gem_original_datadir datadir
-
     # Return the path to the data directory associated with the named
     # package.  If the package is loaded as a gem, return the gem
     # specific data directory.  Otherwise return a path to the share
     # area as define by "#{ConfigMap[:datadir]}/#{package_name}".
     def datadir(package_name)
-      Gem.datadir(package_name) || Config.gem_original_datadir(package_name)
+      Gem.datadir(package_name) ||
+        File.join(Gem::ConfigMap[:datadir], package_name)
     end
   end
+  # :startdoc:
 end
 
 require 'rubygems/exceptions'
@@ -712,7 +868,22 @@
 require 'rubygems/platform'
 require 'rubygems/builder'              # HACK: Needed for rake's package task.
 
+begin
+  require 'rubygems/defaults/operating_system'
+rescue LoadError
+end
+
+if defined?(RUBY_ENGINE) then
+  begin
+    require "rubygems/defaults/#{RUBY_ENGINE}"
+  rescue LoadError
+  end
+end
+
+require 'rubygems/config_file'
+
 if RUBY_VERSION < '1.9' then
   require 'rubygems/custom_require'
 end
 
+Gem.clear_paths

Modified: MacRuby/branches/experimental/lib/scanf.rb
===================================================================
--- MacRuby/branches/experimental/lib/scanf.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/scanf.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,9 +1,9 @@
 # scanf for Ruby
 #
 # $Release Version: 1.1.2 $
-# $Revision: 14912 $
-# $Id: scanf.rb 14912 2008-01-06 15:49:38Z akr $
-# $Author: akr $
+# $Revision: 19094 $
+# $Id: scanf.rb 19094 2008-09-03 12:54:13Z dblack $
+# $Author: dblack $
 #
 # A product of the Austin Ruby Codefest (Austin, Texas, August 2002)
 
@@ -325,7 +325,7 @@
     end
 
     def count_space?
-      /(?:\A|\S)%\*?\d*c|\[/.match(@spec_string)
+      /(?:\A|\S)%\*?\d*c|%\d*\[/.match(@spec_string)
     end
 
     def initialize(str)
@@ -357,7 +357,7 @@
 
           # %i
         when /%\*?i/
-          [ "([-+]?(?:(?:0[0-7]+)|(?:0[Xx]#{h}+)|(?:[1-9]\\d+)))", :extract_integer ]
+          [ "([-+]?(?:(?:0[0-7]+)|(?:0[Xx]#{h}+)|(?:[1-9]\\d*)))", :extract_integer ]
 
           # %5i
         when /%\*?(\d+)i/

Modified: MacRuby/branches/experimental/lib/shell/command-processor.rb
===================================================================
--- MacRuby/branches/experimental/lib/shell/command-processor.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/shell/command-processor.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   shell/command-controller.rb - 
 #   	$Release Version: 0.7 $
-#   	$Revision: 14912 $
+#   	$Revision: 20880 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -26,7 +26,7 @@
     #
     m = [:initialize, :expand_path]
     if Object.methods.first.kind_of?(String)
-      NoDelegateMethods = m.collect{|m| m.id2name}
+      NoDelegateMethods = m.collect{|x| x.id2name}
     else
       NoDelegateMethods = m
     end
@@ -124,7 +124,7 @@
 	  f = File.open(path, mode, perm)
 	  File.chmod(perm & ~@shell.umask, path)
 	  if block_given?
-	    f.each &b
+	    f.each(&b)
 	  end
 	  f
 	else

Modified: MacRuby/branches/experimental/lib/shell/process-controller.rb
===================================================================
--- MacRuby/branches/experimental/lib/shell/process-controller.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/shell/process-controller.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   shell/process-controller.rb - 
 #   	$Release Version: 0.7 $
-#   	$Revision: 14912 $
+#   	$Revision: 20880 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -62,7 +62,7 @@
       end
 
       def block_output_synchronize(&b)
-	@BlockOutputMonitor.synchronize &b
+	@BlockOutputMonitor.synchronize(&b)
       end
 
       def wait_to_finish_all_process_controllers
@@ -84,7 +84,7 @@
       end
     end
 
-    # for shell-command complete finish at this prosess exit.
+    # for shell-command complete finish at this process exit.
     USING_AT_EXIT_WHEN_PROCESS_EXIT = true
     at_exit do
       wait_to_finish_all_process_controllers unless $@

Modified: MacRuby/branches/experimental/lib/shell.rb
===================================================================
--- MacRuby/branches/experimental/lib/shell.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/shell.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -79,7 +79,7 @@
       @default_record_separator = rs
     end
 
-    # os resource mutecs
+    # os resource mutex
     mutex_methods = ["unlock", "lock", "locked?", "synchronize", "try_lock", "exclusive_unlock"]
     for m in mutex_methods
       def_delegator("@debug_output_mutex", m, "debug_output_"+m.to_s)

Modified: MacRuby/branches/experimental/lib/singleton.rb
===================================================================
--- MacRuby/branches/experimental/lib/singleton.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/singleton.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -9,9 +9,9 @@
 # *  this ensures that only one instance of Klass lets call it
 #    ``the instance'' can be created.
 #
-#    a,b  = Klass.instance, Klass.instance
-#    a == b   # => true
-#    a.new    #  NoMethodError - new is private ...
+#      a,b  = Klass.instance, Klass.instance
+#      a == b    # => true
+#      Klass.new #  NoMethodError - new is private ...
 #
 # *  ``The instance'' is created at instantiation time, in other
 #    words the first call of Klass.instance(), thus
@@ -30,7 +30,7 @@
 # *  Klass.new and Klass.allocate - as private
 #
 # Providing (or modifying) the class methods
-# *  Klass.inherited(sub_klass) and Klass.clone()  - 
+# *  Klass.inherited(sub_klass) and Klass.clone()  -
 #    to ensure that the Singleton pattern is properly
 #    inherited and cloned.
 #
@@ -70,17 +70,15 @@
   def dup
     raise TypeError, "can't dup instance of singleton #{self.class}"
   end
-  
-  private 
 
   #  default marshalling strategy
-  def _dump(depth = -1) 
+  def _dump(depth = -1)
     ''
   end
 
-  module SingletonClassMethods  
+  module SingletonClassMethods
     # properly clone the Singleton pattern - did you know
-    # that duping doesn't copy class methods?  
+    # that duping doesn't copy class methods?
     def clone
       Singleton.__init__(super)
     end
@@ -90,8 +88,8 @@
     end
 
     private
-    
-    #  ensure that the Singleton pattern is properly inherited   
+
+    #  ensure that the Singleton pattern is properly inherited
     def inherited(sub_klass)
       super
       Singleton.__init__(sub_klass)
@@ -114,12 +112,12 @@
       end
       klass
     end
-    
+
     private
 
     #  extending an object with Singleton is a bad idea
     undef_method :extend_object
-    
+
     def append_features(mod)
       #  help out people counting on transitive mixins
       unless mod.instance_of?(Class)
@@ -127,7 +125,7 @@
       end
       super
     end
-    
+
     def included(klass)
       super
       klass.private_class_method  :new, :allocate
@@ -135,7 +133,7 @@
       Singleton.__init__(klass)
     end
   end
-  
+
 end
 
 
@@ -143,14 +141,14 @@
 
 def num_of_instances(klass)
     "#{ObjectSpace.each_object(klass){}} #{klass} instance(s)"
-end 
+end
 
 # The basic and most important example.
 
 class SomeSingletonClass
   include Singleton
 end
-puts "There are #{num_of_instances(SomeSingletonClass)}" 
+puts "There are #{num_of_instances(SomeSingletonClass)}"
 
 a = SomeSingletonClass.instance
 b = SomeSingletonClass.instance # a and b are same object
@@ -173,23 +171,23 @@
     puts "initialize called by thread ##{Thread.current[:i]}"
   end
 end
-  
+
 class << Ups
   def _instantiate?
     @enter.push Thread.current[:i]
     while false.equal?(@singleton__instance__)
       @singleton__mutex__.unlock
-      sleep 0.08 
+      sleep 0.08
       @singleton__mutex__.lock
     end
     @leave.push Thread.current[:i]
     @singleton__instance__
   end
-  
+
   def __sleep
     sleep(rand(0.08))
   end
-  
+
   def new
     begin
       __sleep
@@ -201,12 +199,12 @@
       end
     end
   end
-  
+
   def instantiate_all
     @enter = []
     @leave = []
-    1.upto(9) {|i|  
-      Thread.new { 
+    1.upto(9) {|i|
+      Thread.new {
         begin
           Thread.current[:i] = i
           __sleep
@@ -296,7 +294,7 @@
 class Down < Middle; end
 
 puts  "and basic \"Down test\" is #{Down.instance == Down.instance}\n
-Various exceptions"  
+Various exceptions"
 
 begin
   module AModule

Modified: MacRuby/branches/experimental/lib/sync.rb
===================================================================
--- MacRuby/branches/experimental/lib/sync.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/sync.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 #   sync.rb - 2 phase lock with counter
 #   	$Release Version: 1.0$
-#   	$Revision: 14912 $
+#   	$Revision: 19280 $
 #   	by Keiju ISHITSUKA(keiju at ishitsuka.com)
 #
 # --
@@ -126,9 +126,9 @@
   
   # locking methods.
   def sync_try_lock(mode = EX)
-    return unlock if sync_mode == UN
+    return unlock if mode == UN
     @sync_mutex.synchronize do
-      ret = sync_try_lock_sub(sync_mode)
+      ret = sync_try_lock_sub(mode)
     end
     ret
   end

Modified: MacRuby/branches/experimental/lib/tempfile.rb
===================================================================
--- MacRuby/branches/experimental/lib/tempfile.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/tempfile.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 # tempfile - manipulates temporary files
 #
-# $Id: tempfile.rb 13428 2007-09-11 08:28:29Z knu $
+# $Id: tempfile.rb 19833 2008-10-18 10:32:26Z matz $
 #
 
 require 'delegate'
@@ -29,7 +29,12 @@
   # Dir::tmpdir provided by 'tmpdir.rb'.
   # When $SAFE > 0 and the given tmpdir is tainted, it uses
   # /tmp. (Note that ENV values are tainted by default)
-  def initialize(basename, tmpdir=Dir::tmpdir)
+  def initialize(basename, *rest)
+    # I wish keyword argument settled soon.
+    if opts = Hash.try_convert(rest[-1])
+      rest.pop
+    end
+    tmpdir = rest[0] || Dir::tmpdir
     if $SAFE > 0 and tmpdir.tainted?
       tmpdir = '/tmp'
     end
@@ -56,7 +61,12 @@
     @clean_proc = Tempfile.callback(@data)
     ObjectSpace.define_finalizer(self, @clean_proc)
 
-    @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
+    if opts.nil?
+      opts = []
+    else
+      opts = [opts]
+    end
+    @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600, *opts)
     @tmpname = tmpname
     @@cleanlist << @tmpname
     @data[1] = @tmpfile
@@ -187,8 +197,6 @@
 	ensure
 	  tempfile.close
 	end
-
-	nil
       else
 	tempfile
       end

Deleted: MacRuby/branches/experimental/lib/test/unit/assertionfailederror.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/assertionfailederror.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/assertionfailederror.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,14 +0,0 @@
-#--
-#
-# Author:: Nathaniel Talbott.
-# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
-# License:: Ruby license.
-
-module Test
-  module Unit
-
-    # Thrown by Test::Unit::Assertions when an assertion fails.
-    class AssertionFailedError < StandardError
-    end
-  end
-end

Modified: MacRuby/branches/experimental/lib/test/unit/assertions.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/assertions.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/assertions.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,622 +1,122 @@
-# Author:: Nathaniel Talbott.
-# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
-# License:: Ruby license.
+require 'minitest/unit'
+require 'pp'
 
-require 'test/unit/assertionfailederror'
-require 'test/unit/util/backtracefilter'
-
-module Test # :nodoc:
-  module Unit # :nodoc:
-
-    ##
-    # Test::Unit::Assertions contains the standard Test::Unit assertions.
-    # Assertions is included in Test::Unit::TestCase.
-    #
-    # To include it in your own code and use its functionality, you simply
-    # need to rescue Test::Unit::AssertionFailedError. Additionally you may
-    # override add_assertion to get notified whenever an assertion is made.
-    #
-    # Notes:
-    # * The message to each assertion, if given, will be propagated with the
-    #   failure.
-    # * It is easy to add your own assertions based on assert_block().
-    #
-    # = Example Custom Assertion
-    #
-    #   def deny(boolean, message = nil)
-    #     message = build_message message, '<?> is not false or nil.', boolean
-    #     assert_block message do
-    #       not boolean
-    #     end
-    #   end
-
+module Test
+  module Unit
     module Assertions
+      include MiniTest::Assertions
 
-      ##
-      # The assertion upon which all other assertions are based. Passes if the
-      # block yields true.
-      #
-      # Example:
-      #   assert_block "Couldn't do the thing" do
-      #     do_the_thing
-      #   end
-
-      public
-      def assert_block(message="assert_block failed.") # :yields: 
-        _wrap_assertion do
-          if (! yield)
-            raise AssertionFailedError.new(message.to_s)
-          end
-        end
+      def mu_pp(obj)
+        obj.pretty_inspect.chomp
       end
 
-      ##
-      # Asserts that +boolean+ is not false or nil.
-      #
-      # Example:
-      #   assert [1, 2].include?(5)
-
-      public
-      def assert(boolean, message=nil)
-        _wrap_assertion do
-          assert_block("assert should not be called with a block.") { !block_given? }
-          assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
-        end
+      def assert_raise(*args, &b)
+        assert_raises(*args, &b)
       end
 
-      ##
-      # Passes if +expected+ == +actual.
-      #
-      # Note that the ordering of arguments is important, since a helpful
-      # error message is generated when this one fails that tells you the
-      # values of expected and actual.
-      #
-      # Example:
-      #   assert_equal 'MY STRING', 'my string'.upcase
-
-      public
-      def assert_equal(expected, actual, message=nil)
-        full_message = build_message(message, <<EOT, expected, actual)
-<?> expected but was
-<?>.
-EOT
-        assert_block(full_message) { expected == actual }
-      end
-
-      private
-      def _check_exception_class(args) # :nodoc:
-        args.partition do |klass|
-          next if klass.instance_of?(Module)
-          assert(Exception >= klass, "Should expect a class of exception, #{klass}")
-          true
+      def assert_nothing_raised(*args)
+        self._assertions += 1
+        if Module === args.last
+          msg = nil
+        else
+          msg = args.pop
         end
-      end
-
-      private
-      def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
-        exceptions.include?(actual_exception.class) or
-          modules.any? {|mod| actual_exception.is_a?(mod)}
-      end
-
-      ##
-      # Passes if the block raises one of the given exceptions.
-      #
-      # Example:
-      #   assert_raise RuntimeError, LoadError do
-      #     raise 'Boom!!!'
-      #   end
-
-      public
-      def assert_raise(*args)
-        _wrap_assertion do
-          if Module === args.last
-            message = ""
+        begin
+          line = __LINE__; yield
+        rescue Exception => e
+          bt = e.backtrace
+          as = e.instance_of?(MiniTest::Assertion)
+          if as
+            ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o
+            bt.reject! {|line| ans =~ line}
+          end
+          if ((args.empty? && !as) ||
+              args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a })
+            msg = message(msg) { "Exception raised:\n<#{mu_pp(e)}>" }
+            raise MiniTest::Assertion, msg.call, bt
           else
-            message = args.pop
+            raise
           end
-          exceptions, modules = _check_exception_class(args)
-          expected = args.size == 1 ? args.first : args
-          actual_exception = nil
-          full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
-          assert_block(full_message) do
-            begin
-              yield
-            rescue Exception => actual_exception
-              break
-            end
-            false
-          end
-          full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
-          assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
-          actual_exception
         end
+        nil
       end
 
-      ##
-      # Alias of assert_raise.
-      #
-      # Will be deprecated in 1.9, and removed in 2.0.
-
-      public
-      def assert_raises(*args, &block)
-        assert_raise(*args, &block)
-      end
-
-      ##
-      # Passes if +object+ .instance_of? +klass+
-      #
-      # Example:
-      #   assert_instance_of String, 'foo'
-
-      public
-      def assert_instance_of(klass, object, message="")
-        _wrap_assertion do
-          assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
-          full_message = build_message(message, <<EOT, object, klass, object.class)
-<?> expected to be an instance of
-<?> but was
-<?>.
-EOT
-          assert_block(full_message){object.instance_of?(klass)}
+      def assert_nothing_thrown(msg=nil)
+        begin
+          yield
+        rescue ArgumentError => error
+          raise error if /\Auncaught throw (.+)\z/m !~ error.message
+          msg = message(msg) { "<#{$1}> was thrown when nothing was expected" }
+          flunk(msg)
         end
+        assert(true, "Expected nothing to be thrown")
       end
 
-      ##
-      # Passes if +object+ is nil.
-      #
-      # Example:
-      #   assert_nil [1, 2].uniq!
-
-      public
-      def assert_nil(object, message="")
-        assert_equal(nil, object, message)
-      end
-
-      ##
-      # Passes if +object+ .kind_of? +klass+
-      #
-      # Example:
-      #   assert_kind_of Object, 'foo'
-
-      public
-      def assert_kind_of(klass, object, message="")
-        _wrap_assertion do
-          assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
-          full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
-          assert_block(full_message){object.kind_of?(klass)}
-        end
-      end
-
-      ##
-      # Passes if +object+ .respond_to? +method+
-      #
-      # Example:
-      #   assert_respond_to 'bugbear', :slice
-
-      public
-      def assert_respond_to(object, method, message="")
-        _wrap_assertion do
-          full_message = build_message(nil, "<?>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method)
-
-          assert_block(full_message) do
-            method.kind_of?(Symbol) || method.respond_to?(:to_str)
-          end
-          full_message = build_message(message, <<EOT, object, object.class, method)
-<?>
-of type <?>
-expected to respond_to\\?<?>.
-EOT
-          assert_block(full_message) { object.respond_to?(method) }
-        end
-      end
-
-      ##
-      # Passes if +string+ =~ +pattern+.
-      #
-      # Example:
-      #   assert_match(/\d+/, 'five, 6, seven')
-
-      public
-      def assert_match(pattern, string, message="")
-        _wrap_assertion do
-          pattern = case(pattern)
-            when String
-              Regexp.new(Regexp.escape(pattern))
+      def assert_equal(exp, act, msg = nil)
+        msg = message(msg) {
+          exp_str = mu_pp(exp)
+          act_str = mu_pp(act)
+          exp_comment = ''
+          act_comment = ''
+          if exp_str == act_str
+            if (exp.is_a?(String) && act.is_a?(String)) ||
+               (exp.is_a?(Regexp) && act.is_a?(Regexp))
+              exp_comment = " (#{exp.encoding})"
+              act_comment = " (#{act.encoding})"
+            elsif exp.is_a?(Float) && act.is_a?(Float)
+              exp_str = "%\#.#{Float::DIG+2}g" % exp
+              act_str = "%\#.#{Float::DIG+2}g" % act
+            elsif exp.is_a?(Time) && act.is_a?(Time)
+              exp_comment = " (nsec=#{exp.nsec})"
+              act_comment = " (nsec=#{act.nsec})"
+            end
+          elsif !Encoding.compatible?(exp_str, act_str)
+            if exp.is_a?(String) && act.is_a?(String)
+              exp_str = exp.dump
+              act_str = act.dump
+              exp_comment = " (#{exp.encoding})"
+              act_comment = " (#{act.encoding})"
             else
-              pattern
+              exp_str = exp_str.dump
+              act_str = act_str.dump
+            end
           end
-          full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
-          assert_block(full_message) { string =~ pattern }
-        end
+          "<#{exp_str}>#{exp_comment} expected but was\n<#{act_str}>#{act_comment}"
+        }
+        assert(exp == act, msg)
       end
 
-      ##
-      # Passes if +actual+ .equal? +expected+ (i.e. they are the same
-      # instance).
-      #
-      # Example:
-      #   o = Object.new
-      #   assert_same o, o
-
-      public
-      def assert_same(expected, actual, message="")
-        full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
-<?>
-with id <?> expected to be equal\\? to
-<?>
-with id <?>.
-EOT
-        assert_block(full_message) { actual.equal?(expected) }
+      def assert_not_nil(exp, msg=nil)
+        msg = message(msg) { "<#{mu_pp(exp)}> expected to not be nil" }
+        assert(!exp.nil?, msg)
       end
 
-      ##
-      # Compares the +object1+ with +object2+ using +operator+.
-      #
-      # Passes if object1.__send__(operator, object2) is true.
-      #
-      # Example:
-      #   assert_operator 5, :>=, 4
-
-      public
-      def assert_operator(object1, operator, object2, message="")
-        _wrap_assertion do
-          full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
-          assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
-          full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
-<?> expected to be
-?
-<?>.
-EOT
-          assert_block(full_message) { object1.__send__(operator, object2) }
-        end
+      def assert_not_equal(exp, act, msg=nil)
+        msg = message(msg) { "<#{mu_pp(exp)}> expected to be != to\n<#{mu_pp(act)}>" }
+        assert(exp != act, msg)
       end
 
-      ##
-      # Passes if block does not raise an exception.
-      #
-      # Example:
-      #   assert_nothing_raised do
-      #     [1, 2].uniq
-      #   end
-
-      public
-      def assert_nothing_raised(*args)
-        _wrap_assertion do
-          if Module === args.last
-            message = ""
-          else
-            message = args.pop
-          end
-          exceptions, modules = _check_exception_class(args)
-          begin
-            yield
-          rescue Exception => e
-            if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
-                _expected_exception?(e, exceptions, modules))
-              assert_block(build_message(message, "Exception raised:\n?", e)){false}
-            else
-              raise
-            end
-          end
-          nil
-        end
+      def assert_no_match(regexp, string, msg=nil)
+        assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
+        self._assertions -= 1
+        msg = message(msg) { "<#{mu_pp(regexp)}> expected to not match\n<#{mu_pp(string)}>" }
+        assert(regexp !~ string, msg)
       end
 
-      ##
-      # Flunk always fails.
-      #
-      # Example:
-      #   flunk 'Not done testing yet.'
-
-      public
-      def flunk(message="Flunked")
-        assert_block(build_message(message)){false}
-      end
-
-      ##
-      # Passes if ! +actual+ .equal? +expected+
-      #
-      # Example:
-      #   assert_not_same Object.new, Object.new
-
-      public
       def assert_not_same(expected, actual, message="")
-        full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
+        msg = message(msg) { build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__) }
 <?>
 with id <?> expected to not be equal\\? to
 <?>
 with id <?>.
 EOT
-        assert_block(full_message) { !actual.equal?(expected) }
+        assert(!actual.equal?(expected), msg)
       end
 
-      ##
-      # Passes if +expected+ != +actual+
-      #
-      # Example:
-      #   assert_not_equal 'some string', 5
-
-      public
-      def assert_not_equal(expected, actual, message="")
-        full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
-        assert_block(full_message) { expected != actual }
-      end
-
-      ##
-      # Passes if ! +object+ .nil?
-      #
-      # Example:
-      #   assert_not_nil '1 two 3'.sub!(/two/, '2')
-
-      public
-      def assert_not_nil(object, message="")
-        full_message = build_message(message, "<?> expected to not be nil.", object)
-        assert_block(full_message){!object.nil?}
-      end
-
-      ##
-      # Passes if +regexp+ !~ +string+ 
-      #
-      # Example:
-      #   assert_no_match(/two/, 'one 2 three')
-
-      public
-      def assert_no_match(regexp, string, message="")
-        _wrap_assertion do
-          assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
-          full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
-          assert_block(full_message) { regexp !~ string }
-        end
-      end
-
-      UncaughtThrow = {
-        ArgumentError => /^uncaught throw (.+)$/,
-      } #`
-
-      ##
-      # Passes if the block throws +expected_object+
-      #
-      # Example:
-      #   assert_throws :done do
-      #     throw :done
-      #   end
-
-      public
-      def assert_throws(expected_object, message="", &proc)
-        _wrap_assertion do
-          assert_block("Should have passed a block to assert_throws."){block_given?}
-          caught = true
-          begin
-            catch(expected_object) do
-              proc.call
-              caught = false
-            end
-            full_message = build_message(message, "<?> should have been thrown.", expected_object)
-            assert_block(full_message){caught}
-          rescue ArgumentError => error
-            if UncaughtThrow[error.class] !~ error.message
-              raise error
-            end
-            full_message = build_message(message, "<?> expected to be thrown but\n<#$1> was thrown.", expected_object)
-            flunk(full_message)
-          end
-        end
-      end
-
-      ##
-      # Passes if block does not throw anything.
-      #
-      # Example:
-      #  assert_nothing_thrown do
-      #    [1, 2].uniq
-      #  end
-
-      public
-      def assert_nothing_thrown(message="", &proc)
-        _wrap_assertion do
-          assert(block_given?, "Should have passed a block to assert_nothing_thrown")
-          begin
-            proc.call
-          rescue ArgumentError => error
-            if UncaughtThrow[error.class] !~ error.message
-              raise error
-            end
-            full_message = build_message(message, "<#$1> was thrown when nothing was expected")
-            flunk(full_message)
-          end
-          assert(true, "Expected nothing to be thrown")
-        end
-      end
-
-      ##
-      # Passes if +expected_float+ and +actual_float+ are equal
-      # within +delta+ tolerance.
-      #
-      # Example:
-      #   assert_in_delta 0.05, (50000.0 / 10**6), 0.00001
-
-      public
-      def assert_in_delta(expected_float, actual_float, delta, message="")
-        _wrap_assertion do
-          {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
-            assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
-          end
-          assert_operator(delta, :>=, 0.0, "The delta should not be negative")
-          full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
-<?> and
-<?> expected to be within
-<?> of each other.
-EOT
-          assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
-        end
-      end
-
-      ##
-      # Passes if the method send returns a true value.
-      #
-      # +send_array+ is composed of:
-      # * A receiver
-      # * A method
-      # * Arguments to the method
-      #
-      # Example:
-      #   assert_send [[1, 2], :include?, 4]
-
-      public
-      def assert_send(send_array, message="")
-        _wrap_assertion do
-          assert_instance_of(Array, send_array, "assert_send requires an array of send information")
-          assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
-          full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
-<?> expected to respond to
-<?(?)> with a true value.
-EOT
-          assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
-        end
-      end
-
-      ##
-      # Builds a failure message.  +head+ is added before the +template+ and
-      # +arguments+ replaces the '?'s positionally in the template.
-
-      public
-      def build_message(head, template=nil, *arguments) # :nodoc:
+      def build_message(head, template=nil, *arguments)
         template &&= template.chomp
-        return AssertionMessage.new(head, template, arguments)
+        template.gsub(/\?/) { mu_pp(arguments.shift) }
       end
-
-      private
-      def _wrap_assertion # :nodoc:
-        @_assertion_wrapped ||= false
-        unless (@_assertion_wrapped)
-          @_assertion_wrapped = true
-          begin
-            add_assertion
-            return yield
-          ensure
-            @_assertion_wrapped = false
-          end
-        else
-          return yield
-        end
-      end
-      
-      ##
-      # Called whenever an assertion is made.  Define this in classes that
-      # include Test::Unit::Assertions to record assertion counts.
-
-      private
-      def add_assertion
-      end
-
-      ##
-      # Select whether or not to use the pretty-printer. If this option is set
-      # to false before any assertions are made, pp.rb will not be required.
-
-      public
-      def self.use_pp=(value)
-        AssertionMessage.use_pp = value
-      end
-      
-      # :stopdoc:
-
-      class AssertionMessage
-        @use_pp = true
-        class << self
-          attr_accessor :use_pp
-        end
-
-        class Literal
-          def initialize(value)
-            @value = value
-          end
-          
-          def inspect
-            @value.to_s
-          end
-        end
-
-        class Template
-          def self.create(string)
-            parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
-            self.new(parts)
-          end
-
-          attr_reader :count
-
-          def initialize(parts)
-            @parts = parts
-            @count = parts.find_all{|e| e == '?'}.size
-          end
-
-          def result(parameters)
-            raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
-            params = parameters.dup
-            @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
-          end
-        end
-
-        def self.literal(value)
-          Literal.new(value)
-        end
-
-        include Util::BacktraceFilter
-
-        def initialize(head, template_string, parameters)
-          @head = head
-          @template_string = template_string
-          @parameters = parameters
-        end
-
-        def convert(object)
-          case object
-            when Exception
-              <<EOM.chop
-Class: <#{convert(object.class)}>
-Message: <#{convert(object.message)}>
----Backtrace---
-#{filter_backtrace(object.backtrace).join("\n")}
----------------
-EOM
-            else
-              if(self.class.use_pp)
-                begin
-                  require 'pp'
-                rescue LoadError
-                  self.class.use_pp = false
-                  return object.inspect
-                end unless(defined?(PP))
-                PP.pp(object, '').chomp
-              else
-                object.inspect
-              end
-          end
-        end
-
-        def template
-          @template ||= Template.create(@template_string)
-        end
-
-        def add_period(string)
-          (string =~ /\.\Z/ ? string : string + '.')
-        end
-
-        def to_s
-          message_parts = []
-          if (@head)
-            head = @head.to_s 
-            unless(head.empty?)
-              message_parts << add_period(head)
-            end
-          end
-          tail = template.result(@parameters.collect{|e| convert(e)})
-          message_parts << tail unless(tail.empty?)
-          message_parts.join("\n")
-        end
-      end
-
-      # :startdoc:
-
     end
   end
 end

Deleted: MacRuby/branches/experimental/lib/test/unit/autorunner.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/autorunner.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/autorunner.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,220 +0,0 @@
-require 'test/unit'
-require 'test/unit/ui/testrunnerutilities'
-require 'optparse'
-
-module Test
-  module Unit
-    class AutoRunner
-      def self.run(force_standalone=false, default_dir=nil, argv=ARGV, &block)
-        r = new(force_standalone || standalone?, &block)
-        r.base = default_dir
-        r.process_args(argv)
-        r.run
-      end
-      
-      def self.standalone?
-        return false unless("-e" == $0)
-        ObjectSpace.each_object(Class) do |klass|
-          return false if(klass < TestCase)
-        end
-        true
-      end
-
-      RUNNERS = {
-        :console => proc do |r|
-          require 'test/unit/ui/console/testrunner'
-          Test::Unit::UI::Console::TestRunner
-        end,
-        :gtk => proc do |r|
-          require 'test/unit/ui/gtk/testrunner'
-          Test::Unit::UI::GTK::TestRunner
-        end,
-        :gtk2 => proc do |r|
-          require 'test/unit/ui/gtk2/testrunner'
-          Test::Unit::UI::GTK2::TestRunner
-        end,
-        :fox => proc do |r|
-          require 'test/unit/ui/fox/testrunner'
-          Test::Unit::UI::Fox::TestRunner
-        end,
-        :tk => proc do |r|
-          require 'test/unit/ui/tk/testrunner'
-          Test::Unit::UI::Tk::TestRunner
-        end,
-      }
-
-      OUTPUT_LEVELS = [
-        [:silent, UI::SILENT],
-        [:progress, UI::PROGRESS_ONLY],
-        [:normal, UI::NORMAL],
-        [:verbose, UI::VERBOSE],
-      ]
-
-      COLLECTORS = {
-        :objectspace => proc do |r|
-          require 'test/unit/collector/objectspace'
-          c = Collector::ObjectSpace.new
-          c.filter = r.filters
-          c.collect($0.sub(/\.rb\Z/, ''))
-        end,
-        :dir => proc do |r|
-          require 'test/unit/collector/dir'
-          c = Collector::Dir.new
-          c.filter = r.filters
-          c.pattern.concat(r.pattern) if(r.pattern)
-          c.exclude.concat(r.exclude) if(r.exclude)
-          c.base = r.base
-          $:.push(r.base) if r.base
-          c.collect(*(r.to_run.empty? ? ['.'] : r.to_run))
-        end,
-      }
-
-      attr_reader :suite
-      attr_accessor :output_level, :filters, :to_run, :pattern, :exclude, :base, :workdir
-      attr_writer :runner, :collector
-
-      def initialize(standalone)
-        Unit.run = true
-        @standalone = standalone
-        @runner = RUNNERS[:console]
-        @collector = COLLECTORS[(standalone ? :dir : :objectspace)]
-        @filters = []
-        @to_run = []
-        @output_level = UI::NORMAL
-        @workdir = false
-        yield(self) if(block_given?)
-      end
-
-      def process_args(args = ARGV)
-        begin
-          options.order!(args) {|arg| @to_run << arg}
-        rescue OptionParser::ParseError => e
-          puts e
-          puts options
-          $! = nil
-          abort
-        else
-          @filters << proc{false} unless(@filters.empty?)
-        end
-        not @to_run.empty?
-      end
-
-      def options
-        @options ||= OptionParser.new do |o|
-          o.banner = "Test::Unit automatic runner."
-          o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
-
-          o.on
-          o.on('-r', '--runner=RUNNER', RUNNERS,
-               "Use the given RUNNER.",
-               "(" + keyword_display(RUNNERS) + ")") do |r|
-            @runner = r
-          end
-
-          if(@standalone)
-            o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b|
-              @base = b
-            end
-
-            o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w|
-              @workdir = w
-            end
-
-            o.on('-a', '--add=TORUN', Array,
-                 "Add TORUN to the list of things to run;",
-                 "can be a file or a directory.") do |a|
-              @to_run.concat(a)
-            end
-
-            @pattern = []
-            o.on('-p', '--pattern=PATTERN', Regexp,
-                 "Match files to collect against PATTERN.") do |e|
-              @pattern << e
-            end
-
-            @exclude = []
-            o.on('-x', '--exclude=PATTERN', Regexp,
-                 "Ignore files to collect against PATTERN.") do |e|
-              @exclude << e
-            end
-          end
-
-          o.on('-n', '--name=NAME', String,
-               "Runs tests matching NAME.",
-               "(patterns may be used).") do |n|
-            n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
-            case n
-            when Regexp
-              @filters << proc{|t| n =~ t.method_name ? true : nil}
-            else
-              @filters << proc{|t| n == t.method_name ? true : nil}
-            end
-          end
-
-          o.on('-t', '--testcase=TESTCASE', String,
-               "Runs tests in TestCases matching TESTCASE.",
-               "(patterns may be used).") do |n|
-            n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
-            case n
-            when Regexp
-              @filters << proc{|t| n =~ t.class.name ? true : nil}
-            else
-              @filters << proc{|t| n == t.class.name ? true : nil}
-            end
-          end
-
-          o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
-               "Appends directory list to $LOAD_PATH.") do |dirs|
-            $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR))
-          end
-
-          o.on('-v', '--verbose=[LEVEL]', OUTPUT_LEVELS,
-               "Set the output level (default is verbose).",
-               "(" + keyword_display(OUTPUT_LEVELS) + ")") do |l|
-            @output_level = l || UI::VERBOSE
-          end
-
-          o.on('--',
-               "Stop processing options so that the",
-               "remaining options will be passed to the",
-               "test."){o.terminate}
-
-          o.on('-h', '--help', 'Display this help.'){puts o; exit}
-
-          o.on_tail
-          o.on_tail('Deprecated options:')
-
-          o.on_tail('--console', 'Console runner (use --runner).') do
-            warn("Deprecated option (--console).")
-            @runner = RUNNERS[:console]
-          end
-
-          o.on_tail('--gtk', 'GTK runner (use --runner).') do
-            warn("Deprecated option (--gtk).")
-            @runner = RUNNERS[:gtk]
-          end
-
-          o.on_tail('--fox', 'Fox runner (use --runner).') do
-            warn("Deprecated option (--fox).")
-            @runner = RUNNERS[:fox]
-          end
-
-          o.on_tail
-        end
-      end
-
-      def keyword_display(array)
-        list = array.collect {|e, *| e.to_s}
-        Array === array or list.sort!
-        list.collect {|e| e.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')}.join(", ")
-      end
-
-      def run
-        @suite = @collector[self]
-        result = @runner[self] or return false
-        Dir.chdir(@workdir) if @workdir
-        result.run(@suite, @output_level).passed?
-      end
-    end
-  end
-end

Deleted: MacRuby/branches/experimental/lib/test/unit/collector.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/collector.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/collector.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,43 +0,0 @@
-module Test
-  module Unit
-    module Collector
-      def initialize
-        @filters = []
-      end
-
-      def filter=(filters)
-        @filters = case(filters)
-          when Proc
-            [filters]
-          when Array
-            filters
-        end
-      end
-
-      def add_suite(destination, suite)
-        to_delete = suite.tests.find_all{|t| !include?(t)}
-        to_delete.each{|t| suite.delete(t)}
-        destination << suite unless(suite.size == 0)
-      end
-
-      def include?(test)
-        return true if(@filters.empty?)
-        @filters.each do |filter|
-          result = filter[test]
-          if(result.nil?)
-            next
-          elsif(!result)
-            return false
-          else
-            return true
-          end
-        end
-        true
-      end
-
-      def sort(suites)
-        suites.sort_by{|s| s.name}
-      end
-    end
-  end
-end

Deleted: MacRuby/branches/experimental/lib/test/unit/error.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/error.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/error.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,56 +0,0 @@
-#--
-#
-# Author:: Nathaniel Talbott.
-# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
-# License:: Ruby license.
-
-require 'test/unit/util/backtracefilter'
-
-module Test
-  module Unit
-
-    # Encapsulates an error in a test. Created by
-    # Test::Unit::TestCase when it rescues an exception thrown
-    # during the processing of a test.
-    class Error
-      include Util::BacktraceFilter
-
-      attr_reader(:test_name, :exception)
-
-      SINGLE_CHARACTER = 'E'
-
-      # Creates a new Error with the given test_name and
-      # exception.
-      def initialize(test_name, exception)
-        @test_name = test_name
-        @exception = exception
-      end
-
-      # Returns a single character representation of an error.
-      def single_character_display
-        SINGLE_CHARACTER
-      end
-
-      # Returns the message associated with the error.
-      def message
-        "#{@exception.class.name}: #{@exception.message}"
-      end
-
-      # Returns a brief version of the error description.
-      def short_display
-        "#@test_name: #{message.split("\n")[0]}"
-      end
-
-      # Returns a verbose version of the error description.
-      def long_display
-        backtrace = filter_backtrace(@exception.backtrace).join("\n    ")
-        "Error:\n#@test_name:\n#{message}\n    #{backtrace}"
-      end
-
-      # Overridden to return long_display.
-      def to_s
-        long_display
-      end
-    end
-  end
-end

Deleted: MacRuby/branches/experimental/lib/test/unit/failure.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/failure.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/failure.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,51 +0,0 @@
-#--
-#
-# Author:: Nathaniel Talbott.
-# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
-# License:: Ruby license.
-
-module Test
-  module Unit
-
-    # Encapsulates a test failure. Created by Test::Unit::TestCase
-    # when an assertion fails.
-    class Failure
-      attr_reader :test_name, :location, :message
-      
-      SINGLE_CHARACTER = 'F'
-
-      # Creates a new Failure with the given location and
-      # message.
-      def initialize(test_name, location, message)
-        @test_name = test_name
-        @location = location
-        @message = message
-      end
-      
-      # Returns a single character representation of a failure.
-      def single_character_display
-        SINGLE_CHARACTER
-      end
-
-      # Returns a brief version of the error description.
-      def short_display
-        "#@test_name: #{@message.split("\n")[0]}"
-      end
-
-      # Returns a verbose version of the error description.
-      def long_display
-        location_display = if(location.size == 1)
-          location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
-        else
-          "\n    [#{location.join("\n     ")}]"
-        end
-        "Failure:\n#@test_name#{location_display}:\n#@message"
-      end
-
-      # Overridden to return long_display.
-      def to_s
-        long_display
-      end
-    end
-  end
-end

Modified: MacRuby/branches/experimental/lib/test/unit/testcase.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/testcase.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/testcase.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,158 +1,12 @@
-#--
-#
-# Author:: Nathaniel Talbott.
-# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
-# License:: Ruby license.
-
 require 'test/unit/assertions'
-require 'test/unit/failure'
-require 'test/unit/error'
-require 'test/unit/testsuite'
-require 'test/unit/assertionfailederror'
-require 'test/unit/util/backtracefilter'
 
 module Test
   module Unit
-
-    # Ties everything together. If you subclass and add your own
-    # test methods, it takes care of making them into tests and
-    # wrapping those tests into a suite. It also does the
-    # nitty-gritty of actually running an individual test and
-    # collecting its results into a Test::Unit::TestResult object.
-    class TestCase
+    class TestCase < MiniTest::Unit::TestCase
       include Assertions
-      include Util::BacktraceFilter
-      
-      attr_reader :method_name
-      
-      STARTED = name + "::STARTED"
-      FINISHED = name + "::FINISHED"
-
-      ##
-      # These exceptions are not caught by #run.
-
-      PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt,
-                                SystemExit]
-
-      # Creates a new instance of the fixture for running the
-      # test represented by test_method_name.
-      def initialize(test_method_name)
-        unless(respond_to?(test_method_name) && method(test_method_name).arity == 0)
-          throw :invalid_test
-        end
-        @method_name = test_method_name
-        @test_passed = true
+      def self.test_order
+        :sorted
       end
-
-      # Rolls up all of the test* methods in the fixture into
-      # one suite, creating a new instance of the fixture for
-      # each method.
-      def self.suite
-        method_names = public_instance_methods(true).map { |m| m.to_s }
-        tests = method_names.delete_if {|method_name| method_name !~ /^test./}
-        suite = TestSuite.new(name)
-        tests.sort.each do
-          |test|
-          catch(:invalid_test) do
-            suite << new(test)
-          end
-        end
-        if (suite.empty?)
-          catch(:invalid_test) do
-            suite << new(:default_test)
-          end
-        end
-        return suite
-      end
-
-      # Runs the individual test method represented by this
-      # instance of the fixture, collecting statistics, failures
-      # and errors in result.
-      def run(result)
-        yield(STARTED, name)
-        @_result = result
-        begin
-          setup
-          __send__(@method_name)
-        rescue AssertionFailedError => e
-          add_failure(e.message, e.backtrace)
-        rescue Exception
-          raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
-          add_error($!)
-        ensure
-          begin
-            teardown
-          rescue AssertionFailedError => e
-            add_failure(e.message, e.backtrace)
-          rescue Exception
-            raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
-            add_error($!)
-          end
-        end
-        result.add_run
-        yield(FINISHED, name)
-      end
-
-      # Called before every test method runs. Can be used
-      # to set up fixture information.
-      def setup
-      end
-
-      # Called after every test method runs. Can be used to tear
-      # down fixture information.
-      def teardown
-      end
-      
-      def default_test
-        flunk("No tests were specified")
-      end
-
-      # Returns whether this individual test passed or
-      # not. Primarily for use in teardown so that artifacts
-      # can be left behind if the test fails.
-      def passed?
-        return @test_passed
-      end
-      private :passed?
-
-      def size # :nodoc:
-        1
-      end
-
-      def add_assertion # :nodoc:
-        @_result.add_assertion
-      end
-      private :add_assertion
-
-      def add_failure(message, all_locations=caller()) # :nodoc:
-        @test_passed = false
-        @_result.add_failure(Failure.new(name, filter_backtrace(all_locations), message))
-      end
-      private :add_failure
-
-      def add_error(exception) # :nodoc:
-        @test_passed = false
-        @_result.add_error(Error.new(name, exception))
-      end
-      private :add_error
-
-      # Returns a human-readable name for the specific test that
-      # this instance of TestCase represents.
-      def name
-        "#{@method_name}(#{self.class.name})"
-      end
-
-      # Overridden to return #name.
-      def to_s
-        name
-      end
-      
-      # It's handy to be able to compare TestCase instances.
-      def ==(other)
-        return false unless(other.kind_of?(self.class))
-        return false unless(@method_name == other.method_name)
-        self.class == other.class
-      end
     end
   end
 end

Deleted: MacRuby/branches/experimental/lib/test/unit/testresult.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/testresult.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/testresult.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,81 +0,0 @@
-#--
-#
-# Author:: Nathaniel Talbott.
-# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
-# License:: Ruby license.
-
-require 'test/unit/util/observable'
-
-module Test
-  module Unit
-
-    # Collects Test::Unit::Failure and Test::Unit::Error so that
-    # they can be displayed to the user. To this end, observers
-    # can be added to it, allowing the dynamic updating of, say, a
-    # UI.
-    class TestResult
-      include Util::Observable
-
-      CHANGED = "CHANGED"
-      FAULT = "FAULT"
-
-      attr_reader(:run_count, :assertion_count)
-
-      # Constructs a new, empty TestResult.
-      def initialize
-        @run_count, @assertion_count = 0, 0
-        @failures, @errors = Array.new, Array.new
-      end
-
-      # Records a test run.
-      def add_run
-        @run_count += 1
-        notify_listeners(CHANGED, self)
-      end
-
-      # Records a Test::Unit::Failure.
-      def add_failure(failure)
-        @failures << failure
-        notify_listeners(FAULT, failure)
-        notify_listeners(CHANGED, self)
-      end
-
-      # Records a Test::Unit::Error.
-      def add_error(error)
-        @errors << error
-        notify_listeners(FAULT, error)
-        notify_listeners(CHANGED, self)
-      end
-
-      # Records an individual assertion.
-      def add_assertion
-        @assertion_count += 1
-        notify_listeners(CHANGED, self)
-      end
-
-      # Returns a string contain the recorded runs, assertions,
-      # failures and errors in this TestResult.
-      def to_s
-        "#{run_count} tests, #{assertion_count} assertions, #{failure_count} failures, #{error_count} errors"
-      end
-
-      # Returns whether or not this TestResult represents
-      # successful completion.
-      def passed?
-        return @failures.empty? && @errors.empty?
-      end
-
-      # Returns the number of failures this TestResult has
-      # recorded.
-      def failure_count
-        return @failures.size
-      end
-
-      # Returns the number of errors this TestResult has
-      # recorded.
-      def error_count
-        return @errors.size
-      end
-    end
-  end
-end

Deleted: MacRuby/branches/experimental/lib/test/unit/testsuite.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit/testsuite.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit/testsuite.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,76 +0,0 @@
-#--
-#
-# Author:: Nathaniel Talbott.
-# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
-# License:: Ruby license.
-
-module Test
-  module Unit
-
-    # A collection of tests which can be #run.
-    #
-    # Note: It is easy to confuse a TestSuite instance with
-    # something that has a static suite method; I know because _I_
-    # have trouble keeping them straight. Think of something that
-    # has a suite method as simply providing a way to get a
-    # meaningful TestSuite instance.
-    class TestSuite
-      attr_reader :name, :tests
-      
-      STARTED = name + "::STARTED"
-      FINISHED = name + "::FINISHED"
-
-      # Creates a new TestSuite with the given name.
-      def initialize(name="Unnamed TestSuite")
-        @name = name
-        @tests = []
-      end
-
-      # Runs the tests and/or suites contained in this
-      # TestSuite.
-      def run(result, &progress_block)
-        yield(STARTED, name)
-        @tests.each do |test|
-          test.run(result, &progress_block)
-        end
-        yield(FINISHED, name)
-      end
-
-      # Adds the test to the suite.
-      def <<(test)
-        @tests << test
-        self
-      end
-
-      def delete(test)
-        @tests.delete(test)
-      end
-
-      # Retuns the rolled up number of tests in this suite;
-      # i.e. if the suite contains other suites, it counts the
-      # tests within those suites, not the suites themselves.
-      def size
-        total_size = 0
-        @tests.each { |test| total_size += test.size }
-        total_size
-      end
-      
-      def empty?
-        tests.empty?
-      end
-
-      # Overridden to return the name given the suite at
-      # creation.
-      def to_s
-        @name
-      end
-      
-      # It's handy to be able to compare TestSuite instances.
-      def ==(other)
-        return false unless(other.kind_of?(self.class))
-        return false unless(@name == other.name)
-        @tests == other.tests
-      end
-    end
-  end
-end

Modified: MacRuby/branches/experimental/lib/test/unit.rb
===================================================================
--- MacRuby/branches/experimental/lib/test/unit.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/test/unit.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,280 +1,66 @@
+# test/unit compatibility layer using minitest.
+
+require 'minitest/unit'
+require 'test/unit/assertions'
 require 'test/unit/testcase'
-require 'test/unit/autorunner'
 
-module Test # :nodoc:
-  #
-  # = Test::Unit - Ruby Unit Testing Framework
-  # 
-  # == Introduction
-  # 
-  # Unit testing is making waves all over the place, largely due to the
-  # fact that it is a core practice of XP. While XP is great, unit testing
-  # has been around for a long time and has always been a good idea. One
-  # of the keys to good unit testing, though, is not just writing tests,
-  # but having tests. What's the difference? Well, if you just _write_ a
-  # test and throw it away, you have no guarantee that something won't
-  # change later which breaks your code. If, on the other hand, you _have_
-  # tests (obviously you have to write them first), and run them as often
-  # as possible, you slowly build up a wall of things that cannot break
-  # without you immediately knowing about it. This is when unit testing
-  # hits its peak usefulness.
-  # 
-  # Enter Test::Unit, a framework for unit testing in Ruby, helping you to
-  # design, debug and evaluate your code by making it easy to write and
-  # have tests for it.
-  # 
-  # 
-  # == Notes
-  # 
-  # Test::Unit has grown out of and superceded Lapidary.
-  # 
-  # 
-  # == Feedback
-  # 
-  # I like (and do my best to practice) XP, so I value early releases,
-  # user feedback, and clean, simple, expressive code. There is always
-  # room for improvement in everything I do, and Test::Unit is no
-  # exception. Please, let me know what you think of Test::Unit as it
-  # stands, and what you'd like to see expanded/changed/improved/etc. If
-  # you find a bug, let me know ASAP; one good way to let me know what the
-  # bug is is to submit a new test that catches it :-) Also, I'd love to
-  # hear about any successes you have with Test::Unit, and any
-  # documentation you might add will be greatly appreciated. My contact
-  # info is below.
-  # 
-  # 
-  # == Contact Information
-  # 
-  # A lot of discussion happens about Ruby in general on the ruby-talk
-  # mailing list (http://www.ruby-lang.org/en/ml.html), and you can ask
-  # any questions you might have there. I monitor the list, as do many
-  # other helpful Rubyists, and you're sure to get a quick answer. Of
-  # course, you're also welcome to email me (Nathaniel Talbott) directly
-  # at mailto:testunit at talbott.ws, and I'll do my best to help you out.
-  # 
-  # 
-  # == Credits
-  # 
-  # I'd like to thank...
-  # 
-  # Matz, for a great language!
-  # 
-  # Masaki Suketa, for his work on RubyUnit, which filled a vital need in
-  # the Ruby world for a very long time. I'm also grateful for his help in
-  # polishing Test::Unit and getting the RubyUnit compatibility layer
-  # right. His graciousness in allowing Test::Unit to supercede RubyUnit
-  # continues to be a challenge to me to be more willing to defer my own
-  # rights.
-  # 
-  # Ken McKinlay, for his interest and work on unit testing, and for his
-  # willingness to dialog about it. He was also a great help in pointing
-  # out some of the holes in the RubyUnit compatibility layer.
-  # 
-  # Dave Thomas, for the original idea that led to the extremely simple
-  # "require 'test/unit'", plus his code to improve it even more by
-  # allowing the selection of tests from the command-line. Also, without
-  # RDoc, the documentation for Test::Unit would stink a lot more than it
-  # does now.
-  # 
-  # Everyone who's helped out with bug reports, feature ideas,
-  # encouragement to continue, etc. It's a real privilege to be a part of
-  # the Ruby community.
-  # 
-  # The guys at RoleModel Software, for putting up with me repeating, "But
-  # this would be so much easier in Ruby!" whenever we're coding in Java.
-  # 
-  # My Creator, for giving me life, and giving it more abundantly.
-  # 
-  # 
-  # == License
-  # 
-  # Test::Unit is copyright (c) 2000-2003 Nathaniel Talbott. It is free
-  # software, and is distributed under the Ruby license. See the COPYING
-  # file in the standard Ruby distribution for details.
-  # 
-  # 
-  # == Warranty
-  # 
-  # This software is provided "as is" and without any express or
-  # implied warranties, including, without limitation, the implied
-  # warranties of merchantibility and fitness for a particular
-  # purpose.
-  # 
-  # 
-  # == Author
-  # 
-  # Nathaniel Talbott.
-  # Copyright (c) 2000-2003, Nathaniel Talbott
-  #
-  # ----
-  #
-  # = Usage
-  #
-  # The general idea behind unit testing is that you write a _test_
-  # _method_ that makes certain _assertions_ about your code, working
-  # against a _test_ _fixture_. A bunch of these _test_ _methods_ are
-  # bundled up into a _test_ _suite_ and can be run any time the
-  # developer wants. The results of a run are gathered in a _test_
-  # _result_ and displayed to the user through some UI. So, lets break
-  # this down and see how Test::Unit provides each of these necessary
-  # pieces.
-  #
-  #
-  # == Assertions
-  #
-  # These are the heart of the framework. Think of an assertion as a
-  # statement of expected outcome, i.e. "I assert that x should be equal
-  # to y". If, when the assertion is executed, it turns out to be
-  # correct, nothing happens, and life is good. If, on the other hand,
-  # your assertion turns out to be false, an error is propagated with
-  # pertinent information so that you can go back and make your
-  # assertion succeed, and, once again, life is good. For an explanation
-  # of the current assertions, see Test::Unit::Assertions.
-  #
-  #
-  # == Test Method & Test Fixture
-  #
-  # Obviously, these assertions have to be called within a context that
-  # knows about them and can do something meaningful with their
-  # pass/fail value. Also, it's handy to collect a bunch of related
-  # tests, each test represented by a method, into a common test class
-  # that knows how to run them. The tests will be in a separate class
-  # from the code they're testing for a couple of reasons. First of all,
-  # it allows your code to stay uncluttered with test code, making it
-  # easier to maintain. Second, it allows the tests to be stripped out
-  # for deployment, since they're really there for you, the developer,
-  # and your users don't need them. Third, and most importantly, it
-  # allows you to set up a common test fixture for your tests to run
-  # against.
-  #
-  # What's a test fixture? Well, tests do not live in a vacuum; rather,
-  # they're run against the code they are testing. Often, a collection
-  # of tests will run against a common set of data, also called a
-  # fixture. If they're all bundled into the same test class, they can
-  # all share the setting up and tearing down of that data, eliminating
-  # unnecessary duplication and making it much easier to add related
-  # tests.
-  #
-  # Test::Unit::TestCase wraps up a collection of test methods together
-  # and allows you to easily set up and tear down the same test fixture
-  # for each test. This is done by overriding #setup and/or #teardown,
-  # which will be called before and after each test method that is
-  # run. The TestCase also knows how to collect the results of your
-  # assertions into a Test::Unit::TestResult, which can then be reported
-  # back to you... but I'm getting ahead of myself. To write a test,
-  # follow these steps:
-  #
-  # * Make sure Test::Unit is in your library path.
-  # * require 'test/unit' in your test script.
-  # * Create a class that subclasses Test::Unit::TestCase.
-  # * Add a method that begins with "test" to your class.
-  # * Make assertions in your test method.
-  # * Optionally define #setup and/or #teardown to set up and/or tear
-  #   down your common test fixture.
-  # * You can now run your test as you would any other Ruby
-  #   script... try it and see!
-  #
-  # A really simple test might look like this (#setup and #teardown are
-  # commented out to indicate that they are completely optional):
-  #
-  #     require 'test/unit'
-  #     
-  #     class TC_MyTest < Test::Unit::TestCase
-  #       # def setup
-  #       # end
-  #     
-  #       # def teardown
-  #       # end
-  #     
-  #       def test_fail
-  #         assert(false, 'Assertion was false.')
-  #       end
-  #     end
-  #
-  #
-  # == Test Runners
-  #
-  # So, now you have this great test class, but you still need a way to
-  # run it and view any failures that occur during the run. This is
-  # where Test::Unit::UI::Console::TestRunner (and others, such as
-  # Test::Unit::UI::GTK::TestRunner) comes into play. The console test
-  # runner is automatically invoked for you if you require 'test/unit'
-  # and simply run the file. To use another runner, or to manually
-  # invoke a runner, simply call its run class method and pass in an
-  # object that responds to the suite message with a
-  # Test::Unit::TestSuite. This can be as simple as passing in your
-  # TestCase class (which has a class suite method). It might look
-  # something like this:
-  #
-  #    require 'test/unit/ui/console/testrunner'
-  #    Test::Unit::UI::Console::TestRunner.run(TC_MyTest)
-  #
-  #
-  # == Test Suite
-  #
-  # As more and more unit tests accumulate for a given project, it
-  # becomes a real drag running them one at a time, and it also
-  # introduces the potential to overlook a failing test because you
-  # forget to run it. Suddenly it becomes very handy that the
-  # TestRunners can take any object that returns a Test::Unit::TestSuite
-  # in response to a suite method. The TestSuite can, in turn, contain
-  # other TestSuites or individual tests (typically created by a
-  # TestCase). In other words, you can easily wrap up a group of
-  # TestCases and TestSuites like this:
-  #
-  #  require 'test/unit/testsuite'
-  #  require 'tc_myfirsttests'
-  #  require 'tc_moretestsbyme'
-  #  require 'ts_anothersetoftests'
-  #
-  #  class TS_MyTests
-  #    def self.suite
-  #      suite = Test::Unit::TestSuite.new
-  #      suite << TC_MyFirstTests.suite
-  #      suite << TC_MoreTestsByMe.suite
-  #      suite << TS_AnotherSetOfTests.suite
-  #      return suite
-  #    end
-  #  end
-  #  Test::Unit::UI::Console::TestRunner.run(TS_MyTests)
-  #
-  # Now, this is a bit cumbersome, so Test::Unit does a little bit more
-  # for you, by wrapping these up automatically when you require
-  # 'test/unit'. What does this mean? It means you could write the above
-  # test case like this instead:
-  #
-  #  require 'test/unit'
-  #  require 'tc_myfirsttests'
-  #  require 'tc_moretestsbyme'
-  #  require 'ts_anothersetoftests'
-  #
-  # Test::Unit is smart enough to find all the test cases existing in
-  # the ObjectSpace and wrap them up into a suite for you. It then runs
-  # the dynamic suite using the console TestRunner.
-  #
-  #
-  # == Questions?
-  #
-  # I'd really like to get feedback from all levels of Ruby
-  # practitioners about typos, grammatical errors, unclear statements,
-  # missing points, etc., in this document (or any other).
-  #
-
+module Test
   module Unit
-    # If set to false Test::Unit will not automatically run at exit.
-    def self.run=(flag)
-      @run = flag
-    end
+    TEST_UNIT_IMPLEMENTATION = 'test/unit compatibility layer using minitest'
 
-    # Automatically run tests at exit?
-    def self.run?
-      @run ||= false
+    def self.setup_argv(original_argv=ARGV)
+      minitest_argv = []
+      files = []
+      reject = []
+      original_argv = original_argv.dup
+      while arg = original_argv.shift
+        case arg
+        when '-v'
+          minitest_argv << '-v'
+        when '-n', '--name'
+          minitest_argv << arg
+          minitest_argv << original_argv.shift
+        when '-x'
+          reject << original_argv.shift
+        else
+          files << arg
+        end
+      end
+
+      if block_given?
+        files = yield files
+      end
+
+      files.map! {|f|
+        f = f.gsub(Regexp.compile(Regexp.quote(File::ALT_SEPARATOR)), File::SEPARATOR) if File::ALT_SEPARATOR
+        if File.directory? f
+          Dir["#{f}/**/test_*.rb"]
+        elsif File.file? f
+          f
+        else
+          raise ArgumentError, "file not found: #{f}"
+        end
+      }
+      files.flatten!
+
+      reject_pat = Regexp.union(reject.map {|r| /#{r}/ })
+      files.reject! {|f| reject_pat =~ f }
+        
+      files.each {|f|
+        d = File.dirname(File.expand_path(f))
+        unless $:.include? d
+          $: << d
+        end
+        begin
+          require f
+        rescue LoadError
+          puts "#{f}: #{$!}"
+        end
+      }
+
+      ARGV.replace minitest_argv
     end
   end
 end
 
-at_exit do
-  unless $! || Test::Unit.run?
-    exit Test::Unit::AutoRunner.run
-  end
-end
+MiniTest::Unit.autorun

Modified: MacRuby/branches/experimental/lib/thwait.rb
===================================================================
--- MacRuby/branches/experimental/lib/thwait.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/thwait.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -53,7 +53,7 @@
 class ThreadsWait
   RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-'
   
-  Exception2MessageMapper.extend_to(binding)
+  extend Exception2MessageMapper
   def_exception("ErrNoWaitingThread", "No threads for waiting.")
   def_exception("ErrNoFinishedThread", "No finished threads.")
   

Modified: MacRuby/branches/experimental/lib/time.rb
===================================================================
--- MacRuby/branches/experimental/lib/time.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/time.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,37 +1,37 @@
 
 #
 # == Introduction
-# 
+#
 # This library extends the Time class:
 # * conversion between date string and time object.
 #   * date-time defined by RFC 2822
 #   * HTTP-date defined by RFC 2616
 #   * dateTime defined by XML Schema Part 2: Datatypes (ISO 8601)
 #   * various formats handled by Date._parse (string to time only)
-# 
+#
 # == Design Issues
-# 
+#
 # === Specialized interface
-# 
+#
 # This library provides methods dedicated to special purposes:
 # * RFC 2822, RFC 2616 and XML Schema.
 # * They makes usual life easier.
-# 
+#
 # === Doesn't depend on strftime
-# 
+#
 # This library doesn't use +strftime+.  Especially #rfc2822 doesn't depend
 # on +strftime+ because:
-# 
+#
 # * %a and %b are locale sensitive
-# 
+#
 #   Since they are locale sensitive, they may be replaced to
 #   invalid weekday/month name in some locales.
 #   Since ruby-1.6 doesn't invoke setlocale by default,
 #   the problem doesn't arise until some external library invokes setlocale.
 #   Ruby/GTK is the example of such library.
-# 
+#
 # * %z is not portable
-# 
+#
 #   %z is required to generate zone in date-time of RFC 2822
 #   but it is not portable.
 #
@@ -61,9 +61,9 @@
       'PST' => -8, 'PDT' => -7,
       # Following definition of military zones is original one.
       # See RFC 1123 and RFC 2822 for the error in RFC 822.
-      'A' => +1, 'B' => +2, 'C' => +3, 'D' => +4,  'E' => +5,  'F' => +6, 
+      'A' => +1, 'B' => +2, 'C' => +3, 'D' => +4,  'E' => +5,  'F' => +6,
       'G' => +7, 'H' => +8, 'I' => +9, 'K' => +10, 'L' => +11, 'M' => +12,
-      'N' => -1, 'O' => -2, 'P' => -3, 'Q' => -4,  'R' => -5,  'S' => -6, 
+      'N' => -1, 'O' => -2, 'P' => -3, 'Q' => -4,  'R' => -5,  'S' => -6,
       'T' => -7, 'U' => -8, 'V' => -9, 'W' => -10, 'X' => -11, 'Y' => -12,
     }
     def zone_offset(zone, year=self.now.year)
@@ -84,8 +84,26 @@
     end
 
     def zone_utc?(zone)
-      # * +0000 means localtime. [RFC 2822]
-      # * GMT is a localtime abbreviation in Europe/London, etc.
+      # * +0000
+      #   In RFC 2822, +0000 indicate a time zone at Universal Time.
+      #   Europe/London is "a time zone at Universal Time" in Winter.
+      #   Europe/Lisbon is "a time zone at Universal Time" in Winter.
+      #   Atlantic/Reykjavik is "a time zone at Universal Time".
+      #   Africa/Dakar is "a time zone at Universal Time".
+      #   So +0000 is a local time such as Europe/London, etc.
+      # * GMT
+      #   GMT is used as a time zone abbreviation in Europe/London,
+      #   Africa/Dakar, etc.
+      #   So it is a local time.
+      #
+      # * -0000, -00:00
+      #   In RFC 2822, -0000 the date-time contains no information about the
+      #   local time zone.
+      #   In RFC 3339, -00:00 is used for the time in UTC is known,
+      #   but the offset to local time is unknown.
+      #   They are not appropriate for specific time zone such as
+      #   Europe/London because time zone neutral, 
+      #   So -00:00 and -0000 are treated as UTC.
       if /\A(?:-00:00|-0000|-00|UTC|Z|UT)\z/i =~ zone
         true
       else
@@ -374,7 +392,7 @@
           (-?\d+)-(\d\d)-(\d\d)
           T
           (\d\d):(\d\d):(\d\d)
-          (\.\d*)?
+          (\.\d+)?
           (Z|[+-]\d\d:\d\d)?
           \s*\z/ix =~ date
         year = $1.to_i
@@ -384,7 +402,9 @@
         min = $5.to_i
         sec = $6.to_i
         usec = 0
-        usec = $7.to_f * 1000000 if $7
+        if $7
+          usec = Rational($7) * 1000000
+        end
         if $8
           zone = $8
           year, mon, day, hour, min, sec =
@@ -434,8 +454,8 @@
 
   #
   # Returns a string which represents the time as rfc1123-date of HTTP-date
-  # defined by RFC 2616: 
-  # 
+  # defined by RFC 2616:
+  #
   #   day-of-week, DD month-name CCYY hh:mm:ss GMT
   #
   # Note that the result is always UTC (GMT).
@@ -622,6 +642,7 @@
                    Time.xmlschema("2000-01-12T12:13:14Z"))
       assert_equal(Time.utc(2001, 4, 17, 19, 23, 17, 300000),
                    Time.xmlschema("2001-04-17T19:23:17.3Z"))
+      assert_raise(ArgumentError) { Time.xmlschema("2000-01-01T00:00:00.+00:00") }
     end
 
     def test_encode_xmlschema
@@ -645,6 +666,8 @@
         t = Time.utc(1960, 12, 31, 23, 0, 0, 123456)
         assert_equal("1960-12-31T23:00:00.123456Z", t.xmlschema(6))
       end
+
+      assert_equal(249, Time.xmlschema("2008-06-05T23:49:23.000249+09:00").usec)
     end
 
     def test_completion
@@ -736,6 +759,18 @@
       assert_equal(true, Time.rfc2822("Sat, 01 Jan 2000 00:00:00 UTC").utc?)
     end
 
+    def test_rfc2822_utc_roundtrip_winter
+      t1 = Time.local(2008,12,1)
+      t2 = Time.rfc2822(t1.rfc2822)
+      assert_equal(t1.utc?, t2.utc?, "[ruby-dev:37126]")
+    end
+
+    def test_rfc2822_utc_roundtrip_summer
+      t1 = Time.local(2008,8,1)
+      t2 = Time.rfc2822(t1.rfc2822)
+      assert_equal(t1.utc?, t2.utc?)
+    end
+
     def test_parse_leap_second
       t = Time.utc(1998,12,31,23,59,59)
       assert_equal(t, Time.parse("Thu Dec 31 23:59:59 UTC 1998"))
@@ -763,21 +798,21 @@
     def test_rfc2822_leap_second
       t = Time.utc(1998,12,31,23,59,59)
       assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:59 UTC"))
-      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 -0000"));t.localtime                                  
+      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 -0000"));t.localtime
       assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 08:59:59 +0900"))
       assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 00:59:59 +0100"))
       assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 +0000"))
-      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:59 -0100"));t.utc                                  
+      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:59 -0100"));t.utc
       t += 1
       assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:60 UTC"))
-      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 -0000"));t.localtime                                  
+      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 -0000"));t.localtime
       assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 08:59:60 +0900"))
       assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 00:59:60 +0100"))
       assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 +0000"))
-      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:60 -0100"));t.utc                                  
+      assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:60 -0100"));t.utc
       t += 1 if t.sec == 60
       assert_equal(t, Time.rfc2822("Thu,  1 Jan 1999 00:00:00 UTC"))
-      assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 00:00:00 -0000"));t.localtime                                  
+      assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 00:00:00 -0000"));t.localtime
       assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 09:00:00 +0900"))
       assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 01:00:00 +0100"))
       assert_equal(t, Time.rfc2822("Fri,  1 Jan 1999 00:00:00 +0000"))
@@ -808,6 +843,10 @@
       assert_equal(t, Time.xmlschema("1998-12-31T23:00:00-01:00"))
     end
 
+    def test_xmlschema_fraction
+      assert_equal(500000, Time.xmlschema("2000-01-01T00:00:00.5+00:00").tv_usec)
+    end
+
     def test_ruby_talk_152866
       t = Time::xmlschema('2005-08-30T22:48:00-07:00')
       assert_equal(31, t.day)

Modified: MacRuby/branches/experimental/lib/tmpdir.rb
===================================================================
--- MacRuby/branches/experimental/lib/tmpdir.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/tmpdir.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 #
 # tmpdir - retrieve temporary directory path
 #
-# $Id: tmpdir.rb 13762 2007-10-24 06:03:48Z akr $
+# $Id: tmpdir.rb 19513 2008-09-24 05:39:39Z usa $
 #
 
 require 'fileutils'
@@ -12,16 +12,23 @@
 
   begin
     require 'Win32API'
+    CSIDL_LOCAL_APPDATA = 0x001c
     max_pathlen = 260
-    windir = ' '*(max_pathlen+1)
+    windir = "\0"*(max_pathlen+1)
     begin
-      getdir = Win32API.new('kernel32', 'GetSystemWindowsDirectory', 'PL', 'L')
+      getdir = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L')
+      raise RuntimeError if getdir.call(0, CSIDL_LOCAL_APPDATA, 0, 0, windir) != 0
+      windir = File.expand_path(windir.rstrip)
     rescue RuntimeError
-      getdir = Win32API.new('kernel32', 'GetWindowsDirectory', 'PL', 'L')
+      begin
+        getdir = Win32API.new('kernel32', 'GetSystemWindowsDirectory', 'PL', 'L')
+      rescue RuntimeError
+        getdir = Win32API.new('kernel32', 'GetWindowsDirectory', 'PL', 'L')
+      end
+      len = getdir.call(windir, windir.size)
+      windir = File.expand_path(windir[0, len])
     end
-    len = getdir.call(windir, windir.size)
-    windir = File.expand_path(windir[0, len])
-    temp = File.join(windir, 'temp')
+    temp = File.join(windir.untaint, 'temp')
     @@systmpdir = temp if File.directory?(temp) and File.writable?(temp)
   rescue LoadError
   end
@@ -41,8 +48,8 @@
 	  break
 	end
       end
+      File.expand_path(tmp)
     end
-    File.expand_path(tmp)
   end
 
   # Dir.mktmpdir creates a temporary directory.

Modified: MacRuby/branches/experimental/lib/tsort.rb
===================================================================
--- MacRuby/branches/experimental/lib/tsort.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/tsort.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -32,7 +32,7 @@
 # array using the user-supplied block.
 #
 #   require 'tsort'
-#   
+#
 #   class Hash
 #     include TSort
 #     alias tsort_each_node each_key
@@ -40,10 +40,10 @@
 #       fetch(node).each(&block)
 #     end
 #   end
-#   
+#
 #   {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
 #   #=> [3, 2, 1, 4]
-#   
+#
 #   {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
 #   #=> [[4], [2, 3], [1]]
 #
@@ -52,19 +52,19 @@
 # A very simple `make' like tool can be implemented as follows:
 #
 #   require 'tsort'
-#   
+#
 #   class Make
 #     def initialize
 #       @dep = {}
 #       @dep.default = []
 #     end
-#     
+#
 #     def rule(outputs, inputs=[], &block)
 #       triple = [outputs, inputs, block]
 #       outputs.each {|f| @dep[f] = [triple]}
 #       @dep[triple] = inputs
 #     end
-#     
+#
 #     def build(target)
 #       each_strongly_connected_component_from(target) {|ns|
 #         if ns.length != 1
@@ -88,18 +88,18 @@
 #         end
 #       }
 #     end
-#     
+#
 #     def tsort_each_child(node, &block)
 #       @dep[node].each(&block)
 #     end
 #     include TSort
 #   end
-#   
+#
 #   def command(arg)
 #     print arg, "\n"
 #     system arg
 #   end
-#   
+#
 #   m = Make.new
 #   m.rule(%w[t1]) { command 'date > t1' }
 #   m.rule(%w[t2]) { command 'date > t2' }
@@ -189,7 +189,7 @@
   end
 
   #
-  # Iterates over strongly connected component in the subgraph reachable from 
+  # Iterates over strongly connected component in the subgraph reachable from
   # _node_.
   #
   # Return value is unspecified.

Modified: MacRuby/branches/experimental/lib/un.rb
===================================================================
--- MacRuby/branches/experimental/lib/un.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/un.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -19,6 +19,8 @@
 #   ruby -run -e install -- [OPTION] SOURCE DEST
 #   ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE
 #   ruby -run -e touch -- [OPTION] FILE
+#   ruby -run -e wait_writable -- [OPTION] FILE
+#   ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION]
 #   ruby -run -e help [COMMAND]
 
 require "fileutils"
@@ -29,30 +31,32 @@
   @fileutils_output = $stdout
 end
 
-def setup(options = "")
-  ARGV.map! do |x|
-    case x
-    when /^-/
-      x.delete "^-#{options}v"
-    when /[*?\[{]/
-      Dir[x]
-    else
-      x
-    end
-  end
-  ARGV.flatten!
-  ARGV.delete_if{|x| x == "-"}
+def setup(options = "", *long_options)
   opt_hash = {}
+  argv = []
   OptionParser.new do |o|
     options.scan(/.:?/) do |s|
+      opt_name = s.delete(":").intern
       o.on("-" + s.tr(":", " ")) do |val|
-        opt_hash[s.delete(":").intern] = val
+        opt_hash[opt_name] = val
       end
     end
+    long_options.each do |s|
+      opt_name = s[/\A(?:--)?([^\s=]+)/, 1].intern
+      o.on(s.sub(/\A(?!--)/, '--')) do |val|
+        opt_hash[opt_name] = val
+      end
+    end
     o.on("-v") do opt_hash[:verbose] = true end
-    o.parse!
+    o.order!(ARGV) do |x|
+      if /[*?\[{]/ =~ x
+        argv.concat(Dir[x])
+      else
+        argv << x
+      end
+    end
   end
-  yield ARGV, opt_hash
+  yield argv, opt_hash
 end
 
 ##
@@ -154,11 +158,13 @@
 #
 #   ruby -run -e rmdir -- [OPTION] DIR
 #
+#   -p		remove DIRECTORY and its ancestors.
 #   -v		verbose
 #
 
 def rmdir
-  setup do |argv, options|
+  setup("p") do |argv, options|
+    options[:parents] = true if options.delete :p
     FileUtils.rmdir argv, options
   end
 end
@@ -218,6 +224,10 @@
 #
 #   ruby -run -e wait_writable -- [OPTION] FILE
 #
+#   -n RETRY	count to retry
+#   -w SEC	each wait time in seconds
+#   -v		verbose
+#
 
 def wait_writable
   setup("n:w:v") do |argv, options|
@@ -241,6 +251,38 @@
 end
 
 ##
+# Create makefile using mkmf.
+#
+#   ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION]
+#
+#   -d ARGS	run dir_config
+#   -h ARGS	run have_header
+#   -l ARGS	run have_library
+#   -f ARGS	run have_func
+#   -v ARGS	run have_var
+#   -t ARGS	run have_type
+#   -m ARGS	run have_macro
+#   -c ARGS	run have_const
+#   --vendor	install to vendor_ruby
+#
+
+def mkmf
+  setup("d:h:l:f:v:t:m:c:", "vendor") do |argv, options|
+    require 'mkmf'
+    opt = options[:d] and opt.split(/:/).each {|n| dir_config(*n.split(/,/))}
+    opt = options[:h] and opt.split(/:/).each {|n| have_header(*n.split(/,/))}
+    opt = options[:l] and opt.split(/:/).each {|n| have_library(*n.split(/,/))}
+    opt = options[:f] and opt.split(/:/).each {|n| have_func(*n.split(/,/))}
+    opt = options[:v] and opt.split(/:/).each {|n| have_var(*n.split(/,/))}
+    opt = options[:t] and opt.split(/:/).each {|n| have_type(*n.split(/,/))}
+    opt = options[:m] and opt.split(/:/).each {|n| have_macro(*n.split(/,/))}
+    opt = options[:c] and opt.split(/:/).each {|n| have_const(*n.split(/,/))}
+    $configure_args["--vendor"] = true if options[:vendor]
+    create_makefile(*argv)
+  end
+end
+
+##
 # Display help message.
 #
 #   ruby -run -e help [COMMAND]

Modified: MacRuby/branches/experimental/lib/uri/common.rb
===================================================================
--- MacRuby/branches/experimental/lib/uri/common.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/uri/common.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,7 +1,7 @@
 # = uri/common.rb
 #
 # Author:: Akira Yamada <akira at ruby-lang.org>
-# Revision:: $Id: common.rb 15442 2008-02-12 06:18:06Z naruse $
+# Revision:: $Id: common.rb 19413 2008-09-18 11:05:09Z mame $
 # License:: 
 #   You can redistribute it and/or modify it under the same term as Ruby.
 #
@@ -38,22 +38,232 @@
       #                 "$" | "," | "[" | "]" (RFC 2732)
       RESERVED = ";/?:@&=+$,\\[\\]"
 
+      # domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
+      DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
+      # toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
+      TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
+      # hostname      = *( domainlabel "." ) toplabel [ "." ]
+      HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
+
+      # :startdoc:
+    end # PATTERN
+
+    # :startdoc:
+  end # REGEXP
+
+  class Parser
+    include REGEXP
+
+    #
+    # == Synopsis
+    #
+    #   URI::Parser.new([opts])
+    #
+    # == Args
+    #
+    # The constructor accepts a hash as options for parser.
+    # Keys of options are pattern names of URI components
+    # and values of options are pattern strings.
+    # The constructor generetes set of regexps for parsing URIs.
+    #
+    # You can use the following keys:
+    #
+    #   * <tt>:ESCAPED</tt> (URI::PATTERN::ESCAPED in default)
+    #   * <tt>:UNRESERVED</tt> (URI::PATTERN::UNRESERVED in default)
+    #   * <tt>:DOMLABEL</tt> (URI::PATTERN::DOMLABEL in default)
+    #   * <tt>:TOPLABEL</tt> (URI::PATTERN::TOPLABEL in default)
+    #   * <tt>:HOSTNAME</tt> (URI::PATTERN::HOSTNAME in default)
+    #
+    # == Examples
+    #
+    #   p = URI::Parser.new(:ESCPAED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})"
+    #   u = p.parse("http://example.jp/%uABCD") #=> #<URI::HTTP:0xb78cf4f8 URL:http://example.jp/%uABCD>
+    #   URI.parse(u.to_s) #=> raises URI::InvalidURIError
+    #
+    #   s = "http://examle.com/ABCD"
+    #   u1 = p.parse(s) #=> #<URI::HTTP:0xb78c3220 URL:http://example.com/ABCD>
+    #   u2 = URI.parse(s) #=> #<URI::HTTP:0xb78b6d54 URL:http://example.com/ABCD>
+    #   u1 == u2 #=> true
+    #   u1.eql?(u2) #=> false
+    #
+    def initialize(opts = {})
+      @pattern = initialize_pattern(opts)
+      @pattern.each_value {|v| v.freeze}
+      @pattern.freeze
+
+      @regexp = initialize_regexp(@pattern)
+      @regexp.each_value {|v| v.freeze}
+      @regexp.freeze
+    end
+    attr_reader :pattern, :regexp
+
+    def split(uri)
+      case uri
+      when ''
+	# null uri
+
+      when @regexp[:ABS_URI]
+	scheme, opaque, userinfo, host, port, 
+	  registry, path, query, fragment = $~[1..-1]
+
+	# URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+
+	# absoluteURI   = scheme ":" ( hier_part | opaque_part )
+	# hier_part     = ( net_path | abs_path ) [ "?" query ]
+	# opaque_part   = uric_no_slash *uric
+
+	# abs_path      = "/"  path_segments
+	# net_path      = "//" authority [ abs_path ]
+
+	# authority     = server | reg_name
+	# server        = [ [ userinfo "@" ] hostport ]
+
+	if !scheme
+	  raise InvalidURIError, 
+	    "bad URI(absolute but no scheme): #{uri}"
+	end
+	if !opaque && (!path && (!host && !registry))
+	  raise InvalidURIError,
+	    "bad URI(absolute but no path): #{uri}" 
+	end
+
+      when @regexp[:REL_URI]
+	scheme = nil
+	opaque = nil
+
+	userinfo, host, port, registry, 
+	  rel_segment, abs_path, query, fragment = $~[1..-1]
+	if rel_segment && abs_path
+	  path = rel_segment + abs_path
+	elsif rel_segment
+	  path = rel_segment
+	elsif abs_path
+	  path = abs_path
+	end
+
+	# URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+
+	# relativeURI   = ( net_path | abs_path | rel_path ) [ "?" query ]
+
+	# net_path      = "//" authority [ abs_path ]
+	# abs_path      = "/"  path_segments
+	# rel_path      = rel_segment [ abs_path ]
+
+	# authority     = server | reg_name
+	# server        = [ [ userinfo "@" ] hostport ]
+
+      else
+	raise InvalidURIError, "bad URI(is not URI?): #{uri}"
+      end
+
+      path = '' if !path && !opaque # (see RFC2396 Section 5.2)
+      ret = [
+	scheme, 
+	userinfo, host, port,         # X
+	registry,                     # X
+	path,                         # Y
+	opaque,                       # Y
+	query,
+	fragment
+      ]
+      return ret
+    end
+
+    def parse(uri)
+      scheme, userinfo, host, port, 
+       	registry, path, opaque, query, fragment = self.split(uri)
+
+      if scheme && URI.scheme_list.include?(scheme.upcase)
+	URI.scheme_list[scheme.upcase].new(scheme, userinfo, host, port, 
+                                           registry, path, opaque, query, 
+                                           fragment, self)
+      else
+	Generic.new(scheme, userinfo, host, port, 
+	   	    registry, path, opaque, query, 
+	    	    fragment, self)
+      end
+    end
+
+    def join(*str)
+      u = self.parse(str[0])
+      str[1 .. -1].each do |x|
+	u = u.merge(x)
+      end
+      u
+    end
+
+    def extract(str, schemes = nil, &block)
+      if block_given?
+       	str.scan(make_regexp(schemes)) { yield $& }
+	nil
+      else
+	result = []
+	str.scan(make_regexp(schemes)) { result.push $& }
+	result
+      end
+    end
+
+    def make_regexp(schemes = nil)
+      unless schemes
+       	@regexp[:ABS_URI_REF]
+      else
+	/(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
+      end
+    end
+
+    def escape(str, unsafe = @regexp[:UNSAFE])
+      unless unsafe.kind_of?(Regexp)
+        # perhaps unsafe is String object
+        unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false)
+      end
+      str.gsub(unsafe) do
+        us = $&
+        tmp = ''
+        us.each_byte do |uc|
+          tmp << sprintf('%%%02X', uc)
+        end
+        tmp
+      end
+    end
+
+    def unescape(str, escaped = @regexp[:ESCAPED])
+      str.gsub(escaped) { [$&[1, 2].hex].pack('U') }
+    end
+
+    @@to_s = Kernel.instance_method(:to_s)
+    def inspect
+      @@to_s.bind(self).call
+    end
+
+    private
+
+    def initialize_pattern(opts = {})
+      ret = {}
+      ret[:ESCAPED] = escaped = (opts.delete(:ESCAPED) || PATTERN::ESCAPED)
+      ret[:UNRESERVED] = unreserved = opts.delete(:UNRESERVED) || PATTERN::UNRESERVED
+      ret[:RESERVED] = reserved = opts.delete(:RESERVED) || PATTERN::RESERVED
+      ret[:DOMLABEL] = domlabel = opts.delete(:DOMLABEL) || PATTERN::DOMLABEL
+      ret[:TOPLABEL] = toplabel = opts.delete(:TOPLABEL) || PATTERN::TOPLABEL
+      ret[:HOSTNAME] = hostname = opts.delete(:HOSTNAME)
+
+      # RFC 2396 (URI Generic Syntax)
+      # RFC 2732 (IPv6 Literal Addresses in URL's)
+      # RFC 2373 (IPv6 Addressing Architecture)
+
       # uric          = reserved | unreserved | escaped
-      URIC = "(?:[#{UNRESERVED}#{RESERVED}]|#{ESCAPED})"
+      ret[:URIC] = uric = "(?:[#{unreserved}#{reserved}]|#{escaped})"
       # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
       #                 "&" | "=" | "+" | "$" | ","
-      URIC_NO_SLASH = "(?:[#{UNRESERVED};?:@&=+$,]|#{ESCAPED})"
+      ret[:URIC_NO_SLASH] = uric_no_slash = "(?:[#{unreserved};?:@&=+$,]|#{escaped})"
       # query         = *uric
-      QUERY = "#{URIC}*"
+      ret[:QUERY] = query = "#{uric}*"
       # fragment      = *uric
-      FRAGMENT = "#{URIC}*"
+      ret[:FRAGMENT] = fragment = "#{uric}*"
 
-      # domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
-      DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
-      # toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
-      TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
       # hostname      = *( domainlabel "." ) toplabel [ "." ]
-      HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
+      unless hostname
+	ret[:HOSTNAME] = hostname = "(?:#{domlabel}\\.)*#{toplabel}\\.?"
+      end
 
       # RFC 2373, APPENDIX B:
       # IPv6address = hexpart [ ":" IPv4address ]
@@ -66,153 +276,165 @@
       # allowed too.  Here is a replacement.
       #
       # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
-      IPV4ADDR = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
+      ret[:IPV4ADDR] = ipv4addr = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
       # hex4     = 1*4HEXDIG
-      HEX4 = "[#{HEX}]{1,4}"
+      hex4 = "[#{PATTERN::HEX}]{1,4}"
       # lastpart = hex4 | IPv4address
-      LASTPART = "(?:#{HEX4}|#{IPV4ADDR})"
+      lastpart = "(?:#{hex4}|#{ipv4addr})"
       # hexseq1  = *( hex4 ":" ) hex4
-      HEXSEQ1 = "(?:#{HEX4}:)*#{HEX4}"
+      hexseq1 = "(?:#{hex4}:)*#{hex4}"
       # hexseq2  = *( hex4 ":" ) lastpart
-      HEXSEQ2 = "(?:#{HEX4}:)*#{LASTPART}"
+      hexseq2 = "(?:#{hex4}:)*#{lastpart}"
       # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ]
-      IPV6ADDR = "(?:#{HEXSEQ2}|(?:#{HEXSEQ1})?::(?:#{HEXSEQ2})?)"
+      ret[:IPV6ADDR] = ipv6addr = "(?:#{hexseq2}|(?:#{hexseq1})?::(?:#{hexseq2})?)"
 
       # IPv6prefix  = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT
       # unused
 
       # ipv6reference = "[" IPv6address "]" (RFC 2732)
-      IPV6REF = "\\[#{IPV6ADDR}\\]"
+      ret[:IPV6REF] = ipv6ref = "\\[#{ipv6addr}\\]"
 
       # host          = hostname | IPv4address
       # host          = hostname | IPv4address | IPv6reference (RFC 2732)
-      HOST = "(?:#{HOSTNAME}|#{IPV4ADDR}|#{IPV6REF})"
+      ret[:HOST] = host = "(?:#{hostname}|#{ipv4addr}|#{ipv6ref})"
       # port          = *digit
-      PORT = '\d*'
+      port = '\d*'
       # hostport      = host [ ":" port ]
-      HOSTPORT = "#{HOST}(?::#{PORT})?"
+      ret[:HOSTPORT] = hostport = "#{host}(?::#{port})?"
 
       # userinfo      = *( unreserved | escaped |
       #                    ";" | ":" | "&" | "=" | "+" | "$" | "," )
-      USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})*"
+      ret[:USERINFO] = userinfo = "(?:[#{unreserved};:&=+$,]|#{escaped})*"
 
       # pchar         = unreserved | escaped |
       #                 ":" | "@" | "&" | "=" | "+" | "$" | ","
-      PCHAR = "(?:[#{UNRESERVED}:@&=+$,]|#{ESCAPED})"
+      pchar = "(?:[#{unreserved}:@&=+$,]|#{escaped})"
       # param         = *pchar
-      PARAM = "#{PCHAR}*"
+      param = "#{pchar}*"
       # segment       = *pchar *( ";" param )
-      SEGMENT = "#{PCHAR}*(?:;#{PARAM})*"
+      segment = "#{pchar}*(?:;#{param})*"
       # path_segments = segment *( "/" segment )
-      PATH_SEGMENTS = "#{SEGMENT}(?:/#{SEGMENT})*"
+      ret[:PATH_SEGMENTS] = path_segments = "#{segment}(?:/#{segment})*"
 
       # server        = [ [ userinfo "@" ] hostport ]
-      SERVER = "(?:#{USERINFO}@)?#{HOSTPORT}"
+      server = "(?:#{userinfo}@)?#{hostport}"
       # reg_name      = 1*( unreserved | escaped | "$" | "," |
       #                     ";" | ":" | "@" | "&" | "=" | "+" )
-      REG_NAME = "(?:[#{UNRESERVED}$,;:@&=+]|#{ESCAPED})+"
+      ret[:REG_NAME] = reg_name = "(?:[#{unreserved}$,;:@&=+]|#{escaped})+"
       # authority     = server | reg_name
-      AUTHORITY = "(?:#{SERVER}|#{REG_NAME})"
+      authority = "(?:#{server}|#{reg_name})"
 
       # rel_segment   = 1*( unreserved | escaped |
       #                     ";" | "@" | "&" | "=" | "+" | "$" | "," )
-      REL_SEGMENT = "(?:[#{UNRESERVED};@&=+$,]|#{ESCAPED})+"
+      ret[:REL_SEGMENT] = rel_segment = "(?:[#{unreserved};@&=+$,]|#{escaped})+"
 
       # scheme        = alpha *( alpha | digit | "+" | "-" | "." )
-      SCHEME = "[#{ALPHA}][-+.#{ALPHA}\\d]*"
+      ret[:SCHEME] = scheme = "[#{PATTERN::ALPHA}][-+.#{PATTERN::ALPHA}\\d]*"
 
       # abs_path      = "/"  path_segments
-      ABS_PATH = "/#{PATH_SEGMENTS}"
+      ret[:ABS_PATH] = abs_path = "/#{path_segments}"
       # rel_path      = rel_segment [ abs_path ]
-      REL_PATH = "#{REL_SEGMENT}(?:#{ABS_PATH})?"
+      ret[:REL_PATH] = rel_path = "#{rel_segment}(?:#{abs_path})?"
       # net_path      = "//" authority [ abs_path ]
-      NET_PATH   = "//#{AUTHORITY}(?:#{ABS_PATH})?"
+      ret[:NET_PATH] = net_path = "//#{authority}(?:#{abs_path})?"
 
       # hier_part     = ( net_path | abs_path ) [ "?" query ]
-      HIER_PART   = "(?:#{NET_PATH}|#{ABS_PATH})(?:\\?(?:#{QUERY}))?"
+      ret[:HIER_PART] = hier_part = "(?:#{net_path}|#{abs_path})(?:\\?(?:#{query}))?"
       # opaque_part   = uric_no_slash *uric
-      OPAQUE_PART = "#{URIC_NO_SLASH}#{URIC}*"
+      ret[:OPAQUE_PART] = opaque_part = "#{uric_no_slash}#{uric}*"
 
       # absoluteURI   = scheme ":" ( hier_part | opaque_part )
-      ABS_URI   = "#{SCHEME}:(?:#{HIER_PART}|#{OPAQUE_PART})"
+      ret[:ABS_URI] = abs_uri = "#{scheme}:(?:#{hier_part}|#{opaque_part})"
       # relativeURI   = ( net_path | abs_path | rel_path ) [ "?" query ]
-      REL_URI = "(?:#{NET_PATH}|#{ABS_PATH}|#{REL_PATH})(?:\\?#{QUERY})?"
+      ret[:REL_URI] = rel_uri = "(?:#{net_path}|#{abs_path}|#{rel_path})(?:\\?#{query})?"
 
       # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
-      URI_REF = "(?:#{ABS_URI}|#{REL_URI})?(?:##{FRAGMENT})?"
+      ret[:URI_REF] = uri_ref = "(?:#{abs_uri}|#{rel_uri})?(?:##{fragment})?"
 
-      # XXX:
-      X_ABS_URI = "
-        (#{PATTERN::SCHEME}):                     (?# 1: scheme)
+      ret[:X_ABS_URI] = "
+        (#{scheme}):                           (?# 1: scheme)
         (?:
-           (#{PATTERN::OPAQUE_PART})              (?# 2: opaque)
+           (#{opaque_part})                    (?# 2: opaque)
         |
            (?:(?:
              //(?:
-                 (?:(?:(#{PATTERN::USERINFO})@)?  (?# 3: userinfo)
-                   (?:(#{PATTERN::HOST})(?::(\\d*))?))?(?# 4: host, 5: port)
+                 (?:(?:(#{userinfo})@)?        (?# 3: userinfo)
+                   (?:(#{host})(?::(\\d*))?))? (?# 4: host, 5: port)
                |
-                 (#{PATTERN::REG_NAME})           (?# 6: registry)
+                 (#{reg_name})                 (?# 6: registry)
                )
              |
-             (?!//))                              (?# XXX: '//' is the mark for hostport)
-             (#{PATTERN::ABS_PATH})?              (?# 7: path)
-           )(?:\\?(#{PATTERN::QUERY}))?           (?# 8: query)
+             (?!//))                           (?# XXX: '//' is the mark for hostport)
+             (#{abs_path})?                    (?# 7: path)
+           )(?:\\?(#{query}))?                 (?# 8: query)
         )
-        (?:\\#(#{PATTERN::FRAGMENT}))?            (?# 9: fragment)
+        (?:\\#(#{fragment}))?                  (?# 9: fragment)
       "
-      X_REL_URI = "
+
+      ret[:X_REL_URI] = "
         (?:
           (?:
             //
             (?:
-              (?:(#{PATTERN::USERINFO})@)?       (?# 1: userinfo)
-                (#{PATTERN::HOST})?(?::(\\d*))?  (?# 2: host, 3: port)
+              (?:(#{userinfo})@)?       (?# 1: userinfo)
+                (#{host})?(?::(\\d*))?  (?# 2: host, 3: port)
             |
-              (#{PATTERN::REG_NAME})             (?# 4: registry)
+              (#{reg_name})             (?# 4: registry)
             )
           )
         |
-          (#{PATTERN::REL_SEGMENT})              (?# 5: rel_segment)
+          (#{rel_segment})              (?# 5: rel_segment)
         )?
-        (#{PATTERN::ABS_PATH})?                  (?# 6: abs_path)
-        (?:\\?(#{PATTERN::QUERY}))?              (?# 7: query)
-        (?:\\#(#{PATTERN::FRAGMENT}))?           (?# 8: fragment)
+        (#{abs_path})?                  (?# 6: abs_path)
+        (?:\\?(#{query}))?              (?# 7: query)
+        (?:\\#(#{fragment}))?           (?# 8: fragment)
       "
-      # :startdoc:
-    end # PATTERN
 
-    # :stopdoc:
+      ret
+    end
 
-    # for URI::split
-    ABS_URI = Regexp.new('^' + PATTERN::X_ABS_URI + '$', #'
-                         Regexp::EXTENDED).freeze
-    REL_URI = Regexp.new('^' + PATTERN::X_REL_URI + '$', #'
-                         Regexp::EXTENDED).freeze
+    def initialize_regexp(pattern)
+      ret = {}
 
-    # for URI::extract
-    URI_REF     = Regexp.new(PATTERN::URI_REF).freeze
-    ABS_URI_REF = Regexp.new(PATTERN::X_ABS_URI, Regexp::EXTENDED).freeze
-    REL_URI_REF = Regexp.new(PATTERN::X_REL_URI, Regexp::EXTENDED).freeze
+      # for URI::split
+      ret[:ABS_URI] = Regexp.new('^' + pattern[:X_ABS_URI] + '$', Regexp::EXTENDED)
+      ret[:REL_URI] = Regexp.new('^' + pattern[:X_REL_URI] + '$', Regexp::EXTENDED)
 
-    # for URI::escape/unescape
-    ESCAPED = Regexp.new(PATTERN::ESCAPED).freeze
-    UNSAFE  = Regexp.new("[^#{PATTERN::UNRESERVED}#{PATTERN::RESERVED}]").freeze
+      # for URI::extract
+      ret[:URI_REF]     = Regexp.new(pattern[:URI_REF])
+      ret[:ABS_URI_REF] = Regexp.new(pattern[:X_ABS_URI], Regexp::EXTENDED)
+      ret[:REL_URI_REF] = Regexp.new(pattern[:X_REL_URI], Regexp::EXTENDED)
 
-    # for Generic#initialize
-    SCHEME   = Regexp.new("^#{PATTERN::SCHEME}$").freeze #"
-    USERINFO = Regexp.new("^#{PATTERN::USERINFO}$").freeze #"
-    HOST     = Regexp.new("^#{PATTERN::HOST}$").freeze #"
-    PORT     = Regexp.new("^#{PATTERN::PORT}$").freeze #"
-    OPAQUE   = Regexp.new("^#{PATTERN::OPAQUE_PART}$").freeze #"
-    REGISTRY = Regexp.new("^#{PATTERN::REG_NAME}$").freeze #"
-    ABS_PATH = Regexp.new("^#{PATTERN::ABS_PATH}$").freeze #"
-    REL_PATH = Regexp.new("^#{PATTERN::REL_PATH}$").freeze #"
-    QUERY    = Regexp.new("^#{PATTERN::QUERY}$").freeze #"
-    FRAGMENT = Regexp.new("^#{PATTERN::FRAGMENT}$").freeze #"
-    # :startdoc:
-  end # REGEXP
+      # for URI::escape/unescape
+      ret[:ESCAPED] = Regexp.new(pattern[:ESCAPED])
+      ret[:UNSAFE]  = Regexp.new("[^#{pattern[:UNRESERVED]}#{pattern[:RESERVED]}]")
 
+      # for Generic#initialize
+      ret[:SCHEME]   = Regexp.new("^#{pattern[:SCHEME]}$")
+      ret[:USERINFO] = Regexp.new("^#{pattern[:USERINFO]}$")
+      ret[:HOST]     = Regexp.new("^#{pattern[:HOST]}$")
+      ret[:PORT]     = Regexp.new("^#{pattern[:PORT]}$")
+      ret[:OPAQUE]   = Regexp.new("^#{pattern[:OPAQUE_PART]}$")
+      ret[:REGISTRY] = Regexp.new("^#{pattern[:REG_NAME]}$")
+      ret[:ABS_PATH] = Regexp.new("^#{pattern[:ABS_PATH]}$")
+      ret[:REL_PATH] = Regexp.new("^#{pattern[:REL_PATH]}$")
+      ret[:QUERY]    = Regexp.new("^#{pattern[:QUERY]}$")
+      ret[:FRAGMENT] = Regexp.new("^#{pattern[:FRAGMENT]}$")
+
+      ret
+    end
+  end # class Parser
+
+  DEFAULT_PARSER = Parser.new
+  DEFAULT_PARSER.pattern.each_pair do |sym, str|
+    unless REGEXP::PATTERN.const_defined?(sym)
+      REGEXP::PATTERN.const_set(sym, str)
+    end
+  end
+  DEFAULT_PARSER.regexp.each_pair do |sym, str|
+    const_set(sym, str)
+  end
+
   module Util # :nodoc:
     def make_components_hash(klass, array_hash)
       tmp = {}
@@ -246,8 +468,6 @@
   end
 
   module Escape
-    include REGEXP
-
     #
     # == Synopsis
     #
@@ -280,19 +500,8 @@
     #   p URI.escape("@?@!", "!?")
     #   # => "@%3F@%21"
     #
-    def escape(str, unsafe = UNSAFE)
-      unless unsafe.kind_of?(Regexp)
-        # perhaps unsafe is String object
-        unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false, 'N')
-      end
-      str.gsub(unsafe) do
-        us = $&
-        tmp = ''
-        us.each_byte do |uc|
-          tmp << sprintf('%%%02X', uc)
-        end
-        tmp
-      end
+    def escape(*arg)
+      DEFAULT_PARSER.escape(*arg)
     end
     alias encode escape
     #
@@ -316,18 +525,19 @@
     #   p URI.unescape(enc_uri)
     #   # => "http://example.com/?a=\t\r"
     #
-    def unescape(str)
-      str.gsub(ESCAPED) do
-        $&[1,2].hex.chr
-      end
+    def unescape(*arg)
+      DEFAULT_PARSER.unescape(*arg)
     end
     alias decode unescape
   end
 
+  extend Escape
   include REGEXP
-  extend Escape
 
   @@schemes = {}
+  def self.scheme_list
+    @@schemes
+  end
   
   #
   # Base class for all URI exceptions.
@@ -378,75 +588,7 @@
   #   # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil]
   #
   def self.split(uri)
-    case uri
-    when ''
-      # null uri
-
-    when ABS_URI
-      scheme, opaque, userinfo, host, port, 
-        registry, path, query, fragment = $~[1..-1]
-
-      # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
-
-      # absoluteURI   = scheme ":" ( hier_part | opaque_part )
-      # hier_part     = ( net_path | abs_path ) [ "?" query ]
-      # opaque_part   = uric_no_slash *uric
-
-      # abs_path      = "/"  path_segments
-      # net_path      = "//" authority [ abs_path ]
-
-      # authority     = server | reg_name
-      # server        = [ [ userinfo "@" ] hostport ]
-
-      if !scheme
-        raise InvalidURIError, 
-          "bad URI(absolute but no scheme): #{uri}"
-      end
-      if !opaque && (!path && (!host && !registry))
-        raise InvalidURIError,
-          "bad URI(absolute but no path): #{uri}" 
-      end
-
-    when REL_URI
-      scheme = nil
-      opaque = nil
-
-      userinfo, host, port, registry, 
-        rel_segment, abs_path, query, fragment = $~[1..-1]
-      if rel_segment && abs_path
-        path = rel_segment + abs_path
-      elsif rel_segment
-        path = rel_segment
-      elsif abs_path
-        path = abs_path
-      end
-
-      # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
-
-      # relativeURI   = ( net_path | abs_path | rel_path ) [ "?" query ]
-
-      # net_path      = "//" authority [ abs_path ]
-      # abs_path      = "/"  path_segments
-      # rel_path      = rel_segment [ abs_path ]
-
-      # authority     = server | reg_name
-      # server        = [ [ userinfo "@" ] hostport ]
-
-    else
-      raise InvalidURIError, "bad URI(is not URI?): #{uri}"
-    end
-
-    path = '' if !path && !opaque # (see RFC2396 Section 5.2)
-    ret = [
-      scheme, 
-      userinfo, host, port,         # X
-      registry,                        # X
-      path,                         # Y
-      opaque,                        # Y
-      query,
-      fragment
-    ]
-    return ret
+    DEFAULT_PARSER.split(uri)
   end
 
   #
@@ -481,18 +623,7 @@
   #   # => "www.ruby-lang.org" 
   # 
   def self.parse(uri)
-    scheme, userinfo, host, port, 
-      registry, path, opaque, query, fragment = self.split(uri)
-
-    if scheme && @@schemes.include?(scheme.upcase)
-      @@schemes[scheme.upcase].new(scheme, userinfo, host, port, 
-                                   registry, path, opaque, query, 
-                                   fragment)
-    else
-      Generic.new(scheme, userinfo, host, port, 
-                  registry, path, opaque, query, 
-                  fragment)
-    end
+    DEFAULT_PARSER.parse(uri)
   end
 
   #
@@ -517,11 +648,7 @@
   #   # => #<URI::HTTP:0x2022ac02 URL:http://localhost/main.rbx>
   #
   def self.join(*str)
-    u = self.parse(str[0])
-    str[1 .. -1].each do |x|
-      u = u.merge(x)
-    end
-    u
+    DEFAULT_PARSER.join(*str)
   end
 
   #
@@ -549,14 +676,7 @@
   #   # => ["http://foo.example.com/bla", "mailto:test at example.com"]
   #
   def self.extract(str, schemes = nil, &block)
-    if block_given?
-      str.scan(regexp(schemes)) { yield $& }
-      nil
-    else
-      result = []
-      str.scan(regexp(schemes)) { result.push $& }
-      result
-    end
+    DEFAULT_PARSER.extract(str, schemes, &block)
   end
 
   #
@@ -591,11 +711,7 @@
   #   end
   #
   def self.regexp(schemes = nil)
-    unless schemes
-      ABS_URI_REF
-    else
-      /(?=#{Regexp.union(*schemes)}:)#{PATTERN::X_ABS_URI}/xn
-    end
+    DEFAULT_PARSER.make_regexp(schemes)
   end
 
 end

Modified: MacRuby/branches/experimental/lib/uri/generic.rb
===================================================================
--- MacRuby/branches/experimental/lib/uri/generic.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/uri/generic.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,7 +3,7 @@
 #
 # Author:: Akira Yamada <akira at ruby-lang.org>
 # License:: You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: generic.rb 15456 2008-02-13 07:26:52Z naruse $
+# Revision:: $Id: generic.rb 20258 2008-11-18 16:46:16Z yugui $
 #
 
 require 'uri/common'
@@ -16,7 +16,6 @@
   #
   class Generic
     include URI
-    include REGEXP
 
     DEFAULT_PORT = nil
 
@@ -74,7 +73,7 @@
         if args.kind_of?(Array)
           return self.build(args.collect{|x| 
             if x
-              URI.escape(x)
+              @parser.escape(x)
             else
               x
             end
@@ -83,7 +82,7 @@
           tmp = {}
           args.each do |key, value|
             tmp[key] = if value
-                URI.escape(value)
+                @parser.escape(value)
               else
                 value
               end
@@ -122,6 +121,7 @@
         "expected Array of or Hash of components of #{self.class} (#{self.class.component.join(', ')})"
       end
 
+      tmp << DEFAULT_PARSER
       tmp << true
       return self.new(*tmp)
     end
@@ -146,6 +146,8 @@
     #   Query data
     # +fragment+::
     #   A part of URI after '#' sign
+    # +parser+::
+    #   Parser for internal use [URI::DEFAULT_PARSER by default]
     # +arg_check+::
     #   Check arguments [false by default]
     #
@@ -158,6 +160,7 @@
                    path, opaque, 
                    query, 
                    fragment,
+		   parser = DEFAULT_PARSER,
                    arg_check = false)
       @scheme = nil
       @user = nil
@@ -169,6 +172,7 @@
       @opaque = nil
       @registry = nil
       @fragment = nil
+      @parser = parser
 
       if arg_check
         self.scheme = scheme
@@ -208,6 +212,7 @@
     attr_reader :query
     attr_reader :opaque
     attr_reader :fragment
+    attr_reader :parser
 
     # replace self by other URI object
     def replace!(oth)
@@ -226,7 +231,7 @@
     end
 
     def check_scheme(v)
-      if v && SCHEME !~ v
+      if v && @parser.regexp[:SCHEME] !~ v
         raise InvalidComponentError,
           "bad component(expected scheme component): #{v}"
       end
@@ -265,7 +270,7 @@
 
       return v unless v
 
-      if USERINFO !~ v
+      if @parser.regexp[:USERINFO] !~ v
         raise InvalidComponentError,
           "bad component(expected userinfo component or user component): #{v}"
       end
@@ -286,7 +291,7 @@
           "password component depends user component"
       end
 
-      if USERINFO !~ v
+      if @parser.regexp[:USERINFO] !~ v
         raise InvalidComponentError,
           "bad component(expected user component): #{v}"
       end
@@ -351,7 +356,7 @@
     private :split_userinfo
 
     def escape_userpass(v)
-      v = URI.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
+      v = @parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
     end
     private :escape_userpass
 
@@ -379,7 +384,7 @@
       if @registry || @opaque
         raise InvalidURIError, 
           "can not set host with registry or opaque"
-      elsif HOST !~ v
+      elsif @parser.regexp[:HOST] !~ v
         raise InvalidComponentError,
           "bad component(expected host component): #{v}"
       end
@@ -405,7 +410,7 @@
       if @registry || @opaque
         raise InvalidURIError, 
           "can not set port with registry or opaque"
-      elsif !v.kind_of?(Fixnum) && PORT !~ v
+      elsif !v.kind_of?(Fixnum) && @parser.regexp[:PORT] !~ v
         raise InvalidComponentError,
           "bad component(expected port component): #{v}"
       end
@@ -441,7 +446,7 @@
       if @host || @port || @user # userinfo = @user + ':' + @password
         raise InvalidURIError, 
           "can not set registry with host, port, or userinfo"
-      elsif v && REGISTRY !~ v
+      elsif v && @parser.regexp[:REGISTRY] !~ v
         raise InvalidComponentError,
           "bad component(expected registry component): #{v}"
       end
@@ -471,12 +476,12 @@
       end
 
       if @scheme
-        if v && v != '' && ABS_PATH !~ v
+        if v && v != '' && @parser.regexp[:ABS_PATH] !~ v
           raise InvalidComponentError, 
             "bad component(expected absolute path component): #{v}"
         end
       else
-        if v && v != '' && ABS_PATH !~ v && REL_PATH !~ v
+        if v && v != '' && @parser.regexp[:ABS_PATH] !~ v && @parser.regexp[:REL_PATH] !~ v
           raise InvalidComponentError, 
             "bad component(expected relative path component): #{v}"
         end
@@ -508,10 +513,10 @@
           "query conflicts with opaque"
       end
 
-      if v && v != '' && QUERY !~ v
+      if v && v != '' && @parser.regexp[:QUERY] !~ v
           raise InvalidComponentError, 
             "bad component(expected query component): #{v}"
-        end
+      end
 
       return true
     end
@@ -537,7 +542,7 @@
       if @host || @port || @user || @path  # userinfo = @user + ':' + @password
         raise InvalidURIError, 
           "can not set opaque with host, port, userinfo or path"
-      elsif v && OPAQUE !~ v
+      elsif v && @parser.regexp[:OPAQUE] !~ v
         raise InvalidComponentError,
           "bad component(expected opaque component): #{v}"
       end
@@ -560,7 +565,7 @@
     def check_fragment(v)
       return v unless v
 
-      if v && v != '' && FRAGMENT !~ v
+      if v && v != '' && @parser.regexp[:FRAGMENT] !~ v
         raise InvalidComponentError, 
           "bad component(expected fragment component): #{v}"
       end
@@ -772,7 +777,7 @@
       case oth
       when Generic
       when String
-        oth = URI.parse(oth)
+        oth = @parser.parse(oth)
       else
         raise ArgumentError,
           "bad argument(expected URI object or URI string)"
@@ -843,7 +848,7 @@
       case oth
       when Generic
       when String
-        oth = URI.parse(oth)
+        oth = @parser.parse(oth)
       else
         raise ArgumentError,
           "bad argument(expected URI object or URI string)"
@@ -864,7 +869,7 @@
       rel = URI::Generic.new(nil, # it is relative URI
                              self.userinfo, self.host, self.port, 
                              self.registry, self.path, self.opaque,
-                             self.query, self.fragment)
+                             self.query, self.fragment, @parser)
 
       if rel.userinfo != oth.userinfo ||
           rel.host.to_s.downcase != oth.host.to_s.downcase ||
@@ -955,7 +960,7 @@
       case oth
       when Generic
       when String
-        oth = URI.parse(oth)
+        oth = @parser.parse(oth)
       else
         raise ArgumentError,
           "bad argument(expected URI object or URI string)"
@@ -1054,6 +1059,7 @@
     end
 
     def eql?(oth)
+      @parser == oth.parser &&
       self.component_ary.eql?(oth.component_ary)
     end
 
@@ -1111,7 +1117,7 @@
     def coerce(oth)
       case oth
       when String
-        oth = URI.parse(oth)
+        oth = @parser.parse(oth)
       else
         super
       end

Modified: MacRuby/branches/experimental/lib/uri/mailto.rb
===================================================================
--- MacRuby/branches/experimental/lib/uri/mailto.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/uri/mailto.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,7 +3,7 @@
 #
 # Author:: Akira Yamada <akira at ruby-lang.org>
 # License:: You can redistribute it and/or modify it under the same term as Ruby.
-# Revision:: $Id: mailto.rb 14565 2007-12-24 01:51:49Z drbrain $
+# Revision:: $Id: mailto.rb 19495 2008-09-23 18:16:08Z drbrain $
 #
 
 require 'uri/generic'
@@ -135,7 +135,7 @@
       @headers = []
 
       if MAILTO_REGEXP =~ @opaque
-         if arg[-1]
+        if arg[-1]
           self.to = $1
           self.headers = $2
         else
@@ -159,7 +159,7 @@
       return true unless v
       return true if v.size == 0
 
-      if OPAQUE !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v
+      if @parser.regexp[:OPAQUE] !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v
         raise InvalidComponentError,
           "bad component(expected opaque component): #{v}"
       end
@@ -183,7 +183,7 @@
       return true unless v
       return true if v.size == 0
 
-      if OPAQUE !~ v || 
+      if @parser.regexp[:OPAQUE] !~ v || 
           /\A(#{HEADER_PATTERN}(?:\&#{HEADER_PATTERN})*)\z/o !~ v
         raise InvalidComponentError,
           "bad component(expected opaque component): #{v}"
@@ -239,18 +239,18 @@
     #   # => "To: ruby-list at ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n"
     #
     def to_mailtext
-      to = URI::unescape(@to)
+      to = @parser.unescape(@to)
       head = ''
       body = ''
       @headers.each do |x|
         case x[0]
         when 'body'
-          body = URI::unescape(x[1])
+          body = @parser.unescape(x[1])
         when 'to'
-          to << ', ' + URI::unescape(x[1])
+          to << ', ' + @parser.unescape(x[1])
         else
-          head << URI::unescape(x[0]).capitalize + ': ' +
-            URI::unescape(x[1])  + "\n"
+          head << @parser.unescape(x[0]).capitalize + ': ' +
+            @parser.unescape(x[1])  + "\n"
         end
       end
 

Modified: MacRuby/branches/experimental/lib/webrick/cgi.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/cgi.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/cgi.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -5,7 +5,7 @@
 # Copyright (c) 2003 Internet Programming with Ruby writers. All rights
 # reserved.
 #
-# $Id: cgi.rb 14260 2007-12-17 07:03:57Z gotoyuzo $
+# $Id: cgi.rb 18678 2008-08-17 17:33:13Z gotoyuzo $
 
 require "webrick/httprequest"
 require "webrick/httpresponse"
@@ -207,6 +207,10 @@
       def each
         input.each{|line| yield(line) }
       end
+
+      def eof?
+        input.eof?
+      end
   
       def <<(data)
         @out_port << data

Modified: MacRuby/branches/experimental/lib/webrick/httpauth/digestauth.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httpauth/digestauth.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httpauth/digestauth.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -52,7 +52,7 @@
         when 'SHA1','SHA1-sess'  # it is a bonus feature :-)
           @h = Digest::SHA1
         else
-          msg = format('Alogrithm "%s" is not supported.', @algorithm)
+          msg = format('Algorithm "%s" is not supported.', @algorithm)
           raise ArgumentError.new(msg)
         end
 
@@ -229,7 +229,7 @@
 
       def split_param_value(string)
         ret = {}
-        while string.size != 0
+        while string.bytesize != 0
           case string           
           when /^\s*([\w\-\.\*\%\!]+)=\s*\"((\\.|[^\"])*)\"\s*,?/
             key = $1

Modified: MacRuby/branches/experimental/lib/webrick/httpproxy.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httpproxy.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httpproxy.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -146,11 +146,11 @@
         while fds = IO::select([ua, os])
           if fds[0].member?(ua)
             buf = ua.sysread(1024);
-            @logger.debug("CONNECT: #{buf.size} byte from User-Agent")
+            @logger.debug("CONNECT: #{buf.bytesize} byte from User-Agent")
             os.syswrite(buf)
           elsif fds[0].member?(os)
             buf = os.sysread(1024);
-            @logger.debug("CONNECT: #{buf.size} byte from #{host}:#{port}")
+            @logger.debug("CONNECT: #{buf.bytesize} byte from #{host}:#{port}")
             ua.syswrite(buf)
           end
         end
@@ -186,7 +186,7 @@
 
     private
 
-    # Some header fields shuold not be transfered.
+    # Some header fields should not be transferred.
     HopByHop = %w( connection keep-alive proxy-authenticate upgrade
                    proxy-authorization te trailers transfer-encoding )
     ShouldNotTransfer = %w( set-cookie proxy-connection )
@@ -272,7 +272,7 @@
         response = yield(http, path, header)
       end
 
-      # Persistent connction requirements are mysterious for me.
+      # Persistent connection requirements are mysterious for me.
       # So I will close the connection in every response.
       res['proxy-connection'] = "close"
       res['connection'] = "close"

Modified: MacRuby/branches/experimental/lib/webrick/httprequest.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httprequest.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httprequest.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -244,12 +244,12 @@
 
     def read_request_line(socket)
       @request_line = read_line(socket, 1024) if socket
-      if @request_line.size >= 1024 and @request_line[-1, 1] != LF
+      if @request_line.bytesize >= 1024 and @request_line[-1, 1] != LF
         raise HTTPStatus::RequestURITooLarge
       end
       @request_time = Time.now
       raise HTTPStatus::EOFError unless @request_line
-      if /^(\S+)\s+(\S+)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line
+      if /^(\S+)\s+(\S++)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line
         @request_method = $1
         @unparsed_uri   = $2
         @http_version   = HTTPVersion.new($3 ? $3 : "0.9")
@@ -307,7 +307,7 @@
         while @remaining_size > 0 
           sz = [@buffer_size, @remaining_size].min
           break unless buf = read_data(socket, sz)
-          @remaining_size -= buf.size
+          @remaining_size -= buf.bytesize
           block.call(buf)
         end
         if @remaining_size > 0 && @socket.eof?
@@ -334,7 +334,7 @@
       chunk_size, = read_chunk_size(socket)
       while chunk_size > 0
         data = read_data(socket, chunk_size) # read chunk-data
-        if data.nil? || data.size != chunk_size
+        if data.nil? || data.bytesize != chunk_size
           raise BadRequest, "bad chunk data size."
         end
         read_line(socket)                    # skip CRLF

Modified: MacRuby/branches/experimental/lib/webrick/httpresponse.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httpresponse.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httpresponse.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -131,7 +131,7 @@
         end
       end
 
-      # Determin the message length (RFC2616 -- 4.4 Message Length)
+      # Determine the message length (RFC2616 -- 4.4 Message Length)
       if @status == 304 || @status == 204 || HTTPStatus::info?(@status)
         @header.delete('content-length')
         @body = ""
@@ -142,7 +142,7 @@
         @header.delete('content-length')
       elsif @header['content-length'].nil?
         unless @body.is_a?(IO)
-          @header['content-length'] = @body ? @body.size : 0
+          @header['content-length'] = @body ? @body.bytesize : 0
         end
       end
 
@@ -260,10 +260,10 @@
           while buf = @body.read(@buffer_size)
             next if buf.empty?
             data = ""
-            data << format("%x", buf.size) << CRLF
+            data << format("%x", buf.bytesize) << CRLF
             data << buf << CRLF
             _write_data(socket, data)
-            @sent_size += buf.size
+            @sent_size += buf.bytesize
           end
           _write_data(socket, "0#{CRLF}#{CRLF}")
         else
@@ -280,20 +280,20 @@
       if @request_method == "HEAD"
         # do nothing
       elsif chunked?
-        remain = body ? @body.size : 0
+        remain = body ? @body.bytesize : 0
         while buf = @body[@sent_size, @buffer_size]
           break if buf.empty?
           data = ""
-          data << format("%x", buf.size) << CRLF
+          data << format("%x", buf.bytesize) << CRLF
           data << buf << CRLF
           _write_data(socket, data)
-          @sent_size += buf.size
+          @sent_size += buf.bytesize
         end
         _write_data(socket, "0#{CRLF}#{CRLF}")
       else
-        if @body && @body.size > 0
+        if @body && @body.bytesize > 0
           _write_data(socket, @body)
-          @sent_size = @body.size
+          @sent_size = @body.bytesize
         end
       end
     end
@@ -302,7 +302,7 @@
       while offset > 0
         sz = @buffer_size < size ? @buffer_size : size
         buf = input.read(sz)
-        offset -= buf.size
+        offset -= buf.bytesize
       end
 
       if size == 0
@@ -314,7 +314,7 @@
           sz = @buffer_size < size ? @buffer_size : size
           buf = input.read(sz)
           _write_data(output, buf)
-          size -= buf.size
+          size -= buf.bytesize
         end
       end
     end

Modified: MacRuby/branches/experimental/lib/webrick/httpservlet/abstract.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httpservlet/abstract.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httpservlet/abstract.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -59,7 +59,7 @@
       def redirect_to_directory_uri(req, res)
         if req.path[-1] != ?/
           location = WEBrick::HTTPUtils.escape_path(req.path + "/")
-          if req.query_string && req.query_string.size > 0
+          if req.query_string && req.query_string.bytesize > 0
             location << "?" << req.query_string
           end
           res.set_redirect(HTTPStatus::MovedPermanently, location)

Modified: MacRuby/branches/experimental/lib/webrick/httpservlet/cgi_runner.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httpservlet/cgi_runner.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httpservlet/cgi_runner.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -13,7 +13,7 @@
   while size > 0
     tmp = io.sysread(size)
     buf << tmp
-    size -= tmp.size
+    size -= tmp.bytesize
   end
   return buf
 end

Modified: MacRuby/branches/experimental/lib/webrick/httpservlet/cgihandler.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httpservlet/cgihandler.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httpservlet/cgihandler.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -48,14 +48,14 @@
           end
           dump = Marshal.dump(meta)
 
-          cgi_in.write("%8d" % cgi_out.path.size)
+          cgi_in.write("%8d" % cgi_out.path.bytesize)
           cgi_in.write(cgi_out.path)
-          cgi_in.write("%8d" % cgi_err.path.size)
+          cgi_in.write("%8d" % cgi_err.path.bytesize)
           cgi_in.write(cgi_err.path)
-          cgi_in.write("%8d" % dump.size)
+          cgi_in.write("%8d" % dump.bytesize)
           cgi_in.write(dump)
 
-          if req.body and req.body.size > 0
+          if req.body and req.body.bytesize > 0
             cgi_in.write(req.body)
           end
         ensure
@@ -65,7 +65,7 @@
           data = cgi_out.read
           cgi_out.close(true)
           if errmsg = cgi_err.read
-            if errmsg.size > 0
+            if errmsg.bytesize > 0
               @logger.error("CGIHandler: #{@script_filename}:\n" + errmsg)
             end
           end 

Modified: MacRuby/branches/experimental/lib/webrick/httpservlet/filehandler.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httpservlet/filehandler.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httpservlet/filehandler.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -407,13 +407,13 @@
         list.each{ |name, time, size|
           if name == ".."
             dname = "Parent Directory"
-          elsif name.size > 25
+          elsif name.bytesize > 25
             dname = name.sub(/^(.{23})(?:.*)/, '\1..')
           else
             dname = name
           end
           s =  " <A HREF=\"#{HTTPUtils::escape(name)}\">#{dname}</A>"
-          s << " " * (30 - dname.size)
+          s << " " * (30 - dname.bytesize)
           s << (time ? time.strftime("%Y/%m/%d %H:%M      ") : " " * 22)
           s << (size >= 0 ? size.to_s : "-") << "\n"
           res.body << s

Modified: MacRuby/branches/experimental/lib/webrick/httputils.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/httputils.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/httputils.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -23,16 +23,8 @@
       ret = path.dup
 
       ret.gsub!(%r{/+}o, '/')                    # //      => /
-      while ret.sub!(%r{/\.(/|\Z)}o, '/'); end   # /.      => /
-      begin                                      # /foo/.. => /foo
-        match = ret.sub!(%r{/([^/]+)/\.\.(/|\Z)}o){
-          if $1 == ".."
-            raise "abnormal path `#{path}'"
-          else
-            "/"
-          end
-        }
-      end while match
+      while ret.sub!(%r'/\.(?:/|\Z)', '/'); end  # /.      => /
+      while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo
 
       raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret
       ret
@@ -155,8 +147,8 @@
     module_function :parse_header
 
     def split_header_value(str)
-      str.scan(/((?:"(?:\\.|[^"])+?"|[^",]+)+)
-                (?:,\s*|\Z)/xn).collect{|v| v[0] }
+      str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
+                    (?:,\s*|\Z)'xn).flatten
     end
     module_function :split_header_value
 

Modified: MacRuby/branches/experimental/lib/webrick/server.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/server.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/server.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -130,9 +130,17 @@
           addr = s.addr
           @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
         end
-        s.shutdown
-        unless @config[:ShutdownSocketWithoutClose]
+        begin
+          s.shutdown
+        rescue Errno::ENOTCONN
+          # when `Errno::ENOTCONN: Socket is not connected' on some platforms,
+          # call #close instead of #shutdown.
+          # (ignore @config[:ShutdownSocketWithoutClose])
           s.close
+        else
+          unless @config[:ShutdownSocketWithoutClose]
+            s.close
+          end
         end
       }
       @listeners.clear

Modified: MacRuby/branches/experimental/lib/webrick/utils.rb
===================================================================
--- MacRuby/branches/experimental/lib/webrick/utils.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/webrick/utils.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -89,7 +89,7 @@
                  "abcdefghijklmnopqrstuvwxyz" 
 
     def random_string(len)
-      rand_max = RAND_CHARS.size
+      rand_max = RAND_CHARS.bytesize
       ret = "" 
       len.times{ ret << RAND_CHARS[rand(rand_max)] }
       ret 

Modified: MacRuby/branches/experimental/lib/xmlrpc/client.rb
===================================================================
--- MacRuby/branches/experimental/lib/xmlrpc/client.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/xmlrpc/client.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -268,7 +268,7 @@
 
 
 = History
-    $Id: client.rb 16042 2008-04-15 14:10:18Z kou $
+    $Id: client.rb 19657 2008-10-01 13:46:53Z mame $
 
 =end
 
@@ -567,6 +567,7 @@
 
       set_cookies = resp.get_fields("Set-Cookie")
       if set_cookies and !set_cookies.empty?
+        require 'webrick/cookie'
         @cookie = set_cookies.collect do |set_cookie|
           cookie = WEBrick::Cookie.parse_set_cookie(set_cookie)
           WEBrick::Cookie.new(cookie.name, cookie.value).to_s
@@ -604,16 +605,16 @@
     class Proxy
 
       def initialize(server, prefix, args=[], meth=:call, delim=".")
-	@server = server
-	@prefix = prefix ? prefix + delim : ""
-	@args   = args 
+        @server = server
+        @prefix = prefix ? prefix + delim : ""
+        @args   = args 
         @meth   = meth
       end
 
       def method_missing(mid, *args)
-	pre = @prefix + mid.to_s
-	arg = @args + args
-	@server.send(@meth, pre, *arg)
+        pre = @prefix + mid.to_s
+        arg = @args + args
+        @server.send(@meth, pre, *arg)
       end
 
     end # class Proxy

Modified: MacRuby/branches/experimental/lib/xmlrpc/create.rb
===================================================================
--- MacRuby/branches/experimental/lib/xmlrpc/create.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/xmlrpc/create.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,7 +3,7 @@
 # 
 # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
 #
-# $Id: create.rb 11816 2007-02-23 03:42:01Z knu $
+# $Id: create.rb 19657 2008-10-01 13:46:53Z mame $
 #
 
 require "date"
@@ -15,11 +15,11 @@
 
     class Abstract
       def ele(name, *children)
-	element(name, nil, *children)
+        element(name, nil, *children)
       end
 
       def tag(name, txt)
-	element(name, nil, text(txt))
+        element(name, nil, text(txt))
       end
     end
 
@@ -27,19 +27,19 @@
     class Simple < Abstract
 
       def document_to_str(doc)
-	doc
+        doc
       end
 
       def document(*params)
-	params.join("")
+        params.join("")
       end
 
       def pi(name, *params)
-	"<?#{name} " + params.join(" ") + " ?>"
+        "<?#{name} " + params.join(" ") + " ?>"
       end
 
       def element(name, attrs, *children)
-	raise "attributes not yet implemented" unless attrs.nil?
+        raise "attributes not yet implemented" unless attrs.nil?
         if children.empty?
           "<#{name}/>" 
         else
@@ -61,27 +61,27 @@
     class XMLParser < Abstract
 
       def initialize
-	require "xmltreebuilder"
+        require "xmltreebuilder"
       end
 
       def document_to_str(doc)
-	doc.to_s
+        doc.to_s
       end
 
       def document(*params)
-	XML::SimpleTree::Document.new(*params) 
+        XML::SimpleTree::Document.new(*params) 
       end
 
       def pi(name, *params)
-	XML::SimpleTree::ProcessingInstruction.new(name, *params)
+        XML::SimpleTree::ProcessingInstruction.new(name, *params)
       end
 
       def element(name, attrs, *children)
-	XML::SimpleTree::Element.new(name, attrs, *children)
+        XML::SimpleTree::Element.new(name, attrs, *children)
       end
 
       def text(txt)
-	XML::SimpleTree::Text.new(txt)
+        XML::SimpleTree::Text.new(txt)
       end
 
     end # class XMLParser
@@ -111,20 +111,20 @@
       name = name.to_s
 
       if name !~ /[a-zA-Z0-9_.:\/]+/
-	raise ArgumentError, "Wrong XML-RPC method-name"
+        raise ArgumentError, "Wrong XML-RPC method-name"
       end
 
       parameter = params.collect do |param|
-	@writer.ele("param", conv2value(param))
+        @writer.ele("param", conv2value(param))
       end
 
       tree = @writer.document(
-	       @writer.pi("xml", 'version="1.0"'),
-	       @writer.ele("methodCall",   
-		 @writer.tag("methodName", name),
-		 @writer.ele("params", *parameter)    
-	       )
-	     )
+               @writer.pi("xml", 'version="1.0"'),
+               @writer.ele("methodCall",   
+                 @writer.tag("methodName", name),
+                 @writer.ele("params", *parameter)    
+               )
+             )
 
       @writer.document_to_str(tree) + "\n"
     end
@@ -144,23 +144,23 @@
     def methodResponse(is_ret, *params)
 
       if is_ret 
-	resp = params.collect do |param|
-	  @writer.ele("param", conv2value(param))
-	end
+        resp = params.collect do |param|
+          @writer.ele("param", conv2value(param))
+        end
      
-	resp = [@writer.ele("params", *resp)]
+        resp = [@writer.ele("params", *resp)]
       else
-	if params.size != 1 or params[0] === XMLRPC::FaultException 
-	  raise ArgumentError, "no valid fault-structure given"
-	end
-	resp = @writer.ele("fault", conv2value(params[0].to_h))
+        if params.size != 1 or params[0] === XMLRPC::FaultException 
+          raise ArgumentError, "no valid fault-structure given"
+        end
+        resp = @writer.ele("fault", conv2value(params[0].to_h))
       end
 
-	
+        
       tree = @writer.document(
-	       @writer.pi("xml", 'version="1.0"'),
-	       @writer.ele("methodResponse", resp) 
-	     )
+               @writer.pi("xml", 'version="1.0"'),
+               @writer.ele("methodResponse", resp) 
+             )
 
       @writer.document_to_str(tree) + "\n"
     end
@@ -177,11 +177,11 @@
     #
     def conv2value(param)
 
-	val = case param
-	when Fixnum 
-	  @writer.tag("i4", param.to_s)
+        val = case param
+        when Fixnum 
+          @writer.tag("i4", param.to_s)
 
-	when Bignum
+        when Bignum
           if Config::ENABLE_BIGINT
             @writer.tag("i4", param.to_s)
           else
@@ -191,14 +191,14 @@
               raise "Bignum is too big! Must be signed 32-bit integer!"
             end
           end
-	when TrueClass, FalseClass
-	  @writer.tag("boolean", param ? "1" : "0")
+        when TrueClass, FalseClass
+          @writer.tag("boolean", param ? "1" : "0")
 
-	when Symbol 
-	  @writer.tag("string", param.to_s)
+        when Symbol 
+          @writer.tag("string", param.to_s)
 
-	when String 
-	  @writer.tag("string", param)
+        when String 
+          @writer.tag("string", param)
 
         when NilClass
           if Config::ENABLE_NIL_CREATE
@@ -207,51 +207,51 @@
             raise "Wrong type NilClass. Not allowed!"
           end
 
-	when Float
-	  @writer.tag("double", param.to_s)
+        when Float
+          @writer.tag("double", param.to_s)
 
-	when Struct
-	  h = param.members.collect do |key| 
-	    value = param[key]
-	    @writer.ele("member", 
-	      @writer.tag("name", key.to_s),
-	      conv2value(value) 
-	    )
-	  end
+        when Struct
+          h = param.members.collect do |key| 
+            value = param[key]
+            @writer.ele("member", 
+              @writer.tag("name", key.to_s),
+              conv2value(value) 
+            )
+          end
 
-	  @writer.ele("struct", *h) 
+          @writer.ele("struct", *h) 
 
-	when Hash
-	  # TODO: can a Hash be empty?
-	  
-	  h = param.collect do |key, value|
-	    @writer.ele("member", 
-	      @writer.tag("name", key.to_s),
-	      conv2value(value) 
-	    )
-	  end
+        when Hash
+          # TODO: can a Hash be empty?
+          
+          h = param.collect do |key, value|
+            @writer.ele("member", 
+              @writer.tag("name", key.to_s),
+              conv2value(value) 
+            )
+          end
 
-	  @writer.ele("struct", *h) 
+          @writer.ele("struct", *h) 
 
-	when Array
-	  # TODO: can an Array be empty?
-	  a = param.collect {|v| conv2value(v) }
-	  
-	  @writer.ele("array", 
-	    @writer.ele("data", *a)
-	  )
+        when Array
+          # TODO: can an Array be empty?
+          a = param.collect {|v| conv2value(v) }
+          
+          @writer.ele("array", 
+            @writer.ele("data", *a)
+          )
 
-	when Time, Date, ::DateTime
-	  @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S"))  
+        when Time, Date, ::DateTime
+          @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S"))  
 
-	when XMLRPC::DateTime
-	  @writer.tag("dateTime.iso8601", 
-	    format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a))
+        when XMLRPC::DateTime
+          @writer.tag("dateTime.iso8601", 
+            format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a))
    
-	when XMLRPC::Base64
-	  @writer.tag("base64", param.encoded) 
+        when XMLRPC::Base64
+          @writer.tag("base64", param.encoded) 
 
-	else 
+        else 
           if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable
             # convert Ruby object into Hash
             ret = {"___class___" => param.class.name}
@@ -274,9 +274,9 @@
               raise "Wrong type!"
             end
           end
-	end
-	 
-	@writer.ele("value", val)
+        end
+         
+        @writer.ele("value", val)
     end
 
     def wrong_type(value)

Modified: MacRuby/branches/experimental/lib/xmlrpc/httpserver.rb
===================================================================
--- MacRuby/branches/experimental/lib/xmlrpc/httpserver.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/xmlrpc/httpserver.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -4,7 +4,7 @@
 # 
 # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
 #
-# $Id: httpserver.rb 11708 2007-02-12 23:01:19Z shyouhei $
+# $Id: httpserver.rb 19657 2008-10-01 13:46:53Z mame $
 #
 
 
@@ -156,7 +156,7 @@
     # parse HTTP headers
     while (line=io.gets) !~ /^(\n|\r)/
       if line =~ /^([\w-]+):\s*(.*)$/
-	request.header[$1] = $2.strip
+        request.header[$1] = $2.strip
       end
     end
 

Modified: MacRuby/branches/experimental/lib/xmlrpc/parser.rb
===================================================================
--- MacRuby/branches/experimental/lib/xmlrpc/parser.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/xmlrpc/parser.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -3,7 +3,7 @@
 # 
 # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
 #
-# $Id: parser.rb 13770 2007-10-24 21:24:09Z jeg2 $
+# $Id: parser.rb 19657 2008-10-01 13:46:53Z mame $
 #
 
 
@@ -160,11 +160,11 @@
     class AbstractTreeParser
 
       def parseMethodResponse(str)
-	methodResponse_document(createCleanedTree(str))
+        methodResponse_document(createCleanedTree(str))
       end
 
       def parseMethodCall(str)
-	methodCall_document(createCleanedTree(str))
+        methodCall_document(createCleanedTree(str))
       end
 
       private
@@ -174,11 +174,11 @@
       # and all comments
       #
       def removeWhitespacesAndComments(node)
-	remove = []
-	childs = node.childNodes.to_a
-	childs.each do |nd|
-	  case _nodeType(nd)
-	  when :TEXT
+        remove = []
+        childs = node.childNodes.to_a
+        childs.each do |nd|
+          case _nodeType(nd)
+          when :TEXT
             # TODO: add nil?
             unless %w(i4 int boolean string double dateTime.iso8601 base64).include? node.nodeName
 
@@ -189,190 +189,190 @@
                else
                  remove << nd if nd.nodeValue.strip == ""
                end
-	    end
-	  when :COMMENT
-	    remove << nd
-	  else
-	    removeWhitespacesAndComments(nd)
-	  end 
-	end
+            end
+          when :COMMENT
+            remove << nd
+          else
+            removeWhitespacesAndComments(nd)
+          end 
+        end
 
-	remove.each { |i| node.removeChild(i) }
+        remove.each { |i| node.removeChild(i) }
       end
 
 
       def nodeMustBe(node, name)
-	cmp = case name
-	when Array 
-	  name.include?(node.nodeName)
-	when String
-	  name == node.nodeName
-	else
-	  raise "error"
-	end  
+        cmp = case name
+        when Array 
+          name.include?(node.nodeName)
+        when String
+          name == node.nodeName
+        else
+          raise "error"
+        end  
 
-	if not cmp then
-	  raise "wrong xml-rpc (name)"
-	end
+        if not cmp then
+          raise "wrong xml-rpc (name)"
+        end
 
-	node
+        node
       end
 
       #
       # returns, when successfully the only child-node
       #
       def hasOnlyOneChild(node, name=nil)
-	if node.childNodes.to_a.size != 1
-	  raise "wrong xml-rpc (size)"
-	end
-	if name != nil then
-	  nodeMustBe(node.firstChild, name)
-	end
+        if node.childNodes.to_a.size != 1
+          raise "wrong xml-rpc (size)"
+        end
+        if name != nil then
+          nodeMustBe(node.firstChild, name)
+        end
       end
 
 
       def assert(b)
-	if not b then
-	  raise "assert-fail" 
-	end
+        if not b then
+          raise "assert-fail" 
+        end
       end
 
       # the node `node` has empty string or string
       def text_zero_one(node)
-	nodes = node.childNodes.to_a.size
+        nodes = node.childNodes.to_a.size
 
-	if nodes == 1
-	  text(node.firstChild)
-	elsif nodes == 0
-	  ""
-	else
-	  raise "wrong xml-rpc (size)"
-	end
+        if nodes == 1
+          text(node.firstChild)
+        elsif nodes == 0
+          ""
+        else
+          raise "wrong xml-rpc (size)"
+        end
       end
      
 
       def integer(node)
-	#TODO: check string for float because to_i returnsa
-	#      0 when wrong string
-	 nodeMustBe(node, %w(i4 int))    
-	hasOnlyOneChild(node)
-	
-	Convert.int(text(node.firstChild))
+        #TODO: check string for float because to_i returnsa
+        #      0 when wrong string
+         nodeMustBe(node, %w(i4 int))    
+        hasOnlyOneChild(node)
+        
+        Convert.int(text(node.firstChild))
       end
 
       def boolean(node)
-	nodeMustBe(node, "boolean")    
-	hasOnlyOneChild(node)
-	
+        nodeMustBe(node, "boolean")    
+        hasOnlyOneChild(node)
+        
         Convert.boolean(text(node.firstChild))
       end
 
       def v_nil(node)
         nodeMustBe(node, "nil")
-	assert( node.childNodes.to_a.size == 0 )
+        assert( node.childNodes.to_a.size == 0 )
         nil
       end
 
       def string(node)
-	nodeMustBe(node, "string")    
-	text_zero_one(node)
+        nodeMustBe(node, "string")    
+        text_zero_one(node)
       end
 
       def double(node)
-	#TODO: check string for float because to_f returnsa
-	#      0.0 when wrong string
-	nodeMustBe(node, "double")    
-	hasOnlyOneChild(node)
-	
-	Convert.double(text(node.firstChild))
+        #TODO: check string for float because to_f returnsa
+        #      0.0 when wrong string
+        nodeMustBe(node, "double")    
+        hasOnlyOneChild(node)
+        
+        Convert.double(text(node.firstChild))
       end
 
       def dateTime(node)
-	nodeMustBe(node, "dateTime.iso8601")
-	hasOnlyOneChild(node)
-	
+        nodeMustBe(node, "dateTime.iso8601")
+        hasOnlyOneChild(node)
+        
         Convert.dateTime( text(node.firstChild) )
       end
 
       def base64(node)
-	nodeMustBe(node, "base64")
-	#hasOnlyOneChild(node)
-	 
+        nodeMustBe(node, "base64")
+        #hasOnlyOneChild(node)
+         
         Convert.base64(text_zero_one(node))
       end
 
       def member(node)
-	nodeMustBe(node, "member")
-	assert( node.childNodes.to_a.size == 2 ) 
+        nodeMustBe(node, "member")
+        assert( node.childNodes.to_a.size == 2 ) 
 
-	[ name(node[0]), value(node[1]) ]
+        [ name(node[0]), value(node[1]) ]
       end
 
       def name(node)
-	nodeMustBe(node, "name")
-	#hasOnlyOneChild(node)
-	text_zero_one(node) 
+        nodeMustBe(node, "name")
+        #hasOnlyOneChild(node)
+        text_zero_one(node) 
       end
 
       def array(node)
-	nodeMustBe(node, "array")
-	hasOnlyOneChild(node, "data") 
-	data(node.firstChild)  
+        nodeMustBe(node, "array")
+        hasOnlyOneChild(node, "data") 
+        data(node.firstChild)  
       end
 
       def data(node)
-	nodeMustBe(node, "data")
+        nodeMustBe(node, "data")
 
-	node.childNodes.to_a.collect do |val|
-	  value(val)
-	end 
+        node.childNodes.to_a.collect do |val|
+          value(val)
+        end 
       end
 
       def param(node)
-	nodeMustBe(node, "param")
-	hasOnlyOneChild(node, "value")
-	value(node.firstChild) 
+        nodeMustBe(node, "param")
+        hasOnlyOneChild(node, "value")
+        value(node.firstChild) 
       end
  
       def methodResponse(node)
-	nodeMustBe(node, "methodResponse")
-	hasOnlyOneChild(node, %w(params fault))
-	child = node.firstChild
+        nodeMustBe(node, "methodResponse")
+        hasOnlyOneChild(node, %w(params fault))
+        child = node.firstChild
 
-	case child.nodeName
-	when "params"
-	  [ true, params(child,false) ] 
-	when "fault"
-	  [ false, fault(child) ]
-	else
-	  raise "unexpected error"
-	end
+        case child.nodeName
+        when "params"
+          [ true, params(child,false) ] 
+        when "fault"
+          [ false, fault(child) ]
+        else
+          raise "unexpected error"
+        end
 
       end
 
       def methodName(node)
-	nodeMustBe(node, "methodName")
-	hasOnlyOneChild(node)
-	text(node.firstChild) 
+        nodeMustBe(node, "methodName")
+        hasOnlyOneChild(node)
+        text(node.firstChild) 
       end
 
       def params(node, call=true)
-	nodeMustBe(node, "params")
+        nodeMustBe(node, "params")
 
-	if call 
-	  node.childNodes.to_a.collect do |n|
-	    param(n)
-	  end
-	else # response (only one param)
-	  hasOnlyOneChild(node)
-	  param(node.firstChild)
-	end
+        if call 
+          node.childNodes.to_a.collect do |n|
+            param(n)
+          end
+        else # response (only one param)
+          hasOnlyOneChild(node)
+          param(node.firstChild)
+        end
       end
 
       def fault(node)
-	nodeMustBe(node, "fault")
-	hasOnlyOneChild(node, "value")
-	f = value(node.firstChild) 
+        nodeMustBe(node, "fault")
+        hasOnlyOneChild(node, "value")
+        f = value(node.firstChild) 
         Convert.fault(f)
       end
 
@@ -380,76 +380,76 @@
 
       # _nodeType is defined in the subclass
       def text(node)
-	assert( _nodeType(node) == :TEXT )
-	assert( node.hasChildNodes == false )
-	assert( node.nodeValue != nil )
+        assert( _nodeType(node) == :TEXT )
+        assert( node.hasChildNodes == false )
+        assert( node.nodeValue != nil )
 
-	node.nodeValue.to_s
+        node.nodeValue.to_s
       end
 
       def struct(node)
-	nodeMustBe(node, "struct")    
+        nodeMustBe(node, "struct")    
 
-	hash = {}
-	node.childNodes.to_a.each do |me|
-	  n, v = member(me)  
-	  hash[n] = v
-	end 
+        hash = {}
+        node.childNodes.to_a.each do |me|
+          n, v = member(me)  
+          hash[n] = v
+        end 
 
         Convert.struct(hash)
-     end
+      end
 
 
       def value(node)
-	nodeMustBe(node, "value")
-	nodes = node.childNodes.to_a.size
+        nodeMustBe(node, "value")
+        nodes = node.childNodes.to_a.size
         if nodes == 0 
           return ""
         elsif nodes > 1 
-	  raise "wrong xml-rpc (size)"
+          raise "wrong xml-rpc (size)"
         end
 
-	child = node.firstChild
+        child = node.firstChild
 
-	case _nodeType(child)
-	when :TEXT
+        case _nodeType(child)
+        when :TEXT
           text_zero_one(node)
-	when :ELEMENT
-	  case child.nodeName
-	  when "i4", "int"        then integer(child)
-	  when "boolean"          then boolean(child)
-	  when "string"           then string(child)
-	  when "double"           then double(child)
-	  when "dateTime.iso8601" then dateTime(child)
-	  when "base64"           then base64(child)
-	  when "struct"           then struct(child)
-	  when "array"            then array(child) 
+        when :ELEMENT
+          case child.nodeName
+          when "i4", "int"        then integer(child)
+          when "boolean"          then boolean(child)
+          when "string"           then string(child)
+          when "double"           then double(child)
+          when "dateTime.iso8601" then dateTime(child)
+          when "base64"           then base64(child)
+          when "struct"           then struct(child)
+          when "array"            then array(child) 
           when "nil"              
             if Config::ENABLE_NIL_PARSER
               v_nil(child)
             else
               raise "wrong/unknown XML-RPC type 'nil'"
             end
-	  else 
-	    raise "wrong/unknown XML-RPC type"
-	  end
-	else
-	  raise "wrong type of node"
-	end
+          else 
+            raise "wrong/unknown XML-RPC type"
+          end
+        else
+          raise "wrong type of node"
+        end
 
       end
 
       def methodCall(node)
-	nodeMustBe(node, "methodCall")
-	assert( (1..2).include?( node.childNodes.to_a.size ) ) 
-	name = methodName(node[0])
+        nodeMustBe(node, "methodCall")
+        assert( (1..2).include?( node.childNodes.to_a.size ) ) 
+        name = methodName(node[0])
 
-	if node.childNodes.to_a.size == 2 then
-	  pa = params(node[1])
-	else # no parameters given
-	  pa = []
-	end
-	[name, pa]
+        if node.childNodes.to_a.size == 2 then
+          pa = params(node[1])
+        else # no parameters given
+          pa = []
+        end
+        [name, pa]
       end
 
     end # module TreeParserMixin
@@ -635,34 +635,34 @@
       private
 
       def _nodeType(node)
-	tp = node.nodeType
-	if tp == XML::SimpleTree::Node::TEXT then :TEXT
-	elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT 
-	elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT 
-	else :ELSE
-	end
+        tp = node.nodeType
+        if tp == XML::SimpleTree::Node::TEXT then :TEXT
+        elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT 
+        elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT 
+        else :ELSE
+        end
       end
 
 
       def methodResponse_document(node)
-	assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT )
-	hasOnlyOneChild(node, "methodResponse")
-	
-	methodResponse(node.firstChild)
+        assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT )
+        hasOnlyOneChild(node, "methodResponse")
+        
+        methodResponse(node.firstChild)
       end
 
       def methodCall_document(node)
-	assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT )
-	hasOnlyOneChild(node, "methodCall")
-	
-	methodCall(node.firstChild)
+        assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT )
+        hasOnlyOneChild(node, "methodCall")
+        
+        methodCall(node.firstChild)
       end
 
       def createCleanedTree(str)
-	doc = XML::SimpleTreeBuilder.new.parse(str)
-	doc.documentElement.normalize
-	removeWhitespacesAndComments(doc)
-	doc
+        doc = XML::SimpleTreeBuilder.new.parse(str)
+        doc.documentElement.normalize
+        removeWhitespacesAndComments(doc)
+        doc
       end
 
     end # class XMLParser
@@ -676,21 +676,21 @@
       private
 
       def _nodeType(node)
-	node.nodeType
+        node.nodeType
       end
 
       def methodResponse_document(node)
-	methodResponse(node)
+        methodResponse(node)
       end
 
       def methodCall_document(node)
-	methodCall(node)
+        methodCall(node)
       end
 
       def createCleanedTree(str)
         doc = ::NQXML::TreeParser.new(str).document.rootNode 
-	removeWhitespacesAndComments(doc)
-	doc
+        removeWhitespacesAndComments(doc)
+        doc
       end
 
     end # class NQXMLTreeParser
@@ -715,7 +715,7 @@
 
         def parse(str)
           parser = REXML::Document.parse_stream(str, self)
-       end
+        end
       end 
 
     end

Modified: MacRuby/branches/experimental/lib/xmlrpc/server.rb
===================================================================
--- MacRuby/branches/experimental/lib/xmlrpc/server.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/xmlrpc/server.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -267,7 +267,9 @@
         if obj.kind_of? Proc
           methods << name
         else
-          obj.methods.each {|meth| methods << name + meth}
+          obj.class.public_instance_methods(false).each do |meth|
+            methods << "#{name}#{meth}"
+          end
         end
       end
       methods
@@ -775,6 +777,6 @@
 
 =begin
 = History
-    $Id: server.rb 14070 2007-12-01 16:01:49Z jeg2 $    
+    $Id: server.rb 20879 2008-12-19 11:37:33Z yugui $    
 =end
 

Modified: MacRuby/branches/experimental/lib/xmlrpc/utils.rb
===================================================================
--- MacRuby/branches/experimental/lib/xmlrpc/utils.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/xmlrpc/utils.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -6,7 +6,7 @@
 # 
 # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann at ntecs.de)
 #
-# $Id: utils.rb 13767 2007-10-24 18:46:08Z jeg2 $ 
+# $Id: utils.rb 19657 2008-10-01 13:46:53Z mame $ 
 #
 
 module XMLRPC
@@ -37,7 +37,7 @@
     def create
       # if set_writer was not already called then call it now
       if @create.nil? then
-	set_writer(Config::DEFAULT_WRITER.new)
+        set_writer(Config::DEFAULT_WRITER.new)
       end
       @create
     end
@@ -45,7 +45,7 @@
     def parser
       # if set_parser was not already called then call it now
       if @parser.nil? then
-	set_parser(Config::DEFAULT_PARSER.new)
+        set_parser(Config::DEFAULT_PARSER.new)
       end
       @parser
     end

Modified: MacRuby/branches/experimental/lib/yaml/baseemitter.rb
===================================================================
--- MacRuby/branches/experimental/lib/yaml/baseemitter.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/yaml/baseemitter.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -7,241 +7,236 @@
 require 'yaml/error'
 
 module YAML
+  module BaseEmitter
+    def options( opt = nil )
+      if opt
+        @options[opt] || YAML::DEFAULTS[opt]
+      else
+        @options
+      end
+    end
 
-    module BaseEmitter
+    def options=( opt )
+      @options = opt
+    end
 
-        def options( opt = nil )
-            if opt
-                @options[opt] || YAML::DEFAULTS[opt]
-            else
-                @options
-            end
-        end
+    #
+    # Emit binary data
+    #
+    def binary_base64( value )
+      self << "!binary "
+      self.node_text( [value].pack("m"), '|' )
+    end
 
-        def options=( opt )
-            @options = opt
+    #
+    # Emit plain, normal flowing text
+    #
+    def node_text( value, block = nil )
+      @seq_map = false
+      valx = value.dup
+      unless block
+        block =
+          if options(:UseBlock)
+            '|'
+          elsif not options(:UseFold) and valx =~ /\n[ \t]/ and not valx =~ /#{YAML::ESCAPE_CHAR}/
+            '|'
+          else
+            '>'
+          end 
+        indt = $&.to_i if block =~ /\d+/
+        if valx =~ /(\A\n*[ \t#]|^---\s+)/
+          indt = options(:Indent) unless indt.to_i > 0
+          block += indt.to_s
         end
 
-        #
-        # Emit binary data
-        #
-        def binary_base64( value )
-            self << "!binary "
-            self.node_text( [value].pack("m"), '|' )
+        block +=
+          if valx =~ /\n\Z\n/
+            "+"
+          elsif valx =~ /\Z\n/
+            ""
+          else
+            "-"
+          end
+      end
+      block += "\n"
+      if block[0] == ?"
+        esc_skip = ( "\t\n" unless valx =~ /^[ \t]/ ) || ""
+        valx = fold( YAML::escape( valx, esc_skip ) + "\"" ).chomp
+        self << '"' + indent_text( valx, indt, false )
+      else
+        if block[0] == ?> 
+          valx = fold( valx ) 
         end
+        #p [block, indt]
+        self << block + indent_text( valx, indt )
+      end
+    end
 
-		#
-		# Emit plain, normal flowing text
-		#
-		def node_text( value, block = nil )
-            @seq_map = false
-			valx = value.dup
-            unless block
-            block =
-                if options(:UseBlock)
-                    '|'
-                elsif not options(:UseFold) and valx =~ /\n[ \t]/ and not valx =~ /#{YAML::ESCAPE_CHAR}/
-                    '|'
-                else
-                    '>'
-                end 
+    #
+    # Emit a simple, unqouted string
+    #
+    def simple( value )
+      @seq_map = false
+      self << value.to_s
+    end
 
-                indt = $&.to_i if block =~ /\d+/
-                if valx =~ /(\A\n*[ \t#]|^---\s+)/
-                    indt = options(:Indent) unless indt.to_i > 0
-                    block += indt.to_s
-                end
+    #
+    # Emit double-quoted string
+    #
+    def double( value )
+      "\"#{YAML.escape( value )}\"" 
+    end
 
-            block +=
-                if valx =~ /\n\Z\n/
-                    "+"
-                elsif valx =~ /\Z\n/
-                    ""
-                else
-                    "-"
-                end
-            end
-            block += "\n"
-            if block[0] == ?"
-                esc_skip = ( "\t\n" unless valx =~ /^[ \t]/ ) || ""
-                valx = fold( YAML::escape( valx, esc_skip ) + "\"" ).chomp
-                self << '"' + indent_text( valx, indt, false )
-            else
-                if block[0] == ?> 
-                    valx = fold( valx ) 
-                end
-                #p [block, indt]
-                self << block + indent_text( valx, indt )
-            end
-		end
+    #
+    # Emit single-quoted string
+    #
+    def single( value )
+      "'#{value}'"
+    end
 
-		#
-		# Emit a simple, unqouted string
-		#
-		def simple( value )
-            @seq_map = false
-            self << value.to_s
-		end
+    #
+    # Write a text block with the current indent
+    #
+    def indent_text( text, mod, first_line = true )
+      return "" if text.to_s.empty?
+      spacing = indent( mod )
+      text = text.gsub( /\A([^\n])/, "#{ spacing }\\1" ) if first_line
+      return text.gsub( /\n^([^\n])/, "\n#{spacing}\\1" )
+    end
 
-		#
-		# Emit double-quoted string
-		#
-		def double( value )
-			"\"#{YAML.escape( value )}\"" 
-		end
+    #
+    # Write a current indent
+    #
+    def indent( mod = nil )
+      #p [ self.id, level, mod, :INDENT ]
+      if level <= 0
+        mod ||= 0
+      else
+        mod ||= options(:Indent)
+        mod += ( level - 1 ) * options(:Indent)
+      end
+      return " " * mod
+    end
 
-		#
-		# Emit single-quoted string
-		#
-		def single( value )
-			"'#{value}'"
-		end
+    #
+    # Add indent to the buffer
+    #
+    def indent!
+      self << indent
+    end
 
-		#
-		# Write a text block with the current indent
-		#
-		def indent_text( text, mod, first_line = true )
-			return "" if text.to_s.empty?
-            spacing = indent( mod )
-            text = text.gsub( /\A([^\n])/, "#{ spacing }\\1" ) if first_line
-			return text.gsub( /\n^([^\n])/, "\n#{spacing}\\1" )
-		end
+    #
+    # Folding paragraphs within a column
+    #
+    def fold( value )
+      value.gsub( /(^[ \t]+.*$)|(\S.{0,#{options(:BestWidth) - 1}})(?:[ \t]+|(\n+(?=[ \t]|\Z))|$)/ ) do
+        $1 || $2 + ( $3 || "\n" )
+      end
+    end
 
-		#
-		# Write a current indent
-		#
-        def indent( mod = nil )
-            #p [ self.id, level, mod, :INDENT ]
-            if level <= 0
-                mod ||= 0
-            else
-                mod ||= options(:Indent)
-                mod += ( level - 1 ) * options(:Indent)
-            end
-            return " " * mod
-		end
+    #
+    # Quick mapping
+    #
+    def map( type, &e )
+      val = Mapping.new
+      e.call( val )
+      self << "#{type} " if type.length.nonzero?
 
-		#
-		# Add indent to the buffer
-		#
-		def indent!
-			self << indent
-		end
+      #
+      # Empty hashes
+      #
+      if val.length.zero?
+        self << "{}"
+        @seq_map = false
+      else
+        # FIXME
+        # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? 
+        #     @headless = 1 
+        # end
 
-		#
-		# Folding paragraphs within a column
-		#
-		def fold( value )
-            value.gsub( /(^[ \t]+.*$)|(\S.{0,#{options(:BestWidth) - 1}})(?:[ \t]+|(\n+(?=[ \t]|\Z))|$)/ ) do
-                $1 || $2 + ( $3 || "\n" )
-            end
-		end
+        defkey = @options.delete( :DefaultKey )
+        if defkey
+          seq_map_shortcut
+          self << "= : "
+          defkey.to_yaml( :Emitter => self )
+        end
 
         #
-        # Quick mapping
+        # Emit the key and value
         #
-        def map( type, &e )
-            val = Mapping.new
-            e.call( val )
-			self << "#{type} " if type.length.nonzero?
+        val.each { |v|
+          seq_map_shortcut
+          if v[0].is_complex_yaml?
+            self << "? "
+          end
+          v[0].to_yaml( :Emitter => self )
+          if v[0].is_complex_yaml?
+            self << "\n"
+            indent!
+          end
+          self << ": " 
+          v[1].to_yaml( :Emitter => self )
+        }
+      end
+    end
 
-			#
-			# Empty hashes
-			#
-			if val.length.zero?
-				self << "{}"
-                @seq_map = false
-			else
-                # FIXME
-                # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? 
-			    #     @headless = 1 
-                # end
+    def seq_map_shortcut
+      # FIXME: seq_map needs to work with the new anchoring system
+      # if @seq_map
+      #     @anchor_extras[@buffer.length - 1] = "\n" + indent
+      #     @seq_map = false
+      # else
+      self << "\n"
+      indent! 
+      # end
+    end
 
-                defkey = @options.delete( :DefaultKey )
-                if defkey
-                    seq_map_shortcut
-                    self << "= : "
-                    defkey.to_yaml( :Emitter => self )
-                end
+    #
+    # Quick sequence
+    #
+    def seq( type, &e )
+      @seq_map = false
+      val = Sequence.new
+      e.call( val )
+      self << "#{type} " if type.length.nonzero?
 
-				#
-				# Emit the key and value
-				#
-                val.each { |v|
-                    seq_map_shortcut
-                    if v[0].is_complex_yaml?
-                        self << "? "
-                    end
-                    v[0].to_yaml( :Emitter => self )
-                    if v[0].is_complex_yaml?
-                        self << "\n"
-                        indent!
-                    end
-                    self << ": " 
-                    v[1].to_yaml( :Emitter => self )
-                }
-			end
-        end
+      #
+      # Empty arrays
+      #
+      if val.length.zero?
+        self << "[]"
+      else
+        # FIXME
+        # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? 
+        #     @headless = 1 
+        # end
 
-        def seq_map_shortcut
-            # FIXME: seq_map needs to work with the new anchoring system
-            # if @seq_map
-            #     @anchor_extras[@buffer.length - 1] = "\n" + indent
-            #     @seq_map = false
-            # else
-                self << "\n"
-                indent! 
-            # end
-        end
-
         #
-        # Quick sequence
+        # Emit the key and value
         #
-        def seq( type, &e )
-            @seq_map = false
-            val = Sequence.new
-            e.call( val )
-			self << "#{type} " if type.length.nonzero?
-
-			#
-			# Empty arrays
-			#
-			if val.length.zero?
-				self << "[]"
-			else
-                # FIXME
-                # if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero? 
-			    #     @headless = 1 
-                # end
-
-				#
-				# Emit the key and value
-				#
-                val.each { |v|
-                    self << "\n"
-                    indent!
-                    self << "- "
-                    @seq_map = true if v.class == Hash
-                    v.to_yaml( :Emitter => self )
-                }
-			end
-        end
-
+        val.each { |v|
+          self << "\n"
+          indent!
+          self << "- "
+          @seq_map = true if v.class == Hash
+          v.to_yaml( :Emitter => self )
+        }
+      end
     end
+  end
 
-    #
-    # Emitter helper classes
-    #
-    class Mapping < Array
-        def add( k, v )
-            push [k, v]
-        end
+  #
+  # Emitter helper classes
+  #
+  class Mapping < Array
+    def add( k, v )
+      push [k, v]
     end
+  end
 
-    class Sequence < Array
-        def add( v )
-            push v
-        end
+  class Sequence < Array
+    def add( v )
+      push v
     end
-
+  end
 end

Modified: MacRuby/branches/experimental/lib/yaml/rubytypes.rb
===================================================================
--- MacRuby/branches/experimental/lib/yaml/rubytypes.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/yaml/rubytypes.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -379,6 +379,44 @@
 	end
 end
 
+class Rational
+	yaml_as "tag:ruby.yaml.org,2002:object:Rational"
+	def Rational.yaml_new( klass, tag, val )
+		if val.is_a? String
+			Rational( val )
+		else
+			Rational( val['numerator'], val['denominator'] )
+		end
+	end
+	def to_yaml( opts = {} ) 
+		YAML::quick_emit( self, opts ) do |out|
+			out.map( taguri, nil ) do |map| 
+				map.add( 'denominator', denominator )
+				map.add( 'numerator', numerator )
+			end
+		end
+	end
+end
+
+class Complex
+	yaml_as "tag:ruby.yaml.org,2002:object:Complex"
+	def Complex.yaml_new( klass, tag, val )
+		if val.is_a? String
+			Complex( val )
+		else
+			Complex( val['real'], val['image'] )
+		end
+	end
+	def to_yaml( opts = {} )
+		YAML::quick_emit( self, opts ) do |out|
+			out.map( taguri, nil ) do |map|
+				map.add( 'image', imaginary )
+				map.add( 'real', real )
+			end
+		end
+	end
+end
+
 class TrueClass
     yaml_as "tag:yaml.org,2002:bool#yes"
 	def to_yaml( opts = {} )

Modified: MacRuby/branches/experimental/lib/yaml/yamlnode.rb
===================================================================
--- MacRuby/branches/experimental/lib/yaml/yamlnode.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/yaml/yamlnode.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -11,13 +11,13 @@
     class YamlNode
         include BaseNode
         attr_accessor :kind, :type_id, :value, :anchor
-        def initialize( t, v )
+        def initialize(t, v)
             @type_id = t
             if Hash === v
                 @kind = 'map'
                 @value = {}
-                v.each { |k,v|
-                    @value[ k.transform ] = [ k, v ]
+                v.each {|key,val|
+                    @value[key.transform] = [key, val]
                 }
             elsif Array === v
                 @kind = 'seq'

Modified: MacRuby/branches/experimental/lib/yaml.rb
===================================================================
--- MacRuby/branches/experimental/lib/yaml.rb	2009-06-19 22:27:12 UTC (rev 1888)
+++ MacRuby/branches/experimental/lib/yaml.rb	2009-06-19 22:42:24 UTC (rev 1889)
@@ -1,5 +1,5 @@
 # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4
-# $Id: yaml.rb 13940 2007-11-15 17:54:32Z why $
+# $Id: yaml.rb 19495 2008-09-23 18:16:08Z drbrain $
 #
 # = yaml.rb: top-level module with methods for loading and parsing YAML documents
 #
@@ -213,7 +213,7 @@
     #     end
     #   end
 	#
-	def YAML.each_document( io, &block )
+    def YAML.each_document( io, &block )
 		yp = parser.load_documents( io, &block )
     end
 
@@ -228,7 +228,7 @@
     #     end
     #   end
 	#
-	def YAML.load_documents( io, &doc_proc )
+    def YAML.load_documents( io, &doc_proc )
 		YAML.each_document( io, &doc_proc )
     end
 
@@ -243,7 +243,7 @@
     #     end
     #   end
 	#
-	def YAML.each_node( io, &doc_proc )
+    def YAML.each_node( io, &doc_proc )
 		yp = generic_parser.load_documents( io, &doc_proc )
     end
 
@@ -258,7 +258,7 @@
     #     end
     #   end
 	#
-	def YAML.parse_documents( io, &doc_proc )
+    def YAML.parse_documents( io, &doc_proc )
 		YAML.each_node( io, &doc_proc )
     end
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090619/307ae424/attachment-0001.html>


More information about the macruby-changes mailing list