[macruby-changes] [199] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sun May 18 01:10:25 PDT 2008


Revision: 199
          http://trac.macosforge.org/projects/ruby/changeset/199
Author:   lsansonetti at apple.com
Date:     2008-05-18 01:10:19 -0700 (Sun, 18 May 2008)

Log Message:
-----------
sync with ruby trunk r15665

Modified Paths:
--------------
    MacRuby/trunk/ChangeLog
    MacRuby/trunk/Makefile.in
    MacRuby/trunk/array.c
    MacRuby/trunk/benchmark/bm_so_sieve.rb
    MacRuby/trunk/benchmark/bm_vm2_eval.rb
    MacRuby/trunk/bignum.c
    MacRuby/trunk/bootstraptest/runner.rb
    MacRuby/trunk/bootstraptest/test_knownbug.rb
    MacRuby/trunk/bootstraptest/test_thread.rb
    MacRuby/trunk/class.c
    MacRuby/trunk/common.mk
    MacRuby/trunk/compar.c
    MacRuby/trunk/compile.c
    MacRuby/trunk/compile.h
    MacRuby/trunk/configure.in
    MacRuby/trunk/cont.c
    MacRuby/trunk/debug.c
    MacRuby/trunk/debug.h
    MacRuby/trunk/dir.c
    MacRuby/trunk/dln.c
    MacRuby/trunk/dln.h
    MacRuby/trunk/dmyencoding.c
    MacRuby/trunk/dmytranscode.c
    MacRuby/trunk/doc/NEWS
    MacRuby/trunk/enc/depend
    MacRuby/trunk/enc/make_encdb.rb
    MacRuby/trunk/enc/make_encmake.rb
    MacRuby/trunk/enc/trans/make_transdb.rb
    MacRuby/trunk/enc/trans/utf_16_32.c
    MacRuby/trunk/encoding.c
    MacRuby/trunk/enum.c
    MacRuby/trunk/enumerator.c
    MacRuby/trunk/error.c
    MacRuby/trunk/eval.c
    MacRuby/trunk/eval_intern.h
    MacRuby/trunk/eval_jump.c
    MacRuby/trunk/eval_method.c
    MacRuby/trunk/ext/dbm/dbm.c
    MacRuby/trunk/ext/digest/defs.h
    MacRuby/trunk/ext/dl/win32/lib/win32/registry.rb
    MacRuby/trunk/ext/dl/win32/lib/win32/resolv.rb
    MacRuby/trunk/ext/extmk.rb
    MacRuby/trunk/ext/gdbm/gdbm.c
    MacRuby/trunk/ext/nkf/nkf-utf8/nkf.c
    MacRuby/trunk/ext/nkf/nkf.c
    MacRuby/trunk/ext/openssl/lib/openssl/digest.rb
    MacRuby/trunk/ext/openssl/openssl_missing.c
    MacRuby/trunk/ext/openssl/openssl_missing.h
    MacRuby/trunk/ext/openssl/ossl_asn1.c
    MacRuby/trunk/ext/openssl/ossl_config.c
    MacRuby/trunk/ext/openssl/ossl_digest.c
    MacRuby/trunk/ext/openssl/ossl_hmac.c
    MacRuby/trunk/ext/openssl/ossl_pkey_dh.c
    MacRuby/trunk/ext/openssl/ossl_pkey_dsa.c
    MacRuby/trunk/ext/openssl/ossl_pkey_ec.c
    MacRuby/trunk/ext/openssl/ossl_pkey_rsa.c
    MacRuby/trunk/ext/openssl/ossl_ssl.c
    MacRuby/trunk/ext/openssl/ossl_ssl_session.c
    MacRuby/trunk/ext/openssl/ossl_version.h
    MacRuby/trunk/ext/openssl/ossl_x509ext.c
    MacRuby/trunk/ext/purelib.rb
    MacRuby/trunk/ext/readline/extconf.rb
    MacRuby/trunk/ext/readline/readline.c
    MacRuby/trunk/ext/sdbm/init.c
    MacRuby/trunk/ext/stringio/stringio.c
    MacRuby/trunk/ext/strscan/strscan.c
    MacRuby/trunk/ext/syck/rubyext.c
    MacRuby/trunk/ext/syck/syck.h
    MacRuby/trunk/ext/syslog/syslog.txt
    MacRuby/trunk/ext/tk/extconf.rb
    MacRuby/trunk/ext/tk/lib/multi-tk.rb
    MacRuby/trunk/ext/tk/lib/tk/autoload.rb
    MacRuby/trunk/ext/tk/stubs.c
    MacRuby/trunk/ext/tk/tcltklib.c
    MacRuby/trunk/ext/tk/tkutil/tkutil.c
    MacRuby/trunk/ext/win32ole/win32ole.c
    MacRuby/trunk/ext/zlib/zlib.c
    MacRuby/trunk/file.c
    MacRuby/trunk/gc.c
    MacRuby/trunk/gem_prelude.rb
    MacRuby/trunk/golf_prelude.rb
    MacRuby/trunk/hash.c
    MacRuby/trunk/include/ruby/defines.h
    MacRuby/trunk/include/ruby/encoding.h
    MacRuby/trunk/include/ruby/intern.h
    MacRuby/trunk/include/ruby/missing.h
    MacRuby/trunk/include/ruby/node.h
    MacRuby/trunk/include/ruby/ruby.h
    MacRuby/trunk/include/ruby/win32.h
    MacRuby/trunk/inits.c
    MacRuby/trunk/insns.def
    MacRuby/trunk/instruby.rb
    MacRuby/trunk/io.c
    MacRuby/trunk/iseq.c
    MacRuby/trunk/lib/cgi.rb
    MacRuby/trunk/lib/complex.rb
    MacRuby/trunk/lib/csv.rb
    MacRuby/trunk/lib/date.rb
    MacRuby/trunk/lib/debug.rb
    MacRuby/trunk/lib/drb/drb.rb
    MacRuby/trunk/lib/erb.rb
    MacRuby/trunk/lib/getoptlong.rb
    MacRuby/trunk/lib/ipaddr.rb
    MacRuby/trunk/lib/irb/cmd/help.rb
    MacRuby/trunk/lib/irb/workspace.rb
    MacRuby/trunk/lib/irb.rb
    MacRuby/trunk/lib/mathn.rb
    MacRuby/trunk/lib/mkmf.rb
    MacRuby/trunk/lib/net/http.rb
    MacRuby/trunk/lib/net/pop.rb
    MacRuby/trunk/lib/net/smtp.rb
    MacRuby/trunk/lib/net/telnet.rb
    MacRuby/trunk/lib/open3.rb
    MacRuby/trunk/lib/pstore.rb
    MacRuby/trunk/lib/rational.rb
    MacRuby/trunk/lib/rdoc/code_objects.rb
    MacRuby/trunk/lib/rdoc/generator/html.rb
    MacRuby/trunk/lib/rdoc/generator.rb
    MacRuby/trunk/lib/rdoc/markup/inline.rb
    MacRuby/trunk/lib/rdoc/markup/to_html.rb
    MacRuby/trunk/lib/rdoc/markup.rb
    MacRuby/trunk/lib/rdoc/options.rb
    MacRuby/trunk/lib/rdoc/parsers/parse_rb.rb
    MacRuby/trunk/lib/rdoc/rdoc.rb
    MacRuby/trunk/lib/rdoc/ri/descriptions.rb
    MacRuby/trunk/lib/rdoc/ri/display.rb
    MacRuby/trunk/lib/rdoc/ri/driver.rb
    MacRuby/trunk/lib/rdoc/ri/formatter.rb
    MacRuby/trunk/lib/rdoc/ri/util.rb
    MacRuby/trunk/lib/rdoc/ri/writer.rb
    MacRuby/trunk/lib/rdoc/template.rb
    MacRuby/trunk/lib/rdoc.rb
    MacRuby/trunk/lib/resolv.rb
    MacRuby/trunk/lib/rexml/document.rb
    MacRuby/trunk/lib/rubygems/builder.rb
    MacRuby/trunk/lib/rubygems/command_manager.rb
    MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb
    MacRuby/trunk/lib/rubygems/commands/environment_command.rb
    MacRuby/trunk/lib/rubygems/commands/fetch_command.rb
    MacRuby/trunk/lib/rubygems/commands/install_command.rb
    MacRuby/trunk/lib/rubygems/commands/list_command.rb
    MacRuby/trunk/lib/rubygems/commands/mirror_command.rb
    MacRuby/trunk/lib/rubygems/commands/pristine_command.rb
    MacRuby/trunk/lib/rubygems/commands/query_command.rb
    MacRuby/trunk/lib/rubygems/commands/sources_command.rb
    MacRuby/trunk/lib/rubygems/commands/specification_command.rb
    MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb
    MacRuby/trunk/lib/rubygems/commands/unpack_command.rb
    MacRuby/trunk/lib/rubygems/commands/update_command.rb
    MacRuby/trunk/lib/rubygems/custom_require.rb
    MacRuby/trunk/lib/rubygems/defaults.rb
    MacRuby/trunk/lib/rubygems/dependency_installer.rb
    MacRuby/trunk/lib/rubygems/doc_manager.rb
    MacRuby/trunk/lib/rubygems/exceptions.rb
    MacRuby/trunk/lib/rubygems/format.rb
    MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb
    MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb
    MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb
    MacRuby/trunk/lib/rubygems/indexer.rb
    MacRuby/trunk/lib/rubygems/install_update_options.rb
    MacRuby/trunk/lib/rubygems/installer.rb
    MacRuby/trunk/lib/rubygems/package.rb
    MacRuby/trunk/lib/rubygems/remote_fetcher.rb
    MacRuby/trunk/lib/rubygems/requirement.rb
    MacRuby/trunk/lib/rubygems/rubygems_version.rb
    MacRuby/trunk/lib/rubygems/security.rb
    MacRuby/trunk/lib/rubygems/server.rb
    MacRuby/trunk/lib/rubygems/source_index.rb
    MacRuby/trunk/lib/rubygems/source_info_cache.rb
    MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb
    MacRuby/trunk/lib/rubygems/specification.rb
    MacRuby/trunk/lib/rubygems/uninstaller.rb
    MacRuby/trunk/lib/rubygems/user_interaction.rb
    MacRuby/trunk/lib/rubygems/version_option.rb
    MacRuby/trunk/lib/rubygems.rb
    MacRuby/trunk/lib/set.rb
    MacRuby/trunk/lib/shellwords.rb
    MacRuby/trunk/lib/webrick/httprequest.rb
    MacRuby/trunk/lib/webrick/httpservlet/filehandler.rb
    MacRuby/trunk/lib/xmlrpc/client.rb
    MacRuby/trunk/lib/yaml/store.rb
    MacRuby/trunk/load.c
    MacRuby/trunk/marshal.c
    MacRuby/trunk/math.c
    MacRuby/trunk/misc/README
    MacRuby/trunk/misc/ruby-mode.el
    MacRuby/trunk/misc/ruby-style.el
    MacRuby/trunk/missing/lgamma_r.c
    MacRuby/trunk/missing/tgamma.c
    MacRuby/trunk/missing/vsnprintf.c
    MacRuby/trunk/numeric.c
    MacRuby/trunk/object.c
    MacRuby/trunk/pack.c
    MacRuby/trunk/parse.y
    MacRuby/trunk/prelude.rb
    MacRuby/trunk/proc.c
    MacRuby/trunk/process.c
    MacRuby/trunk/random.c
    MacRuby/trunk/range.c
    MacRuby/trunk/re.c
    MacRuby/trunk/regexec.c
    MacRuby/trunk/regint.h
    MacRuby/trunk/regparse.c
    MacRuby/trunk/ruby.1
    MacRuby/trunk/ruby.c
    MacRuby/trunk/sample/test.rb
    MacRuby/trunk/signal.c
    MacRuby/trunk/sprintf.c
    MacRuby/trunk/st.c
    MacRuby/trunk/string.c
    MacRuby/trunk/struct.c
    MacRuby/trunk/template/insns.inc.tmpl
    MacRuby/trunk/template/insns_info.inc.tmpl
    MacRuby/trunk/template/opt_sc.inc.tmpl
    MacRuby/trunk/template/optunifs.inc.tmpl
    MacRuby/trunk/test/erb/test_erb.rb
    MacRuby/trunk/test/gdbm/test_gdbm.rb
    MacRuby/trunk/test/io/nonblock/test_flush.rb
    MacRuby/trunk/test/net/imap/test_imap.rb
    MacRuby/trunk/test/openssl/test_ssl.rb
    MacRuby/trunk/test/openssl/utils.rb
    MacRuby/trunk/test/rdoc/test_rdoc_c_parser.rb
    MacRuby/trunk/test/rdoc/test_rdoc_markup_attribute_manager.rb
    MacRuby/trunk/test/rdoc/test_rdoc_ri_formatter.rb
    MacRuby/trunk/test/ruby/envutil.rb
    MacRuby/trunk/test/ruby/marshaltestlib.rb
    MacRuby/trunk/test/ruby/test_array.rb
    MacRuby/trunk/test/ruby/test_assignment.rb
    MacRuby/trunk/test/ruby/test_beginendblock.rb
    MacRuby/trunk/test/ruby/test_bignum.rb
    MacRuby/trunk/test/ruby/test_class.rb
    MacRuby/trunk/test/ruby/test_continuation.rb
    MacRuby/trunk/test/ruby/test_enum.rb
    MacRuby/trunk/test/ruby/test_enumerator.rb
    MacRuby/trunk/test/ruby/test_env.rb
    MacRuby/trunk/test/ruby/test_eval.rb
    MacRuby/trunk/test/ruby/test_exception.rb
    MacRuby/trunk/test/ruby/test_file.rb
    MacRuby/trunk/test/ruby/test_file_exhaustive.rb
    MacRuby/trunk/test/ruby/test_fixnum.rb
    MacRuby/trunk/test/ruby/test_float.rb
    MacRuby/trunk/test/ruby/test_hash.rb
    MacRuby/trunk/test/ruby/test_integer.rb
    MacRuby/trunk/test/ruby/test_io.rb
    MacRuby/trunk/test/ruby/test_io_m17n.rb
    MacRuby/trunk/test/ruby/test_iterator.rb
    MacRuby/trunk/test/ruby/test_literal.rb
    MacRuby/trunk/test/ruby/test_m17n.rb
    MacRuby/trunk/test/ruby/test_m17n_comb.rb
    MacRuby/trunk/test/ruby/test_marshal.rb
    MacRuby/trunk/test/ruby/test_math.rb
    MacRuby/trunk/test/ruby/test_method.rb
    MacRuby/trunk/test/ruby/test_module.rb
    MacRuby/trunk/test/ruby/test_numeric.rb
    MacRuby/trunk/test/ruby/test_objectspace.rb
    MacRuby/trunk/test/ruby/test_pack.rb
    MacRuby/trunk/test/ruby/test_pipe.rb
    MacRuby/trunk/test/ruby/test_process.rb
    MacRuby/trunk/test/ruby/test_rand.rb
    MacRuby/trunk/test/ruby/test_range.rb
    MacRuby/trunk/test/ruby/test_regexp.rb
    MacRuby/trunk/test/ruby/test_settracefunc.rb
    MacRuby/trunk/test/ruby/test_sprintf.rb
    MacRuby/trunk/test/ruby/test_sprintf_comb.rb
    MacRuby/trunk/test/ruby/test_string.rb
    MacRuby/trunk/test/ruby/test_struct.rb
    MacRuby/trunk/test/ruby/test_symbol.rb
    MacRuby/trunk/test/ruby/test_system.rb
    MacRuby/trunk/test/ruby/test_thread.rb
    MacRuby/trunk/test/ruby/test_time.rb
    MacRuby/trunk/test/ruby/test_trace.rb
    MacRuby/trunk/test/ruby/test_transcode.rb
    MacRuby/trunk/test/ruby/test_utf16.rb
    MacRuby/trunk/test/ruby/test_variable.rb
    MacRuby/trunk/test/ruby/test_yield.rb
    MacRuby/trunk/test/rubygems/gemutilities.rb
    MacRuby/trunk/test/rubygems/mockgemui.rb
    MacRuby/trunk/test/rubygems/test_gem.rb
    MacRuby/trunk/test/rubygems/test_gem_command_manager.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_environment_command.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_fetch_command.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_install_command.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_query_command.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_server_command.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_sources_command.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_specification_command.rb
    MacRuby/trunk/test/rubygems/test_gem_commands_unpack_command.rb
    MacRuby/trunk/test/rubygems/test_gem_dependency_installer.rb
    MacRuby/trunk/test/rubygems/test_gem_ext_configure_builder.rb
    MacRuby/trunk/test/rubygems/test_gem_format.rb
    MacRuby/trunk/test/rubygems/test_gem_indexer.rb
    MacRuby/trunk/test/rubygems/test_gem_installer.rb
    MacRuby/trunk/test/rubygems/test_gem_remote_fetcher.rb
    MacRuby/trunk/test/rubygems/test_gem_server.rb
    MacRuby/trunk/test/rubygems/test_gem_source_index.rb
    MacRuby/trunk/test/rubygems/test_gem_source_info_cache.rb
    MacRuby/trunk/test/rubygems/test_gem_source_info_cache_entry.rb
    MacRuby/trunk/test/stringio/test_stringio.rb
    MacRuby/trunk/test/strscan/test_stringscanner.rb
    MacRuby/trunk/test/webrick/test_filehandler.rb
    MacRuby/trunk/thread.c
    MacRuby/trunk/thread_pthread.c
    MacRuby/trunk/thread_win32.c
    MacRuby/trunk/time.c
    MacRuby/trunk/tool/compile_prelude.rb
    MacRuby/trunk/tool/instruction.rb
    MacRuby/trunk/transcode.c
    MacRuby/trunk/variable.c
    MacRuby/trunk/version.c
    MacRuby/trunk/version.h
    MacRuby/trunk/vm.c
    MacRuby/trunk/vm_core.h
    MacRuby/trunk/vm_evalbody.c
    MacRuby/trunk/vm_insnhelper.c
    MacRuby/trunk/win32/Makefile.sub
    MacRuby/trunk/win32/win32.c

Added Paths:
-----------
    MacRuby/trunk/complex.c
    MacRuby/trunk/enc/prelude.rb
    MacRuby/trunk/rational.c
    MacRuby/trunk/test/erb/hello.erb
    MacRuby/trunk/test/rdoc/test_rdoc_ri_default_display.rb
    MacRuby/trunk/test/ruby/allpairs.rb
    MacRuby/trunk/test/ruby/lbtest.rb
    MacRuby/trunk/test/ruby/test_comparable.rb
    MacRuby/trunk/test/ruby/test_complex.rb
    MacRuby/trunk/test/ruby/test_integer_comb.rb
    MacRuby/trunk/test/ruby/test_object.rb
    MacRuby/trunk/test/ruby/test_parse.rb
    MacRuby/trunk/test/ruby/test_rational.rb
    MacRuby/trunk/test/ruby/test_rational2.rb
    MacRuby/trunk/test/ruby/test_rubyoptions.rb
    MacRuby/trunk/test/ruby/test_utf32.rb
    MacRuby/trunk/test/rubygems/gem_installer_test_case.rb
    MacRuby/trunk/test/rubygems/gem_package_tar_test_case.rb
    MacRuby/trunk/test/rubygems/private_key.pem
    MacRuby/trunk/test/rubygems/public_cert.pem
    MacRuby/trunk/test/rubygems/test_gem_commands_update_command.rb
    MacRuby/trunk/test/rubygems/test_gem_package_tar_header.rb
    MacRuby/trunk/test/rubygems/test_gem_package_tar_input.rb
    MacRuby/trunk/test/rubygems/test_gem_package_tar_output.rb
    MacRuby/trunk/test/rubygems/test_gem_package_tar_reader.rb
    MacRuby/trunk/test/rubygems/test_gem_package_tar_reader_entry.rb
    MacRuby/trunk/test/rubygems/test_gem_package_tar_writer.rb
    MacRuby/trunk/test/rubygems/test_gem_uninstaller.rb
    MacRuby/trunk/test/test_pstore.rb
    MacRuby/trunk/test/xmlrpc/test_cookie.rb
    MacRuby/trunk/test/yaml/test_yamlstore.rb

Removed Paths:
-------------
    MacRuby/trunk/test/rubygems/test_open_uri.rb
    MacRuby/trunk/test/rubygems/test_package.rb
    MacRuby/trunk/test/test_generator.rb

Modified: MacRuby/trunk/ChangeLog
===================================================================
--- MacRuby/trunk/ChangeLog	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ChangeLog	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,3 +1,2664 @@
+Sat May 17 03:21:29 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* array.c (rb_ary_sort_bang): stop memory leak.  [ruby-dev:34726]
+
+	* re.c (rb_reg_search): need to free allocated buffer in re_register.
+
+	* regexec.c (onig_region_new): more pedantic malloc check.
+
+	* regexec.c (onig_region_resize): ditto.
+
+	* regexec.c (STATE_CHECK_BUFF_INIT): ditto.
+
+	* regexec.c (onig_region_copy): use onig_region_resize.
+
+Fri May 16 12:48:33 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* math.c (to_flo): rb_Float() accepts even strings for input.
+
+	* complex.c (nucomp_to_f): fix wrong message.
+
+	* complex.c (nucomp_to_r): ditto.
+
+	* object.c (rb_Float): do not check NaN for error.  NaN is a part
+	  of valid float values.
+
+Thu May 15 23:36:09 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_string.rb: add tests to achieve over 90% test
+	  coverage of string.c.
+
+	* test/ruby/test_m17n.rb: ditto.
+
+	* test/ruby/test_symbol.rb: ditto.
+
+	* test/ruby/test_pack.rb: ditto.
+
+Thu May 15 23:01:06 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* string.c (tr_find): String#delete returned wrong result when multiple
+	  utf-8 arguments are passed.
+
+	* test/ruby/test_m17n.rb (test_delete): add a test for above.
+
+Thu May 15 22:37:56 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* parse.y (ripper_warningS): now used.
+
+Thu May 15 15:33:59 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* file.c (file_expand_path): support for alternative data stream
+	  and ignored trailing garbages of NTFS.
+
+	* file.c (rb_file_s_basename): ditto.
+
+	* file.c (rb_file_s_extname): ditto.
+
+Thu May 15 13:43:36 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* object.c (rb_cstr_to_dbl): no need for forceful warning when
+	  converting to float.  overflow is a nature of float values.
+
+	* parse.y (parser_yylex): ditto.
+
+Thu May 15 13:23:20 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* re.c (rb_reg_prepare_enc): error condition was updated for non
+	  ASCII compatible strings.
+
+Thu May 15 12:19:42 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* ext/openssl/openssl_missing.c (HMAC_CTX_copy): adopted to
+	  prototype change in openssl bundled with newer OpenBSD.
+	  a patch from Takahiro Kambe <taca at back-street.net> in
+	  [ruby-dev:34691].
+
+Wed May 14 22:09:25 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* ChangeLog: fix typo.
+
+Wed May 14 21:49:14 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_object.rb: new tests to achieve over 90% test
+	  coverage of object.c, eval.c and eval_method.c.
+
+	* test/ruby/test_module.rb: ditto.
+
+	* test/ruby/test_trace.rb: ditto.
+
+	* test/ruby/test_integer.rb: ditto.
+
+	* test/ruby/test_float.rb: ditto.
+
+	* test/ruby/test_method.rb: ditto.
+
+	* test/ruby/test_variable.rb: ditto.
+
+	* test/ruby/test_eval.rb: ditto.
+
+	* test/ruby/test_exception.rb: ditto.
+
+	* test/ruby/test_class.rb: ditto.
+
+Wed May 14 12:46:37 2008  Koichi Sasada  <ko1 at atdot.net>
+
+	* iseq.c (insn_operand_intern): remove Qundef related code.
+
+Wed May 14 12:42:36 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* array.c (rb_ary_count): Override Enumerable#count for better
+	  performance.
+
+Wed May 14 11:29:06 2008  Koichi Sasada  <ko1 at atdot.net>
+
+	* insns.def: add a "putcbase" instruction.
+
+	* compile.c, insns.def: fix to use putcbase instruction for
+	  class search.  Qundef should not be used.
+
+Wed May 14 07:49:35 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* eval.c (rb_call0): defer calling of rb_frame_self() until it
+	  become really necessary.
+
+	* eval.c (rb_call): ditto.
+
+Wed May 14 00:55:56 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_io_m17n.rb: remove a duplicative method.
+
+	* test/ruby/test_utf16.rb: rename a conflicting method name.
+
+	* test/ruby/test_array.rb: ditto.
+
+	* test/ruby/test_file_exhaustive.rb: ditto.
+
+	* test/ruby/test_hash.rb: ditto.
+
+	* test/ruby/test_env.rb: ditto.
+
+	* test/ruby/test_fixnum.rb: ditto.
+
+	* test/ruby/test_rational.rb: ditto.
+
+Wed May 14 00:45:58 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* eval_method.c (rb_add_method): fix check for warning when
+	  Object#initialize is redefined. (same as 1.8)
+
+Tue May 13 23:32:44 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* enum.c (enum_yield): use rb_yield_values2.
+
+	* enum.c (DEFINE_ENUMFUNCS): macro to define enumerator and yielding
+	  functions.
+
+	* enum.c (enum_all_func, enum_any_func, enum_one_func,
+	  enum_none_func): reduced duplicate code.
+
+Tue May 13 15:09:38 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enumerator.c: Update rdoc.
+	  (enumerator_initialize): Discourage the use.
+	  (enum_each_slice, enum_each_cons, enumerator_each)
+	  (enumerator_with_index): Add a note about a call without a block.
+
+Tue May 13 08:25:31 2008  Tanaka Akira  <akr at fsij.org>
+
+	* io.c (rb_f_gets.): re-enable rdoc.
+	  (rb_f_readline): ditto.
+	  (rb_f_readlines): ditto.
+
+Tue May 13 07:56:36 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (rb_str_cat): fixed buffer overrun reported by
+	  Christopher Thompson <cthompson at nexopia.com> in [ruby-core:16746]
+
+Mon May 12 23:37:57 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* vm.c (collect_local_variables_in_env): remove unnecessary check
+	  which causes: x=1;proc{local_variables}.call #=> []
+
+	* test/ruby/test_variable.rb: add a test for above.
+
+Mon May 12 23:05:24 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* process.c, include/ruby/intern.h (rb_run_exec_options): externed.
+
+	* process.c (save_redirect_fd, save_env_i, save_env, run_exec_dup2,
+	  run_exec_open, run_exec_pgroup, run_exec_rlimit, rb_run_exec_options):
+	  save parent's process environments.
+
+	* process.c (rb_spawn_internal): remove calling run_exec_options()
+	  because cannot restore after spawn.
+
+	* io.c (pipe_open): ditto.
+
+	* test/ruby/test_process.rb (test_execopts_env): upcase environment
+	  variable name for case insensitive platforms.
+
+	* win32/win32.c (init_env): set USER environment variable only when
+	  USERNAME is available.
+
+Mon May 12 22:23:01 2008  Tanaka Akira  <akr at fsij.org>
+
+	* lib/date.rb (once): use Object#object_id instead of Symbol#to_i.
+
+Mon May 12 21:34:46 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* test/ruby/envutil.rb (rubybin): return expanded rubyexe instead of
+	  expanded ruby if available.
+
+Mon May 12 20:19:55 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enum.c (grep_i): Be aware of multiple values;
+	  fix [ruby-dev:34653].
+	  (grep_iter_i): Ditto.
+	  (count_i): Ditto.
+	  (find_i): Ditto.
+	  (find_index_i): Ditto.
+	  (find_all_i): Ditto.
+	  (reject_i): Ditto.
+	  (inject_i): Ditto.
+	  (inject_op_i): Ditto.
+	  (partition_i): Ditto.
+	  (group_by_i): Ditto.
+	  (first_i): Ditto.
+	  (sort_by_i): Ditto.
+	  (all_i): Ditto.
+	  (all_iter_i): Ditto.
+	  (any_i): Ditto.
+	  (any_iter_i): Ditto.
+	  (one_i): Ditto.
+	  (one_iter_i): Ditto.
+	  (none_i): Ditto.
+	  (none_iter_i): Ditto.
+	  (min_i): Ditto.
+	  (min_ii): Ditto.
+	  (max_i): Ditto.
+	  (max_ii): Ditto.
+	  (minmax_i): Ditto.
+	  (minmax_ii): Ditto.
+	  (min_by_i): Ditto.
+	  (max_by_i): Ditto.
+	  (minmax_by_i): Ditto.
+	  (member_i): Ditto.
+	  (take_i): Ditto.
+	  (take_while_i): Ditto.
+	  (drop_i): Ditto.
+	  (drop_while_i): Ditto.
+	  (cycle_i): Ditto.
+
+	* enum.c (each_with_index): Update rdoc.  each_with_index() takes
+	  argments that are passed through to each(), and a hash preserves
+	  key order.
+
+Mon May 12 19:05:24 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* process.c (rb_spawn_internal): remove calling run_exec_options()
+	  because cannot restore after spawn. we'll fix this later.
+
+Mon May 12 18:16:44 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* process.c (rb_spawn_internal): need to call run_exec_options() before
+	  spawn if the platform doesn't have fork. [ruby-dev:34647]
+
+Mon May 12 15:20:02 2008  Tanaka Akira  <akr at fsij.org>
+
+	* gc.c (ruby_vm_xmalloc): increase malloc_increase only if malloc
+	  succeeds.  failed malloc size can be huge.  it may increase
+	  malloc_limit too big which cause less GC and memory full.
+	  (ruby_vm_xrealloc): ditto.
+	  (rb_objspace): make params.limit and params.increase size_t.
+
+Mon May 12 15:04:58 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* re.c (rb_reg_prepare_re): made non static with small refactoring.
+
+	* ext/strscan/strscan.c (strscan_do_scan): should adjust encoding
+	  before regex searching.
+
+Mon May 12 13:57:19 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* eval.c (is_defined): add NODE_OP_ASGN_{OR,AND}.  "defined?(a||=1)"
+	  should not operate assignment.  [ruby-dev:34645]
+
+Mon May 12 13:29:26 2008  Tanaka Akira  <akr at fsij.org>
+
+	* bignum.c (bigzero_p): check from MSB to LSB.  [ruby-dev:34649]
+
+Mon May 12 12:32:10 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* common.mk (RUBYOPT): affected BASERUBY too.  [ruby-talk:301514]
+
+Mon May 12 12:27:55 2008  Tanaka Akira  <akr at fsij.org>
+
+	* gc.c (assign_heap_slot): fix condition for number of objects in
+	  a heap.
+
+Mon May 12 12:24:48 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (sym_to_i): really removed.  [ruby-dev:34641]
+
+Mon May 12 11:15:55 2008  Yuki Sonoda (Yugui) <yugui at yugui.jp>
+
+	* gc.c (assign_heap_slot):  put the binary search routine in order.
+
+Mon May 12 10:52:51 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* ruby.c (ruby_init_gems), gem_prelude.rb: check if Gem is defined
+	  instead of Gem::Enable.
+
+	* gem_prelude.rb (load_full_rubygems_library, const_missing): prevent
+	  infinite recursion.  [ruby-dev:34539]
+
+Sun May 11 23:19:39 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* enum.c (all_iter_i, any_iter_i): reduced duplicated code.
+
+Sun May 11 22:54:02 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* bootstraptest/runner.rb (main): leave -I options for purelib.rb
+	  untouched.
+
+	* bootstraptest/runner.rb (main): handle relative path -r options.
+
+Sun May 11 19:04:06 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_thread.rb: kill and join temporal threads that are
+	  created in each test.
+
+Sun May 11 17:58:45 2008  Tanaka Akira  <akr at fsij.org>
+
+	* test/ruby/test_process.rb (TestProcess#with_stdin): defined.
+	  (TestProcess#test_argv0_noarg): don't use redirect_fds.
+	  [ruby-dev:34647]
+
+Sun May 11 17:57:36 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (MINIRUBY): should not include extension library path.
+
+Sun May 11 14:40:36 2008  Tanaka Akira  <akr at fsij.org>
+
+	* include/ruby/ruby.h (SIZET2NUM): new macro.
+	  (NUM2SIZET): new macro.
+
+	* gc.c (struct rb_objspace): use size_t for increment, length and
+	  used for 64bit.
+	  (allocate_heaps): ditto.
+	  (assign_heap_slot): ditto.
+	  (set_heaps_increment): ditto.
+	  (gc_mark_all): ditto.
+	  (is_pointer_to_heap): ditto.
+	  (free_unused_heaps): ditto.
+	  (gc_sweep): ditto.
+	  (os_obj_of): ditto.
+	  (rb_gc_call_finalizer_at_exit): ditto.
+	  (count_objects): ditto.
+
+Sun May 11 13:14:09 2008  Tanaka Akira  <akr at fsij.org>
+
+	* thread.c (thread_cleanup_func_before_exec): extracted from
+	  thread_cleanup_func not to touch pthread data.
+	  pthread_cond_destroy in forked process may cause deadlock on
+	  Debian GNU/Linux Etch on x86, x86-64 and IA64.
+	  this doesn't cause resource leak because the process will exec soon.
+	  (terminate_atfork_before_exec_i): defined.
+	  (rb_thread_atfork_before_exec): defined.
+
+	* include/ruby/intern.h (rb_thread_atfork_before_exec): declared.
+
+	* process.c (rb_exec_atfork): call rb_thread_atfork_before_exec
+	  instead of rb_thread_atfork.
+
+	* io.c (popen_exec): call rb_thread_atfork_before_exec instead of
+	  rb_thread_atfork.
+
+Sat May 10 22:14:03 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (tr_trans): single '^' does not mean negation.
+	  [ruby-dev:34632]
+
+	* string.c (tr_trans): should check src size, not str size.
+	  [ruby-dev:34637]
+
+	* string.c (tr_trans): should not turn on modify flag if no
+	  modification happens.  [ruby-dev:34631]
+
+Sat May 10 18:11:18 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (rb_str_each_line): zero length record separator should
+	  split a string into paragraphs.  [ruby-dev:34586]
+
+	* string.c (rb_str_each_line): RDoc updated.
+
+Sat May 10 11:36:20 2008  Tanaka Akira  <akr at fsij.org>
+
+	* vm.c (env_mark): mark env->block.self.  prevent SEGV when GC occur
+	  in prepare_iseq_build with gcc version 3.4.6 [FreeBSD] 20060305 on
+	  FreeBSD/amd64.
+
+Fri May  9 19:16:00 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* thread.c (timeofday): use monotonic clock.  based on a patch
+	  from zimbatm <zimbatm at oree.ch> in [ruby-core:16627].
+
+Fri May  9 07:47:07 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* cont.c (cont_restore_0): dynamic stack direction code should be
+	  consistent with static one.  [ruby-talk:301152]
+
+Fri May  9 00:03:50 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* parse.y (arg): operator assignment "a += b rescue c" should be
+	  parsed as "a += (b rescue c)" just like normal assignment.
+	  [ruby-talk:301000]
+
+Thu May  8 18:14:00 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* bignum.c (rb_big_and): bit-wise operation should not take float
+	  values.  [ruby-dev:34612]
+
+	* bignum.c (rb_big_or): ditto.
+
+	* bignum.c (rb_big_xor): ditto.
+
+Thu May  8 17:44:13 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* common.mk, ext/extmk.rb, lib/mkmf.rb: use absolute path for RUBYOPT.
+
+	* file.c (rb_find_file_ext): guard load_path from GC.
+	  gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21) optimizes
+	  load_path by holding only RARRAY_LEN(load_path) and
+	  RARRAY_PTR(load_path) in registers on IA64 GNU/Linux Etch.
+
+Thu May  8 16:41:20 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (MINIRUBY), common.mk (RUBYOPT): add purelib.rb.
+	  [ruby-core:16642]
+
+Thu May  8 16:00:41 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* parse.y (parser_yylex): ! and ? at the bottom are no longer part
+	  of valid symbol names.  [ruby-dev:34590]
+
+Thu May  8 15:36:11 2008  Tanaka Akira  <akr at fsij.org>
+
+	* thread.c (rb_gc_save_machine_context): call FLUSH_REGISTER_WINDOWS
+	  to mark the register stack from GC on another thread.
+
+Thu May  8 15:14:34 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* array.c (rb_ary_sort_bang): freeze temporary array.
+
+Thu May  8 13:19:18 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* vm.c (rb_thread_mark): mark stat_insn_usage only when ptr is not
+	  null.
+
+Thu May  8 10:44:04 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* array.c (sort_reentered): reentered check may be called from
+	  Array#sort.
+
+Thu May  8 09:51:52 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* array.c (sort_1, sort_2): check for reentered and if elements are
+	  accessible.  [ruby-core:16679]
+
+Thu May  8 06:43:52 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* dln.c (dln_find_exe_r, dln_find_file_r): reentrant versions.
+
+	* file.c (rb_find_file_ext, rb_find_file), process.c (proc_exec_v),
+	  (rb_proc_exec, proc_spawn_v, proc_spawn), ruby.c (process_options):
+	  use reentrant versions.
+
+Thu May  8 06:27:33 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* thread.c (rb_thread_key_p): thread local storage stores ID.
+
+Thu May  8 01:10:03 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (tr_trans): should squeeze properly.  [ruby-dev:34587]
+
+	* string.c (tr_trans): had a bug in treating multi-byte character
+	  replacement.
+
+	* string.c (rb_str_delete_bang): need not to do anything for empty
+	  strings.
+
+	* test/ruby/test_m17n_comb.rb (TestM17NComb::test_str_delete): add
+	  test for empty receiver.
+
+Wed May  7 20:19:18 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* ruby.c (process_options, ruby_set_argv): set encoding of rb_argv
+	  after Init_prelude() because cannot load encoding extensions before
+	  it.
+
+Wed May  7 20:00:21 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* numeric.c (bit_coerce): float should not be a valid operand of
+	  bitwise operations.  [ruby-dev:34583]
+
+Wed May  7 19:35:29 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* thread.c (rb_thread_key_p): should always convert symbol to ID.
+	  [ruby-dev:34588]
+
+Wed May  7 19:30:34 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* numeric.c (fix_divide): float division should floor() before
+	  rounding into integer.  [ruby-dev:34584]
+
+Wed May  7 18:02:01 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (sym_to_i): remove obsolete method.  preparation for
+	  symbol GC.
+
+	* numeric.c (fix_to_sym): ditto.
+
+	* numeric.c (fix_id2name): ditto.
+
+Wed May  7 17:43:22 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c (io_puts_ary): check recursion first.  [ruby-dev:34580]
+
+Wed May  7 17:41:14 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* vm.c (vm_eval_body): initialize retval.  [ruby-dev:34576]
+
+Wed May  7 13:02:56 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* bignum.c (rb_big_fdiv): flo.fdiv(NaN) should result NaN.
+
+	* numeric.c (num_quo): renamed and moved from bignum.c.
+	  [ruby-dev:34582]
+
+	* bignum.c (rb_big_fdiv): update RDoc description
+
+	* rational.c (nurat_s_new_m): small refactoring.
+
+	* bignum.c (rb_big2dbl): no need for forceful warning when
+	  converting to float.  overflow is a nature of float values.
+
+Wed May  7 00:54:25 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* ext/zlib/zlib.c (gzreader_gets): may cause infinite loop.
+	  a patch from Kouya <kouyataifu4 at gmail.com> in
+	  [ruby-reference-manual:762].
+
+Tue May  6 02:08:18 2008  Tanaka Akira  <akr at fsij.org>
+
+	* test/io/nonblock/test_flush.rb: don't set Thread.abort_on_exception.
+
+	* test/net/imap/test_imap.rb: ensure disconnecting imap to terminate
+	  receiver thread.
+
+Tue May  6 00:29:21 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* iseq.c (insn_operand_intern): should handle Qundef embedded in
+	  operand.  [ruby-core:16656]
+
+Tue May  6 00:00:02 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* compile.c (iseq_compile_each): should call compile_cpath() for
+	  modules as well.  [ruby-dev:34585]
+
+	* insns.def (defineclass): add undef handling.
+
+Mon May  5 23:49:40 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* insns.def (defineclass): was using wrong variable.  [ruby-dev:34592]
+
+Mon May  5 20:07:59 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* io.c (io_fflush): IO#flush problem within threads.  a patch from
+	  <s.wanabe at gmail.com> in [ruby-dev:34595].
+
+Mon May  5 19:58:44 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* compile.c (defined_expr): protect some expression from
+	  segmentation fault.  a patch from wanabe <s.wanabe at gmail.com>
+	  in [ruby-dev:34593].
+
+Mon May  5 19:49:59 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* struct.c (rb_struct_s_def): Struct.new(0) should not SEGV.
+	  based on the patch from wanabe <s.wanabe at gmail.com> in
+	  [ruby-dev:34594].
+
+	* struct.c (make_struct): call to_str on name object.
+
+Mon May  5 17:17:40 2008  Tanaka Akira  <akr at fsij.org>
+
+	* eval.c (ruby_cleanup): wrap ruby_finalize_0 by SAVE_ROOT_JMPBUF to
+	  avoid SEGV by at_exit { Fiber.new{}.resume } on IA64.
+
+Mon May  5 12:12:11 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* array.c (rb_ary_slice_bang): should adjust length before making
+	  sub-array.
+
+Mon May  5 11:36:14 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* array.c (rb_ary_dup): should dupe corresponding information.
+	  [ruby-dev:34581]
+
+Mon May  5 11:13:50 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* compile.c (compile_cpath): use Qundef to denote cbase lookup.
+
+	* insns.def (defineclass): Qundef is passed for cbase.
+
+	* insns.def (setconstant): ditto.
+
+	* vm_insnhelper.c (vm_check_if_namespace): use rb_inspect()
+	  instead of rb_obj_as_string() for better description.
+
+Mon May  5 02:10:23 2008  Tanaka Akira  <akr at fsij.org>
+
+	* gc.c (set_heaps_increment): fix memory allocation strategy by
+	  determining heaps_inc from heaps_used, not objects_delta.
+	  (struct rb_objspace): delta removed.  change increment, length and
+	  used to long for LP64.
+	  (objects_delta): removed.
+	  (allocate_heaps): add next_heaps_length argument.
+	  (init_heap): renamed from add_heap.
+	  (garbage_collect): use heaps_increment in dont_gc.
+
+Sun May  4 21:09:32 2008  Tanaka Akira  <akr at fsij.org>
+
+	* lib/getoptlong.rb: use $stderr instead of $deferr.
+
+Sun May  4 16:04:28 2008  Tanaka Akira  <akr at fsij.org>
+
+	* time.c (obj2nsec): fix string argument.
+
+Sun May  4 14:29:14 2008  Tanaka Akira  <akr at fsij.org>
+
+	* eval.c (rb_obj_respond_to): check the result of respond_to? method
+	  by RTEST.
+
+Sun May  4 12:57:58 2008  Tanaka Akira  <akr at fsij.org>
+
+	* string.c (rb_str_each_line): return original string.
+
+Sat May  3 20:57:06 2008  Tanaka Akira  <akr at fsij.org>
+
+	* test/ruby/envutil.rb (Test::Unit::Assertions#assert_normal_exit):
+	  new method.
+
+Sat May  3 18:10:54 2008  Tanaka Akira  <akr at fsij.org>
+
+	* time.c (time_timespec): raise TypeError for nil and other objects
+	  which has no divmod method.
+
+Fri May  2 23:59:26 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c (internal_read_func, internal_write_func): split from
+	  internal_io_func.
+
+Fri May  2 23:55:15 2008  Tanaka Akira  <akr at fsij.org>
+
+	* variable.c (rb_define_hooked_variable): guard *var from GC to
+	  prevent collecting argf under RUBY_DEBUG=gc_stress.
+
+Fri May  2 17:29:59 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* range.c (range_step): call to_int if step is not a numeric
+	  value.  [ruby-dev:34575]
+
+Fri May  2 16:10:57 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* range.c (range_step): do not forcefully convert steps into
+	  integers.  [ruby-dev:34571]
+
+Fri May  2 14:52:33 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* misc/ruby-mode.el: move fontifying code from hook.  a patch from
+	  Phil Hagelberg <phil at hagelb.org> in [ruby-core:16636].
+
+Fri May  2 14:10:17 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* range.c (range_step): step may be bignum.
+
+Fri May  2 13:52:36 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* re.c (Init_Regexp): remove MatchData#select.  [ruby-dev:34563]
+
+Thu May  1 23:59:59 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* bignum.c (rb_big_divide), numeric.c (fix_divide): check for result
+	  domain.  [ruby-dev:34559]
+
+Thu May  1 23:57:06 2008  James Edward Gray II  <jeg2 at ruby-lang.org>
+
+	* lib/net/telnet.rb:  This patch from Brian Candler adds a FailEOF mode which
+	  can be activated to have net/telnet raise EOFError exceptions when the
+	  remote connection is closed.  The default behavior remains unchanged though.
+
+Thu May  1 23:43:21 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* range.c (range_step): check if step can be converted to an integer.
+	  [ruby-dev:34558]
+
+	* range.c (range_step): allow float step bigger than zero but less
+	  than one.  [ruby-dev:34557]
+
+Thu May  1 23:20:12 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* bignum.c (rb_big_divide): return an integer for idiv.
+	  [ruby-dev:34553]
+
+Thu May  1 20:47:30 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* hash.c (rb_hash_s_create): should access converted hash value.
+	  [ruby-dev:34555]
+
+Thu May  1 20:31:09 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* test/ruby/test_parse.rb (TestParse::test_void_expr_stmts_value):
+	  shut up warning.
+
+	* rational.c (nurat_to_f): no need for forceful warning when
+	  converting to float.  overflow is a nature of float values.
+
+Thu May  1 16:10:21 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* hash.c (env_delete_if): return enumerator if no block given.
+	  [ruby-dev:34554]
+
+Wed Apr 30 21:36:40 2008  Masatoshi SEKI  <m_seki at mva.biglobe.ne.jp>
+
+	* lib/erb.rb (url_encode): [ruby-dev:34497] ERB::Util#url_encode
+	  bug fix. Reported by rubikitch.
+
+	* test/erb/test_erb.rb: ditto
+
+Wed Apr 30 20:11:36 2008  James Edward Gray II  <jeg2 at ruby-lang.org>
+
+	* lib/net/telnet.rb:  Fixing a bug where line endings would not be properly
+	  escaped when the two character ending was broken up into separate TCP
+	  packets.  Issue reported and patched by Brian Candler.
+
+Wed Apr 30 18:03:01 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* load.c (rb_load_path), vm_core.h (rb_vm_t): moved to VM.
+
+	* load.c (rb_get_load_path): returns absolute load path.
+
+	* load.c (load_path_getter): $LOAD_PATH getter.
+
+	* file.c (rb_find_file_ext, rb_find_file), ruby.c (push_include,
+	  ruby_init_loadpath): use the accessor.
+
+	* vm.c (rb_vm_mark): mark load_path.
+
+Wed Apr 30 17:47:21 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* re.c (rb_reg_search): use local variable.  a patch from wanabe
+	  <s.wanabe AT gmail.com> in [ruby-dev:34537].  [ruby-dev:34492]
+
+Wed Apr 30 16:10:18 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* eval_intern.h: specify the values of the enumeration constants
+	  explicitly.  [ruby-dev:34489]
+
+Wed Apr 30 12:32:39 2008  Tanaka Akira  <akr at fsij.org>
+
+	* process.c (check_exec_redirect_fd): prohibit duplex IO.
+	  (check_exec_fds): record maxhint even if close_others is not
+	  specified.
+	  (rb_exec_arg_fixup): renamed from rb_exec_arg_fix.
+
+Mon Apr 28 20:24:27 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* rational.c (nurat_marshal_load): checks the given
+	  denominator. [ruby-dev:34536]
+
+Mon Apr 28 14:21:18 2008  Tanaka Akira  <akr at fsij.org>
+
+	* include/ruby/ruby.h (POSFIXABLE): use FIXNUM_MAX+1 instead of
+	  FIXNUM_MAX to make it possible to convert to double accurately on
+	  environments with 64bit VALUE and 64bit double.
+	  It assumes FLT_RADIX is 2.
+	  fix RubyForge bug #14102.
+
+Mon Apr 28 12:48:57 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* process.c (rb_exec_arg_addopt, rb_exec_arg_addopt): now can specify
+	  close_exec on having no fork environment (but still meaningless).
+
+Mon Apr 28 11:11:29 2008  Tanaka Akira  <akr at fsij.org>
+
+	* process.c (run_exec_options): don't call FIX2INT for nil.
+
+Mon Apr 28 11:11:38 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* proc.c (method_name): should return symbols instead of strings.
+	  [ruby-dev:34531]
+
+Mon Apr 28 09:02:43 2008  Tanaka Akira  <akr at fsij.org>
+
+	* include/ruby/intern.h (rb_exec_arg_init): declared.
+	  (rb_exec_arg_addopt): declared.
+	  (rb_exec_arg_fix): declared.
+	  (rb_exec_initarg): removed.
+	  (rb_exec_getargs): removed.
+	  (rb_exec_initarg2): removed.
+
+	* io.c (struct popen_arg): make execarg as a pointer.
+	  (popen_exec): follow popen_arg change.
+	  (pipe_open): add eargp argument.  extract argc and argv from eargp.
+	  use rb_exec_arg_addopt to add redirect options.
+	  (pipe_open_v): set up struct rb_exec_arg.
+	  (pipe_open_s): set up struct rb_exec_arg.
+
+	* process.c (rb_exec_arg_addopt): new function extracted from
+	  check_exec_options_i.
+	  (check_exec_options_i): use rb_exec_arg_addopt.
+	  (rb_check_exec_options): opthash is always a hash now.
+	  (rb_exec_getargs): make it static.
+	  (rb_exec_fillarg): renamed from rb_exec_initarg2.  don't set up
+	  redirect_fds.
+	  (rb_exec_arg_init): new function.
+	  (rb_exec_arg_fix): new function.
+	  (rb_f_exec): use rb_exec_arg_init and rb_exec_arg_fix.  use
+	  rb_exec_arg_addopt to set close_others option.
+	  (run_exec_options): make close_others by default.
+	  (rb_spawn_internal): use rb_exec_arg_init and rb_exec_arg_fix.  use
+	  rb_exec_arg_addopt to set close_others option.
+
+Sun Apr 27 18:59:04 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* rational.c (nurat_expt): use f_rational_new2. [ruby-dev:34524]
+
+Sun Apr 27 15:23:40 2008  Koichi Sasada  <ko1 at atdot.net>
+
+	* gc.c (gc_count): add a GC.count method.  This method returns
+	  a GC invoking count.
+
+Sun Apr 27 12:20:33 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* vm_core.h (rb_vm_t), gc.c (rb_objspace, rb_newobj), vm.c
+	  (Init_BareVM): per-VM object space support, which is disabled now.
+
+	* gc.c (rb_objspace_alloc), vm.c (Init_BareVM): should not use ruby
+	  malloc here.
+
+	* gc.c (garbage_collect, etc): performance improvement by passing the
+	  reference instead of referring the global variable in each functions.
+
+Sun Apr 27 08:06:15 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* ruby.c (ruby_set_argv): ARGV should be locale encoding.
+	  [ruby-list:44861]
+
+Sun Apr 27 01:46:29 2008  Tanaka Akira  <akr at fsij.org>
+
+	* lib/open3.rb (Open3.popen3w): removed.
+	  (Open3.popen3): notice wait_thr.
+
+Sun Apr 27 01:13:05 2008  Eric Hodel  <drbrain at segment7.net>
+
+	* lib/rdoc, test/rdoc:  Update to RDoc 2.0.0 r56.
+
+Sat Apr 26 21:30:40 2008  Tanaka Akira  <akr at fsij.org>
+
+	* include/ruby/intern.h (rb_hash_dup): declared.
+
+	* hash.c (rb_hash_dup): new function.
+
+	* process.c (rb_spawn_internal): don't modify option hash.
+
+Sat Apr 26 18:36:31 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c, signal.c, thread.c, thread_win32.c, include/ruby/intern.h:
+	  suppress warnings.
+
+Sat Apr 26 17:42:30 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* error.c (builtin_types), gc.c (count_objects): added Complex and
+	  Rational.
+
+Sat Apr 26 17:35:19 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* error.c (rb_eNOERROR): renamed.
+
+Sat Apr 26 17:30:11 2008  Koichi Sasada  <ko1 at atdot.net>
+
+	* include/ruby/ruby.h, gc.c: remove T_BLOCK.
+
+	* include/ruby/ruby.h: re-number T_xxx.
+
+Sat Apr 26 17:31:09 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* process.c (rb_cProcessTms, rb_cProcessStatus): renamed.
+
+	* error.c (builtin_types), signal.c (siglist), st.c (primes),
+	  struct.c (ref_func), time.c (months): constified.
+
+Sat Apr 26 13:00:41 2008  Tanaka Akira  <akr at fsij.org>
+
+	* lib/open3.rb: double fork is replaced by spawn with Process.detach.
+	  (Open3.popen3w): new method to access the thread returned by
+	  Process.detach.
+
+Sat Apr 26 00:47:43 2008  Tanaka Akira  <akr at fsij.org>
+
+	* process.c (rb_spawn_internal): new function to specify
+	  default_close_others.
+	  (rb_spawn): specify default_close_others true.
+	  (rb_f_system): call rb_spawn_internal with default_close_others as
+	  false.
+
+Sat Apr 26 12:26:41 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* range.c (range_each): use INT2FIX() for fixnum values.
+
+Fri Apr 25 17:56:25 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* gc.c (free_unused_heaps): preserve last used heap segment to
+	  reduce malloc() call.
+
+Fri Apr 25 17:54:10 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* gc.c (HEAP_SIZE): use smaller heap segment (2K) for more chance
+	  to be freed.  based on patch from authorNari <authornari at gmail.com>.
+
+	* gc.c (rb_newobj_from_heap): eventually allocate heap segments.
+
+Fri Apr 25 15:35:36 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* process.c (rb_spawn): rb_exec_initarg() returns new argc and argv in
+	  earg.
+
+Fri Apr 25 12:37:54 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* array.c (flatten): returns an instance of same class.
+	  [ruby-core:16554]
+
+Fri Apr 25 10:52:27 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* include/ruby/win32.h: define mode_t for umask.
+
+	* process.c (check_exec_options_i, check_exec_fds, run_exec_options):
+	  support "close_others" only when fork(2) is available.
+
+Fri Apr 25 00:16:11 2008  Tanaka Akira  <akr at fsij.org>
+
+	* process.c: include sys/stat.h for umask.
+
+Thu Apr 24 23:25:17 2008  Tanaka Akira  <akr at fsij.org>
+
+	* include/ruby/intern.h (rb_env_clear): declared.
+	  (rb_io_mode_modenum): declared.
+	  (rb_close_before_exec): declared.
+	  (struct rb_exec_arg): add options and redirect_fds field.
+	  (rb_check_argv): removed.
+	  (rb_exec_initarg): declared.
+	  (rb_exec_getargs): declared.
+	  (rb_exec_initarg2): declared.
+	  (rb_fork): add third argument: fds.
+
+	* io.c (max_file_descriptor): new static variable to record maximum
+	  file descriptor ruby used.
+	  (UPDATE_MAXFD): new macro.
+	  (UPDATE_MAXFD_PIPE): new macro.
+	  (rb_io_mode_modenum): externed.
+	  (rb_sysopen): update max_file_descriptor.
+	  (rb_close_before_exec): new function.
+	  (popen_exec): redirection removed because it is done by extended
+	  spawn mechanism.
+	  (pipe_open): generate a hash for spawn options to specify
+	  redirections.
+	  (pipe_open_v): use rb_exec_getargs.
+	  (pipe_open_s): use rb_exec_getargs.
+	  (rb_io_initialize): update max_file_descriptor.
+
+	* process.c (hide_obj): new function.
+	  (check_exec_redirect_fd): new function.
+	  (check_exec_redirect): new function.
+	  (check_exec_options_i): new function.
+	  (check_exec_fds): new function.
+	  (rb_check_exec_options): new function.
+	  (check_exec_env_i): new function.
+	  (rb_check_exec_env): new function.
+	  (rb_exec_getargs): new function.
+	  (rb_exec_initarg2): new function.
+	  (rb_exec_initarg): new function.
+	  (rb_f_exec): use rb_exec_initarg.
+	  (intcmp): new function.
+	  (run_exec_dup2): new function.
+	  (run_exec_close): new function.
+	  (run_exec_open): new function.
+	  (run_exec_pgroup): new function.
+	  (run_exec_rlimit): new function.
+	  (run_exec_options): new function.
+	  (rb_exec): call run_exec_options.
+	  (move_fds_to_avoid_crash): new function.
+	  (pipe_nocrash): new function.
+	  (rb_fork): use pipe_nocrash to avoid file descriptor conflicts.
+	  (rb_spawn): use rb_exec_initarg.
+	  (rlimit_resource_name2int): extracted from rlimit_resource_type.
+	  (rlimit_type_by_hname): new function.
+	  (rlimit_type_by_lname): new function.
+	  (rlimit_resource_type): use rlimit_type_by_hname.
+	  (proc_daemon): add fds argument for rb_fork.
+
+	* hash.c (rb_env_clear): renamed from env_clear and externed.
+
+	[ruby-dev:34086]
+
+Thu Apr 24 23:00:58 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_thread.rb: fix typos.
+
+	* test/ruby/envutil.rb (rubyexec): move Open3.popen3 call into timeout
+	  block.
+
+Thu Apr 24 22:34:52 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_comparable.rb: new tests for Comparable, to achieve
+	  100% test coverage of compar.c.
+
+Thu Apr 24 17:19:01 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* ruby.c (process_options): set safe_level before loading script.
+	  [ruby-dev:34421]
+
+Thu Apr 24 14:15:11 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* dln.c (dln_find_1): prior files with extensions to files sans
+	  extensions.  [ruby-core:16517]
+
+Thu Apr 24 00:26:06 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* lib/rdoc/ri/descriptions.rb: fixed wrong class nestings.
+
+Thu Apr 24 00:20:01 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_settracefunc.rb: add a test for set_trace_func.
+
+	* test/ruby/envutil.rb: move "rubyexec" method from test_rubyoptions.rb.
+
+	* test/ruby/test_rubyoptions.rb: use rubyexec in envutil.rb.
+
+	* test/ruby/test_thread.rb: add tests to achieve over 90% test coverage
+	  of thread.c.
+
+Wed Apr 23 15:28:52 2008  Kazuhiro NISHIYAMA  <zn at mbf.nifty.com>
+
+	* test/gdbm/test_gdbm.rb (TestGDBM#test_s_open_no_create): failed
+	  notice moved from comment to assertion message. [ruby-dev:29127]
+
+Wed Apr 23 11:49:54 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* lib/set.rb (Set#each, SortedSet#each, TC_Set#test_each): Return
+	  an enumerator if no block is given.
+
+Wed Apr 23 00:36:03 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/openssl/test_ssl.rb (start_server): add timeout to server.join.
+
+Wed Apr 23 00:18:45 2008  Kazuhiro NISHIYAMA  <zn at mbf.nifty.com>
+
+	* test/ruby/test_symbol.rb (TestSymbol#test_to_proc): Improve
+	  tests of Symbol#to_proc.
+
+Tue Apr 22 22:40:57 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/drb/drb.rb (DRb::DRbServer::check_insecure_method): should
+	  check method names by symbols, not by strings.  a patch from
+	  Kazuhiro NISHIYAMA <zn at mbf.nifty.com> in [ruby-dev:34487].
+
+Tue Apr 22 22:15:54 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* misc/ruby-style.el (ruby-style-{case,label}-indent): up list from
+	  indentation point.
+
+Tue Apr 22 21:09:05 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* ext/nkf/nkf-utf8/nkf.c (score_table_A0, score_table_F0):
+	  type of content is unsigned char.
+
+	* ext/nkf/nkf-utf8/nkf.c (push_broken_buf): 'c' is nkf_char.
+
+	* ext/nkf/nkf-utf8/nkf.c (push_broken_buf): enc is 0 or pointer.
+
+	* ext/nkf//nkf.c (options): type of option is unsigned char.
+
+Tue Apr 22 20:51:58 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* ext/nkf/nkf-utf8/nkf.c (z_conv): characters must be nkf_char.
+
+Tue Apr 22 19:23:05 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enumerator.c (enumerator_initialize): Remove an undocumented
+	  feature (passing a block to the constructor) that's broken.
+	  This is not what I intended.
+
+Tue Apr 22 17:54:05 2008  URABE Shyouhei  <shyouhei at ruby-lang.org>
+
+	* vm_core.h (exec_event_hooks): ``inline'' is a type modifier, not
+	a type itself.
+
+Tue Apr 22 16:24:27 2008  URABE Shyouhei  <shyouhei at ruby-lang.org>
+
+	* string.c (rb_enc_cr_str_buf_cat): do not use C++ comments.
+
+Tue Apr 22 16:23:53 2008  URABE Shyouhei  <shyouhei at ruby-lang.org>
+
+	* configure.in: use AC_USE_SYSTEM_EXTENSIONS.
+
+Tue Apr 22 16:23:16 2008  URABE Shyouhei  <shyouhei at ruby-lang.org>
+
+	* vm_evalbody.c (DECL_SC_REG): use __asm__ instead.
+
+Tue Apr 22 16:18:30 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* vm_evalbody.c (DECL_SC_REG): typo fixed.
+
+Tue Apr 22 15:25:04 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (struct timespec): needs time.h according to POSIX.
+
+Tue Apr 22 13:19:48 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* thread.c (rb_thread_stop_timer_thread): should clear
+	  timer_thread_id after stopping it.
+
+Tue Apr 22 13:12:58 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* thread.c (thread_join): remove the current thread from the join list
+	  of the target thread.
+
+Tue Apr 22 12:03:50 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* vm_insnhelper.c (vm_get_ev_const): search from the base klass if it
+	  is given.
+
+Tue Apr 22 09:58:13 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* ext/win32ole/win32ole.c: avoid warnings.
+
+Tue Apr 22 09:56:51 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* file.c (eaccess): workaround for recent msvcrt's behavior.
+	  [ruby-core:16460]
+
+Mon Apr 21 19:08:32 2008  Tanaka Akira  <akr at fsij.org>
+
+	* io.c (copy_stream_body): call rb_io_check_readable and
+	  rb_io_check_writable.
+
+Mon Apr 21 17:45:27 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* ext/dbm/dbm.c (fdbm_each_value, fdbm_each_key, fdbm_each_pair):
+	  GDBM#{each,each_pair,each_key,each_value}: Return an enumerator
+	  if no block is given.
+
+	* ext/gdbm/gdbm.c (fgdbm_each_value, fgdbm_each_key,
+	  fgdbm_each_pair): GDBM#{each,each_pair,each_key,each_value}:
+	  Return an enumerator if no block is given.
+
+	* ext/openssl/ossl_config.c (ossl_config_each):
+	  OpenSSL::Config#each: Return an enumerator if no block is given.
+
+	* ext/readline/readline.c (hist_each): Readline::HISTORY#each:
+	  Return an enumerator if no block is given.
+
+	* ext/sdbm/init.c (fsdbm_each_value, fsdbm_each_key,
+	  fsdbm_each_pair): SDBM#{each,each_pair,each_key,each_value}:
+	  Return an enumerator if no block is given.
+
+	* ext/stringio/stringio.c (strio_each_byte, strio_each):
+	  StringIO#{each,each_line,each_byte}: Return an enumerator if no
+	  block is given.
+
+	* ext/stringio/stringio.c (Init_stringio): Add #lines and #bytes,
+	  which are aliases to #each_line and #each_byte, respectively.
+
+	* ext/win32ole/win32ole.c (fole_each): WIN32OLE#each: Return an
+	  enumerator if no block is given.
+
+	* ext/zlib/zlib.c (rb_gzreader_each_byte, rb_gzreader_each):
+	  Zlib::GzipReader#{each,each_line,each_byte}: Return an
+	  enumerator if no block is given.
+
+	* ext/zlib/zlib.c (Init_zlib): Add Zlib::GzipReader#lines and
+	  #bytes, which are aliases to #each_line and #each_byte,
+	  respectively.
+
+Mon Apr 21 17:01:44 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* iseq.c (rb_iseq_compile_with_option): check if src is a string.
+	  [ruby-core:16453]
+
+Mon Apr 21 16:06:47 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* enumerator.c (enumerator_init): preserve the method name in ID.
+
+	* enumerator.c (enumerator_each): need not to call rb_to_id().
+
+	* enumerator.c (enumerator_with_index): ditto.
+
+Mon Apr 21 11:00:27 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* compile.c (defined_expr): capture exception during defined?
+	  evaluation.  a patch from wanabe <s.wanabe at gmail.com> in
+	  [ruby-dev:34461].  [ruby-core:16010]
+
+Mon Apr 21 10:06:26 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* time.c: should include <errno.h> to refer errno.
+
+Mon Apr 21 09:58:04 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* time.c (rb_strftime): check errno to detect strftime(3)'s error.
+	  this is workaround for recent version of MSVCRT.
+	  [ruby-dev:34456]
+
+Mon Apr 21 08:54:30 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* gc.c (ruby_xmalloc): use size_t for malloc argument instead of long.
+
+Sun Apr 20 21:00:21 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enumerator.c, include/ruby/ruby.h: Export rb_cEnumerator.
+
+Sun Apr 20 20:47:50 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enumerator.c: Resolve the method every time an enumeration
+	  method is run, not once when the enumerator is initialized as it
+	  was before, so that method_missing() and method (re)definition
+	  afterwards are both in effect; pointed out in: [ruby-core:16441]
+
+Sun Apr 20 15:11:00 2008  Tanaka Akira  <akr at fsij.org>
+
+	* io.c (copy_stream_rbuf_to_dst): removed.
+	  (copy_stream_fallback_body): don't bypass write method.
+	  (copy_stream_body): simplified.
+
+Sun Apr 20 15:01:25 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* vm_core.h (struct iseq_compile_data): moved label_no from
+	  new_label_body().
+
+	* compile.c (iseq_set_exception_table): allocates catch_table only
+	  when entries exist.
+
+	* compile.c (struct iseq_link_element, struct iseq_insn_data): made
+	  enum for debuggers.
+
+Sun Apr 20 14:44:45 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* compile.c (iseq_compile_each): fix for splat in when and rescue.
+	  a patch from wanabe <s.wanabe AT gmail.com> in [ruby-dev:34429].
+	  [ruby-core:14537]
+
+Sun Apr 20 13:55:37 2008  Tanaka Akira  <akr at fsij.org>
+
+	* io.c (copy_stream_fallback): write directly (bypassing write method)
+	  if possible.
+
+Sun Apr 20 12:49:03 2008  Tanaka Akira  <akr at fsij.org>
+
+	* io.c (copy_stream_fallback): read directly (bypassing readpartial
+	  method) if possible.
+
+Sun Apr 20 04:45:13 2008  Tanaka Akira  <akr at fsij.org>
+
+	* io.c (copy_stream_body): use readpartial and write method for
+	  non-IOs such as StringIO and ARGF.
+
+Fri Apr 18 20:57:33 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_array.rb: add tests to achieve over 95% test coverage
+	  of array.c.
+
+Fri Apr 18 17:37:48 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* gc.c (rb_gc_mark_locations): get rid of underflow.
+
+	* gc.c (mark_current_machine_context): check if the main thread stack
+	  position may shrink under the initialized position.  [ruby-core:16436]
+
+Thu Apr 17 22:20:52 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* enc/trans/utf_16_32.c (fun_so_to_utf_16be, fun_so_to_utf_16le): add
+	  parentheses to remove warnings of gcc.
+
+	* io.c (rb_io_getc): remove unused variables.
+
+	* compile.c (NODE_NEXT, NODE_REDO): remove unused labels.
+
+	* ext/nkf/nkf.c (rb_nkf_convert): remove unused variables.
+
+	* ext/syck/rubyext.c (syck_resolver_initialize,
+	  syck_resolver_detect_implicit, syck_emitter_emit): remove unused
+	  variables.
+
+Thu Apr 17 20:12:47 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_rubyoptions.rb (test_search): enable some assertions.
+
+	* test/ruby/test_rubyoptions.rb: flunk message in win32.
+
+Thu Apr 17 16:07:12 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* test/ruby/test_rubyoptions.rb (ruby): run in C locale.
+
+	* test/ruby/test_rubyoptions.rb (test_encoding): --encoding does not
+	  affect source code.
+
+Thu Apr 17 00:45:41 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_process.rb (test_rlimit_nofile): reset RLIMIT_NOFILE
+	  before exit (for gcov).
+
+	* test/ruby/test_rubyoptions.rb: new tests for option of ruby
+	  interpreter, to achieve over 95% test coverage of ruby.c.
+
+Wed Apr 16 02:40:44 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* ruby.c (process_options): preludes and parser need to run in safe
+	  level 0.  [ruby-dev:34407]
+
+Wed Apr 16 02:26:27 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* ruby.c (process_options): dln_find_file returns the pointer to a
+	  static buffer, so should copy it.  [ruby-dev:34409]
+
+Tue Apr 15 23:08:46 2008  Kouhei Sutou  <kou at cozmixng.org>
+
+	* lib/xmlrpc/client.rb: fix cookie handling. [ruby-dev:34403]
+
+	* test/xmlrpc/test_cookie.rb: add a test for the above fix.
+
+Tue Apr 15 19:20:14 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* io.c: #undef rb_argv moved before #define.
+
+Tue Apr 15 18:02:17 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* include/ruby/intern.h (rb_argv): replaced with rb_get_argv().
+	  [ruby-Bugs-19514]
+
+Tue Apr 15 17:10:59 2008  Kazuhiro NISHIYAMA  <zn at mbf.nifty.com>
+
+	* lib/net/http.rb, lib/net/smtp.rb, lib/net/pop.rb: update
+	  URLs of Japanese documents.
+
+Tue Apr 15 16:45:14 2008  Kazuhiro NISHIYAMA  <zn at mbf.nifty.com>
+
+	* test/ruby/test_symbol.rb (TestSymbol#test_to_proc): add tests.
+
+Tue Apr 15 15:38:02 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* misc/ruby-mode.el (ruby-encoding-map): added shift-jis for older
+	  versions.
+
+	* misc/ruby-mode.el (ruby-mode-set-encoding):
+	  coding-system-to-mime-charset is not a standard function.
+	  [carbon-emacs:795]
+	  fix for the case that magic comment exists but coding system is
+	  absent.
+
+	* misc/ruby-mode.el (ruby-mode): use write-contents-functions or
+	  write-contents-hooks for older versions.
+
+Tue Apr 15 07:21:21 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* complex.c (nucomp_div): [ruby-dev:34357]
+
+	* complex.c (nucomp_abs): use hypot.
+
+	* complex.c (nucomp_quo): do not force conversion.
+
+	* test/ruby/test_complex.rb: omitted some meaningless tests.
+
+Mon Apr 14 23:25:50 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_objectspace.rb: add a test for
+	  ObjectSpace.count_objects.
+
+Mon Apr 14 22:44:24 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* file.c (SET_EXTERNAL_ENCODING): avoid call rb_enc_check() on
+	  half-baked result string.
+
+	* re.c (rb_reg_search): make search reentrant.  [ruby-dev:34223]
+
+	* test/ruby/test_parse.rb (TestParse::test_global_variable):
+	  should preserve $& variable.
+
+Mon Apr 14 17:23:27 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* hash.c (rb_hash_delete_if, rb_hash_reject_bang, env_delete_if,
+	  env_reject_bang): Return an enumerator if no block is given.
+
+Mon Apr 14 14:33:59 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* compile.c, compile.h (compile_debug): made runtime option.
+
+	* debug.c (ruby_debug_print_indent): returns if debug_level exceeds
+	  the threshold.
+
+	* debug.c (ruby_debug_printf): printf to stderr.
+
+	* iseq.c (make_compile_option, make_compile_option_value): added
+	  debug_level option.
+
+	* vm_core.h (rb_compile_option_t): added debug_level.
+
+	* vm_core.h (struct iseq_compile_data): added node_level.
+
+Mon Apr 14 12:52:25 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* gc.c (Init_stack): use ruby_init_stack.  [ruby-dev:34350]
+
+	* gc.c (rb_objspace_t): packed globals.  [ruby-dev:34348]
+
+	* gc.c (finalizers): removed.  [ruby-dev:34349]
+
+Mon Apr 14 11:30:07 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* array.c (ary_new): new integer overflow check condition.
+	  suggested by TOYOFUKU Chikanobu <nobu_toyofuku at nifty.com> in
+	  [ruby-dev:34156].
+
+	* array.c (rb_ary_initialize): ditto.
+
+Mon Apr 14 00:51:40 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_parse.rb: add tests to achieve over 95% test coverage
+	  of parse.y.
+
+Sun Apr 13 23:53:58 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enum.c (enum_cycle): Make Enumerable#cycle do a finite loop when
+	  the number of cycles is specified.
+
+	* array.c (rb_ary_cycle): Ditto for Array#cycle.
+
+Sun Apr 13 18:52:27 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* thread_pthread.c (lock_func): should not check interrupts in
+	  blocking region.  [ruby-dev:34378]
+
+Sat Apr 12 12:41:49 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* eval.c (ruby_exec_node, ruby_run_node), ruby.c (process_options):
+	  use iseq instead of NODE.
+
+	* gc.c (source_filenames): removed.
+
+	* include/ruby/intern.h, parse.y (yycompile, parser_mark, parser_free,
+	  ripper_initialize): rb_source_filename() is no longer used.
+
+	* compile.c, compile.h (ERROR_ARGS), parse.y (node_newnode, fixpos,
+	  parser_warn, e_option_supplied, warn_unless_e_option, range_op,
+	  cond0): nd_file is no longer used.
+
+Sat Apr 12 12:17:31 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* prelude.rb (require_relative): move require_relative from
+	  lib/require_relative.rb.  [ruby-core:16356]
+
+	* lib/require_relative.rb: removed.
+
+Sat Apr 12 05:55:57 2008  Eric Hodel  <drbrain at segment7.net>
+
+	* lib/rubygems*, test/rubygems*:  Update to RubyGems 1.1.1 r1701.
+
+Sat Apr 12 03:13:38 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* file.c (file_expand_path): set external encoding.
+
+	* file.c (rb_file_s_basename, rb_file_s_dirname, rb_file_s_extname):
+	  copy encoding.
+
+Fri Apr 11 17:35:06 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* enum.c (count_i): modified to shut warning up.
+
+Fri Apr 11 17:25:09 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enum.c (count_i, count_iter_i, enum_count, enum_find_index):
+	  Reduce code.
+
+Fri Apr 11 17:06:01 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* enum.c (find_index_i): modified to shut warning up.
+
+	* enum.c (find_index_iter_i): ditto.
+
+Fri Apr 11 16:44:43 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* enum.c (enum_find_index): Add support for find_index(obj);
+	  [ruby-dev:34313].
+
+	* array.c (rb_ary_index): Define find_index as an alias to index.
+
+Fri Apr 11 16:42:33 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/yaml/store.rb (YAML::load): modified to support empty
+	  database.
+
+Fri Apr 11 08:05:12 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* marshal.c (w_object): add volatile to avoid potential GC bug.  a
+	  patch from Tomoyuki Chikanaga <chikanag at nippon-control-system.co.jp>
+	  in [ruby-dev:34311].
+
+Thu Apr 10 23:08:52 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/pstore.rb (PStore::dump, PStore::load): allow subclass
+	  overriding.  [ruby-dev:34305]
+
+	* lib/yaml/store.rb (YAML::Store::marshal_dump_supports_canonical_option?):
+	  add a method to support faster PStore.
+
+Thu Apr 10 20:36:45 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* misc/rdebug.el, misc/README: Remove rdebug.el as per request
+	  from the maintainer and mention the ruby-debug project at
+	  RubyForge in README; bug#19043.
+
+Thu Apr 10 19:41:00 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* eval.c (rb_f_loop): Mention StopIteration in the document.
+
+Thu Apr 10 19:23:55 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* array.c (rb_ary_pop_m, rb_ary_shift_m): Update documents for
+	  #pop() and #shift().
+
+	* array.c (rb_ary_slice_bang): Update document.  Assigning
+	  array[*args]= nil no longer removes elements.
+
+Thu Apr 10 16:58:44 2008  Tanaka Akira  <akr at fsij.org>
+
+	* marshal.c (w_object): TYPE_USERDEF assigns id for ivars first.
+	  [ruby-dev:34159] by nagachika.
+
+Thu Apr 10 15:03:47 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/generator.rb: removed obsolete library.  [ruby-core:16233]
+
+	* test/test_generator.rb: removed as well.  [ruby-dev:34306]
+
+	* lib/pstore.rb: replaced by Hongli Lai's faster version.
+
+Thu Apr 10 10:27:24 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* thread_pthread.c (native_sleep): sleep_cond is initialized at
+	  creation.  [ruby-Patches-19361].
+
+Wed Apr  9 14:43:26 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* thread.c (lock_func): optimized and checks for interrupt_flag.
+	  based on a patch from Sylvain Joyeux in [ruby-Patches-19361] and
+	  [ruby-Patches-19362].
+
+Wed Apr  9 12:12:01 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* test/ruby/test_thread.rb: new tests from Sylvain Joyeux in
+	  [ruby-Patches-19361].
+
+Tue Apr  8 21:36:40 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* thread.c (rb_mutex_sleep): ensures to re-acquire at waking up.
+	  [ruby-Patches-19361]
+
+Tue Apr  8 11:00:14 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/complex.rb: remove Math first before overwriting by CMath.
+
+Tue Apr  8 10:34:10 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* load.c (rb_require_safe): should check fname path after $SAFE is
+	  properly set.  [ruby-dev:34268]
+
+	* re.c (rb_reg_quote): should always copy the quoting string.
+	  [ruby-core:16235]
+
+Tue Apr  8 10:30:29 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* common.mk (prelude.c): depends on enc/prelude.rb.
+
+	* enc/prelude.rb: fixed initial library names.
+
+Tue Apr  8 03:39:26 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* load.c (rb_provided): check expanded path for relative path
+	  features, loading or loaded features are already expanded in 1.9.
+
+	* variable.c (rb_autoload_load): no needs to check if provided before
+	  rb_require_safe.  [ruby-dev:34266]
+
+Mon Apr  7 22:41:21 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* numeric.c: cancelled recent changes (except to remove rdiv).
+
+	* bignum.c: ditto.
+
+	* bignum.c: added rb_big_idiv.
+
+Mon Apr  7 15:51:31 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* encoding.c (enc_init_db): moved to enc/encdb.c.
+
+	* transcode.c (init_transcoder_table): moved to enc/trans/transdb.c.
+
+	* enc/depend (enc/encdb.o enc/trans/transdb.o): depend on
+	  corresponding headers.
+
+	* common.mk (COMMONOBJS): moved transcode.o from OBJS
+
+Mon Apr  7 12:26:32 2008  Koichi Sasada  <ko1 at atdot.net>
+
+	* bootstraptest/test_knownbug.rb: add a known-bug.
+
+Mon Apr  7 12:15:24 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* range.c (range_each_func): should not leave a variable
+	  uninitialized, which could cause SEGV.
+
+	* range.c (range_step): removed duplicated and unreachable code.
+
+Mon Apr  7 02:12:27 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (rb_str_intern): need not to check if tainted.
+	  [ruby-dev:34219]
+
+Sun Apr  6 09:45:00 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* dir.c (dir_tell): check if closed.  [ruby-core:16223]
+
+Sat Apr  5 23:17:20 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* lib/cmath.rb: new.
+
+	* lib/complex.rb: depends lib/cmath.rb.
+
+	* lib/rational.rb: added rdiv.
+
+	* complex.c: removed some math functions.
+
+Sat Apr  5 05:50:57 2008  Eric Hodel  <drbrain at segment7.net>
+
+	* lib/rdoc/parsers/parse_rb.rb: Fix uninitialized variable warnings.
+
+	* lib/rdoc/generator/html.rb: ditto.
+
+	* lib/rdoc/options.rb: Fix shadowed variable warning.
+
+	* lib/webrick/httprequest.rb: Fix redefined method warning.
+
+Sat Apr  5 02:13:52 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* bignum.c (rb_cmpint): moved from compar.c, to check bignum
+	  zero.
+
+Fri Apr  4 23:24:06 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* re.c (rb_memsearch_qs): wrong boundary condition.
+
+	* re.c (rb_memsearch_qs_utf8): ditto.
+
+Fri Apr  4 14:11:36 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* re.c (rb_memsearch_qs): wrong boundary condition.  a patch from
+	  wanabe <s.wanabe AT gmail.com> in [ruby-dev:34248].
+
+Fri Apr  4 05:57:11 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/net/pop.rb (Net::POP3::do_finish): clear @n_mails and
+	  @n_bytes as well.  [ruby-core:16144]
+
+Fri Apr  4 01:59:30 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* range.c (range_step): add step for each iteration if begin and
+	  end are numeric.  [ruby-core:15990]
+
+Fri Apr  4 00:42:26 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* bignum.c (Init_Bignum): rdiv method removed.  [ruby-dev:34242]
+
+	* complex.c (nucomp_quo): ditto.
+
+	* numeric.c (num_rdiv): ditto.
+
+	* rational.c (nurat_div): ditto.
+
+	* complex.c (nucomp_fdiv): fdiv implementation restored.
+
+	* numeric.c (num_quo): RDoc updated.
+
+Thu Apr  3 21:51:45 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* complex.c (nucomp_int_check): function for DRY real check.
+
+	* complex.c (nucomp_{add,sub,mul,div,expt}): use rb_num_coerce_bin().
+
+Thu Apr  3 19:59:42 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* insns.def (defineclass): check if cbase is a class or a module.
+	  [ruby-core:16118]
+
+Thu Apr  3 14:42:11 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* common.mk (INSNS): add insns_info.inc.
+
+	* common.mk (INSNS): make incs separately for nmake.
+
+Thu Apr  3 13:20:38 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* common.mk (endb.h, transdb.h, prelude.c): depend on $(PREP) and
+	  check if really changed.  [ruby-core:16102]
+
+	* Makefile.in, common.mk, configure.in, {win32,bcc32}/Makefile.sub
+	  (MINIOBJS, ARCHMINIOBJS): separated.
+
+Thu Apr  3 09:00:45 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* compile.c (iseq_set_sequence, iseq_insns_unification,
+	  insn_data_to_s_detail): constified.
+
+	* iseq.c (insn_operand_intern, ruby_iseq_disasm_insn): ditto.
+
+	* template/{insns_info,opt_sc,optunifs}.inc.tmpl: ditto.
+
+	* tool/instruction.rb (OptUnifsIncGenerator): ditto.
+
+Thu Apr  3 08:46:09 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* range.c (range_include): add RDoc to describe that comparison
+	  for numeric is done according magnitude of values.
+	  [ruby-core:15907]
+
+Wed Apr  2 22:29:35 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* rational.c (nurat_int_check): function for DRY integer check.
+
+	* numeric.c (num_rdiv): should always return rational number.
+
+	* rational.c (nurat_add, nurat_sub, nurat_mul, nurat_fdiv,
+	  nurat_cmp): use rb_num_coerce_bin().
+
+	* rational.c (nurat_division): does / and rdiv.
+
+	* .gdbinit (rp): no longer use rb_p().
+
+Wed Apr  2 06:52:31 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* .gdbinit (rp): supports rational and complex numbers.  it's
+	  cheating since it uses rb_p().
+
+Wed Apr  2 06:24:06 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* include/ruby/node.h: add new constants for rb_call()'s scope.
+
+	* eval.c (iterate_method): use CALL_* scope constant to specify
+	  proper scope value.
+
+	* eval.c (rb_each, rb_apply, rb_funcall, rb_funcall2, rb_funcall3):
+	  ditto.
+
+Tue Apr  1 21:19:41 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* rational.c: need to include <float.h> just once.
+
+Tue Apr  1 16:40:21 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* bignum.c (big2dbl): more precise conversion at edge cases.
+	  [ruby-dev:34195]
+
+Tue Apr  1 14:43:38 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in: get rid of empty expansion.
+
+	* configure.in: _setjmp is available but _longjmp is not on mingw.
+
+Tue Apr  1 09:41:22 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* {bcc,win}32/Makefile (config.h): need to define RUBY_SETJMP, etc.
+
+Tue Apr  1 07:31:58 2008  Eric Hodel  <drbrain at segment7.net>
+
+	* lib/rubygems* test/rubygems*: Import RubyGems 1.1.0.
+
+Tue Apr  1 03:20:40 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (RUBY_SETJMP, RUBY_LONGJMP, RUBY_JMP_BUF): prefers
+	  _setjmp over setjmp and sigsetjmp.  [ruby-core:16023]
+	  __builtin_setjmp cannot handle a variable.
+
+	* configure.in (--with-setjmp-type): new option to override the
+	  default rule in the above.
+
+	* eval_intern.h (ruby_setjmp, ruby_longjmp), gc.c (rb_setjmp),
+	  vm_core.h (rb_jmpbuf_t): use RUBY_SETJMP, RUBY_LONGJMP and
+	  RUBY_JMP_BUF.
+
+Tue Apr  1 01:55:52 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* lib/resolv.rb (Resolv::Config.default_config_hash): requires
+	  win32/resolv to use Win32::Resolv.  [ruby-dev:34138]
+
+Tue Apr  1 01:40:58 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* complex.c: adopted the ruby's style.
+
+	* rational.c: ditto.
+
+Tue Apr  1 00:17:35 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* rational.c: revert.
+
+Mon Mar 31 18:57:36 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* {bcc,win}32/Makefile.sub (config.h): define ssize_t.
+
+	* io.c (copy_stream_body): some platform don't have O_NOCTTY.
+
+Mon Mar 31 18:42:41 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in: check for ssize_t.  [ruby-dev:34184]
+
+Mon Mar 31 14:45:00 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* numeric.c (num_quo): should convert its operand to Rational.
+
+	* rational.c (string_to_r_strict): should raise TypeError.
+
+	* bignum.c (Init_Bignum): should not redefine Bignum#div.
+	  Numeric#div will do.  [ruby-dev:34066]
+
+Mon Mar 31 04:05:15 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* io.c (io_getc): set coderange while getting characters.
+
+Sun Mar 30 23:16:49 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* proc.c (proc_dup): should copy is_lambda attribute as well.
+	  [ruby-talk:296244]
+
+Sun Mar 30 15:33:29 2008  Tanaka Akira  <akr at fsij.org>
+
+	* io.c: IO.copy_stream implemented.  [ruby-dev:33843]
+
+	* thread.c (rb_fd_select): new function.
+
+	* configure.in (sys/sendfile.h): check the header file.
+	  (sendfile): check the function.
+	  (pread): check the function.
+
+Sat Mar 29 14:18:41 2008  Hidetoshi NAGAI  <nagai at ai.kyutech.ac.jp>
+
+	* ext/tk/*: full update Ruby/Tk to support Ruby(1.9|1.8) and Tc/Tk8.5.
+
+	* ext/tk/lib/tkextlib/tile.rb: [incompatible] remove TileWidgets'
+	  instate/state/identify method to avoid the conflict with standard
+	  widget options. Those methods are renamed to ttk_instate/ttk_state/
+	  ttk_identify (tile_instate/tile_state/tile_identify are available
+	  too). Although I don't recommend, if you really need old methods,
+	  please define "Tk::USE_OBSOLETE_TILE_STATE_METHOD = true" before
+	  "require 'tkextlib/tile'".
+
+	* ext/tk/lib/tkextlib/tile.rb: "Tk::Tile::__Import_Tile_Widgets__!"
+	  is obsolete. It outputs warning. To control default widget set,
+	  use "Tk.default_widget_set = :Ttk".
+
+	* ext/tk/lib/tk.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__ method and
+	  __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method are defined
+	  as module methods of TkConfigMethod. It may help users to wrap old
+	  Ruby/Tk scripts (use standard widgets) to force to use Ttk widgets.
+	  Ttk widgets don't have some options of standard widgets which are
+	  control the view of widgets. When set ignore-mode true, configure
+	  method tries to ignore such unknown options with no exception.
+	  Of course, it may raise other troubles on the GUI design.
+	  So, those are a little danger methods.
+
+	* ext/tk/lib/tk/itemconfig.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__
+	  method and __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method
+	  are defined as module methods of TkItemConfigMethod as the same
+	  purpose as TkConfigMethod's ones.
+
+	* ext/tk/sample/ttk_wrapper.rb: A new example. This is a tool for
+	  wrapping old Ruby/Tk scripts (which use standard widgets) to use
+	  Ttk (Tile) widgets as default.
+
+	* ext/tk/sample/tkextlib/tile/demo.rb: use ttk_instate/ttk_state
+	  method instead of instate/state method.
+
+	* ext/tk/lib/tk/root, ext/tk/lib/tk/namespace.rb,
+	  ext/tk/lib/tk/text.rb, ext/tk/lib/tkextlib/*: some 'instance_eval's
+	  are replaced to "instance_exec(self)".
+
+	* ext/tk/lib/tk/event.rb: bug fix on KEY_TBL and PROC_TBL (?x is not
+	  a character code on Ruby1.9).
+
+	* ext/tk/lib/tk/variable.rb: support new style of operation argument
+	  on Tcl/Tk's 'trace' command for variables.
+
+	* ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget: bug fix
+
+	* ext/tk/sample/demos-jp/textpeer.rb,
+	  ext/tk/sample/demos-en/textpeer.rb: new widget demo.
+
+	* ext/tk/tcltklib.c: decrease SEGV troubles (probably)
+
+	* ext/tk/lib/tk.rb: remove Thread.critical access if Ruby1.9
+
+	* ext/tk/lib/tk/multi-tk.rb: support Ruby1.9 (probably)
+
+	* ext/tk/lib/tkextlib/tile.rb: add method to define Tcl/Tk command
+	  to make Tcl/Tk theme sources (based on different version of Tile
+	  extension) available.
+	  (Tk::Tile::__define_LoadImages_proc_for_compatibility__)
+
+	* ext/tk/lib/tk.rb, ext/tk/lib/tk/wm.rb: support dockable frames
+	  (Tcl/Tk8.5 feature). 'wm' command can treat many kinds of widgets
+	  as toplevel widgets.
+
+	* ext/tk/lib/tkextlib/tile/style.rb: ditto.
+	  (Tk::Tile::Style.__define_wrapper_proc_for_compatibility__)
+
+	* ext/tk/lib/tk/font.rb: add actual_hash and metrics_hash to get
+	  properties as a hash. metrics_hash method returns a boolean value
+	  for 'fixed' option. But metrics method returns numeric value
+	  (0 or 1) for 'fixed' option, because of backward compatibility.
+
+	* ext/tk/lib/tk/timer.rb: sometimes fail to set callback procedure.
+
+	* ext/tk/lib/tk.rb: add Tk.sleep and Tk.wakeup method. Tk.sleep
+	  doesn't block the eventloop. It will be better to use the method
+	  in event callbacks.
+
+	* ext/tk/sample/tksleep_sample.rb: sample script about Tk.sleep.
+
+Thu Mar 27 20:44:22 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* complex.c (f_lcm): removed.
+
+	* rational.c (rb_lcm, rb_gcdlcm): added.
+
+	* lib/complex.rb (gcd, lcm, gcdlcm): removed.
+
+	* lib/rational.rb (gcd, lcm, gcdlcm): ditto.
+
+Wed Mar 26 18:11:26 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* variable.c (rb_mod_constants): rdoc updated.  a patch from
+	  Florian Gilcher <flo AT andersground.net> in [ruby-core:16009].
+
+Wed Mar 26 00:55:28 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_rand.rb: add tests to achieve over 95% test coverage
+	  of random.c.
+
+Wed Mar 26 00:28:55 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* test/ruby/test_rational.rb: add tests to achieve over 90% test
+	  coverage of rational.c.
+
+	* test/ruby/test_complex.rb: ditto for complex.c.
+
+Tue Mar 25 19:34:05 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* bootstraptest/test_knownbug.rb: add tests.  [ruby-dev:34128]
+
+Tue Mar 25 19:09:04 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* array.c (ary_new): fix size check.  [ruby-dev:34123]
+
+	* array.c (rb_ary_take, rb_ary_drop): check negative size and use
+	  NUM2LONG instead of FIX2LONG.  [ruby-dev:34123]
+
+	* enum.c (enum_take, enum_drop): check negative size.
+
+	* test/ruby/test_array.rb: add tests for above.
+
+Tue Mar 25 16:32:56 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* ruby.c (proc_options): checks if the word is empty.
+
+	* ruby.c (process_options): typo fixed.  [ruby-dev:34122]
+
+Tue Mar 25 15:26:30 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* compile.c (defined_expr): false short-circuit destination label may
+	  be needed.  [ruby-talk:295296]
+
+	* compile.c (iseq_compile_each): put nil if false short-circuit is
+	  created.
+
+	* compile.c (compile_massign_opt): no need to use alloca.
+
+Mon Mar 24 19:23:52 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* parse.y (debug_lines): Always prepare a new array for each
+	  file's SCRIPT_LINES__ storage, instead of appending source lines
+	  every time a file is re-loaded; submitted by Rocky Bernstein in
+	  #18517.
+
+Mon Mar 24 10:25:54 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in: sitearch should use target_cpu.  [ruby-core:15986]
+
+Sun Mar 23 02:51:57 2008  Tanaka Akira  <akr at fsij.org>
+
+	* process.c (rlimit_resource_value): use NUM2RLIM.
+
+Sun Mar 23 02:28:01 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* complex.c: fixed. [ruby-dev:34109]
+
+	* rational.c: ditto.
+
+Fri Mar 21 21:32:25 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c (rb_f_gets, rb_f_readline, rb_f_readlines): delegates to ARGF
+	  as well as puts and putc.  [ruby-dev:34100]
+
+Fri Mar 21 21:26:52 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* lib/resolv.rb (Resolv::Hosts): should not use win32/resolv on cygwin.
+	  [ruby-dev:29945], [ruby-dev:34095]
+
+	* lib/win32/registry.rb (Win32::Registry.expand_environ): try upcased
+	  name too for cygwin.  [ruby-dev:29945]
+
+	* lib/win32/resolv.rb (Win32::Resolv.get_hosts_path): use expand_path.
+
+Fri Mar 21 21:10:00 2008  Akinori MUSHA  <knu at iDaemons.org>
+
+	* lib/ipaddr.rb: Say that I am the current maintainer.
+
+	* lib/set.rb: Ditto.
+
+	* lib/shellwords.rb: Ditto.
+
+	* ext/syslog/syslog.txt: Ditto.
+
+Fri Mar 21 09:24:28 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* instruby.rb (open_for_install): write block result and rewrite only
+	  if changed from existing file.
+
+Fri Mar 21 08:29:33 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* rational.c (nurat_to_f): rearrangement.
+
+Fri Mar 21 06:44:59 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* rational.c (nurat_to_f): C99.
+
+Fri Mar 21 01:40:27 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* complex.c (nucomp_sub, nucomp_expt): call corresponding functions.
+
+Fri Mar 21 01:21:43 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* missing/tgamma.c: include config.h before math.h.  [ruby-dev:34075]
+
+Thu Mar 20 21:46:33 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c (argf_getline): use receiver.
+
+Thu Mar 20 21:20:19 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* rational.c: some improvements (include Shin-ichiro HARA's
+	  effort).
+
+	* complex.c: some improvements.
+
+	* test/ruby/test_rational2.rb: new.
+
+Thu Mar 20 00:21:12 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c (argf_initialize_copy): get rid of segfault.
+
+	* io.c (argf_tell, argf_seek_m, argf_set_pos, argf_rewind,
+	  argf_fileno, argf_to_io, argf_eofl, argf_getc, argf_getbyte,
+	  argf_readchar, argf_readbyte, argf_each_line): use receiver.
+
+Wed Mar 19 23:52:41 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c (rb_io_putc, rb_io_puts): output directly if the receiver is
+	  rb_stdout to get rid of infinite recursion.  [ruby-dev:34059]
+
+Wed Mar 19 22:27:41 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* rational.c: added rb_gcd.
+
+	* complex.c: use rb_gcd.
+
+Wed Mar 19 18:37:00 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* complex.c: revert.
+
+	* rational.c: revert.
+
+Wed Mar 19 17:31:20 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* eval_intern.h (TH_EXEC_TAG): need not to FLUSH_REGISTER_WINDOWS.
+	  [ruby-core:15871], [ruby-dev:34088]
+
+Wed Mar 19 14:53:03 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* complex.c (nucomp_to_s, nucomp_inspect): get rid of making
+	  unnecessary intermediate objects.
+
+	* complex.c (make_patterns, string_to_c): do not treat successive
+	  underscores as a part of numeric like as literals.  [ruby-dev:34085]
+
+	* rational.c (make_patterns, string_to_r): ditto.
+
+Wed Mar 19 14:36:40 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* bignum.c (rb_cstr_to_inum): treat successive underscores as
+	  nondigit.  [ruby-dev:34089]
+
+Wed Mar 19 14:08:47 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* encoding.c (enc_check_encoding): should not load autoloaded encoding
+	  directly, instead use rb_enc_find_index() which deal with alias and
+	  replica.  [ruby-core:15957]
+
+Wed Mar 19 11:49:47 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* regint.h (include): include ruby.h instead of defines.h and config.h.
+
+Wed Mar 19 10:17:12 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* regint.h (CHECK_INTERRUPT_IN_MATCH_AT): add interrupt check
+	  during match.  [ruby-talk:295002]
+
+Tue Mar 18 16:24:53 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* parse.y (literal_concat_gen): bail out at different encoding.
+
+Tue Mar 18 04:00:27 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* re.c (rb_memsearch_ss): simple shift search.
+
+	* re.c (rb_memsearch_qs): quick search.
+
+	* re.c (rb_memsearch_qs_utf8): quick search for UTF-8 string.
+
+	* re.c (rb_memsearch_qs_utf8_hash): hash functions for above.
+
+	* re.c (rb_memsearch): use above functions.
+
+	* string.c (rb_str_index): give enc to rb_memsearch.
+
+	* include/ruby/intern.h (rb_memsearch): move to encoding.h.
+
+	* include/ruby/encoding.h (rb_memsearch): move from intern.h.
+
+	* common.mk (PREP): add dependency.
+
+Mon Mar 17 22:23:54 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* array.c (rb_ary_take, rb_ary_take_while, rb_ary_drop,
+	  rb_ary_drop_while): new methods. [ruby-dev:34067]
+
+	* test/ruby/test_array.rb: add tests for above.
+
+Mon Mar 17 17:11:13 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* misc/ruby-mode.el (ruby-mode): should use `run-mode-hooks' instead
+	  of calling `run-hooks' directly to run the mode hook.  patch from
+	  Chiyuan Zhang <pluskid AT gmail.com> in [ruby-core:15915]
+
+Mon Mar 17 16:41:08 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in: unset GREP_OPTIONS.  [ruby-core:15918]
+
+Sun Mar 16 18:07:07 2008  Martin Duerst  <duerst at it.aoyama.ac.jp>
+
+	* enc/trans/utf_16_32.c: bug fix (some invalid UTF-8 sequences
+	  were legal)
+
+	* test/ruby/test_transcode.rb: test for above bug
+
+Sun Mar 16 17:28:07 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* common.mk (LIBRUBY_SO): add dependency to $(BUILTIN_ENCOBJS).
+
+Sun Mar 16 08:51:41 2008  Tadayoshi Funaba  <tadf at dotrb.org>
+
+	* include/ruby/intern.h: added some declarations.
+
+	* include/ruby/ruby.h: ditto.
+
+	* common.mk: added some entries.
+
+	* configure.in: added a check for signbit.
+
+	* lib/complex.rb: nearly all of core definitions have been removed.
+
+	* lib/rational.rb: ditto.
+
+	* lib/mathn.rb: some trivial adjustments.
+
+	* complex.c: new.
+
+	* rational.c: ditto.
+
+	* numeric.c (flo_{quo,rdiv}, fix_fdiv): added.
+
+	* numeric.c ({num,int}_{numerator,denominator}): ditto.
+
+	* bignum.c (rb_big_fdiv): ditto.
+
+	* numeric.c (fix_{quo,pow}): now may yield rational number.
+
+	* bignum.c (rb_big_{quo,pow}): ditto.
+
+	* numeric.c (rb_{int,flo}_induced_from): now can accept rational.
+
+	* gc.c (gc_mark_children, obj_free): now detects complex and rational.
+
+	* inits.c (rb_call_inits): now calls Init_{Complex,Rational}.
+
+	* test/ruby/test_complex.rb: new.
+
+	* test/ruby/test_rational.rb: ditto.
+
+Sat Mar 15 17:48:48 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* encoding.c (rb_enc_associate_index): pass unnecessary enc_capable().
+
+	* string.c (rb_str_cmp): reduce invocation of rb_enc_compatible().
+
+Fri Mar 14 17:04:43 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* include/ruby/ruby.h (inttypes.h): includes always if available.
+
+	* string.c, ext/digest/defs.h: moved inttypes.h to ruby.h.
+
+Fri Mar 14 16:59:23 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (RUBY_LIB_PREFIX): fix for prefix.
+
+Fri Mar 14 16:35:11 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/cgi.rb (CGI::Cookie::initialize): performance patch from
+	  Makoto Kuwata <kwa at kuwata-lab.com> in [ruby-dev:34048].
+
+Fri Mar 14 15:49:05 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (RUBY_LIB_PREFIX): use libdir.
+
+Fri Mar 14 14:24:15 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* ext/digest/defs.h: inttypes.h is still needed.
+
+Fri Mar 14 11:34:12 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* {bcc,win}32/Makefile.sub: follow below changes.
+
+Fri Mar 14 11:24:30 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* misc/ruby-mode.el (ruby-encoding-map, ruby-use-encoding-map): added
+	  to customize.
+
+Fri Mar 14 10:37:15 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* configure.in (int8_t, uint8_t,  int16_t,  uint16_t int32_t,
+	  uint32_t int64_t, uint64_t, int128_t, uint128_t,
+	  intptr_t, uintptr_t): check if defined.
+
+	* win32/Makefile.sub: follow configure.in.
+
+	* ext/digest/defs.h: remove checks for uint8_t, uint32_t and uint64_t.
+
+Fri Mar 14 10:12:29 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (RUBY_CHECK_VARTYPE): should not indent preprocessor
+	  directives.
+
+Fri Mar 14 10:03:59 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* string.c (UNALIGNED_WORD_ACCESS): IA64 cannot access unaligned word.
+
+Thu Mar 13 21:00:50 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* array.c (rb_ary_slice_bang): should not use rb_ary_subseq()
+	  which shares internal pointer.  splice modifies the receiver
+	  right after subseq.  [ruby-dev:34005]
+
+	* bootstraptest/test_struct.rb: some test moved from test to shut
+	  warning up.
+
+Thu Mar 13 19:42:43 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* {bcc,win}32/Makefile.sub (config.h): define uint32_t.
+
+Thu Mar 13 14:14:19 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* trunk/configure.in (AC_CHECK_HEADERS): stdint.h is not needed to
+	  check.
+
+	* trunk/configure.in (rb_cv_type_uint32_t): unquoted.  [ruby-dev:34030]
+
+	* trunk/string.c (hash): use inttypes.h instead of stdint.h.
+
+Thu Mar 13 10:42:46 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* numeric.c (fix_divmod): should return integer division.  [ruby-dev:34006]
+
+	* enum.c (zip_ary): wrong boundary condition.
+
+	* test/ruby/test_numeric.rb (TestNumeric::test_num2long): bit-and
+	  should not raise RangeError.
+
+Thu Mar 13 03:12:48 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/irb/cmd/help.rb: should be updated for new ri structure.
+	  [ruby-core:15825]
+
+	* lib/rdoc/ri/driver.rb (RDoc::initialize): allow options to be optional.
+
+	* lib/rdoc/ri/driver.rb (RDoc::class_cache): map_dirs may be
+	  empty.
+
+	* lib/rdoc/ri/driver.rb (RDoc::get_info_for): revive get_info_for
+	  method.  maybe broken.
+
+	* lib/rdoc/ri/util.rb (RDoc::initialize): should not use RiError
+	  no more.
+
+Thu Mar 13 01:45:25 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* configure.in (stdint.h): check if presence.
+
+	* configure.in (uint32_t): check if defined.
+
+	* string.c (hash): fix for portability.  [ruby-dev:34020]
+
+Wed Mar 12 17:33:34 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* object.c (rb_cstr_to_dbl): fix for a mere underscore.
+
+Wed Mar 12 14:47:07 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* eval_intern.h (rb_thread_raised_set): use generic flags.
+
+	* eval.c (rb_longjmp): clear all raised flags.
+
+	* eval.c (stack_check): leave clearing flag to rb_longjmp.
+
+	* gc.c (rb_memerror): use thread raised flag instead of static flag.
+
+Tue Mar 11 23:38:39 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* array.c (rb_ary_combination): argument check before creating
+	  Enumerator.
+
+	* array.c (rb_ary_permutation): ditto.
+
+	* enum.c (enum_zip): optimize if all arguments are arrays.
+
+Tue Mar 11 19:48:09 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* numeric.c (fix_coerce): try conversion before type check.
+	  [ruby-core:15838]
+
+Tue Mar 11 12:39:53 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* common.mk (clean-local): WINMAINOBJ is Windows specific.
+
+Tue Mar 11 10:19:10 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (hash): replaced by MurmurHash described in
+	  <http://murmurhash.googlepages.com/>.
+
+Tue Mar 11 09:52:49 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* string.c (rb_str_comparable): empty strings in any encoding are
+	  compatible each other.
+
+Tue Mar 11 00:46:29 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* ruby.c (usage): remove some unimportant lines to fit -h message
+	  in a page.  [ruby-dev:34018]
+
+Mon Mar 10 17:11:00 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* eval.c (rb_f_local_variables): local_variables should return an
+	  array of symbols.  [ruby-dev:34008]
+
+	* vm.c (collect_local_variables_in_env): ditto.
+
+Mon Mar 10 15:53:48 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* version.c (MKSTR): make US-ASCII.  [ruby-dev:34010]
+
+Mon Mar 10 02:08:21 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* string.c (rb_str_index): if t == s + pos, the character beginning
+	  from s + pos is valid.
+
+Sun Mar  9 13:51:21 2008  Eric Hodel  <drbrain at segment7.net>
+
+	* lib/rdoc/generator.rb: Restore missing line to #params.  Patch by
+	  Lincoln Stoll <lstoll at lstoll.net>
+
+Sun Mar  9 09:52:00 2008  Eric Hodel  <drbrain at segment7.net>
+
+	* lib/rdoc/code_objects.rb: Remove debugging Kernel#p.  Patch by
+	  Lincoln Stoll <lstoll at lstoll.net>
+	* lib/rdoc/generator/html.rb: Fully qualify AllReferences.  Patch by
+	  Lincoln Stoll <lstoll at lstoll.net>
+	* lib/rdoc/ri/writer.rb: Fix 1.8 backwards compatibility.
+
+Sat Mar  8 18:50:57 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* file.c (isdirsep): backslash is valid path separator on cygwin too.
+
+Sat Mar  8 06:53:48 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* string.c (search_nonascii): Use VALUE instead of unsigned long
+	  because VALUE can be the fastest unsigned integer type.
+	  On LLP64 unsigned long isn't the fastest.
+	* string.c (str_strlen): ditto.
+	* string.c (str_utf8_nth): ditto.
+	* string.c (count_utf8_lead_bytes_with_ulong): ditto.
+
+	* string.c (count_utf8_lead_bytes_with_word): renamed.
+
+Fri Mar  7 21:27:43 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* bignum.c: fix indent.
+
+Fri Mar  7 21:12:19 2008  Yusuke Endoh  <mame at tsg.ne.jp>
+
+	* bignum.c (power_cache_init, power_cache_get_power0, Init_Bignum):
+	  delayed initializing power cache per base.  [ruby-dev:34003]
+
+Fri Mar  7 20:30:05 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* cont.c (cont_restore_0): fixed typo.  [ruby-core:15821]
+
+Fri Mar  7 19:56:10 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* lib/mkmf.rb: rdoc added.  [ruby-Patches-9762]
+
+Thu Mar  6 17:26:53 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* sprintf.c (rb_str_format): space flag is in effect for Inf/NaN too.
+	  [ruby-dev:34002]
+
+Thu Mar  6 15:44:20 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* sprintf.c (rb_str_format): casting double to long is undefined
+	  if the integer part of double is out of the range of long.
+
+Thu Mar  6 15:11:40 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* sprintf.c (rb_str_format): ignore 0 flag for NaN and Inf.
+	  [ruby-dev:33994]
+
+Thu Mar  6 15:05:25 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
+
+	* {bcc32,win32}/Makefile.sub (RUNRUBY): use $(PROGRAM) instead of
+	  ruby$(EXEEXT).
+	  suggested by KIMURA Koichi <kimura.koichi at canon.co.jp>.
+	  [ruby-dev:34000]
+
+Thu Mar  6 14:46:08 2008  Tanaka Akira  <akr at fsij.org>
+
+	* missing/lgamma_r.c (loggamma): return 0 for 1 and 2.
+
+	* test/ruby/test_math.rb: accept errors by functions under missing/.
+
+Thu Mar  6 14:29:44 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* transcode.c (rb_str_transcode_bang): set coderange.
+
+	* transcode.c (rb_str_transcode): use rb_str_transcode_bang.
+
+Thu Mar  6 14:00:10 2008  Tanaka Akira  <akr at fsij.org>
+
+	* include/ruby/missing.h (cbrt): add declaration.
+
+Thu Mar  6 11:14:14 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* misc/ruby-mode.el (ruby-add-log-current-method): use ruby style
+	  method name format.
+
+Thu Mar  6 11:12:29 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* sprintf.c (rb_str_format): no need of loop.
+
+Thu Mar  6 08:30:42 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* object.c (rb_mod_freeze): call rb_class_name() directly.
+	  [ruby-core:15802]
+
+Thu Mar  6 04:32:06 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* string.c (count_utf8_lead_bytes_with_ulong): fix shift size.
+	  [ruby-dev:33993]
+
+	* string.c (str_utf8_nth) fix wrong counting.
+
+Thu Mar  6 00:34:00 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* sprintf.c (rb_str_format): size_t returned from strlen() can be
+	  unsigned.
+
+Thu Mar  6 00:31:39 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* struct.c (make_struct): preserve encoding of struct name.
+
+Wed Mar  5 22:49:20 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* string.c (is_utf8_lead_byte, count_utf8_lead_bytes_with_ulong):
+	  defined for UTF-8 optimization.
+
+	* string.c (str_strlen): use is_utf8_lead_byte and
+	  count_utf8_lead_bytes_with_ulong.
+
+	* string.c (str_utf8_nth) ditto.
+
+Wed Mar  5 17:53:01 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* file.c (rb_file_flock): returns false on EAGAIN if non-blocking.
+	  [ruby-core:15795]
+
+Wed Mar  5 17:43:43 2008  Martin Duerst  <duerst at it.aoyama.ac.jp>
+
+	* transcode.c (transcode_loop): Adjusted detection of invalid
+	  (ill-formed) UTF-8 sequences. Fixing potential security issue, see
+	  http://www.unicode.org/versions/Unicode5.1.0/#Notable_Changes.
+
+	* test/ruby/test_transcode.rb: Added two tests for above fix.
+
+Wed Mar  5 14:00:49 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* numeric.c (fix_to_s): avoid rb_scan_args() when no argument
+	  given.
+	* bignum.c (rb_big_to_s): ditto.
+	* enum.c (enum_first): ditto.
+	* eval_jump.c (rb_f_catch): ditto.
+	* io.c (rb_obj_display): ditto.
+	* class.c (rb_obj_singleton_methods): ditto.
+	* object.c (rb_class_initialize): ditto.
+	* random.c (rb_f_srand): ditto.
+	* range.c (range_step): ditto.
+	* re.c (rb_reg_s_last_match): ditto.
+	* string.c (rb_str_to_i): ditto.
+	* string.c (rb_str_each_line): ditto.
+	* string.c (rb_str_chomp_bang): ditto.
+	* string.c (rb_str_sum): ditto.
+
+	* string.c (str_modifiable): declare inline.
+	* string.c (str_independent): ditto.
+
+Wed Mar  5 11:50:32 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/debug.rb: require 'continuation' to implement "restart"
+	  command.  [ruby-dev:33992]
+
+	* lib/debug.rb (Context::debug_command): remove local variable
+	  shadowing to shut up warnings.  [ruby-dev:33992]
+
+	* lib/debug.rb (Context::display_list): ditto.
+
+	* lib/debug.rb (Context::resume): ditto.
+
+	* lib/debug.rb (Context::get_thread): no longer use #index for Hash.
+
+Tue Mar  4 21:35:59 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* lib/irb.rb (IRB::Irb::eval_input): SyntaxError should not be
+	  considered as IRB bug.  [ruby-dev:33991]
+
+	* lib/irb/workspace.rb (IRB::WorkSpace::filter_backtrace): should
+	  filter 'irb.rb' as well for context mode 2 and 3.
+
+Tue Mar  4 19:10:43 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* hash.c (rb_hash_aset): should not copy key string when
+	  compare_by_identity is set.  [ruby-dev:33604]
+
+	* hash.c (hash_equal): two hash tables are different when internal
+	  comparison table differ.  [ruby-dev:33989]
+
+Tue Mar  4 16:29:06 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* parse.y (parser_yylex): disallow non digits '0o' expression.
+
+Tue Mar  4 14:35:12 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* io.c (open_key_args): use rb_io_open_with_args instead of rb_f_open.
+	  [ruby-core:15763]
+
+Tue Mar  4 13:41:46 2008  Tanaka Akira  <akr at fsij.org>
+
+	* gc.c (add_heap): fix previous change.  [ruby-dev:33988]
+
+Tue Mar  4 10:21:03 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* gc.c (add_heap): use binary search to find the place to insert the
+	  new heap slot.  [ruby-dev:33983]
+
+Tue Mar  4 05:30:31 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+
+	* io.c (open_key_args): use rb_io_open instead of rb_f_open.
+	  [ruby-core:15746]
+
+Mon Mar  3 23:28:37 2008  GOTOU Yuuzou  <gotoyuzo at notwork.org>
+
+	* lib/webrick/httpservlet/filehandler.rb: should normalize path
+	  separators in path_info to prevent directory traversal
+	  attacks on DOSISH platforms.
+	  reported by Digital Security Research Group [DSECRG-08-026].
+
+	* lib/webrick/httpservlet/filehandler.rb: pathnames which have
+	  not to be published should be checked case-insensitively.
+
+Mon Mar  3 17:25:45 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* gc.c (add_heap): sort heaps array in ascending order to use
+	  binary search.
+
+	* gc.c (is_pointer_to_heap): use binary search to identify object
+	  in heaps.  works better when number of heap segments grow big.
+
+Mon Mar  3 17:15:09 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
+
+	* re.c (rb_reg_regsub): remove too strict encoding check.
+	  [ruby-dev:33966]
+
+Mon Mar  3 16:14:24 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* hash.c (rb_any_hash): shrinks all results in Fixnum range.
+	  [ruby-core:15713]
+
+Sun Mar  2 23:03:59 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* io.c (rb_io_ungetc): reduce redundant call.
+
+Sun Mar  2 10:13:12 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* ruby.c (load_file): parse shebang in us-ascii.  a patch from
+	  sheepman <sheepman AT sheepman.sakura.ne.jp> in [ruby-dev:33955]
+
+Sun Mar  2 00:08:10 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
+
+	* object.c (rb_cstr_to_dbl): check for successive underscores.
+	  [ruby-dev:33952]
+
 Sat Mar  1 17:59:01 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
 	* io.c (struct argf): packed ARGF stuffs.
@@ -41,7 +2702,7 @@
 	* thread.c (remove_event_hook): should not access freed memory.
 	  [ruby-dev:31820]
 
-Sat Mar 01 10:31:19 2008  NARUSE, Yui  <naruse at ruby-lang.org>
+Sat Mar  1 10:31:19 2008  NARUSE, Yui  <naruse at ruby-lang.org>
 
 	* io.c (read_all, rb_io_getline_fast): encoding is io_input_encoding.
 
@@ -77,7 +2738,7 @@
 Fri Feb 29 23:14:38 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* test/ruby/test_m17n_comb.rb (TestM17NComb::test_str_chomp): test
-	  updated. 
+	  updated.
 
 Fri Feb 29 20:58:09 2008  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
@@ -137,11 +2798,11 @@
 	* ext/tk/lib/tk.rb: forgot to update RELEASE_DATE
 
 	* ext/tk/lib/tk.rb, ext/tk/lib/tk/text.rb,
-	  ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb: remove adhoc check 
-	  of Ruby's features (use existence of some classes instead of 
+	  ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb: remove adhoc check
+	  of Ruby's features (use existence of some classes instead of
 	  comparing with RUBY_VERSION)
 
-	* ext/tk/lib/tk/root.rb, ext/tk/lib/tk/autoload.rb: make TkRoot 
+	* ext/tk/lib/tk/root.rb, ext/tk/lib/tk/autoload.rb: make TkRoot
 	  (Tk::Root) unswitchable
 
 	* ext/tk/lib/multi-tk.rb: partial bug fix (still not work!!)
@@ -193,13 +2854,13 @@
 
 Thu Feb 28 11:19:51 2008  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
-	* string.c (rb_str_reverse_bang): removed unsed variables.
+	* string.c (rb_str_reverse_bang): removed unused variables.
 
 	* include/ruby/encoding.h (rb_str_coderange_scan_restartable): added
 	  prototype.
 
 	* string.c (rb_str_coderange_scan_restartable, rb_str_times): removed
-	  unsed variables.
+	  unused variables.
 
 	* string.c (rb_str_reverse_bang): ditto
 
@@ -207,29 +2868,29 @@
 
 Thu Feb 28 03:03:32 2008  Hidetoshi NAGAI  <nagai at ai.kyutech.ac.jp>
 
-	* ext/tk/lib/tk.rb, ext/tk/lib/*: make default widget set 
-	  switchable between Tk (standard Tcl/Tk widget set) and 
-	  Ttk (Tile). Initial default widget set is Tk. Now, toplevel 
-	  widget classes are removed and defined as aliases. 
-	  For example, "TkButton" is an alias of the "Tk::Button" class. 
-	  Those aliases are replaced when switching default widget set. 
-	  "Tk.default_widget_set=" is the method for switching default 
-	  widget set. "Tk.default_widget_set = :Ttk" defines Ttk (Tile) 
-	  widget set as default. It means that "TkButton" denotes 
-	  "Tk::Tile::Button" class. And then, "TkButton.new" creates 
-	  a Tk::Tile::Button widget. Of course, you can back to use 
-	  standard Tk widgets as the default widget set by calling 
-	  "Tk.default_widget_set = :Tk", whenever you want. Based on 
-	  thie feature, you can use Ttk widget styling engine on your 
-	  old Ruby/Tk application without modifying its source, if you 
-	  don'tuse widget options unsupported on Ttk widgets (At first, 
-	  call "Tk.default_widget_set = :Ttk", and next load and run 
-	  your application). 
+	* ext/tk/lib/tk.rb, ext/tk/lib/*: make default widget set
+	  switchable between Tk (standard Tcl/Tk widget set) and
+	  Ttk (Tile). Initial default widget set is Tk. Now, toplevel
+	  widget classes are removed and defined as aliases.
+	  For example, "TkButton" is an alias of the "Tk::Button" class.
+	  Those aliases are replaced when switching default widget set.
+	  "Tk.default_widget_set=" is the method for switching default
+	  widget set. "Tk.default_widget_set = :Ttk" defines Ttk (Tile)
+	  widget set as default. It means that "TkButton" denotes
+	  "Tk::Tile::Button" class. And then, "TkButton.new" creates
+	  a Tk::Tile::Button widget. Of course, you can back to use
+	  standard Tk widgets as the default widget set by calling
+	  "Tk.default_widget_set = :Tk", whenever you want. Based on
+	  the feature, you can use Ttk widget styling engine on your
+	  old Ruby/Tk application without modifying its source, if you
+	  don't use widget options unsupported on Ttk widgets (At first,
+	  call "Tk.default_widget_set = :Ttk", and next load and run
+	  your application).
 	  This is one step for supporting Tcl/Tk8.5 features.
 
 Wed Feb 27 22:55:42 2008  NARUSE, Yui  <naruse at ruby-lang.org>
 
-	* string.c (rb_str_coderange_scan_restartable): coderange scaning
+	* string.c (rb_str_coderange_scan_restartable): coderange scanning
 	  for partial read.
 
 	* io.c (read_all): set coderange when not convert encoding.
@@ -367,7 +3028,7 @@
 
 	* string.c (str_sublen): removed.
 
-	* string.c (rb_str_reverse, rb_str_reverse_bang): use 
+	* string.c (rb_str_reverse, rb_str_reverse_bang): use
 	  single_byte_optimizable.
 
 Sat Feb 23 19:25:18 2008  NARUSE, Yui  <naruse at ruby-lang.org>
@@ -693,7 +3354,7 @@
 	* encoding.c (rb_enc_compatible): empty strings are always compatible.
 
 	* string.c (rb_enc_cr_str_buf_cat): ditto.
-	  
+
 Sat Feb 16 16:14:35 2008  Tanaka Akira  <akr at fsij.org>
 
 	* string.c (rb_enc_strlen): UTF-8 character count moved to str_strlen.
@@ -864,7 +3525,7 @@
 	  [ruby-dev:33763]
 
 	* test/ruby/test_proc.rb: add tests to achieve over 70% test coverage
-	  of time.c.
+	  of proc.c.
 
 	* test/ruby/test_method.rb: ditto.
 
@@ -1029,16 +3690,16 @@
 	* object.c (rb_to_integer): ditto.
 
 	* string.c (rb_str_equal): inline memcmp to avoid unnecessary
-	  rb_str_comparable(). 
+	  rb_str_comparable().
 
 	* parse.y (rb_intern2): use US-ASCII encoding.
 
-	* parse.y (rb_intern_str): ditto. 
+	* parse.y (rb_intern_str): ditto.
 
 Mon Feb 11 17:21:18 2008  Kouhei Sutou  <kou at cozmixng.org>
 
 	* lib/rss/rss.rb (RSS::VERSION), test/rss/test_version.rb:
-	0.2.3 -> 0.2.4.
+	  0.2.3 -> 0.2.4.
 
 	* lib/rss/maker.rb, lib/rss/maker/, test/rss/test_maker_2.0.rb:
 	  fixed a bug that RSS::Maker.make("0.9")'s item doesn't make some
@@ -1249,7 +3910,7 @@
 
 	* configure.in (tgamma): check for replacement functions.
 	  (lgamma_r): ditto.
-	
+
 	* missing/tgamma.c: new file.  based on gamma.c from
 	  "C-gengo niyoru saishin algorithm jiten" (New Algorithm handbook
 	  in C language) (Gijyutsu hyouron sha, Tokyo, 1991)
@@ -1573,7 +4234,7 @@
 	  string.
 
 	* re.c (rb_reg_new_ary): defined for toregexp.  it concatenates
-	  strings after each string is preprocessed. 
+	  strings after each string is preprocessed.
 
 	* compile.c (compile_dstr_fragments): split from compile_dstr.
 	  (compile_dstr): call compile_dstr_fragments.
@@ -1870,7 +4531,7 @@
 	  use rb_str_ascii_new.
 
 	* array.c (recursive_join, inspect_ary): ditto.
-	
+
 	* object.c (nil_to_s, nil_inspect, true_to_s, false_to_s,
 	  rb_mod_to_s): ditto.
 
@@ -2068,7 +4729,7 @@
 	* parse.y (parser_str_new, rb_intern3): ascii only string literal is
 	  US-ASCII.
 
-	* ruby.c (proc_optionc): -Kn means ASCII-8BIT. 
+	* ruby.c (proc_optionc): -Kn means ASCII-8BIT.
 
 Wed Jan 23 23:54:40 2008  Yusuke Endoh  <mame at tsg.ne.jp>
 
@@ -2441,7 +5102,7 @@
 
 	* parse.y (parser_prepare): lex_input may not be have encoding (e.g. IO).
 
-	* parse.y (rb_parser_compile_string): set encoding from input string. 
+	* parse.y (rb_parser_compile_string): set encoding from input string.
 
 	* encoding.c (rb_enc_find_index): use ASCII-8BIT if loading known
 	  encoding failed.
@@ -2583,7 +5244,7 @@
 Tue Jan 15 23:00:08 2008  NARUSE, Yui  <naruse at ruby-lang.org>
 
 	* enc/utf_{16,32}{be,le}.c: remove some ARG_UNUSED.  replace struct
-	OnigEncodingST by OnigEncoding.
+	  OnigEncodingST by OnigEncoding.
 
 Tue Jan 15 22:30:43 2008  NARUSE, Yui  <naruse at ruby-lang.org>
 
@@ -2789,7 +5450,7 @@
 Sun Jan 13 22:47:28 2008  NARUSE, Yui  <naruse at ruby-lang.org>
 
 	* enc/make_encdb.h: sort encoding names by original name.
-	
+
 	* encoding.c, enc/*.c: define replicas and aliases.
 
 Sun Jan 13 20:24:03 2008  NARUSE, Yui  <naruse at ruby-lang.org>
@@ -2836,7 +5497,7 @@
 Sun Jan 13 09:58:17 2008  NARUSE, Yui  <naruse at ruby-lang.org>
 
 	* encoding.c (rb_enc_init): revert removing SJIS.
-	
+
 	* enc/sjis.c: move to enc/shift_jis.c, to make encoding name equal to
 	  filename for convenience of loading lib.
 
@@ -2872,7 +5533,7 @@
 	  encoding library.
 	  (rb_enc_name_list, rb_enc_aliases_enc_i, rb_enc_aliases_str_i,
 	   rb_enc_aliases, Encoding.name_list, Encoding.aliases): added.
-	  (Init_Encoding): init encdb.	
+	  (Init_Encoding): init encdb.
 
 	* enc/ascii.c, enc/us_ascii.c, enc/euc_jp.c, enc/sjis.c:
 	  add replica encoding and encoding alias definition.
@@ -2948,7 +5609,7 @@
 	* ext/nkf/nkf-utf8/nkf.c: update to r1.163.
 
 	* ext/nkf/nkf.c: ASCII's canonical name is US-ASCII.
-	
+
 	* ext/nkf/lib/kconv.rb (Kconv.isjis): force_encoding('BINARY').
 
 Fri Jan 11 09:23:31 2008  NARUSE, Yui  <naruse at ruby-lang.org>
@@ -3077,7 +5738,7 @@
 Tue Jan  8 19:48:15 2008  Eric Hodel  <drbrain at segment7.net>
 
 	* lib/rdoc/ri/driver.rb: Speed up Marshal.load. Fix bug with nested
-	classes' methods.
+	  classes' methods.
 
 Tue Jan  8 19:17:29 2008  Eric Hodel  <drbrain at segment7.net>
 
@@ -3188,7 +5849,7 @@
 Mon Jan  7 15:51:35 2008  Eric Hodel  <drbrain at segment7.net>
 
 	* lib/rdoc/options.rb:  Convert to OptionParser, clean up -h output,
-	namespace under RDoc.
+	  namespace under RDoc.
 	* lib/rdoc/*:  Namespace RDoc::Options.
 
 Mon Jan  7 15:42:46 2008  NAKAMURA Usaku  <usa at ruby-lang.org>
@@ -3431,7 +6092,7 @@
 
 Thu Jan  3 20:24:48 2008  Koichi Sasada  <ko1 at atdot.net>
 
-	* eval_jump.c (rb_f_catch): Restore cfp if catched thrown object.
+	* eval_jump.c (rb_f_catch): Restore cfp if caught thrown object.
 
 Thu Jan  3 19:45:57 2008  Koichi Sasada  <ko1 at atdot.net>
 
@@ -3734,7 +6395,7 @@
 Mon Dec 31 22:53:29 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* thread_pthread.c (native_sleep): timespec tv_sec may overflow on
-	  some platform.  a patch from zunda <zunda616e AT yahoo.co.jp> in 
+	  some platform.  a patch from zunda <zunda616e AT yahoo.co.jp> in
 	  [ruby-dev:32904].
 
 Mon Dec 31 19:35:20 2007  Tanaka Akira  <akr at fsij.org>
@@ -3812,9 +6473,9 @@
 Sun Dec 30 10:54:49 2007  NARUSE, Yui  <naruse at ruby-lang.org>
 
 	* configure.in: rm largefile.h.
-	
+
 	* common.mk: clean golf, conf*, preludes, and so on.
-	
+
 	* enc/depend: silent and ignore error for rm.
 
 	* enc/Makefile.in: should define prefix and exec_prefix.
@@ -3855,7 +6516,7 @@
 
 Sat Dec 29 13:29:29 2007  Tanaka Akira  <akr at fsij.org>
 
-	* bootstraptest/test_knownbug.rb: add a test reported by 
+	* bootstraptest/test_knownbug.rb: add a test reported by
 	  Kazuhiro NISHIYAMA.  [ruby-dev:32819].
 	  add a test reported by Frederick Cheung.  [ruby-core:14556].
 
@@ -3986,7 +6647,7 @@
 	* lib/rss/rss.rb, test/rss/test_version.rb: 0.2.2 -> 0.2.3.
 
 	* lib/rss/parser.rb, test/rss/test_parser.rb: supported "-" in tag name.
-	Reported by Ray Chen. Thanks.
+	  Reported by Ray Chen. Thanks.
 
 Fri Dec 28 13:07:31 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
@@ -4151,7 +6812,7 @@
 Tue Dec 25 23:25:29 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* lib/rexml/node.rb (REXML::Node::indent): should initialize rv
-	  variable.  a patch from Tadayoshi Funaba <tadf AT dotrb.org> in 
+	  variable.  a patch from Tadayoshi Funaba <tadf AT dotrb.org> in
 	  [ruby-dev:32783].
 
 Tue Dec 25 23:16:01 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
@@ -4207,7 +6868,7 @@
 
 Tue Dec 25 20:24:58 2007  Technorama Ltd.  <oss-ruby at technorama.net>
 
-	* ext/openssl/ossl_ssl.c: Only show a warning if the default 
+	* ext/openssl/ossl_ssl.c: Only show a warning if the default
 	  DH callback is actually used.
 
 	* ext/openssl/ossl_rand.c: New method: random_add().
@@ -4243,7 +6904,7 @@
 	  string.
 
 Tue Dec 25 18:06:04 2007  Tanaka Akira  <akr at fsij.org>
-	
+
 	* string.c (rb_str_inspect): don't call rb_enc_codepoint with empty
 	  string.  fix '#'.inspect.
 
@@ -4359,7 +7020,7 @@
 Tue Dec 25 14:09:16 2007  James Edward Gray II  <jeg2 at ruby-lang.org>
 
 	* lib/csv.rb:  Fixed test failures caused by changes to Ruby.
-	
+
 	* test/csv/tc_serialization, test/csv/tc_csv_parsing, test/csv/tc_features:
 	  Fixed test failures caused by changes to Ruby.
 
@@ -4442,7 +7103,7 @@
 Tue Dec 25 11:45:34 2007  James Edward Gray II  <jeg2 at ruby-lang.org>
 
 	* lib/csv.rb:  Import the FasterCSV source as the new CSV class.
-	
+
 	* test/csv/*:  Added all applicable tests from FasterCSV.
 
 Tue Dec 25 11:33:52 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
@@ -4474,7 +7135,7 @@
 Tue Dec 25 08:37:43 2007  James Edward Gray II  <jeg2 at ruby-lang.org>
 
 	* lib/csv.rb, test/csv/test_csv.rb:  Removed in preparation for
-	FasterCSV code import.
+	  FasterCSV code import.
 
 Tue Dec 25 08:27:43 2007  Eric Hodel  <drbrain at segment7.net>
 
@@ -4497,10 +7158,10 @@
 Tue Dec 25 05:44:56 2007  Eric Hodel  <drbrain at segment7.net>
 
 	* lib/net/http.rb:  Fix uninitialized variable warning.
-	[ruby-talk:284582]
+	  [ruby-talk:284582]
 
 	* lib/irb/output-method.rb:  Remove unused #foo method.
-	[ruby-talk:284582]
+	  [ruby-talk:284582]
 
 Tue Dec 25 05:24:12 2007  Koichi Sasada  <ko1 at atdot.net>
 
@@ -4862,7 +7523,7 @@
 
 	* io.c (io_read_encoding): retrieve reading encoding.
 
-	* io.c (prepare_getline_args): convert RS to external encoding. 
+	* io.c (prepare_getline_args): convert RS to external encoding.
 
 	* string.c (str_new_shared): was setting embedding flag of wrong
 	  string object.  [ruby-dev:32685]
@@ -4911,7 +7572,7 @@
 
 Mon Dec 24 00:47:05 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
-	* test/ruby/test_beginendblock.rb (TestBeginEndBlock::test_endblockwarn): 
+	* test/ruby/test_beginendblock.rb (TestBeginEndBlock::test_endblockwarn):
 	  rename endblockwarn.rb to endblockwarn_rb to avoid unnecessary
 	  warning in make test.
 
@@ -4969,7 +7630,7 @@
 Sun Dec 23 14:43:10 2007  Eric Hodel  <drbrain at segment7.net>
 
 	* gem_prelude.rb:  Use require to load rubygems.rb so the correct path
-	is in $LOADED_FEATURES on RubyGems upgrade.
+	  is in $LOADED_FEATURES on RubyGems upgrade.
 
 Sun Dec 23 11:26:43 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
@@ -5078,7 +7739,7 @@
 	* ext/openssl/lib/net/ssl.rb (OpenSSL::SSL::SSLContext#set_params):
 	  new method to set suitable SSL parameters.
 
-	* lib/net/pop.rb, lib/net/http.rb, lib/net/imap.rb, 
+	* lib/net/pop.rb, lib/net/http.rb, lib/net/imap.rb,
 	  test/openssl/test_ssl.rb: follow above change.
 
 	* test/net/http/test_https.rb: refine error case.
@@ -5186,7 +7847,7 @@
 Sat Dec 22 11:05:44 2007  Jim Weirich  <jim at tardis.local>
 
 	* lib/rake.rb (Rake): Added Rake and related libraries to the
-	source code base.
+	  source code base.
 
 Sat Dec 22 10:30:45 2007  Koichi Sasada  <ko1 at atdot.net>
 
@@ -5312,14 +7973,14 @@
 
 	* ext/tk/tcltklib.c: provisional support on Ruby-VM.
 
-	* ext/tk/MANUAL_tcltklib.eng, ext/tk/MANUAL_tcltklib.eucj: 
+	* ext/tk/MANUAL_tcltklib.eng, ext/tk/MANUAL_tcltklib.eucj:
 	  modify document about new functions.
 
 	* ext/tk/lib/tk.rb, ext/tk/lib/tk/labelframe.rb,
 	  ext/tk/lib/tk/frame.rb, ext/tk/lib/tk/toplevel.rb,
 	  ext/tk/lib/tk/scrollbar.rb, ext/tk/lib/tk/message.rb,
 	  ext/tk/lib/tk/listbox.rb, ext/tk/lib/tk/text.rb,
-	  ext/tk/lib/tk/scale.rb, ext/tk/lib/tk/entry.rb, 
+	  ext/tk/lib/tk/scale.rb, ext/tk/lib/tk/entry.rb,
 	  ext/tk/lib/tk/ttk_selector.rb, ext/tk/lib/tk/menu.rb,
 	  ext/tk/lib/tk/label.rb, ext/tk/lib/tk/spinbox.rb,
 	  ext/tk/lib/tk/textmark.rb, ext/tk/lib/tk/winpkg.rb,
@@ -5339,8 +8000,8 @@
 	* ext/tk/sample/demos-jp/widget,
 	  ext/tk/sample/demos-jp/pendulum.rb,
 	  ext/tk/sample/demos-jp/bind.rb,
-	  ext/tk/sample/tkextlib/vu/canvSticker2.rb, 
-	  ext/tk/sample/demos-en/pendulum.rb, 
+	  ext/tk/sample/tkextlib/vu/canvSticker2.rb,
+	  ext/tk/sample/demos-en/pendulum.rb,
 	  ext/tk/sample/demos-en/bind.rb: remove $KCODE and minor bug fix.
 
 Fri Dec 21 17:49:06 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
@@ -5394,7 +8055,7 @@
 	* ext/nkf/nkf-utf8/config.h (MIME_DECODE_DEFAULT, X0201_DEFAULT):
 	 defined as FALSE.  nkf and kconv don't decode MIME encoded string
 	 and don't convert JIS X 0201 Katakana.
-	
+
 	* test/nkf/test_kconv.rb: fix tests.
 
 Fri Dec 21 16:33:28 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
@@ -5709,7 +8370,7 @@
 Thu Dec 20 09:42:11 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* bignum.c (big2str_orig): access beyond memory region cause crash
-	  on interrupt.  a patch from Yusuke ENDOH <mame AT tsg.ne.jp> in 
+	  on interrupt.  a patch from Yusuke ENDOH <mame AT tsg.ne.jp> in
 	  [ruby-dev:32651].  [ruby-dev:32641]
 
 Thu Dec 20 09:06:54 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
@@ -5856,7 +8517,7 @@
 
 Wed Dec 19 17:12:59 2007  Koichi Sasada  <ko1 at atdot.net>
 
-	* bootstraptest/test_knownbug.rb, test_block.rb: 
+	* bootstraptest/test_knownbug.rb, test_block.rb:
 	  move fixed bug.
 
 	* bootstraptest/test_m17n.rb: added.
@@ -5934,7 +8595,7 @@
 
 Tue Dec 18 23:27:51 2007  GOTOU Yuuzou  <gotoyuzo at notwork.org>
 
-	* lib/webrick/server.rb (WEBrick::GenericServer#accept_client): 
+	* lib/webrick/server.rb (WEBrick::GenericServer#accept_client):
 	  should rescue Errno::EINVAL from TCPServer#accept. this exception
 	  might occur if the server socket is not in ready to listen.
 
@@ -5946,7 +8607,7 @@
 
 Tue Dec 18 22:51:47 2007  GOTOU Yuuzou  <gotoyuzo at notwork.org>
 
-	* ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLServer#shutdown): 
+	* ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLServer#shutdown):
 	  new method which calls TCPSocket#shutdown of the underlying socket.
 
 Tue Dec 18 22:11:50 2007  GOTOU Yuuzou  <gotoyuzo at notwork.org>
@@ -6009,7 +8670,7 @@
 	* object.c (rb_obj_frozen_p): check immediate values too.
 
 	* variable.c (generic_ivar_set): add frozen check fro immediate
-	  values. 
+	  values.
 
 Tue Dec 18 17:04:25 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
@@ -6050,15 +8711,15 @@
 	* proc.c (rb_obj_public_method): Object#public_method to retrieve
 	  public method object.
 
-	* proc.c (rb_mod_public_instance_method): Module#public_instance_method 
+	* proc.c (rb_mod_public_instance_method): Module#public_instance_method
 	  to retrieve public instance method from class / module.
-	
+
 	* proc.c (mnew): visibility check added.
 
 	* eval_error.ci (rb_print_undef): add rb_ prefix.
 
 	* eval_error.ci (rb_print_undef): add visibility in the error
-	  message. 
+	  message.
 
 Tue Dec 18 05:54:26 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
@@ -6327,7 +8988,7 @@
 	* thread_pthread.ci (native_thread_create): twice the stack size.
 	  512KB is not enough to complete test-all on Debian GNU/Linux on
 	  IA64.
-	  
+
 Fri Dec 14 16:10:50 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* io.c (rb_f_p): RDoc update.  a patch from murphy <murphy AT rubychan.de>.
@@ -6381,7 +9042,7 @@
 Fri Dec 14 10:25:56 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* lib/e2mmap.rb (Exception2MessageMapper::E2MM.Raise): $! no
-	  longer modifiable in 1.9. 
+	  longer modifiable in 1.9.
 
 Fri Dec 14 08:17:24 2007  Tanaka Akira  <akr at fsij.org>
 
@@ -6434,7 +9095,7 @@
 	  is empty.
 
 	* string.c (rb_str_justify): associate encoding of original to the
-	  result. 
+	  result.
 
 	* string.c (rb_str_chomp_bang): need to check encoding of record
 	  separator.
@@ -7016,7 +9677,7 @@
 
 Sun Dec  2 09:12:48 2007  Tanaka Akira  <akr at fsij.org>
 
-	* parse.y (regexp): fix /#{}\xa1\xa2/e to be EUC-JP. 
+	* parse.y (regexp): fix /#{}\xa1\xa2/e to be EUC-JP.
 	  (reg_fragment_setenc_gen): extracted from reg_compile_gen.
 
 Sun Dec  2 01:39:51 2007  Tanaka Akira  <akr at fsij.org>
@@ -7213,11 +9874,11 @@
 Tue Nov 27 11:23:20 2007  Koichi Sasada  <ko1 at atdot.net>
 
 	* test_beginendblock.rb: add loop to wait signal.
-	  [ruby-dev:32332] 
+	  [ruby-dev:32332]
 
 Tue Nov 27 11:14:57 2007  Tanaka Akira  <akr at fsij.org>
 
-	* include/ruby/encoding.h, encoding.c, re.c, string.c, parse.y: 
+	* include/ruby/encoding.h, encoding.c, re.c, string.c, parse.y:
 	  rename ENC_CODERANGE_SINGLE to ENC_CODERANGE_7BIT.
 	  rename ENC_CODERANGE_MULTI to ENC_CODERANGE_8BIT.
 	  Because single byte 8bit character, such as Shift_JIS 1byte katakana,
@@ -7449,7 +10110,7 @@
 Tue Nov 20 12:12:04 2007  Tanaka Akira  <akr at fsij.org>
 
 	* include/ruby/io.h (rb_io_t): add tied_io_for_writing member.
-	  
+
 	* io.c: use tied_io_for_writing for duplex popen.
 
 	* gc.c: mark tied_io_for_writing.
@@ -7784,7 +10445,7 @@
 	  pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
 	  time.c: apply above changes.
 
-	* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c: 
+	* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
 	  ditto.
 
 Wed Nov 14 00:15:37 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
@@ -7916,7 +10577,7 @@
 	  vm_call_cfunc() instead of klass.
 
 	* vm.c (rb_thread_method_id_and_klass): traverse parent_iseq.
-	
+
 	* thread.c (call_trace_proc): use rb_thread_method_id_and_klass().
 
 Sun Nov 11 16:54:25 2007  Tanaka Akira  <akr at fsij.org>
@@ -7942,7 +10603,7 @@
 
 Sat Nov 10 19:46:54 2007  Tanaka Akira  <akr at fsij.org>
 
-	* configure.in, common.mk, Makefile.in: generate libminiruby-static.a 
+	* configure.in, common.mk, Makefile.in: generate libminiruby-static.a
 	  which contains prelude.o for miniruby.
 
 Sat Nov 10 18:10:07 2007  Tanaka Akira  <akr at fsij.org>
@@ -7951,7 +10612,7 @@
 
 	* common.mk: generate ext_prelude.c by prelude.rb and gem_prelude.rb.
 	  ruby (not miniruby) is linked with ext_prelude.o instead of
-	  prelude.o. 
+	  prelude.o.
 
 	* inits.c (rb_call_inits): don't call Init_prelude.
 
@@ -8046,7 +10707,7 @@
 	  #each_pair is now alias to #each.  [ruby-dev:32192]
 
 	* test/ruby/test_iterator.rb (TestIterator::test_assoc_yield):
-	  ditto 
+	  ditto
 
 Fri Nov  9 12:56:36 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
@@ -8113,7 +10774,7 @@
 
 	* parse.y: fix segfault with \x escapes in regexps
 	  delete unused #if 0 code regions from previous patch
-	
+
 Thu Nov  8 12:12:10 2007  NAKAMURA Usaku  <usa at ruby-lang.org>
 
 	* parse.y (parser_read_escape): remove C99/gcc-ism.
@@ -8126,18 +10787,18 @@
 	* test/ruby/test_unicode_escapes.rb: test cases
 
 	* test/ruby/test_mixed_unicode_escapes.rb: mixed encoding test cases
-	
+
 Thu Nov  8 07:14:37 2007 David Flanagan <davidflanagan at ruby-lang.org>
 
 	* parse.y (rb_intern3): commented out broken code that prevented
 	  correct interning of multi-byte symbols.  Without this patch
-	  :x==:x is false when x is a multi-byte character. 
-	
+	  :x==:x is false when x is a multi-byte character.
+
 Thu Nov  8 07:04:31 2007 David Flanagan <davidflanagan at ruby-lang.org>
 
 	* string.c (tr_setup_table, tr_trans): fix test failures
 	  in test/ruby/test_string.rb
-	
+
 Wed Nov  7 15:07:51 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
 	* enum.c (enum_each_with_index): make different arrays at each
@@ -8293,7 +10954,7 @@
 
 Thu Nov  1 14:51:39 2007 David Flanagan <davidflanagan at ruby-lang.org>
 	* enum.c (take_while_i, drop_while_i) add RTEST to handle nil return
-	
+
 Thu Nov  1 02:12:50 2007  NAKAMURA Usaku  <usa at ruby-lang.org>
 
 	* common.mk (prereq): update the path of prelude.c.
@@ -8376,7 +11037,7 @@
 
 Fri Oct 26 05:48:57 2007  David Flanagan <davidflanagan at ruby-lang.org>
 	* array.c: raise IndexError for negative length in rb_ary_fill
-	
+
 Wed Oct 25 07:12:03 2007  James Edward Gray II  <jeg2 at ruby-lang.org>
 
 	* lib/net/telnet.rb (Net::Telnet#login): Allowing "passphrase" in
@@ -8419,7 +11080,7 @@
 
 	* parse.y (parser_tokspace): increment tokidx
 	  fixes test failure at [test/ruby/test_stringchar.rb:72]
-	
+
 Thu Oct 25 09:49:49 2007  akira yamada  <akira at ruby-lang.org>
 
 	* lib/uri.rb, lib/uri/ldaps.rb: added LDAPS
@@ -8773,11 +11434,11 @@
 
 Sat Oct 13 21:23:21 2007  Masaki Suketa  <masaki.suketa at nifty.ne.jp>
 
-	* ext/win32ole/win32ole.c (foletype_s_ole_classes, 
+	* ext/win32ole/win32ole.c (foletype_s_ole_classes,
 	  foletype_s_typelibs): refactoring.
-	
-	* test/win32ole/test_win32ole_type.rb: add some test. 
 
+	* test/win32ole/test_win32ole_type.rb: add some test.
+
 	* ext/win32ole/win32ole.c (Init_win32ole): change method name
 	  WIN32OLE_TYPELIB.ole_types from WIN32OLE_TYPELIB.ole_classes.
 
@@ -8826,7 +11487,7 @@
 Fri Oct 12 11:22:15 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* re.c (match_values_at): make #select to be alias to #values_at
-	  to adapt RDoc description.  [ruby-core:12588]  
+	  to adapt RDoc description.  [ruby-core:12588]
 
 Thu Oct 11 21:10:17 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
@@ -8967,7 +11628,7 @@
 
 Sat Oct  6 02:34:18 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
-	* include/ruby/defines.h: no longer provide DEFAULT_KCODE. 
+	* include/ruby/defines.h: no longer provide DEFAULT_KCODE.
 
 Fri Oct  5 21:24:59 2007  Tanaka Akira  <akr at fsij.org>
 
@@ -9274,7 +11935,7 @@
 
 	* cont.c: Thread local storage should be fiber local.
 
-	* bootstraptest/test_knownbug.rb, test/ruby/test_fiber.rb: 
+	* bootstraptest/test_knownbug.rb, test/ruby/test_fiber.rb:
 	  move a fixed test.
 
 Fri Sep 28 23:15:31 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
@@ -9584,7 +12245,7 @@
 
 	* lib/net/http.rb: fix typo.
 
-Mon Sep 24 06:49:15 2007  GOTOU Yuuzou  <gotoyuzo at notwork.org>  
+Mon Sep 24 06:49:15 2007  GOTOU Yuuzou  <gotoyuzo at notwork.org>
 
 	* lib/net/http.rb: an SSL verification (the server hostname should
 	  be matched with its certificate's commonName) is added.
@@ -9596,7 +12257,7 @@
 	  perform SSL post connection check.
 
 	* ext/openssl/lib/openssl/ssl.c
-	(OpenSSL::SSL::SSLSocket#post_connection_check): refine error message.  
+	  (OpenSSL::SSL::SSLSocket#post_connection_check): refine error message.
 
 Sun Sep 23 09:05:05 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
 
@@ -9859,7 +12520,7 @@
 	* marshal.c: support marshal format compatibility layer designed for
 	  marshaling T_STRUCT Range using T_OBJECT format.
 	  (rb_marshal_define_compat): defined.
-	
+
 	[ruby-dev:31710]
 
 Sat Sep  8 10:05:14 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
@@ -10030,7 +12691,7 @@
 	* eval_jump.ci (rb_f_throw): allow throwing non-symbol object.
 
 	* eval_jump.ci (rb_catch_obj): new function to wait throw with arbitrary
-	  object. 
+	  object.
 
 	* eval_jump.ci (rb_throw_obj): new function to throw arbitrary object.
 
@@ -10141,7 +12802,7 @@
 	  (unpack_entries): new function for converting to unpacked mode.
 
 	[ruby-list:43954]
-	  
+
 Wed Aug 29 10:46:37 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* include/ruby/defines.h (flush_register_windows): call "ta 0x03"
@@ -10156,7 +12817,7 @@
 	  compareMode value to raise WIN32OLERuntimeError.
 
 	* test/win32ole/test_win32ole_type.rb (test_implemented_ole_types):
-	  support some environment which returns IShellDispatch5 instead 
+	  support some environment which returns IShellDispatch5 instead
 	  of IShellDispatch.
 
 Tue Aug 28 15:42:09 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
@@ -10262,7 +12923,7 @@
 
 Sun Aug 26 06:51:46 2007  Masaki Suketa  <masaki.suketa at nifty.ne.jp>
 
-	* ext/win32ole/win32ole.c (ole_wc2mb, reg_enum_key): allocate 
+	* ext/win32ole/win32ole.c (ole_wc2mb, reg_enum_key): allocate
 	  buffer should be NULL terminated.
 
 Sun Aug 26 06:04:13 2007  Koichi Sasada  <ko1 at atdot.net>
@@ -10291,7 +12952,7 @@
 Sat Aug 25 22:50:14 2007  Masaki Suketa  <masaki.suketa at nifty.ne.jp>
 
 	* ext/win32ole/win32ole.c (ole_event_free, EVENTSINK_Destructor,
-	  fev_initialize): remove the connection ole_event_free and 
+	  fev_initialize): remove the connection ole_event_free and
 	  EVENTSINK_Destructor.
 
 Sat Aug 25 17:52:06 2007  Koichi Sasada  <ko1 at atdot.net>
@@ -10324,7 +12985,7 @@
 
 	* parse.y (rb_intern3): encoding specified symbols.
 
-	* string.c (rb_str_length): length based on characters.  
+	* string.c (rb_str_length): length based on characters.
 	  for older behavior, bytesize method added.
 
 	* string.c (rb_str_index_m): index based on characters.  rindex as
@@ -10355,7 +13016,7 @@
 	* string.c (rb_str_justify): encoding aware justifying (ljust,
 	  rjust, center).
 
-	* string.c (str_encoding): get encoding attribute from a string. 
+	* string.c (str_encoding): get encoding attribute from a string.
 
 	* re.c (rb_reg_initialize): encoding aware regular expression
 
@@ -10483,7 +13144,7 @@
 
 Fri Aug 24 18:30:50 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
-	* lib/drb/drb.rb (DRb::DRbServer::InvokeMethod::perform_without_block): 
+	* lib/drb/drb.rb (DRb::DRbServer::InvokeMethod::perform_without_block):
 	  replace funcall by send!.  other files in the distribution as well.
 
 Fri Aug 24 17:06:56 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
@@ -10551,7 +13212,7 @@
 	* insns.def, insnhelper.ci: move process body of expandarray insn to
 	  vm_expandarray().
 
-	* bootstraptest/test_knownbug.rb, bootstraptest/test_massign.rb: 
+	* bootstraptest/test_knownbug.rb, bootstraptest/test_massign.rb:
 	  move a solved test.
 
 Thu Aug 23 15:51:19 2007  Nobuyoshi Nakada  <nobu at ruby-lang.org>
@@ -10739,7 +13400,7 @@
 
 Sat Aug 18 16:44:15 2007  Koichi Sasada  <ko1 at atdot.net>
 
-	* insnhelper.ci (vm_call_bmethod), 
+	* insnhelper.ci (vm_call_bmethod),
 	  vm.c (vm_invoke_proc_core): fix to do not restore
 	  $SAFE when proc invoked by bmethod.
 
@@ -10817,7 +13478,7 @@
 Sat Aug 18 11:44:59 2007  Koichi Sasada  <ko1 at atdot.net>
 
 	* compile.c (iseq_set_arguments), insnhelper.ci
-	  (vm_callee_setup_arg, vm_yield_setup_args): 
+	  (vm_callee_setup_arg, vm_yield_setup_args):
 	  fix to cause raise on "lambda{|a|}.call(1, 2)".
 	  [ruby-dev:31464]
 
@@ -10868,7 +13529,7 @@
 Fri Aug 17 01:25:23 2007  Koichi Sasada  <ko1 at atdot.net>
 
 	* compile.c (iseq_set_arguments), insnhelper.ci
-	  (vm_callee_setup_arg, vm_yield_setup_args): fix 
+	  (vm_callee_setup_arg, vm_yield_setup_args): fix
 	  block parameter problems. [ruby-dev:31437], [ruby-dev:31440]
 
 	* bootstraptest/test_block.rb: add a test of [ruby-dev:31440].
@@ -10887,7 +13548,7 @@
 	  access.  [ruby-dev:31404]
 
 	* sprintf.c (rb_str_format): small float should not call
-	  rb_dbl2big(). 
+	  rb_dbl2big().
 
 Thu Aug 16 22:10:06 2007  Koichi Sasada  <ko1 at atdot.net>
 
@@ -11164,7 +13825,7 @@
 Wed Aug  8 19:17:40 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* ext/dl/cptr.c (rb_dlptr_s_to_ptr): no longer check
-	  HAVE_RB_IO_STDIO_FILE. 
+	  HAVE_RB_IO_STDIO_FILE.
 
 Wed Aug  8 15:52:01 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
@@ -11234,7 +13895,7 @@
 Tue Aug  7 01:42:05 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
 	* enum.c (enum_zip): zip no longer converts arguments into
-	  arrays, uses enumerators. 
+	  arrays, uses enumerators.
 
 Tue Aug  7 01:27:47 2007  Yukihiro Matsumoto  <matz at ruby-lang.org>
 
@@ -15072,7 +17733,7 @@
 Fri Feb 16 11:18:21 2007  Eric Hodel  <drbrain at segment7.net>
 
 	* lib/.document: Apply patch for irb, e2mmap and README by Hugh Sasse
-	<hgs at dmu.ac.uk> from [ruby-core:10135]
+	  <hgs at dmu.ac.uk> from [ruby-core:10135]
 
 	* lib/prettyprint.rb: Suppress RDoc for PrettyPrint test suite.
 

Modified: MacRuby/trunk/Makefile.in
===================================================================
--- MacRuby/trunk/Makefile.in	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/Makefile.in	2008-05-18 08:10:19 UTC (rev 199)
@@ -39,6 +39,9 @@
 OUTFLAG = @OUTFLAG@$(empty)
 COUTFLAG = @COUTFLAG@$(empty)
 CFLAGS = @CFLAGS@ @ARCH_FLAG@
+cflags = @cflags@
+optflags = @optflags@
+debugflags = @debugflags@
 XCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir) @XCFLAGS@
 CPPFLAGS = @CPPFLAGS@
 LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
@@ -51,7 +54,7 @@
 DLDFLAGS = @LIBRUBY_DLDFLAGS@ $(EXTLDFLAGS) @ARCH_FLAG@
 SOLIBS = @SOLIBS@
 MAINLIBS = @MAINLIBS@
-MINIOBJS = @MINIOBJS@ miniprelude.$(OBJEXT)
+ARCHMINIOBJS = @MINIOBJS@
 BUILTIN_ENCOBJS = @BUILTIN_ENCOBJS@
 
 RUBY_INSTALL_NAME=@RUBY_INSTALL_NAME@

Modified: MacRuby/trunk/array.c
===================================================================
--- MacRuby/trunk/array.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/array.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   array.c -
 
-  $Author: nobu $
+  $Author: matz $
   created at: Fri Aug  6 09:46:12 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -203,7 +203,7 @@
     if (len < 0) {
 	rb_raise(rb_eArgError, "negative array size (or size too big)");
     }
-    if (len > 0 && len * sizeof(VALUE) <= len) {
+    if (len > LONG_MAX / sizeof(VALUE)) {
 	rb_raise(rb_eArgError, "array size too big");
     }
     ary = ary_alloc(klass);
@@ -422,7 +422,7 @@
     if (len < 0) {
 	rb_raise(rb_eArgError, "negative array size");
     }
-    if (len > 0 && len * (long)sizeof(VALUE) <= len) {
+    if (len > LONG_MAX / sizeof(VALUE)) {
 	rb_raise(rb_eArgError, "array size too big");
     }
     rb_ary_modify(ary);
@@ -677,11 +677,15 @@
 
 /*
  *  call-seq:
- *     array.pop  -> obj or nil
+ *     array.pop    -> obj or nil
+ *     array.pop(n) -> array
  *  
  *  Removes the last element from <i>self</i> and returns it, or
  *  <code>nil</code> if the array is empty.
  *     
+ *  If a number _n_ is given, returns an array of the last n elements
+ *  (or less) just like <code>array.slice!(-n, n)</code> does.
+ *     
  *     a = [ "a", "b", "c", "d" ]
  *     a.pop     #=> "d"
  *     a.pop(2)  #=> ["b", "c"]
@@ -735,12 +739,16 @@
 
 /*
  *  call-seq:
- *     array.shift   ->   obj or nil
+ *     array.shift    -> obj or nil
+ *     array.shift(n) -> array
  *  
  *  Returns the first element of <i>self</i> and removes it (shifting all
  *  other elements down by one). Returns <code>nil</code> if the array
  *  is empty.
  *     
+ *  If a number _n_ is given, returns an array of the first n elements
+ *  (or less) just like <code>array.slice!(0, n)</code> does.
+ *     
  *     args = [ "-m", "-q", "filename" ]
  *     args.shift     #=> "-m"
  *     args           #=> ["-q", "filename"]
@@ -1131,6 +1139,8 @@
  *     a.index("b")        #=> 1
  *     a.index("z")        #=> nil
  *     a.index{|x|x=="b"}  #=> 1
+ *
+ *  This is an alias of <code>#find_index</code>.
  */
 
 static VALUE
@@ -1340,7 +1350,7 @@
  *     a[0..2] = "A"               #=> ["A", "4"]
  *     a[-1]   = "Z"               #=> ["A", "Z"]
  *     a[1..-1] = nil              #=> ["A", nil]
- *     a[1..-1] = []              #=> ["A"]
+ *     a[1..-1] = []               #=> ["A"]
  */
 
 static VALUE
@@ -1550,14 +1560,8 @@
     VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
 
     MEMCPY(RARRAY_PTR(dup), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
-
     RARRAY(dup)->len = RARRAY_LEN(ary);
-    OBJ_INFECT(dup, ary);
 
-//FIXME #if WITH_OBJC
-//    if (FL_TEST(ary, RARRAY_NAMED_ARGS))
-//	FL_SET(dup, RARRAY_NAMED_ARGS);
-//#endif
 #endif
     return dup;
 }
@@ -1862,12 +1866,18 @@
 
 	RBASIC(tmp)->klass = 0;
 	ruby_qsort(RARRAY_PTR(tmp), RARRAY_LEN(tmp), sizeof(VALUE),
-		   rb_block_given_p()?sort_1:sort_2, 0);
-	RARRAY(ary)->ptr = RARRAY(tmp)->ptr;
-	RARRAY(ary)->len = RARRAY(tmp)->len;
-	RARRAY(ary)->aux.capa = RARRAY(tmp)->aux.capa;
+		   rb_block_given_p()?sort_1:sort_2, &RBASIC(tmp)->klass);
+	if (RARRAY(ary)->ptr != RARRAY(tmp)->ptr) {
+	    xfree(RARRAY(ary)->ptr);
+	    RARRAY(ary)->ptr = RARRAY(tmp)->ptr;
+	    RARRAY(ary)->len = RARRAY(tmp)->len;
+	    RARRAY(ary)->aux.capa = RARRAY(tmp)->aux.capa;
+	};
 	FL_UNSET(ary, ELTS_SHARED);
-	rb_gc_force_recycle(tmp);
+	RARRAY(tmp)->ptr = 0;
+	RARRAY(tmp)->len = 0;
+	RARRAY(tmp)->aux.capa = 0;
+	RBASIC(tmp)->klass = RBASIC(ary)->klass;
 #endif
     }
     return ary;
@@ -2160,14 +2170,8 @@
  *  
  *  Deletes the element(s) given by an index (optionally with a length)
  *  or by a range. Returns the deleted object, subarray, or
- *  <code>nil</code> if the index is out of range. Equivalent to:
+ *  <code>nil</code> if the index is out of range.
  *     
- *     def slice!(*args)
- *       result = self[*args]
- *       self[*args] = nil
- *       result
- *     end
- *     
  *     a = [ "a", "b", "c" ]
  *     a.slice!(1)     #=> "b"
  *     a               #=> ["a", "c"]
@@ -2182,16 +2186,26 @@
 {
     VALUE arg1, arg2;
     long pos, len;
+    long alen;
 
+    alen = RARRAY_LEN(ary);
     if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
 	pos = NUM2LONG(arg1);
 	len = NUM2LONG(arg2);
       delete_pos_len:
 	if (pos < 0) {
-	    pos = RARRAY_LEN(ary) + pos;
+	    pos = alen + pos;
 	    if (pos < 0) return Qnil;
 	}
+	if (alen < len || alen < pos + len) {
+	    len = alen - pos;
+	}
+#if WITH_OBJC
 	arg2 = rb_ary_subseq(ary, pos, len);
+#else
+	arg2 = rb_ary_new4(len, RARRAY_PTR(ary)+pos);
+	RBASIC(arg2)->klass = rb_obj_class(ary);
+#endif
 	rb_ary_splice(ary, pos, len, Qundef);	/* Qnil/rb_ary_new2(0) */
 	return arg2;
     }
@@ -2332,7 +2346,6 @@
  *     
  *     a = [ 4, 5, 6 ]
  *     b = [ 7, 8, 9 ]
- *     
  *     [1,2,3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
  *     [1,2].zip(a,b)         #=> [[1, 4, 7], [2, 5, 8]]
  *     a.zip([1,2],[8])       #=> [[4,1,8], [5,2,nil], [6,nil,nil]]
@@ -2550,7 +2563,7 @@
 	if (end >= ARY_CAPA(ary)) {
 	    RESIZE_CAPA(ary, end);
 	}
-	rb_mem_clear(RARRAY_PTR(ary) + n, end - n);
+	rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), end - RARRAY_LEN(ary));
 	RARRAY(ary)->len = end;
     }
 #endif
@@ -2573,12 +2586,6 @@
 	for (i=beg; i<end; i++) {
 	    rb_ary_store(ary, i, item);
 	}
-# if 0
-	const void **vals = (const void **)alloca(sizeof(void *) * (end - beg));
-	for (i=beg; i<end; i++) { vals[i] = (const void *)item; }
-	CFArrayReplaceValues((CFMutableArrayRef)ary, CFRangeMake(beg, end),
-	    vals, end);
-# endif
 #else
 	p = RARRAY_PTR(ary) + beg;
 	pend = p + len;
@@ -2832,16 +2839,10 @@
 static VALUE
 rb_ary_eql(VALUE ary1, VALUE ary2)
 {
-    long i;
-
     if (ary1 == ary2) return Qtrue;
     if (TYPE(ary2) != T_ARRAY) return Qfalse;
     if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
-    for (i=0; i<RARRAY_LEN(ary1); i++) {
-	if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
-	    return Qfalse;
-    }
-    return Qtrue;
+    return rb_exec_recursive(recursive_eql, ary1, ary2);
 }
 
 static VALUE
@@ -2897,7 +2898,7 @@
 	CFRangeMake(0, RARRAY_LEN(ary)), (const void *)item) ? Qtrue : Qfalse;
 #else
     long i;
-
+    
     for (i=0; i<RARRAY_LEN(ary); i++) {
 	if (rb_equal(RARRAY_PTR(ary)[i], item)) {
 	    return Qtrue;
@@ -2927,7 +2928,6 @@
     return Qundef;
 }
 
-
 /* 
  *  call-seq:
  *     array <=> other_array   ->  -1, 0, +1
@@ -3038,7 +3038,7 @@
     hash = ary_make_hash(ary2, 0);
 
     if (RHASH_EMPTY_P(hash))
-	return ary3;
+        return ary3;
 
     for (i=0; i<RARRAY_LEN(ary1); i++) {
 	v = vv = rb_ary_elt(ary1, i);
@@ -3123,7 +3123,6 @@
 rb_ary_uniq_bang(VALUE ary)
 {
 #if WITH_OBJC
-# if 1
     long i, n;
     bool changed;
 
@@ -3146,32 +3145,6 @@
     }
     if (!changed)
 	return Qnil;
-# else
-    VALUE hash;
-    long i, n, n_orig;
-    bool changed;
-
-    rb_ary_modify(ary);
-    hash = ary_make_hash(ary, 0);
-    n_orig = n = RARRAY_LEN(ary);
-    if (RARRAY_LEN(ary) == RHASH_SIZE(hash))
-	return Qnil;
-    for (i = 0, changed = false; i < n; i++) {
-	VALUE e;
-
-        e = RARRAY_AT(ary, i);
-	if (CFDictionaryContainsKey((CFDictionaryRef)hash, (const void *)e)) {
-	    CFDictionaryRemoveValue((CFMutableDictionaryRef)hash,
-		(const void *)e);
-	}
-	else {
-	    CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, i);
-	    n--;
-	}
-    }
-    if (n != n_orig)
-	return Qnil;
-# endif
 #else
     VALUE hash, v, vv;
     long i, j;
@@ -3334,6 +3307,7 @@
  	}
 #endif
     }
+
     return LONG2NUM(n);
 }
 
@@ -3346,7 +3320,7 @@
     st_data_t id;
 
     stack = rb_ary_new();
-    result = rb_ary_new();
+    result = ary_new(rb_class_of(ary), RARRAY_LEN(ary));
     memo = st_init_numtable();
     st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
     *modified = 0;
@@ -3432,7 +3406,7 @@
  *     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
+ *     a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  *     a = [ 1, 2, [3, [4, 5] ] ]
  *     a.flatten(1)              #=> [1, 2, 3, [4, 5]]
  */
@@ -3523,25 +3497,41 @@
 /*
  *  call-seq:
  *     ary.cycle {|obj| block }
+ *     ary.cycle(n) {|obj| block }
  *  
- *  Calls <i>block</i> repeatedly forever.
+ *  Calls <i>block</i> for each element repeatedly _n_ times or
+ *  forever if none or nil is given.  If a non-positive number is
+ *  given or the array is empty, does nothing.  Returns nil if the
+ *  loop has finished without getting interrupted.
  *     
  *     a = ["a", "b", "c"]
  *     a.cycle {|x| puts x }  # print, a, b, c, a, b, c,.. forever.
+ *     a.cycle(2) {|x| puts x }  # print, a, b, c, a, b, c.
  *     
  */
 
 static VALUE
-rb_ary_cycle(VALUE ary)
+rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
 {
-    long i;
+    long n, i;
+    VALUE nv = Qnil;
 
-    RETURN_ENUMERATOR(ary, 0, 0);
-    while (RARRAY_LEN(ary) > 0) {
-	for (i=0; i<RARRAY_LEN(ary); i++) {
-	    rb_yield(RARRAY_AT(ary, i));
-	}
+    rb_scan_args(argc, argv, "01", &nv);
+
+    RETURN_ENUMERATOR(ary, argc, argv);
+    if (NIL_P(nv)) {
+        n = -1;
     }
+    else {
+        n = NUM2LONG(nv);
+        if (n <= 0) return Qnil;
+    }
+
+    while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) {
+        for (i=0; i<RARRAY_LEN(ary); i++) {
+            rb_yield(RARRAY_PTR(ary)[i]);
+        }
+    }
     return Qnil;
 }
 
@@ -3609,13 +3599,14 @@
  * When invoked without a block, return an enumerator object instead.
  * 
  * Examples:
+ *
  *     a = [1, 2, 3]
  *     a.permutation.to_a     #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
  *     a.permutation(1).to_a  #=> [[1],[2],[3]]
  *     a.permutation(2).to_a  #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
  *     a.permutation(3).to_a  #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
- *     a.permutation(0).to_a  #=> [[]]: one permutation of length 0
- *     a.permutation(4).to_a  #=> []  : no permutations of length 4
+ *     a.permutation(0).to_a  #=> [[]] # one permutation of length 0
+ *     a.permutation(4).to_a  #=> []   # no permutations of length 4
  */
 
 static VALUE
@@ -3695,13 +3686,14 @@
  * When invoked without a block, returns an enumerator object instead.
  *     
  * Examples:
+ *
  *     a = [1, 2, 3, 4]
  *     a.combination(1).to_a  #=> [[1],[2],[3],[4]]
  *     a.combination(2).to_a  #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
  *     a.combination(3).to_a  #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
  *     a.combination(4).to_a  #=> [[1,2,3,4]]
- *     a.combination(0).to_a  #=> [[]]: one combination of length 0
- *     a.combination(5).to_a  #=> []  : no combinations of length 5
+ *     a.combination(0).to_a  #=> [[]] # one combination of length 0
+ *     a.combination(5).to_a  #=> []   # no combinations of length 5
  *     
  */
 
@@ -3712,6 +3704,7 @@
 
     RETURN_ENUMERATOR(ary, 1, &num);
     n = NUM2LONG(num);
+    RETURN_ENUMERATOR(ary, 1, &num);
     len = RARRAY_LEN(ary);
     if (n < 0 || len < n) {
 	/* yield nothing */
@@ -3832,6 +3825,102 @@
     return result;
 }
 
+/*
+ *  call-seq:
+ *     ary.take(n)               => array
+ *  
+ *  Returns first n elements from <i>ary</i>.
+ *     
+ *     a = [1, 2, 3, 4, 5, 0]
+ *     a.take(3)             # => [1, 2, 3]
+ *     
+ */
+
+static VALUE
+rb_ary_take(VALUE obj, VALUE n)
+{
+    long len = NUM2LONG(n);
+    if (len < 0) {
+	rb_raise(rb_eArgError, "attempt to take negative size");
+    }
+    return rb_ary_subseq(obj, 0, len);
+}
+
+/*
+ *  call-seq:
+ *     ary.take_while {|arr| block }   => array
+ *  
+ *  Passes elements to the block until the block returns nil or false,
+ *  then stops iterating and returns an array of all prior elements.
+ *     
+ *     a = [1, 2, 3, 4, 5, 0]
+ *     a.take_while {|i| i < 3 }   # => [1, 2]
+ *     
+ */
+
+static VALUE
+rb_ary_take_while(VALUE ary)
+{
+    long i;
+
+    RETURN_ENUMERATOR(ary, 0, 0);
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+	if (!RTEST(rb_yield(RARRAY_AT(ary, i)))) break;
+    }
+    return rb_ary_take(ary, LONG2FIX(i));
+}
+
+/*
+ *  call-seq:
+ *     ary.drop(n)               => array
+ *  
+ *  Drops first n elements from <i>ary</i>, and returns rest elements
+ *  in an array.
+ *     
+ *     a = [1, 2, 3, 4, 5, 0]
+ *     a.drop(3)             # => [4, 5, 0]
+ *     
+ */
+
+static VALUE
+rb_ary_drop(VALUE ary, VALUE n)
+{
+    VALUE result;
+    long pos = NUM2LONG(n);
+    if (pos < 0) {
+	rb_raise(rb_eArgError, "attempt to drop negative size");
+    }
+
+    result = rb_ary_subseq(ary, pos, RARRAY_LEN(ary));
+    if (result == Qnil) result = rb_ary_new();
+    return result;
+}
+
+/*
+ *  call-seq:
+ *     ary.drop_while {|arr| block }   => array
+ *  
+ *  Drops elements up to, but not including, the first element for
+ *  which the block returns nil or false and returns an array
+ *  containing the remaining elements.
+ *     
+ *     a = [1, 2, 3, 4, 5, 0]
+ *     a.drop_while {|i| i < 3 }   # => [3, 4, 5, 0]
+ *     
+ */
+
+static VALUE
+rb_ary_drop_while(VALUE ary)
+{
+    long i;
+
+    RETURN_ENUMERATOR(ary, 0, 0);
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+	if (!RTEST(rb_yield(RARRAY_AT(ary, i)))) break;
+    }
+    return rb_ary_drop(ary, LONG2FIX(i));
+}
+
 #if WITH_OBJC
 static Class __nscfarray = NULL;
 
@@ -4010,6 +4099,7 @@
     rb_define_method(rb_cArray, "length", rb_ary_length, 0);
     rb_define_alias(rb_cArray,  "size", "length");
     rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
+    rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
     rb_define_method(rb_cArray, "index", rb_ary_index, -1);
     rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1);
     rb_define_method(rb_cArray, "join", rb_ary_join_m, -1);
@@ -4059,10 +4149,15 @@
     rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0);
     rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0);
     rb_define_method(rb_cArray, "choice", rb_ary_choice, 0);
-    rb_define_method(rb_cArray, "cycle", rb_ary_cycle, 0);
+    rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1);
     rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1);
     rb_define_method(rb_cArray, "combination", rb_ary_combination, 1);
     rb_define_method(rb_cArray, "product", rb_ary_product, -1);
 
+    rb_define_method(rb_cArray, "take", rb_ary_take, 1);
+    rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0);
+    rb_define_method(rb_cArray, "drop", rb_ary_drop, 1);
+    rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0);
+
     id_cmp = rb_intern("<=>");
 }

Modified: MacRuby/trunk/benchmark/bm_so_sieve.rb
===================================================================
--- MacRuby/trunk/benchmark/bm_so_sieve.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/benchmark/bm_so_sieve.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 # from http://www.bagley.org/~doug/shootout/bench/sieve/sieve.ruby
-num = 400
+num = 40
 count = i = j = 0
 flags0 = Array.new(8192,1)
 k = 0

Modified: MacRuby/trunk/benchmark/bm_vm2_eval.rb
===================================================================
--- MacRuby/trunk/benchmark/bm_vm2_eval.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/benchmark/bm_vm2_eval.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 i=0
-while i<1000000 # benchmark loop 2
+while i<6000000 # benchmark loop 2
   i+=1
   eval("1")
 end

Modified: MacRuby/trunk/bignum.c
===================================================================
--- MacRuby/trunk/bignum.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/bignum.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   bignum.c -
 
-  $Author: nobu $
+  $Author: akr $
   created at: Fri Jun 10 00:48:55 JST 1994
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -44,12 +44,29 @@
 bigzero_p(VALUE x)
 {
     long i;
-    for (i = 0; i < RBIGNUM_LEN(x); ++i) {
+    for (i = RBIGNUM_LEN(x) - 1; 0 <= i; i--) {
 	if (BDIGITS(x)[i]) return 0;
     }
     return 1;
 }
 
+int
+rb_cmpint(VALUE val, VALUE a, VALUE b)
+{
+    if (NIL_P(val)) {
+	rb_cmperr(a, b);
+    }
+    if (FIXNUM_P(val)) return FIX2INT(val);
+    if (TYPE(val) == T_BIGNUM) {
+	if (BIGZEROP(val)) return 0;
+	if (RBIGNUM_SIGN(val)) return 1;
+	return -1;
+    }
+    if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1;
+    if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1;
+    return 0;
+}
+
 #define RBIGNUM_SET_LEN(b,l) \
   ((RBASIC(b)->flags & RBIGNUM_EMBED_FLAG) ? \
    (RBASIC(b)->flags = (RBASIC(b)->flags & ~RBIGNUM_EMBED_LEN_MASK) | \
@@ -61,32 +78,32 @@
 {
     BDIGIT *ds;
     if (RBASIC(big)->flags & RBIGNUM_EMBED_FLAG) {
-        if (RBIGNUM_EMBED_LEN_MAX < len) {
-            ds = ALLOC_N(BDIGIT, len);
-            MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, RBIGNUM_EMBED_LEN_MAX);
-            RBIGNUM(big)->as.heap.len = RBIGNUM_LEN(big);
-            RBIGNUM(big)->as.heap.digits = ds;
-            RBASIC(big)->flags &= ~RBIGNUM_EMBED_FLAG;
-        }
+	if (RBIGNUM_EMBED_LEN_MAX < len) {
+	    ds = ALLOC_N(BDIGIT, len);
+	    MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, RBIGNUM_EMBED_LEN_MAX);
+	    RBIGNUM(big)->as.heap.len = RBIGNUM_LEN(big);
+	    RBIGNUM(big)->as.heap.digits = ds;
+	    RBASIC(big)->flags &= ~RBIGNUM_EMBED_FLAG;
+	}
     }
     else {
-        if (len <= RBIGNUM_EMBED_LEN_MAX) {
-            ds = RBIGNUM(big)->as.heap.digits;
-            RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
-            RBIGNUM_SET_LEN(big, len);
-            if (ds) {
-                MEMCPY(RBIGNUM(big)->as.ary, ds, BDIGIT, len);
-                xfree(ds);
-            }
-        }
-        else {
-            if (RBIGNUM_LEN(big) == 0) {
-                RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
-            }
-            else {
-                REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len);
-            }
-        }
+	if (len <= RBIGNUM_EMBED_LEN_MAX) {
+	    ds = RBIGNUM(big)->as.heap.digits;
+	    RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
+	    RBIGNUM_SET_LEN(big, len);
+	    if (ds) {
+		MEMCPY(RBIGNUM(big)->as.ary, ds, BDIGIT, len);
+		xfree(ds);
+	    }
+	}
+	else {
+	    if (RBIGNUM_LEN(big) == 0) {
+		RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
+	    }
+	    else {
+		REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len);
+	    }
+	}
     }
 }
 
@@ -104,11 +121,11 @@
     OBJSETUP(big, klass, T_BIGNUM);
     RBIGNUM_SET_SIGN(big, sign?1:0);
     if (len <= RBIGNUM_EMBED_LEN_MAX) {
-        RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
-        RBIGNUM_SET_LEN(big, len);
+	RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
+	RBIGNUM_SET_LEN(big, len);
     }
     else {
-        rb_big_resize((VALUE)big, len);
+	rb_big_resize((VALUE)big, len);
     }
 
     return (VALUE)big;
@@ -142,7 +159,7 @@
 	num = BIGDN(num);
     } while (i < RBIGNUM_LEN(x));
     if (num != 0) {
-        rb_big_resize(x, RBIGNUM_LEN(x)+1);
+	rb_big_resize(x, RBIGNUM_LEN(x)+1);
 	ds = BDIGITS(x);
 	ds[RBIGNUM_LEN(x)-1] = 1;
     }
@@ -532,10 +549,11 @@
     for (i=len;i--;) zds[i]=0;
     while ((c = *str++) != 0) {
 	if (c == '_') {
-	    if (badcheck) {
-		if (nondigit) goto bad;
-		nondigit = c;
+	    if (nondigit) {
+		if (badcheck) goto bad;
+		break;
 	    }
+	    nondigit = c;
 	    continue;
 	}
 	else if ((c = conv_digit(c)) < 0) {
@@ -737,19 +755,15 @@
 #define MAX_BIG2STR_TABLE_ENTRIES 64
 
 static VALUE big2str_power_cache[35][MAX_BIG2STR_TABLE_ENTRIES];
-static int power_cache_initialized = 0;
 
 static void
 power_cache_init(void)
 {
     int i, j;
     for (i = 0; i < 35; ++i) {
-        big2str_power_cache[i][0] =
-            rb_big_pow(rb_int2big(i+2), INT2FIX(KARATSUBA_DIGITS));
-        rb_global_variable(&big2str_power_cache[i][0]);
-        for (j = 1; j < MAX_BIG2STR_TABLE_ENTRIES; ++j) {
-            big2str_power_cache[i][j] = Qnil;
-        }
+	for (j = 0; j < MAX_BIG2STR_TABLE_ENTRIES; ++j) {
+	    big2str_power_cache[i][j] = Qnil;
+	}
     }
 }
 
@@ -757,9 +771,10 @@
 power_cache_get_power0(int base, int i)
 {
     if (NIL_P(big2str_power_cache[base - 2][i])) {
-        big2str_power_cache[base - 2][i] =
-            bigsqr(power_cache_get_power0(base, i - 1));
-        rb_global_variable(&big2str_power_cache[base - 2][i]);
+	big2str_power_cache[base - 2][i] =
+	    i == 0 ? rb_big_pow(rb_int2big(base), INT2FIX(KARATSUBA_DIGITS))
+		   : bigsqr(power_cache_get_power0(base, i - 1));
+	rb_global_variable(&big2str_power_cache[base - 2][i]);
     }
     return big2str_power_cache[base - 2][i];
 }
@@ -771,19 +786,19 @@
     VALUE t;
 
     if (n1 <= KARATSUBA_DIGITS)
-        rb_bug("n1 > KARATSUBA_DIGITS");
+	rb_bug("n1 > KARATSUBA_DIGITS");
 
     m = ceil_log2(n1);
     if (m1) *m1 = 1 << m;
     i = m - LOG2_KARATSUBA_DIGITS;
     if (i >= MAX_BIG2STR_TABLE_ENTRIES)
-        i = MAX_BIG2STR_TABLE_ENTRIES - 1;
+	i = MAX_BIG2STR_TABLE_ENTRIES - 1;
     t = power_cache_get_power0(base, i);
 
     j = KARATSUBA_DIGITS*(1 << i);
     while (n1 > j) {
-        t = bigsqr(t);
-        j *= 2;
+	t = bigsqr(t);
+	j *= 2;
     }
     return t;
 }
@@ -821,19 +836,19 @@
     long bits;
 
     if (base < 2 || 36 < base)
-        rb_bug("invalid radix %d", base);
+	rb_bug("invalid radix %d", base);
 
     if (FIXNUM_P(x)) {
-        bits = (SIZEOF_LONG*CHAR_BIT - 1)/2 + 1;
+	bits = (SIZEOF_LONG*CHAR_BIT - 1)/2 + 1;
     }
     else if (BIGZEROP(x)) {
-        return 0;
+	return 0;
     }
     else if (RBIGNUM_LEN(x) >= LONG_MAX/BITSPERDIG) {
 	rb_raise(rb_eRangeError, "bignum too big to convert into `string'");
     }
     else {
-        bits = BITSPERDIG*RBIGNUM_LEN(x);
+	bits = BITSPERDIG*RBIGNUM_LEN(x);
     }
 
     return (long)ceil(bits/log_2[base - 2]);
@@ -846,34 +861,34 @@
     BDIGIT* ds = BDIGITS(x);
 
     while (i && j > 0) {
-        long k = i;
-        BDIGIT_DBL num = 0;
+	long k = i;
+	BDIGIT_DBL num = 0;
 
-        while (k--) {               /* x / hbase */
-            num = BIGUP(num) + ds[k];
-            ds[k] = (BDIGIT)(num / hbase);
-            num %= hbase;
-        }
-        if (trim && ds[i-1] == 0) i--;
-        k = SIZEOF_BDIGITS;
-        while (k--) {
-            ptr[--j] = ruby_digitmap[num % base];
-            num /= base;
-            if (j <= 0) break;
-            if (trim && i == 0 && num == 0) break;
-        }
+	while (k--) {               /* x / hbase */
+	    num = BIGUP(num) + ds[k];
+	    ds[k] = (BDIGIT)(num / hbase);
+	    num %= hbase;
+	}
+	if (trim && ds[i-1] == 0) i--;
+	k = SIZEOF_BDIGITS;
+	while (k--) {
+	    ptr[--j] = ruby_digitmap[num % base];
+	    num /= base;
+	    if (j <= 0) break;
+	    if (trim && i == 0 && num == 0) break;
+	}
     }
     if (trim) {
-        while (j < len && ptr[j] == '0') j++;
-        MEMMOVE(ptr, ptr + j, char, len - j);
-        len -= j;
+	while (j < len && ptr[j] == '0') j++;
+	MEMMOVE(ptr, ptr + j, char, len - j);
+	len -= j;
     }
     return len;
 }
 
 static long
 big2str_karatsuba(VALUE x, int base, char* ptr,
-                  long n1, long len, long hbase, int trim)
+		  long n1, long len, long hbase, int trim)
 {
     long lh, ll, m1;
     VALUE b, q, r;
@@ -894,27 +909,23 @@
         }
     }
     if (BIGZEROP(x)) {
-        if (trim) return 0;
-        else {
-            memset(ptr, '0', len);
-            return len;
-        }
+	if (trim) return 0;
+	else {
+	    memset(ptr, '0', len);
+	    return len;
+	}
     }
 
     if (n1 <= KARATSUBA_DIGITS) {
-        return big2str_orig(x, base, ptr, len, hbase, trim);
+	return big2str_orig(x, base, ptr, len, hbase, trim);
     }
 
-    if (!power_cache_initialized) {
-	power_cache_init();
-	power_cache_initialized = 1;
-    }
     b = power_cache_get_power(base, n1, &m1);
     bigdivmod(x, b, &q, &r);
     lh = big2str_karatsuba(q, base, ptr,      (len - m1)/2,
-                           len - m1, hbase, trim);
+			   len - m1, hbase, trim);
     ll = big2str_karatsuba(r, base, ptr + lh, m1/2,
-                           m1,       hbase, !lh && trim);
+			   m1,       hbase, !lh && trim);
 
     return lh + ll;
 }
@@ -928,14 +939,14 @@
     char* ptr;
 
     if (FIXNUM_P(x)) {
-        return rb_fix2str(x, base);
+	return rb_fix2str(x, base);
     }
     if (BIGZEROP(x)) {
-        return rb_usascii_str_new2("0");
+	return rb_usascii_str_new2("0");
     }
 
     if (base < 2 || 36 < base)
-        rb_raise(rb_eArgError, "invalid radix %d", base);
+	rb_raise(rb_eArgError, "invalid radix %d", base);
 
     n2 = big2str_find_n1(x, base);
     n1 = (n2 + 1) / 2;
@@ -951,11 +962,11 @@
     xx = rb_big_clone(x);
     RBIGNUM_SET_SIGN(xx, 1);
     if (n1 <= KARATSUBA_DIGITS) {
-        len = off + big2str_orig(xx, base, ptr + off, n2, hbase, trim);
+	len = off + big2str_orig(xx, base, ptr + off, n2, hbase, trim);
     }
     else {
-        len = off + big2str_karatsuba(xx, base, ptr + off, n1,
-                                      n2, hbase, trim);
+	len = off + big2str_karatsuba(xx, base, ptr + off, n1,
+				      n2, hbase, trim);
     }
 
     ptr[len] = '\0';
@@ -988,12 +999,15 @@
 static VALUE
 rb_big_to_s(int argc, VALUE *argv, VALUE x)
 {
-    VALUE b;
     int base;
 
-    rb_scan_args(argc, argv, "01", &b);
     if (argc == 0) base = 10;
-    else base = NUM2INT(b);
+    else {
+	VALUE b;
+
+	rb_scan_args(argc, argv, "01", &b);
+	base = NUM2INT(b);
+    }
     return rb_big2str(x, base);
 }
 
@@ -1137,15 +1151,64 @@
     return bignorm(dbl2big(d));
 }
 
+static int
+nlz(BDIGIT x)
+{
+    BDIGIT y;
+    int n = BITSPERDIG;
+#if BITSPERDIG > 64
+    y = x >> 64; if (y) {n -= 64; x = y;}
+#endif
+#if BITSPERDIG > 32
+    y = x >> 32; if (y) {n -= 32; x = y;}
+#endif
+#if BITSPERDIG > 16
+    y = x >> 16; if (y) {n -= 16; x = y;}
+#endif
+    y = x >>  8; if (y) {n -=  8; x = y;}
+    y = x >>  4; if (y) {n -=  4; x = y;}
+    y = x >>  2; if (y) {n -=  2; x = y;}
+    y = x >>  1; if (y) {return n - 2;}
+    return n - x;
+}
+
 static double
 big2dbl(VALUE x)
 {
     double d = 0.0;
-    long i = RBIGNUM_LEN(x);
-    BDIGIT *ds = BDIGITS(x);
+    long i = RBIGNUM_LEN(x), lo = 0, bits;
+    BDIGIT *ds = BDIGITS(x), dl;
 
-    while (i--) {
-	d = ds[i] + BIGRAD*d;
+    if (i) {
+	bits = i * BITSPERDIG - nlz(ds[i-1]);
+	if (bits > DBL_MANT_DIG+DBL_MAX_EXP) {
+	    d = HUGE_VAL;
+	}
+	else {
+	    if (bits > DBL_MANT_DIG+1)
+		lo = (bits -= DBL_MANT_DIG+1) / BITSPERDIG;
+	    else
+		bits = 0;
+	    while (--i > lo) {
+		d = ds[i] + BIGRAD*d;
+	    }
+	    dl = ds[i];
+	    if (bits && (dl & (1UL << (bits %= BITSPERDIG)))) {
+		int carry = dl & ~(~0UL << bits);
+		if (!carry) {
+		    while (i-- > 0) {
+			if ((carry = ds[i]) != 0) break;
+		    }
+		}
+		if (carry) {
+		    dl &= ~0UL << bits;
+		    dl += 1UL << bits;
+		    if (!dl) d += 1;
+		}
+	    }
+	    d = dl + BIGRAD*d;
+	    if (lo) d = ldexp(d, lo * BITSPERDIG);
+	}
     }
     if (!RBIGNUM_SIGN(x)) d = -d;
     return d;
@@ -1157,7 +1220,7 @@
     double d = big2dbl(x);
 
     if (isinf(d)) {
-	rb_warn("Bignum out of Float range");
+	rb_warning("Bignum out of Float range");
 	d = HUGE_VAL;
     }
     return d;
@@ -1738,16 +1801,9 @@
     }
 }
 
-/*
- *  call-seq:
- *     big / other     => Numeric
- *     big.div(other)  => Numeric
- *
- *  Divides big by other, returning the result.
- */
 
-VALUE
-rb_big_div(VALUE x, VALUE y)
+static VALUE
+rb_big_divide(VALUE x, VALUE y, ID op)
 {
     VALUE z;
 
@@ -1760,10 +1816,18 @@
 	break;
 
       case T_FLOAT:
-	return DOUBLE2NUM(rb_big2dbl(x) / RFLOAT_VALUE(y));
+	{
+	    double div = rb_big2dbl(x) / RFLOAT_VALUE(y);
+	    if (op == '/') {
+		return DOUBLE2NUM(div);
+	    }
+	    else {
+		return rb_dbl2big(div);
+	    }
+	}
 
       default:
-	return rb_num_coerce_bin(x, y, '/');
+	return rb_num_coerce_bin(x, y, op);
     }
     bigdivmod(x, y, &z, 0);
 
@@ -1772,6 +1836,25 @@
 
 /*
  *  call-seq:
+ *     big / other     => Numeric
+ *
+ *  Divides big by other, returning the result.
+ */
+
+VALUE
+rb_big_div(VALUE x, VALUE y)
+{
+  return rb_big_divide(x, y, '/');
+}
+
+VALUE
+rb_big_idiv(VALUE x, VALUE y)
+{
+  return rb_big_divide(x, y, rb_intern("div"));
+}
+
+/*
+ *  call-seq:
  *     big % other         => Numeric
  *     big.modulo(other)   => Numeric
  *
@@ -1893,19 +1976,18 @@
 
 /*
  *  call-seq:
- *     big.quo(numeric) -> float
- *     big.fdiv(numeric) -> float
+  *     big.fdiv(numeric) -> float
  *
  *  Returns the floating point result of dividing <i>big</i> by
  *  <i>numeric</i>.
  *
- *     -1234567890987654321.quo(13731)      #=> -89910996357705.5
- *     -1234567890987654321.quo(13731.24)   #=> -89909424858035.7
+ *     -1234567890987654321.fdiv(13731)      #=> -89910996357705.5
+ *     -1234567890987654321.fdiv(13731.24)   #=> -89909424858035.7
  *
  */
 
 static VALUE
-rb_big_quo(VALUE x, VALUE y)
+rb_big_fdiv(VALUE x, VALUE y)
 {
     double dx = big2dbl(x);
     double dy;
@@ -1933,6 +2015,7 @@
 	    return DOUBLE2NUM(ldexp(big2dbl(z), ex - ey));
 	  }
 	  case T_FLOAT:
+	    if (isnan(RFLOAT_VALUE(y))) return y;
 	    y = dbl2big(ldexp(frexp(RFLOAT_VALUE(y), &ey), DBL_MANT_DIG));
 	    ey -= DBL_MANT_DIG;
 	    goto bignum;
@@ -1952,7 +2035,7 @@
 	break;
 
       default:
-	return rb_num_coerce_bin(x, y, rb_intern("quo"));
+	return rb_num_coerce_bin(x, y, rb_intern("fdiv"));
     }
     return DOUBLE2NUM(dx / dy);
 }
@@ -1977,8 +2060,8 @@
     z = bigsqr(b);
     rb_big_realloc(z, (len = 2 * k + RBIGNUM_LEN(a2)) + 1);
     while (RBIGNUM_LEN(z) < 2 * k) {
-          BDIGITS(z)[RBIGNUM_LEN(z)] = 0;
-          RBIGNUM_SET_LEN(z, RBIGNUM_LEN(z)+1);
+	BDIGITS(z)[RBIGNUM_LEN(z)] = 0;
+	RBIGNUM_SET_LEN(z, RBIGNUM_LEN(z)+1);
     }
     MEMCPY(BDIGITS(z) + 2 * k, BDIGITS(a2), BDIGIT, RBIGNUM_LEN(a2));
     RBIGNUM_SET_LEN(z, len);
@@ -1998,7 +2081,7 @@
 	}
 	if (num) {
 	    BDIGITS(z)[RBIGNUM_LEN(z)] = BIGLO(num);
-            RBIGNUM_SET_LEN(z, RBIGNUM_LEN(z)+1);
+	    RBIGNUM_SET_LEN(z, RBIGNUM_LEN(z)+1);
 	}
     }
     return bigtrunc(z);
@@ -2006,7 +2089,7 @@
 
 /*
  *  call-seq:
- *     big ** exponent   #=> numeric
+ *     big ** exponent   => numeric
  *
  *  Raises _big_ to the _exponent_ power (which may be an integer, float,
  *  or anything that will coerce to a number). The result may be
@@ -2030,13 +2113,19 @@
 	break;
 
       case T_BIGNUM:
+	if (rb_funcall(y, '<', 1, INT2FIX(0)))
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+
 	rb_warn("in a**b, b may be too big");
 	d = rb_big2dbl(y);
 	break;
 
       case T_FIXNUM:
 	yy = FIX2LONG(y);
-	if (yy > 0) {
+
+	if (yy < 0)
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+	else {
 	    VALUE z = 0;
 	    SIGNED_VALUE mask;
 	    const long BIGLEN_LIMIT = 1024*1024 / SIZEOF_BDIGITS;
@@ -2055,7 +2144,7 @@
 	    }
 	    return bignorm(z);
 	}
-	d = (double)yy;
+	/* NOTREACHED */
 	break;
 
       default:
@@ -2064,6 +2153,18 @@
     return DOUBLE2NUM(pow(rb_big2dbl(x), d));
 }
 
+static VALUE
+bit_coerce(VALUE x)
+{
+    while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) {
+	if (TYPE(x) == T_FLOAT) {
+	    rb_raise(rb_eTypeError, "can't convert Float into Integer");
+	}
+	x = rb_to_int(x);
+    }
+    return x;
+}
+
 /*
  * call-seq:
  *     big & numeric   =>  integer
@@ -2080,7 +2181,7 @@
     char sign;
 
     x = xx;
-    y = rb_to_int(yy);
+    y = bit_coerce(yy);
     if (FIXNUM_P(y)) {
 	y = rb_int2big(FIX2LONG(y));
     }
@@ -2135,7 +2236,7 @@
     char sign;
 
     x = xx;
-    y = rb_to_int(yy);
+    y = bit_coerce(yy);
     if (FIXNUM_P(y)) {
 	y = rb_int2big(FIX2LONG(y));
     }
@@ -2193,7 +2294,7 @@
     char sign;
 
     x = xx;
-    y = rb_to_int(yy);
+    y = bit_coerce(yy);
     if (FIXNUM_P(y)) {
 	y = rb_int2big(FIX2LONG(y));
     }
@@ -2590,12 +2691,11 @@
     rb_define_method(rb_cBignum, "*", rb_big_mul, 1);
     rb_define_method(rb_cBignum, "/", rb_big_div, 1);
     rb_define_method(rb_cBignum, "%", rb_big_modulo, 1);
-    rb_define_method(rb_cBignum, "div", rb_big_div, 1);
+    rb_define_method(rb_cBignum, "div", rb_big_idiv, 1);
     rb_define_method(rb_cBignum, "divmod", rb_big_divmod, 1);
     rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1);
     rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1);
-    rb_define_method(rb_cBignum, "quo", rb_big_quo, 1);
-    rb_define_method(rb_cBignum, "fdiv", rb_big_quo, 1);
+    rb_define_method(rb_cBignum, "fdiv", rb_big_fdiv, 1);
     rb_define_method(rb_cBignum, "**", rb_big_pow, 1);
     rb_define_method(rb_cBignum, "&", rb_big_and, 1);
     rb_define_method(rb_cBignum, "|", rb_big_or, 1);

Modified: MacRuby/trunk/bootstraptest/runner.rb
===================================================================
--- MacRuby/trunk/bootstraptest/runner.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/bootstraptest/runner.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,4 +1,4 @@
-# $Id: runner.rb 15443 2008-02-12 06:28:23Z naruse $
+# $Id: runner.rb 16364 2008-05-11 13:54:04Z nobu $
 
 # NOTE:
 # Never use optparse in this file.
@@ -52,7 +52,8 @@
     when /\A--ruby=(.*)/
       @ruby = $1
       @ruby.gsub!(/^([^ ]*)/){File.expand_path($1)}
-      @ruby.gsub!(/-I([^ ]*)/){"-I"+File.expand_path($1)}
+      @ruby.gsub!(/(\s+-I\s*)((?!(?:\.\/)*-(?:\s|\z))\S+)/){$1+File.expand_path($2)}
+      @ruby.gsub!(/(\s+-r\s*)(\.\.?\/\S+)/){$1+File.expand_path($2)}
       true
     when /\A--sets=(.*)/
       tests = Dir.glob("#{File.dirname($0)}/test_{#{$1}}*.rb")
@@ -79,14 +80,14 @@
     -q, --quiet                     Don\'t print header message.
     -h, --help                      Print this message and quit.
 End
-      exit 0
+      exit true
     else
       false
     end
   }
   if tests and not ARGV.empty?
     $stderr.puts "--tests and arguments are exclusive"
-    exit 1
+    exit false
   end
   tests ||= ARGV
   tests = Dir.glob("#{File.dirname($0)}/test_*.rb") if tests.empty?
@@ -96,7 +97,7 @@
     puts Time.now
     patchlevel = defined?(RUBY_PATCHLEVEL) ? " patchlevel #{RUBY_PATCHLEVEL}" : ''
     puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}#{patchlevel}) [#{RUBY_PLATFORM}]"
-    puts "Target is #{`#{@ruby} -v`}"
+    puts "Target is #{`#{@ruby} -v`.chomp}"
     puts
     $stdout.flush
   end
@@ -118,13 +119,13 @@
   $stderr.puts
   if @error == 0
     $stderr.puts "PASS #{@count} tests"
-    exit 0
+    exit true
   else
     @errbuf.each do |msg|
       $stderr.puts msg
     end
     $stderr.puts "FAIL #{@error}/#{@count} tests failed"
-    exit 1
+    exit false
   end
 end
 

Modified: MacRuby/trunk/bootstraptest/test_knownbug.rb
===================================================================
--- MacRuby/trunk/bootstraptest/test_knownbug.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/bootstraptest/test_knownbug.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,8 +3,6 @@
 # So all tests will cause failure.
 #
 
-=begin
-
 assert_equal 'ok', %q{
   class C
     define_method(:foo) {
@@ -53,8 +51,194 @@
   "".center(1, "\x80".force_encoding("utf-8"))
 }, '[ruby-dev:33807]'
 
+assert_equal 'ok', %q{
+  a = lambda {|x, y, &b| b }
+  b = a.curry[1]
+  if b.call(2){} == nil
+    :ng
+  else
+    :ok
+  end
+}, '[ruby-core:15551]'
+
 assert_normal_exit %q{
-  ARGF.set_encoding "foo"
+  sprintf("% 0e", 1.0/0.0)
 }
 
-=end
+assert_normal_exit %q{
+  g = Module.enum_for(:new)
+  loop { g.next }
+}, '[ruby-dev:34128]'
+
+assert_normal_exit %q{
+  Fiber.new(&Object.method(:class_eval)).resume("foo")
+}, '[ruby-dev:34128]'
+
+assert_normal_exit %q{
+  Thread.new("foo", &Object.method(:class_eval)).join
+}, '[ruby-dev:34128]'
+
+assert_normal_exit %q{
+  g = enum_for(:local_variables)
+  loop { g.next }
+}, '[ruby-dev:34128]'
+
+assert_normal_exit %q{
+  g = enum_for(:block_given?)
+  loop { g.next }
+}, '[ruby-dev:34128]'
+
+assert_normal_exit %q{
+  g = enum_for(:binding)
+  loop { g.next }
+}, '[ruby-dev:34128]'
+
+assert_normal_exit %q{
+  g = "abc".enum_for(:scan, /./)
+  loop { g.next }
+}, '[ruby-dev:34128]'
+
+assert_equal %q{[:bar, :foo]}, %q{
+  def foo
+    klass = Class.new do
+      define_method(:bar) do
+        return :bar
+      end
+    end
+    [klass.new.bar, :foo]
+  end
+  foo
+}, "[ ruby-Bugs-19304 ]"
+
+assert_equal 'ok', %q{
+  def a() end
+  begin
+    if defined?(a(1).a)
+      :ng
+    else
+      :ok
+    end
+  rescue
+    :ng
+  end
+}, '[ruby-core:16010]'
+
+assert_equal 'ok', %q{
+  def a() end
+  begin
+    if defined?(a::B)
+      :ng
+    else
+      :ok
+    end
+  rescue
+    :ng
+  end
+}, '[ruby-core:16010]'
+
+
+assert_equal 'ok', %q{
+  class Module
+    def my_module_eval(&block)
+      module_eval(&block)
+    end
+  end
+  class String
+    Integer.my_module_eval do
+      def hoge; end
+    end
+  end
+  if Integer.instance_methods(false).map{|m|m.to_sym}.include?(:hoge) &&
+     !String.instance_methods(false).map{|m|m.to_sym}.include?(:hoge)
+    :ok
+  else
+    :ng
+  end
+}, "[ruby-dev:34236]"
+
+assert_equal 'ok', %q{
+  def m
+    t = Thread.new { while true do // =~ "" end }
+    sleep 0.1
+    10.times {
+      if /((ab)*(ab)*)*(b)/ =~ "ab"*7
+        return :ng if !$4
+        return :ng if $~.size != 5
+      end
+    }
+    :ok
+  ensure
+    Thread.kill t
+  end
+  m
+}, '[ruby-dev:34492]'
+
+assert_normal_exit %q{
+  begin
+    r = 0**-1
+    r + r
+  rescue
+  end
+}, '[ruby-dev:34524]'
+
+assert_normal_exit %q{
+  begin
+    r = Marshal.load("\x04\bU:\rRational[\ai\x06i\x05")
+    r + r
+  rescue
+  end
+}, '[ruby-dev:34536]'
+
+assert_normal_exit %q{
+  begin
+    Struct.new(0)
+  rescue
+  end
+}
+
+assert_normal_exit %q{
+  defined? C && 0
+}
+
+assert_normal_exit %q{
+  class C
+    def m
+      defined?(super())
+    end
+  end
+  C.new.m
+}
+
+assert_normal_exit %q{
+  [1,2,3].slice!(1,10000).inspect
+}
+
+assert_equal 'ok', %q{
+  begin
+    eval("class nil::Foo; end")
+    :ng
+  rescue Exception
+    :ok
+  end
+}
+
+assert_normal_exit %q{
+  at_exit { Fiber.new{}.resume }
+}
+
+assert_equal 'ok', %q{
+  lambda {
+    break :ok
+    :ng
+  }.call
+}, '[ruby-dev:34646]'
+
+assert_equal 'ok', %q{
+  begin
+    0.instance_eval { def m() :m end }
+    1.m
+    :ng
+  rescue Exception
+    :ok
+  end
+}, '[ruby-dev:34579]'

Modified: MacRuby/trunk/bootstraptest/test_thread.rb
===================================================================
--- MacRuby/trunk/bootstraptest/test_thread.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/bootstraptest/test_thread.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -213,3 +213,36 @@
     true
   end
 }
+
+assert_finish 3, %{
+  th = Thread.new {sleep 2}
+  th.join(1)
+  th.join
+}
+
+assert_finish 3, %{
+  require 'timeout'
+  th = Thread.new {sleep 2}
+  begin
+    Timeout.timeout(1) {th.join}
+  rescue Timeout::Error
+  end
+  th.join
+}
+
+assert_normal_exit %q{
+  STDERR.reopen(STDOUT)
+  exec "/"
+}
+
+assert_normal_exit %q{
+  (0..10).map {
+    Thread.new {
+     10000.times {
+        Object.new.to_s
+      }
+    }
+  }.each {|t|
+    t.join
+  }
+}

Modified: MacRuby/trunk/class.c
===================================================================
--- MacRuby/trunk/class.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/class.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -328,7 +328,6 @@
     RCLASS_SUPER(clone) = RCLASS_SUPER(orig);
 #if WITH_OBJC
     {
-#if 1
 	Class ocsuper;
 	extern VALUE rb_cStringRuby;
 	extern VALUE rb_cArrayRuby;
@@ -344,13 +343,6 @@
 	    ocsuper = class_getSuperclass(RCLASS_OCID(orig));
 	}
 	class_setSuperclass(RCLASS(clone)->ocklass, ocsuper);
-#else
-	char *ocname = strdup(class_getName(RCLASS_OCID(clone)));
-	objc_disposeClassPair(RCLASS_OCID(clone));
-	RCLASS(clone)->ocklass = objc_duplicateClass(RCLASS_OCID(orig), 
-						     ocname, 0);
-	free(ocname);
-#endif
     }
 #endif
     if (RCLASS_IV_TBL(orig)) {
@@ -937,9 +929,9 @@
  *       def method3()  end
  *     end
  *     
- *     A.instance_methods                #=> ["method1"]
- *     B.instance_methods(false)         #=> ["method2"]
- *     C.instance_methods(false)         #=> ["method3"]
+ *     A.instance_methods                #=> [:method1]
+ *     B.instance_methods(false)         #=> [:method2]
+ *     C.instance_methods(false)         #=> [:method3]
  *     C.instance_methods(true).length   #=> 43
  */
 
@@ -977,8 +969,8 @@
  *       private :method1
  *       def method2()  end
  *     end
- *     Mod.instance_methods           #=> ["method2"]
- *     Mod.private_instance_methods   #=> ["method1"]
+ *     Mod.instance_methods           #=> [:method2]
+ *     Mod.private_instance_methods   #=> [:method1]
  */
 
 VALUE
@@ -1029,9 +1021,9 @@
  *       end
  *     end
  *     
- *     Single.singleton_methods    #=> ["four"]
- *     a.singleton_methods(false)  #=> ["two", "one"]
- *     a.singleton_methods         #=> ["two", "one", "three"]
+ *     Single.singleton_methods    #=> [:four]
+ *     a.singleton_methods(false)  #=> [:two, :one]
+ *     a.singleton_methods         #=> [:two, :one, :three]
  */
 
 VALUE
@@ -1040,10 +1032,12 @@
     VALUE recur, ary, klass;
     st_table *list;
 
-    rb_scan_args(argc, argv, "01", &recur);
     if (argc == 0) {
 	recur = Qtrue;
     }
+    else {
+	rb_scan_args(argc, argv, "01", &recur);
+    }
     klass = CLASS_OF(obj);
     list = st_init_numtable();
     if (klass && FL_TEST(klass, FL_SINGLETON)) {

Modified: MacRuby/trunk/common.mk
===================================================================
--- MacRuby/trunk/common.mk	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/common.mk	2008-05-18 08:10:19 UTC (rev 199)
@@ -4,7 +4,8 @@
 
 .SUFFIXES: .inc
 
-RUBYOPT       =
+RUBYLIB       = -
+RUBYOPT       = -
 
 STATIC_RUBY   = static-ruby
 
@@ -18,11 +19,13 @@
 MAINOBJ       = $(NORMALMAINOBJ)
 EXTOBJS	      = 
 DLDOBJS	      = $(DMYEXT)
+MINIOBJS      = $(ARCHMINIOBJS) dmyencoding.$(OBJEXT) miniprelude.$(OBJEXT)
 
 COMMONOBJS    = array.$(OBJEXT) \
 		bignum.$(OBJEXT) \
 		class.$(OBJEXT) \
 		compar.$(OBJEXT) \
+		complex.$(OBJEXT) \
 		dir.$(OBJEXT) \
 		enum.$(OBJEXT) \
 		enumerator.$(OBJEXT) \
@@ -45,6 +48,7 @@
 		prec.$(OBJEXT) \
 		random.$(OBJEXT) \
 		range.$(OBJEXT) \
+		rational.$(OBJEXT) \
 		re.$(OBJEXT) \
 		regcomp.$(OBJEXT) \
 		regenc.$(OBJEXT) \
@@ -59,6 +63,7 @@
 		string.$(OBJEXT) \
 		struct.$(OBJEXT) \
 		time.$(OBJEXT) \
+		transcode.$(OBJEXT) \
 		util.$(OBJEXT) \
 		variable.$(OBJEXT) \
 		version.$(OBJEXT) \
@@ -78,11 +83,13 @@
 OBJS          = dln.$(OBJEXT) \
 		encoding.$(OBJEXT) \
 		prelude.$(OBJEXT) \
-		transcode.$(OBJEXT) \
 		$(COMMONOBJS)
 
 GOLFOBJS      = goruby.$(OBJEXT) golf_prelude.$(OBJEXT)
 
+PRELUDE_SCRIPTS = $(srcdir)/prelude.rb $(srcdir)/enc/prelude.rb $(srcdir)/gem_prelude.rb
+PRELUDES      = prelude.c miniprelude.c golf_prelude.c
+
 SCRIPT_ARGS   =	--dest-dir="$(DESTDIR)" \
 		--extout="$(EXTOUT)" \
 		--mflags="$(MFLAGS)" \
@@ -105,10 +112,15 @@
 
 VCS           = svn
 
-all: $(MKFILES) $(PREP) encdb transdb $(RBCONFIG) $(LIBRUBY) encs
+all: $(MKFILES) $(PREP) incs $(RBCONFIG) $(LIBRUBY) encs
 	@$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS)
 prog: $(PROGRAM) $(WPROGRAM)
 
+loadpath: $(PREP)
+	$(MINIRUBY) -e 'p $$:'
+
+$(PREP): $(MKFILES)
+
 miniruby$(EXEEXT): config.status $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(DMYEXT) $(ARCHFILE)
 
 GORUBY = go$(RUBY_INSTALL_NAME)
@@ -121,7 +133,7 @@
 
 $(LIBRUBY_A):	$(OBJS) $(DMYEXT) $(ARCHFILE)
 
-$(LIBRUBY_SO):	$(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(LIBRUBY_SO_UPDATE)
+$(LIBRUBY_SO):	$(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(LIBRUBY_SO_UPDATE) $(BUILTIN_ENCOBJS)
 
 $(LIBRUBY_EXTS):
 	@exit > $@
@@ -309,9 +321,9 @@
 
 clean: clean-ext clean-local clean-enc
 clean-local::
-	@$(RM) $(OBJS) $(MINIOBJS) $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
+	@$(RM) $(OBJS) $(MINIOBJS) $(MAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
 	@$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE) .*.time
-	@$(RM) *.inc $(GOLFOBJS) y.tab.c y.output
+	@$(RM) *.inc $(GOLFOBJS) y.tab.c y.output encdb.h transdb.h
 clean-ext:
 	@-$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) clean
 clean-enc:
@@ -319,7 +331,7 @@
 
 distclean: distclean-ext distclean-local distclean-enc
 distclean-local:: clean-local
-	@$(RM) $(MKFILES) config.h rbconfig.rb yasmdata.rb encdb.h
+	@$(RM) $(MKFILES) $(arch_hdrdir)/ruby/config.h rbconfig.rb yasmdata.rb encdb.h
 	@$(RM) config.cache config.log config.status config.status.lineno $(PRELUDES)
 	@$(RM) *~ *.bak *.stackdump core *.core gmon.out $(PREP)
 distclean-ext:
@@ -425,6 +437,9 @@
 compar.$(OBJEXT): {$(VPATH)}compar.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h
+complex.$(OBJEXT): {$(VPATH)}complex.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
+  {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
+  {$(VPATH)}st.h
 dir.$(OBJEXT): {$(VPATH)}dir.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h {$(VPATH)}util.h
@@ -438,7 +453,7 @@
   {$(VPATH)}config.h {$(VPATH)}defines.h {$(VPATH)}missing.h \
   {$(VPATH)}intern.h {$(VPATH)}st.h {$(VPATH)}encoding.h \
   {$(VPATH)}oniguruma.h {$(VPATH)}regenc.h
-encoding.$(OBJEXT): dmyencoding.$(OBJEXT) {$(VPATH)}encdb.h
+encoding.$(OBJEXT): dmyencoding.$(OBJEXT)
 enum.$(OBJEXT): {$(VPATH)}enum.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h {$(VPATH)}node.h {$(VPATH)}util.h
@@ -474,7 +489,7 @@
   {$(VPATH)}regex.h {$(VPATH)}oniguruma.h {$(VPATH)}io.h \
   {$(VPATH)}encoding.h {$(VPATH)}vm_core.h {$(VPATH)}debug.h \
   {$(VPATH)}vm_opts.h {$(VPATH)}id.h {$(VPATH)}thread_$(THREAD_MODEL).h \
-  {$(VPATH)}gc.h
+  {$(VPATH)}gc.h {$(VPATH)}eval_intern.h
 hash.$(OBJEXT): {$(VPATH)}hash.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h {$(VPATH)}util.h {$(VPATH)}signal.h
@@ -531,6 +546,9 @@
 range.$(OBJEXT): {$(VPATH)}range.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h
+rational.$(OBJEXT): {$(VPATH)}rational.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
+  {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
+  {$(VPATH)}st.h
 re.$(OBJEXT): {$(VPATH)}re.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h {$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}oniguruma.h \
@@ -586,11 +604,10 @@
   {$(VPATH)}debug.h {$(VPATH)}vm_opts.h {$(VPATH)}id.h \
   {$(VPATH)}thread_$(THREAD_MODEL).h {$(VPATH)}dln.h {$(VPATH)}vm.h \
   {$(VPATH)}gc.h {$(VPATH)}thread_$(THREAD_MODEL).c
-dmytranscode.$(OBJEXT): {$(VPATH)}transcode.c {$(VPATH)}ruby.h \
+transcode.$(OBJEXT): {$(VPATH)}transcode.c {$(VPATH)}ruby.h \
   {$(VPATH)}config.h {$(VPATH)}defines.h {$(VPATH)}missing.h \
   {$(VPATH)}intern.h {$(VPATH)}st.h {$(VPATH)}encoding.h \
   {$(VPATH)}oniguruma.h {$(VPATH)}transcode_data.h
-transcode.$(OBJEXT): dmytranscode.$(OBJEXT) {$(VPATH)}transdb.h
 cont.$(OBJEXT): {$(VPATH)}cont.c {$(VPATH)}ruby.h {$(VPATH)}config.h \
   {$(VPATH)}defines.h {$(VPATH)}missing.h {$(VPATH)}intern.h \
   {$(VPATH)}st.h {$(VPATH)}vm_core.h {$(VPATH)}signal.h {$(VPATH)}node.h \
@@ -684,14 +701,14 @@
   {$(VPATH)}encoding.h
 bs.$(OBJEXT): {$(VPATH)}bs.c {$(VPATH)}bs.h {$(VPATH)}bs_lex.h
 
-INSNS	= opt_sc.inc optinsn.inc optunifs.inc insns.inc \
+INSNS	= opt_sc.inc optinsn.inc optunifs.inc insns.inc insns_info.inc \
 	  vmtc.inc vm.inc
 
 INSNS2VMOPT = --srcdir="$(srcdir)"
 
 $(INSNS): $(srcdir)/insns.def {$(VPATH)}vm_opts.h
 	$(RM) $(PROGRAM)
-	$(BASERUBY) -Ks $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT)
+	$(BASERUBY) -Ks $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT) $@
 
 minsns.inc: $(srcdir)/template/minsns.inc.tmpl
 
@@ -713,37 +730,35 @@
 
 incs: $(INSNS) {$(VPATH)}node_name.inc {$(VPATH)}encdb.h {$(VPATH)}transdb.h $(srcdir)/revision.h
 
+insns: $(INSNS)
+
 node_name.inc: {$(VPATH)}node.h
 	$(BASERUBY) -n $(srcdir)/tool/node_name.rb $? > $@
 
-encdb: $(PREP)
-	$(MINIRUBY) $(srcdir)/enc/make_encdb.rb $(srcdir)/enc encdb.h.new
-	$(IFCHANGE) "encdb.h" "encdb.h.new"
+encdb.h: $(PREP)
+	$(MINIRUBY) $(srcdir)/enc/make_encdb.rb $(srcdir)/enc $@.new
+	$(IFCHANGE) "$@" "$@.new"
 
-encdb.h:
-	$(MINIRUBY) $(srcdir)/enc/make_encdb.rb $(srcdir)/enc $@
+transdb.h: $(PREP)
+	$(MINIRUBY) $(srcdir)/enc/trans/make_transdb.rb $(srcdir)/enc/trans $@.new
+	$(IFCHANGE) "$@" "$@.new"
 
-transdb: $(PREP)
-	$(MINIRUBY) $(srcdir)/enc/trans/make_transdb.rb $(srcdir)/enc/trans transdb.h.new
-	$(IFCHANGE) "transdb.h" "transdb.h.new"
-
-transdb.h:
-	$(MINIRUBY) $(srcdir)/enc/trans/make_transdb.rb $(srcdir)/enc/trans $@
-
 miniprelude.c: $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb
 	$(BASERUBY) -I$(srcdir) $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb $@
 
-prelude.c: $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb $(srcdir)/gem_prelude.rb $(RBCONFIG)
-	$(MINIRUBY) -I$(srcdir) -rrbconfig $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb $(srcdir)/gem_prelude.rb $@
+prelude.c: $(srcdir)/tool/compile_prelude.rb $(PRELUDE_SCRIPTS) $(RBCONFIG) $(PREP)
+	$(MINIRUBY) -I$(srcdir) -rrbconfig $(srcdir)/tool/compile_prelude.rb \
+		$(PRELUDE_SCRIPTS) $@.new
+	$(IFCHANGE) "$@" "$@.new"
 
-golf_prelude.c: $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb $(srcdir)/golf_prelude.rb
-	$(MINIRUBY) -I$(srcdir) -rrbconfig $(srcdir)/tool/compile_prelude.rb $(srcdir)/golf_prelude.rb $@
+golf_prelude.c: $(srcdir)/tool/compile_prelude.rb $(srcdir)/prelude.rb $(srcdir)/golf_prelude.rb $(PREP)
+	$(MINIRUBY) -I$(srcdir) -rrbconfig $(srcdir)/tool/compile_prelude.rb $(srcdir)/golf_prelude.rb $@.new
+	$(IFCHANGE) "$@" "$@.new"
 
 prereq: incs srcs preludes
 
 preludes: {$(VPATH)}miniprelude.c
 preludes: {$(srcdir)}golf_prelude.c
-PRELUDES = prelude.c miniprelude.c golf_prelude.c
 
 docs:
 	$(BASERUBY) -I$(srcdir) $(srcdir)/tool/makedocs.rb $(INSNS2VMOPT)

Modified: MacRuby/trunk/compar.c
===================================================================
--- MacRuby/trunk/compar.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/compar.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   compar.c -
 
-  $Author: akr $
+  $Author: matz $
   created at: Thu Aug 26 14:39:48 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -15,22 +15,6 @@
 
 static ID cmp;
 
-int
-rb_cmpint(VALUE val, VALUE a, VALUE b)
-{
-    if (NIL_P(val)) {
-	rb_cmperr(a, b);
-    }
-    if (FIXNUM_P(val)) return FIX2INT(val);
-    if (TYPE(val) == T_BIGNUM) {
-	if (RBIGNUM_SIGN(val)) return 1;
-	return -1;
-    }
-    if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1;
-    if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1;
-    return 0;
-}
-
 void
 rb_cmperr(VALUE x, VALUE y)
 {

Modified: MacRuby/trunk/compile.c
===================================================================
--- MacRuby/trunk/compile.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/compile.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   compile.c - ruby node tree -> VM instruction sequence
 
-  $Author: matz $
+  $Author: ko1 $
   created at: 04/01/01 03:42:15 JST
 
   Copyright (C) 2004-2007 Koichi Sasada
@@ -34,13 +34,13 @@
 
 /* types */
 
-#define ISEQ_ELEMENT_NONE   INT2FIX(0x00)
-#define ISEQ_ELEMENT_LABEL  INT2FIX(0x01)
-#define ISEQ_ELEMENT_INSN   INT2FIX(0x02)
-#define ISEQ_ELEMENT_ADJUST INT2FIX(0x03)
-
 typedef struct iseq_link_element {
-    int type;
+    enum {
+	ISEQ_ELEMENT_NONE   = INT2FIX(0x00),
+	ISEQ_ELEMENT_LABEL  = INT2FIX(0x01),
+	ISEQ_ELEMENT_INSN   = INT2FIX(0x02),
+	ISEQ_ELEMENT_ADJUST = INT2FIX(0x03),
+    } type;
     struct iseq_link_element *next;
     struct iseq_link_element *prev;
 } LINK_ELEMENT;
@@ -61,7 +61,7 @@
 
 typedef struct iseq_insn_data {
     LINK_ELEMENT link;
-    int insn_id;
+    enum ruby_vminsn_type insn_id;
     int line_no;
     int operand_size;
     int sc_state;
@@ -92,18 +92,28 @@
 #endif
 
 /* for debug */
-#if CPDEBUG > 0
-static long gl_node_level = 0;
-static void debug_list(LINK_ANCHOR *anchor);
+#if CPDEBUG < 0
+#define ISEQ_ARG iseq,
+#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
+#else
+#define ISEQ_ARG
+#define ISEQ_ARG_DECLARE
 #endif
 
+#if CPDEBUG
+#define gl_node_level iseq->compile_data->node_level
+#if 0
+static void debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor);
+#endif
+#endif
+
 static void dump_disasm_list(LINK_ELEMENT *elem);
 
 static int insn_data_length(INSN *iobj);
 static int insn_data_line_no(INSN *iobj);
 static int calc_sp_depth(int depth, INSN *iobj);
 
-static void ADD_ELEM(LINK_ANCHOR *anchor, LINK_ELEMENT *elem);
+static void ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem);
 
 static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...);
 static LABEL *new_label_body(rb_iseq_t *iseq, int line);
@@ -123,6 +133,59 @@
 static int iseq_set_exception_table(rb_iseq_t *iseq);
 static int iseq_set_optargs_table(rb_iseq_t *iseq);
 
+/*
+ * To make Array to LinkedList, use link_anchor
+ */
+
+static void
+verify_list(ISEQ_ARG_DECLARE char *info, LINK_ANCHOR *anchor)
+{
+#if CPDEBUG
+    int flag = 0;
+    LINK_ELEMENT *list, *plist;
+
+    if (!compile_debug) return;
+
+    list = anchor->anchor.next;
+    plist = &anchor->anchor;
+    while (list) {
+	if (plist != list->prev) {
+	    flag += 1;
+	}
+	plist = list;
+	list = list->next;
+    }
+
+    if (anchor->last != plist && anchor->last != 0) {
+	flag |= 0x70000;
+    }
+
+    if (flag != 0) {
+	rb_bug("list verify error: %08x (%s)", flag, info);
+    }
+#endif
+}
+#if CPDEBUG < 0
+#define verify_list(info, anchor) verify_list(iseq, info, anchor)
+#endif
+
+/*
+ * elem1, elem2 => elem1, elem2, elem
+ */
+static void
+ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem)
+{
+    elem->prev = anchor->last;
+    anchor->last->next = elem;
+    anchor->last = elem;
+    verify_list("add", anchor);
+}
+#if CPDEBUG < 0
+#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, anchor, elem)
+#endif
+
+#define ruby_sourcefile		RSTRING_CPTR(iseq->filename)
+
 #if WITH_OBJC
 # define iseq_add_mark_object(x,y)
 # define iseq_add_mark_object_compile_time(x,y)
@@ -313,47 +376,6 @@
 }
 
 /*
- * To make Array to LinkedList, use link_anchor
- */
-
-static void
-verify_list(char *info, LINK_ANCHOR *anchor)
-{
-#if CPDEBUG > 0
-    int flag = 0;
-    LINK_ELEMENT *list = anchor->anchor.next, *plist = &anchor->anchor;
-
-    while (list) {
-	if (plist != list->prev) {
-	    flag += 1;
-	}
-	plist = list;
-	list = list->next;
-    }
-
-    if (anchor->last != plist && anchor->last != 0) {
-	flag |= 0x70000;
-    }
-
-    if (flag != 0) {
-	rb_bug("list verify error: %08x (%s)", flag, info);
-    }
-#endif
-}
-
-/*
- * elem1, elem2 => elem1, elem2, elem
- */
-static void
-ADD_ELEM(LINK_ANCHOR *anchor, LINK_ELEMENT *elem)
-{
-    elem->prev = anchor->last;
-    anchor->last->next = elem;
-    anchor->last = elem;
-    verify_list("add", anchor);
-}
-
-/*
  * elem1, elemX => elem1, elem2, elemX
  */
 static void
@@ -423,7 +445,7 @@
 #endif
 
 static LINK_ELEMENT *
-POP_ELEMENT(LINK_ANCHOR *anchor)
+POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
 {
     LINK_ELEMENT *elem = anchor->last;
     anchor->last = anchor->last->prev;
@@ -431,6 +453,9 @@
     verify_list("pop", anchor);
     return elem;
 }
+#if CPDEBUG < 0
+#define POP_ELEMENT(anchor) POP_ELEMENT(iseq, anchor)
+#endif
 
 #if 0 /* unused */
 static LINK_ELEMENT *
@@ -477,7 +502,7 @@
  * anc2: e4, e5 (broken)
  */
 static void
-APPEND_LIST(LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
+APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
 {
     if (anc2->anchor.next) {
 	anc1->last->next = anc2->anchor.next;
@@ -486,6 +511,9 @@
     }
     verify_list("append", anc1);
 }
+#if CPDEBUG < 0
+#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, anc1, anc2)
+#endif
 
 /*
  * anc1: e1, e2, e3
@@ -495,7 +523,7 @@
  * anc2: e4, e5 (broken)
  */
 static void
-INSERT_LIST(LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
+INSERT_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
 {
     if (anc2->anchor.next) {
 	LINK_ELEMENT *first = anc1->anchor.next;
@@ -512,6 +540,9 @@
 
     verify_list("append", anc1);
 }
+#if CPDEBUG < 0
+#define INSERT_LIST(anc1, anc2) INSERT_LIST(iseq, anc1, anc2)
+#endif
 
 #if 0 /* unused */
 /*
@@ -522,7 +553,7 @@
  * anc2: e1, e2, e3
  */
 static void
-SWAP_LIST(LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
+SWAP_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
 {
     LINK_ANCHOR tmp = *anc2;
 
@@ -533,9 +564,12 @@
     verify_list("swap1", anc1);
     verify_list("swap2", anc2);
 }
+#if CPDEBUG < 0
+#define SWAP_LIST(anc1, anc2) SWAP_LIST(iseq, anc1, anc2)
+#endif
 
 static LINK_ANCHOR *
-REVERSE_LIST(LINK_ANCHOR *anc)
+REVERSE_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc)
 {
     LINK_ELEMENT *first, *last, *elem, *e;
     first = &anc->anchor;
@@ -564,11 +598,14 @@
     verify_list("reverse", anc);
     return anc;
 }
+#if CPDEBUG < 0
+#define REVERSE_LIST(anc) REVERSE_LIST(iseq, anc)
 #endif
+#endif
 
-#if CPDEBUG > 0
+#if CPDEBUG && 0
 static void
-debug_list(LINK_ANCHOR *anchor)
+debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
 {
     LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
     printf("----\n");
@@ -584,18 +621,20 @@
     dump_disasm_list(anchor->anchor.next);
     verify_list("debug list", anchor);
 }
+#if CPDEBUG < 0
+#define debug_list(anc) debug_list(iseq, anc)
 #endif
+#endif
 
 static LABEL *
 new_label_body(rb_iseq_t *iseq, int line)
 {
     LABEL *labelobj = compile_data_alloc_label(iseq);
-    static int label_no = 0;
 
     labelobj->link.type = ISEQ_ELEMENT_LABEL;
     labelobj->link.next = 0;
 
-    labelobj->label_no = label_no++;
+    labelobj->label_no = iseq->compile_data->label_no++;
     labelobj->sc_state = 0;
     labelobj->sp = -1;
     return labelobj;
@@ -681,32 +720,32 @@
 {
     /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
 
-    if (CPDEBUG > 5)
+    if (compile_debug > 5)
 	dump_disasm_list(FIRST_ELEMENT(anchor));
 
     debugs("[compile step 3.1 (iseq_optimize)]\n");
     iseq_optimize(iseq, anchor);
 
-    if (CPDEBUG > 5)
+    if (compile_debug > 5)
 	dump_disasm_list(FIRST_ELEMENT(anchor));
 
     if (iseq->compile_data->option->instructions_unification) {
 	debugs("[compile step 3.2 (iseq_insns_unification)]\n");
 	iseq_insns_unification(iseq, anchor);
-	if (CPDEBUG > 5)
+	if (compile_debug > 5)
 	    dump_disasm_list(FIRST_ELEMENT(anchor));
     }
 
     if (iseq->compile_data->option->stack_caching) {
 	debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
 	iseq_set_sequence_stackcaching(iseq, anchor);
-	if (CPDEBUG > 5)
+	if (compile_debug > 5)
 	    dump_disasm_list(FIRST_ELEMENT(anchor));
     }
 
     debugs("[compile step 4.1 (iseq_set_sequence)]\n");
     iseq_set_sequence(iseq, anchor);
-    if (CPDEBUG > 5)
+    if (compile_debug > 5)
 	dump_disasm_list(FIRST_ELEMENT(anchor));
 
     debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
@@ -718,7 +757,7 @@
     debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
     iseq_translate_threaded_code(iseq);
 
-    if (CPDEBUG > 1) {
+    if (compile_debug > 1) {
 	VALUE str = ruby_iseq_disasm(iseq->self);
 	printf("%s\n", StringValueCStr(str));
 	fflush(stdout);
@@ -1044,7 +1083,7 @@
 	  case ISEQ_ELEMENT_INSN:
 	    {
 		int j, len, insn;
-		char *types;
+		const char *types;
 		VALUE *operands;
 
 		iobj = (INSN *)list;
@@ -1664,9 +1703,9 @@
 	    iobj = (INSN *)list;
 	    id = iobj->insn_id;
 	    if (unified_insns_data[id] != 0) {
-		int **entry = unified_insns_data[id];
+		const int *const *entry = unified_insns_data[id];
 		for (j = 1; j < (int)entry[0]; j++) {
-		    int *unified = entry[j];
+		    const int *unified = entry[j];
 		    LINK_ELEMENT *li = list->next;
 		    for (k = 2; k < unified[1]; k++) {
 			if (li->type != ISEQ_ELEMENT_INSN ||
@@ -2113,9 +2152,9 @@
 compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *ret,
 		    NODE *rhsn, NODE *orig_lhsn)
 {
-    int memsize = 64;
+    VALUE mem[64];
+    const int memsize = sizeof(mem) / sizeof(mem[0]);
     int memindex = 0;
-    VALUE *mem = ALLOCA_N(VALUE, memsize);
     int llen = 0, rlen = 0;
     int i;
     NODE *lhsn = orig_lhsn;
@@ -2259,24 +2298,29 @@
     return COMPILE_OK;
 }
 
-static int
+static VALUE
 compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath)
 {
-    if (cpath->nd_head) {
+    if (nd_type(cpath) == NODE_COLON3) {
+	/* toplevel class ::Foo */
+	ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
+	return Qfalse;
+    }
+    else if (cpath->nd_head) {
+	/* Bar::Foo */
 	COMPILE(ret, "nd_else->nd_head", cpath->nd_head);
+	return Qfalse;
     }
-    else if (nd_type(cpath) == NODE_COLON2) {
-	COMPILE(ret, "cpath (NODE_COLON2)", cpath->nd_head);
-    }
     else {
-	ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
+	/* class at cbase Foo */
+	ADD_INSN(ret, nd_line(cpath), putcbase);
+	return Qtrue;
     }
-    return COMPILE_OK;
 }
 
 static int
 defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
-	     NODE * node, LABEL *lfinish, VALUE needstr)
+	     NODE *node, LABEL **lfinish, VALUE needstr)
 {
     char *estr = 0;
     enum node_type type;
@@ -2298,22 +2342,21 @@
 	break;
 
       case NODE_ARRAY:{
-	LABEL *lfalse = NULL;
 	NODE *vals = node;
 
 	do {
 	    defined_expr(iseq, ret, vals->nd_head, lfinish, Qfalse);
 
-	    if (lfalse) {
-		ADD_INSNL(ret, nd_line(node), branchunless, lfalse);
+	    if (lfinish[1]) {
+		ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
 	    }
 	    else {
 		LABEL *lcont = NEW_LABEL(nd_line(node));
-		lfalse = NEW_LABEL(nd_line(node));
+		lfinish[1] = NEW_LABEL(nd_line(node));
 		ADD_INSNL(ret, nd_line(node), branchif, lcont);
-		ADD_LABEL(ret, lfalse);
+		ADD_LABEL(ret, lfinish[1]);
 		ADD_INSN(ret, nd_line(node), putnil);
-		ADD_INSNL(ret, nd_line(node), jump, lfinish);
+		ADD_INSNL(ret, nd_line(node), jump, lfinish[0]);
 		ADD_LABEL(ret, lcont);
 	    }
 	} while ((vals = vals->nd_next) != NULL);
@@ -2354,28 +2397,18 @@
 		  ID2SYM(node->nd_vid), needstr);
 	return 1;
       case NODE_COLON2:
+	if (!lfinish[1]) {
+	    lfinish[1] = NEW_LABEL(nd_line(node));
+	}
+	defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
+	ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
+
 	if (rb_is_const_id(node->nd_mid)) {
-	    LABEL *lcont = NEW_LABEL(nd_line(node));
-	    defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
-
-	    ADD_INSNL(ret, nd_line(node), branchif, lcont);
-	    ADD_INSN(ret, nd_line(node), putnil);
-	    ADD_INSNL(ret, nd_line(node), jump, lfinish);
-
-	    ADD_LABEL(ret, lcont);
 	    COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
 	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST),
 		      ID2SYM(node->nd_mid), needstr);
 	}
 	else {
-	    LABEL *lcont = NEW_LABEL(nd_line(node));
-	    defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
-
-	    ADD_INSNL(ret, nd_line(node), branchif, lcont);
-	    ADD_INSN(ret, nd_line(node), putnil);
-	    ADD_INSNL(ret, nd_line(node), jump, lfinish);
-
-	    ADD_LABEL(ret, lcont);
 	    COMPILE(ret, "defined/colon2#nd_head", node->nd_head);
 	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
 		      ID2SYM(node->nd_mid), needstr);
@@ -2392,7 +2425,6 @@
       case NODE_VCALL:
       case NODE_FCALL:
       case NODE_ATTRASGN:{
-	LABEL *lfalse = NULL;
 	int self = Qtrue;
 
 	switch (type) {
@@ -2404,24 +2436,29 @@
 	  default:
 	    /* through */;
 	}
+	if (!lfinish[1]) {
+	    lfinish[1] = NEW_LABEL(nd_line(node));
+	}
 	if (node->nd_args) {
-	    lfalse = NEW_LABEL(nd_line(node));
 	    defined_expr(iseq, ret, node->nd_args, lfinish, Qfalse);
-	    ADD_INSNL(ret, nd_line(node), branchunless, lfalse);
+	    ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
 	}
 	if (!self) {
-	    LABEL *lcont = NEW_LABEL(nd_line(node));
+	    LABEL *lstart = NEW_LABEL(nd_line(node));
+	    LABEL *lend = NEW_LABEL(nd_line(node));
+	    VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(),
+					     rb_str_concat(rb_str_new2
+							   ("defined guard in "),
+							   iseq->name),
+					     ISEQ_TYPE_DEFINED_GUARD);
 
 	    defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse);
-	    ADD_INSNL(ret, nd_line(node), branchif, lcont);
-	    if (lfalse) {
-		ADD_LABEL(ret, lfalse);
-	    }
-	    ADD_INSN(ret, nd_line(node), putnil);
-	    ADD_INSNL(ret, nd_line(node), jump, lfinish);
+	    ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
 
-	    ADD_LABEL(ret, lcont);
+	    ADD_LABEL(ret, lstart);
 	    COMPILE(ret, "defined/recv", node->nd_recv);
+	    ADD_LABEL(ret, lend);
+	    ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
 	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD),
 		      ID2SYM(node->nd_mid), needstr);
 	}
@@ -2429,12 +2466,6 @@
 	    ADD_INSN(ret, nd_line(node), putself);
 	    ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_FUNC),
 		      ID2SYM(node->nd_mid), needstr);
-	    ADD_INSNL(ret, nd_line(node), jump, lfinish);
-	    if (lfalse) {
-		ADD_LABEL(ret, lfalse);
-		ADD_INSN(ret, nd_line(node), putnil);
-		ADD_INSNL(ret, nd_line(node), jump, lfinish);
-	    }
 	}
 	return 1;
       }
@@ -2449,10 +2480,11 @@
       case NODE_NTH_REF:
 	ADD_INSN(ret, nd_line(node), putnil);
 	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_REF),
-		  INT2FIX(node->nd_nth << 1 | type == NODE_BACK_REF),
+		  INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
 		  needstr);
 	return 1;
 
+      case NODE_SUPER:
       case NODE_ZSUPER:
 	ADD_INSN(ret, nd_line(node), putnil);
 	ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0,
@@ -2461,6 +2493,8 @@
 
       case NODE_OP_ASGN1:
       case NODE_OP_ASGN2:
+      case NODE_OP_ASGN_OR:
+      case NODE_OP_ASGN_AND:
       case NODE_MASGN:
       case NODE_LASGN:
       case NODE_DASGN:
@@ -2476,7 +2510,6 @@
       default:{
 	LABEL *lstart = NEW_LABEL(nd_line(node));
 	LABEL *lend = NEW_LABEL(nd_line(node));
-	LABEL *ldefed = NEW_LABEL(nd_line(node));
 	VALUE ensure = NEW_CHILD_ISEQVAL(NEW_NIL(),
 					 rb_str_concat(rb_str_new2
 						       ("defined guard in "),
@@ -2485,10 +2518,10 @@
 
 	ADD_LABEL(ret, lstart);
 	COMPILE(ret, "defined expr (others)", node);
-	ADD_INSNL(ret, nd_line(node), branchif, ldefed);
-	ADD_INSN(ret, nd_line(node), putnil);
-	ADD_INSNL(ret, nd_line(node), jump, lend);
-	ADD_LABEL(ret, ldefed);
+	if (!lfinish[1]) {
+	    lfinish[1] = NEW_LABEL(nd_line(node));
+	}
+	ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]);
 	if (needstr) {
 	    ADD_INSN1(ret, nd_line(node), putstring, rb_str_new2("expression"));
 	}
@@ -2497,7 +2530,7 @@
 	}
 	ADD_LABEL(ret, lend);
 
-	ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, lstart, lend, ensure, lfinish);
+	ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, ensure, lfinish[1]);
 	return 1;
       } /* end of default */
     }
@@ -2782,26 +2815,19 @@
 
 	    vals = node->nd_head;
 	    if (vals) {
-		if (nd_type(vals) == NODE_ARRAY) {
+		switch (nd_type(vals)) {
+		  case NODE_ARRAY:
 		    special_literals = when_vals(iseq, cond_seq, vals, l1, special_literals);
-		}
-		else if (nd_type(vals) == NODE_SPLAT ||
-			 nd_type(vals) == NODE_ARGSCAT ||
-			 nd_type(vals) == NODE_ARGSPUSH) {
-		    NODE *val = vals->nd_head;
+		    break;
+		  case NODE_SPLAT:
+		  case NODE_ARGSCAT:
+		  case NODE_ARGSPUSH:
 		    special_literals = 0;
-
-		    if (nd_type(vals) == NODE_ARGSCAT ||
-			nd_type(vals) == NODE_ARGSPUSH) {
-			when_vals(iseq, cond_seq, vals->nd_head, l1, 0);
-			val = vals->nd_body;
-		    }
-
-		    COMPILE(cond_seq, "when/cond splat", val);
-		    ADD_INSN1(cond_seq, nd_line(val), checkincludearray, Qtrue);
-		    ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
-		}
-		else {
+		    COMPILE(cond_seq, "when/cond splat", vals);
+		    ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue);
+		    ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
+		    break;
+		  default:
 		    rb_bug("NODE_CASE: unknown node (%s)",
 			   ruby_node_name(nd_type(vals)));
 		}
@@ -3106,7 +3132,6 @@
 	}
 	else {
 	    rb_iseq_t *ip;
-	  next_by_throw:
 	    ip = iseq;
 	    while (ip) {
 		level = 0x8000;
@@ -3168,7 +3193,6 @@
 	else {
 	    rb_iseq_t *ip;
 	    unsigned long level;
-	  redo_by_throw:
 	    level = 0x8000 | 0x4000;
 	    ip = iseq;
 	    while (ip) {
@@ -3253,15 +3277,35 @@
 	    label_hit = NEW_LABEL(nd_line(node));
 
 	    narg = resq->nd_args;
-	    while (narg) {
-		COMPILE(ret, "rescue arg", narg->nd_head);
-		ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
-			  INT2FIX(0));
-		ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
-		ADD_INSNL(ret, nd_line(node), branchif, label_hit);
-		narg = narg->nd_next;
+	    if (narg) {
+		switch (nd_type(narg)) {
+		  case NODE_ARRAY:
+		    while (narg) {
+			COMPILE(ret, "rescue arg", narg->nd_head);
+			ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
+				  INT2FIX(0));
+			ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
+			ADD_INSNL(ret, nd_line(node), branchif, label_hit);
+			narg = narg->nd_next;
+		    }
+		    break;
+		  case NODE_SPLAT:
+		  case NODE_ARGSCAT:
+		  case NODE_ARGSPUSH:
+		    ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
+			      INT2FIX(0));
+		    COMPILE(ret, "rescue/cond splat", narg);
+		    ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue);
+		    ADD_INSN(ret, nd_line(node), swap);
+		    ADD_INSN(ret, nd_line(node), pop);
+		    ADD_INSNL(ret, nd_line(node), branchif, label_hit);
+		    break;
+		  default:
+		    rb_bug("NODE_RESBODY: unknown node (%s)",
+			   ruby_node_name(nd_type(narg)));
+		}
 	    }
-	    if (resq->nd_args == 0) {
+	    else {
 		ADD_INSN1(ret, nd_line(node), putobject,
 			  rb_eStandardError);
 		ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(1),
@@ -3414,14 +3458,12 @@
 	}
 
 	if (node->nd_vid) {
-	    ADD_INSN(ret, nd_line(node), putnil);
-	    ADD_INSN1(ret, nd_line(node), setconstant,
-		      ID2SYM(node->nd_vid));
+	    ADD_INSN (ret, nd_line(node), putcbase);
+	    ADD_INSN1(ret, nd_line(node), setconstant, ID2SYM(node->nd_vid));
 	}
 	else {
 	    compile_cpath(ret, iseq, node->nd_else);
-	    ADD_INSN1(ret, nd_line(node), setconstant,
-		      ID2SYM(node->nd_else->nd_mid));
+	    ADD_INSN1(ret, nd_line(node), setconstant, ID2SYM(node->nd_else->nd_mid));
 	}
 	break;
       }
@@ -3627,12 +3669,22 @@
       case NODE_OP_ASGN_AND:
       case NODE_OP_ASGN_OR:{
 	LABEL *lfin = NEW_LABEL(nd_line(node));
-	LABEL *lassign = NEW_LABEL(nd_line(node));
+	LABEL *lassign;
 
 	if (nd_type(node) == NODE_OP_ASGN_OR) {
-	    defined_expr(iseq, ret, node->nd_head, lassign, Qfalse);
+	    LABEL *lfinish[2];
+	    lfinish[0] = lfin;
+	    lfinish[1] = 0;
+	    defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
+	    lassign = lfinish[1];
+	    if (!lassign) {
+		lassign = NEW_LABEL(nd_line(node));
+	    }
 	    ADD_INSNL(ret, nd_line(node), branchunless, lassign);
 	}
+	else {
+	    lassign = NEW_LABEL(nd_line(node));
+	}
 
 	COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
 	ADD_INSN(ret, nd_line(node), dup);
@@ -3827,12 +3879,12 @@
 			for (j=0; j<post_len; j++) {
 			    int idx = liseq->local_size - (post_start + j);
 			    ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
+			}
+			argc = INT2FIX(post_len + post_start);
 		    }
-			argc = INT2FIX(post_len + post_start);
 		}
 	    }
 	}
-	}
 
 	/* dummy reciever */
 	ADD_INSN1(ret, nd_line(node), putobject,
@@ -4227,34 +4279,34 @@
 	break;
       }
       case NODE_ALIAS:{
-	  COMPILE(ret, "alias arg1", node->u1.node);
-	  COMPILE(ret, "alias arg2", node->u2.node);
+	COMPILE(ret, "alias arg1", node->u1.node);
+	COMPILE(ret, "alias arg2", node->u2.node);
 
-	  ADD_INSN1(ret, nd_line(node), alias, Qfalse);
+	ADD_INSN1(ret, nd_line(node), alias, Qfalse);
 
-	  if (!poped) {
-	      ADD_INSN(ret, nd_line(node), putnil);
-	  }
-	  break;
+	if (!poped) {
+	    ADD_INSN(ret, nd_line(node), putnil);
+	}
+	break;
       }
       case NODE_VALIAS:{
-	  ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u1.id));
-	  ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u2.id));
-	  ADD_INSN1(ret, nd_line(node), alias, Qtrue);
+	ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u1.id));
+	ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u2.id));
+	ADD_INSN1(ret, nd_line(node), alias, Qtrue);
 
-	  if (!poped) {
-	      ADD_INSN(ret, nd_line(node), putnil);
-	  }
-	  break;
+	if (!poped) {
+	    ADD_INSN(ret, nd_line(node), putnil);
+	}
+	break;
       }
       case NODE_UNDEF:{
-	  COMPILE(ret, "undef arg", node->u2.node);
-	  ADD_INSN(ret, nd_line(node), undef);
+	COMPILE(ret, "undef arg", node->u2.node);
+	ADD_INSN(ret, nd_line(node), undef);
 
-	  if (!poped) {
-	      ADD_INSN(ret, nd_line(node), putnil);
-	  }
-	  break;
+	if (!poped) {
+	    ADD_INSN(ret, nd_line(node), putnil);
+	}
+	break;
       }
       case NODE_CLASS:{
 	VALUE iseqval =
@@ -4278,7 +4330,7 @@
 	    rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
 	    ISEQ_TYPE_CLASS);
 
-	COMPILE(ret, "mbase", node->nd_cpath->nd_head);
+	compile_cpath(ret, iseq, node->nd_cpath);
 	ADD_INSN (ret, nd_line(node), putnil); /* dummy */
 	ADD_INSN3(ret, nd_line(node), defineclass,
 		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(2));
@@ -4477,9 +4529,16 @@
       }
       case NODE_DEFINED:{
 	if (!poped) {
-	    LABEL *lfinish = NEW_LABEL(nd_line(node));
+	    LABEL *lfinish[2];
+	    lfinish[0] = NEW_LABEL(nd_line(node));
+	    lfinish[1] = 0;
 	    defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue);
-	    ADD_LABEL(ret, lfinish);
+	    if (lfinish[1]) {
+		ADD_INSNL(ret, nd_line(node), jump, lfinish[0]);
+		ADD_LABEL(ret, lfinish[1]);
+		ADD_INSN(ret, nd_line(node), putnil);
+	    }
+	    ADD_LABEL(ret, lfinish[0]);
 	}
 	break;
       }
@@ -4614,7 +4673,7 @@
 
     str = rb_sprintf("%-16s", insn_name(iobj->insn_id));
     if (iobj->operands) {
-	char *types = insn_op_types(iobj->insn_id);
+	const char *types = insn_op_types(iobj->insn_id);
 	int j;
 
 	for (j = 0; types[j]; j++) {

Modified: MacRuby/trunk/compile.h
===================================================================
--- MacRuby/trunk/compile.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/compile.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   compile.h -
 
-  $Author: ko1 $
+  $Author: nobu $
   created at: 04/01/01 23:36:57 JST
 
   Copyright (C) 2004-2007 Koichi Sasada
@@ -15,6 +15,7 @@
 /*  */
 /**
  * debug function(macro) interface depend on CPDEBUG
+ * if it is less than 0, runtime option is in effect.
  *
  * debug level:
  *  0: no debug output
@@ -29,39 +30,44 @@
 #define CPDEBUG 0
 #endif
 
-#if 0
-#undef  CPDEBUG
-#define CPDEBUG 2
+#if CPDEBUG >= 0
+#define compile_debug CPDEBUG
+#else
+#define compile_debug iseq->compile_data->option->debug_level
 #endif
 
 NORETURN(PRINTF_ARGS(void rb_compile_bug(const char*, int, const char*, ...), 3, 4));
 
-#if CPDEBUG > 0
+#if CPDEBUG
 
-#define debugp(header, value) \
-  (ruby_debug_print_indent(0, CPDEBUG, gl_node_level * 2), \
-   ruby_debug_print_value(0, CPDEBUG, header, value))
+#define compile_debug_print_indent(level) \
+    ruby_debug_print_indent(level, compile_debug, gl_node_level * 2)
 
-#define debugi(header, id) \
-  (ruby_debug_print_indent(0, CPDEBUG, gl_node_level * 2), \
-   ruby_debug_print_id(0, CPDEBUG, header, id))
+#define debugp(header, value) (void) \
+  (compile_debug_print_indent(1) && \
+   ruby_debug_print_value(1, compile_debug, header, value))
 
-#define debugp_param(header, value) \
-  (ruby_debug_print_indent(1, CPDEBUG, gl_node_level * 2), \
-   ruby_debug_print_value(1, CPDEBUG, header, value))
+#define debugi(header, id)  (void) \
+  (compile_debug_print_indent(1) && \
+   ruby_debug_print_id(1, compile_debug, header, id))
 
-#define debugp_verbose(header, value) \
-  (ruby_debug_print_indent(2, CPDEBUG, gl_node_level * 2), \
-   ruby_debug_print_value(2, CPDEBUG, header, value))
+#define debugp_param(header, value)  (void) \
+  (compile_debug_print_indent(1) && \
+   ruby_debug_print_value(1, compile_debug, header, value))
 
-#define debugp_verbose_node(header, value) \
-  (ruby_debug_print_indent(10, CPDEBUG, gl_node_level * 2), \
-   ruby_debug_print_value(10, CPDEBUG, header, value))
+#define debugp_verbose(header, value)  (void) \
+  (compile_debug_print_indent(2) && \
+   ruby_debug_print_value(2, compile_debug, header, value))
 
-#define debug_node_start(node) \
-  (ruby_debug_print_indent(-1, CPDEBUG, gl_node_level*2), \
-   ruby_debug_print_node(1, CPDEBUG, "", (NODE *)node), gl_node_level++) \
+#define debugp_verbose_node(header, value)  (void) \
+  (compile_debug_print_indent(10) && \
+   ruby_debug_print_value(10, compile_debug, header, value))
 
+#define debug_node_start(node)  ((void) \
+  (compile_debug_print_indent(1) && \
+   (ruby_debug_print_node(1, CPDEBUG, "", (NODE *)node), gl_node_level)), \
+   gl_node_level++)
+
 #define debug_node_end()  gl_node_level --;
 
 #else
@@ -83,13 +89,14 @@
 #define debugp_verbose(header, value)      r_value(value)
 #define debugp_verbose_node(header, value) r_value(value)
 #define debugp_param(header, value)        r_value(value)
-#define debug_node_start(node)
-#define debug_node_end()
+#define debug_node_start(node)             ((void)0)
+#define debug_node_end()                   ((void)0)
 #endif
 
-#if CPDEBUG > 1
-#define debugs ruby_debug_print_indent(-1, CPDEBUG, gl_node_level*2), printf
-#define debug_compile(msg, v) (ruby_debug_print_indent(-1, CPDEBUG, gl_node_level*2), printf("%s", msg), (v))
+#if CPDEBUG > 1 || CPDEBUG < 0
+PRINTF_ARGS(void ruby_debug_printf(const char*, ...), 1, 2);
+#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
+#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs(msg, stderr)), (v))
 #else
 #define debugs                             if(0)printf
 #define debug_compile(msg, v) (v)
@@ -201,7 +208,7 @@
 #define COMPILE_ERROR(strs)                        \
 {                                                  \
   VALUE tmp = GET_THREAD()->errinfo;               \
-  if(CPDEBUG)rb_bug strs;                          \
+  if (compile_debug) rb_compile_bug strs;          \
   GET_THREAD()->errinfo = iseq->compile_data->err_info;  \
   rb_compile_error strs;                           \
   iseq->compile_data->err_info = GET_THREAD()->errinfo; \
@@ -210,7 +217,7 @@
   break;                                           \
 }
 
-#define ERROR_ARGS (node)->nd_file, nd_line(node),
+#define ERROR_ARGS ruby_sourcefile, nd_line(node),
 
 
 #define COMPILE_OK 1

Added: MacRuby/trunk/complex.c
===================================================================
--- MacRuby/trunk/complex.c	                        (rev 0)
+++ MacRuby/trunk/complex.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,1547 @@
+/*
+  complex.c: Coded by Tadayoshi Funaba 2008
+
+  This implementation is based on Keiju Ishitsuka's Complex library
+  which is written in ruby.
+*/
+
+#include "ruby.h"
+#include <math.h>
+
+#define NDEBUG
+#include <assert.h>
+
+#ifndef COMPLEX_NAME
+#define COMPLEX_NAME "Complex"
+#endif
+
+#define ZERO INT2FIX(0)
+#define ONE INT2FIX(1)
+#define TWO INT2FIX(2)
+
+VALUE rb_cComplex;
+
+static ID id_Unify, id_abs, id_abs2, id_arg, id_atan2_bang, id_cmp,
+  id_conjugate, id_convert, id_cos, id_denominator, id_divmod,
+  id_equal_p, id_exact_p, id_exp_bang, id_expt, id_floor, id_format,
+  id_hypot, id_idiv, id_inspect, id_log_bang, id_negate, id_new, id_new_bang,
+  id_numerator, id_polar, id_quo, id_scalar_p, id_sin, id_sqrt, id_to_f,
+  id_to_i, id_to_r, id_to_s, id_truncate;
+
+#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
+
+#define binop(n,op) \
+inline static VALUE \
+f_##n(VALUE x, VALUE y)\
+{\
+    return rb_funcall(x, op, 1, y);\
+}
+
+#define fun1(n) \
+inline static VALUE \
+f_##n(VALUE x)\
+{\
+    return rb_funcall(x, id_##n, 0);\
+}
+
+#define fun2(n) \
+inline static VALUE \
+f_##n(VALUE x, VALUE y)\
+{\
+    return rb_funcall(x, id_##n, 1, y);\
+}
+
+#define math1(n) \
+inline static VALUE \
+m_##n(VALUE x)\
+{\
+    return rb_funcall(rb_mMath, id_##n, 1, x);\
+}
+
+#define math2(n) \
+inline static VALUE \
+m_##n(VALUE x, VALUE y)\
+{\
+    return rb_funcall(rb_mMath, id_##n, 2, x, y);\
+}
+
+inline static VALUE
+f_add(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y)) {
+	if (FIX2LONG(y) == 0)
+	    r = x;
+	else
+	    r = rb_funcall(x, '+', 1, y);
+    }
+    else if (FIXNUM_P(x)) {
+	if (FIX2LONG(x) == 0)
+	    r = y;
+	else
+	    r = rb_funcall(x, '+', 1, y);
+    }
+    else
+	r = rb_funcall(x, '+', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_cmp(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y)) {
+	long c = FIX2LONG(x) - FIX2LONG(y);
+	if (c > 0)
+	    c = 1;
+	else if (c < 0)
+	    c = -1;
+	r = INT2FIX(c);
+    }
+    else
+	r = rb_funcall(x, id_cmp, 1, y);
+    return r;
+}
+
+inline static VALUE
+f_div(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y) && FIX2LONG(y) == 1)
+	r = x;
+    else
+	r = rb_funcall(x, '/', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_gt_p(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y))
+	r = f_boolcast(FIX2LONG(x) > FIX2LONG(y));
+    else
+	r = rb_funcall(x, '>', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_lt_p(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y))
+	r = f_boolcast(FIX2LONG(x) < FIX2LONG(y));
+    else
+	r = rb_funcall(x, '<', 1, y);
+    return r;
+}
+
+binop(mod, '%')
+
+inline static VALUE
+f_mul(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y)) {
+	long _iy = FIX2LONG(y);
+	if (_iy == 0) {
+	    if (TYPE(x) == T_FLOAT)
+		r = rb_float_new(0.0);
+	    else
+		r = ZERO;
+	}
+	else if (_iy == 1)
+	    r = x;
+	else
+	    r = rb_funcall(x, '*', 1, y);
+    }
+    else if (FIXNUM_P(x)) {
+	long _ix = FIX2LONG(x);
+	if (_ix == 0) {
+	    if (TYPE(y) == T_FLOAT)
+		r = rb_float_new(0.0);
+	    else
+		r = ZERO;
+	}
+	else if (_ix == 1)
+	    r = y;
+	else
+	    r = rb_funcall(x, '*', 1, y);
+    }
+    else
+	r = rb_funcall(x, '*', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_sub(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y)) {
+	if (FIX2LONG(y) == 0)
+	    r = x;
+	else
+	    r = rb_funcall(x, '-', 1, y);
+    }
+    else
+	r = rb_funcall(x, '-', 1, y);
+    return r;
+}
+
+binop(xor, '^')
+
+fun1(abs)
+fun1(abs2)
+fun1(arg)
+fun1(conjugate)
+fun1(denominator)
+fun1(exact_p)
+fun1(floor)
+fun1(inspect)
+fun1(negate)
+fun1(numerator)
+fun1(polar)
+fun1(scalar_p)
+fun1(to_f)
+fun1(to_i)
+fun1(to_r)
+fun1(to_s)
+fun1(truncate)
+
+fun2(divmod)
+
+inline static VALUE
+f_equal_p(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y))
+	r = f_boolcast(FIX2LONG(x) == FIX2LONG(y));
+    else
+	r = rb_funcall(x, id_equal_p, 1, y);
+    return r;
+}
+
+fun2(expt)
+fun2(idiv)
+fun2(quo)
+
+inline static VALUE
+f_negative_p(VALUE x)
+{
+    VALUE r;
+    if (FIXNUM_P(x))
+	r = f_boolcast(FIX2LONG(x) < 0);
+    else
+	r = rb_funcall(x, '<', 1, ZERO);
+    return r;
+}
+
+inline static VALUE
+f_zero_p(VALUE x)
+{
+    VALUE r;
+    if (FIXNUM_P(x))
+	r = f_boolcast(FIX2LONG(x) == 0);
+    else
+	r = rb_funcall(x, id_equal_p, 1, ZERO);
+    return r;
+}
+
+inline static VALUE
+f_one_p(VALUE x)
+{
+    VALUE r;
+    if (FIXNUM_P(x))
+	r = f_boolcast(FIX2LONG(x) == 1);
+    else
+	r = rb_funcall(x, id_equal_p, 1, ONE);
+    return r;
+}
+
+inline static VALUE
+f_kind_of_p(VALUE x, VALUE c)
+{
+    return rb_obj_is_kind_of(x, c);
+}
+
+inline static VALUE
+k_numeric_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cNumeric);
+}
+
+inline static VALUE
+k_integer_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cInteger);
+}
+
+inline static VALUE
+k_float_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cFloat);
+}
+
+inline static VALUE
+k_rational_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cRational);
+}
+
+inline static VALUE
+k_complex_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cComplex);
+}
+
+inline static VALUE
+f_generic_p(VALUE x)
+{
+    switch (TYPE(x)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	return Qtrue;
+      default:
+	return Qfalse;
+    }
+}
+
+static VALUE
+nucomp_s_generic_p(VALUE klass, VALUE x)
+{
+    return f_generic_p(x);
+}
+
+#define get_dat1(x) \
+    struct RComplex *dat;\
+    dat = ((struct RComplex *)(x))
+
+#define get_dat2(x,y) \
+    struct RComplex *adat, *bdat;\
+    adat = ((struct RComplex *)(x));\
+    bdat = ((struct RComplex *)(y))
+
+inline static VALUE
+nucomp_s_new_internal(VALUE klass, VALUE real, VALUE image)
+{
+    NEWOBJ(obj, struct RComplex);
+    OBJSETUP(obj, klass, T_COMPLEX);
+
+    obj->real = real;
+    obj->image = image;
+
+    return (VALUE)obj;
+}
+
+static VALUE
+nucomp_s_alloc(VALUE klass)
+{
+    return nucomp_s_new_internal(klass, ZERO, ZERO);
+}
+
+static VALUE
+nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE real, image;
+
+    switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+      case 1:
+	if (!k_numeric_p(real))
+	    real = f_to_i(real);
+	image = ZERO;
+	break;
+      default:
+	if (!k_numeric_p(real))
+	    real = f_to_i(real);
+	if (!k_numeric_p(image))
+	    image = f_to_i(image);
+	break;
+    }
+
+    return nucomp_s_new_internal(klass, real, image);
+}
+
+inline static VALUE
+f_complex_new_bang1(VALUE klass, VALUE x)
+{
+    return nucomp_s_new_internal(klass, x, ZERO);
+}
+
+inline static VALUE
+f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
+{
+    return nucomp_s_new_internal(klass, x, y);
+}
+
+#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
+
+inline static void
+nucomp_real_check(VALUE num)
+{
+    switch (TYPE(num)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	break;
+      default:
+	rb_raise(rb_eArgError, "not a real");
+    }
+}
+
+inline static VALUE
+nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE image)
+{
+#define CL_CANON
+#ifdef CL_CANON
+    if (f_zero_p(image) && f_unify_p(klass) &&
+	!k_float_p(real) && !k_float_p(image))
+	return real;
+#else
+    if (f_zero_p(image) && f_unify_p(klass))
+	return real;
+#endif
+    else if (f_scalar_p(real) && f_scalar_p(image))
+	return nucomp_s_new_internal(klass, real, image);
+    else if (f_scalar_p(real)) {
+	get_dat1(image);
+
+	return nucomp_s_new_internal(klass,
+				     f_sub(real, dat->image),
+				     f_add(ZERO, dat->real));
+    }
+    else if (f_scalar_p(image)) {
+	get_dat1(real);
+
+	return nucomp_s_new_internal(klass,
+				     dat->real,
+				     f_add(dat->image, image));
+    }
+    else {
+	get_dat2(real, image);
+
+	return nucomp_s_new_internal(klass,
+				     f_sub(adat->real, bdat->image),
+				     f_add(adat->image, bdat->real));
+    }
+}
+
+#if 0
+static VALUE
+nucomp_s_canonicalize(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE real, image;
+
+    switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+      case 1:
+	image = ZERO;
+	break;
+    }
+
+    nucomp_real_check(real);
+    nucomp_real_check(image);
+
+    return nucomp_s_canonicalize_internal(klass, real, image);
+}
+#endif
+
+static VALUE
+nucomp_s_new(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE real, image;
+
+    switch (rb_scan_args(argc, argv, "11", &real, &image)) {
+      case 1:
+	image = ZERO;
+	break;
+    }
+
+    nucomp_real_check(real);
+    nucomp_real_check(image);
+
+    return nucomp_s_canonicalize_internal(klass, real, image);
+}
+
+inline static VALUE
+f_complex_new1(VALUE klass, VALUE x)
+{
+    assert(!k_complex_p(x));
+    return nucomp_s_canonicalize_internal(klass, x, ZERO);
+}
+
+inline static VALUE
+f_complex_new2(VALUE klass, VALUE x, VALUE y)
+{
+    assert(!k_complex_p(x));
+    return nucomp_s_canonicalize_internal(klass, x, y);
+}
+
+static VALUE
+nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
+{
+    return rb_funcall2(rb_cComplex, id_convert, argc, argv);
+}
+
+extern VALUE math_atan2(VALUE obj, VALUE x, VALUE y);
+extern VALUE math_cos(VALUE obj, VALUE x);
+extern VALUE math_cosh(VALUE obj, VALUE x);
+extern VALUE math_exp(VALUE obj, VALUE x);
+extern VALUE math_hypot(VALUE obj, VALUE x, VALUE y);
+extern VALUE math_log(int argc, VALUE *argv);
+extern VALUE math_sin(VALUE obj, VALUE x);
+extern VALUE math_sinh(VALUE obj, VALUE x);
+extern VALUE math_sqrt(VALUE obj, VALUE x);
+
+#define m_atan2_bang(x,y) math_atan2(Qnil,x,y)
+#define m_cos_bang(x) math_cos(Qnil,x)
+#define m_cosh_bang(x) math_cosh(Qnil,x)
+#define m_exp_bang(x) math_exp(Qnil,x)
+#define m_hypot(x,y) math_hypot(Qnil,x,y)
+
+static VALUE
+m_log_bang(VALUE x)
+{
+  return math_log(1, &x);
+}
+
+#define m_sin_bang(x) math_sin(Qnil,x)
+#define m_sinh_bang(x) math_sinh(Qnil,x)
+#define m_sqrt_bang(x) math_sqrt(Qnil,x)
+
+static VALUE
+m_cos(VALUE x)
+{
+    get_dat1(x);
+
+    if (f_generic_p(x))
+	return m_cos_bang(x);
+    else
+	return f_complex_new2(rb_cComplex,
+			      f_mul(m_cos_bang(dat->real),
+				    m_cosh_bang(dat->image)),
+			      f_mul(f_negate(m_sin_bang(dat->real)),
+				    m_sinh_bang(dat->image)));
+}
+
+static VALUE
+m_sin(VALUE x)
+{
+    get_dat1(x);
+
+    if (f_generic_p(x))
+	return m_sin_bang(x);
+    else
+	return f_complex_new2(rb_cComplex,
+			      f_mul(m_sin_bang(dat->real),
+				    m_cosh_bang(dat->image)),
+			      f_mul(m_cos_bang(dat->real),
+				    m_sinh_bang(dat->image)));
+}
+
+static VALUE
+m_sqrt(VALUE x)
+{
+    if (f_generic_p(x)) {
+	if (!f_negative_p(x))
+	    return m_sqrt_bang(x);
+	else
+	    return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x)));
+    }
+    else {
+	get_dat1(x);
+
+	if (f_negative_p(dat->image))
+	    return f_conjugate(m_sqrt(f_conjugate(x)));
+	else {
+	    VALUE a = f_abs(x);
+	    return f_complex_new2(rb_cComplex,
+				  m_sqrt_bang(f_div(f_add(a, dat->real), TWO)),
+				  m_sqrt_bang(f_div(f_sub(a, dat->real), TWO)));
+	}
+    }
+}
+
+static VALUE
+nucomp_s_polar(VALUE klass, VALUE abs, VALUE arg)
+{
+    return f_complex_new2(klass,
+			  f_mul(abs, m_cos(arg)),
+			  f_mul(abs, m_sin(arg)));
+}
+
+static VALUE
+nucomp_real(VALUE self)
+{
+    get_dat1(self);
+    return dat->real;
+}
+
+static VALUE
+nucomp_image(VALUE self)
+{
+    get_dat1(self);
+    return dat->image;
+}
+
+static VALUE
+nucomp_add(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	{
+	    get_dat1(self);
+
+	    return f_complex_new2(CLASS_OF(self),
+				  f_add(dat->real, other), dat->image);
+	}
+      case T_COMPLEX:
+	{
+	    VALUE real, image;
+
+	    get_dat2(self, other);
+
+	    real = f_add(adat->real, bdat->real);
+	    image = f_add(adat->image, bdat->image);
+
+	    return f_complex_new2(CLASS_OF(self), real, image);
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '+');
+    }
+}
+
+static VALUE
+nucomp_sub(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	{
+	    get_dat1(self);
+
+	    return f_complex_new2(CLASS_OF(self),
+				  f_sub(dat->real, other), dat->image);
+	}
+      case T_COMPLEX:
+	{
+	    VALUE real, image;
+
+	    get_dat2(self, other);
+
+	    real = f_sub(adat->real, bdat->real);
+	    image = f_sub(adat->image, bdat->image);
+
+	    return f_complex_new2(CLASS_OF(self), real, image);
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '-');
+    }
+}
+
+static VALUE
+nucomp_mul(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	{
+	    get_dat1(self);
+
+	    return f_complex_new2(CLASS_OF(self),
+				  f_mul(dat->real, other),
+				  f_mul(dat->image, other));
+	}
+      case T_COMPLEX:
+	{
+	    VALUE real, image;
+
+	    get_dat2(self, other);
+
+	    real = f_sub(f_mul(adat->real, bdat->real),
+			 f_mul(adat->image, bdat->image));
+	    image = f_add(f_mul(adat->real, bdat->image),
+			  f_mul(adat->image, bdat->real));
+
+	    return f_complex_new2(CLASS_OF(self), real, image);
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '*');
+    }
+}
+
+static VALUE
+nucomp_div(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	{
+	    get_dat1(self);
+
+	    return f_complex_new2(CLASS_OF(self),
+				  f_div(dat->real, other),
+				  f_div(dat->image, other));
+	}
+      case T_COMPLEX:
+	{
+	    get_dat2(self, other);
+
+	    if (TYPE(adat->real)  == T_FLOAT ||
+		TYPE(adat->image) == T_FLOAT ||
+		TYPE(bdat->real)  == T_FLOAT ||
+		TYPE(bdat->image) == T_FLOAT) {
+		VALUE magn = m_hypot(bdat->real, bdat->image);
+		VALUE tmp = f_complex_new_bang2(CLASS_OF(self),
+						f_div(bdat->real, magn),
+						f_div(bdat->image, magn));
+		return f_div(f_mul(self, f_conjugate(tmp)), magn);
+	    }
+	    return f_div(f_mul(self, f_conjugate(other)), f_abs2(other));
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '/');
+    }
+}
+
+static VALUE
+nucomp_quo(VALUE self, VALUE other)
+{
+    get_dat1(self);
+
+    return f_div(f_complex_new2(CLASS_OF(self),
+				f_quo(dat->real, ONE),
+				f_quo(dat->image, ONE)), other);
+}
+
+static VALUE
+nucomp_fdiv(VALUE self, VALUE other)
+{
+    get_dat1(self);
+
+    return f_div(f_complex_new2(CLASS_OF(self),
+				f_to_f(dat->real),
+				f_to_f(dat->image)), other);
+}
+
+static VALUE
+nucomp_expt(VALUE self, VALUE other)
+{
+    if (f_zero_p(other))
+	return f_complex_new_bang1(CLASS_OF(self), ONE);
+
+    if (k_rational_p(other) && f_one_p(f_denominator(other)))
+	other = f_numerator(other); /* good? */
+
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	if (f_gt_p(other, ZERO)) {
+	    VALUE x, z, n;
+
+	    x = self;
+	    z = x;
+	    n = f_sub(other, ONE);
+
+	    while (!f_zero_p(n)) {
+		VALUE a;
+
+		while (a = f_divmod(n, TWO),
+		       f_zero_p(RARRAY_AT(a, 1))) {
+		    get_dat1(x);
+
+		    x = f_complex_new2(CLASS_OF(self),
+				       f_sub(f_mul(dat->real, dat->real),
+					     f_mul(dat->image, dat->image)),
+				       f_mul(f_mul(TWO, dat->real), dat->image));
+		    n = RARRAY_AT(a, 0);
+		}
+		z = f_mul(z, x);
+		n = f_sub(n, ONE);
+	    }
+	    return z;
+	}
+	else {
+	    return f_expt(f_div(f_to_r(ONE), self), f_negate(other));
+	}
+      case T_FLOAT:
+      case T_RATIONAL:
+	{
+	    VALUE a, r, theta;
+
+	    a = f_polar(self);
+	    r = RARRAY_PTR(a)[0];
+	    theta = RARRAY_PTR(a)[1];
+	    return nucomp_s_polar(CLASS_OF(self), f_expt(r, other),
+				  f_mul(theta, other));
+	}
+      case T_COMPLEX:
+	{
+	    VALUE a, r, theta, ore, oim, nr, ntheta;
+
+	    get_dat1(other);
+
+	    a = f_polar(self);
+	    r = RARRAY_PTR(a)[0];
+	    theta = RARRAY_PTR(a)[1];
+
+	    ore = dat->real;
+	    oim = dat->image;
+	    nr = m_exp_bang(f_sub(f_mul(ore, m_log_bang(r)),
+				  f_mul(oim, theta)));
+	    ntheta = f_add(f_mul(theta, ore), f_mul(oim, m_log_bang(r)));
+	    return nucomp_s_polar(CLASS_OF(self), nr, ntheta);
+	}
+      default:
+	return rb_num_coerce_bin(self, other, id_expt);
+    }
+}
+
+static VALUE
+nucomp_equal_p(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	{
+	    get_dat1(self);
+
+	    return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->image));
+	}
+      case T_COMPLEX:
+	{
+	    get_dat2(self, other);
+
+	    return f_boolcast(f_equal_p(adat->real, bdat->real) &&
+			      f_equal_p(adat->image, bdat->image));
+	}
+      default:
+	return f_equal_p(other, self);
+    }
+}
+
+static VALUE
+nucomp_coerce(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+      case T_RATIONAL:
+	return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
+    }
+
+    rb_raise(rb_eTypeError, "%s can't be coerced into %s",
+	     rb_obj_classname(other), rb_obj_classname(self));
+    return Qnil;
+}
+
+static VALUE
+nucomp_abs(VALUE self)
+{
+    get_dat1(self);
+    return m_hypot(dat->real, dat->image);
+}
+
+static VALUE
+nucomp_abs2(VALUE self)
+{
+    get_dat1(self);
+    return f_add(f_mul(dat->real, dat->real),
+		 f_mul(dat->image, dat->image));
+}
+
+static VALUE
+nucomp_arg(VALUE self)
+{
+    get_dat1(self);
+    return m_atan2_bang(dat->image, dat->real);
+}
+
+static VALUE
+nucomp_polar(VALUE self)
+{
+    return rb_assoc_new(f_abs(self), f_arg(self));
+}
+
+static VALUE
+nucomp_conjugate(VALUE self)
+{
+    get_dat1(self);
+    return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->image));
+}
+
+#if 0
+static VALUE
+nucomp_real_p(VALUE self)
+{
+    return Qfalse;
+}
+
+static VALUE
+nucomp_complex_p(VALUE self)
+{
+    return Qtrue;
+}
+
+static VALUE
+nucomp_exact_p(VALUE self)
+{
+    get_dat1(self);
+    return f_boolcast(f_exact_p(dat->real) && f_exact_p(dat->image));
+}
+
+static VALUE
+nucomp_inexact_p(VALUE self)
+{
+    return f_boolcast(!nucomp_exact_p(self));
+}
+#endif
+
+extern VALUE rb_lcm(VALUE x, VALUE y);
+
+static VALUE
+nucomp_denominator(VALUE self)
+{
+    get_dat1(self);
+    return rb_lcm(f_denominator(dat->real), f_denominator(dat->image));
+}
+
+static VALUE
+nucomp_numerator(VALUE self)
+{
+    VALUE cd;
+
+    get_dat1(self);
+
+    cd = f_denominator(self);
+    return f_complex_new2(CLASS_OF(self),
+			  f_mul(f_numerator(dat->real),
+				f_div(cd, f_denominator(dat->real))),
+			  f_mul(f_numerator(dat->image),
+				f_div(cd, f_denominator(dat->image))));
+}
+
+static VALUE
+nucomp_hash(VALUE self)
+{
+    get_dat1(self);
+    return f_xor(dat->real, dat->image);
+}
+
+#ifndef HAVE_SIGNBIT
+#ifdef signbit
+#define HAVE_SIGNBIT 1
+#endif
+#endif
+
+inline static VALUE
+f_signbit(VALUE x)
+{
+    switch (TYPE(x)) {
+      case T_FLOAT:
+#ifdef HAVE_SIGNBIT
+	return f_boolcast(signbit(RFLOAT_VALUE(x)));
+#else
+	{
+	    char s[2];
+
+	    (void)snprintf(s, sizeof s, "%.0f", RFLOAT_VALUE(x));
+
+	    return f_boolcast(s[0] == '-');
+	}
+#endif
+    }
+    return f_negative_p(x);
+}
+
+inline static VALUE
+f_tzero_p(VALUE x)
+{
+    return f_boolcast(f_zero_p(x) && !f_signbit(x));
+}
+
+inline static VALUE
+f_tpositive_p(VALUE x)
+{
+    return f_boolcast(!f_signbit(x));
+}
+
+static VALUE
+nucomp_to_s(VALUE self)
+{
+    VALUE s, rezero, impos;
+
+    get_dat1(self);
+
+    rezero = f_tzero_p(dat->real);
+    impos = f_tpositive_p(dat->image);
+
+    if (rezero)
+	s = rb_str_new2("");
+    else {
+	s = f_to_s(dat->real);
+	rb_str_cat2(s, !impos ? "-" : "+");
+    }
+
+    if (k_rational_p(dat->image) &&
+	!f_one_p(f_denominator(dat->image))) {
+	rb_str_cat2(s, "(");
+	rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image)));
+	rb_str_cat2(s, ")i");
+    }
+    else {
+	rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image)));
+	rb_str_cat2(s, "i");
+    }
+
+    return s;
+}
+
+static VALUE
+nucomp_inspect(VALUE self)
+{
+    VALUE s;
+
+    get_dat1(self);
+
+    s = rb_str_new2("Complex(");
+    rb_str_concat(s, f_inspect(dat->real));
+    rb_str_cat2(s, ", ");
+    rb_str_concat(s, f_inspect(dat->image));
+    rb_str_cat2(s, ")");
+
+    return s;
+}
+
+static VALUE
+nucomp_marshal_dump(VALUE self)
+{
+    get_dat1(self);
+    return rb_assoc_new(dat->real, dat->image);
+}
+
+static VALUE
+nucomp_marshal_load(VALUE self, VALUE a)
+{
+    get_dat1(self);
+    dat->real = RARRAY_PTR(a)[0];
+    dat->image = RARRAY_PTR(a)[1];
+    return self;
+}
+
+/* --- */
+
+VALUE
+rb_complex_raw(VALUE x, VALUE y)
+{
+    return nucomp_s_new_internal(rb_cComplex, x, y);
+}
+
+VALUE
+rb_complex_new(VALUE x, VALUE y)
+{
+    return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
+}
+
+static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
+
+VALUE
+rb_Complex(VALUE x, VALUE y)
+{
+    VALUE a[2];
+    a[0] = x;
+    a[1] = y;
+    return nucomp_s_convert(2, a, rb_cComplex);
+}
+
+static VALUE
+nucomp_scalar_p(VALUE self)
+{
+    return Qfalse;
+}
+
+static VALUE
+nucomp_to_i(VALUE self)
+{
+    get_dat1(self);
+
+    if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+	VALUE s = f_to_s(self);
+	rb_raise(rb_eRangeError, "can't convert %s into Integer",
+		 StringValuePtr(s));
+    }
+    return f_to_i(dat->real);
+}
+
+static VALUE
+nucomp_to_f(VALUE self)
+{
+    get_dat1(self);
+
+    if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+	VALUE s = f_to_s(self);
+	rb_raise(rb_eRangeError, "can't convert %s into Float",
+		 StringValuePtr(s));
+    }
+    return f_to_f(dat->real);
+}
+
+static VALUE
+nucomp_to_r(VALUE self)
+{
+    get_dat1(self);
+
+    if (k_float_p(dat->image) || !f_zero_p(dat->image)) {
+	VALUE s = f_to_s(self);
+	rb_raise(rb_eRangeError, "can't convert %s into Rational",
+		 StringValuePtr(s));
+    }
+    return f_to_r(dat->real);
+}
+
+static VALUE
+nilclass_to_c(VALUE self)
+{
+    return rb_complex_new1(INT2FIX(0));
+}
+
+static VALUE
+numeric_to_c(VALUE self)
+{
+    return rb_complex_new1(self);
+}
+
+static VALUE comp_pat1, comp_pat2, a_slash, a_dot_and_an_e,
+    image_garbages_pat, null_string, underscores_pat, an_underscore;
+
+#define DIGITS "(?:\\d(?:_\\d|\\d)*)"
+#define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
+#define DENOMINATOR "[-+]?" DIGITS
+#define NUMBER "[-+]?" NUMERATOR "(?:\\/" DENOMINATOR ")?"
+#define NUMBERNOS NUMERATOR "(?:\\/" DENOMINATOR ")?"
+#define PATTERN1 "\\A(" NUMBER "|\\(" NUMBER "\\))[iIjJ]"
+#define PATTERN2 "\\A(" NUMBER ")([-+](?:" NUMBERNOS "|\\(" NUMBER "\\))[iIjJ])?"
+
+static void
+make_patterns(void)
+{
+    static char comp_pat1_source[] = PATTERN1;
+    static char comp_pat2_source[] = PATTERN2;
+    static char image_garbages_pat_source[] = "[+\\(\\)iIjJ]";
+    static char underscores_pat_source[] = "_+";
+
+    comp_pat1 = rb_reg_new(comp_pat1_source, sizeof comp_pat1_source - 1, 0);
+    rb_global_variable(&comp_pat1);
+
+    comp_pat2 = rb_reg_new(comp_pat2_source, sizeof comp_pat2_source - 1, 0);
+    rb_global_variable(&comp_pat2);
+
+    a_slash = rb_str_new2("/");
+    rb_global_variable(&a_slash);
+
+    a_dot_and_an_e = rb_str_new2(".eE");
+    rb_global_variable(&a_dot_and_an_e);
+
+    image_garbages_pat = rb_reg_new(image_garbages_pat_source,
+				    sizeof image_garbages_pat_source - 1, 0);
+    rb_global_variable(&image_garbages_pat);
+
+    null_string = rb_str_new2("");
+    rb_global_variable(&null_string);
+
+    underscores_pat = rb_reg_new(underscores_pat_source,
+				 sizeof underscores_pat_source - 1, 0);
+    rb_global_variable(&underscores_pat);
+
+    an_underscore = rb_str_new2("_");
+    rb_global_variable(&an_underscore);
+}
+
+#define id_strip rb_intern("strip")
+#define f_strip(x) rb_funcall(x, id_strip, 0)
+
+#define id_match rb_intern("match")
+#define f_match(x,y) rb_funcall(x, id_match, 1, y)
+
+#define id_aref rb_intern("[]")
+#define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
+
+#define id_post_match rb_intern("post_match")
+#define f_post_match(x) rb_funcall(x, id_post_match, 0)
+
+#define id_split rb_intern("split")
+#define f_split(x,y) rb_funcall(x, id_split, 1, y)
+
+#define id_include_p rb_intern("include?")
+#define f_include_p(x,y) rb_funcall(x, id_include_p, 1, y)
+
+#define id_count rb_intern("count")
+#define f_count(x,y) rb_funcall(x, id_count, 1, y)
+
+#define id_gsub_bang rb_intern("gsub!")
+#define f_gsub_bang(x,y,z) rb_funcall(x, id_gsub_bang, 2, y, z)
+
+static VALUE
+string_to_c_internal(VALUE self)
+{
+    VALUE s;
+
+    s = f_strip(self);
+
+    if (RSTRING_LEN(s) == 0)
+	return rb_assoc_new(Qnil, self);
+
+    {
+	VALUE m, sr, si, re, r, i;
+
+	m = f_match(comp_pat1, s);
+	if (!NIL_P(m)) {
+	    sr = Qnil;
+	    si = f_aref(m, INT2FIX(1));
+	    re = f_post_match(m);
+	}
+	if (NIL_P(m)) {
+	    m = f_match(comp_pat2, s);
+	    if (NIL_P(m))
+		return rb_assoc_new(Qnil, self);
+	    sr = f_aref(m, INT2FIX(1));
+	    si = f_aref(m, INT2FIX(2));
+	    re = f_post_match(m);
+	}
+	r = INT2FIX(0);
+	i = INT2FIX(0);
+	if (!NIL_P(sr)) {
+	    if (f_include_p(sr, a_slash))
+		r = f_to_r(sr);
+	    else if (f_gt_p(f_count(sr, a_dot_and_an_e), INT2FIX(0)))
+		r = f_to_f(sr);
+	    else
+		r = f_to_i(sr);
+	}
+	if (!NIL_P(si)) {
+	    f_gsub_bang(si, image_garbages_pat, null_string);
+	    if (f_include_p(si, a_slash))
+		i = f_to_r(si);
+	    else if (f_gt_p(f_count(si, a_dot_and_an_e), INT2FIX(0)))
+		i = f_to_f(si);
+	    else
+		i = f_to_i(si);
+	}
+	return rb_assoc_new(rb_complex_new2(r, i), re);
+    }
+}
+
+static VALUE
+string_to_c_strict(VALUE self)
+{
+    VALUE a = string_to_c_internal(self);
+    if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
+	VALUE s = f_inspect(self);
+	rb_raise(rb_eArgError, "invalid value for Complex: %s",
+		 StringValuePtr(s));
+    }
+    return RARRAY_PTR(a)[0];
+}
+
+#define id_gsub rb_intern("gsub")
+#define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
+
+static VALUE
+string_to_c(VALUE self)
+{
+    VALUE s = f_gsub(self, underscores_pat, an_underscore);
+    VALUE a = string_to_c_internal(s);
+    if (!NIL_P(RARRAY_PTR(a)[0]))
+	return RARRAY_PTR(a)[0];
+    return rb_complex_new1(INT2FIX(0));
+}
+
+static VALUE
+nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE a1, a2;
+
+    a1 = Qnil;
+    a2 = Qnil;
+    rb_scan_args(argc, argv, "02", &a1, &a2);
+
+    switch (TYPE(a1)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+	break;
+      case T_STRING:
+	a1 = string_to_c_strict(a1);
+	break;
+    }
+
+    switch (TYPE(a2)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+      case T_FLOAT:
+	break;
+      case T_STRING:
+	a2 = string_to_c_strict(a2);
+	break;
+    }
+
+    switch (TYPE(a1)) {
+      case T_COMPLEX:
+	{
+	    get_dat1(a1);
+
+	    if (!k_float_p(dat->image) && f_zero_p(dat->image))
+		a1 = dat->real;
+	}
+    }
+
+    switch (TYPE(a2)) {
+      case T_COMPLEX:
+	{
+	    get_dat1(a2);
+
+	    if (!k_float_p(dat->image) && f_zero_p(dat->image))
+		a2 = dat->real;
+	}
+    }
+
+    switch (TYPE(a1)) {
+      case T_COMPLEX:
+	if (NIL_P(a2) || f_zero_p(a2))
+	    return a1;
+    }
+
+    {
+	VALUE argv2[2];
+	argv2[0] = a1;
+	argv2[1] = a2;
+	return nucomp_s_new(argc, argv2, klass);
+    }
+}
+
+/* --- */
+
+#define id_Complex rb_intern("Complex")
+
+static VALUE
+numeric_re(VALUE self)
+{
+    return rb_Complex1(self);
+}
+
+static VALUE
+numeric_im(VALUE self)
+{
+    return rb_Complex2(ZERO, self);
+}
+
+static VALUE
+numeric_real(VALUE self)
+{
+    return self;
+}
+
+static VALUE
+numeric_image(VALUE self)
+{
+    return INT2FIX(0);
+}
+
+#define id_PI rb_intern("PI")
+
+static VALUE
+numeric_arg(VALUE self)
+{
+    if (!f_negative_p(self))
+	return INT2FIX(0);
+    return rb_const_get(rb_mMath, id_PI);
+}
+
+static VALUE
+numeric_polar(VALUE self)
+{
+    return rb_assoc_new(f_abs(self), f_arg(self));
+}
+
+static VALUE
+numeric_conjugate(VALUE self)
+{
+    return self;
+}
+
+void
+Init_Complex(void)
+{
+    assert(fprintf(stderr, "assert() is now active\n"));
+
+    id_Unify = rb_intern("Unify");
+    id_abs = rb_intern("abs");
+    id_abs2 = rb_intern("abs2");
+    id_arg = rb_intern("arg");
+    id_atan2_bang = rb_intern("atan2!");
+    id_cmp = rb_intern("<=>");
+    id_conjugate = rb_intern("conjugate");
+    id_convert = rb_intern("convert");
+    id_cos = rb_intern("cos");
+    id_denominator = rb_intern("denominator");
+    id_divmod = rb_intern("divmod");
+    id_equal_p = rb_intern("==");
+    id_exact_p = rb_intern("exact?");
+    id_exp_bang = rb_intern("exp!");
+    id_expt = rb_intern("**");
+    id_floor = rb_intern("floor");
+    id_format = rb_intern("format");
+    id_hypot = rb_intern("hypot");
+    id_idiv = rb_intern("div");
+    id_inspect = rb_intern("inspect");
+    id_log_bang = rb_intern("log!");
+    id_negate = rb_intern("-@");
+    id_new = rb_intern("new");
+    id_new_bang = rb_intern("new!");
+    id_numerator = rb_intern("numerator");
+    id_polar = rb_intern("polar");
+    id_quo = rb_intern("quo");
+    id_scalar_p = rb_intern("scalar?");
+    id_sin = rb_intern("sin");
+    id_sqrt = rb_intern("sqrt");
+    id_to_f = rb_intern("to_f");
+    id_to_i = rb_intern("to_i");
+    id_to_r = rb_intern("to_r");
+    id_to_s = rb_intern("to_s");
+    id_truncate = rb_intern("truncate");
+
+    rb_cComplex = rb_define_class(COMPLEX_NAME, rb_cNumeric);
+
+    rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
+    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("allocate")));
+
+    rb_define_singleton_method(rb_cComplex, "generic?", nucomp_s_generic_p, 1);
+
+    rb_define_singleton_method(rb_cComplex, "new!", nucomp_s_new_bang, -1);
+    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("new!")));
+
+    rb_define_singleton_method(rb_cComplex, "new", nucomp_s_new, -1);
+    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("new")));
+
+#if 0
+    rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
+    rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
+#endif
+    rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, 2);
+
+    rb_define_global_function(COMPLEX_NAME, nucomp_f_complex, -1);
+
+    rb_undef_method(rb_cComplex, "<");
+    rb_undef_method(rb_cComplex, "<=");
+    rb_undef_method(rb_cComplex, "<=>");
+    rb_undef_method(rb_cComplex, ">");
+    rb_undef_method(rb_cComplex, ">=");
+    rb_undef_method(rb_cComplex, "between?");
+    rb_undef_method(rb_cComplex, "divmod");
+    rb_undef_method(rb_cComplex, "floor");
+    rb_undef_method(rb_cComplex, "ceil");
+    rb_undef_method(rb_cComplex, "modulo");
+    rb_undef_method(rb_cComplex, "round");
+    rb_undef_method(rb_cComplex, "step");
+    rb_undef_method(rb_cComplex, "truncate");
+
+#if NUBY
+    rb_undef_method(rb_cComplex, "//");
+#endif
+
+    rb_define_method(rb_cComplex, "real", nucomp_real, 0);
+    rb_define_method(rb_cComplex, "image", nucomp_image, 0);
+    rb_define_method(rb_cComplex, "imag", nucomp_image, 0);
+
+    rb_define_method(rb_cComplex, "+", nucomp_add, 1);
+    rb_define_method(rb_cComplex, "-", nucomp_sub, 1);
+    rb_define_method(rb_cComplex, "*", nucomp_mul, 1);
+    rb_define_method(rb_cComplex, "/", nucomp_div, 1);
+    rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
+    rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
+    rb_define_method(rb_cComplex, "**", nucomp_expt, 1);
+
+    rb_define_method(rb_cComplex, "==", nucomp_equal_p, 1);
+    rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
+
+    rb_define_method(rb_cComplex, "abs", nucomp_abs, 0);
+#if 0
+    rb_define_method(rb_cComplex, "magnitude", nucomp_abs, 0);
+#endif
+    rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
+    rb_define_method(rb_cComplex, "arg", nucomp_arg, 0);
+    rb_define_method(rb_cComplex, "angle", nucomp_arg, 0);
+    rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
+    rb_define_method(rb_cComplex, "conjugate", nucomp_conjugate, 0);
+    rb_define_method(rb_cComplex, "conj", nucomp_conjugate, 0);
+#if 0
+    rb_define_method(rb_cComplex, "~", nucomp_conjugate, 0); /* gcc */
+#endif
+
+#if 0
+    rb_define_method(rb_cComplex, "real?", nucomp_real_p, 0);
+    rb_define_method(rb_cComplex, "complex?", nucomp_complex_p, 0);
+    rb_define_method(rb_cComplex, "exact?", nucomp_exact_p, 0);
+    rb_define_method(rb_cComplex, "inexact?", nucomp_inexact_p, 0);
+#endif
+
+    rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
+    rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
+
+    rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
+
+    rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
+    rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
+
+    rb_define_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
+    rb_define_method(rb_cComplex, "marshal_load", nucomp_marshal_load, 1);
+
+    /* --- */
+
+    rb_define_method(rb_cComplex, "scalar?", nucomp_scalar_p, 0);
+    rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
+    rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
+    rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
+    rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
+    rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
+
+    make_patterns();
+
+    rb_define_method(rb_cString, "to_c", string_to_c, 0);
+
+    rb_define_singleton_method(rb_cComplex, "convert", nucomp_s_convert, -1);
+    rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("convert")));
+
+    /* --- */
+
+    rb_define_method(rb_cNumeric, "re", numeric_re, 0);
+    rb_define_method(rb_cNumeric, "im", numeric_im, 0);
+    rb_define_method(rb_cNumeric, "real", numeric_real, 0);
+    rb_define_method(rb_cNumeric, "image", numeric_image, 0);
+    rb_define_method(rb_cNumeric, "imag", numeric_image, 0);
+    rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
+    rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
+    rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
+    rb_define_method(rb_cNumeric, "conjugate", numeric_conjugate, 0);
+    rb_define_method(rb_cNumeric, "conj", numeric_conjugate, 0);
+
+    rb_define_const(rb_cComplex, "I",
+		    f_complex_new_bang2(rb_cComplex, ZERO, ONE));
+}


Property changes on: MacRuby/trunk/complex.c
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: MacRuby/trunk/configure.in
===================================================================
--- MacRuby/trunk/configure.in	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/configure.in	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,7 +1,7 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_INIT()
 
-AC_PREREQ(2.58)
+AC_PREREQ(2.60)
 
 AC_ARG_WITH(baseruby,
 	[  --with-baseruby=RUBY use RUBY as baseruby; RUBY is the pathname of ruby],
@@ -63,10 +63,20 @@
 GNU_LD=$rb_cv_prog_gnu_ld
 AC_SUBST(GNU_LD)])
 
+unset GREP_OPTIONS
 rb_version=`grep RUBY_VERSION $srcdir/version.h`
 MAJOR=`expr "$rb_version" : '#define RUBY_VERSION "\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*"'`
 MINOR=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*"'`
 TEENY=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\)"'`
+if test "$MAJOR" = ""; then
+  AC_MSG_ERROR(could not determine MAJOR number from version.h)
+fi
+if test "$MINOR" = ""; then
+  AC_MSG_ERROR(could not determine MINOR number from version.h)
+fi
+if test "$TEENY" = ""; then
+  AC_MSG_ERROR(could not determine TEENY number from version.h)
+fi
 AC_SUBST(MAJOR)
 AC_SUBST(MINOR)
 AC_SUBST(TEENY)
@@ -237,8 +247,7 @@
 AC_PROG_INSTALL
 
 # checks for UNIX variants that set C preprocessor variables
-AC_AIX
-AC_MINIX
+AC_USE_SYSTEM_EXTENSIONS
 
 AC_SUBST(RM, ['rm -f'])
 AC_SUBST(CP, ['cp'])
@@ -423,13 +432,7 @@
 RUBY_FUNC_ATTRIBUTE(noinline, NOINLINE)
 RUBY_FUNC_ATTRIBUTE(stdcall)
 RUBY_FUNC_ATTRIBUTE(cdecl)
-case "$target_os" in
-    darwin*)
-	;;
-    *)
-	RUBY_FUNC_ATTRIBUTE(fastcall)
-	;;
-esac
+RUBY_FUNC_ATTRIBUTE(fastcall)
 
 AC_CACHE_CHECK([for RUBY_EXTERN], rb_cv_ruby_extern,
 [rb_cv_ruby_extern=no
@@ -625,7 +628,7 @@
 		 fcntl.h sys/fcntl.h sys/select.h sys/time.h sys/times.h sys/param.h\
 		 syscall.h pwd.h grp.h a.out.h utime.h memory.h direct.h sys/resource.h \
 		 sys/mkdev.h sys/utime.h xti.h netinet/in_systm.h float.h ieeefp.h pthread.h \
-		 ucontext.h intrinsics.h langinfo.h locale.h)
+		 ucontext.h intrinsics.h langinfo.h locale.h sys/sendfile.h time.h)
 
 dnl Check additional types.
 AC_CHECK_SIZEOF(rlim_t, 0, [
@@ -646,6 +649,7 @@
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_TYPE_SIZE_T
+AC_CHECK_SIZEOF(size_t, 0)
 AC_STRUCT_ST_BLKSIZE
 AC_STRUCT_ST_BLOCKS
 AC_STRUCT_ST_RDEV
@@ -659,10 +663,47 @@
 AC_CHECK_MEMBERS([struct stat.st_ctimespec])
 AC_CHECK_MEMBERS([struct stat.st_ctimensec])
 
-AC_CHECK_TYPES(struct timespec)
+AC_CHECK_TYPES([struct timespec], [], [], [@%:@ifdef HAVE_TIME_H
+@%:@include <time.h>
+@%:@endif])
 
 AC_CHECK_TYPE(fd_mask, [AC_DEFINE(HAVE_RB_FD_INIT, 1)])
 
+dnl RUBY_DEFINT TYPENAME, SIZE, [SIGNED-OR-UNSIGNED], [INCLUDES = DEFAULT-INCLUDES]
+AC_DEFUN([RUBY_DEFINT], [dnl
+AC_CACHE_CHECK([for $1], [rb_cv_type_$1],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT([$4])
+typedef $1 t; int s = sizeof(t) == 42;])],
+   [rb_cv_type_$1=yes],
+   [case m4_bmatch([$2], [^[1-9][0-9]*$], $2, [$ac_cv_sizeof_]AS_TR_SH($2)) in
+    "1") rb_cv_type_$1="m4_if([$3], [], [signed ], [$3 ])char";;
+    "$ac_cv_sizeof_short") rb_cv_type_$1="m4_if([$3], [], [], [$3 ])short";;
+    "$ac_cv_sizeof_int") rb_cv_type_$1="m4_if([$3], [], [], [$3 ])int";;
+    "$ac_cv_sizeof_long") rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long";;
+    "$ac_cv_sizeof_long_long") rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long long";;
+    "$ac_cv_sizeof___int64") rb_cv_type_$1="m4_if([$3], [], [], [$3 ])__int64";;
+    *) rb_cv_type_$1=no;;
+    esac])])
+if test "${rb_cv_type_$1}" != no; then
+    AC_DEFINE([HAVE_]AS_TR_CPP($1), 1)
+    test "${rb_cv_type_$1}" = yes || AC_DEFINE_UNQUOTED($1, [$rb_cv_type_$1])
+fi
+])
+
+RUBY_DEFINT(int8_t, 1)
+RUBY_DEFINT(uint8_t, 1, unsigned)
+RUBY_DEFINT(int16_t, 2)
+RUBY_DEFINT(uint16_t, 2, unsigned)
+RUBY_DEFINT(int32_t, 4)
+RUBY_DEFINT(uint32_t, 4, unsigned)
+RUBY_DEFINT(int64_t, 8)
+RUBY_DEFINT(uint64_t, 8, unsigned)
+RUBY_DEFINT(int128_t, 16)
+RUBY_DEFINT(uint128_t, 16, unsigned)
+RUBY_DEFINT(intptr_t, void*)
+RUBY_DEFINT(uintptr_t, void*, unsigned)
+RUBY_DEFINT(ssize_t, size_t)	dnl may differ from int, so not use AC_TYPE_SSIZE_T.
+
 AC_CACHE_CHECK(for stack end address, rb_cv_stack_end_address,
 [rb_cv_stack_end_address=no
 for addr in __libc_stack_end _SEND; do
@@ -701,10 +742,61 @@
 	      setrgid setegid setregid setresgid issetugid pause lchown lchmod\
 	      getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\
 	      getpriority getrlimit setrlimit sysconf group_member\
-	      dlopen sigprocmask sigaction sigsetjmp _setjmp vsnprintf snprintf\
-	      setsid telldir seekdir fchmod cosh sinh tanh log2 round\
+	      dlopen sigprocmask sigaction sigsetjmp _setjmp _longjmp vsnprintf snprintf\
+	      setsid telldir seekdir fchmod cosh sinh tanh log2 round signbit\
 	      setuid setgid daemon select_large_fdset setenv unsetenv\
-	      mktime timegm clock_gettime gettimeofday)
+              mktime timegm clock_gettime gettimeofday\
+              pread sendfile)
+
+AC_CACHE_CHECK(for __builtin_setjmp, ac_cv_func___builtin_setjmp,
+[AC_TRY_LINK([@%:@include <setjmp.h>
+    jmp_buf jb; void t(v) int v; {__builtin_longjmp(jb, v);}],
+    [__builtin_setjmp(jb);],
+    [ac_cv_func___builtin_setjmp=yes],
+    [ac_cv_func___builtin_setjmp=no])
+])
+
+test x$ac_cv_func__longjmp = xno && ac_cv_func__setjmp=no
+
+AC_MSG_CHECKING(for setjmp type)
+AC_ARG_WITH(setjmp-type, 
+	[  --with-setjmp-type      select setjmp type], [
+	case $withval in
+	__builtin_setjmp) setjmp_prefix=__builtin_;;
+	_setjmp) setjmp_prefix=_;;
+	sigsetjmp) setjmp_prefix=sig;;
+	setjmp) setjmp_prefix=;;
+	'') unset setjmp_prefix;;
+	*)   AC_MSG_ERROR(invalid setjmp type: $withval);;
+	esac], [unset setjmp_prefix])
+if test ${setjmp_prefix+set}; then
+    if test "${setjmp_prefix}" && eval test '$ac_cv_func_'${setjmp_prefix}setjmp = no; then
+	AC_MSG_ERROR(${setjmp_prefix}setjmp is not available)
+    fi
+elif test "$ac_cv_func___builtin_setjmp" = yes; then
+    setjmp_prefix=__builtin_
+elif test "$ac_cv_func__setjmp" = yes; then
+    setjmp_prefix=_
+elif test "$ac_cv_func_sigsetjmp" = yes; then
+    case $target_os in
+    solaris*|cygwin*)
+	setjmp_prefix=;;
+    *)
+	setjmp_prefix=sig;;
+    esac
+else
+    setjmp_prefix=
+fi
+if test x$setjmp_prefix = xsig; then
+    setjmp_sigmask=yes
+else
+    unset setjmp_sigmask
+fi
+AC_MSG_RESULT(${setjmp_prefix}setjmp)
+AC_DEFINE_UNQUOTED([RUBY_SETJMP(env)], [${setjmp_prefix}setjmp(env${setjmp_sigmask+,0})])
+AC_DEFINE_UNQUOTED([RUBY_LONGJMP(env,val)], [${setjmp_prefix}longjmp(env,val)])
+AC_DEFINE_UNQUOTED(RUBY_JMP_BUF, ${setjmp_sigmask+${setjmp_prefix}}jmp_buf)
+
 AC_ARG_ENABLE(setreuid,
        [  --enable-setreuid       use setreuid()/setregid() according to need even if obsolete.],
        [use_setreuid=$enableval])
@@ -737,17 +829,19 @@
 #ifndef _XOPEN_SOURCE
 #define _XOPEN_SOURCE 1
 #endif
-    $2
-    const volatile void *volatile t;],
+$2
+;
+const volatile void *volatile t;],
     [t = &(&$1)[0];],
     [for t in $3; do
       AC_TRY_COMPILE([
 #ifndef _XOPEN_SOURCE
 #define _XOPEN_SOURCE 1
 #endif
-        $2
-        extern $t $1;
-        const volatile void *volatile t;],
+$2
+;
+extern $t $1;
+const volatile void *volatile t;],
         [t = &(&$1)[0];],
         [rb_cv_var_$1=$t; break])
     done])])
@@ -755,13 +849,13 @@
   AC_DEFINE([HAVE_VAR_]m4_toupper($1))
   AC_DEFINE_UNQUOTED([TYPEOF_VAR_]m4_toupper($1), $rb_cv_var_$1)
 fi])
-RUBY_CHECK_VARTYPE(timezone, [#include <time.h>], [long int])
-RUBY_CHECK_VARTYPE(altzone, [#include <time.h>], [long int])
+RUBY_CHECK_VARTYPE(timezone, [@%:@include <time.h>], [long int])
+RUBY_CHECK_VARTYPE(altzone, [@%:@include <time.h>], [long int])
 if test "$rb_cv_var_timezone" = no; then
   AC_CHECK_FUNCS(timezone)
   if test "$ac_cv_func_timezone" = yes; then
     AC_CACHE_CHECK([whether timezone requires zero arguments], rb_cv_func_timezone_void,
-      [AC_TRY_COMPILE([#include <time.h>],
+      [AC_TRY_COMPILE([@%:@include <time.h>],
 	[(void)timezone(0, 0);],
 	[rb_cv_func_timezone_void=no],
 	[rb_cv_func_timezone_void=yes])]
@@ -1434,6 +1528,7 @@
   RUNRUBY='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
 else
   MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib'
+  MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common -I./- -r$(srcdir)/ext/purelib.rb'
   PREP='miniruby$(EXEEXT)'
   RUNRUBY='$(MINIRUBY) $(srcdir)/runruby.rb --extout=$(EXTOUT)'
 fi
@@ -1569,7 +1664,6 @@
 MINIDLNOBJ=dln.o
 case "$target_os" in
     linux*)
-	XCFLAGS="$XCFLAGS -D_GNU_SOURCE=1"
 	;;
     netbsd*)
     	CFLAGS="$CFLAGS -pipe"
@@ -1667,7 +1761,7 @@
     *)
 	;;
 esac
-MINIOBJS="$MINIDLNOBJ dmyencoding.o dmytranscode.o"
+MINIOBJS="$MINIDLNOBJ"
 
 case "$build_os" in
   *msdosdjgpp*) FIRSTMAKEFILE=GNUmakefile:djgpp/GNUmakefile.in;;
@@ -1677,7 +1771,7 @@
 test -z "$CFLAGS" || CFLAGS="$CFLAGS "; CFLAGS="$CFLAGS"'${cflags}'
 test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}'
 AC_SUBST(cppflags, [])dnl
-AC_SUBST(cflags, ["${optflags} ${debugflags}"])dnl
+AC_SUBST(cflags, ['${optflags} ${debugflags}'])dnl
 AC_SUBST(optflags)dnl
 AC_SUBST(debugflags)dnl
 AC_SUBST(XCFLAGS)dnl
@@ -1738,35 +1832,34 @@
 AC_ARG_WITH(sitedir,
 	    [  --with-sitedir=DIR      site libraries in DIR [PREFIX/lib/ruby/site_ruby]],
             [sitedir=$withval],
-            [sitedir='${prefix}/lib/ruby/site_ruby'])
+            [sitedir='${libdir}/ruby/site_ruby'])
 SITE_DIR=`eval echo \\"${sitedir}\\"`
-case "$target_os" in
-  cygwin*|mingw*|*djgpp*|os2-emx*)
-    RUBY_SITE_LIB_PATH="`expr "$SITE_DIR" : "$prefix\(/.*\)"`" ||
-    RUBY_SITE_LIB_PATH="$SITE_DIR";;
-  *)
-    RUBY_SITE_LIB_PATH="$SITE_DIR";;
-esac
-RUBY_SITE_LIB_PATH2="${RUBY_SITE_LIB_PATH}/${MAJOR}.${MINOR}.${TEENY}"
 
-AC_DEFINE_UNQUOTED(RUBY_LIB, "${RUBY_LIB_PATH}")
-AC_DEFINE_UNQUOTED(RUBY_SITE_LIB, "${RUBY_SITE_LIB_PATH}")
-AC_DEFINE_UNQUOTED(RUBY_SITE_LIB2, "${RUBY_SITE_LIB_PATH2}")
-
 AC_ARG_WITH(vendordir,
 	    [  --with-vendordir=DIR    vendor libraries in DIR [PREFIX/lib/ruby/vendor_ruby]],
             [vendordir=$withval],
             [vendordir='${prefix}/lib/ruby/vendor_ruby'])
 VENDOR_DIR=`eval echo \\"${vendordir}\\"`
+
 case "$target_os" in
   cygwin*|mingw*|*djgpp*|os2-emx*)
-    RUBY_VENDOR_LIB_PATH="`expr "$VENDOR_DIR" : "$prefix\(/.*\)"`" ||
-    RUBY_VENDOR_LIB_PATH="$VENDOR_DIR";;
+    RUBY_LIB_PREFIX="`eval echo "$RUBY_LIB_PREFIX" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`"
+    RUBY_SITE_LIB_PATH="`eval echo "$SITE_DIR" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`"
+    RUBY_VENDOR_LIB_PATH="`eval echo "$VENDOR_DIR" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`"
+    ;;
   *)
-    RUBY_VENDOR_LIB_PATH="$VENDOR_DIR";;
+    RUBY_LIB_PREFIX="`eval echo \\"$RUBY_LIB_PREFIX\\" | sed 's|^NONE/|'"$prefix"'/|'`"
+    RUBY_SITE_LIB_PATH="`eval echo \\"$SITE_DIR\\" | sed 's|^NONE/|'"$prefix"'/|'`"
+    RUBY_VENDOR_LIB_PATH="`eval echo \\"$VENDOR_DIR\\" | sed 's|^NONE/|'"$prefix"'/|'`"
+    ;;
 esac
+RUBY_LIB_PATH="${RUBY_LIB_PREFIX}/${MAJOR}.${MINOR}.${TEENY}"
+RUBY_SITE_LIB_PATH2="${RUBY_SITE_LIB_PATH}/${MAJOR}.${MINOR}.${TEENY}"
 RUBY_VENDOR_LIB_PATH2="${RUBY_VENDOR_LIB_PATH}/${MAJOR}.${MINOR}.${TEENY}"
 
+AC_DEFINE_UNQUOTED(RUBY_LIB, "${RUBY_LIB_PATH}")
+AC_DEFINE_UNQUOTED(RUBY_SITE_LIB, "${RUBY_SITE_LIB_PATH}")
+AC_DEFINE_UNQUOTED(RUBY_SITE_LIB2, "${RUBY_SITE_LIB_PATH2}")
 AC_DEFINE_UNQUOTED(RUBY_VENDOR_LIB, "${RUBY_VENDOR_LIB_PATH}")
 AC_DEFINE_UNQUOTED(RUBY_VENDOR_LIB2, "${RUBY_VENDOR_LIB_PATH2}")
 
@@ -1804,7 +1897,7 @@
 fi
 
 case "$target_os" in
-  mingw*) sitearch="i386-$rb_cv_msvcrt" ;;
+  mingw*) sitearch="$target_cpu-$rb_cv_msvcrt" ;;
   *) sitearch="${arch}" ;;
 esac
 

Modified: MacRuby/trunk/cont.c
===================================================================
--- MacRuby/trunk/cont.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/cont.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   cont.c - 
 
-  $Author: akr $
+  $Author: matz $
   created at: Thu May 23 09:03:43 2007
 
   Copyright (C) 2007 Koichi Sasada
@@ -111,6 +111,7 @@
     int size;
     rb_thread_t *sth = &cont->saved_thread;
 
+#if !WITH_OBJC
     SET_MACHINE_STACK_END(&th->machine_stack_end);
 #ifdef __ia64
     th->machine_register_stack_end = rb_ia64_bsp();
@@ -153,6 +154,7 @@
 #ifdef __ia64
     sth->machine_register_stack_start = sth->machine_register_stack_end = 0;
 #endif
+#endif
 }
 
 static rb_context_t *
@@ -327,7 +329,7 @@
 #else
 	if (addr_in_prev_frame > &space[0]) {
 	    /* Stack grows downward */
-	    if (addr_in_prev_frame > cont->saved_thread.machine_stack_src) {
+	    if (addr_in_prev_frame > cont->machine_stack_src) {
 		cont_restore_0(cont, &space[0]);
 	    }
 	}

Modified: MacRuby/trunk/debug.c
===================================================================
--- MacRuby/trunk/debug.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/debug.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,12 +13,14 @@
 #include "ruby/encoding.h"
 #include "ruby/util.h"
 #include "debug.h"
+#include "eval_intern.h"
 #include "vm_core.h"
 
 /* for gdb */
 static const union {
     enum ruby_special_consts    special_consts;
     enum ruby_value_type        value_type;
+    enum ruby_tag_type          tag_type;
     enum node_type              node_type;
     enum {
 #if !WITH_OBJC
@@ -29,7 +31,7 @@
         RUBY_ENC_CODERANGE_UNKNOWN = ENC_CODERANGE_UNKNOWN,
         RUBY_ENC_CODERANGE_7BIT    = ENC_CODERANGE_7BIT,
         RUBY_ENC_CODERANGE_VALID   = ENC_CODERANGE_VALID,
-        RUBY_ENC_CODERANGE_BROKEN  = ENC_CODERANGE_BROKEN,
+        RUBY_ENC_CODERANGE_BROKEN  = ENC_CODERANGE_BROKEN, 
 #endif
         RUBY_FL_MARK        = FL_MARK,
         RUBY_FL_RESERVED    = FL_RESERVED,
@@ -69,15 +71,26 @@
 
 const VALUE RUBY_FL_USER20    = FL_USER20;
 
-void
+int
 ruby_debug_print_indent(int level, int debug_level, int indent_level)
 {
     if (level < debug_level) {
 	fprintf(stderr, "%*s", indent_level, "");
 	fflush(stderr);
+	return Qtrue;
     }
+    return Qfalse;
 }
 
+void
+ruby_debug_printf(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    vfprintf(stderr, format, ap);
+    va_end(ap);
+}
+
 VALUE
 ruby_debug_print_value(int level, int debug_level, const char *header, VALUE obj)
 {
@@ -135,10 +148,10 @@
 	    return;			    \
 	}				    \
     } while (0)
-	SET_WHEN("gc_stress", gc_stress);
-	SET_WHEN("core", enable_coredump);
-	fprintf(stderr, "unexpected debug option: %.*s\n", len, str);
-    }
+    SET_WHEN("gc_stress", gc_stress);
+    SET_WHEN("core", enable_coredump);
+    fprintf(stderr, "unexpected debug option: %.*s\n", len, str);
+}
 
 void
 ruby_set_debug_option(const char *str)

Modified: MacRuby/trunk/debug.h
===================================================================
--- MacRuby/trunk/debug.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/debug.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   debug.h - YARV Debug function interface
 
-  $Author: akr $
+  $Author: nobu $
   created at: 04/08/25 02:33:49 JST
 
   Copyright (C) 2004-2007 Koichi Sasada
@@ -25,7 +25,7 @@
 VALUE ruby_debug_print_value(int level, int debug_level, const char *header, VALUE v);
 ID    ruby_debug_print_id(int level, int debug_level, const char *header, ID id);
 NODE *ruby_debug_print_node(int level, int debug_level, const char *header, const NODE *node);
-void  ruby_debug_print_indent(int level, int debug_level, int indent_level);
+int   ruby_debug_print_indent(int level, int debug_level, int indent_level);
 void  ruby_debug_breakpoint(void);
 void  ruby_debug_gc_check_func(void);
 

Modified: MacRuby/trunk/dir.c
===================================================================
--- MacRuby/trunk/dir.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/dir.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   dir.c -
 
-  $Author: akr $
+  $Author: nobu $
   created at: Wed Jan  5 09:51:01 JST 1994
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -66,14 +66,6 @@
 #define lstat stat
 #endif
 
-#ifndef CASEFOLD_FILESYSTEM
-# if defined DOSISH || defined __VMS
-#   define CASEFOLD_FILESYSTEM 1
-# else
-#   define CASEFOLD_FILESYSTEM 0
-# endif
-#endif
-
 #define FNM_NOESCAPE	0x01
 #define FNM_PATHNAME	0x02
 #define FNM_DOTMATCH	0x04
@@ -583,7 +575,7 @@
     struct dir_data *dirp;
     long pos;
 
-    Data_Get_Struct(dir, struct dir_data, dirp);
+    GetDIR(dir, dirp);
     pos = telldir(dirp->dir);
     return rb_int2inum(pos);
 #else
@@ -1670,14 +1662,14 @@
  *
  *     rbfiles = File.join("**", "*.rb")
  *     Dir.glob(rbfiles)                   #=> ["main.rb",
- *                                              "lib/song.rb",
- *                                              "lib/song/karaoke.rb"]
+ *                                         #    "lib/song.rb",
+ *                                         #    "lib/song/karaoke.rb"]
  *     libdirs = File.join("**", "lib")
  *     Dir.glob(libdirs)                   #=> ["lib"]
  *
  *     librbfiles = File.join("**", "lib", "**", "*.rb")
  *     Dir.glob(librbfiles)                #=> ["lib/song.rb",
- *                                              "lib/song/karaoke.rb"]
+ *                                         #    "lib/song/karaoke.rb"]
  *
  *     librbfiles = File.join("**", "lib", "*.rb")
  *     Dir.glob(librbfiles)                #=> ["lib/song.rb"]
@@ -1805,31 +1797,31 @@
  *  parameters. The same glob pattern and flags are used by
  *  <code>Dir::glob</code>.
  *
- *     File.fnmatch('cat',       'cat')        #=> true  : match entire string
- *     File.fnmatch('cat',       'category')   #=> false : only match partial string
- *     File.fnmatch('c{at,ub}s', 'cats')       #=> false : { } isn't supported
+ *     File.fnmatch('cat',       'cat')        #=> true  # match entire string
+ *     File.fnmatch('cat',       'category')   #=> false # only match partial string
+ *     File.fnmatch('c{at,ub}s', 'cats')       #=> false # { } isn't supported
  *
- *     File.fnmatch('c?t',     'cat')          #=> true  : '?' match only 1 character
- *     File.fnmatch('c??t',    'cat')          #=> false : ditto
- *     File.fnmatch('c*',      'cats')         #=> true  : '*' match 0 or more characters
- *     File.fnmatch('c*t',     'c/a/b/t')      #=> true  : ditto
- *     File.fnmatch('ca[a-z]', 'cat')          #=> true  : inclusive bracket expression
- *     File.fnmatch('ca[^t]',  'cat')          #=> false : exclusive bracket expression ('^' or '!')
+ *     File.fnmatch('c?t',     'cat')          #=> true  # '?' match only 1 character
+ *     File.fnmatch('c??t',    'cat')          #=> false # ditto
+ *     File.fnmatch('c*',      'cats')         #=> true  # '*' match 0 or more characters
+ *     File.fnmatch('c*t',     'c/a/b/t')      #=> true  # ditto
+ *     File.fnmatch('ca[a-z]', 'cat')          #=> true  # inclusive bracket expression
+ *     File.fnmatch('ca[^t]',  'cat')          #=> false # exclusive bracket expression ('^' or '!')
  *
- *     File.fnmatch('cat', 'CAT')                     #=> false : case sensitive
- *     File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true  : case insensitive
+ *     File.fnmatch('cat', 'CAT')                     #=> false # case sensitive
+ *     File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true  # case insensitive
  *
- *     File.fnmatch('?',   '/', File::FNM_PATHNAME)  #=> false : wildcard doesn't match '/' on FNM_PATHNAME
- *     File.fnmatch('*',   '/', File::FNM_PATHNAME)  #=> false : ditto
- *     File.fnmatch('[/]', '/', File::FNM_PATHNAME)  #=> false : ditto
+ *     File.fnmatch('?',   '/', File::FNM_PATHNAME)  #=> false # wildcard doesn't match '/' on FNM_PATHNAME
+ *     File.fnmatch('*',   '/', File::FNM_PATHNAME)  #=> false # ditto
+ *     File.fnmatch('[/]', '/', File::FNM_PATHNAME)  #=> false # ditto
  *
- *     File.fnmatch('\?',   '?')                       #=> true  : escaped wildcard becomes ordinary
- *     File.fnmatch('\a',   'a')                       #=> true  : escaped ordinary remains ordinary
- *     File.fnmatch('\a',   '\a', File::FNM_NOESCAPE)  #=> true  : FNM_NOESACPE makes '\' ordinary
- *     File.fnmatch('[\?]', '?')                       #=> true  : can escape inside bracket expression
+ *     File.fnmatch('\?',   '?')                       #=> true  # escaped wildcard becomes ordinary
+ *     File.fnmatch('\a',   'a')                       #=> true  # escaped ordinary remains ordinary
+ *     File.fnmatch('\a',   '\a', File::FNM_NOESCAPE)  #=> true  # FNM_NOESACPE makes '\' ordinary
+ *     File.fnmatch('[\?]', '?')                       #=> true  # can escape inside bracket expression
  *
- *     File.fnmatch('*',   '.profile')                      #=> false : wildcard doesn't match leading
- *     File.fnmatch('*',   '.profile', File::FNM_DOTMATCH)  #=> true    period by default.
+ *     File.fnmatch('*',   '.profile')                      #=> false # wildcard doesn't match leading
+ *     File.fnmatch('*',   '.profile', File::FNM_DOTMATCH)  #=> true  # period by default.
  *     File.fnmatch('.*',  '.profile')                      #=> true
  *
  *     rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.

Modified: MacRuby/trunk/dln.c
===================================================================
--- MacRuby/trunk/dln.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/dln.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   dln.c -
 
-  $Author: akr $
+  $Author: nobu $
   created at: Tue Jan 18 17:05:06 JST 1994
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -1570,10 +1570,10 @@
     return 0;			/* dummy return */
 }
 
-static char *dln_find_1(const char *fname, const char *path, int exe_flag);
+static char *dln_find_1(const char *fname, const char *path, char *buf, int size, int exe_flag);
 
 char *
-dln_find_exe(const char *fname, const char *path)
+dln_find_exe_r(const char *fname, const char *path, char *buf, int size)
 {
     if (!path) {
 	path = getenv(PATH_ENV);
@@ -1586,25 +1586,38 @@
 	path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
 #endif
     }
-    return dln_find_1(fname, path, 1);
+    return dln_find_1(fname, path, buf, size, 1);
 }
 
 char *
-dln_find_file(const char *fname, const char *path)
+dln_find_file_r(const char *fname, const char *path, char *buf, int size)
 {
 #ifndef __MACOS__
     if (!path) path = ".";
-    return dln_find_1(fname, path, 0);
+    return dln_find_1(fname, path, buf, size, 0);
 #else
     if (!path) path = ".";
-    return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0));
+    return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, buf, size, 0));
 #endif
 }
 
 static char fbuf[MAXPATHLEN];
 
+char *
+dln_find_exe(const char *fname, const char *path)
+{
+    return dln_find_exe_r(fname, path, fbuf, sizeof(fbuf));
+}
+
+char *
+dln_find_file(const char *fname, const char *path)
+{
+    return dln_find_file_r(fname, path, fbuf, sizeof(fbuf));
+}
+
 static char *
-dln_find_1(const char *fname, const char *path, int exe_flag /* non 0 if looking for executable. */)
+dln_find_1(const char *fname, const char *path, char *fbuf, int size,
+	   int exe_flag /* non 0 if looking for executable. */)
 {
     register const char *dp;
     register const char *ep;
@@ -1644,7 +1657,7 @@
 	/* find the length of that component */
 	l = ep - dp;
 	bp = fbuf;
-	fspace = sizeof fbuf - 2;
+	fspace = size - 2;
 	if (l > 0) {
 	    /*
 	    **	If the length of the component is zero length,
@@ -1696,26 +1709,9 @@
 	}
 	memcpy(bp, fname, i + 1);
 
-#ifndef __MACOS__
-	if (stat(fbuf, &st) == 0) {
-	    if (exe_flag == 0) return fbuf;
-	    /* looking for executable */
-	    if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
-		return fbuf;
-	}
-#else
-	if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
-	    if (exe_flag == 0) return mac_fullpath;
-	    /* looking for executable */
-	    if (stat(mac_fullpath, &st) == 0) {
-		if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
-		    return mac_fullpath;
-	    }
-	}
-#endif
 #if defined(DOSISH)
 	if (exe_flag) {
-	    static const char *const extension[] = {
+	    static const char extension[][5] = {
 #if defined(MSDOS)
 		".com", ".exe", ".bat",
 #if defined(DJGPP)
@@ -1728,11 +1724,10 @@
 		".r", ".R", ".x", ".X", ".bat", ".BAT",
 /* __human68k__ */
 #endif
-		(char *) NULL
 	    };
 	    int j;
 
-	    for (j = 0; extension[j]; j++) {
+	    for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
 		if (fspace < strlen(extension[j])) {
 		    fprintf(stderr, "openpath: pathname too long (ignored)\n");
 		    fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
@@ -1749,9 +1744,28 @@
 
 #endif
 	    }
+	    goto next;
 	}
 #endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */
 
+#ifndef __MACOS__
+	if (stat(fbuf, &st) == 0) {
+	    if (exe_flag == 0) return fbuf;
+	    /* looking for executable */
+	    if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
+		return fbuf;
+	}
+#else
+	if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
+	    if (exe_flag == 0) return mac_fullpath;
+	    /* looking for executable */
+	    if (stat(mac_fullpath, &st) == 0) {
+		if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
+		    return mac_fullpath;
+	    }
+	}
+#endif
+
       next:
 	/* if not, and no other alternatives, life is bleak */
 	if (*ep == '\0') {

Modified: MacRuby/trunk/dln.h
===================================================================
--- MacRuby/trunk/dln.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/dln.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   dln.h -
 
-  $Author: akr $
+  $Author: nobu $
   created at: Wed Jan 19 16:53:09 JST 1994
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -30,6 +30,8 @@
 
 char *dln_find_exe(const char*,const char*);
 char *dln_find_file(const char*,const char*);
+char *dln_find_exe_r(const char*,const char*,char*,int);
+char *dln_find_file_r(const char*,const char*,char*,int);
 
 #ifdef USE_DLN_A_OUT
 extern char *dln_argv0;

Modified: MacRuby/trunk/dmyencoding.c
===================================================================
--- MacRuby/trunk/dmyencoding.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/dmyencoding.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,3 +1,2 @@
-#define NO_ENCDB_H 1
 #define NO_LOCALE_CHARMAP 1
 #include "encoding.c"

Modified: MacRuby/trunk/dmytranscode.c
===================================================================
--- MacRuby/trunk/dmytranscode.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/dmytranscode.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,2 +0,0 @@
-#define NO_TRANSDB_H 1
-#include "transcode.c"

Modified: MacRuby/trunk/doc/NEWS
===================================================================
--- MacRuby/trunk/doc/NEWS	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/doc/NEWS	2008-05-18 08:10:19 UTC (rev 199)
@@ -195,7 +195,8 @@
           o Process.exec
     * Misc. new methods
           o public_send
-          o GC.stress, GC.stress=
+          o GC.stress, GC.stress=, GC.count
+          o ObjectSpace.count_objects
           o Method#hash, Proc#hash
           o __method__ and __callee__
           o Symbol#to_proc

Modified: MacRuby/trunk/enc/depend
===================================================================
--- MacRuby/trunk/enc/depend	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/enc/depend	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,7 +1,7 @@
 % deffile = (true if /\$\(DEFFILE\)/ =~ CONFIG["LINK_SO"])
 % encs = Dir.open($srcdir) {|d| d.grep(/.+\.c\z/)} - BUILTIN_ENCS
 % encs.each {|e| e.chomp!(".c")}
-% alphanumeric_order = proc {|e| e.split(/(\d+)/).map {|n| Integer(n) rescue n}}
+% alphanumeric_order = proc {|e| e.scan(/(\d+)|(\D+)/).map {|n,a| a||[n.size,n.to_i]}.flatten}
 % encs = encs.sort_by(&alphanumeric_order)
 % trans = Dir.open($srcdir+"/trans") {|d| d.select {|e| e.chomp!('.c')}}
 % trans = trans.sort_by(&alphanumeric_order)
@@ -54,5 +54,8 @@
 	<%=COMPILE_C.sub(/\$\(<(?:.*)\)/) {"$(srcdir)/enc/#{e}.c"}%>
 % end
 
+enc/encdb.$(OBJEXT): encdb.h
+enc/trans/transdb.$(OBJEXT): transdb.h
+
 clean:
 	@$(RM) $(ENCSOS) $(ENCDEFS) $(ENCOBJS) $(TRANSSOS) $(TRANSDEFS) $(TRANSOBJS)

Modified: MacRuby/trunk/enc/make_encdb.rb
===================================================================
--- MacRuby/trunk/enc/make_encdb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/enc/make_encdb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -24,7 +24,9 @@
 defs = {}
 encdir = ARGV[0]
 outhdr = ARGV[1] || 'encdb.h'
-Dir.open(encdir) {|d| d.grep(/.+\.[ch]\z/)}.sort.each do |fn|
+Dir.open(encdir) {|d| d.grep(/.+\.[ch]\z/)}.sort_by {|e|
+  e.scan(/(\d+)|(\D+)/).map {|n,a| a||[n.size,n.to_i]}.flatten
+}.each do |fn|
   open(File.join(encdir,fn)) do |f|
     orig = nil
     name = nil

Modified: MacRuby/trunk/enc/make_encmake.rb
===================================================================
--- MacRuby/trunk/enc/make_encmake.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/enc/make_encmake.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,10 +1,10 @@
 #! ./miniruby
 
 dir = File.expand_path("../..", __FILE__)
-$:.unshift(File.join(dir, "lib"))
 $:.unshift(dir)
 $:.unshift(".")
-require 'mkmf'
+$" << "mkmf.rb"
+load File.expand_path("lib/mkmf.rb", dir)
 require 'erb'
 
 if /--builtin-encs=/ =~ ARGV[0]

Added: MacRuby/trunk/enc/prelude.rb
===================================================================
--- MacRuby/trunk/enc/prelude.rb	                        (rev 0)
+++ MacRuby/trunk/enc/prelude.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,6 @@
+%w'enc/encdb enc/trans/transdb'.each do |init|
+  begin
+    require(init)
+  rescue LoadError
+  end
+end

Modified: MacRuby/trunk/enc/trans/make_transdb.rb
===================================================================
--- MacRuby/trunk/enc/trans/make_transdb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/enc/trans/make_transdb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -10,7 +10,9 @@
 converters = {}
 transdir = ARGV[0]
 outhdr = ARGV[1] || 'transdb.h'
-Dir.open(transdir) {|d| d.grep(/.+\.[ch]\z/)}.sort.each do |fn|
+Dir.open(transdir) {|d| d.grep(/.+\.[ch]\z/)}.sort_by {|e|
+  e.scan(/(\d+)|(\D+)/).map {|n,a| a||[n.size,n.to_i]}.flatten
+}.each do |fn|
   open(File.join(transdir,fn)) do |f|
     f.each_line do |line|
       if (/^static const rb_transcoder/ =~ line)..(/"(.*?)"\s*,\s*"(.*?)"/ =~ line)

Modified: MacRuby/trunk/enc/trans/utf_16_32.c
===================================================================
--- MacRuby/trunk/enc/trans/utf_16_32.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/enc/trans/utf_16_32.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -45,12 +45,12 @@
         return 2;
     }
     else if ((s[0]&0xF0)==0xE0) {
-        o[0] = (s[0]<<4) | (s[1]>>2)^0x20;
+        o[0] = (s[0]<<4) | ((s[1]>>2)^0x20);
         o[1] = (s[1]<<6) | (s[2]^0x80);
         return 2;
     }
     else {
-        int w = (((s[0]&0x07)<<2) | (s[1]>>4)&0x03) - 1;
+        int w = (((s[0]&0x07)<<2) | ((s[1]>>4)&0x03)) - 1;
         o[0] = 0xD8 | (w>>2);
         o[1] = (w<<6) | ((s[1]&0x0F)<<2) | ((s[2]>>4)-8);
         o[2] = 0xDC | ((s[2]>>2)&0x03);
@@ -106,7 +106,7 @@
         return 2;
     }
     else {
-        int w = (((s[0]&0x07)<<2) | (s[1]>>4)&0x03) - 1;
+        int w = (((s[0]&0x07)<<2) | ((s[1]>>4)&0x03)) - 1;
         o[1] = 0xD8 | (w>>2);
         o[0] = (w<<6) | ((s[1]&0x0F)<<2) | ((s[2]>>4)-8);
         o[3] = 0xDC | ((s[2]>>2)&0x03);
@@ -211,7 +211,7 @@
 static const struct byte_lookup* const
 from_UTF_16BE_00_infos[1] = {
   /* used by from_UTF_16BE_00 */
-  /* used by to_UTF_32BE_82 */
+  /* used by to_UTF_32BE_C2 */
      FUNso,
 };
 static const BYTE_LOOKUP
@@ -324,8 +324,8 @@
 };
 
 static const unsigned char
-to_UTF_32BE_82_offsets[64] = {
-  /* used by to_UTF_32BE_82 */
+to_UTF_32BE_C2_offsets[64] = {
+  /* used by to_UTF_32BE_C2 */
   /* used by to_UTF_32BE_E1 */
   /* used by to_UTF_32BE_F1 */
       0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
@@ -334,7 +334,7 @@
       0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
 };
 static const BYTE_LOOKUP
-to_UTF_32BE_82 = {
+to_UTF_32BE_C2 = {
   /* used as  to_UTF_32BE */
   /* used as  to_UTF_16BE */
   /* used as  to_UTF_32BE_E0 */
@@ -363,7 +363,7 @@
   /* used as  to_UTF_32LE_F1_80 */
   /* used as  to_UTF_16LE_F4_80 */
   /* used as  to_UTF_32LE_F4_80 */
-    to_UTF_32BE_82_offsets,
+    to_UTF_32BE_C2_offsets,
     from_UTF_16BE_00_infos
 };
 
@@ -378,7 +378,7 @@
 };
 static const struct byte_lookup* const
 to_UTF_32BE_E0_infos[2] = {
-             INVALID, &to_UTF_32BE_82,
+             INVALID, &to_UTF_32BE_C2,
 };
 static const BYTE_LOOKUP
 to_UTF_32BE_E0 = {
@@ -392,7 +392,7 @@
 
 static const struct byte_lookup* const
 to_UTF_32BE_E1_infos[1] = {
-     &to_UTF_32BE_82,
+     &to_UTF_32BE_C2,
 };
 static const BYTE_LOOKUP
 to_UTF_32BE_E1 = {
@@ -412,13 +412,13 @@
   /* used as  to_UTF_32LE_F1 */
   /* used as  to_UTF_16LE_F4 */
   /* used as  to_UTF_32LE_F4 */
-    to_UTF_32BE_82_offsets,
+    to_UTF_32BE_C2_offsets,
     to_UTF_32BE_E1_infos
 };
 
 static const struct byte_lookup* const
 to_UTF_32BE_ED_infos[2] = {
-     &to_UTF_32BE_82,         INVALID,
+     &to_UTF_32BE_C2,         INVALID,
 };
 static const BYTE_LOOKUP
 to_UTF_32BE_ED = {
@@ -463,7 +463,7 @@
   /* used as  to_UTF_16BE */
   /* used as  to_UTF_16LE */
   /* used as  to_UTF_32LE */
-    to_UTF_32BE_82_offsets,
+    to_UTF_32BE_C2_offsets,
     to_UTF_32BE_F1_infos
 };
 
@@ -491,18 +491,18 @@
       0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
       0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
       0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
+      1,  1,  1,  1,  1,  1,  1,  1,    1,  1,  1,  1,  1,  1,  1,  1,
+      1,  1,  1,  1,  1,  1,  1,  1,    1,  1,  1,  1,  1,  1,  1,  1,
+      1,  1,  1,  1,  1,  1,  1,  1,    1,  1,  1,  1,  1,  1,  1,  1,
+      1,  1,  1,  1,  1,  1,  1,  1,    1,  1,  1,  1,  1,  1,  1,  1,
       1,  1,  2,  2,  2,  2,  2,  2,    2,  2,  2,  2,  2,  2,  2,  2,
       2,  2,  2,  2,  2,  2,  2,  2,    2,  2,  2,  2,  2,  2,  2,  2,
-      2,  2,  2,  2,  2,  2,  2,  2,    2,  2,  2,  2,  2,  2,  2,  2,
-      2,  2,  2,  2,  2,  2,  2,  2,    2,  2,  2,  2,  2,  2,  2,  2,
-      2,  2,  2,  2,  2,  2,  2,  2,    2,  2,  2,  2,  2,  2,  2,  2,
-      2,  2,  2,  2,  2,  2,  2,  2,    2,  2,  2,  2,  2,  2,  2,  2,
       3,  4,  4,  4,  4,  4,  4,  4,    4,  4,  4,  4,  4,  5,  4,  4,
       6,  7,  7,  7,  8,  1,  1,  1,    1,  1,  1,  1,  1,  1,  1,  1,
 };
 static const struct byte_lookup* const
 to_UTF_32BE_infos[9] = {
-               FUNso,         INVALID, &to_UTF_32BE_82, &to_UTF_32BE_E0,
+               FUNso,         INVALID, &to_UTF_32BE_C2, &to_UTF_32BE_E0,
      &to_UTF_32BE_E1, &to_UTF_32BE_ED, &to_UTF_32BE_F0, &to_UTF_32BE_F1,
      &to_UTF_32BE_F4,
 };

Modified: MacRuby/trunk/encoding.c
===================================================================
--- MacRuby/trunk/encoding.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/encoding.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -128,29 +128,7 @@
 
 void rb_enc_init(void);
 
-#ifndef NO_ENCDB_H
-#undef ENC_REPLICATE
-#undef ENC_ALIAS
-#undef ENC_DUMMY
-static int encdb_replicate(const char *alias, const char *orig);
-static int encdb_alias(const char *alias, const char *orig);
-static int encdb_dummy(const char *name);
-static void encdb_declare(const char *name);
-#define ENC_REPLICATE(name, orig) encdb_replicate(name, orig)
-#define ENC_ALIAS(name, orig) encdb_alias(name, orig)
-#define ENC_DUMMY(name) encdb_dummy(name)
-#define ENC_DEFINE(name) encdb_declare(name)
-#endif
-
-static void
-enc_init_db(void)
-{
-#ifdef NO_ENCDB_H
 #define ENCODING_COUNT ENCINDEX_BUILTIN_MAX
-#else
-#include "encdb.h"
-#endif
-}
 
 #define enc_autoload_p(enc) (!rb_enc_mbmaxlen(enc))
 
@@ -202,7 +180,7 @@
     if (rb_enc_from_index(index) != enc)
 	return -1;
     if (enc_autoload_p(enc)) {
-	index = load_encoding(enc->name);
+	index = rb_enc_find_index(enc->name);
     }
     return index;
 }
@@ -345,9 +323,8 @@
     return index;
 }
 
-#ifndef NO_ENCDB_H
-static void
-encdb_declare(const char *name)
+void
+rb_encdb_declare(const char *name)
 {
     int idx = rb_enc_registered(name);
     if (idx < 0) {
@@ -355,7 +332,6 @@
     }
     set_encoding_const(name, rb_enc_from_index(idx));
 }
-#endif
 
 static void
 enc_check_duplication(const char *name)
@@ -387,7 +363,6 @@
     return idx;
 }
 
-#ifndef NO_ENCDB_H
 static int
 enc_replicate(int idx, const char *name, rb_encoding *origenc)
 {
@@ -404,8 +379,8 @@
     return idx;
 }
 
-static int
-encdb_replicate(const char *name, const char *orig)
+int
+rb_encdb_replicate(const char *name, const char *orig)
 {
     int origidx = rb_enc_registered(orig);
     int idx = rb_enc_registered(name);
@@ -415,7 +390,6 @@
     }
     return enc_replicate(idx, name, rb_enc_from_index(origidx));
 }
-#endif
 
 int
 rb_define_dummy_encoding(const char *name)
@@ -427,9 +401,8 @@
     return index;
 }
 
-#ifndef NO_ENCDB_H
-static int
-encdb_dummy(const char *name)
+int
+rb_encdb_dummy(const char *name)
 {
     int index = enc_replicate(rb_enc_registered(name), name,
 			      rb_ascii8bit_encoding());
@@ -438,7 +411,6 @@
     ENC_SET_DUMMY(enc);
     return index;
 }
-#endif
 #endif // WITH_OBJC
 
 int
@@ -496,9 +468,8 @@
     return enc_alias(alias, idx);
 }
 
-#ifndef NO_ENCDB_H
-static int
-encdb_alias(const char *alias, const char *orig)
+int
+rb_encdb_alias(const char *alias, const char *orig)
 {
     int idx = rb_enc_registered(orig);
 
@@ -507,7 +478,6 @@
     }
     return enc_alias(alias, idx);
 }
-#endif
 
 enum {
     ENCINDEX_ASCII,
@@ -716,7 +686,7 @@
 rb_enc_associate_index(VALUE obj, int idx)
 {
     enc_check_capable(obj);
-    if (rb_enc_get_index(obj) == idx)
+    if (rb_enc_internal_get_index(obj) == idx)
     	return;
     if (!ENC_CODERANGE_ASCIIONLY(obj) ||
 	!rb_enc_asciicompat(rb_enc_from_index(idx))) {
@@ -1003,7 +973,6 @@
  *       #<Encoding:US-ASCII>, #<Encoding:ISO-2022-JP (dummy)>]
  *
  */
-
 static VALUE
 enc_list(VALUE klass)
 {
@@ -1440,7 +1409,8 @@
 long
 rb_enc_mbmaxlen(rb_encoding *enc)
 {
-    return CFStringGetMaximumSizeForEncoding(1, *enc);
+    return enc == NULL
+	? 1 : CFStringGetMaximumSizeForEncoding(1, *enc);
 }
 
 rb_encoding *

Modified: MacRuby/trunk/enum.c
===================================================================
--- MacRuby/trunk/enum.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/enum.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   enum.c -
 
-  $Author: mame $
+  $Author: nobu $
   created at: Fri Oct  1 15:15:19 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -24,17 +24,19 @@
     return rb_ary_new4(argc, argv);
 }
 
-static VALUE
-enum_yield(int argc, VALUE *argv)
-{
-    return rb_yield(enum_values_pack(argc, argv));
-}
+#define ENUM_WANT_SVALUE() do { \
+    i = enum_values_pack(argc, argv); \
+} while (0)
 
+#define enum_yield rb_yield_values2
+
 static VALUE
 grep_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
 {
+    ENUM_WANT_SVALUE();
+
     if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
-	rb_ary_push(arg[1], enum_values_pack(argc, argv));
+	rb_ary_push(arg[1], i);
     }
     return Qnil;
 }
@@ -42,8 +44,10 @@
 static VALUE
 grep_iter_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
 {
+    ENUM_WANT_SVALUE();
+
     if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
-	rb_ary_push(arg[1], enum_yield(argc, argv));
+	rb_ary_push(arg[1], rb_yield(i));
     }
     return Qnil;
 }
@@ -52,18 +56,18 @@
  *  call-seq:
  *     enum.grep(pattern)                   => array
  *     enum.grep(pattern) {| obj | block }  => array
- *  
+ *
  *  Returns an array of every element in <i>enum</i> for which
  *  <code>Pattern === element</code>. If the optional <em>block</em> is
  *  supplied, each matching element is passed to it, and the block's
  *  result is stored in the output array.
- *     
+ *
  *     (1..100).grep 38..44   #=> [38, 39, 40, 41, 42, 43, 44]
  *     c = IO.constants
- *     c.grep(/SEEK/)         #=> ["SEEK_END", "SEEK_SET", "SEEK_CUR"]
+ *     c.grep(/SEEK/)         #=> [:SEEK_SET, :SEEK_CUR, :SEEK_END]
  *     res = c.grep(/SEEK/) {|v| IO.const_get(v) }
- *     res                    #=> [2, 0, 1]
- *     
+ *     res                    #=> [0, 1, 2]
+ *
  */
 
 static VALUE
@@ -76,24 +80,30 @@
     arg[1] = ary;
 
     rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
-    
+
     return ary;
 }
 
 static VALUE
-count_i(VALUE i, VALUE *arg)
+count_i(VALUE i, VALUE memop, int argc, VALUE *argv)
 {
-    if (rb_equal(i, arg[0])) {
-	arg[1]++;
+    VALUE *memo = (VALUE*)memop;
+
+    ENUM_WANT_SVALUE();
+
+    if (rb_equal(i, memo[1])) {
+	memo[0]++;
     }
     return Qnil;
 }
 
 static VALUE
-count_iter_i(VALUE i, long *n, int argc, VALUE *argv)
+count_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
 {
+    VALUE *memo = (VALUE*)memop;
+
     if (RTEST(enum_yield(argc, argv))) {
-	(*n)++;
+	memo[0]++;
     }
     return Qnil;
 }
@@ -102,50 +112,45 @@
  *  call-seq:
  *     enum.count(item)             => int
  *     enum.count {| obj | block }  => int
- *  
+ *
  *  Returns the number of items in <i>enum</i> for which equals to <i>item</i>.
  *  If a block is given, counts the number of elements yielding a true value.
- *     
+ *
  *     ary = [1, 2, 4, 2]
  *     ary.count(2)          # => 2
  *     ary.count{|x|x%2==0}  # => 3
- *     
+ *
  */
 
 static VALUE
 enum_count(int argc, VALUE *argv, VALUE obj)
 {
-    if (argc == 1) {
-	VALUE item, args[2];
+    VALUE memo[2];	/* [count, condition value] */
+    rb_block_call_func *func;
 
+    if (argc == 0) {
+	RETURN_ENUMERATOR(obj, 0, 0);
+        func = count_iter_i;
+    }
+    else {
+	rb_scan_args(argc, argv, "1", &memo[1]);
 	if (rb_block_given_p()) {
 	    rb_warn("given block not used");
 	}
-	rb_scan_args(argc, argv, "1", &item);
-	args[0] = item;
-	args[1] = 0;
-	rb_block_call(obj, id_each, 0, 0, count_i, (VALUE)&args);
-	return INT2NUM(args[1]);
+        func = count_i;
     }
-    else if (argc == 0) {
-	long n;
 
-	RETURN_ENUMERATOR(obj, 0, 0);
-	n = 0;
-	rb_block_call(obj, id_each, 0, 0, count_iter_i, (VALUE)&n);
-	return INT2NUM(n);
-    }
-    else {
-        VALUE v;
-	rb_scan_args(argc, argv, "1", &v);
-        return Qnil; /* not reached */
-    }
+    memo[0] = 0;
+    rb_block_call(obj, id_each, 0, 0, func, (VALUE)&memo);
+    return INT2NUM(memo[0]);
 }
 
 static VALUE
 find_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
-    if (RTEST(enum_yield(argc, argv))) {
+    ENUM_WANT_SVALUE();
+
+    if (RTEST(rb_yield(i))) {
 	*memo = i;
 	rb_iter_break();
     }
@@ -156,15 +161,15 @@
  *  call-seq:
  *     enum.detect(ifnone = nil) {| obj | block }  => obj or nil
  *     enum.find(ifnone = nil)   {| obj | block }  => obj or nil
- *  
+ *
  *  Passes each entry in <i>enum</i> to <em>block</em>. Returns the
  *  first for which <em>block</em> is not <code>false</code>.  If no
  *  object matches, calls <i>ifnone</i> and returns its result when it
  *  is specified, or returns <code>nil</code>
- *     
+ *
  *     (1..10).detect  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
  *     (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 }   #=> 35
- *     
+ *
  */
 
 static VALUE
@@ -186,8 +191,25 @@
 }
 
 static VALUE
-find_index_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
+find_index_i(VALUE i, VALUE memop, int argc, VALUE *argv)
 {
+    VALUE *memo = (VALUE*)memop;
+
+    ENUM_WANT_SVALUE();
+
+    if (rb_equal(i, memo[2])) {
+	memo[0] = UINT2NUM(memo[1]);
+	rb_iter_break();
+    }
+    memo[1]++;
+    return Qnil;
+}
+
+static VALUE
+find_index_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
+{
+    VALUE *memo = (VALUE*)memop;
+
     if (RTEST(enum_yield(argc, argv))) {
 	memo[0] = UINT2NUM(memo[1]);
 	rb_iter_break();
@@ -198,36 +220,50 @@
 
 /*
  *  call-seq:
- *     enum.find_index()   {| obj | block }  => int
- *  
- *  Passes each entry in <i>enum</i> to <em>block</em>. Returns the
- *  index for the first for which <em>block</em> is not <code>false</code>.
- *  If no object matches, returns <code>nil</code>
- *     
+ *     enum.find_index(value)            => int or nil
+ *     enum.find_index {| obj | block }  => int or nil
+ *
+ *  Compares each entry in <i>enum</i> with <em>value</em> or passes
+ *  to <em>block</em>.  Returns the index for the first for which the
+ *  evaluated value is non-false.  If no object matches, returns
+ *  <code>nil</code>
+ *
  *     (1..10).find_index  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
  *     (1..100).find_index {|i| i % 5 == 0 and i % 7 == 0 }   #=> 34
- *     
+ *     (1..100).find_index(50)                                #=> 49
+ *
  */
 
 static VALUE
-enum_find_index(VALUE obj)
+enum_find_index(int argc, VALUE *argv, VALUE obj)
 {
-    VALUE memo[2];
+    VALUE memo[3];	/* [return value, current index, condition value] */
+    rb_block_call_func *func;
 
-    RETURN_ENUMERATOR(obj, 0, 0);
-    memo[0] = Qundef;
+    if (argc == 0) {
+        RETURN_ENUMERATOR(obj, 0, 0);
+        func = find_index_iter_i;
+    }
+    else {
+	rb_scan_args(argc, argv, "1", &memo[2]);
+	if (rb_block_given_p()) {
+	    rb_warn("given block not used");
+	}
+        func = find_index_i;
+    }
+
+    memo[0] = Qnil;
     memo[1] = 0;
-    rb_block_call(obj, id_each, 0, 0, find_index_i, (VALUE)memo);
-    if (memo[0] != Qundef) {
-	return memo[0];
-    }
-    return Qnil;
+    rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
+    return memo[0];
 }
 
 static VALUE
 find_all_i(VALUE i, VALUE ary, int argc, VALUE *argv)
 {
-    if (RTEST(enum_yield(argc, argv))) {
+    ENUM_WANT_SVALUE();
+
+    if (RTEST(rb_yield(i))) {
 	rb_ary_push(ary, i);
     }
     return Qnil;
@@ -237,20 +273,20 @@
  *  call-seq:
  *     enum.find_all {| obj | block }  => array
  *     enum.select   {| obj | block }  => array
- *  
+ *
  *  Returns an array containing all elements of <i>enum</i> for which
  *  <em>block</em> is not <code>false</code> (see also
  *  <code>Enumerable#reject</code>).
- *     
+ *
  *     (1..10).find_all {|i|  i % 3 == 0 }   #=> [3, 6, 9]
- *     
+ *
  */
 
 static VALUE
 enum_find_all(VALUE obj)
 {
     VALUE ary;
-    
+
     RETURN_ENUMERATOR(obj, 0, 0);
 
     ary = rb_ary_new();
@@ -262,7 +298,9 @@
 static VALUE
 reject_i(VALUE i, VALUE ary, int argc, VALUE *argv)
 {
-    if (!RTEST(enum_yield(argc, argv))) {
+    ENUM_WANT_SVALUE();
+
+    if (!RTEST(rb_yield(i))) {
 	rb_ary_push(ary, i);
     }
     return Qnil;
@@ -271,19 +309,19 @@
 /*
  *  call-seq:
  *     enum.reject {| obj | block }  => array
- *  
+ *
  *  Returns an array for all elements of <i>enum</i> for which
  *  <em>block</em> is false (see also <code>Enumerable#find_all</code>).
- *     
+ *
  *     (1..10).reject {|i|  i % 3 == 0 }   #=> [1, 2, 4, 5, 7, 8, 10]
- *     
+ *
  */
 
 static VALUE
 enum_reject(VALUE obj)
 {
     VALUE ary;
-    
+
     RETURN_ENUMERATOR(obj, 0, 0);
 
     ary = rb_ary_new();
@@ -312,13 +350,13 @@
  *  call-seq:
  *     enum.collect {| obj | block }  => array
  *     enum.map     {| obj | block }  => array
- *  
+ *
  *  Returns a new array with the results of running <em>block</em> once
  *  for every element in <i>enum</i>.
- *     
+ *
  *     (1..4).collect {|i| i*i }   #=> [1, 4, 9, 16]
  *     (1..4).collect { "cat"  }   #=> ["cat", "cat", "cat", "cat"]
- *     
+ *
  */
 
 static VALUE
@@ -338,9 +376,9 @@
  *  call-seq:
  *     enum.to_a      =>    array
  *     enum.entries   =>    array
- *  
+ *
  *  Returns an array containing the items in <i>enum</i>.
- *     
+ *
  *     (1..7).to_a                       #=> [1, 2, 3, 4, 5, 6, 7]
  *     { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a   #=> [["a", 1], ["b", 2], ["c", 3]]
  */
@@ -358,11 +396,14 @@
 inject_i(VALUE i, VALUE p, int argc, VALUE *argv)
 {
     VALUE *memo = (VALUE *)p;
+
+    ENUM_WANT_SVALUE();
+
     if (memo[0] == Qundef) {
 	memo[0] = i;
     }
     else {
-	memo[0] = rb_yield_values(2, memo[0], enum_values_pack(argc, argv));
+	memo[0] = rb_yield_values(2, memo[0], i);
     }
     return Qnil;
 }
@@ -372,8 +413,10 @@
 {
     VALUE *memo = (VALUE *)p;
 
+    ENUM_WANT_SVALUE();
+
     if (memo[0] == Qundef) {
-	memo[0] = enum_values_pack(argc, argv);
+	memo[0] = i;
     }
     else {
 	memo[0] = rb_funcall(memo[0], (ID)memo[1], 1, i);
@@ -392,7 +435,7 @@
  *     enum.reduce(sym)          => obj
  *     enum.reduce(initial) {| memo, obj | block }  => obj
  *     enum.reduce          {| memo, obj | block }  => obj
- *  
+ *
  *  Combines all elements of <i>enum</i> by applying a binary
  *  operation, specified by a block or a symbol that names a
  *  method or operator.
@@ -401,7 +444,7 @@
  *  the block is passed an accumulator value (<i>memo</i>) and the element.
  *  If you specify a symbol instead, then each element in the collection
  *  will be passed to the named method of <i>memo</i>.
- *  In either case, the result becomes the new value for <i>memo</i>. 
+ *  In either case, the result becomes the new value for <i>memo</i>.
  *  At the end of the iteration, the final value of <i>memo</i> is the
  *  return value fo the method.
  *
@@ -409,7 +452,7 @@
  *  then uses the first element of collection is used as the initial value
  *  of <i>memo</i>.
  *
- *  Examples:   
+ *  Examples:
  *
  *     # Sum some numbers
  *     (5..10).reduce(:+)                            #=> 45
@@ -424,7 +467,7 @@
  *        memo.length > word.length ? memo : word
  *     end
  *     longest                                       #=> "sheep"
- *     
+ *
  */
 static VALUE
 enum_inject(int argc, VALUE *argv, VALUE obj)
@@ -460,7 +503,9 @@
 static VALUE
 partition_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
 {
-    if (RTEST(enum_yield(argc, argv))) {
+    ENUM_WANT_SVALUE();
+
+    if (RTEST(rb_yield(i))) {
 	rb_ary_push(ary[0], i);
     }
     else {
@@ -472,13 +517,13 @@
 /*
  *  call-seq:
  *     enum.partition {| obj | block }  => [ true_array, false_array ]
- *  
+ *
  *  Returns two arrays, the first containing the elements of
  *  <i>enum</i> for which the block evaluates to true, the second
  *  containing the rest.
- *     
+ *
  *     (1..6).partition {|i| (i&1).zero?}   #=> [[2, 4, 6], [1, 3, 5]]
- *     
+ *
  */
 
 static VALUE
@@ -498,9 +543,12 @@
 static VALUE
 group_by_i(VALUE i, VALUE hash, int argc, VALUE *argv)
 {
-    VALUE group = enum_yield(argc, argv);
+    VALUE group;
     VALUE values;
 
+    ENUM_WANT_SVALUE();
+
+    group = rb_yield(i);
     values = rb_hash_aref(hash, group);
     if (NIL_P(values)) {
 	values = rb_ary_new3(1, i);
@@ -515,13 +563,13 @@
 /*
  *  call-seq:
  *     enum.group_by {| obj | block }  => a_hash
- *  
+ *
  *  Returns a hash, which keys are evaluated result from the
  *  block, and values are arrays of elements in <i>enum</i>
  *  corresponding to the key.
- *     
+ *
  *     (1..6).group_by {|i| i%3}   #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
- *     
+ *
  */
 
 static VALUE
@@ -538,8 +586,10 @@
 }
 
 static VALUE
-first_i(VALUE i, VALUE *ary)
+first_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
 {
+    ENUM_WANT_SVALUE();
+
     if (NIL_P(ary[0])) {
 	ary[1] = i;
 	rb_iter_break();
@@ -561,24 +611,23 @@
  *  call-seq:
  *     enum.first      -> obj or nil
  *     enum.first(n)   -> an_array
- *  
+ *
  *  Returns the first element, or the first +n+ elements, of the enumerable.
  *  If the enumerable is empty, the first form returns <code>nil</code>, and the
  *  second form returns an empty array.
- *     
+ *
  */
 
 static VALUE
 enum_first(int argc, VALUE *argv, VALUE obj)
 {
     VALUE n, ary[2];
-    
-    rb_scan_args(argc, argv, "01", &n);
 
     if (argc == 0) {
 	ary[0] = ary[1] = Qnil;
     }
     else {
+	rb_scan_args(argc, argv, "01", &n);
 	ary[0] = n;
 	ary[1] = rb_ary_new2(NUM2LONG(n));
     }
@@ -592,7 +641,7 @@
  *  call-seq:
  *     enum.sort                     => array
  *     enum.sort {| a, b | block }   => array
- *  
+ *
  *  Returns an array containing the items in <i>enum</i> sorted,
  *  either according to their own <code><=></code> method, or by using
  *  the results of the supplied block. The block should return -1, 0, or
@@ -600,7 +649,7 @@
  *  Ruby 1.8, the method <code>Enumerable#sort_by</code> implements a
  *  built-in Schwartzian Transform, useful when key computation or
  *  comparison is expensive..
- *     
+ *
  *     %w(rhea kea flea).sort         #=> ["flea", "kea", "rhea"]
  *     (1..10).sort {|a,b| b <=> a}   #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
  */
@@ -614,16 +663,15 @@
 static VALUE
 sort_by_i(VALUE i, VALUE ary, int argc, VALUE *argv)
 {
-    VALUE v;
     NODE *memo;
 
-    v = enum_yield(argc, argv);
+    ENUM_WANT_SVALUE();
 #if !WITH_OBJC
     if (RBASIC(ary)->klass) {
 	rb_raise(rb_eRuntimeError, "sort_by reentered");
     }
 #endif
-    memo = rb_node_newnode(NODE_MEMO, v, i, 0);
+    memo = rb_node_newnode(NODE_MEMO, rb_yield(i), i, 0);
     rb_ary_push(ary, (VALUE)memo);
     return Qnil;
 }
@@ -651,53 +699,53 @@
 /*
  *  call-seq:
  *     enum.sort_by {| obj | block }    => array
- *  
+ *
  *  Sorts <i>enum</i> using a set of keys generated by mapping the
  *  values in <i>enum</i> through the given block.
- *     
+ *
  *     %w{ apple pear fig }.sort_by {|word| word.length}
-                     #=> ["fig", "pear", "apple"]
- *     
+ *                   #=> ["fig", "pear", "apple"]
+ *
  *  The current implementation of <code>sort_by</code> generates an
  *  array of tuples containing the original collection element and the
  *  mapped value. This makes <code>sort_by</code> fairly expensive when
  *  the keysets are simple
- *     
+ *
  *     require 'benchmark'
  *     include Benchmark
- *     
+ *
  *     a = (1..100000).map {rand(100000)}
- *     
+ *
  *     bm(10) do |b|
  *       b.report("Sort")    { a.sort }
  *       b.report("Sort by") { a.sort_by {|a| a} }
  *     end
- *     
+ *
  *  <em>produces:</em>
- *     
+ *
  *     user     system      total        real
  *     Sort        0.180000   0.000000   0.180000 (  0.175469)
  *     Sort by     1.980000   0.040000   2.020000 (  2.013586)
- *     
+ *
  *  However, consider the case where comparing the keys is a non-trivial
  *  operation. The following code sorts some files on modification time
  *  using the basic <code>sort</code> method.
- *     
+ *
  *     files = Dir["*"]
  *     sorted = files.sort {|a,b| File.new(a).mtime <=> File.new(b).mtime}
  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
- *     
+ *
  *  This sort is inefficient: it generates two new <code>File</code>
  *  objects during every comparison. A slightly better technique is to
  *  use the <code>Kernel#test</code> method to generate the modification
  *  times directly.
- *     
+ *
  *     files = Dir["*"]
  *     sorted = files.sort { |a,b|
  *       test(?M, a) <=> test(?M, b)
  *     }
  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
- *     
+ *
  *  This still generates many unnecessary <code>Time</code> objects. A
  *  more efficient technique is to cache the sort keys (modification
  *  times in this case) before the sort. Perl users often call this
@@ -705,14 +753,14 @@
  *  construct a temporary array, where each element is an array
  *  containing our sort key along with the filename. We sort this array,
  *  and then extract the filename from the result.
- *     
+ *
  *     sorted = Dir["*"].collect { |f|
  *        [test(?M, f), f]
  *     }.sort.collect { |f| f[1] }
  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
- *     
+ *
  *  This is exactly what <code>sort_by</code> does internally.
- *     
+ *
  *     sorted = Dir["*"].sort_by {|f| test(?M, f)}
  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
  */
@@ -759,41 +807,46 @@
     return ary;
 }
 
-static VALUE
-all_iter_i(VALUE i, VALUE *memo)
-{
-    if (!RTEST(rb_yield(i))) {
-	*memo = Qfalse;
-	rb_iter_break();
-    }
-    return Qnil;
+#define DEFINE_ENUMFUNCS(name) \
+static VALUE \
+name##_i(VALUE i, VALUE *memo, int argc, VALUE *argv) \
+{ \
+    return enum_##name##_func(enum_values_pack(argc, argv), memo); \
+} \
+\
+static VALUE \
+name##_iter_i(VALUE i, VALUE *memo, int argc, VALUE *argv) \
+{ \
+    return enum_##name##_func(enum_yield(argc, argv), memo); \
 }
-
+    
 static VALUE
-all_i(VALUE i, VALUE *memo)
+enum_all_func(VALUE result, VALUE *memo)
 {
-    if (!RTEST(i)) {
+    if (!RTEST(result)) {
 	*memo = Qfalse;
 	rb_iter_break();
     }
     return Qnil;
 }
 
+DEFINE_ENUMFUNCS(all)
+
 /*
  *  call-seq:
  *     enum.all? [{|obj| block } ]   => true or false
- *  
+ *
  *  Passes each element of the collection to the given block. The method
  *  returns <code>true</code> if the block never returns
  *  <code>false</code> or <code>nil</code>. If the block is not given,
  *  Ruby adds an implicit block of <code>{|obj| obj}</code> (that is
  *  <code>all?</code> will return <code>true</code> only if none of the
  *  collection members are <code>false</code> or <code>nil</code>.)
- *     
+ *
  *     %w{ant bear cat}.all? {|word| word.length >= 3}   #=> true
  *     %w{ant bear cat}.all? {|word| word.length >= 4}   #=> false
  *     [ nil, true, 99 ].all?                            #=> false
- *     
+ *
  */
 
 static VALUE
@@ -806,29 +859,21 @@
 }
 
 static VALUE
-any_iter_i(VALUE i, VALUE *memo)
+enum_any_func(VALUE result, VALUE *memo)
 {
-    if (RTEST(rb_yield(i))) {
+    if (RTEST(result)) {
 	*memo = Qtrue;
 	rb_iter_break();
     }
     return Qnil;
 }
 
-static VALUE
-any_i(VALUE i, VALUE *memo)
-{
-    if (RTEST(i)) {
-	*memo = Qtrue;
-	rb_iter_break();
-    }
-    return Qnil;
-}
+DEFINE_ENUMFUNCS(any)
 
 /*
  *  call-seq:
  *     enum.any? [{|obj| block } ]   => true or false
- *  
+ *
  *  Passes each element of the collection to the given block. The method
  *  returns <code>true</code> if the block ever returns a value other
  *  than <code>false</code> or <code>nil</code>. If the block is not
@@ -836,11 +881,11 @@
  *  is <code>any?</code> will return <code>true</code> if at least one
  *  of the collection members is not <code>false</code> or
  *  <code>nil</code>.
- *     
+ *
  *     %w{ant bear cat}.any? {|word| word.length >= 3}   #=> true
  *     %w{ant bear cat}.any? {|word| word.length >= 4}   #=> true
  *     [ nil, true, 99 ].any?                            #=> true
- *     
+ *
  */
 
 static VALUE
@@ -853,9 +898,9 @@
 }
 
 static VALUE
-one_i(VALUE i, VALUE *memo)
+enum_one_func(VALUE result, VALUE *memo)
 {
-    if (RTEST(i)) {
+    if (RTEST(result)) {
 	if (*memo == Qundef) {
 	    *memo = Qtrue;
 	}
@@ -867,28 +912,24 @@
     return Qnil;
 }
 
-static VALUE
-one_iter_i(VALUE i, VALUE *memo)
-{
-    return one_i(rb_yield(i), memo);
-}
+DEFINE_ENUMFUNCS(one)
 
 /*
  *  call-seq:
  *     enum.one? [{|obj| block }]   => true or false
- *  
+ *
  *  Passes each element of the collection to the given block. The method
  *  returns <code>true</code> if the block returns <code>true</code>
  *  exactly once. If the block is not given, <code>one?</code> will return
  *  <code>true</code> only if exactly one of the collection members is
  *  true.
- *     
+ *
  *     %w{ant bear cat}.one? {|word| word.length == 4}   #=> true
  *     %w{ant bear cat}.one? {|word| word.length > 4}    #=> false
  *     %w{ant bear cat}.one? {|word| word.length < 4}    #=> false
  *     [ nil, true, 99 ].one?                            #=> false
  *     [ nil, true, false ].one?                         #=> true
- *     
+ *
  */
 
 static VALUE
@@ -902,30 +943,26 @@
 }
 
 static VALUE
-none_i(VALUE i, VALUE *memo)
+enum_none_func(VALUE result, VALUE *memo)
 {
-    if (RTEST(i)) {
+    if (RTEST(result)) {
 	*memo = Qfalse;
 	rb_iter_break();
     }
     return Qnil;
 }
 
-static VALUE
-none_iter_i(VALUE i, VALUE *memo)
-{
-    return none_i(rb_yield(i), memo);
-}
+DEFINE_ENUMFUNCS(none)
 
 /*
  *  call-seq:
  *     enum.none? [{|obj| block }]   => true or false
- *  
+ *
  *  Passes each element of the collection to the given block. The method
  *  returns <code>true</code> if the block never returns <code>true</code>
  *  for all elements. If the block is not given, <code>none?</code> will return
  *  <code>true</code> only if none of the collection members is true.
- *     
+ *
  *     %w{ant bear cat}.none? {|word| word.length == 5}  #=> true
  *     %w{ant bear cat}.none? {|word| word.length >= 4}  #=> false
  *     [].none?                                          #=> true
@@ -942,10 +979,12 @@
 }
 
 static VALUE
-min_i(VALUE i, VALUE *memo)
+min_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     VALUE cmp;
 
+    ENUM_WANT_SVALUE();
+
     if (*memo == Qundef) {
 	*memo = i;
     }
@@ -959,10 +998,12 @@
 }
 
 static VALUE
-min_ii(VALUE i, VALUE *memo)
+min_ii(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     VALUE cmp;
 
+    ENUM_WANT_SVALUE();
+
     if (*memo == Qundef) {
 	*memo = i;
     }
@@ -983,11 +1024,11 @@
  *  call-seq:
  *     enum.min                    => obj
  *     enum.min {| a,b | block }   => obj
- *  
+ *
  *  Returns the object in <i>enum</i> with the minimum value. The
  *  first form assumes all objects implement <code>Comparable</code>;
  *  the second uses the block to return <em>a <=> b</em>.
- *     
+ *
  *     a = %w(albatross dog horse)
  *     a.min                                  #=> "albatross"
  *     a.min {|a,b| a.length <=> b.length }   #=> "dog"
@@ -1011,10 +1052,12 @@
 }
 
 static VALUE
-max_i(VALUE i, VALUE *memo)
+max_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     VALUE cmp;
 
+    ENUM_WANT_SVALUE();
+
     if (*memo == Qundef) {
 	*memo = i;
     }
@@ -1028,10 +1071,12 @@
 }
 
 static VALUE
-max_ii(VALUE i, VALUE *memo)
+max_ii(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     VALUE cmp;
 
+    ENUM_WANT_SVALUE();
+
     if (*memo == Qundef) {
 	*memo = i;
     }
@@ -1051,15 +1096,15 @@
  *  call-seq:
  *     enum.max                   => obj
  *     enum.max {|a,b| block }    => obj
- *  
+ *
  *  Returns the object in _enum_ with the maximum value. The
  *  first form assumes all objects implement <code>Comparable</code>;
  *  the second uses the block to return <em>a <=> b</em>.
- *     
+ *
  *     a = %w(albatross dog horse)
  *     a.max                                  #=> "horse"
  *     a.max {|a,b| a.length <=> b.length }   #=> "albatross"
- */  
+ */
 
 static VALUE
 enum_max(VALUE obj)
@@ -1079,10 +1124,12 @@
 }
 
 static VALUE
-minmax_i(VALUE i, VALUE *memo)
+minmax_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     int n;
 
+    ENUM_WANT_SVALUE();
+
     if (memo[0] == Qundef) {
 	memo[0] = i;
 	memo[1] = i;
@@ -1101,10 +1148,12 @@
 }
 
 static VALUE
-minmax_ii(VALUE i, VALUE *memo)
+minmax_ii(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     int n;
 
+    ENUM_WANT_SVALUE();
+
     if (memo[0] == Qundef) {
 	memo[0] = i;
 	memo[1] = i;
@@ -1132,16 +1181,16 @@
  *  call-seq:
  *     enum.minmax                   => [min,max]
  *     enum.minmax {|a,b| block }    => [min,max]
- *  
+ *
  *  Returns two elements array which contains the minimum and the
  *  maximum value in the enumerable.  The first form assumes all
  *  objects implement <code>Comparable</code>; the second uses the
  *  block to return <em>a <=> b</em>.
- *     
+ *
  *     a = %w(albatross dog horse)
  *     a.minmax                                  #=> ["albatross", "horse"]
  *     a.minmax {|a,b| a.length <=> b.length }   #=> ["dog", "albatross"]
- */  
+ */
 
 static VALUE
 enum_minmax(VALUE obj)
@@ -1169,7 +1218,9 @@
 {
     VALUE v;
 
-    v = enum_yield(argc, argv);
+    ENUM_WANT_SVALUE();
+
+    v = rb_yield(i);
     if (memo[0] == Qundef) {
 	memo[0] = v;
 	memo[1] = i;
@@ -1184,10 +1235,10 @@
 /*
  *  call-seq:
  *     enum.min_by {| obj| block }   => obj
- *  
+ *
  *  Returns the object in <i>enum</i> that gives the minimum
  *  value from the given block.
- *     
+ *
  *     a = %w(albatross dog horse)
  *     a.min_by {|x| x.length }   #=> "dog"
  */
@@ -1210,7 +1261,9 @@
 {
     VALUE v;
 
-    v = enum_yield(argc, argv);
+    ENUM_WANT_SVALUE();
+
+    v = rb_yield(i);
     if (memo[0] == Qundef) {
 	memo[0] = v;
 	memo[1] = i;
@@ -1225,10 +1278,10 @@
 /*
  *  call-seq:
  *     enum.max_by {| obj| block }   => obj
- *  
+ *
  *  Returns the object in <i>enum</i> that gives the maximum
  *  value from the given block.
- *     
+ *
  *     a = %w(albatross dog horse)
  *     a.max_by {|x| x.length }   #=> "albatross"
  */
@@ -1245,13 +1298,15 @@
     rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
     return memo[1];
 }
- 
+
 static VALUE
 minmax_by_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     VALUE v;
 
-    v = enum_yield(argc, argv);
+    ENUM_WANT_SVALUE();
+
+    v = rb_yield(i);
     if (memo[0] == Qundef) {
 	memo[0] = v;
 	memo[1] = v;
@@ -1274,11 +1329,11 @@
 /*
  *  call-seq:
  *     enum.minmax_by {| obj| block }   => [min, max]
- *  
+ *
  *  Returns two elements array array containing the objects in
  *  <i>enum</i> that gives the minimum and maximum values respectively
  *  from the given block.
- *     
+ *
  *     a = %w(albatross dog horse)
  *     a.minmax_by {|x| x.length }   #=> ["dog", "albatross"]
  */
@@ -1299,9 +1354,9 @@
 }
 
 static VALUE
-member_i(VALUE item, VALUE *memo)
+member_i(VALUE iter, VALUE *memo, int argc, VALUE *argv)
 {
-    if (rb_equal(item, memo[0])) {
+    if (rb_equal(enum_values_pack(argc, argv), memo[0])) {
 	memo[1] = Qtrue;
 	rb_iter_break();
     }
@@ -1312,13 +1367,13 @@
  *  call-seq:
  *     enum.include?(obj)     => true or false
  *     enum.member?(obj)      => true or false
- *  
+ *
  *  Returns <code>true</code> if any member of <i>enum</i> equals
  *  <i>obj</i>. Equality is tested using <code>==</code>.
- *     
- *     IO.constants.include? "SEEK_SET"          #=> true
- *     IO.constants.include? "SEEK_NO_FURTHER"   #=> false
- *     
+ *
+ *     IO.constants.include? :SEEK_SET          #=> true
+ *     IO.constants.include? :SEEK_NO_FURTHER   #=> false
+ *
  */
 
 static VALUE
@@ -1343,16 +1398,17 @@
 /*
  *  call-seq:
  *     enum.each_with_index {|obj, i| block }  -> enum
- *  
- *  Calls <em>block</em> with two arguments, the item and its index, for
- *  each item in <i>enum</i>.
- *     
+ *
+ *  Calls <em>block</em> with two arguments, the item and its index,
+ *  for each item in <i>enum</i>.  Given arguments are passed through
+ *  to #each().
+ *
  *     hash = Hash.new
  *     %w(cat dog wombat).each_with_index {|item, index|
  *       hash[item] = index
  *     }
- *     hash   #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
- *     
+ *     hash   #=> {"cat"=>0, "dog"=>1, "wombat"=>2}
+ *
  */
 
 static VALUE
@@ -1369,6 +1425,36 @@
 
 
 static VALUE
+zip_ary(VALUE val, NODE *memo, int argc, VALUE *argv)
+{
+    volatile VALUE result = memo->u1.value;
+    volatile VALUE args = memo->u2.value;
+    int n = memo->u3.cnt++;
+    volatile VALUE tmp;
+    int i;
+
+    tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
+    rb_ary_store(tmp, 0, enum_values_pack(argc, argv));
+    for (i=0; i<RARRAY_LEN(args); i++) {
+	VALUE e = RARRAY_AT(args, i);
+
+	if (RARRAY_LEN(e) <= n) {
+	    rb_ary_push(tmp, Qnil);
+	}
+	else {
+	    rb_ary_push(tmp, RARRAY_AT(e, n));
+	}
+    }
+    if (NIL_P(result)) {
+	rb_yield(tmp);
+    }
+    else {
+	rb_ary_push(result, tmp);
+    }
+    return Qnil;
+}
+
+static VALUE
 call_next(VALUE *v)
 {
     return v[0] = rb_funcall(v[1], id_next, 0, 0);
@@ -1419,7 +1505,7 @@
  *  call-seq:
  *     enum.zip(arg, ...)                   => enumerator
  *     enum.zip(arg, ...) {|arr| block }    => nil
- *  
+ *
  *  Takes one element from <i>enum</i> and merges corresponding
  *  elements from each <i>args</i>.  This generates a sequence of
  *  <em>n</em>-element arrays, where <em>n</em> is one more than the
@@ -1428,14 +1514,14 @@
  *  <code>enum#size</code>, <code>nil</code> values are supplied. If
  *  a block is given, it is invoked for each output array, otherwise
  *  an array of arrays is returned.
- *     
+ *
  *     a = [ 4, 5, 6 ]
  *     b = [ 7, 8, 9 ]
- *     
+ *
  *     [1,2,3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
  *     [1,2].zip(a,b)         #=> [[1, 4, 7], [2, 5, 8]]
  *     a.zip([1,2],[8])       #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
- *     
+ *
  */
 
 static VALUE
@@ -1445,46 +1531,60 @@
     ID conv;
     NODE *memo;
     VALUE result = Qnil;
+    int allary = Qtrue;
 
-    conv = rb_intern("to_enum");
     for (i=0; i<argc; i++) {
-	argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
+	if (TYPE(argv[i]) != T_ARRAY) {
+	    allary = Qfalse;
+	    break;
+	}
     }
+    if (!allary) {
+	conv = rb_intern("to_enum");
+	for (i=0; i<argc; i++) {
+	    argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
+	}
+    }
     if (!rb_block_given_p()) {
 	result = rb_ary_new();
     }
     memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), 0);
-    rb_block_call(obj, id_each, 0, 0, zip_i, (VALUE)memo);
+    rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
 
     return result;
 }
 
 static VALUE
-take_i(VALUE i, VALUE *arg)
+take_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
 {
     if (arg[1]-- == 0) rb_iter_break();
-    rb_ary_push(arg[0], i);
+    rb_ary_push(arg[0], enum_values_pack(argc, argv));
     return Qnil;
 }
 
 /*
  *  call-seq:
  *     enum.take(n)               => array
- *  
+ *
  *  Returns first n elements from <i>enum</i>.
- *     
+ *
  *     a = [1, 2, 3, 4, 5, 0]
  *     a.take(3)             # => [1, 2, 3]
- *     
+ *
  */
 
 static VALUE
 enum_take(VALUE obj, VALUE n)
 {
     VALUE args[2];
+    long len = NUM2LONG(n);
 
-    args[1] = NUM2LONG(n);
-    args[0] = rb_ary_new2(args[1]);
+    if (len < 0) {
+	rb_raise(rb_eArgError, "attempt to take negative size");
+    }
+
+    args[1] = len;
+    args[0] = rb_ary_new();
     rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)args);
     return args[0];
 }
@@ -1494,20 +1594,20 @@
 take_while_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
 {
     if (!RTEST(enum_yield(argc, argv))) rb_iter_break();
-    rb_ary_push(*ary, i);
+    rb_ary_push(*ary, enum_values_pack(argc, argv));
     return Qnil;
 }
 
 /*
  *  call-seq:
  *     enum.take_while {|arr| block }   => array
- *  
+ *
  *  Passes elements to the block until the block returns nil or false,
  *  then stops iterating and returns an array of all prior elements.
- *     
+ *
  *     a = [1, 2, 3, 4, 5, 0]
  *     a.take_while {|i| i < 3 }   # => [1, 2]
- *     
+ *
  */
 
 static VALUE
@@ -1522,10 +1622,10 @@
 }
 
 static VALUE
-drop_i(VALUE i, VALUE *arg)
+drop_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
 {
     if (arg[1] == 0) {
-	rb_ary_push(arg[0], i);
+	rb_ary_push(arg[0], enum_values_pack(argc, argv));
     }
     else {
 	arg[1]--;
@@ -1536,22 +1636,27 @@
 /*
  *  call-seq:
  *     enum.drop(n)               => array
- *  
+ *
  *  Drops first n elements from <i>enum</i>, and returns rest elements
  *  in an array.
- *     
+ *
  *     a = [1, 2, 3, 4, 5, 0]
  *     a.drop(3)             # => [4, 5, 0]
- *     
+ *
  */
 
 static VALUE
 enum_drop(VALUE obj, VALUE n)
 {
     VALUE args[2];
+    long len = NUM2LONG(n);
 
-    args[1] = NUM2ULONG(n);
-    args[0] = rb_ary_new2(args[1]);
+    if (len < 0) {
+	rb_raise(rb_eArgError, "attempt to drop negative size");
+    }
+
+    args[1] = len;
+    args[0] = rb_ary_new();
     rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)args);
     return args[0];
 }
@@ -1560,7 +1665,9 @@
 static VALUE
 drop_while_i(VALUE i, VALUE *args, int argc, VALUE *argv)
 {
-    if (!args[1] && !RTEST(enum_yield(argc, argv))) {
+    ENUM_WANT_SVALUE();
+
+    if (!args[1] && !RTEST(rb_yield(i))) {
 	args[1] = Qtrue;
     }
     if (args[1]) {
@@ -1572,14 +1679,14 @@
 /*
  *  call-seq:
  *     enum.drop_while {|arr| block }   => array
- *  
+ *
  *  Drops elements up to, but not including, the first element for
  *  which the block returns nil or false and returns an array
  *  containing the remaining elements.
- *     
+ *
  *     a = [1, 2, 3, 4, 5, 0]
  *     a.drop_while {|i| i < 3 }   # => [3, 4, 5, 0]
- *     
+ *
  */
 
 static VALUE
@@ -1597,41 +1704,58 @@
 static VALUE
 cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv)
 {
+    ENUM_WANT_SVALUE();
+
     rb_ary_push(ary, i);
-    enum_yield(argc, argv);
+    rb_yield(i);
     return Qnil;
 }
 
 /*
  *  call-seq:
  *     enum.cycle {|obj| block }
- *  
- *  Calls <i>block</i> for each element of <i>enum</i> repeatedly
- *  forever. Returns nil if and only if the collection is empty.
+ *     enum.cycle(n) {|obj| block }
+ *
+ *  Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_
+ *  times or forever if none or nil is given.  If a non-positive
+ *  number is given or the collection is empty, does nothing.  Returns
+ *  nil if the loop has finished without getting interrupted.
+ *
  *  Enumerable#cycle saves elements in an internal array so changes
  *  to <i>enum</i> after the first pass have no effect.
- *     
+ *
  *     a = ["a", "b", "c"]
  *     a.cycle {|x| puts x }  # print, a, b, c, a, b, c,.. forever.
- *     
+ *     a.cycle(2) {|x| puts x }  # print, a, b, c, a, b, c.
+ *
  */
 
 static VALUE
-enum_cycle(VALUE obj)
+enum_cycle(int argc, VALUE *argv, VALUE obj)
 {
     VALUE ary;
-    long i, len;
+    VALUE nv = Qnil;
+    long n, i, len;
 
-    RETURN_ENUMERATOR(obj, 0, 0);
+    rb_scan_args(argc, argv, "01", &nv);
+
+    RETURN_ENUMERATOR(obj, argc, argv);
+    if (NIL_P(nv)) {
+        n = -1;
+    }
+    else {
+        n = NUM2LONG(nv);
+        if (n <= 0) return Qnil;
+    }
     ary = rb_ary_new();
     RBASIC(ary)->klass = 0;
     rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
     len = RARRAY_LEN(ary);
     if (len == 0) return Qnil;
-    for (;;) {
-	for (i=0; i<len; i++) {
-	    rb_yield(RARRAY_AT(ary, i));
-	}
+    while (n < 0 || 0 < --n) {
+        for (i=0; i<len; i++) {
+            rb_yield(RARRAY_AT(ary, i));
+        }
     }
     return Qnil;		/* not reached */
 }
@@ -1666,7 +1790,7 @@
 #endif
     rb_define_method(rb_mEnumerable,"find", enum_find, -1);
     rb_define_method(rb_mEnumerable,"detect", enum_find, -1);
-    rb_define_method(rb_mEnumerable,"find_index", enum_find_index, 0);
+    rb_define_method(rb_mEnumerable,"find_index", enum_find_index, -1);
     rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0);
     rb_define_method(rb_mEnumerable,"select", enum_find_all, 0);
     rb_define_method(rb_mEnumerable,"reject", enum_reject, 0);
@@ -1684,8 +1808,8 @@
     rb_define_method(rb_mEnumerable,"min", enum_min, 0);
     rb_define_method(rb_mEnumerable,"max", enum_max, 0);
     rb_define_method(rb_mEnumerable,"minmax", enum_minmax, 0);
-    rb_define_method(rb_mEnumerable,"min_by", enum_min_by, 0);  
-    rb_define_method(rb_mEnumerable,"max_by", enum_max_by, 0);  
+    rb_define_method(rb_mEnumerable,"min_by", enum_min_by, 0);
+    rb_define_method(rb_mEnumerable,"max_by", enum_max_by, 0);
     rb_define_method(rb_mEnumerable,"minmax_by", enum_minmax_by, 0);
     rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
     rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
@@ -1695,7 +1819,7 @@
     rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
     rb_define_method(rb_mEnumerable, "drop", enum_drop, 1);
     rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
-    rb_define_method(rb_mEnumerable, "cycle", enum_cycle, 0);
+    rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
 
     id_eqq  = rb_intern("===");
     id_each = rb_intern("each");

Modified: MacRuby/trunk/enumerator.c
===================================================================
--- MacRuby/trunk/enumerator.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/enumerator.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,13 +2,13 @@
 
   enumerator.c - provides Enumerator class
 
-  $Author: mame $
+  $Author: knu $
 
   Copyright (C) 2001-2003 Akinori MUSHA
 
   $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
   $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
-  $Id: enumerator.c 15326 2008-01-29 13:30:15Z mame $
+  $Id: enumerator.c 16402 2008-05-13 06:10:56Z knu $
 
 ************************************************/
 
@@ -21,23 +21,14 @@
  * A class which provides a method `each' to be used as an Enumerable
  * object.
  */
-static VALUE rb_cEnumerator;
-static VALUE sym_each, sym_call;
+VALUE rb_cEnumerator;
+static VALUE sym_each;
 
 VALUE rb_eStopIteration;
 
-static VALUE
-proc_call(VALUE proc, VALUE args)
-{
-    if (TYPE(args) != T_ARRAY) {
-	args = rb_ary_new3(1, args);
-    }
-    return rb_proc_call(proc, args);
-}
-
 struct enumerator {
-    VALUE method;
-    VALUE proc;
+    VALUE obj;
+    ID    meth;
     VALUE args;
     rb_block_call_func *iter;
     VALUE fib;
@@ -49,8 +40,7 @@
 enumerator_mark(void *p)
 {
     struct enumerator *ptr = p;
-    rb_gc_mark(ptr->method);
-    rb_gc_mark(ptr->proc);
+    rb_gc_mark(ptr->obj);
     rb_gc_mark(ptr->args);
     rb_gc_mark(ptr->fib);
     rb_gc_mark(ptr->dst);
@@ -73,13 +63,6 @@
     return ptr;
 }
 
-static VALUE
-enumerator_iter_i(VALUE i, VALUE enum_obj, int argc, VALUE *argv)
-{
-    struct enumerator *e = (struct enumerator *)enum_obj;
-    return rb_yield(proc_call(e->proc, i));
-}
-
 /*
  *  call-seq:
  *    obj.to_enum(method = :each, *args)
@@ -88,6 +71,7 @@
  *  Returns Enumerable::Enumerator.new(self, method, *args).
  *
  *  e.g.:
+ *
  *     str = "xyz"
  *
  *     enum = str.enum_for(:each_byte)
@@ -130,8 +114,10 @@
 /*
  *  call-seq:
  *    e.each_slice(n) {...}
+ *    e.each_slice(n)
  *
- *  Iterates the given block for each slice of <n> elements.
+ *  Iterates the given block for each slice of <n> elements.  If no
+ *  block is given, returns an enumerator.
  *
  *  e.g.:
  *      (1..10).each_slice(3) {|a| p a}
@@ -181,9 +167,10 @@
 /*
  *  call-seq:
  *    each_cons(n) {...}
+ *    each_cons(n)
  *
  *  Iterates the given block for each array of consecutive <n>
- *  elements.
+ *  elements.  If no block is given, returns an enumerator.a
  *
  *  e.g.:
  *      (1..10).each_cons(3) {|a| p a}
@@ -233,14 +220,9 @@
 {
     struct enumerator *ptr = enumerator_ptr(enum_obj);
 
-    ptr->method = rb_obj_method(obj, meth);
-    if (rb_block_given_p()) {
-	ptr->proc = rb_block_proc();
-	ptr->iter = enumerator_iter_i;
-    }
-    else {
-	ptr->iter = enumerator_each_i;
-    }
+    ptr->obj  = obj;
+    ptr->meth = rb_to_id(meth);
+    ptr->iter = enumerator_each_i;
     if (argc) GC_WB(&ptr->args, rb_ary_new4(argc, argv));
     ptr->fib = 0;
     ptr->dst = Qnil;
@@ -257,12 +239,8 @@
  *  used as an Enumerable object using the given object's given
  *  method with the given arguments.
  *
- *  e.g.:
- *      str = "xyz"
- *
- *      enum = Enumerable::Enumerator.new(str, :each_byte)
- *      a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
- *
+ *  Use of this method is not discouraged.  Use Kernel#enum_for()
+ *  instead.
  */
 static VALUE
 enumerator_initialize(int argc, VALUE *argv, VALUE obj)
@@ -292,8 +270,8 @@
     }
     ptr1 = enumerator_ptr(obj);
 
-    ptr1->method = ptr0->method;
-    ptr1->proc = ptr0->proc;
+    ptr1->obj  = ptr0->obj;
+    ptr1->meth = ptr0->meth;
     ptr1->iter = ptr0->iter;
     ptr1->args = ptr0->args;
     ptr1->fib  = 0;
@@ -312,7 +290,7 @@
  *    enum.each {...}
  *
  *  Iterates the given block using the object and the method specified
- *  in the first place.
+ *  in the first place.  If no block is given, returns self.
  *
  */
 static VALUE
@@ -328,7 +306,7 @@
 	argc = RARRAY_LEN(e->args);
 	argv = RARRAY_PTR(e->args);
     }
-    return rb_block_call(e->method, SYM2ID(sym_call), argc, argv, e->iter, (VALUE)e);
+    return rb_block_call(e->obj, e->meth, argc, argv, e->iter, (VALUE)e);
 }
 
 static VALUE
@@ -342,9 +320,10 @@
 /*
  *  call-seq:
  *    e.with_index {|(*args), idx| ... }
+ *    e.with_index
  *
  *  Iterates the given block for each elements with an index, which
- *  start from 0.
+ *  start from 0.  If no block is given, returns an enumerator.
  *
  */
 static VALUE
@@ -360,7 +339,7 @@
 	argc = RARRAY_LEN(e->args);
 	argv = RARRAY_PTR(e->args);
     }
-    return rb_block_call(e->method, SYM2ID(sym_call), argc, argv,
+    return rb_block_call(e->obj, e->meth, argc, argv,
 			 enumerator_with_index_i, (VALUE)&memo);
 }
 
@@ -465,8 +444,7 @@
 
     rb_eStopIteration   = rb_define_class("StopIteration", rb_eIndexError);
 
-    sym_each		= ID2SYM(rb_intern("each"));
-    sym_call		= ID2SYM(rb_intern("call"));
+    sym_each	 	= ID2SYM(rb_intern("each"));
 
     rb_provide("enumerator.so");	/* for backward compatibility */
 }

Modified: MacRuby/trunk/error.c
===================================================================
--- MacRuby/trunk/error.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/error.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   error.c -
 
-  $Author: akr $
+  $Author: nobu $
   created at: Mon Aug  9 16:11:34 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -238,7 +238,7 @@
     abort();
 }
 
-static struct types {
+static const struct types {
     int type;
     const char *name;
 } builtin_types[] = {
@@ -256,6 +256,8 @@
     {T_STRUCT,	"Struct"},
     {T_BIGNUM,	"Bignum"},
     {T_FILE,	"File"},
+    {T_RATIONAL,"Rational"},
+    {T_COMPLEX, "Complex"},
     {T_TRUE,	"true"},
     {T_FALSE,	"false"},
     {T_SYMBOL,	"Symbol"},	/* :symbol */
@@ -263,20 +265,21 @@
     {T_MATCH,	"MatchData"},	/* data of $~ */
     {T_NODE,	"Node"},	/* internal use: syntax tree node */
     {T_UNDEF,	"undef"},	/* internal use: #undef; should not happen */
-    {-1,	0}
 };
 
 void
 rb_check_type(VALUE x, int t)
 {
-    struct types *type = builtin_types;
+    const struct types *type = builtin_types;
+    const struct types *const typeend = builtin_types +
+	sizeof(builtin_types) / sizeof(builtin_types[0]);
 
     if (x == Qundef) {
 	rb_bug("undef leaked to the Ruby space");
     }
 
     if (TYPE(x) != t) {
-	while (type->type >= 0) {
+	while (type < typeend) {
 	    if (type->type == t) {
 		const char *etype;
 
@@ -332,7 +335,7 @@
 
 VALUE rb_eSystemCallError;
 VALUE rb_mErrno;
-static VALUE eNOERROR;
+static VALUE rb_eNOERROR;
 
 VALUE
 rb_exc_new(VALUE etype, const char *ptr, long len)
@@ -845,7 +848,7 @@
  *  The full list of operating system errors on your particular platform
  *  are available as the constants of <code>Errno</code>.
  *
- *     Errno.constants   #=> E2BIG, EACCES, EADDRINUSE, EADDRNOTAVAIL, ...
+ *     Errno.constants   #=> :E2BIG, :EACCES, :EADDRINUSE, :EADDRNOTAVAIL, ...
  */
 
 static st_table *syserr_tbl;
@@ -988,7 +991,7 @@
 static VALUE
 errno_missing(VALUE self, VALUE id)
 {
-    return eNOERROR;
+    return rb_eNOERROR;
 }
 
 /*
@@ -1534,7 +1537,7 @@
 #ifdef EDQUOT
     set_syserr(EDQUOT, "EDQUOT");
 #endif
-    eNOERROR = set_syserr(0, "NOERROR");
+    rb_eNOERROR = set_syserr(0, "NOERROR");
 }
 
 static void

Modified: MacRuby/trunk/eval.c
===================================================================
--- MacRuby/trunk/eval.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/eval.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   eval.c -
 
-  $Author: mame $
+  $Author: matz $
   created at: Thu Jun 10 14:22:17 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -171,7 +171,13 @@
     errs[1] = th->errinfo;
     th->safe_level = 0;
     Init_stack((void *)&state);
-    ruby_finalize_0();
+
+    PUSH_TAG();
+    if ((state = EXEC_TAG()) == 0) {
+	SAVE_ROOT_JMPBUF(th, ruby_finalize_0());
+    }
+    POP_TAG();
+
     errs[0] = th->errinfo;
     PUSH_TAG();
     if ((state = EXEC_TAG()) == 0) {
@@ -221,22 +227,19 @@
 }
 
 int
-ruby_exec_node(void *n, char *file)
+ruby_exec_node(void *n, const char *file)
 {
     int state;
-    VALUE val;
-    NODE *node = n;
+    VALUE iseq = (VALUE)n;
     rb_thread_t *th = GET_THREAD();
 
-    if (!node) return 0;
+    if (!n) return 0;
 
     PUSH_TAG();
     if ((state = EXEC_TAG()) == 0) {
-	VALUE iseq = rb_iseq_new(n, rb_str_new2("<main>"),
-				 rb_str_new2(file), Qfalse, ISEQ_TYPE_TOP);
 	SAVE_ROOT_JMPBUF(th, {
 	    th->base_block = 0;
-	    val = rb_iseq_eval(iseq);
+	    rb_iseq_eval(iseq);
 	});
     }
     POP_TAG();
@@ -252,17 +255,17 @@
 int
 ruby_run_node(void *n)
 {
-    NODE *node = (NODE *)n;
+    VALUE v = (VALUE)n;
 
-    switch ((VALUE)n) {
+    switch (v) {
       case Qtrue:  return EXIT_SUCCESS;
       case Qfalse: return EXIT_FAILURE;
     }
-    if (FIXNUM_P((VALUE)n)) {
-	return FIX2INT((VALUE)n);
+    if (FIXNUM_P(v)) {
+	return FIX2INT(v);
     }
     Init_stack((void *)&n);
-    return ruby_cleanup(ruby_exec_node(node, node->nd_file));
+    return ruby_cleanup(ruby_exec_node(n, 0));
 }
 
 VALUE
@@ -464,7 +467,7 @@
 	args[n++] = ID2SYM(id);
 	if (priv)
 	    args[n++] = Qtrue;
-	return rb_funcall2(obj, respond_to, n, args);
+	return RTEST(rb_funcall2(obj, respond_to, n, args));
     }
 }
 
@@ -722,7 +725,7 @@
 			0 /* TODO: id */, 0 /* TODO: klass */);
     }
 
-    rb_thread_reset_raised(th);
+    rb_thread_raised_clear(th);
     JUMP_TAG(tag);
 }
 
@@ -991,6 +994,8 @@
  *       break if !line or line =~ /^qQ/
  *       # ...
  *     end
+ *
+ *  StopIteration raised in the block breaks the loop.
  */
 
 static VALUE
@@ -1076,7 +1081,7 @@
 
     arg = (struct iter_method_arg *)obj;
     return rb_call(CLASS_OF(arg->obj), arg->obj, arg->mid,
-		   arg->argc, arg->argv, NOEX_PRIVATE);
+		   arg->argc, arg->argv, CALL_FCALL);
 }
 
 VALUE
@@ -1095,8 +1100,7 @@
 VALUE
 rb_each(VALUE obj)
 {
-    return rb_call(CLASS_OF(obj), obj, rb_intern("each"), 0, 0,
-		   NOEX_PRIVATE);
+    return rb_call(CLASS_OF(obj), obj, rb_intern("each"), 0, 0, CALL_FCALL);
 }
 
 VALUE
@@ -1250,16 +1254,9 @@
 {
     rb_thread_t *th = GET_THREAD();
 
-    if (!rb_thread_stack_overflowing_p(th) && ruby_stack_check()) {
-	int state;
-	rb_thread_set_stack_overflow(th);
-	PUSH_TAG();
-	if ((state = EXEC_TAG()) == 0) {
-	    rb_exc_raise(sysstack_error);
-	}
-	POP_TAG();
-	rb_thread_reset_stack_overflow(th);
-	JUMP_TAG(state);
+    if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW) && ruby_stack_check()) {
+	rb_thread_raised_set(th, RAISED_STACKOVERFLOW);
+	rb_exc_raise(sysstack_error);
     }
 }
 
@@ -1445,6 +1442,9 @@
 		    defined_class = RBASIC(defined_class)->klass;
 		}
 		
+		if (self == Qundef) {
+		    self = rb_frame_self();
+		}
 		if (!rb_obj_is_kind_of(self, rb_class_real(defined_class))) {
 		    return method_missing(recv, mid, argc, argv, NOEX_PROTECTED);
 		}
@@ -1484,7 +1484,7 @@
 static VALUE
 rb_call(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int scope)
 {
-    return rb_call0(klass, recv, mid, argc, argv, scope, rb_frame_self());
+    return rb_call0(klass, recv, mid, argc, argv, scope, Qundef);
 }
 
 VALUE
@@ -1496,7 +1496,7 @@
     argc = RARRAY_LEN(args);	/* Assigns LONG, but argc is INT */
     argv = ALLOCA_N(VALUE, argc);
     MEMCPY(argv, RARRAY_PTR(args), VALUE, argc);
-    return rb_call(CLASS_OF(recv), recv, mid, argc, argv, NOEX_NOSUPER);
+    return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_FCALL);
 }
 
 static VALUE
@@ -1576,21 +1576,19 @@
     else {
 	argv = 0;
     }
-    return rb_call(CLASS_OF(recv), recv, mid, n, argv,
-		   NOEX_NOSUPER | NOEX_PRIVATE);
+    return rb_call(CLASS_OF(recv), recv, mid, n, argv, CALL_FCALL);
 }
 
 VALUE
 rb_funcall2(VALUE recv, ID mid, int argc, const VALUE *argv)
 {
-    return rb_call(CLASS_OF(recv), recv, mid, argc, argv,
-		   NOEX_NOSUPER | NOEX_PRIVATE);
+    return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_FCALL);
 }
 
 VALUE
 rb_funcall3(VALUE recv, ID mid, int argc, const VALUE *argv)
 {
-    return rb_call(CLASS_OF(recv), recv, mid, argc, argv, NOEX_PUBLIC);
+    return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_PUBLIC);
 }
 
 static VALUE
@@ -2010,12 +2008,12 @@
  *  parameters supply a filename and starting line number that are used
  *  when reporting compilation errors.
  *
- *     class Klass
+ *     class KlassWithSecret
  *       def initialize
  *         @secret = 99
  *       end
  *     end
- *     k = Klass.new
+ *     k = KlassWithSecret.new
  *     k.instance_eval { @secret }   #=> 99
  */
 
@@ -2025,7 +2023,7 @@
     VALUE klass;
 
     if (SPECIAL_CONST_P(self)) {
-	klass = CLASS_OF(self); //klass = Qnil;
+	klass = CLASS_OF(self); /* klass = Qnil; */
     }
     else {
 	klass = rb_singleton_class(self);
@@ -2042,12 +2040,12 @@
  *  to _obj_ while the code is executing, giving the code access to
  *  _obj_'s instance variables.  Arguments are passed as block parameters.
  *
- *     class Klass
+ *     class KlassWithSecret
  *       def initialize
  *         @secret = 99
  *       end
  *     end
- *     k = Klass.new
+ *     k = KlassWithSecret.new
  *     k.instance_exec(5) {|x| @secret+x }   #=> 104
  */
 
@@ -2203,7 +2201,7 @@
  *       def c()  end
  *       private :a
  *     end
- *     Mod.private_instance_methods   #=> ["a", "c"]
+ *     Mod.private_instance_methods   #=> [:a, :c]
  */
 
 static VALUE
@@ -2658,7 +2656,7 @@
 		    const char *vname = rb_id2name(lid);
 		    /* should skip temporary variable */
 		    if (vname) {
-			rb_ary_push(ary, rb_str_new2(vname));
+			rb_ary_push(ary, ID2SYM(lid));
 		    }
 		}
 	    }

Modified: MacRuby/trunk/eval_intern.h
===================================================================
--- MacRuby/trunk/eval_intern.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/eval_intern.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -81,12 +81,10 @@
 #include "vmsruby_private.h"
 #endif
 
-#if !defined(setjmp) && defined(HAVE__SETJMP) && !defined(sigsetjmp) && !defined(HAVE_SIGSETJMP)
-#define ruby_setjmp(env) _setjmp(env)
-#define ruby_longjmp(env,val) _longjmp(env,val)
-#else
-#define ruby_setjmp(env) setjmp(env)
-#define ruby_longjmp(env,val) longjmp(env,val)
+#define ruby_setjmp(env) RUBY_SETJMP(env)
+#define ruby_longjmp(env,val) RUBY_LONGJMP(env,val)
+#ifdef __CYGWIN__
+int _setjmp(), _longjmp();
 #endif
 
 #include <sys/types.h>
@@ -142,8 +140,7 @@
 #define PUSH_TAG() TH_PUSH_TAG(GET_THREAD())
 #define POP_TAG()      TH_POP_TAG()
 
-#define TH_EXEC_TAG() \
-  (FLUSH_REGISTER_WINDOWS, ruby_setjmp(_th->tag->buf))
+#define TH_EXEC_TAG() ruby_setjmp(_th->tag->buf)
 
 #define EXEC_TAG() \
   TH_EXEC_TAG()
@@ -154,15 +151,26 @@
 
 #define JUMP_TAG(st) TH_JUMP_TAG(GET_THREAD(), st)
 
-#define TAG_RETURN	0x1
-#define TAG_BREAK	0x2
-#define TAG_NEXT	0x3
-#define TAG_RETRY	0x4
-#define TAG_REDO	0x5
-#define TAG_RAISE	0x6
-#define TAG_THROW	0x7
-#define TAG_FATAL	0x8
-#define TAG_MASK	0xf
+enum ruby_tag_type {
+    RUBY_TAG_RETURN	= 0x1,
+    RUBY_TAG_BREAK	= 0x2,
+    RUBY_TAG_NEXT	= 0x3,
+    RUBY_TAG_RETRY	= 0x4,
+    RUBY_TAG_REDO	= 0x5,
+    RUBY_TAG_RAISE	= 0x6,
+    RUBY_TAG_THROW	= 0x7,
+    RUBY_TAG_FATAL	= 0x8,
+    RUBY_TAG_MASK	= 0xf
+};
+#define TAG_RETURN	RUBY_TAG_RETURN
+#define TAG_BREAK	RUBY_TAG_BREAK
+#define TAG_NEXT	RUBY_TAG_NEXT
+#define TAG_RETRY	RUBY_TAG_RETRY
+#define TAG_REDO	RUBY_TAG_REDO
+#define TAG_RAISE	RUBY_TAG_RAISE
+#define TAG_THROW	RUBY_TAG_THROW
+#define TAG_FATAL	RUBY_TAG_FATAL
+#define TAG_MASK	RUBY_TAG_MASK
 
 #define NEW_THROW_OBJECT(val, pt, st) \
   ((VALUE)NEW_NODE(NODE_LIT, (val), (pt), (st)))
@@ -195,16 +203,17 @@
 void rb_thread_cleanup(void);
 void rb_thread_wait_other_threads(void);
 
-#define RAISED_EXCEPTION     1
-#define RAISED_STACKOVERFLOW 2
+enum {
+    RAISED_EXCEPTION = 1,
+    RAISED_STACKOVERFLOW = 2,
+    RAISED_NOMEMORY = 4,
+};
 int rb_thread_set_raised(rb_thread_t *th);
 int rb_thread_reset_raised(rb_thread_t *th);
-#define rb_thread_set_stack_overflow(th) \
-    ((th)->raised_flag |= RAISED_STACKOVERFLOW)
-#define rb_thread_reset_stack_overflow(th) \
-    ((th)->raised_flag &= ~RAISED_STACKOVERFLOW)
-#define rb_thread_stack_overflowing_p(th) \
-    (((th)->raised_flag & RAISED_STACKOVERFLOW) != 0)
+#define rb_thread_raised_set(th, f)   ((th)->raised_flag |= (f))
+#define rb_thread_raised_reset(th, f) ((th)->raised_flag &= ~(f))
+#define rb_thread_raised_p(th, f)     (((th)->raised_flag & (f)) != 0)
+#define rb_thread_raised_clear(th)    ((th)->raised_flag = 0)
 
 VALUE rb_f_eval(int argc, VALUE *argv, VALUE self);
 VALUE rb_make_exception(int argc, VALUE *argv);

Modified: MacRuby/trunk/eval_jump.c
===================================================================
--- MacRuby/trunk/eval_jump.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/eval_jump.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -107,10 +107,12 @@
     rb_thread_t *th = GET_THREAD();
     rb_control_frame_t *saved_cfp = th->cfp;
 
-    rb_scan_args(argc, argv, "01", &tag);
     if (argc == 0) {
 	tag = rb_obj_alloc(rb_cObject);
     }
+    else {
+	rb_scan_args(argc, argv, "01", &tag);
+    }
     PUSH_TAG();
 
     th->tag->tag = tag;

Modified: MacRuby/trunk/eval_method.c
===================================================================
--- MacRuby/trunk/eval_method.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/eval_method.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -164,10 +164,10 @@
 		    rb_warning("method redefined; discarding old %s", rb_id2name(mid));
 		}
 	    }
-	    if (klass == rb_cObject && node && node->nd_mid == init) {
-		rb_warn("redefining Object#initialize may cause infinite loop");
-	    }
 	}
+	if (klass == rb_cObject && node && mid == init) {
+	    rb_warn("redefining Object#initialize may cause infinite loop");
+	}
 
 	if (mid == object_id || mid == __send__) {
 	    if (node && nd_type(node) == RUBY_VM_METHOD_NODE) {

Modified: MacRuby/trunk/ext/dbm/dbm.c
===================================================================
--- MacRuby/trunk/ext/dbm/dbm.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/dbm/dbm.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   dbm.c -
 
-  $Author: akr $
+  $Author: knu $
   created at: Mon Jan 24 15:59:52 JST 1994
 
   Copyright (C) 1995-2001 Yukihiro Matsumoto
@@ -505,6 +505,8 @@
     struct dbmdata *dbmp;
     DBM *dbm;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
 	val = dbm_fetch(dbm, key);
@@ -521,6 +523,8 @@
     struct dbmdata *dbmp;
     DBM *dbm;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
 	rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
@@ -537,6 +541,8 @@
     struct dbmdata *dbmp;
     VALUE keystr, valstr;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
 
     for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {

Modified: MacRuby/trunk/ext/digest/defs.h
===================================================================
--- MacRuby/trunk/ext/digest/defs.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/digest/defs.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /* -*- C -*-
- * $Id: defs.h 11708 2007-02-12 23:01:19Z shyouhei $
+ * $Id: defs.h 15780 2008-03-14 08:04:45Z nobu $
  */
 
 #ifndef DEFS_H
@@ -16,18 +16,4 @@
 # define __END_DECLS
 #endif
 
-#if defined(HAVE_INTTYPES_H)
-# include <inttypes.h>
-#elif !defined __CYGWIN__ || !defined __uint8_t_defined
-  typedef unsigned char uint8_t;
-  typedef unsigned int  uint32_t;
-# if SIZEOF_LONG == 8
-  typedef unsigned long uint64_t;
-# elif SIZEOF_LONG_LONG == 8
-  typedef unsigned LONG_LONG uint64_t;
-# else
-#  define NO_UINT64_T
-# endif
-#endif
-
 #endif /* DEFS_H */

Modified: MacRuby/trunk/ext/dl/win32/lib/win32/registry.rb
===================================================================
--- MacRuby/trunk/ext/dl/win32/lib/win32/registry.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/dl/win32/lib/win32/registry.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -337,9 +337,10 @@
       FormatMessageA = Win32API.new('kernel32.dll', 'FormatMessageA', 'LPLLPLP', 'L')
       def initialize(code)
         @code = code
-        msg = "\0" * 1024
+        msg = "\0".force_encoding(Encoding::ASCII_8BIT) * 1024
         len = FormatMessageA.call(0x1200, 0, code, 0, msg, 1024, 0)
-        super msg[0, len].tr("\r", '').chomp
+        msg = msg[0, len].force_encoding(Encoding.find(Encoding.locale_charmap))
+        super msg.tr("\r", '').chomp
       end
       attr_reader :code
     end
@@ -493,7 +494,7 @@
     # utility functions
     #
     def self.expand_environ(str)
-      str.gsub(/%([^%]+)%/) { ENV[$1] || $& }
+      str.gsub(/%([^%]+)%/) { ENV[$1] || ENV[$1.upcase] || $& }
     end
     
     @@type2name = { }

Modified: MacRuby/trunk/ext/dl/win32/lib/win32/resolv.rb
===================================================================
--- MacRuby/trunk/ext/dl/win32/lib/win32/resolv.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/dl/win32/lib/win32/resolv.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -11,7 +11,7 @@
     
     def self.get_hosts_path
       path = get_hosts_dir
-      path = File.join(path.gsub(/\\/, File::SEPARATOR), 'hosts')
+      path = File.expand_path('hosts', path)
       File.exist?(path) ? path : nil
     end
     
@@ -82,10 +82,14 @@
               reg.open(iface) do |regif|
                 begin
                   [ 'NameServer', 'DhcpNameServer' ].each do |key|
-                    ns = regif.read_s(key)
-                    unless ns.empty?
-                      nameserver.concat(ns.split(/[,\s]\s*/))
-                      break
+                    begin
+                      ns = regif.read_s(key)
+                    rescue
+                    else
+                      unless ns.empty?
+                        nameserver.concat(ns.split(/[,\s]\s*/))
+                        break
+                      end
                     end
                   end
                 rescue Registry::Error

Modified: MacRuby/trunk/ext/extmk.rb
===================================================================
--- MacRuby/trunk/ext/extmk.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/extmk.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -24,17 +24,18 @@
 $extlist = []
 $compiled = {}
 
-$:.replace([Dir.pwd])
+srcdir = File.dirname(File.dirname(__FILE__))
+unless defined?(CROSS_COMPILING) and CROSS_COMPILING
+  $:.replace([File.expand_path("lib", srcdir), Dir.pwd])
+end
+$:.unshift(srcdir)
 require 'rbconfig'
 
-srcdir = File.dirname(File.dirname(__FILE__))
-
-$:.unshift(srcdir, File.expand_path("lib", srcdir))
-
 $topdir = "."
 $top_srcdir = srcdir
 
-require 'mkmf'
+$" << "mkmf.rb"
+load File.expand_path("lib/mkmf.rb", srcdir)
 require 'optparse/shellwords'
 
 def sysquote(x)
@@ -60,7 +61,7 @@
       unless installrb.empty?
         config = CONFIG.dup
         install_dirs(target_prefix).each {|var, val| config[var] = val}
-        FileUtils.rm_f(installrb.values.collect {|f| RbConfig.expand(f, config)}, verbose: true)
+        FileUtils.rm_f(installrb.values.collect {|f| RbConfig.expand(f, config)}, :verbose => true)
       end
     end
     return false
@@ -288,7 +289,7 @@
   $mflags.unshift(*rest) unless rest.empty?
 
   def $mflags.set?(flag)
-    grep(/\A-(?!-).*#{'%s' % flag}/i) { return true }
+    grep(/\A-(?!-).*#{flag.chr}/i) { return true }
     false
   end
   def $mflags.defined?(var)
@@ -338,18 +339,22 @@
 
 EXEEXT = CONFIG['EXEEXT']
 if CROSS_COMPILING
-  $ruby = CONFIG['MINIRUBY']
+  $ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY']
 elsif sep = config_string('BUILD_FILE_SEPARATOR')
   $ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT
 else
   $ruby = '$(topdir)/miniruby' + EXEEXT
 end
-$ruby << " -I'$(topdir)' -I'$(top_srcdir)/lib'"
-$ruby << " -I'$(extout)/$(arch)' -I'$(extout)/common'" if $extout
-$ruby << " -I'$(top_srcdir)/ext' -rpurelib.rb"
+$ruby << " -I'$(topdir)'"
+unless CROSS_COMPILING
+  $ruby << " -I'$(top_srcdir)/lib'"
+  $ruby << " -I'$(extout)/$(arch)' -I'$(extout)/common'" if $extout
+  $ruby << " -I./- -I'$(top_srcdir)/ext' -rpurelib.rb"
+  ENV["RUBYLIB"] = "-"
+  ENV["RUBYOPT"] = "-r#{File.expand_path('ext/purelib.rb', $top_srcdir)}"
+end
 $config_h = '$(arch_hdrdir)/ruby/config.h'
-ENV["RUBYLIB"] = "-"
-ENV["RUBYOPT"] = "-rpurelib.rb"
+$mflags << "ruby=#$ruby"
 
 MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)}
 
@@ -399,12 +404,12 @@
     elsif (w = w.grep(String)).empty?
       proc {true}
     else
-      w.collect {|o| o.split(/,/)}.flatten.method(:any?)
+      proc {|c1| w.collect {|o| o.split(/,/)}.flatten.any?(&c1)}
     end
   }
-  cond = proc {|ext|
-    cond1 = proc {|n| File.fnmatch(n, ext, File::FNM_PATHNAME)}
-    withes.call(&cond1) or !withouts.call(&cond1)
+  cond = proc {|ext, *|
+    cond1 = proc {|n| File.fnmatch(n, ext)}
+    withes.call(cond1) or !withouts.call(cond1)
   }
   exts |= Dir.glob("#{ext_prefix}/*/**/extconf.rb").collect {|d|
     d = File.dirname(d)
@@ -553,7 +558,7 @@
   end
 end
 $mflags.unshift("topdir=#$topdir")
-ENV["RUBYOPT"] = ''
+ENV.delete("RUBYOPT")
 system($make, *sysquote($mflags)) or exit($?.exitstatus)
 
 #Local variables:

Modified: MacRuby/trunk/ext/gdbm/gdbm.c
===================================================================
--- MacRuby/trunk/ext/gdbm/gdbm.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/gdbm/gdbm.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   gdbm.c -
 
-  $Author: akr $
+  $Author: knu $
   modified at: Mon Jan 24 15:59:52 JST 1994
 
   Documentation by Peter Adolphs < futzilogik at users dot sourceforge dot net >
@@ -801,6 +801,8 @@
     GDBM_FILE dbm;
     VALUE keystr;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
          keystr = rb_gdbm_nextkey(dbm, keystr)) {
@@ -825,6 +827,8 @@
     GDBM_FILE dbm;
     VALUE keystr;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
          keystr = rb_gdbm_nextkey(dbm, keystr)) {
@@ -849,6 +853,8 @@
     struct dbmdata *dbmp;
     VALUE keystr;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
          keystr = rb_gdbm_nextkey(dbm, keystr)) {

Modified: MacRuby/trunk/ext/nkf/nkf-utf8/nkf.c
===================================================================
--- MacRuby/trunk/ext/nkf/nkf-utf8/nkf.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/nkf/nkf-utf8/nkf.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -31,7 +31,7 @@
  * $B8=:_!"(Bnkf $B$O(B SorceForge $B$K$F%a%s%F%J%s%9$,B3$1$i$l$F$$$^$9!#(B
  * http://sourceforge.jp/projects/nkf/
 ***********************************************************************/
-#define NKF_IDENT "$Id: nkf.c 15386 2008-02-07 00:06:55Z matz $"
+#define NKF_IDENT "$Id: nkf.c 16149 2008-04-22 12:20:36Z naruse $"
 #define NKF_VERSION "2.0.8"
 #define NKF_RELEASE_DATE "2008-01-23"
 #define COPY_RIGHT \
@@ -2456,14 +2456,14 @@
 
 #define SCORE_INIT (SCORE_iMIME)
 
-static const char score_table_A0[] = {
+static const unsigned char score_table_A0[] = {
     0, 0, 0, 0,
     0, 0, 0, 0,
     0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
     SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_NO_EXIST,
 };
 
-static const char score_table_F0[] = {
+static const unsigned char score_table_F0[] = {
     SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
     SCORE_L2, SCORE_DEPEND, SCORE_NO_EXIST, SCORE_NO_EXIST,
     SCORE_DEPEND, SCORE_DEPEND, SCORE_CP932, SCORE_CP932,
@@ -3041,7 +3041,7 @@
     memset(&broken_state, 0, sizeof(broken_state));
 }
 
-static void push_broken_buf(c)
+static void push_broken_buf(nkf_char c)
 {
     broken_state.buf[broken_state.count++] = c;
 }
@@ -3390,7 +3390,7 @@
     if (alpha_f & 16) {
 	/* JIS X 0208 Katakana to JIS X 0201 Katakana */
 	if (c2 == 0x21) {
-	    char c = 0;
+	    nkf_char c = 0;
 	    switch (c1) {
 	    case 0x23:
 		/* U+3002 (0x8142) Ideographic Full Stop -> U+FF61 (0xA1) Halfwidth Ideographic Full Stop */
@@ -5599,7 +5599,7 @@
                 if (strcmp(long_option[i].name, "oc=") == 0){
 		    nkf_str_upcase((char *)p, codeset, 32);
 		    enc = nkf_enc_find(codeset);
-		    if (enc <= 0) continue;
+		    if (enc == 0) continue;
 		    output_encoding = enc;
                     continue;
 		}

Modified: MacRuby/trunk/ext/nkf/nkf.c
===================================================================
--- MacRuby/trunk/ext/nkf/nkf.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/nkf/nkf.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,11 +3,11 @@
  *
  *  original nkf2.x is maintained at http://sourceforge.jp/projects/nkf/
  *
- *  $Id: nkf.c 15267 2008-01-27 07:43:31Z naruse $
+ *  $Id: nkf.c 16149 2008-04-22 12:20:36Z naruse $
  *
  */
 
-#define RUBY_NKF_REVISION "$Revision: 15267 $"
+#define RUBY_NKF_REVISION "$Revision: 16149 $"
 #define RUBY_NKF_VERSION NKF_VERSION " (" NKF_RELEASE_DATE ")"
 
 #include "ruby/ruby.h"
@@ -80,7 +80,7 @@
 int nkf_split_options(const char *arg)
 {
     int count = 0;
-    char option[256];
+    unsigned char option[256];
     int i = 0, j = 0;
     int is_escaped = FALSE;
     int is_single_quoted = FALSE;
@@ -138,10 +138,6 @@
 static VALUE
 rb_nkf_convert(VALUE obj, VALUE opt, VALUE src)
 {
-    rb_encoding *to_enc;
-    const char *to_e;
-    int to_encidx;
-
     reinit();
     StringValue(opt);
     nkf_split_options(RSTRING_PTR(opt));

Modified: MacRuby/trunk/ext/openssl/lib/openssl/digest.rb
===================================================================
--- MacRuby/trunk/ext/openssl/lib/openssl/digest.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/lib/openssl/digest.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -11,7 +11,7 @@
   (See the file 'LICENCE'.)
 
 = Version
-  $Id: digest.rb 12148 2007-04-05 05:59:22Z technorama $
+  $Id: digest.rb 15602 2008-02-25 08:51:18Z technorama $
 =end
 
 ##
@@ -26,6 +26,10 @@
       alg += %w(SHA224 SHA256 SHA384 SHA512)
     end
 
+    def self.digest(name, data)
+        super(data, name)
+    end
+
     alg.each{|name|
       klass = Class.new(Digest){
         define_method(:initialize){|*data|
@@ -46,7 +50,10 @@
 
     # This class is only provided for backwards compatibility.  Use OpenSSL::Digest in the future.
     class Digest < Digest
-      # add warning
+      def initialize(*args)
+        # add warning
+        super(*args)
+      end
     end
 
   end # Digest

Modified: MacRuby/trunk/ext/openssl/openssl_missing.c
===================================================================
--- MacRuby/trunk/ext/openssl/openssl_missing.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/openssl_missing.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: openssl_missing.c 11708 2007-02-12 23:01:19Z shyouhei $
+ * $Id: openssl_missing.c 16422 2008-05-15 09:44:38Z matz $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -22,17 +22,15 @@
 #include "openssl_missing.h"
 
 #if !defined(HAVE_HMAC_CTX_COPY)
-int
+void
 HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in)
 {
-    if (!out || !in) return 0;
+    if (!out || !in) return;
     memcpy(out, in, sizeof(HMAC_CTX));
 
-    if (!EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx)
-	    || !EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx)
-	    || !EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx))
-	return 0;
-    return 1;
+    EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx);
+    EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx);
+    EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx);
 }
 #endif /* HAVE_HMAC_CTX_COPY */
 #endif /* NO_HMAC */

Modified: MacRuby/trunk/ext/openssl/openssl_missing.h
===================================================================
--- MacRuby/trunk/ext/openssl/openssl_missing.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/openssl_missing.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: openssl_missing.h 11708 2007-02-12 23:01:19Z shyouhei $
+ * $Id: openssl_missing.h 16422 2008-05-15 09:44:38Z matz $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -56,14 +56,33 @@
 	(char *(*)())d2i_PKCS7_RECIP_INFO, (char *)ri)
 #endif
 
+#if !defined(HAVE_EVP_MD_CTX_INIT)
 void HMAC_CTX_init(HMAC_CTX *ctx);
-int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
+#endif
+
+#if !defined(HAVE_HMAC_CTX_COPY)
+void HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
+#endif
+
+#if !defined(HAVE_HMAC_CTX_CLEANUP)
 void HMAC_CTX_cleanup(HMAC_CTX *ctx);
+#endif
 
+#if !defined(HAVE_EVP_MD_CTX_CREATE)
 EVP_MD_CTX *EVP_MD_CTX_create(void);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_INIT)
 void EVP_MD_CTX_init(EVP_MD_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_CLEANUP)
 int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_DESTROY)
 void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
+#endif
 
 #if !defined(HAVE_EVP_CIPHER_CTX_COPY)
 int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in);
@@ -107,19 +126,54 @@
 #define OPENSSL_cleanse(p, l) memset(p, 0, l)
 #endif
 
+#if !defined(HAVE_X509_STORE_SET_EX_DATA)
 void *X509_STORE_get_ex_data(X509_STORE *str, int idx);
 int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data);
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_VERSION)
 int X509_CRL_set_version(X509_CRL *x, long version);
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME)
 int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
+#endif
+
+#if !defined(HAVE_X509_CRL_SORT)
 int X509_CRL_sort(X509_CRL *c);
+#endif
+
+#if !defined(HAVE_X509_CRL_ADD0_REVOKED)
 int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
+#endif
+
+#if !defined(HAVE_BN_MOD_SQR)
 int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_MOD_ADD)
 int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_MOD_SUB)
 int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_RAND_RANGE)
 int BN_rand_range(BIGNUM *r, BIGNUM *range);
+#endif
+
+#if !defined(HAVE_BN_PSEUDO_RAND_RANGE)
 int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range);
+#endif
+
+#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE)
 char *CONF_get1_default_config_file(void);
+#endif
+
+#if !defined(HAVE_PEM_DEF_CALLBACK)
 int PEM_def_callback(char *buf, int num, int w, void *key);
+#endif
 
 #if defined(__cplusplus)
 }

Modified: MacRuby/trunk/ext/openssl/ossl_asn1.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_asn1.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_asn1.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_asn1.c 12040 2007-03-12 02:01:19Z knu $
+ * $Id: ossl_asn1.c 15610 2008-02-26 07:07:26Z technorama $
  * 'OpenSSL for Ruby' team members
  * Copyright (C) 2003
  * All rights reserved.
@@ -347,16 +347,11 @@
     if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
 	ossl_raise(eASN1Error, NULL);
     len = bstr->length;
-    if(!(buf = OPENSSL_malloc(len))){
-	ASN1_BIT_STRING_free(bstr);
-	ossl_raise(eASN1Error, NULL);
-    }
     *unused_bits = 0;
     if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT)
 	*unused_bits = bstr->flags & 0x07;
-    memcpy(buf, bstr->data, len);
+    ret = rb_str_new(bstr->data, len);
     ASN1_BIT_STRING_free(bstr);
-    ret = ossl_buf2str(buf, len);
 
     return ret;
 }
@@ -925,7 +920,7 @@
 {
     ASN1_TYPE *asn1;
     int tn, tc, explicit;
-    long length, reallen;
+    long len, reallen;
     unsigned char *buf, *p;
     VALUE str;
 
@@ -934,26 +929,24 @@
     explicit = ossl_asn1_is_explicit(self);
     asn1 = ossl_asn1_get_asn1type(self);
 
-    length = ASN1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn);
-    if(!(buf = OPENSSL_malloc(length))){
+    len = ASN1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn);
+    if(!(buf = OPENSSL_malloc(len))){
 	ossl_ASN1_TYPE_free(asn1);
 	ossl_raise(eASN1Error, "cannot alloc buffer");
     }
     p = buf;
-    if(tc == V_ASN1_UNIVERSAL) ossl_i2d_ASN1_TYPE(asn1, &p);
-    else{
-	if(explicit){
-	    ASN1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc);
-	    ossl_i2d_ASN1_TYPE(asn1, &p);
-	}
-	else{
-	    ossl_i2d_ASN1_TYPE(asn1, &p);
-	    *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED);
-	}
+    if (tc == V_ASN1_UNIVERSAL) {
+        ossl_i2d_ASN1_TYPE(asn1, &p);
+    } else if (explicit) {
+        ASN1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc);
+        ossl_i2d_ASN1_TYPE(asn1, &p);
+    } else {
+        ossl_i2d_ASN1_TYPE(asn1, &p);
+        *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED);
     }
     ossl_ASN1_TYPE_free(asn1);
     reallen = p - buf;
-    assert(reallen <= length);
+    assert(reallen <= len);
     str = ossl_buf2str(buf, reallen); /* buf will be free in ossl_buf2str */
 
     return str;

Modified: MacRuby/trunk/ext/openssl/ossl_config.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_config.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_config.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_config.c 12821 2007-07-20 06:22:54Z nobu $
+ * $Id: ossl_config.c 16125 2008-04-21 08:48:33Z knu $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -389,6 +389,8 @@
 {
     CONF *conf;
 
+    RETURN_ENUMERATOR(self, 0, 0);
+
     GetConfig(self, conf);
     lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(each_conf_value), (void*)NULL);
 

Modified: MacRuby/trunk/ext/openssl/ossl_digest.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_digest.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_digest.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_digest.c 12148 2007-04-05 05:59:22Z technorama $
+ * $Id: ossl_digest.c 15602 2008-02-25 08:51:18Z technorama $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -48,7 +48,7 @@
 
         SafeGetDigest(obj, ctx);
 
-        md = EVP_MD_CTX_md(ctx); /*== ctx->digest*/
+        md = EVP_MD_CTX_md(ctx);
     }
 
     return md;
@@ -62,7 +62,6 @@
 
     ret = ossl_digest_alloc(cDigest);
     GetDigest(ret, ctx);
-    EVP_MD_CTX_init(ctx);
     EVP_DigestInit_ex(ctx, md, NULL);
    
     return ret;
@@ -80,9 +79,8 @@
     ctx = EVP_MD_CTX_create();
     if (ctx == NULL)
 	ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed");
-    EVP_MD_CTX_init(ctx);
     obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx);
-	
+
     return obj;
 }
 
@@ -102,14 +100,9 @@
     VALUE type, data;
 
     rb_scan_args(argc, argv, "11", &type, &data);
-    StringValue(type);
+    md = GetDigestPtr(type);
     if (!NIL_P(data)) StringValue(data);
-    name = StringValuePtr(type);
-    
-    md = EVP_get_digestbyname(name);
-    if (!md) {
-	ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name);
-    }
+
     GetDigest(self, ctx);
     EVP_DigestInit_ex(ctx, md, NULL);
     
@@ -167,147 +160,72 @@
     return self;
 }
 
-static void
-digest_final(EVP_MD_CTX *ctx, char **buf, int *buf_len)
-{
-    EVP_MD_CTX final;
-
-    if (!EVP_MD_CTX_copy(&final, ctx)) {
-	ossl_raise(eDigestError, NULL);
-    }
-    if (!(*buf = OPENSSL_malloc(EVP_MD_CTX_size(&final)))) {
-	EVP_MD_CTX_cleanup(&final);
-	ossl_raise(eDigestError, "Cannot allocate mem for digest");
-    }
-    EVP_DigestFinal_ex(&final, *buf, buf_len);
-    EVP_MD_CTX_cleanup(&final);
-}
-
 /*
  *  call-seq:
- *      digest.final -> aString
+ *      digest.finish -> aString
  *
  */
 static VALUE
-ossl_digest_digest(VALUE self)
+ossl_digest_finish(int argc, VALUE *argv, VALUE self)
 {
     EVP_MD_CTX *ctx;
-    char *buf;
-    int buf_len;
-    VALUE digest;
-	
-    GetDigest(self, ctx);
-    digest_final(ctx, &buf, &buf_len);
-    digest = ossl_buf2str(buf, buf_len);
-	
-    return digest;
-}
+    VALUE str;
 
-/*
- *  call-seq:
- *      digest.hexdigest -> aString
- *
- */
-static VALUE
-ossl_digest_hexdigest(VALUE self)
-{
-    EVP_MD_CTX *ctx;
-    char *buf, *hexbuf;
-    int buf_len;
-    VALUE hexdigest;
+    rb_scan_args(argc, argv, "01", &str);
 
     GetDigest(self, ctx);
-    digest_final(ctx, &buf, &buf_len);
-    if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) {
-	OPENSSL_free(buf);
-	ossl_raise(eDigestError, "Memory alloc error");
+
+    if (NIL_P(str)) {
+        str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
+    } else {
+        StringValue(str);
+        rb_str_resize(str, EVP_MD_CTX_size(ctx));
     }
-    OPENSSL_free(buf);
-    hexdigest = ossl_buf2str(hexbuf, 2 * buf_len);
 
-    return hexdigest;
-}
+    EVP_DigestFinal_ex(ctx, RSTRING_PTR(str), NULL);
 
-static VALUE
-ossl_digest_s_digest(VALUE klass, VALUE str, VALUE data)
-{
-    VALUE obj = rb_class_new_instance(1, &str, klass);
-
-    ossl_digest_update(obj, data);
-
-    return ossl_digest_digest(obj);
+    return str;
 }
 
-static VALUE
-ossl_digest_s_hexdigest(VALUE klass, VALUE str, VALUE data)
-{
-    VALUE obj = rb_class_new_instance(1, &str, klass);
-
-    ossl_digest_update(obj, data);
-
-    return ossl_digest_hexdigest(obj);
-}
-
 /*
  *  call-seq:
- *      digest1 == digest2 -> true | false
+ *      digest.name -> string
  *
  */
 static VALUE
-ossl_digest_equal(VALUE self, VALUE other)
+ossl_digest_name(VALUE self)
 {
     EVP_MD_CTX *ctx;
-    VALUE str1, str2;
 
-    if (rb_obj_is_kind_of(other, cDigest) == Qtrue) {
-	str2 = ossl_digest_digest(other);
-    } else {
-	StringValue(other);
-	str2 = other;
-    }
     GetDigest(self, ctx);
-    if (RSTRING_LEN(str2) == EVP_MD_CTX_size(ctx)) {
-	str1 = ossl_digest_digest(self);
-    } else {
-	str1 = ossl_digest_hexdigest(self);
-    }
-    if (RSTRING_LEN(str1) == RSTRING_LEN(str2)
-	&& rb_str_cmp(str1, str2) == 0) {
-	return Qtrue;
-    }
 
-    return Qfalse;
+    return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
 }
 
 /*
  *  call-seq:
- *      digest.name -> string
+ *      digest.digest_size -> integer
  *
+ *  Returns the output size of the digest.
  */
 static VALUE
-ossl_digest_name(VALUE self)
+ossl_digest_size(VALUE self)
 {
     EVP_MD_CTX *ctx;
 
     GetDigest(self, ctx);
 
-    return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
+    return INT2NUM(EVP_MD_CTX_size(ctx));
 }
 
-/*
- *  call-seq:
- *      digest.size -> integer
- *
- *  Returns the output size of the digest.
- */
 static VALUE
-ossl_digest_size(VALUE self)
+ossl_digest_block_length(VALUE self)
 {
     EVP_MD_CTX *ctx;
 
     GetDigest(self, ctx);
 
-    return INT2NUM(EVP_MD_CTX_size(ctx));
+    return INT2NUM(EVP_MD_CTX_block_size(ctx));
 }
 
 /*
@@ -316,32 +234,26 @@
 void
 Init_ossl_digest()
 {
+    rb_require("openssl");
+    rb_require("digest");
+
 #if 0 /* let rdoc know about mOSSL */
     mOSSL = rb_define_module("OpenSSL");
 #endif
 
-    cDigest = rb_define_class_under(mOSSL, "Digest", rb_cObject);
+    cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class"));
     eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError);
 	
     rb_define_alloc_func(cDigest, ossl_digest_alloc);
-    rb_define_singleton_method(cDigest, "digest", ossl_digest_s_digest, 2);
-    rb_define_singleton_method(cDigest, "hexdigest", ossl_digest_s_hexdigest, 2);
-	
+
     rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1);
-    rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
-    
     rb_define_copy_func(cDigest, ossl_digest_copy);
-    
-    rb_define_method(cDigest, "digest", ossl_digest_digest, 0);
-    rb_define_method(cDigest, "hexdigest", ossl_digest_hexdigest, 0);
-    rb_define_alias(cDigest, "inspect", "hexdigest");
-    rb_define_alias(cDigest, "to_s", "hexdigest");
-    
+    rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
     rb_define_method(cDigest, "update", ossl_digest_update, 1);
     rb_define_alias(cDigest, "<<", "update");
-    
-    rb_define_method(cDigest, "==", ossl_digest_equal, 1);
-    
+    rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1);
+    rb_define_method(cDigest, "digest_length", ossl_digest_size, 0);
+    rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
+
     rb_define_method(cDigest, "name", ossl_digest_name, 0);
-    rb_define_method(cDigest, "size", ossl_digest_size, 0);
 }

Modified: MacRuby/trunk/ext/openssl/ossl_hmac.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_hmac.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_hmac.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_hmac.c 12133 2007-04-02 19:00:23Z technorama $
+ * $Id: ossl_hmac.c 16422 2008-05-15 09:44:38Z matz $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -87,9 +87,7 @@
     GetHMAC(self, ctx1);
     SafeGetHMAC(other, ctx2);
 
-    if (!HMAC_CTX_copy(ctx1, ctx2)) {
-	ossl_raise(eHMACError, NULL);
-    }
+    HMAC_CTX_copy(ctx1, ctx2);
     return self;
 }
 
@@ -115,9 +113,7 @@
 {
     HMAC_CTX final;
 
-    if (!HMAC_CTX_copy(&final, ctx)) {
-	ossl_raise(eHMACError, NULL);
-    }
+    HMAC_CTX_copy(&final, ctx);
     if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) {
 	HMAC_CTX_cleanup(&final);
 	OSSL_Debug("Allocating %d mem", HMAC_size(&final));

Modified: MacRuby/trunk/ext/openssl/ossl_pkey_dh.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_pkey_dh.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_pkey_dh.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_pkey_dh.c 12133 2007-04-02 19:00:23Z technorama $
+ * $Id: ossl_pkey_dh.c 15610 2008-02-26 07:07:26Z technorama $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -524,11 +524,9 @@
 }
 
 #else /* defined NO_DH */
-#   warning >>> OpenSSL is compiled without DH support <<<
 void
 Init_ossl_dh()
 {
-    rb_warning("OpenSSL is compiled without DH support");
 }
 #endif /* NO_DH */
 

Modified: MacRuby/trunk/ext/openssl/ossl_pkey_dsa.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_pkey_dsa.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_pkey_dsa.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_pkey_dsa.c 12128 2007-03-29 17:29:03Z technorama $
+ * $Id: ossl_pkey_dsa.c 15610 2008-02-26 07:07:26Z technorama $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -477,12 +477,8 @@
 }
 
 #else /* defined NO_DSA */
-#   warning >>> OpenSSL is compiled without DSA support <<<
-
 void
 Init_ossl_dsa()
 {
-    rb_warning("OpenSSL is compiled without DSA support");
 }
-
 #endif /* NO_DSA */

Modified: MacRuby/trunk/ext/openssl/ossl_pkey_ec.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_pkey_ec.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_pkey_ec.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1576,10 +1576,7 @@
 }
 
 #else /* defined NO_EC */
-#   warning >>> OpenSSL is compiled without EC support <<<
-
 void Init_ossl_ec()
 {
 }
-
 #endif /* NO_EC */

Modified: MacRuby/trunk/ext/openssl/ossl_pkey_rsa.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_pkey_rsa.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_pkey_rsa.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_pkey_rsa.c 12139 2007-04-03 07:02:44Z technorama $
+ * $Id: ossl_pkey_rsa.c 15610 2008-02-26 07:07:26Z technorama $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -585,11 +585,9 @@
 }
 
 #else /* defined NO_RSA */
-#   warning >>> OpenSSL is compiled without RSA support <<<
 void
 Init_ossl_rsa()
 {
-    rb_warning("OpenSSL is compiled without RSA support");
 }
 #endif /* NO_RSA */
 

Modified: MacRuby/trunk/ext/openssl/ossl_ssl.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_ssl.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_ssl.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_ssl.c 14696 2007-12-25 11:31:51Z technorama $
+ * $Id: ossl_ssl.c 16111 2008-04-20 22:32:06Z technorama $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2000-2002  GOTOU Yuuzou <gotoyuzo at notwork.org>
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
@@ -446,6 +446,14 @@
     return i;
 }
 
+/*
+ * call-seq:
+ *    ctx.setup => Qtrue # first time
+ *    ctx.setup => nil # thereafter
+ *
+ * This method is called automatically when a new SSLSocket is created.
+ * Normally you do not need to call this method (unless you are writing an extension in C).
+ */
 static VALUE
 ossl_sslctx_setup(VALUE self)
 {
@@ -779,18 +787,18 @@
     Data_Get_Struct(self, SSL_CTX, ctx);
 
     hash = rb_hash_new();
-    rb_hash_aset(hash, rb_str_new2("cache_num"), LONG2NUM(SSL_CTX_sess_number(ctx)));
-    rb_hash_aset(hash, rb_str_new2("connect"), LONG2NUM(SSL_CTX_sess_connect(ctx)));
-    rb_hash_aset(hash, rb_str_new2("connect_good"), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
-    rb_hash_aset(hash, rb_str_new2("connect_renegotiate"), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
-    rb_hash_aset(hash, rb_str_new2("accept"), LONG2NUM(SSL_CTX_sess_accept(ctx)));
-    rb_hash_aset(hash, rb_str_new2("accept_good"), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
-    rb_hash_aset(hash, rb_str_new2("accept_renegotiate"), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
-    rb_hash_aset(hash, rb_str_new2("cache_hits"), LONG2NUM(SSL_CTX_sess_hits(ctx)));
-    rb_hash_aset(hash, rb_str_new2("cb_hits"), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
-    rb_hash_aset(hash, rb_str_new2("cache_misses"), LONG2NUM(SSL_CTX_sess_misses(ctx)));
-    rb_hash_aset(hash, rb_str_new2("cache_full"), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
-    rb_hash_aset(hash, rb_str_new2("timeouts"), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));
 
     return hash;
 }
@@ -1347,6 +1355,8 @@
     mSSL = rb_define_module_under(mOSSL, "SSL");
     eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
 
+    Init_ossl_ssl_session();
+
     /* class SSLContext
      *
      * The following attributes are available but don't show up in rdoc.
@@ -1365,6 +1375,8 @@
     rb_define_method(cSSLContext, "ciphers",     ossl_sslctx_get_ciphers, 0);
     rb_define_method(cSSLContext, "ciphers=",    ossl_sslctx_set_ciphers, 1);
 
+    rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
+
     
     rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF));
     rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */

Modified: MacRuby/trunk/ext/openssl/ossl_ssl_session.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_ssl_session.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_ssl_session.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -174,7 +174,7 @@
 
 	p = SSL_SESSION_get_id(ctx, &i);
 
-	return rb_str_new(p, i);
+	return rb_str_new((const char *) p, i);
 }
 #endif
 
@@ -200,7 +200,7 @@
 	else if (len >= sizeof(buf))
 		ossl_raise(eSSLSession, "i2d_SSL_SESSION too large");
 
-	return rb_str_new(p, len);
+	return rb_str_new((const char *) p, len);
 }
 
 /*
@@ -289,6 +289,8 @@
 
 #ifdef HAVE_SSL_SESSION_GET_ID
 	rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
+#else
+	rb_undef_method(cSSLSession, "id");
 #endif
 	rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
 	rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);

Modified: MacRuby/trunk/ext/openssl/ossl_version.h
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_version.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_version.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_version.h 11708 2007-02-12 23:01:19Z shyouhei $
+ * $Id: ossl_version.h 16111 2008-04-20 22:32:06Z technorama $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -11,6 +11,6 @@
 #if !defined(_OSSL_VERSION_H_)
 #define _OSSL_VERSION_H_
 
-#define OSSL_VERSION "1.0.0"
+#define OSSL_VERSION "1.1.0"
 
 #endif /* _OSSL_VERSION_H_ */

Modified: MacRuby/trunk/ext/openssl/ossl_x509ext.c
===================================================================
--- MacRuby/trunk/ext/openssl/ossl_x509ext.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/openssl/ossl_x509ext.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
- * $Id: ossl_x509ext.c 11708 2007-02-12 23:01:19Z shyouhei $
+ * $Id: ossl_x509ext.c 16111 2008-04-20 22:32:06Z technorama $
  * 'OpenSSL for Ruby' project
  * Copyright (C) 2001-2002  Michal Rokos <m.rokos at sh.cvut.cz>
  * All rights reserved.
@@ -110,6 +110,7 @@
     VALUE obj;
 
     MakeX509ExtFactory(klass, obj, ctx);
+    rb_iv_set(obj, "@config", Qnil);
 
     return obj;
 }

Modified: MacRuby/trunk/ext/purelib.rb
===================================================================
--- MacRuby/trunk/ext/purelib.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/purelib.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,3 +1,3 @@
-if nul = $:.index("-")
+if nul = $:.find_index {|path| /\A(?:\.\/)*-\z/ =~ path}
   $:[nul..-1] = ["."]
 end

Modified: MacRuby/trunk/ext/readline/extconf.rb
===================================================================
--- MacRuby/trunk/ext/readline/extconf.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/readline/extconf.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -54,7 +54,8 @@
 have_readline_var("rl_filename_quote_characters")
 have_readline_var("rl_attempted_completion_over")
 have_readline_var("rl_library_version")
-have_readline_var("rl_event_hook")
+# workaround for native windows.
+/mswin|bccwin|mingw/ !~ RUBY_PLATFORM && have_readline_var("rl_event_hook")
 have_func("rl_cleanup_after_signal")
 have_func("rl_clear_signals")
 have_func("rl_vi_editing_mode")

Modified: MacRuby/trunk/ext/readline/readline.c
===================================================================
--- MacRuby/trunk/ext/readline/readline.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/readline/readline.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -54,16 +54,28 @@
 # define rl_completion_matches completion_matches
 #endif
 
-static int readline_event(void);
 static char **readline_attempted_completion_function(const char *text,
                                                      int start, int end);
 
+#ifdef HAVE_RL_EVENT_HOOK
+#define BUSY_WAIT 0
+
+static int readline_event(void);
 static int
-readline_event()
+readline_event(void)
 {
+#if BUSY_WAIT
     rb_thread_schedule();
+#else
+    fd_set rset;
+
+    FD_ZERO(&rset);
+    FD_SET(fileno(rl_instream), &rset);
+    rb_thread_select(fileno(rl_instream) + 1, &rset, NULL, NULL, NULL);
     return 0;
+#endif
 }
+#endif
 
 static VALUE
 readline_readline(int argc, VALUE *argv, VALUE self)
@@ -620,6 +632,8 @@
     HIST_ENTRY *entry;
     int i;
 
+    RETURN_ENUMERATOR(self, 0, 0);
+
     rb_secure(4);
     for (i = 0; i < history_length; i++) {
         entry = history_get(history_base + i);

Modified: MacRuby/trunk/ext/sdbm/init.c
===================================================================
--- MacRuby/trunk/ext/sdbm/init.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/sdbm/init.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   sdbminit.c -
 
-  $Author: akr $
+  $Author: knu $
   created at: Fri May  7 08:34:24 JST 1999
 
   Copyright (C) 1995-2001 Yukihiro Matsumoto
@@ -486,6 +486,8 @@
     struct dbmdata *dbmp;
     DBM *dbm;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
 	val = sdbm_fetch(dbm, key);
@@ -502,6 +504,8 @@
     struct dbmdata *dbmp;
     DBM *dbm;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
 	rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
@@ -518,6 +522,8 @@
     struct dbmdata *dbmp;
     VALUE keystr, valstr;
 
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     GetDBM2(obj, dbmp, dbm);
     for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
 	val = sdbm_fetch(dbm, key);

Modified: MacRuby/trunk/ext/stringio/stringio.c
===================================================================
--- MacRuby/trunk/ext/stringio/stringio.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/stringio/stringio.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   stringio.c -
 
-  $Author: nobu $
+  $Author: knu $
   $RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $
   created at: Tue Feb 19 04:10:38 JST 2002
 
@@ -614,6 +614,9 @@
 strio_each_byte(VALUE self)
 {
     struct StringIO *ptr = readable(StringIO(self));
+
+    RETURN_ENUMERATOR(self, 0, 0);
+
     while (ptr->pos < RSTRING_LEN(ptr->string)) {
 	char c = RSTRING_PTR(ptr->string)[ptr->pos++];
 	rb_yield(CHR2FIX(c));
@@ -938,6 +941,8 @@
     struct StringIO *ptr = StringIO(self);
     VALUE line;
 
+    RETURN_ENUMERATOR(self, argc, argv);
+
     while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
 	rb_yield(line);
     }
@@ -1245,7 +1250,9 @@
 
     rb_define_method(StringIO, "each", strio_each, -1);
     rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
+    rb_define_method(StringIO, "bytes", strio_each_byte, -1);
     rb_define_method(StringIO, "each_line", strio_each, -1);
+    rb_define_method(StringIO, "lines", strio_each, -1);
     rb_define_method(StringIO, "getc", strio_getc, 0);
     rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
     rb_define_method(StringIO, "readchar", strio_readchar, 0);

Modified: MacRuby/trunk/ext/strscan/strscan.c
===================================================================
--- MacRuby/trunk/ext/strscan/strscan.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/strscan/strscan.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,5 @@
 /*
-    $Id: strscan.c 14772 2007-12-28 14:55:43Z akr $
+    $Id: strscan.c 16387 2008-05-12 06:09:53Z matz $
 
     Copyright (c) 1999-2006 Minero Aoki
 
@@ -403,7 +403,9 @@
 static VALUE
 strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
 {
+    regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
     struct strscanner *p;
+    regex_t *re;
     int ret;
 
     Check_Type(regex, T_REGEXP);
@@ -413,13 +415,14 @@
     if (S_RESTLEN(p) < 0) {
         return Qnil;
     }
+    re = rb_reg_prepare_re(regex, p->str);
     if (headonly) {
-        ret = onig_match(RREGEXP(regex)->ptr, (UChar* )CURPTR(p),
+        ret = onig_match(re, (UChar* )CURPTR(p),
                          (UChar* )(CURPTR(p) + S_RESTLEN(p)),
                          (UChar* )CURPTR(p), &(p->regs), ONIG_OPTION_NONE);
     }
     else {
-        ret = onig_search(RREGEXP(regex)->ptr,
+        ret = onig_search(re,
                           (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)),
                           (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)),
                           &(p->regs), ONIG_OPTION_NONE);
@@ -1251,7 +1254,7 @@
     tmp = rb_str_new2(STRSCAN_VERSION);
     rb_obj_freeze(tmp);
     rb_const_set(StringScanner, rb_intern("Version"), tmp);
-    tmp = rb_str_new2("$Id: strscan.c 14772 2007-12-28 14:55:43Z akr $");
+    tmp = rb_str_new2("$Id: strscan.c 16387 2008-05-12 06:09:53Z matz $");
     rb_obj_freeze(tmp);
     rb_const_set(StringScanner, rb_intern("Id"), tmp);
     

Modified: MacRuby/trunk/ext/syck/rubyext.c
===================================================================
--- MacRuby/trunk/ext/syck/rubyext.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/syck/rubyext.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 /*
  * rubyext.c
  *
- * $Author: akr $
+ * $Author: mame $
  *
  * Copyright (C) 2003-2005 why the lucky stiff
  */
@@ -886,7 +886,6 @@
 static VALUE
 syck_resolver_initialize(VALUE self)
 {
-    VALUE tags = rb_hash_new();
     rb_ivar_set(self, s_tags, rb_hash_new());
     return self;
 }
@@ -918,7 +917,6 @@
 VALUE
 syck_resolver_detect_implicit(VALUE self, VALUE val)
 {
-    char *type_id;
     return rb_str_new2( "" );
 }
 
@@ -1068,7 +1066,6 @@
                 VALUE partial;
                 rb_ary_unshift( subclass_parts, rb_ary_pop( parts ) );
                 partial = rb_ary_join( parts, oColon );
-		//printf("partial %p parts %p\n", partial, parts);
                 target_class = rb_hash_aref( tags, partial );
                 if ( NIL_P( target_class ) )
                 {
@@ -1948,7 +1945,6 @@
 syck_emitter_emit(int argc, VALUE *argv, VALUE self)
 {
     VALUE oid, proc;
-    char *anchor_name;
     SyckEmitter *emitter;
     struct emitter_xtra *bonus;
     SYMID symple;
@@ -2158,7 +2154,7 @@
     oGenericResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 );
     rb_define_singleton_method( oGenericResolver, "node_import", syck_genericresolver_node_import, 1 );
     rb_define_const( rb_syck, "GenericResolver", oGenericResolver );
-    
+
     oColon = rb_str_new2( ":" );
     rb_global_variable( &oColon );
     oDoubleColon = rb_str_new2( "::" );

Modified: MacRuby/trunk/ext/syck/syck.h
===================================================================
--- MacRuby/trunk/ext/syck/syck.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/syck/syck.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -48,17 +48,10 @@
 
 #define ALLOC_CT 8
 #define SYCK_BUFFERSIZE 4096
-#if 0//WITH_OBJC
-#define S_ALLOC_N(type,n) (type*)xmalloc(sizeof(type)*(n))
-#define S_ALLOC(type) (type*)xmalloc(sizeof(type))
-#define S_REALLOC_N(var,type,n) (var)=(type*)xrealloc((char*)(var),sizeof(type)*(n))
-#define S_FREE(n) if (n) { xfree(n); n = NULL; }
-#else
 #define S_ALLOC_N(type,n) (type*)malloc(sizeof(type)*(n))
 #define S_ALLOC(type) (type*)malloc(sizeof(type))
 #define S_REALLOC_N(var,type,n) (var)=(type*)realloc((char*)(var),sizeof(type)*(n))
 #define S_FREE(n) if (n) { free(n); n = NULL; }
-#endif
 
 #define S_ALLOCA_N(type,n) (type*)alloca(sizeof(type)*(n))
 

Modified: MacRuby/trunk/ext/syslog/syslog.txt
===================================================================
--- MacRuby/trunk/ext/syslog/syslog.txt	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/syslog/syslog.txt	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,14 +1,17 @@
 .\" syslog.txt -  -*- Indented-Text -*-
 $RoughId: syslog.txt,v 1.18 2002/02/25 08:20:14 knu Exp $
-$Id: syslog.txt 11708 2007-02-12 23:01:19Z shyouhei $
+$Id: syslog.txt 15821 2008-03-21 12:15:06Z knu $
 
 UNIX Syslog extension for Ruby
 Amos Gouaux, University of Texas at Dallas
 <amos+ruby at utdallas.edu>
 &
 Akinori MUSHA
-<knu at ruby-lang.org>
+<knu at iDaemons.org>
 
+Contact:
+  - Akinori MUSHA <knu at iDaemons.org> (current maintainer)
+
 ** Syslog(Module)
 
 Included Modules: Syslog::Constants

Modified: MacRuby/trunk/ext/tk/extconf.rb
===================================================================
--- MacRuby/trunk/ext/tk/extconf.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/tk/extconf.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,8 @@
 
 require 'mkmf'
 
-is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM)
+#is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM)
+is_win32 = (/mswin|mingw|cygwin|bccwin|wince/ =~ RUBY_PLATFORM)
 #is_macosx = (/darwin/ =~ RUBY_PLATFORM)
 
 def find_framework(tcl_hdr, tk_hdr)
@@ -39,18 +40,23 @@
   have_library("m", "log") 
 end
 
-dir_config("tk")
-dir_config("tcl")
-dir_config("X11")
+tk_idir,  tk_ldir  = dir_config("tk")
+tcl_idir, tcl_ldir = dir_config("tcl")
+x11_idir, x11_ldir = dir_config("X11")
 
+tk_ldir2  = with_config("tk-lib")
+tcl_ldir2 = with_config("tcl-lib")
+x11_ldir2 = with_config("X11-lib")
+
 tklib = with_config("tklib")
 tcllib = with_config("tcllib")
 stubs = enable_config("tcltk_stubs") || with_config("tcltk_stubs")
 
 use_X = with_config("X11", (! is_win32))
 
-def find_tcl(tcllib, stubs)
-  paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
+def find_tcl(tcllib, stubs, *opt_paths)
+  default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
+  paths = opt_paths.compact.concat(default_paths)
   if stubs
     func = "Tcl_InitStubs"
     lib = "tclstub"
@@ -60,24 +66,23 @@
   end
   if tcllib
     find_library(tcllib, func, *paths)
-  elsif find_library(lib, func, *paths)
-    true
   else
     %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6].find { |ver|
       find_library("#{lib}#{ver}", func, *paths) or
         find_library("#{lib}#{ver.delete('.')}", func, *paths) or
+        find_library("#{lib}#{ver}g", func, *paths) or
+        find_library("#{lib}#{ver.delete('.')}g", func, *paths) or
         find_library("tcl#{ver}", func, *paths) or
         find_library("tcl#{ver.delete('.')}", func, *paths) or
-        find_library("#{lib}#{ver}g", func, *paths) or
-        find_library("#{lib}#{ver.delete('.')}g", func, *paths) or
         find_library("tcl#{ver}g", func, *paths) or
         find_library("tcl#{ver.delete('.')}g", func, *paths)
-    }
+    } || find_library(lib, func, *paths)
   end
 end
 
-def find_tk(tklib, stubs)
-  paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
+def find_tk(tklib, stubs, *opt_paths)
+  default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
+  paths = opt_paths.compact.concat(default_paths)
   if stubs
     func = "Tk_InitStubs"
     lib = "tkstub"
@@ -87,22 +92,27 @@
   end
   if tklib
     find_library(tklib, func, *paths)
-  elsif find_library(lib, func, *paths)
-    true
   else
     %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 4.2].find { |ver|
       find_library("#{lib}#{ver}", func, *paths) or
         find_library("#{lib}#{ver.delete('.')}", func, *paths) or
+        find_library("#{lib}#{ver}g", func, *paths) or
+        find_library("#{lib}#{ver.delete('.')}g", func, *paths) or
         find_library("tk#{ver}", func, *paths) or
         find_library("tk#{ver.delete('.')}", func, *paths) or 
-        find_library("#{lib}#{ver}g", func, *paths) or
-        find_library("#{lib}#{ver.delete('.')}g", func, *paths) or
         find_library("tk#{ver}g", func, *paths) or
         find_library("tk#{ver.delete('.')}g", func, *paths)
-    }
+    } || find_library(lib, func, *paths)
   end
 end
 
+def find_X11(*opt_paths)
+  default_paths = 
+    [ "/usr/X11/lib", "/usr/lib/X11", "/usr/X11R6/lib", "/usr/openwin/lib" ]
+  paths = opt_paths.compact.concat(default_paths)
+  find_library("X11", "XOpenDisplay", *paths)
+end 
+
 def pthread_check()
   tcl_major_ver = nil
   tcl_minor_ver = nil
@@ -281,13 +291,11 @@
   end
 end
 
-if tcltk_framework || 
-   (have_header("tcl.h") && have_header("tk.h") &&
-      ( !use_X || find_library("X11", "XOpenDisplay",
-                               "/usr/X11/lib", "/usr/lib/X11", 
-                               "/usr/X11R6/lib", "/usr/openwin/lib")) &&
-    find_tcl(tcllib, stubs) &&
-    find_tk(tklib, stubs))
+if have_header("tcl.h") && have_header("tk.h") &&
+    ( tcltk_framework || 
+        ( ( !use_X || find_X11(x11_ldir2, x11_ldir) ) &&
+            find_tcl(tcllib, stubs, tcl_ldir2, tcl_ldir) &&
+            find_tk(tklib, stubs, tk_ldir2, tk_ldir) ) )
   $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs
   $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM
 

Modified: MacRuby/trunk/ext/tk/lib/multi-tk.rb
===================================================================
--- MacRuby/trunk/ext/tk/lib/multi-tk.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/tk/lib/multi-tk.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -114,8 +114,15 @@
 class MultiTkIp
   BASE_DIR = File.dirname(__FILE__)
 
-  @@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
+  WITH_RUBY_VM  = Object.const_defined?(:VM) && ::VM.class == Class
+  WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class
 
+  (@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint]).instance_eval{
+    @mutex = Mutex.new
+    def mutex; @mutex; end
+    freeze
+  }
+
   @@IP_TABLE = {}.taint unless defined?(@@IP_TABLE)
 
   @@INIT_IP_ENV  = [].taint unless defined?(@@INIT_IP_ENV)  # table of Procs
@@ -126,7 +133,11 @@
   unless defined?(@@TK_CMD_TBL)
     @@TK_CMD_TBL = Object.new.taint
 
-    @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint)
+    # @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint)
+    @@TK_CMD_TBL.instance_variable_set('@tbl', Hash.new{|hash,key|
+                                           fail IndexError, 
+                                                "unknown command ID '#{key}'"
+                                       }.taint)
 
     class << @@TK_CMD_TBL
       allow = [
@@ -573,7 +584,11 @@
       # raise exception
       begin
         bt = _toUTF8(e.backtrace.join("\n"))
-        bt.instance_variable_set(:@encoding, 'utf-8')
+        if MultiTkIp::WITH_ENCODING
+          bt.force_encoding('utf-8')
+        else
+          bt.instance_variable_set(:@encoding, 'utf-8')
+        end
       rescue Exception
         bt = e.backtrace.join("\n")
       end
@@ -695,6 +710,11 @@
 
   ######################################
 
+  unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD
+    ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!!
+    RUN_EVENTLOOP_ON_MAIN_THREAD = false
+  end
+
   if self.const_defined? :DEFAULT_MASTER_NAME
     name = DEFAULT_MASTER_NAME.to_s
   else
@@ -723,13 +743,24 @@
       fail ArgumentError, "expecting a Hash object for the 2nd argument"
     end
 
-    if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+    if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
       @interp = TclTkIp.new(name, _keys2opts(keys))
-    else
+    else ### Ruby 1.9 !!!!!!!!!!!
       @interp_thread = Thread.new{
-        Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys))
+        current = Thread.current
+        current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys))
         #sleep
-        interp.mainloop(true)
+        current[:mutex] = mutex = Mutex.new
+        current[:root_check] = cond_var = ConditionVariable.new
+
+        begin
+          current[:status] = interp.mainloop(true)
+        rescue Exception=>e
+          current[:status] = e
+        ensure
+          mutex.synchronize{ cond_var.broadcast }
+        end
+        current[:status] = interp.mainloop(false)
       }
       until @interp_thread[:interp]
         Thread.pass
@@ -876,22 +907,26 @@
     Thread.new{
       current = Thread.current
       loop {
-        mtx, ret, table, script = @init_ip_env_queue.deq
-        begin        
+        mtx, cond, ret, table, script = @init_ip_env_queue.deq
+        begin
           ret[0] = table.each{|tg, ip| ip._init_ip_env(script) }
         rescue Exception => e
           ret[0] = e
         ensure
-          mtx.unlock
+          mtx.synchronize{ cond.signal }
         end
+        mtx = cond = ret = table = script = nil  # clear variables for GC
       }
     }
 
     def self.__init_ip_env__(table, script)
       ret = []
-      mtx = Mutex.new.lock
-      @init_ip_env_queue.enq([mtx, ret, table, script])
-      # mtx.lock
+      mtx  = (Thread.current[:MultiTk_ip_Mutex] ||= Mutex.new)
+      cond = (Thread.current[:MultiTk_ip_CondVar] ||= ConditionVariable.new)
+      mtx.synchronize{
+        @init_ip_env_queue.enq([mtx, cond, ret, table, script])
+        cond.wait(mtx)
+      }
       if ret[0].kind_of?(Exception)
         raise ret[0]
       else
@@ -970,9 +1005,11 @@
   private :_parse_slaveopts
 
   def _create_slave_ip_name
-    name = @@SLAVE_IP_ID.join('')
-    @@SLAVE_IP_ID[1].succ!
-    name.freeze
+    @@SLAVE_IP_ID.mutex.synchronize{
+      name = @@SLAVE_IP_ID.join('')
+      @@SLAVE_IP_ID[1].succ!
+      name.freeze
+    }
   end
   private :_create_slave_ip_name
 
@@ -1229,9 +1266,9 @@
 
     if safeip == nil
       # create master-ip
-      if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+      unless WITH_RUBY_VM
         @interp = TclTkIp.new(name, _keys2opts(tk_opts))
-      else
+      else ### Ruby 1.9 !!!!!!!!!!!
         @interp_thread = Thread.new{
           Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(tk_opts))
           #sleep
@@ -1257,7 +1294,8 @@
         @safe_base = true
         @interp, @ip_name = master.__create_safe_slave_obj(safe_opts, 
                                                            name, tk_opts)
-        @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+        # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+        @interp_thread = nil unless WITH_RUBY_VM  ### Ruby 1.9 !!!!!!!!!!!
         if safe
           safe = master.safe_level if safe < master.safe_level
           @safe_level = [safe]
@@ -1266,7 +1304,8 @@
         end
       else
         @interp, @ip_name = master.__create_trusted_slave_obj(name, tk_opts)
-        @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+        # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+        @interp_thread = nil unless WITH_RUBY_VM  ### Ruby 1.9 !!!!!!!!!!!
         if safe
           safe = master.safe_level if safe < master.safe_level
           @safe_level = [safe]
@@ -1301,11 +1340,11 @@
     @@DEFAULT_MASTER.assign_receiver_and_watchdog(self)
 
     @@IP_TABLE[@threadgroup] = self
-    _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
     @@TK_TABLE_LIST.size.times{ 
       (tbl = {}).tainted? || tbl.taint
       @tk_table_list << tbl
     }
+    _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
 
     class << self
       undef :instance_eval
@@ -1383,8 +1422,13 @@
   alias __new new
   private :__new
 
+  def new_master(safe=nil, keys={})
+    if MultiTkIp::WITH_RUBY_VM
+      #### TODO !!!!!!
+      fail RuntimeError, 
+           'sorry, still not support multiple master-interpreters on Ruby VM'
+    end
 
-  def new_master(safe=nil, keys={})
     if safe.kind_of?(Hash)
       keys = safe
     elsif safe.kind_of?(Integer)
@@ -1601,8 +1645,13 @@
     return if slave?
     names.each{|name|
       name = name.to_s
+
+      return if @interp.deleted?
       @interp._invoke('rename', name, '')
+
+      return if @interp.deleted?
       @interp._invoke('interp', 'slaves').split.each{|slave|
+        return if @interp.deleted?
         @interp._invoke('interp', 'alias', slave, name, '') rescue nil
       }
     }
@@ -1652,11 +1701,16 @@
     id = @@TK_TABLE_LIST.size
     obj = Object.new
     @@TK_TABLE_LIST << obj
-    obj.instance_eval <<-EOD
+    obj.instance_variable_set(:@id, id)
+    obj.instance_variable_set(:@mutex, Mutex.new)
+    obj.instance_eval{
+      def self.mutex
+        @mutex
+      end
       def self.method_missing(m, *args)
-         MultiTkIp.tk_object_table(#{id}).__send__(m, *args)
+        MultiTkIp.tk_object_table(@id).__send__(m, *args)
       end
-    EOD
+    }
     obj.freeze
     @@IP_TABLE.each{|tg, ip| ip._add_new_tables }
     return obj
@@ -2377,7 +2431,7 @@
   def mainloop(check_root = true, restart_on_dead = true)
     raise SecurityError, "no permission to manipulate" unless self.manipulable?
 
-    if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+    unless WITH_RUBY_VM  ### Ruby 1.9 !!!!!!!!!!!
       return @interp_thread.value if @interp_thread
     end
 
@@ -2789,9 +2843,10 @@
     i = -1
     brace = 1
     str.each_byte {|c|
+      c = c.chr
       i += 1
-      brace += 1 if c == ?{
-      brace -= 1 if c == ?}
+      brace += 1 if c == '{'
+      brace -= 1 if c == '}'
       break if brace == 0
     }
     if i == 0
@@ -3230,15 +3285,44 @@
 
 
 # encoding convert
+class << MultiTkIp
+  def encoding_table
+    __getip.encoding_table
+  end
+end
 class MultiTkIp
-  def encoding
+  def encoding_table
+    @interp.encoding_table
+  end
+
+  def force_default_encoding=(mode)
     raise SecurityError, "no permission to manipulate" unless self.manipulable?
-    @interp.encoding
+    @interp.force_default_encoding = mode
   end
+  def force_default_encoding?
+    raise SecurityError, "no permission to manipulate" unless self.manipulable?
+    @interp.force_default_encoding?
+  end
+
+  def default_encoding=(enc)
+    raise SecurityError, "no permission to manipulate" unless self.manipulable?
+    @interp.default_encoding = enc
+  end
+
   def encoding=(enc)
     raise SecurityError, "no permission to manipulate" unless self.manipulable?
     @interp.encoding = enc
   end
+  def encoding_name
+    raise SecurityError, "no permission to manipulate" unless self.manipulable?
+    @interp.encoding_name
+  end
+  def encoding_obj
+    raise SecurityError, "no permission to manipulate" unless self.manipulable?
+    @interp.encoding_obj
+  end
+  alias encoding encoding_name
+  alias default_encoding encoding_name
 
   def encoding_convertfrom(str, enc=None)
     raise SecurityError, "no permission to manipulate" unless self.manipulable?
@@ -3256,12 +3340,28 @@
 
 # remove methods for security
 class MultiTkIp
+  INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread')
+  INTERP_MUTEX  = INTERP_THREAD[:mutex]
+  INTERP_ROOT_CHECK = INTERP_THREAD[:root_check]
+
   # undef_method :instance_eval
   undef_method :instance_variable_get
   undef_method :instance_variable_set
 end
 
-
+module TkCore
+  if MultiTkIp::WITH_RUBY_VM && 
+      ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
+    INTERP_THREAD = MultiTkIp::INTERP_THREAD
+    INTERP_MUTEX  = MultiTkIp::INTERP_MUTEX
+    INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK
+  end
+end
+class MultiTkIp
+  remove_const(:INTERP_THREAD)
+  remove_const(:INTERP_MUTEX)
+  remove_const(:INTERP_ROOT_CHECK)
+end
 # end of MultiTkIp definition
 
 # defend against modification

Modified: MacRuby/trunk/ext/tk/lib/tk/autoload.rb
===================================================================
--- MacRuby/trunk/ext/tk/lib/tk/autoload.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/tk/lib/tk/autoload.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,21 +1,7 @@
 #
 #  autoload
 #
-major, minor, type, type_name, patchlevel = TclTkLib.get_version
-
-######################################
-#  depend on version of Tcl/Tk
-if major > 8 || 
-    (major == 8 && minor > 5) || 
-    (major == 8 && minor == 5 && type >= TclTkLib::RELEASE_TYPE::BETA) 
-  # Tcl/Tk 8.5 beta or later
-  autoload :Ttk, 'tkextlib/tile'
-  module Tk
-    autoload :Tile, 'tkextlib/tile'
-  end
-end
-
-######################################
+############################################
 #  geometry manager
 module Tk
   autoload :Grid,             'tk/grid'

Modified: MacRuby/trunk/ext/tk/stubs.c
===================================================================
--- MacRuby/trunk/ext/tk/stubs.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/tk/stubs.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,11 @@
+/************************************************
+
+  stubs.c - Tcl/Tk stubs support
+
+************************************************/
+
+#include "ruby.h"
 #include "stubs.h"
-#include "ruby/ruby.h"
 #include <tcl.h>
 #include <tk.h>
 
@@ -86,7 +92,12 @@
 static DL_HANDLE tk_dll  = (DL_HANDLE)0;
 
 int
+#ifdef RUBY_VM
 ruby_open_tcl_dll(char *appname)
+#else
+ruby_open_tcl_dll(appname)
+    char *appname;
+#endif
 {
     void (*p_Tcl_FindExecutable)(const char *);
     int n;
@@ -168,7 +179,12 @@
 }
 
 int
+#ifdef RUBY_VM
 ruby_open_tcltk_dll(char *appname)
+#else
+ruby_open_tcltk_dll(appname)
+    char *appname;
+#endif
 {
     return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() );
 }
@@ -187,7 +203,12 @@
 
 
 Tcl_Interp *
+#ifdef RUBY_VM
 ruby_tcl_create_ip_and_stubs_init(int *st)
+#else
+ruby_tcl_create_ip_and_stubs_init(st)
+    int *st;
+#endif
 {
     Tcl_Interp *tcl_ip;
 
@@ -269,7 +290,12 @@
 }
 
 int
+#ifdef RUBY_VM
 ruby_tk_stubs_init(Tcl_Interp *tcl_ip)
+#else
+ruby_tk_stubs_init(tcl_ip)
+    Tcl_Interp *tcl_ip;
+#endif
 {
     Tcl_ResetResult(tcl_ip);
 
@@ -304,7 +330,12 @@
 }
 
 int
+#ifdef RUBY_VM
 ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip)
+#else
+ruby_tk_stubs_safeinit(tcl_ip)
+    Tcl_Interp *tcl_ip;
+#endif
 {
     Tcl_ResetResult(tcl_ip);
 
@@ -390,7 +421,12 @@
 static int call_tk_stubs_init = 0;
 
 int
+#ifdef RUBY_VM
 ruby_open_tcl_dll(char *appname)
+#else
+ruby_open_tcl_dll(appname)
+    char *appname;
+#endif
 {
     if (appname) {
         Tcl_FindExecutable(appname);
@@ -402,7 +438,8 @@
     return TCLTK_STUBS_OK;
 }
 
-int ruby_open_tk_dll()
+int 
+ruby_open_tk_dll()
 {
     if (!open_tcl_dll) {
         /* ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */
@@ -412,7 +449,13 @@
     return TCLTK_STUBS_OK;
 }
 
-int ruby_open_tcltk_dll(char *appname)
+int 
+#ifdef RUBY_VM
+ruby_open_tcltk_dll(char *appname)
+#else
+ruby_open_tcltk_dll(appname)
+    char *appname;
+#endif
 {
     return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() );
 }
@@ -430,7 +473,12 @@
 }
 
 Tcl_Interp *
+#ifdef RUBY_VM
 ruby_tcl_create_ip_and_stubs_init(int *st)
+#else
+ruby_tcl_create_ip_and_stubs_init(st)
+    int *st;
+#endif
 {
     Tcl_Interp *tcl_ip;
 
@@ -458,7 +506,12 @@
 }
 
 int 
+#ifdef RUBY_VM
 ruby_tk_stubs_init(Tcl_Interp *tcl_ip)
+#else
+ruby_tk_stubs_init(tcl_ip)
+    Tcl_Interp *tcl_ip;
+#endif
 {
     if (Tk_Init(tcl_ip) == TCL_ERROR)
         return FAIL_Tk_Init;
@@ -474,7 +527,12 @@
 }
 
 int
+#ifdef RUBY_VM
 ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip)
+#else
+ruby_tk_stubs_safeinit(tcl_ip)
+    Tcl_Interp *tcl_ip;
+#endif
 {
 #if TCL_MAJOR_VERSION >= 8
     if (Tk_SafeInit(tcl_ip) == TCL_ERROR)

Modified: MacRuby/trunk/ext/tk/tcltklib.c
===================================================================
--- MacRuby/trunk/ext/tk/tcltklib.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/tk/tcltklib.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -4,10 +4,20 @@
  *              Oct. 24, 1997   Y. Matsumoto
  */
 
-#define TCLTKLIB_RELEASE_DATE "2007-12-21"
+#define TCLTKLIB_RELEASE_DATE "2008-03-29"
 
-#include "ruby/ruby.h"
+#include "ruby.h"
+
+#ifdef RUBY_VM
+/* #include "ruby/ruby.h" */
 #include "ruby/signal.h"
+#include "ruby/encoding.h"
+#else
+/* #include "ruby.h" */
+#include "rubysig.h"
+#include "version.h"
+#endif
+
 #undef EXTERN   /* avoid conflict with tcl.h of tcl8.2 or before */
 #include <stdio.h>
 #ifdef HAVE_STDARG_PROTOTYPES
@@ -29,6 +39,24 @@
 #define TCL_FINAL_RELEASE       2
 #endif
 
+static struct {
+  int major;
+  int minor;
+  int patchlevel;
+  int type;
+} tcltk_version = {0, 0, 0, 0};
+
+static void
+set_tcltk_version()
+{
+    if (tcltk_version.major) return;
+
+    Tcl_GetVersion(&(tcltk_version.major), 
+		   &(tcltk_version.minor), 
+		   &(tcltk_version.patchlevel), 
+		   &(tcltk_version.type));
+}
+
 #if TCL_MAJOR_VERSION >= 8
 # ifndef CONST84
 #  if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 /* Tcl8.0.x -- 8.4b1 */
@@ -82,7 +110,27 @@
 
 static int at_exit = 0;
 
+#ifdef RUBY_VM
+static VALUE cRubyEncoding;
 
+/* encoding */
+static int ENCODING_INDEX_UTF8;
+static int ENCODING_INDEX_BINARY;
+#endif
+static VALUE ENCODING_NAME_UTF8;
+static VALUE ENCODING_NAME_BINARY;
+
+static VALUE create_dummy_encoding_for_tk_core _((VALUE, VALUE, VALUE));
+static VALUE create_dummy_encoding_for_tk _((VALUE, VALUE));
+static int update_encoding_table _((VALUE, VALUE, VALUE));
+static VALUE encoding_table_get_name_core _((VALUE, VALUE, VALUE));
+static VALUE encoding_table_get_obj_core _((VALUE, VALUE, VALUE));
+static VALUE encoding_table_get_name _((VALUE, VALUE));
+static VALUE encoding_table_get_obj _((VALUE, VALUE));
+static VALUE create_encoding_table _((VALUE));
+static VALUE ip_get_encoding_table _((VALUE));
+
+
 /* for callback break & continue */
 static VALUE eTkCallbackReturn;
 static VALUE eTkCallbackBreak;
@@ -100,6 +148,9 @@
 static ID ID_at_enc;
 static ID ID_at_interp;
 
+static ID ID_encoding_name;
+static ID ID_encoding_table;
+
 static ID ID_stop_p;
 static ID ID_alive_p;
 static ID ID_kill;
@@ -123,6 +174,21 @@
 
 static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE));
 
+/* Tcl's object type */
+#if TCL_MAJOR_VERSION >= 8
+static char *Tcl_ObjTypeName_ByteArray = "bytearray";
+static Tcl_ObjType *Tcl_ObjType_ByteArray;
+
+static char *Tcl_ObjTypeName_String    = "string";
+static Tcl_ObjType *Tcl_ObjType_String;
+
+#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1)
+#define IS_TCL_BYTEARRAY(obj)    ((obj)->typePtr == Tcl_ObjType_ByteArray)
+#define IS_TCL_STRING(obj)       ((obj)->typePtr == Tcl_ObjType_String)
+#define IS_TCL_VALID_STRING(obj) ((obj)->bytes != (char*)NULL)
+#endif
+#endif
+
 /* safe Tcl_Eval and Tcl_GlobalEval */
 static int
 tcl_eval(Tcl_Interp *interp, const char *cmd)
@@ -8325,6 +8391,15 @@
 
     /* --------------------------------------------------------------- */
 
+#if !WITH_OBJC
+    /* XXX these symbols do not seem to be imported */
+    rb_define_method(ip, "create_dummy_encoding_for_tk", 
+		     create_dummy_encoding_for_tk, 1);
+    rb_define_method(ip, "encoding_table", ip_get_encoding_table, 0);
+#endif
+
+    /* --------------------------------------------------------------- */
+
     rb_define_method(ip, "_get_variable", ip_get_variable, 2);
     rb_define_method(ip, "_get_variable2", ip_get_variable2, 3);
     rb_define_method(ip, "_set_variable", ip_set_variable, 3);
@@ -8384,7 +8459,11 @@
 
     /* if ruby->nativethread-supprt and tcltklib->doen't, 
        the following will cause link-error. */
+#ifdef RUBY_VM
     ruby_native_thread_p();
+#else
+    is_ruby_native_thread();
+#endif
 
     /* --------------------------------------------------------------- */
 
@@ -8405,6 +8484,11 @@
     }
 
     /* --------------------------------------------------------------- */
+
+    Tcl_ObjType_ByteArray = Tcl_GetObjType(Tcl_ObjTypeName_ByteArray);
+    Tcl_ObjType_String    = Tcl_GetObjType(Tcl_ObjTypeName_String);
+
+    /* --------------------------------------------------------------- */
 }
 
 /* eof */

Modified: MacRuby/trunk/ext/tk/tkutil/tkutil.c
===================================================================
--- MacRuby/trunk/ext/tk/tkutil/tkutil.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/tk/tkutil/tkutil.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,16 +2,25 @@
 
   tkutil.c -
 
-  $Author: akr $
+  $Author: nagai $
   created at: Fri Nov  3 00:47:54 JST 1995
 
 ************************************************/
 
-#define TKUTIL_RELEASE_DATE "2006-04-06"
+#define TKUTIL_RELEASE_DATE "2008-03-29"
 
-#include "ruby/ruby.h"
+#include "ruby.h"
+
+#ifdef RUBY_VM  /* Ruby 1.9 */
+/* #include "ruby/ruby.h" */
 #include "ruby/signal.h"
 #include "ruby/st.h"
+#else
+/* #include "ruby.h" */
+#include "rubysig.h"
+#include "version.h"
+#include "st.h"
+#endif
 
 static VALUE cMethod;
 
@@ -25,6 +34,8 @@
 static VALUE cCB_SUBST;
 static VALUE cSUBST_INFO;
 
+static VALUE ENCODING_NAME_UTF8; /* for saving GC cost */
+
 static ID ID_split_tklist;
 static ID ID_toUTF8;
 static ID ID_fromUTF8;
@@ -780,7 +791,11 @@
                 return fromDefaultEnc_toUTF8(rb_str_new2(rb_id2name(SYM2ID(obj))), self);
             }
         } else {
+#ifdef RUBY_VM
+            return rb_sym_to_s(obj);
+#else
             return rb_str_new2(rb_id2name(SYM2ID(obj)));
+#endif
         }
 
     case T_HASH:
@@ -1485,6 +1500,7 @@
     return rb_ivar_get(self, ID_at_path);
 }
 
+
 /*************************************/
 /* release date */
 const char tkutil_release_date[] = TKUTIL_RELEASE_DATE;
@@ -1609,4 +1625,8 @@
     rb_define_method(mTK, "num_or_str", tcl2rb_num_or_str, 1);
 
     /* --------------------- */
+    rb_global_variable(&ENCODING_NAME_UTF8);
+    ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8"));
+
+    /* --------------------- */
 }

Modified: MacRuby/trunk/ext/win32ole/win32ole.c
===================================================================
--- MacRuby/trunk/ext/win32ole/win32ole.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/win32ole/win32ole.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -819,7 +819,6 @@
     ENC_MACHING_CP(enc, "KOI8-R", 20866);
     ENC_MACHING_CP(enc, "KOI8-U", 21866);
     ENC_MACHING_CP(enc, "Shift_JIS", 932);
-    ENC_MACHING_CP(enc, "US-ASCII", 20127);
     ENC_MACHING_CP(enc, "UTF-16BE", 1201);
     ENC_MACHING_CP(enc, "UTF-16LE", 1200);
     ENC_MACHING_CP(enc, "UTF-7", 65000);
@@ -849,6 +848,7 @@
     if (code_page_installed(cp)) {
         cWIN32OLE_cp = cp;
     }
+    return cp;
 }
 
 struct myCPINFOEX {
@@ -1326,13 +1326,13 @@
     if ((vt & ~VT_BYREF) == VT_ARRAY) {
         vt = (vt | VT_VARIANT);
     }
-    psa = SafeArrayCreate(vt & VT_TYPEMASK, dim, psab);
+    psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
     if (psa == NULL)
         hr = E_OUTOFMEMORY;
     else
         hr = SafeArrayLock(psa);
     if (SUCCEEDED(hr)) {
-        ole_set_safe_array(dim-1, psa, pid, pub, val, dim, vt & VT_TYPEMASK);
+        ole_set_safe_array(dim-1, psa, pid, pub, val, dim, (VARTYPE)(vt & VT_TYPEMASK));
         hr = SafeArrayUnlock(psa);
     }
 
@@ -1643,7 +1643,7 @@
                 V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
             }
         } else {
-            hr = ole_val_ary2variant_ary(val, &(pvar->realvar), (vt & ~VT_BYREF));
+            hr = ole_val_ary2variant_ary(val, &(pvar->realvar), (VARTYPE)(vt & ~VT_BYREF));
             if (SUCCEEDED(hr)) {
                 if (vt & VT_BYREF) {
                     V_VT(&(pvar->var)) = vt;
@@ -1674,7 +1674,7 @@
                 }
             }
         } else {
-            ole_val2variant_ex(val, &(pvar->realvar), (vt & ~VT_BYREF));
+            ole_val2variant_ex(val, &(pvar->realvar), (VARTYPE)(vt & ~VT_BYREF));
             if (vt == (VT_BYREF | VT_VARIANT)) {
                 ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
             } else if (vt & VT_BYREF) {
@@ -3699,6 +3699,8 @@
     HRESULT hr;
     IEnumVARIANT *pEnum = NULL;
 
+    RETURN_ENUMERATOR(self, 0, 0);
+
     VariantInit(&result);
     dispParams.rgvarg = NULL;
     dispParams.rgdispidNamedArgs = NULL;
@@ -7750,7 +7752,7 @@
         psab[i].lLbound = 0;
     }
 
-    psa = SafeArrayCreate(vt & VT_TYPEMASK, dim, psab);
+    psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
     if (psa == NULL) {
         if (psab) free(psab);
         rb_raise(rb_eRuntimeError, "memory allocation error(SafeArrayCreate)");

Modified: MacRuby/trunk/ext/zlib/zlib.c
===================================================================
--- MacRuby/trunk/ext/zlib/zlib.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ext/zlib/zlib.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,7 +3,7 @@
  *
  *   Copyright (C) UENO Katsuhiro 2000-2003
  *
- * $Id: zlib.c 12480 2007-06-08 07:33:59Z akr $
+ * $Id: zlib.c 16304 2008-05-06 15:56:21Z matz $
  */
 
 #include <ruby.h>
@@ -2934,6 +2934,9 @@
 rb_gzreader_each_byte(VALUE obj)
 {
     VALUE c;
+
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     while (!NIL_P(c = rb_gzreader_getc(obj))) {
 	rb_yield(c);
     }
@@ -3013,6 +3016,8 @@
     if (NIL_P(rs)) {
 	dst = gzfile_read_all(gz);
 	if (RSTRING_LEN(dst) != 0) gz->lineno++;
+	else
+	    return Qnil;
 	return dst;
     }
 
@@ -3102,6 +3107,9 @@
 rb_gzreader_each(int argc, VALUE *argv, VALUE obj)
 {
     VALUE str;
+
+    RETURN_ENUMERATOR(obj, 0, 0);
+
     while (!NIL_P(str = gzreader_gets(argc, argv, obj))) {
 	rb_yield(str);
     }
@@ -3361,11 +3369,13 @@
     rb_define_method(cGzipReader, "getc", rb_gzreader_getc, 0);
     rb_define_method(cGzipReader, "readchar", rb_gzreader_readchar, 0);
     rb_define_method(cGzipReader, "each_byte", rb_gzreader_each_byte, 0);
+    rb_define_method(cGzipReader, "bytes", rb_gzreader_each_byte, 0);
     rb_define_method(cGzipReader, "ungetc", rb_gzreader_ungetc, 1);
     rb_define_method(cGzipReader, "gets", rb_gzreader_gets, -1);
     rb_define_method(cGzipReader, "readline", rb_gzreader_readline, -1);
     rb_define_method(cGzipReader, "each", rb_gzreader_each, -1);
     rb_define_method(cGzipReader, "each_line", rb_gzreader_each, -1);
+    rb_define_method(cGzipReader, "lines", rb_gzreader_each, -1);
     rb_define_method(cGzipReader, "readlines", rb_gzreader_readlines, -1);
 
     rb_define_const(mZlib, "OS_CODE", INT2FIX(OS_CODE));

Modified: MacRuby/trunk/file.c
===================================================================
--- MacRuby/trunk/file.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/file.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -14,6 +14,10 @@
 #ifdef _WIN32
 #include "missing/file.h"
 #endif
+#ifdef __CYGWIN__
+#include <windows.h>
+#include <sys/cygwin.h>
+#endif
 
 #include "ruby/ruby.h"
 #include "ruby/io.h"
@@ -944,8 +948,8 @@
 
     return -1;
 #else
-# if _MSC_VER >= 1400
-    mode &= 6;
+# if defined(_MSC_VER) || defined(__MINGW32__)
+    mode &= ~1;
 # endif
     return access(path, mode);
 #endif
@@ -2390,10 +2394,24 @@
 
 #if defined DOSISH
 #define DOSISH_UNC
+#define DOSISH_DRIVE_LETTER
 #define isdirsep(x) ((x) == '/' || (x) == '\\')
 #else
 #define isdirsep(x) ((x) == '/')
 #endif
+
+#if defined _WIN32 || defined __CYGWIN__
+#define USE_NTFS 1
+#else
+#define USE_NTFS 0
+#endif
+
+#if USE_NTFS
+#define istrailinggabage(x) ((x) == '.' || (x) == ' ')
+#else
+#define istrailinggabage(x) 0
+#endif
+
 #ifndef CharNext		/* defined as CharNext[AW] on Windows. */
 # if defined(DJGPP)
 #   define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
@@ -2402,12 +2420,6 @@
 # endif
 #endif
 
-#ifdef __CYGWIN__
-#undef DOSISH
-#define DOSISH_UNC
-#define DOSISH_DRIVE_LETTER
-#endif
-
 #ifdef DOSISH_DRIVE_LETTER
 static inline int
 has_drive_letter(const char *buf)
@@ -2536,6 +2548,30 @@
     return chompdirsep(path);
 }
 
+#if USE_NTFS
+static char *
+ntfs_tail(const char *path)
+{
+    while (*path && *path != ':') {
+	if (istrailinggabage(*path)) {
+	    const char *last = path++;
+	    while (istrailinggabage(*path)) path++;
+	    if (!*path || *path == ':') return (char *)last;
+	}
+	else if (isdirsep(*path)) {
+	    const char *last = path++;
+	    while (isdirsep(*path)) path++;
+	    if (!*path) return (char *)last;
+	    if (*path == ':') path++;
+	}
+	else {
+	    path = CharNext(path);
+	}
+    }
+    return (char *)path;
+}
+#endif
+
 #define BUFCHECK(cond) do {\
     long bdiff = p - buf;\
     while (cond) {\
@@ -2552,18 +2588,27 @@
     buflen = RSTRING_LEN(result),\
     pend = p + buflen)
 
+#if WITH_OBJC
+# define SET_EXTERNAL_ENCODING()
+#else
+# define SET_EXTERNAL_ENCODING() (\
+    (void)(extenc || (extenc = rb_default_external_encoding())),\
+    rb_enc_associate(result, extenc))
+#endif
+
 static int is_absolute_path(const char*);
 
 static VALUE
 file_expand_path(VALUE fname, VALUE dname, VALUE result)
 {
-    char *s, *buf, *b, *p, *pend, *root;
+    const char *s, *b;
+    char *buf, *p, *pend, *root;
     long buflen, dirlen;
     int tainted;
+    rb_encoding *extenc = 0;
 
     FilePathValue(fname);
     s = StringValuePtr(fname);
-
     BUFINIT();
     tainted = OBJ_TAINTED(fname);
 
@@ -2588,6 +2633,7 @@
 #endif
 	    s++;
 	    tainted = 1;
+	    SET_EXTERNAL_ENCODING();
 	}
 	else {
 #ifdef HAVE_PWD_H
@@ -2643,6 +2689,7 @@
 		BUFCHECK(dirlen > buflen);
 		strcpy(buf, dir);
 		free(dir);
+		SET_EXTERNAL_ENCODING();
 	    }
 	    p = chompdirsep(skiproot(buf));
 	    s += 2;
@@ -2654,8 +2701,10 @@
 	    long n;
 	    file_expand_path(dname, Qnil, result);
 	    BUFINIT();
+#if WITH_OBJC
 	    n = RSTRING_CLEN(result);
 	    BUFCHECK(n + 2 > buflen);
+#endif
 	}
 	else {
 	    char *dir = my_getcwd();
@@ -2665,6 +2714,7 @@
 	    BUFCHECK(dirlen > buflen);
 	    strcpy(buf, dir);
 	    xfree(dir);
+	    SET_EXTERNAL_ENCODING();
 	}
 #if defined DOSISH || defined __CYGWIN__
 	if (isdirsep(*s)) {
@@ -2703,15 +2753,21 @@
 		  case '.':
 		    if (*(s+1) == '\0' || isdirsep(*(s+1))) {
 			/* We must go back to the parent */
+			char *n;
 			*p = '\0';
-			if (!(b = strrdirsep(root))) {
+			if (!(n = strrdirsep(root))) {
 			    *p = '/';
 			}
 			else {
-			    p = b;
+			    p = n;
 			}
 			b = ++s;
 		    }
+#if USE_NTFS
+		    else {
+			do *++s; while (istrailinggabage(*s));
+		    }
+#endif
 		    break;
 		  case '/':
 #if defined DOSISH || defined __CYGWIN__
@@ -2724,6 +2780,19 @@
 		    break;
 		}
 	    }
+#if USE_NTFS
+	    else {
+		--s;
+	      case ' ': {
+		const char *e = s;
+		while (istrailinggabage(*s)) s++;
+		if (!*s) {
+		    s = e;
+		    goto endpath;
+		}
+	      }
+	    }
+#endif
 	    break;
 	  case '/':
 #if defined DOSISH || defined __CYGWIN__
@@ -2746,23 +2815,86 @@
     }
 
     if (s > b) {
+#if USE_NTFS
+      endpath:
+	if (s > b + 6 && strncasecmp(s - 6, ":$DATA", 6) == 0) {
+	    /* alias of stream */
+	    /* get rid of a bug of x64 VC++ */
+	    if (*(s-7) == ':') s -= 7;			/* prime */
+	    else if (memchr(b, ':', s - 6 - b)) s -= 6; /* alternative */
+	}
+#endif
 	BUFCHECK(bdiff + (s-b) >= buflen);
 	memcpy(++p, b, s-b);
 	p += s-b;
     }
     if (p == skiproot(buf) - 1) p++;
+    buflen = p - buf;
 
+#if USE_NTFS
+    *p = '\0';
+    if (!strpbrk(b = buf, "*?")) {
+	size_t len;
+	WIN32_FIND_DATA wfd;
+#ifdef __CYGWIN__
+	int lnk_added = 0;
+	struct stat st;
+	char w32buf[MAXPATHLEN], sep = 0;
+	p = 0;
+	if (lstat(buf, &st) == 0 && S_ISLNK(st.st_mode)) {
+	    p = strrdirsep(buf);
+	    if (!p) p = skipprefix(buf);
+	    if (p) {
+		sep = *p;
+		*p = '\0';
+	    }
+	}
+	if (cygwin_conv_to_win32_path(buf, w32buf) == 0) {
+	    b = w32buf;
+	}
+	if (p) *p = sep;
+	else p = buf;
+	if (b == w32buf) {
+	    strlcat(w32buf, p, sizeof(w32buf));
+	    len = strlen(p);
+	    if (len > 4 && STRCASECMP(p + len - 4, ".lnk") != 0) {
+		lnk_added = 1;
+		strlcat(w32buf, ".lnk", sizeof(w32buf));
+	    }
+	}
+#endif
+	HANDLE h = FindFirstFile(b, &wfd);
+	if (h != INVALID_HANDLE_VALUE) {
+	    FindClose(h);
+	    p = strrdirsep(buf);
+	    len = strlen(wfd.cFileName);
+#ifdef __CYGWIN__
+	    if (lnk_added && len > 4 &&
+		STRCASECMP(wfd.cFileName + len - 4, ".lnk") == 0) {
+		len -= 4;
+	    }
+#endif
+	    if (!p) p = buf;
+	    buflen = ++p - buf + len;
+	    rb_str_resize(result, buflen);
+	    memcpy(p, wfd.cFileName, len + 1);
+	}
+    }
+#endif
+
     if (tainted) OBJ_TAINT(result);
-    rb_str_set_len(result, p - buf);
+    rb_str_set_len(result, buflen);
+#if !WITH_OBJC
+    rb_enc_check(fname, result);
+#endif
     RSTRING_SYNC(result);
-
     return result;
 }
 
 VALUE
 rb_file_expand_path(VALUE fname, VALUE dname)
 {
-    return file_expand_path(fname, dname, rb_str_new(0, MAXPATHLEN + 2));
+    return file_expand_path(fname, dname, rb_usascii_str_new(0, MAXPATHLEN + 2));
 }
 
 /*
@@ -2796,22 +2928,29 @@
 }
 
 static int
-rmext(const char *p, const char *e)
+rmext(const char *p, int l1, const char *e)
 {
-    int l1, l2;
+    int l2;
 
     if (!e) return 0;
 
-    l1 = chompdirsep(p) - p;
     l2 = strlen(e);
     if (l2 == 2 && e[1] == '*') {
-	e = strrchr(p, *e);
-	if (!e) return 0;
+	unsigned char c = *e;
+	e = p + l1;
+	do {
+	    if (e <= p) return 0;
+	} while (*--e != c);
 	return e - p;
     }
     if (l1 < l2) return l1;
 
-    if (strncmp(p+l1-l2, e, l2) == 0) {
+#if CASEFOLD_FILESYSTEM
+#define fncomp strncasecmp
+#else
+#define fncomp strncmp
+#endif
+    if (fncomp(p+l1-l2, e, l2) == 0) {
 	return l1-l2;
     }
     return 0;
@@ -2839,7 +2978,7 @@
 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
     char *root;
 #endif
-    int f;
+    int f, n;
 
     if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
 	StringValue(fext);
@@ -2873,20 +3012,27 @@
 #endif
 #endif
     }
-    else if (!(p = strrdirsep(name))) {
-	if (NIL_P(fext) || !(f = rmext(name, StringValueCStr(fext)))) {
-	    f = chompdirsep(name) - name;
-	    if (f == RSTRING_CLEN(fname)) return fname;
-	}
-	p = name;
-    }
     else {
-	while (isdirsep(*p)) p++; /* skip last / */
-	if (NIL_P(fext) || !(f = rmext(p, StringValueCStr(fext)))) {
-	    f = chompdirsep(p) - p;
+	if (!(p = strrdirsep(name))) {
+	    p = name;
 	}
+	else {
+	    while (isdirsep(*p)) p++; /* skip last / */
+	}
+#if USE_NTFS
+	n = ntfs_tail(p) - p;
+#else
+	n = chompdirsep(p) - p;
+#endif
+	if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) {
+	    f = n;
+	}
+	if (f == RSTRING_CLEN(fname)) return fname;
     }
     basename = rb_str_new(p, f);
+#if !WITH_OBJC
+    rb_enc_copy(basename, fname);
+#endif
     OBJ_INFECT(basename, fname);
     return basename;
 }
@@ -2938,6 +3084,9 @@
     if (has_drive_letter(name) && root == name + 2 && p - name == 2)
 	rb_str_cat(dirname, ".", 1);
 #endif
+#if !WITH_OBJC
+    rb_enc_copy(dirname, fname);
+#endif
     OBJ_INFECT(dirname, fname);
     return dirname;
 }
@@ -2959,21 +3108,51 @@
 static VALUE
 rb_file_s_extname(VALUE klass, VALUE fname)
 {
-    char *name, *p, *e;
+    const char *name, *p, *e;
     VALUE extname;
 
     FilePathStringValue(fname);
     name = StringValueCStr(fname);
     p = strrdirsep(name);	/* get the last path component */
     if (!p)
- 	p = name;
+	p = name;
     else
- 	p++;
- 
-    e = strrchr(p, '.');	/* get the last dot of the last component */
-    if (!e || e == p || !e[1])	/* no dot, or the only dot is first or end? */
+	p++;
+
+    e = 0;
+    while (*p) {
+	if (*p == '.' || istrailinggabage(*p)) {
+#if USE_NTFS
+	    const char *last = p++, *dot = last;
+	    while (istrailinggabage(*p)) {
+		if (*p == '.') dot = p;
+		p++;
+	    }
+	    if (!*p || *p == ':') {
+		p = last;
+		break;
+	    }
+	    e = dot;
+	    continue;
+#else
+	    e = p;	  /* get the last dot of the last component */
+#endif
+	}
+#if USE_NTFS
+	else if (*p == ':') {
+	    break;
+	}
+#endif
+	else if (isdirsep(*p))
+	    break;
+	p = CharNext(p);
+    }
+    if (!e || e+1 == p)	/* no dot, or the only dot is first or end? */
 	return rb_str_new(0, 0);
-    extname = rb_str_new(e, chompdirsep(e) - e);	/* keep the dot, too! */
+    extname = rb_str_new(e, p - e);	/* keep the dot, too! */
+#if !WITH_OBJC
+    rb_enc_copy(extname, fname);
+#endif
     OBJ_INFECT(extname, fname);
     return extname;
 }
@@ -3294,7 +3473,7 @@
 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
 	  case EWOULDBLOCK:
 #endif
-	    if (op1 & LOCK_NB) goto exit;
+	    if (op1 & LOCK_NB) return Qfalse;
 	    rb_thread_polling();
 	    rb_io_check_closed(fptr);
 	    continue;
@@ -3309,7 +3488,6 @@
 	    rb_sys_fail(fptr->path);
 	}
     }
-  exit:
 #endif
     return INT2FIX(0);
 }
@@ -4302,14 +4480,14 @@
     return eaccess(path, R_OK) == 0;
 }
 
-extern VALUE rb_load_path;
+VALUE rb_get_load_path(void);
 
 int
 rb_find_file_ext(VALUE *filep, const char *const *ext)
 {
     const char *path, *found;
     const char *f = RSTRING_CPTR(*filep);
-    VALUE fname;
+    VALUE fname, load_path;
     long i, j;
 
     if (f[0] == '~') {
@@ -4335,35 +4513,38 @@
 	return 0;
     }
 
-    if (!rb_load_path) return 0;
+    load_path = rb_get_load_path();
+    if (!load_path) return 0;
 
-    Check_Type(rb_load_path, T_ARRAY);
     for (j=0; ext[j]; j++) {
 	fname = rb_str_dup(*filep);
 	rb_str_cat2(fname, ext[j]);
 	OBJ_FREEZE(fname);
-	for (i=0;i<RARRAY_LEN(rb_load_path);i++) {
-	    VALUE str = RARRAY_AT(rb_load_path, i);
+	for (i = 0; i < RARRAY_LEN(load_path); i++) {
+	    VALUE str = RARRAY_AT(load_path, i);
+	    char fbuf[MAXPATHLEN];
 
 	    FilePathValue(str);
 	    if (RSTRING_CLEN(str) == 0) continue;
 	    path = RSTRING_CPTR(str);
-	    found = dln_find_file(StringValueCStr(fname), path);
+	    found = dln_find_file_r(StringValueCStr(fname), path, fbuf, sizeof(fbuf));
 	    if (found && file_load_ok(found)) {
 		*filep = rb_str_new2(found);
 		return j+1;
 	    }
 	}
     }
+    RB_GC_GUARD(load_path);
     return 0;
 }
 
 VALUE
 rb_find_file(VALUE path)
 {
-    VALUE tmp;
+    VALUE tmp, load_path;
     char *f = StringValueCStr(path);
     const char *lpath;
+    char fbuf[MAXPATHLEN];
 
     if (f[0] == '~') {
 	path = rb_file_expand_path(path, Qnil);
@@ -4394,13 +4575,13 @@
 	rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
     }
 
-    if (rb_load_path) {
+    load_path = rb_get_load_path();
+    if (load_path) {
 	long i, count;
 
-	Check_Type(rb_load_path, T_ARRAY);
 	tmp = rb_ary_new();
-	for (i=0, count=RARRAY_LEN(rb_load_path);i < count;i++) {
-	    VALUE str = RARRAY_AT(rb_load_path, i);
+	for (i=0, count=RARRAY_LEN(load_path);i < count;i++) {
+	    VALUE str = RARRAY_AT(load_path, i);
 	    FilePathValue(str);
 	    if (RSTRING_CLEN(str) > 0) {
 		rb_ary_push(tmp, str);
@@ -4421,7 +4602,7 @@
     if (!lpath) {
 	return 0;		/* no path, no load */
     }
-    if (!(f = dln_find_file(f, lpath))) {
+    if (!(f = dln_find_file_r(f, lpath, fbuf, sizeof(fbuf)))) {
 	return 0;
     }
     if (rb_safe_level() >= 1 && !fpath_check(f)) {

Modified: MacRuby/trunk/gc.c
===================================================================
--- MacRuby/trunk/gc.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/gc.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -17,6 +17,8 @@
 #include "ruby/node.h"
 #include "ruby/re.h"
 #include "ruby/io.h"
+#include "ruby/util.h"
+#include "eval_intern.h"
 #include "vm_core.h"
 #include "gc.h"
 #include <stdio.h>
@@ -113,9 +115,8 @@
 
 int rb_io_fptr_finalize(struct rb_io_t*);
 
-#if !defined(setjmp) && defined(HAVE__SETJMP) && !defined(sigsetjmp) && !defined(HAVE_SIGSETJMP)
-#define setjmp(env) _setjmp(env)
-#endif
+#define rb_setjmp(env) RUBY_SETJMP(env)
+#define rb_jmp_buf rb_jmpbuf_t
 
 /* Make alloca work the best possible way.  */
 #ifdef __GNUC__
@@ -146,24 +147,16 @@
 #endif
 #endif
 
-static unsigned long malloc_increase = 0;
-static unsigned long malloc_limit = GC_MALLOC_LIMIT;
 static VALUE nomem_error;
 
-static int dont_gc = 0;
-static int during_gc;
-static int need_call_final = 0;
-static st_table *finalizer_table = 0;
-
 #define MARK_STACK_MAX 1024
-static VALUE mark_stack[MARK_STACK_MAX];
-static VALUE *mark_stack_ptr;
-static int mark_stack_overflow;
 
 int ruby_gc_debug_indent = 0;
 
 #undef GC_DEBUG
 
+#if !WITH_OBJC
+
 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
 #pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
 #endif
@@ -171,7 +164,6 @@
 typedef struct RVALUE {
     union {
 	struct {
-	    void *isa;			/* always NULL for freed obj */
 	    VALUE flags;		/* always 0 for freed obj */
 	    struct RVALUE *next;
 	} free;
@@ -179,18 +171,18 @@
 	struct RObject object;
 	struct RClass  klass;
 	struct RFloat  flonum;
-	struct RRegexp regexp;
-#if !WITH_OBJC
 	struct RString string;
 	struct RArray  array;
+	struct RRegexp regexp;
 	struct RHash   hash;
-#endif
 	struct RData   data;
 	struct RStruct rstruct;
 	struct RBignum bignum;
 	struct RFile   file;
 	struct RNode   node;
 	struct RMatch  match;
+	struct RRational rational;
+	struct RComplex complex;
     } as;
 #ifdef GC_DEBUG
     char *file;
@@ -198,40 +190,118 @@
 #endif
 } RVALUE;
 
-#define RANY(o) ((RVALUE*)(o))
-
 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
 #pragma pack(pop)
 #endif
 
-static RVALUE *freelist = 0;
-static RVALUE *deferred_final_list = 0;
-
-#define HEAPS_INCREMENT 10
-static struct heaps_slot {
+struct heaps_slot {
     void *membase;
     RVALUE *slot;
     int limit;
-} *heaps;
-static int heaps_length = 0;
-static int heaps_used   = 0;
+};
 
 #define HEAP_MIN_SLOTS 10000
-static int heap_slots = HEAP_MIN_SLOTS;
+#define FREE_MIN  4096
 
+struct gc_list {
+    VALUE *varptr;
+    struct gc_list *next;
+};
+
+typedef struct rb_objspace {
+    struct {
+	size_t limit;
+	size_t increase;
+    } params;
+    struct {
+	size_t increment;
+	struct heaps_slot *ptr;
+	size_t length;
+	size_t used;
+	RVALUE *freelist;
+	RVALUE *range[2];
+	RVALUE *freed;
+    } heap;
+    struct {
+	int dont_gc;
+	int during_gc;
+    } flags;
+    struct {
+	int need_call;
+	st_table *table;
+	RVALUE *deferred;
+    } final;
+    struct {
+	VALUE buffer[MARK_STACK_MAX];
+	VALUE *ptr;
+	int overflow;
+    } markstack;
+    struct gc_list *global_list;
+    unsigned int count;
+} rb_objspace_t;
+
+#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
+#define rb_objspace (*GET_VM()->objspace)
+#else
+static rb_objspace_t rb_objspace = {{GC_MALLOC_LIMIT}, {HEAP_MIN_SLOTS}};
+#endif
+#define malloc_limit		objspace->params.limit
+#define malloc_increase 	objspace->params.increase
+#define heap_slots		objspace->heap.slots
+#define heaps			objspace->heap.ptr
+#define heaps_length		objspace->heap.length
+#define heaps_used		objspace->heap.used
+#define freelist		objspace->heap.freelist
+#define lomem			objspace->heap.range[0]
+#define himem			objspace->heap.range[1]
+#define heaps_inc		objspace->heap.increment
+#define heaps_freed		objspace->heap.freed
+#define dont_gc 		objspace->flags.dont_gc
+#define during_gc		objspace->flags.during_gc
+#define need_call_final 	objspace->final.need_call
+#define finalizer_table 	objspace->final.table
+#define deferred_final_list	objspace->final.deferred
+#define mark_stack		objspace->markstack.buffer
+#define mark_stack_ptr		objspace->markstack.ptr
+#define mark_stack_overflow	objspace->markstack.overflow
+#define global_List		objspace->global_list
+
+rb_objspace_t *
+rb_objspace_alloc(void)
+{
+    rb_objspace_t *objspace = malloc(sizeof(rb_objspace_t));
+    memset(objspace, 0, sizeof(*objspace));
+    malloc_limit = GC_MALLOC_LIMIT;
+
+    return objspace;
+}
+
+/* tiny heap size */
+/* 32KB */
+/*#define HEAP_SIZE 0x8000 */
+/* 128KB */
+/*#define HEAP_SIZE 0x20000 */
+/* 64KB */
+/*#define HEAP_SIZE 0x10000 */
+/* 16KB */
+#define HEAP_SIZE 0x4000
+/* 8KB */
+/*#define HEAP_SIZE 0x2000 */
+/* 4KB */
+/*#define HEAP_SIZE 0x1000 */
+/* 2KB */
+/*#define HEAP_SIZE 0x800 */
+
+#define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE))
 #define FREE_MIN  4096
 
-static RVALUE *himem, *lomem;
-
 extern st_table *rb_class_tbl;
 VALUE *rb_gc_stack_start = 0;
 #ifdef __ia64
 VALUE *rb_gc_register_stack_start = 0;
 #endif
 
-int ruby_gc_stress = 0;
 
-
 #ifdef DJGPP
 /* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */
 unsigned int _stklen = 0x180000; /* 1.5 kB */
@@ -243,11 +313,23 @@
 size_t rb_gc_stack_maxsize = 655300*sizeof(VALUE);
 #endif
 
+static void run_final(rb_objspace_t *objspace, VALUE obj);
+static int garbage_collect(rb_objspace_t *objspace);
 
+#else
 
-static void run_final(VALUE obj);
-static int garbage_collect(void);
+int ruby_gc_stress = 0;
+static long malloc_increase = 0;
+bool dont_gc = false;
+#define malloc_limit GC_MALLOC_LIMIT
+VALUE *rb_gc_stack_start = 0;
+#ifdef __ia64
+VALUE *rb_gc_register_stack_start = 0;
+#endif
+size_t rb_gc_stack_maxsize = 655300*sizeof(VALUE);
 
+#endif
+
 void
 rb_global_variable(VALUE *var)
 {
@@ -257,12 +339,13 @@
 void
 rb_memerror(void)
 {
-  static int recurse = 0;
-    if (!nomem_error || (recurse > 0 && rb_safe_level() < 4)) {
+    rb_thread_t *th = GET_THREAD();
+    if (!nomem_error ||
+	(rb_thread_raised_p(th, RAISED_NOMEMORY) && rb_safe_level() < 4)) {
 	fprintf(stderr, "[FATAL] failed to allocate memory\n");
 	exit(1);
     }
-    recurse++;
+    rb_thread_raised_set(th, RAISED_NOMEMORY);
     rb_exc_raise(nomem_error);
 }
 
@@ -299,6 +382,8 @@
     return flag;
 }
 
+static int garbage_collect(void);
+
 void
 rb_gc_malloc_increase(size_t size)
 {
@@ -307,6 +392,8 @@
 	garbage_collect();
 }
 
+#if WITH_OBJC
+
 void *
 ruby_xmalloc(size_t size)
 {
@@ -317,7 +404,7 @@
     }
     if (size == 0) size = 1;
     rb_gc_malloc_increase(size);
-#if WITH_OBJC
+    
     if (__auto_zone == NULL) {
     	fprintf(stderr,
 		"The client that links against MacRuby was not built for "\
@@ -325,51 +412,139 @@
 		"try again.\n");
 	exit(1);
     }
-    RUBY_CRITICAL(mem = auto_zone_allocate_object(__auto_zone, size, 
-						  AUTO_MEMORY_SCANNED, 0, 0));
+    mem = auto_zone_allocate_object(__auto_zone, size, 
+				    AUTO_MEMORY_SCANNED, 0, 0);
     xmalloc_count++;
     if (!mem) {
 	rb_memerror();
     }
+
+    return mem;
+}
+
+void *
+ruby_xmalloc2(size_t n, size_t size)
+{
+    size_t len = size * n;
+    if (n != 0 && size != len / n) {
+	rb_raise(rb_eArgError, "malloc: possible integer overflow");
+    }
+    return ruby_xmalloc(len);
+}
+
+void *
+ruby_xcalloc(size_t n, size_t size)
+{
+    void *mem;
+
+    mem = ruby_xmalloc2(n, size);
+    memset(mem, 0, n * size);
+
+    return mem;
+}
+
+
+void *
+ruby_xrealloc(void *ptr, size_t size)
+{
+    void *mem;
+
+    if (size < 0)
+	rb_raise(rb_eArgError, "negative re-allocation size");
+    
+    if (ptr == NULL) 
+	return ruby_xmalloc(size);
+    
+    if (size == 0) 
+	size = 1;
+    
+    rb_gc_malloc_increase(size);
+    if (ruby_gc_stress) 
+	garbage_collect();
+    mem = malloc_zone_realloc(__auto_zone, ptr, size);
+    if (mem == NULL)
+	rb_memerror();
+
+    return mem;
+}
+
+void *
+ruby_xrealloc2(void *ptr, size_t n, size_t size)
+{
+    size_t len = size * n;
+    if (n != 0 && size != len / n) {
+	rb_raise(rb_eArgError, "realloc: possible integer overflow");
+    }
+    return ruby_xrealloc(ptr, len);
+}
+
 #else
+
+void *
+ruby_vm_xmalloc(rb_objspace_t *objspace, size_t size)
+{
+    void *mem;
+
+    if (size < 0) {
+	rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
+    }
+    if (size == 0) size = 1;
+    rb_gc_malloc_increase(size);
     RUBY_CRITICAL(mem = malloc(size));
     if (!mem) {
-	if (garbage_collect()) {
+	if (garbage_collect(objspace)) {
 	    RUBY_CRITICAL(mem = malloc(size));
 	}
 	if (!mem) {
 	    rb_memerror();
 	}
     }
-#endif
 
     return mem;
 }
 
 void *
-ruby_xmalloc2(size_t n, size_t size)
+ruby_xmalloc(size_t size)
 {
-    long len = size * n;
+    return ruby_vm_xmalloc(&rb_objspace, size);
+}
+
+void *
+ruby_vm_xmalloc2(rb_objspace_t *objspace, size_t n, size_t size)
+{
+    size_t len = size * n;
     if (n != 0 && size != len / n) {
 	rb_raise(rb_eArgError, "malloc: possible integer overflow");
     }
-    return ruby_xmalloc(len);
+    return ruby_vm_xmalloc(objspace, len);
 }
 
 void *
-ruby_xcalloc(size_t n, size_t size)
+ruby_xmalloc2(size_t n, size_t size)
 {
+    return ruby_vm_xmalloc2(&rb_objspace, n, size);
+}
+
+void *
+ruby_vm_xcalloc(rb_objspace_t *objspace, size_t n, size_t size)
+{
     void *mem;
 
-    mem = ruby_xmalloc2(n, size);
+    mem = ruby_vm_xmalloc2(objspace, n, size);
     memset(mem, 0, n * size);
 
     return mem;
 }
 
 void *
-ruby_xrealloc(void *ptr, size_t size)
+ruby_xcalloc(size_t n, size_t size)
 {
+    return ruby_vm_xcalloc(&rb_objspace, n, size);
+}
+
+void *
+ruby_vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
+{
     void *mem;
 
     if (size < 0) {
@@ -379,36 +554,43 @@
     if (size == 0) size = 1;
     malloc_increase += size;
     if (ruby_gc_stress) garbage_collect();
-#if WITH_OBJC
-    RUBY_CRITICAL(mem = malloc_zone_realloc(__auto_zone, ptr, size));
-    if (!mem) {
-	rb_memerror();
-    }
-#else
     RUBY_CRITICAL(mem = realloc(ptr, size));
     if (!mem) {
-	if (garbage_collect()) {
+	if (garbage_collect(objspace)) {
 	    RUBY_CRITICAL(mem = realloc(ptr, size));
 	}
 	if (!mem) {
 	    rb_memerror();
         }
     }
-#endif
 
     return mem;
 }
 
 void *
-ruby_xrealloc2(void *ptr, size_t n, size_t size)
+ruby_xrealloc(void *ptr, size_t size)
 {
+    return ruby_vm_xrealloc(&rb_objspace, ptr, size);
+}
+
+void *
+ruby_vm_xrealloc2(rb_objspace_t *objspace, void *ptr, size_t n, size_t size)
+{
     size_t len = size * n;
     if (n != 0 && size != len / n) {
 	rb_raise(rb_eArgError, "realloc: possible integer overflow");
     }
-    return ruby_xrealloc(ptr, len);
+    return ruby_vm_xrealloc(objspace, ptr, len);
 }
 
+void *
+ruby_xrealloc2(void *ptr, size_t n, size_t size)
+{
+    return ruby_vm_xrealloc2(&rb_objspace, ptr, n, size);
+}
+
+#endif
+
 void
 ruby_xfree(void *x)
 {
@@ -423,6 +605,7 @@
 #endif
 }
 
+
 /*
  *  call-seq:
  *     GC.enable    => true or false
@@ -475,14 +658,11 @@
 VALUE rb_mGC;
 
 #if !WITH_OBJC
-static struct gc_list {
-    VALUE *varptr;
-    struct gc_list *next;
-} *global_List = 0;
 
 void
 rb_gc_register_address(VALUE *addr)
 {
+    rb_objspace_t *objspace = &rb_objspace;
     struct gc_list *tmp;
 
     tmp = ALLOC(struct gc_list);
@@ -501,6 +681,7 @@
 void
 rb_gc_unregister_address(VALUE *addr)
 {
+    rb_objspace_t *objspace = &rb_objspace;
     struct gc_list *tmp = global_List;
 
     if (tmp->varptr == addr) {
@@ -520,55 +701,76 @@
     }
 }
 
+
 static void
-add_heap(void)
+allocate_heaps(rb_objspace_t *objspace, size_t next_heaps_length)
 {
-    RVALUE *p, *pend;
+    struct heaps_slot *p;
+    size_t size;
 
-    if (heaps_used == heaps_length) {
-	/* Realloc heaps */
-	struct heaps_slot *p;
-	int length;
+    size = next_heaps_length*sizeof(struct heaps_slot);
+    RUBY_CRITICAL(
+		  if (heaps_used > 0) {
+		      p = (struct heaps_slot *)realloc(heaps, size);
+		      if (p) heaps = p;
+		  }
+		  else {
+		      p = heaps = (struct heaps_slot *)malloc(size);
+		  }
+		  );
+    if (p == 0) rb_memerror();
+    heaps_length = next_heaps_length;
+}
 
-	heaps_length += HEAPS_INCREMENT;
-	length = heaps_length*sizeof(struct heaps_slot);
-	RUBY_CRITICAL(
-	    if (heaps_used > 0) {
-		p = (struct heaps_slot *)realloc(heaps, length);
-		if (p) heaps = p;
-	    }
-	    else {
-		p = heaps = (struct heaps_slot *)malloc(length);
-	    });
-	if (p == 0) rb_memerror();
+static void
+assign_heap_slot(rb_objspace_t *objspace)
+{
+    RVALUE *p, *pend, *membase;
+    size_t hi, lo, mid;
+    int objs;
+	
+    objs = HEAP_OBJ_LIMIT;
+    RUBY_CRITICAL(p = (RVALUE*)malloc(HEAP_SIZE));
+    if (p == 0)
+	rb_memerror();
+
+    membase = p;
+    if ((VALUE)p % sizeof(RVALUE) != 0) {
+	p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
+	if ((HEAP_SIZE - HEAP_OBJ_LIMIT * sizeof(RVALUE)) < ((char*)p - (char*)membase)) {
+	    objs--;
+	}
     }
+    	
 
-    for (;;) {
-	RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
-	if (p == 0) {
-	    if (heap_slots == HEAP_MIN_SLOTS) {
-		rb_memerror();
-	    }
-	    heap_slots = HEAP_MIN_SLOTS;
-	    continue;
+    lo = 0;
+    hi = heaps_used;
+    while (lo < hi) {
+	register RVALUE *mid_membase;
+	mid = (lo + hi) / 2;
+	mid_membase = heaps[mid].membase;
+	if (mid_membase < membase) {
+	    lo = mid + 1;
 	}
-	heaps[heaps_used].membase = p;
-	if ((VALUE)p % sizeof(RVALUE) == 0)
-	    heap_slots += 1;
-	else
-	    p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
-	heaps[heaps_used].slot = p;
-	heaps[heaps_used].limit = heap_slots;
-	break;
+	else if (mid_membase > membase) {
+	    hi = mid;
+	}
+	else {
+	    rb_bug("same heap slot is allocated: %p at %ld", membase, mid);
+	}
     }
-    pend = p + heap_slots;
+    if (hi < heaps_used) {
+	MEMMOVE(&heaps[hi+1], &heaps[hi], struct heaps_slot, heaps_used - hi);
+    }
+    heaps[hi].membase = membase;
+    heaps[hi].slot = p;
+    heaps[hi].limit = objs;
+    pend = p + objs;
     if (lomem == 0 || lomem > p) lomem = p;
     if (himem < pend) himem = pend;
     heaps_used++;
-    heap_slots *= 1.8;
 
     while (p < pend) {
-	p->as.free.isa = NULL;
 	p->as.free.flags = 0;
 	p->as.free.next = freelist;
 	freelist = p;
@@ -576,13 +778,55 @@
     }
 }
 
+static void
+init_heap(rb_objspace_t *objspace)
+{
+    size_t add, i;
+
+    add = HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT;
+
+    if ((heaps_used + add) > heaps_length) {
+    	allocate_heaps(objspace, heaps_used + add);
+    }
+
+    for (i = 0; i < add; i++) {
+    	assign_heap_slot(objspace);
+    }
+    heaps_inc = 0;
+}
+
+
+static void
+set_heaps_increment(rb_objspace_t *objspace)
+{
+    size_t next_heaps_length = heaps_used * 1.8;
+    heaps_inc = next_heaps_length - heaps_used;
+
+    if (next_heaps_length > heaps_length) {
+	allocate_heaps(objspace, next_heaps_length);
+    }
+}
+
+static int
+heaps_increment(rb_objspace_t *objspace)
+{
+    if (heaps_inc > 0) {
+	assign_heap_slot(objspace);
+	heaps_inc--;
+	return Qtrue;
+    }
+    return Qfalse;
+}
+
+#define RANY(o) ((RVALUE*)(o))
+
 static VALUE
-rb_newobj_from_heap(void)
+rb_newobj_from_heap(rb_objspace_t *objspace)
 {
     VALUE obj;
-
+	
     if (ruby_gc_stress || !freelist) {
-	if(!garbage_collect()) {
+    	if (!heaps_increment(objspace) && !garbage_collect(objspace)) {
 	    rb_memerror();
 	}
     }
@@ -595,6 +839,7 @@
     RANY(obj)->file = rb_sourcefile();
     RANY(obj)->line = rb_sourceline();
 #endif
+
     return obj;
 }
 
@@ -602,18 +847,19 @@
 static VALUE
 rb_fill_value_cache(rb_thread_t *th)
 {
+    rb_objspace_t *objspace = &rb_objspace;
     int i;
     VALUE rv;
 
     /* LOCK */
     for (i=0; i<RUBY_VM_VALUE_CACHE_SIZE; i++) {
-	VALUE v = rb_newobj_from_heap();
-	
+	VALUE v = rb_newobj_from_heap(objspace);
+
 	th->value_cache[i] = v;
 	RBASIC(v)->flags = FL_MARK;
     }
     th->value_cache_ptr = &th->value_cache[0];
-    rv = rb_newobj_from_heap();
+    rv = rb_newobj_from_heap(objspace);
     /* UNLOCK */
     return rv;
 }
@@ -625,9 +871,13 @@
 #if USE_VALUE_CACHE
     rb_thread_t *th = GET_THREAD();
     VALUE v = *th->value_cache_ptr;
+#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
+    rb_objspace_t *objspace = th->vm->objspace;
+#else
+    rb_objspace_t *objspace = &rb_objspace;
+#endif
 
     if (v) {
-	RBASIC(v)->isa = NULL;
 	RBASIC(v)->flags = 0;
 	th->value_cache_ptr++;
     }
@@ -641,7 +891,8 @@
 #endif
     return v;
 #else
-    return rb_newobj_from_heap();
+    rb_objspace_t *objspace = &rb_objspace;
+    return rb_newobj_from_heap(objspace);
 #endif
 }
 
@@ -830,6 +1081,7 @@
 # define STACK_LENGTH  ((STACK_END < STACK_START) ? STACK_START - STACK_END\
                                            : STACK_END - STACK_START + 1)
 #endif
+
 #if STACK_GROW_DIRECTION > 0
 # define STACK_UPPER(x, a, b) a
 #elif STACK_GROW_DIRECTION < 0
@@ -839,11 +1091,11 @@
 static int
 stack_grow_direction(VALUE *addr)
 {
-  rb_thread_t *th = GET_THREAD();
-  SET_STACK_END;
+    rb_thread_t *th = GET_THREAD();
+    SET_STACK_END;
 
-  if (STACK_END > addr) return grow_direction = 1;
-  return grow_direction = -1;
+    if (STACK_END > addr) return grow_direction = 1;
+    return grow_direction = -1;
 }
 # define stack_growup_p(x) ((grow_direction ? grow_direction : stack_grow_direction(x)) > 0)
 # define STACK_UPPER(x, a, b) (stack_growup_p(x) ? a : b)
@@ -854,10 +1106,10 @@
 int
 ruby_stack_length(VALUE **p)
 {
-  rb_thread_t *th = GET_THREAD();
-  SET_STACK_END;
-  if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
-  return STACK_LENGTH;
+    rb_thread_t *th = GET_THREAD();
+    SET_STACK_END;
+    if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
+    return STACK_LENGTH;
 }
 
 int
@@ -876,8 +1128,9 @@
     return ret;
 }
 
+#if !WITH_OBJC
 static void
-init_mark_stack(void)
+init_mark_stack(rb_objspace_t *objspace)
 {
     mark_stack_overflow = 0;
     mark_stack_ptr = mark_stack;
@@ -885,64 +1138,23 @@
 
 #define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack)
 
-static st_table *source_filenames;
 
-char *
-rb_source_filename(const char *f)
-{
-    st_data_t name;
+static void gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev);
+static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev);
 
-    if (!st_lookup(source_filenames, (st_data_t)f, &name)) {
-	long len = strlen(f) + 1;
-	char *ptr = ALLOC_N(char, len + 1);
-
-	name = (st_data_t)ptr;
-	*ptr++ = 0;
-	MEMCPY(ptr, f, char, len);
-	st_add_direct(source_filenames, (st_data_t)ptr, name);
-	return ptr;
-    }
-    return (char *)name + 1;
-}
-
-void
-rb_mark_source_filename(char *f)
-{
-    if (f) {
-	f[-1] = 1;
-    }
-}
-
-static int
-sweep_source_filename(char *key, char *value)
-{
-    if (*value) {
-	*value = 0;
-	return ST_CONTINUE;
-    }
-    else {
-	free(value);
-	return ST_DELETE;
-    }
-}
-
-#if !WITH_OBJC
-static void gc_mark(VALUE ptr, int lev);
-static void gc_mark_children(VALUE ptr, int lev);
-
 static void
-gc_mark_all(void)
+gc_mark_all(rb_objspace_t *objspace)
 {
     RVALUE *p, *pend;
-    int i;
+    size_t i;
 
-    init_mark_stack();
+    init_mark_stack(objspace);
     for (i = 0; i < heaps_used; i++) {
 	p = heaps[i].slot; pend = p + heaps[i].limit;
 	while (p < pend) {
 	    if ((p->as.basic.flags & FL_MARK) &&
 		(p->as.basic.flags != FL_MARK)) {
-		gc_mark_children((VALUE)p, 0);
+		gc_mark_children(objspace, (VALUE)p, 0);
 	    }
 	    p++;
 	}
@@ -950,7 +1162,7 @@
 }
 
 static void
-gc_mark_rest(void)
+gc_mark_rest(rb_objspace_t *objspace)
 {
     VALUE tmp_arry[MARK_STACK_MAX];
     VALUE *p;
@@ -958,134 +1170,168 @@
     p = (mark_stack_ptr - mark_stack) + tmp_arry;
     MEMCPY(tmp_arry, mark_stack, VALUE, p - tmp_arry);
 
-    init_mark_stack();
+    init_mark_stack(objspace);
     while (p != tmp_arry) {
 	p--;
-	gc_mark_children(*p, 0);
+	gc_mark_children(objspace, *p, 0);
     }
 }
 
 static inline int
-is_pointer_to_heap(void *ptr)
+is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
 {
     register RVALUE *p = RANY(ptr);
-    register RVALUE *heap_org;
-    register long i;
+    register struct heaps_slot *heap;
+    register size_t hi, lo, mid;
 
     if (p < lomem || p > himem) return Qfalse;
     if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse;
 
-    /* check if p looks like a pointer */
-    for (i=0; i < heaps_used; i++) {
-	heap_org = heaps[i].slot;
-	if (heap_org <= p && p < heap_org + heaps[i].limit)
-	    return Qtrue;
+    /* check if p looks like a pointer using bsearch*/
+    lo = 0;
+    hi = heaps_used;
+    while (lo < hi) {
+	mid = (lo + hi) / 2;
+	heap = &heaps[mid];
+	if (heap->slot <= p) {
+	    if (p < heap->slot + heap->limit)
+		return Qtrue;
+	    lo = mid + 1;
+	}
+	else {
+	    hi = mid;
+	}
     }
     return Qfalse;
 }
 
 static void
-mark_locations_array(register VALUE *x, register long n)
+mark_locations_array(rb_objspace_t *objspace, register VALUE *x, register long n)
 {
     VALUE v;
     while (n--) {
         v = *x;
         VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v));
-	if (is_pointer_to_heap((void *)v)) {
-	    gc_mark(v, 0);
+	if (is_pointer_to_heap(objspace, (void *)v)) {
+	    gc_mark(objspace, v, 0);
 	}
 	x++;
     }
 }
 
-void
-rb_gc_mark_locations(VALUE *start, VALUE *end)
+static void
+gc_mark_locations(rb_objspace_t *objspace, VALUE *start, VALUE *end)
 {
     long n;
 
+    if (end <= start) return;
     n = end - start;
-    mark_locations_array(start,n);
+    mark_locations_array(&rb_objspace, start,n);
 }
 
+void
+rb_gc_mark_locations(VALUE *start, VALUE *end)
+{
+    gc_mark_locations(&rb_objspace, start, end);
+}
+
+#define rb_gc_mark_locations(start, end) gc_mark_locations(objspace, start, end)
+
+struct mark_tbl_arg {
+    rb_objspace_t *objspace;
+    int lev;
+};
+
 static int
-mark_entry(ID key, VALUE value, int lev)
+mark_entry(ID key, VALUE value, st_data_t data)
 {
-    gc_mark(value, lev);
+    struct mark_tbl_arg *arg = (void*)data;
+    gc_mark(arg->objspace, value, arg->lev);
     return ST_CONTINUE;
 }
 
 static void
-mark_tbl(st_table *tbl, int lev)
+mark_tbl(rb_objspace_t *objspace, st_table *tbl, int lev)
 {
+    struct mark_tbl_arg arg;
     if (!tbl) return;
-    st_foreach(tbl, mark_entry, lev);
+    arg.objspace = objspace;
+    arg.lev = lev;
+    st_foreach(tbl, mark_entry, (st_data_t)&arg);
 }
 
 void
 rb_mark_tbl(st_table *tbl)
 {
-    mark_tbl(tbl, 0);
+    mark_tbl(&rb_objspace, tbl, 0);
 }
 
 static int
-mark_key(VALUE key, VALUE value, int lev)
+mark_key(VALUE key, VALUE value, st_data_t data)
 {
-    gc_mark(key, lev);
+    struct mark_tbl_arg *arg = (void*)data;
+    gc_mark(arg->objspace, key, arg->lev);
     return ST_CONTINUE;
 }
 
 static void
-mark_set(st_table *tbl, int lev)
+mark_set(rb_objspace_t *objspace, st_table *tbl, int lev)
 {
+    struct mark_tbl_arg arg;
     if (!tbl) return;
-    st_foreach(tbl, mark_key, lev);
+    arg.objspace = objspace;
+    arg.lev = lev;
+    st_foreach(tbl, mark_key, (st_data_t)&arg);
 }
 
 void
 rb_mark_set(st_table *tbl)
 {
-    mark_set(tbl, 0);
+    mark_set(&rb_objspace, tbl, 0);
 }
 
 static int
-mark_keyvalue(VALUE key, VALUE value, int lev)
+mark_keyvalue(VALUE key, VALUE value, st_data_t data)
 {
-    gc_mark(key, lev);
-    gc_mark(value, lev);
+    struct mark_tbl_arg *arg = (void*)data;
+    gc_mark(arg->objspace, key, arg->lev);
+    gc_mark(arg->objspace, value, arg->lev);
     return ST_CONTINUE;
 }
 
 static void
-mark_hash(st_table *tbl, int lev)
+mark_hash(rb_objspace_t *objspace, st_table *tbl, int lev)
 {
+    struct mark_tbl_arg arg;
     if (!tbl) return;
-    st_foreach(tbl, mark_keyvalue, lev);
+    arg.objspace = objspace;
+    arg.lev = lev;
+    st_foreach(tbl, mark_keyvalue, (st_data_t)&arg);
 }
 
 void
 rb_mark_hash(st_table *tbl)
 {
-    mark_hash(tbl, 0);
+    mark_hash(&rb_objspace, tbl, 0);
 }
 
 void
 rb_gc_mark_maybe(VALUE obj)
 {
-    if (is_pointer_to_heap((void *)obj)) {
-	gc_mark(obj, 0);
+    if (is_pointer_to_heap(&rb_objspace, (void *)obj)) {
+	gc_mark(&rb_objspace, obj, 0);
     }
 }
 
 #define GC_LEVEL_MAX 250
 
 static void
-gc_mark(VALUE ptr, int lev)
+gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev)
 {
     register RVALUE *obj;
 
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
-    if (obj->as.basic.isa != NULL && rb_objc_is_non_native(ptr)) return; /* objc object */
     if (obj->as.basic.flags == 0) return;       /* free cell */
     if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
     obj->as.basic.flags |= FL_MARK;
@@ -1094,7 +1340,7 @@
 	if (!mark_stack_overflow) {
 	    if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
 		*mark_stack_ptr = ptr;
-		mark_stack_ptr++;		
+		mark_stack_ptr++;
 	    }
 	    else {
 		mark_stack_overflow = 1;
@@ -1102,17 +1348,17 @@
 	}
 	return;
     }
-    gc_mark_children(ptr, lev+1);
+    gc_mark_children(objspace, ptr, lev+1);
 }
 
 void
 rb_gc_mark(VALUE ptr)
 {
-    gc_mark(ptr, 0);
+    gc_mark(&rb_objspace, ptr, 0);
 }
 
 static void
-gc_mark_children(VALUE ptr, int lev)
+gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
 {
     register RVALUE *obj = RANY(ptr);
 
@@ -1121,7 +1367,6 @@
   again:
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
-    if (obj->as.basic.isa != NULL && rb_objc_is_non_native(ptr)) return; /* objc object */
     if (obj->as.basic.flags == 0) return;       /* free cell */
     if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
     obj->as.basic.flags |= FL_MARK;
@@ -1138,7 +1383,6 @@
 	break;
 
       case T_NODE:
-	rb_mark_source_filename(obj->as.node.nd_file);
 	switch (nd_type(obj)) {
 	  case NODE_IF:		/* 1,2,3 */
 	  case NODE_FOR:
@@ -1149,7 +1393,7 @@
 	  case NODE_RESBODY:
 	  case NODE_CLASS:
 	  case NODE_BLOCK_PASS:
-	    gc_mark((VALUE)obj->as.node.u2.node, lev);
+	    gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev);
 	    /* fall through */
 	  case NODE_BLOCK:	/* 1,3 */
 	  case NODE_OPTBLOCK:
@@ -1163,7 +1407,7 @@
 	  case NODE_DEFS:
 	  case NODE_OP_ASGN1:
 	  case NODE_ARGS:
-	    gc_mark((VALUE)obj->as.node.u1.node, lev);
+	    gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
 	    /* fall through */
 	  case NODE_SUPER:	/* 3 */
 	  case NODE_FCALL:
@@ -1191,7 +1435,7 @@
 	  case NODE_ALIAS:
 	  case NODE_VALIAS:
 	  case NODE_ARGSCAT:
-	    gc_mark((VALUE)obj->as.node.u1.node, lev);
+	    gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
 	    /* fall through */
 	  case NODE_FBODY:	/* 2 */
 	  case NODE_GASGN:
@@ -1228,7 +1472,7 @@
 	  case NODE_SCOPE:	/* 2,3 */
 	  case NODE_CDECL:
 	  case NODE_OPT_ARG:
-	    gc_mark((VALUE)obj->as.node.u3.node, lev);
+	    gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev);
 	    ptr = (VALUE)obj->as.node.u2.node;
 	    goto again;
 
@@ -1254,32 +1498,33 @@
 	  case NODE_BLOCK_ARG:
 	    break;
 	  case NODE_ALLOCA:
-	    mark_locations_array((VALUE*)obj->as.node.u1.value,
+	    mark_locations_array(objspace,
+				 (VALUE*)obj->as.node.u1.value,
 				 obj->as.node.u3.cnt);
 	    ptr = (VALUE)obj->as.node.u2.node;
 	    goto again;
 
 	  default:		/* unlisted NODE */
-	    if (is_pointer_to_heap(obj->as.node.u1.node)) {
-		gc_mark((VALUE)obj->as.node.u1.node, lev);
+	    if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) {
+		gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
 	    }
-	    if (is_pointer_to_heap(obj->as.node.u2.node)) {
-		gc_mark((VALUE)obj->as.node.u2.node, lev);
+	    if (is_pointer_to_heap(objspace, obj->as.node.u2.node)) {
+		gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev);
 	    }
-	    if (is_pointer_to_heap(obj->as.node.u3.node)) {
-		gc_mark((VALUE)obj->as.node.u3.node, lev);
+	    if (is_pointer_to_heap(objspace, obj->as.node.u3.node)) {
+		gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev);
 	    }
 	}
 	return;			/* no need to mark class. */
     }
 
-    gc_mark(obj->as.basic.klass, lev);
+    gc_mark(objspace, obj->as.basic.klass, lev);
     switch (obj->as.basic.flags & T_MASK) {
       case T_ICLASS:
       case T_CLASS:
       case T_MODULE:
-	mark_tbl(RCLASS_M_TBL(obj), lev);
-	mark_tbl(RCLASS_IV_TBL(obj), lev);
+	mark_tbl(objspace, RCLASS_M_TBL(obj), lev);
+	mark_tbl(objspace, RCLASS_IV_TBL(obj), lev);
 	ptr = RCLASS_SUPER(obj);
 	goto again;
 
@@ -1290,21 +1535,15 @@
 	}
 	else {
 	    long i, len = RARRAY_LEN(obj);
-#if WITH_OBJC
-	    for (i = 0; i < len; i++) {
-		gc_mark(RARRAY_AT(obj, i), lev);
-	    }
-#else
 	    VALUE *ptr = RARRAY_PTR(obj);
 	    for (i=0; i < len; i++) {
-		gc_mark(*ptr++, lev);
+		gc_mark(objspace, *ptr++, lev);
 	    }
-#endif
 	}
 	break;
 
       case T_HASH:
-	mark_hash(obj->as.hash.ntbl, lev);
+	mark_hash(objspace, obj->as.hash.ntbl, lev);
 	ptr = obj->as.hash.ifnone;
 	goto again;
 
@@ -1325,37 +1564,46 @@
             long i, len = ROBJECT_NUMIV(obj);
 	    VALUE *ptr = ROBJECT_IVPTR(obj);
             for (i  = 0; i < len; i++) {
-		gc_mark(*ptr++, lev);
+		gc_mark(objspace, *ptr++, lev);
             }
         }
 	break;
 
       case T_FILE:
         if (obj->as.file.fptr)
-            gc_mark(obj->as.file.fptr->tied_io_for_writing, lev);
+            gc_mark(objspace, obj->as.file.fptr->tied_io_for_writing, lev);
         break;
 
       case T_REGEXP:
       case T_FLOAT:
       case T_BIGNUM:
-      case T_BLOCK:
 	break;
 
       case T_MATCH:
-	gc_mark(obj->as.match.regexp, lev);
+	gc_mark(objspace, obj->as.match.regexp, lev);
 	if (obj->as.match.str) {
 	    ptr = obj->as.match.str;
 	    goto again;
 	}
 	break;
 
+      case T_RATIONAL:
+	gc_mark(objspace, obj->as.rational.num, lev);
+	gc_mark(objspace, obj->as.rational.den, lev);
+	break;
+
+      case T_COMPLEX:
+	gc_mark(objspace, obj->as.complex.real, lev);
+	gc_mark(objspace, obj->as.complex.image, lev);
+	break;
+
       case T_STRUCT:
 	{
 	    long len = RSTRUCT_LEN(obj);
 	    VALUE *ptr = RSTRUCT_PTR(obj);
 
 	    while (len--) {
-		gc_mark(*ptr++, lev);
+		gc_mark(objspace, *ptr++, lev);
 	    }
 	}
 	break;
@@ -1372,21 +1620,20 @@
       default:
 	rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s",
 	       obj->as.basic.flags & T_MASK, obj,
-	       is_pointer_to_heap(obj) ? "corrupted object" : "non object");
+	       is_pointer_to_heap(objspace, obj) ? "corrupted object" : "non object");
     }
 }
 
-static void obj_free(VALUE);
+static void obj_free(rb_objspace_t *, VALUE);
 
 static void
-finalize_list(RVALUE *p)
+finalize_list(rb_objspace_t *objspace, RVALUE *p)
 {
     while (p) {
 	RVALUE *tmp = p->as.free.next;
-	run_final((VALUE)p);
+	run_final(objspace, (VALUE)p);
 	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
             VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
-	    p->as.free.isa = NULL;
 	    p->as.free.flags = 0;
 	    p->as.free.next = freelist;
 	    freelist = p;
@@ -1396,13 +1643,19 @@
 }
 
 static void
-free_unused_heaps(void)
+free_unused_heaps(rb_objspace_t *objspace)
 {
-    int i, j;
+    size_t i, j;
+    RVALUE *last = 0;
 
     for (i = j = 1; j < heaps_used; i++) {
 	if (heaps[i].limit == 0) {
-	    free(heaps[i].membase);
+	    if (!last) {
+		last = heaps[i].membase;
+	    }
+	    else {
+		free(heaps[i].membase);
+	    }
 	    heaps_used--;
 	}
 	else {
@@ -1412,28 +1665,32 @@
 	    j++;
 	}
     }
+    if (last) {
+	if (last < heaps_freed) {
+	    free(heaps_freed);
+	    heaps_freed = last;
+	}
+	else {
+	    free(last);
+	}
+    }
 }
 
 void rb_gc_abort_threads(void);
 
 static void
-gc_sweep(void)
+gc_sweep(rb_objspace_t *objspace)
 {
     RVALUE *p, *pend, *final_list;
-    int freed = 0;
-    int i;
-    unsigned long live = 0;
-    unsigned long free_min = 0;
+    size_t freed = 0;
+    size_t i;
+    size_t live = 0, free_min = 0, do_heap_free = 0;
 
-    for (i = 0; i < heaps_used; i++) {
-        free_min += heaps[i].limit;
-    }
-    free_min = free_min * 0.2;
-    if (free_min < FREE_MIN)
+    do_heap_free = (heaps_used * HEAP_OBJ_LIMIT) * 0.65;
+    free_min = (heaps_used * HEAP_OBJ_LIMIT)  * 0.2;
+    if (free_min < FREE_MIN) {
+	do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
         free_min = FREE_MIN;
-
-    if (source_filenames) {
-        st_foreach(source_filenames, sweep_source_filename, 0);
     }
 
     freelist = 0;
@@ -1448,7 +1705,7 @@
 	while (p < pend) {
 	    if (!(p->as.basic.flags & FL_MARK)) {
 		if (p->as.basic.flags) {
-		    obj_free((VALUE)p);
+		    obj_free(objspace, (VALUE)p);
 		}
 		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
 		    p->as.free.flags = FL_MARK; /* remain marked */
@@ -1457,7 +1714,6 @@
 		}
 		else {
                     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
-		    p->as.free.isa = NULL;
 		    p->as.free.flags = 0;
 		    p->as.free.next = freelist;
 		    freelist = p;
@@ -1474,7 +1730,7 @@
 	    }
 	    p++;
 	}
-	if (n == heaps[i].limit && freed > free_min) {
+	if (n == heaps[i].limit && freed > do_heap_free) {
 	    RVALUE *pp;
 
 	    heaps[i].limit = 0;
@@ -1493,7 +1749,8 @@
     }
     malloc_increase = 0;
     if (freed < free_min) {
-	add_heap();
+    	set_heaps_increment(objspace);
+	heaps_increment(objspace);
     }
     during_gc = 0;
 
@@ -1502,8 +1759,9 @@
 	deferred_final_list = final_list;
 	return;
     }
-    free_unused_heaps();
+    free_unused_heaps(objspace);
 }
+
 #endif /* !WITH_OBJC */
 
 void
@@ -1513,15 +1771,15 @@
     xfree((void *)p);
 #else
     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
-    RANY(p)->as.free.isa = NULL;
     RANY(p)->as.free.flags = 0;
     RANY(p)->as.free.next = freelist;
     freelist = RANY(p);
 #endif
 }
 
+#if !WITH_OBJC
 static void
-obj_free(VALUE obj)
+obj_free(rb_objspace_t *objspace, VALUE obj)
 {
     switch (RANY(obj)->as.basic.flags & T_MASK) {
       case T_NIL:
@@ -1540,7 +1798,7 @@
       case T_OBJECT:
 	if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) &&
             RANY(obj)->as.object.as.heap.ivptr) {
-	    RUBY_CRITICAL(xfree(RANY(obj)->as.object.as.heap.ivptr));
+	    RUBY_CRITICAL(free(RANY(obj)->as.object.as.heap.ivptr));
 	}
 	break;
       case T_MODULE:
@@ -1553,7 +1811,7 @@
 	if (RCLASS_IV_INDEX_TBL(obj)) {
 	    st_free_table(RCLASS_IV_INDEX_TBL(obj));
 	}
-        RUBY_CRITICAL(xfree(RANY(obj)->as.klass.ptr));
+        RUBY_CRITICAL(free(RANY(obj)->as.klass.ptr));
 	break;
       case T_STRING:
 	rb_str_free(obj);
@@ -1561,25 +1819,23 @@
       case T_ARRAY:
 	rb_ary_free(obj);
 	break;
-#if !WITH_OBJC
       case T_HASH:
 	if (RANY(obj)->as.hash.ntbl) {
 	    st_free_table(RANY(obj)->as.hash.ntbl);
 	}
 	break;
-#endif
       case T_REGEXP:
 	if (RANY(obj)->as.regexp.ptr) {
 	    onig_free(RANY(obj)->as.regexp.ptr);
 	}
 	if (RANY(obj)->as.regexp.str) {
-	    RUBY_CRITICAL(xfree(RANY(obj)->as.regexp.str));
+	    RUBY_CRITICAL(free(RANY(obj)->as.regexp.str));
 	}
 	break;
       case T_DATA:
 	if (DATA_PTR(obj)) {
 	    if ((long)RANY(obj)->as.data.dfree == -1) {
-		RUBY_CRITICAL(xfree(DATA_PTR(obj)));
+		RUBY_CRITICAL(free(DATA_PTR(obj)));
 	    }
 	    else if (RANY(obj)->as.data.dfree) {
 		(*RANY(obj)->as.data.dfree)(DATA_PTR(obj));
@@ -1600,19 +1856,21 @@
 	    rb_io_fptr_finalize(RANY(obj)->as.file.fptr);
 	}
 	break;
+      case T_RATIONAL:
+      case T_COMPLEX:
+	break;
       case T_ICLASS:
 	/* iClass shares table with the module */
 	break;
 
       case T_FLOAT:
-      case T_BLOCK:
 	break;
       case T_VALUES:
 	break;
 
       case T_BIGNUM:
 	if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
-	    RUBY_CRITICAL(xfree(RBIGNUM_DIGITS(obj)));
+	    RUBY_CRITICAL(free(RBIGNUM_DIGITS(obj)));
 	}
 	break;
       case T_NODE:
@@ -1631,19 +1889,20 @@
       case T_STRUCT:
 	if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
 	    RANY(obj)->as.rstruct.as.heap.ptr) {
-	    RUBY_CRITICAL(xfree(RANY(obj)->as.rstruct.as.heap.ptr));
+	    RUBY_CRITICAL(free(RANY(obj)->as.rstruct.as.heap.ptr));
 	}
 	break;
 
       default:
-	rb_bug("gc_sweep(): unknown data type 0x%lx(%p)", 
+	rb_bug("gc_sweep(): unknown data type 0x%lx(%p)",
 	       RANY(obj)->as.basic.flags & T_MASK, (void*)obj);
     }
 }
 
-#if !WITH_OBJC
 #ifdef __GNUC__
 #if defined(__human68k__) || defined(DJGPP)
+#undef rb_setjmp
+#undef rb_jmp_buf
 #if defined(__human68k__)
 typedef unsigned long rb_jmp_buf[8];
 __asm__ (".even\n\
@@ -1652,9 +1911,6 @@
 	movem.l	d3-d7/a3-a5,(a0)\n\
 	moveq.l	#0,d0\n\
 	rts");
-#ifdef setjmp
-#undef setjmp
-#endif
 #else
 #if defined(DJGPP)
 typedef unsigned long rb_jmp_buf[6];
@@ -1675,8 +1931,6 @@
 #endif
 #endif
 int rb_setjmp (rb_jmp_buf);
-#define jmp_buf rb_jmp_buf
-#define setjmp rb_setjmp
 #endif /* __human68k__ or DJGPP */
 #endif /* __GNUC__ */
 
@@ -1685,9 +1939,9 @@
 void rb_vm_mark(void *ptr);
 
 static void
-mark_current_machine_context(rb_thread_t *th)
+mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th)
 {
-    jmp_buf save_regs_gc_mark;
+    rb_jmp_buf save_regs_gc_mark;
     VALUE *stack_start, *stack_end;
 
     SET_STACK_END;
@@ -1710,14 +1964,14 @@
 
     FLUSH_REGISTER_WINDOWS;
     /* This assumes that all registers are saved into the jmp_buf (and stack) */
-    setjmp(save_regs_gc_mark);
-    mark_locations_array((VALUE*)save_regs_gc_mark,
+    rb_setjmp(save_regs_gc_mark);
+    mark_locations_array(objspace,
+			 (VALUE*)save_regs_gc_mark,
 			 sizeof(save_regs_gc_mark) / sizeof(VALUE));
 
-    mark_locations_array(stack_start, stack_end - stack_start);
+    rb_gc_mark_locations(stack_start, stack_end);
 #ifdef __ia64
-    mark_locations_array(th->machine_register_stack_start,
-			 th->machine_register_stack_end - th->machine_register_stack_start);
+    rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
 #endif
 #if defined(__human68k__) || defined(__mc68000__)
     mark_locations_array((VALUE*)((char*)STACK_END + 2),
@@ -1728,7 +1982,7 @@
 void rb_gc_mark_encodings(void);
 
 static int
-garbage_collect(void)
+garbage_collect(rb_objspace_t *objspace)
 {
     struct gc_list *list;
     rb_thread_t *th = GET_THREAD();
@@ -1741,23 +1995,27 @@
 
     if (dont_gc || during_gc) {
 	if (!freelist) {
-	    add_heap();
+            if (!heaps_increment(objspace)) {
+                set_heaps_increment(objspace);
+                heaps_increment(objspace);
+            }
 	}
 	return Qtrue;
     }
     during_gc++;
+    objspace->count++;
 
     SET_STACK_END;
 
-    init_mark_stack();
+    init_mark_stack(objspace);
 
     th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
 
     if (finalizer_table) {
-	mark_tbl(finalizer_table, 0);
+	mark_tbl(objspace, finalizer_table, 0);
     }
 
-    mark_current_machine_context(th);
+    mark_current_machine_context(objspace, th);
 
     rb_gc_mark_threads();
     rb_gc_mark_symbols();
@@ -1770,7 +2028,7 @@
     rb_mark_end_proc();
     rb_gc_mark_global_tbl();
 
-    rb_mark_tbl(rb_class_tbl);
+    mark_tbl(objspace, rb_class_tbl, 0);
     rb_gc_mark_trap_list();
 
     /* mark generic instance variables for special constants */
@@ -1781,14 +2039,15 @@
     /* gc_mark objects whose marking are not completed*/
     while (!MARK_STACK_EMPTY) {
 	if (mark_stack_overflow) {
-	    gc_mark_all();
+	    gc_mark_all(objspace);
 	}
 	else {
-	    gc_mark_rest();
+	    gc_mark_rest(objspace);
 	}
     }
 
-    gc_sweep();
+    gc_sweep(objspace);
+
     if (GC_NOTIFY) printf("end garbage_collect()\n");
     return Qtrue;
 }
@@ -1796,12 +2055,13 @@
 int
 rb_garbage_collect(void)
 {
-    return garbage_collect();
+    return garbage_collect(&rb_objspace);
 }
 
 void
 rb_gc_mark_machine_stack(rb_thread_t *th)
 {
+    rb_objspace_t *objspace = &rb_objspace;
 #if STACK_GROW_DIRECTION < 0
     rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
 #elif STACK_GROW_DIRECTION > 0
@@ -1818,7 +2078,9 @@
     rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
 #endif
 }
+
 #else /* !WITH_OBJC */
+
 static int
 garbage_collect(void)
 {
@@ -1828,6 +2090,7 @@
     malloc_increase = 0;
     return Qtrue;
 }
+
 #endif
 
 void
@@ -1856,6 +2119,7 @@
     return Qnil;
 }
 
+#if !WITH_OBJC
 void
 ruby_set_stack_size(size_t size)
 {
@@ -1865,67 +2129,13 @@
 void
 Init_stack(VALUE *addr)
 {
-#ifdef __ia64
-    if (rb_gc_register_stack_start == 0) {
-# if defined(__FreeBSD__)
-        /*
-         * FreeBSD/ia64 currently does not have a way for a process to get the
-         * base address for the RSE backing store, so hardcode it.
-         */
-        rb_gc_register_stack_start = (4ULL<<61);
-# elif defined(HAVE___LIBC_IA64_REGISTER_BACKING_STORE_BASE)
-#  pragma weak __libc_ia64_register_backing_store_base
-        extern unsigned long __libc_ia64_register_backing_store_base;
-        rb_gc_register_stack_start = (VALUE*)__libc_ia64_register_backing_store_base;
-# endif
-    }
-    {
-        VALUE *bsp = (VALUE*)rb_ia64_bsp();
-        if (rb_gc_register_stack_start == 0 ||
-            bsp < rb_gc_register_stack_start) {
-            rb_gc_register_stack_start = bsp;
-        }
-    }
+    ruby_init_stack(addr);
+}
 #endif
-#if defined(_WIN32) || defined(__CYGWIN__)
-    MEMORY_BASIC_INFORMATION m;
-    memset(&m, 0, sizeof(m));
-    VirtualQuery(&m, &m, sizeof(m));
-    rb_gc_stack_start =
-	STACK_UPPER((VALUE *)&m, (VALUE *)m.BaseAddress,
-		    (VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1);
-#elif defined(STACK_END_ADDRESS)
-    {
-        extern void *STACK_END_ADDRESS;
-        rb_gc_stack_start = STACK_END_ADDRESS;
-    }
-#else
-    if (!addr) addr = (VALUE *)&addr;
-    STACK_UPPER(&addr, addr, ++addr);
-    if (rb_gc_stack_start) {
-	if (STACK_UPPER(&addr,
-			rb_gc_stack_start > addr,
-			rb_gc_stack_start < addr))
-	    rb_gc_stack_start = addr;
-	return;
-    }
-    rb_gc_stack_start = addr;
-#endif
-#ifdef HAVE_GETRLIMIT
-    {
-	struct rlimit rlim;
 
-	if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
-	    unsigned int space = rlim.rlim_cur/5;
-
-	    if (space > 1024*1024) space = 1024*1024;
-	    rb_gc_stack_maxsize = rlim.rlim_cur - space;
-	}
-    }
-#endif
-}
-
-void ruby_init_stack(VALUE *addr
+#undef ruby_init_stack
+void
+ruby_init_stack(VALUE *addr
 #ifdef __ia64
     , void *bsp
 #endif
@@ -2084,22 +2294,14 @@
     if (!rb_gc_stack_start) {
 	Init_stack(0);
     }
-    add_heap();
+    init_heap(&rb_objspace);
 }
-#endif
 
 static VALUE
-os_obj_of(VALUE of)
+os_obj_of(rb_objspace_t *objspace, VALUE of)
 {
-#if WITH_OBJC
-    struct rb_objc_recorder_context ctx = {of, 0};
-    (((malloc_zone_t *)__auto_zone)->introspect->enumerator)(
-	    mach_task_self(), (void *)&ctx, MALLOC_PTR_IN_USE_RANGE_TYPE,
-	    (vm_address_t)__auto_zone, NULL, rb_objc_recorder);
-    return INT2FIX(ctx.count);
-#else
-    int i;
-    int n = 0;
+    size_t i;
+    size_t n = 0;
 
     for (i = 0; i < heaps_used; i++) {
 	RVALUE *p, *pend;
@@ -2126,9 +2328,9 @@
 	}
     }
 
-    return INT2FIX(n);
+    return SIZET2NUM(n);
+}
 #endif
-}
 
 /*
  *  call-seq:
@@ -2169,65 +2371,25 @@
     VALUE of;
 
     rb_secure(4);
-    if (rb_scan_args(argc, argv, "01", &of) == 0) {
+    if (argc == 0) {
 	of = 0;
     }
+    else {
+	rb_scan_args(argc, argv, "01", &of);
+    }
     RETURN_ENUMERATOR(os, 1, &of);
-    return os_obj_of(of);
+#if WITH_OBJC
+    struct rb_objc_recorder_context ctx = {of, 0};
+    (((malloc_zone_t *)__auto_zone)->introspect->enumerator)(
+	    mach_task_self(), (void *)&ctx, MALLOC_PTR_IN_USE_RANGE_TYPE,
+	    (vm_address_t)__auto_zone, NULL, rb_objc_recorder);
+    return INT2FIX(ctx.count);
+#else
+    return os_obj_of(&rb_objspace, of);
+#endif
 }
 
-static VALUE finalizers;
-
-/* deprecated
- */
-
-static VALUE
-add_final(VALUE os, VALUE block)
-{
-    rb_warn("ObjectSpace::add_finalizer is deprecated; use define_finalizer");
-    if (!rb_respond_to(block, rb_intern("call"))) {
-	rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
-		 rb_obj_classname(block));
-    }
-    rb_ary_push(finalizers, block);
-    return block;
-}
-
 /*
- * deprecated
- */
-static VALUE
-rm_final(VALUE os, VALUE block)
-{
-    rb_warn("ObjectSpace::remove_finalizer is deprecated; use undefine_finalizer");
-    rb_ary_delete(finalizers, block);
-    return block;
-}
-
-/*
- * deprecated
- */
-static VALUE
-finals(void)
-{
-    rb_warn("ObjectSpace::finalizers is deprecated");
-    return finalizers;
-}
-
-/*
- * deprecated
- */
-
-static VALUE
-call_final(VALUE os, VALUE obj)
-{
-    rb_warn("ObjectSpace::call_finalizer is deprecated; use define_finalizer");
-    need_call_final = 1;
-    FL_SET(obj, FL_FINALIZE);
-    return obj;
-}
-
-/*
  *  call-seq:
  *     ObjectSpace.undefine_finalizer(obj)
  *
@@ -2238,9 +2400,14 @@
 static VALUE
 undefine_final(VALUE os, VALUE obj)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
+    rb_objspace_t *objspace = &rb_objspace;
     if (finalizer_table) {
 	st_delete(finalizer_table, (st_data_t*)&obj, 0);
     }
+#endif
     return obj;
 }
 
@@ -2256,6 +2423,10 @@
 static VALUE
 define_final(int argc, VALUE *argv, VALUE os)
 {
+#if WITH_OBJC
+    rb_notimplement();
+#else
+    rb_objspace_t *objspace = &rb_objspace;
     VALUE obj, block, table;
 
     rb_scan_args(argc, argv, "11", &obj, &block);
@@ -2281,11 +2452,16 @@
 	st_add_direct(finalizer_table, obj, rb_ary_new3(1, block));
     }
     return block;
+#endif
 }
 
 void
 rb_gc_copy_finalizer(VALUE dest, VALUE obj)
 {
+#if WITH_OBJC
+    /* TODO */
+#else
+    rb_objspace_t *objspace = &rb_objspace;
     VALUE table;
 
     if (!finalizer_table) return;
@@ -2294,8 +2470,10 @@
 	st_insert(finalizer_table, dest, table);
     }
     FL_SET(dest, FL_FINALIZE);
+#endif
 }
 
+#if !WITH_OBJC
 static VALUE
 run_single_final(VALUE arg)
 {
@@ -2305,38 +2483,30 @@
 }
 
 static void
-run_final(VALUE obj)
+run_final(rb_objspace_t *objspace, VALUE obj)
 {
     long i;
     int status, critical_save = rb_thread_critical;
     VALUE args[3], table, objid;
 
-assert(0);
-
     objid = rb_obj_id(obj);	/* make obj into id */
     rb_thread_critical = Qtrue;
     args[1] = 0;
-    if (RARRAY_LEN(finalizers) > 0) {
-	args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
-    }
     args[2] = (VALUE)rb_safe_level();
-    for (i=0; i<RARRAY_LEN(finalizers); i++) {
-	args[0] = RARRAY_AT(finalizers, i);
-	rb_protect(run_single_final, (VALUE)args, &status);
-    }
     if (finalizer_table && st_delete(finalizer_table, (st_data_t*)&obj, &table)) {
 	if (!args[1] && RARRAY_LEN(table) > 0) {
 	    args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
 	}
 	for (i=0; i<RARRAY_LEN(table); i++) {
-	    VALUE final = RARRAY_AT(table, i);
-	    args[0] = RARRAY_AT(final, 1);
-	    args[2] = FIX2INT(RARRAY_AT(final, 0));
+	    VALUE final = RARRAY_PTR(table)[i];
+	    args[0] = RARRAY_PTR(final)[1];
+	    args[2] = FIX2INT(RARRAY_PTR(final)[0]);
 	    rb_protect(run_single_final, (VALUE)args, &status);
 	}
     }
     rb_thread_critical = critical_save;
 }
+#endif
 
 #if WITH_OBJC
 static CFMutableArrayRef __exit_finalize = NULL;
@@ -2383,25 +2553,32 @@
 
 #else /* WITH_OBJC */
 
-void
-rb_gc_finalize_deferred(void)
+static void
+gc_finalize_deferred(rb_objspace_t *objspace)
 {
     RVALUE *p = deferred_final_list;
 
     during_gc++;
     deferred_final_list = 0;
     if (p) {
-	finalize_list(p);
+	finalize_list(objspace, p);
     }
-    free_unused_heaps();
+    free_unused_heaps(objspace);
     during_gc = 0;
 }
 
 void
+rb_gc_finalize_deferred(void)
+{
+    gc_finalize_deferred(&rb_objspace);
+}
+
+void
 rb_gc_call_finalizer_at_exit(void)
 {
+    rb_objspace_t *objspace = &rb_objspace;
     RVALUE *p, *pend;
-    int i;
+    size_t i;
 
     /* finalizers are part of garbage collection */
     during_gc++;
@@ -2409,14 +2586,14 @@
     if (need_call_final) {
 	p = deferred_final_list;
 	deferred_final_list = 0;
-	finalize_list(p);
+	finalize_list(objspace, p);
 	for (i = 0; i < heaps_used; i++) {
 	    p = heaps[i].slot; pend = p + heaps[i].limit;
 	    while (p < pend) {
 		if (FL_TEST(p, FL_FINALIZE)) {
 		    FL_UNSET(p, FL_FINALIZE);
 		    p->as.basic.klass = 0;
-		    run_final((VALUE)p);
+		    run_final(objspace, (VALUE)p);
 		}
 		p++;
 	    }
@@ -2429,7 +2606,6 @@
 	    if (BUILTIN_TYPE(p) == T_DATA &&
 		DATA_PTR(p) && RANY(p)->as.data.dfree &&
 		RANY(p)->as.basic.klass != rb_cThread) {
-		p->as.free.isa = NULL;
 		p->as.free.flags = 0;
 		if ((long)RANY(p)->as.data.dfree == -1) {
 		    RUBY_CRITICAL(free(DATA_PTR(p)));
@@ -2441,7 +2617,6 @@
 	    }
 	    else if (BUILTIN_TYPE(p) == T_FILE) {
 		if (rb_io_fptr_finalize(RANY(p)->as.file.fptr)) {
-		    p->as.free.isa = NULL;
 		    p->as.free.flags = 0;
                     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
 		}
@@ -2451,6 +2626,14 @@
     }
     during_gc = 0;
 }
+
+void
+rb_gc(void)
+{
+    rb_objspace_t *objspace = &rb_objspace;
+    garbage_collect(objspace);
+    gc_finalize_deferred(objspace);
+}
 #endif
 
 /*
@@ -2474,6 +2657,9 @@
 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
 #define NUM2PTR(x) NUM2ULL(x)
 #endif
+#if !WITH_OBJC
+    rb_objspace_t *objspace = &rb_objspace;
+#endif
     VALUE ptr;
     void *p0;
 
@@ -2484,6 +2670,10 @@
     if (ptr == Qtrue) return Qtrue;
     if (ptr == Qfalse) return Qfalse;
     if (ptr == Qnil) return Qnil;
+#if WITH_OBJC
+    if (FIXNUM_P(ptr) || SYMBOL_P(ptr))
+	return ptr;
+#else
     if (FIXNUM_P(ptr)) return (VALUE)ptr;
     ptr = objid ^ FIXNUM_FLAG;	/* unset FIXNUM_FLAG */
 
@@ -2493,6 +2683,7 @@
 	    rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
 	return ID2SYM(symid);
     }
+#endif
 
 #if WITH_OBJC
     if (auto_zone_is_valid_pointer(auto_zone(), p0)) {
@@ -2501,12 +2692,13 @@
 	if ((type == AUTO_OBJECT_SCANNED || type == AUTO_OBJECT_UNSCANNED)
 	    && !rb_objc_is_placeholder(p0)
 	    && (rb_objc_is_non_native((VALUE)p0)
-		|| (BUILTIN_TYPE(p0) < T_VALUES && BUILTIN_TYPE(p0) != T_ICLASS)))
+		|| (BUILTIN_TYPE(p0) < T_VALUES 
+		    && BUILTIN_TYPE(p0) != T_ICLASS)))
 	    return (VALUE)p0;
     }
     rb_raise(rb_eRangeError, "%p is not id value", p0);
 #else
-    if (!is_pointer_to_heap((void *)ptr) ||
+    if (!is_pointer_to_heap(objspace, (void *)ptr) ||
 	BUILTIN_TYPE(ptr) >= T_VALUES || BUILTIN_TYPE(ptr) == T_ICLASS) {
 	rb_raise(rb_eRangeError, "%p is not id value", p0);
     }
@@ -2524,7 +2716,7 @@
  *  call-seq:
  *     obj.__id__       => fixnum
  *     obj.object_id    => fixnum
- *  
+ *
  *  Returns an integer identifier for <i>obj</i>. The same number will
  *  be returned on all calls to <code>id</code> for a given object, and
  *  no two active objects will share an id.
@@ -2536,7 +2728,7 @@
 /*
  *  call-seq:
  *     obj.hash    => fixnum
- *  
+ *
  *  Generates a <code>Fixnum</code> hash value for this object. This
  *  function must have the property that <code>a.eql?(b)</code> implies
  *  <code>a.hash == b.hash</code>. The hash value is used by class
@@ -2575,9 +2767,11 @@
      *  24 if 32-bit, double is 8-byte aligned
      *  40 if 64-bit
      */
+#if !WITH_OBJC
     if (TYPE(obj) == T_SYMBOL) {
         return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
     }
+#endif
     if (SPECIAL_CONST_P(obj)) {
         return LONG2NUM((SIGNED_VALUE)obj);
     }
@@ -2611,10 +2805,14 @@
 static VALUE
 count_objects(int argc, VALUE *argv, VALUE os)
 {
-    long counts[T_MASK+1];
-    long freed = 0;
-    long total = 0;
-    int i;
+#if WITH_OBJC
+    return rb_hash_new();
+#else
+    rb_objspace_t *objspace = &rb_objspace;
+    size_t counts[T_MASK+1];
+    size_t freed = 0;
+    size_t total = 0;
+    size_t i;
     VALUE hash;
 
     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
@@ -2643,45 +2841,73 @@
 
     if (hash == Qnil)
         hash = rb_hash_new();
-    rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), LONG2NUM(total));
-    rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), LONG2NUM(freed));
+    rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
+    rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
     for (i = 0; i <= T_MASK; i++) {
         VALUE type;
         switch (i) {
-          case T_NONE:          type = ID2SYM(rb_intern("T_NONE")); break;
-          case T_NIL:           type = ID2SYM(rb_intern("T_NIL")); break;
-          case T_OBJECT:        type = ID2SYM(rb_intern("T_OBJECT")); break;
-          case T_CLASS:         type = ID2SYM(rb_intern("T_CLASS")); break;
-          case T_ICLASS:        type = ID2SYM(rb_intern("T_ICLASS")); break;
-          case T_MODULE:        type = ID2SYM(rb_intern("T_MODULE")); break;
-          case T_FLOAT:         type = ID2SYM(rb_intern("T_FLOAT")); break;
-          case T_STRING:        type = ID2SYM(rb_intern("T_STRING")); break;
-          case T_REGEXP:        type = ID2SYM(rb_intern("T_REGEXP")); break;
-          case T_ARRAY:         type = ID2SYM(rb_intern("T_ARRAY")); break;
-          case T_FIXNUM:        type = ID2SYM(rb_intern("T_FIXNUM")); break;
-          case T_HASH:          type = ID2SYM(rb_intern("T_HASH")); break;
-          case T_STRUCT:        type = ID2SYM(rb_intern("T_STRUCT")); break;
-          case T_BIGNUM:        type = ID2SYM(rb_intern("T_BIGNUM")); break;
-          case T_FILE:          type = ID2SYM(rb_intern("T_FILE")); break;
-          case T_TRUE:          type = ID2SYM(rb_intern("T_TRUE")); break;
-          case T_FALSE:         type = ID2SYM(rb_intern("T_FALSE")); break;
-          case T_DATA:          type = ID2SYM(rb_intern("T_DATA")); break;
-          case T_MATCH:         type = ID2SYM(rb_intern("T_MATCH")); break;
-          case T_SYMBOL:        type = ID2SYM(rb_intern("T_SYMBOL")); break;
-          case T_VALUES:        type = ID2SYM(rb_intern("T_VALUES")); break;
-          case T_BLOCK:         type = ID2SYM(rb_intern("T_BLOCK")); break;
-          case T_UNDEF:         type = ID2SYM(rb_intern("T_UNDEF")); break;
-          case T_NODE:          type = ID2SYM(rb_intern("T_NODE")); break;
+#define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
+	    COUNT_TYPE(T_NONE);
+	    COUNT_TYPE(T_OBJECT);
+	    COUNT_TYPE(T_CLASS);
+	    COUNT_TYPE(T_MODULE);
+	    COUNT_TYPE(T_FLOAT);
+	    COUNT_TYPE(T_STRING);
+	    COUNT_TYPE(T_REGEXP);
+	    COUNT_TYPE(T_ARRAY);
+	    COUNT_TYPE(T_HASH);
+	    COUNT_TYPE(T_STRUCT);
+	    COUNT_TYPE(T_BIGNUM);
+	    COUNT_TYPE(T_FILE);
+	    COUNT_TYPE(T_DATA);
+	    COUNT_TYPE(T_MATCH);
+	    COUNT_TYPE(T_COMPLEX);
+	    COUNT_TYPE(T_RATIONAL);
+	    COUNT_TYPE(T_NIL);
+	    COUNT_TYPE(T_TRUE);
+	    COUNT_TYPE(T_FALSE);
+	    COUNT_TYPE(T_SYMBOL);
+	    COUNT_TYPE(T_FIXNUM);
+	    COUNT_TYPE(T_VALUES);
+	    COUNT_TYPE(T_UNDEF);
+	    COUNT_TYPE(T_NODE);
+	    COUNT_TYPE(T_ICLASS);
+#undef COUNT_TYPE
           default:              type = INT2NUM(i); break;
         }
         if (counts[i])
-            rb_hash_aset(hash, type, LONG2NUM(counts[i]));
+            rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
     }
 
     return hash;
+#endif
 }
 
 /*
+ *  call-seq:
+ *     GC.count -> Integer
+ *
+ *  The number of times GC occured.
+ *
+ *  It returns the number of times GC occured since the process started.
+ *
+ */
+
+#if WITH_OBJC
+static long _gc_count = 0;
+#endif
+
+static VALUE
+gc_count(VALUE self)
+{
+#if WITH_OBJC
+    return UINT2NUM(_gc_count);
+#else
+    return UINT2NUM((&rb_objspace)->count);
+#endif
+}
+
+/*
  *  The <code>GC</code> module provides an interface to Ruby's mark and
  *  sweep garbage collection mechanism. Some of the underlying methods
  *  are also available via the <code>ObjectSpace</code> module.
@@ -2712,6 +2938,10 @@
 			 auto_zone_cursor_t cursor, size_t cursor_size) 
 {
     foreach(cursor, __rb_objc_finalize, NULL);
+    /* By incrementing the GC count here we make sure it will also be updated
+     * when a collection is triggered from the Objective-C world.
+     */
+    _gc_count++;
 }
 #endif
 
@@ -2723,8 +2953,6 @@
 
     __auto_zone = auto_zone();
     //auto_zone_register_thread(__auto_zone);
-    finalizer_table = st_init_strtable();
-    GC_ROOT(&finalizer_table);
 
     control = auto_collection_parameters(__auto_zone);
     control->scan_external_callout = 
@@ -2761,29 +2989,18 @@
     rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
     rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
     rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
+    rb_define_singleton_method(rb_mGC, "count", gc_count, 0);
     rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
 
     rb_mObSpace = rb_define_module("ObjectSpace");
     rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
     rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
-    rb_define_module_function(rb_mObSpace, "add_finalizer", add_final, 1);
-    rb_define_module_function(rb_mObSpace, "remove_finalizer", rm_final, 1);
-    rb_define_module_function(rb_mObSpace, "finalizers", finals, 0);
-    rb_define_module_function(rb_mObSpace, "call_finalizer", call_final, 1);
 
     rb_define_module_function(rb_mObSpace, "define_finalizer", define_final, -1);
     rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1);
 
     rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
 
-    rb_gc_register_address(&rb_mObSpace);
-    rb_global_variable(&finalizers);
-    rb_gc_unregister_address(&rb_mObSpace);
-    finalizers = rb_ary_new();
-
-    source_filenames = st_init_strtable();
-    GC_ROOT(&source_filenames);
-
     rb_global_variable(&nomem_error);
     nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory");
 

Modified: MacRuby/trunk/gem_prelude.rb
===================================================================
--- MacRuby/trunk/gem_prelude.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/gem_prelude.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,207 +1,220 @@
+# depends on: array.rb dir.rb env.rb file.rb hash.rb module.rb regexp.rb
+
 # empty gem_prelude.rb
 #
-# p Gem::Enable
+# p defined?(Gem)
 
-if defined?(Gem::Enable) && Gem::Enable
-#t = Time.now
-  
-module Kernel
+if defined?(Gem) then
 
-  def gem(gem_name, *version_requirements)
-    Gem.push_gem_version_on_load_path(gem_name, *version_requirements)
+  module Kernel
+
+    def gem(gem_name, *version_requirements)
+      Gem.push_gem_version_on_load_path(gem_name, *version_requirements)
+    end
+
   end
 
-end
+  module Gem
 
-module Gem
-  
-  ConfigMap = {
-    :sitedir => RbConfig::CONFIG["sitedir"],
-    :ruby_version => RbConfig::CONFIG["ruby_version"],
-    :libdir => RbConfig::CONFIG["libdir"],
-    :sitelibdir => RbConfig::CONFIG["sitelibdir"],
-    :arch => RbConfig::CONFIG["arch"],
-    :bindir => RbConfig::CONFIG["bindir"],
-    :EXEEXT => RbConfig::CONFIG["EXEEXT"],
-    :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
-    :ruby_install_name => RbConfig::CONFIG["ruby_install_name"]
-  }
+    ConfigMap = {
+      :sitedir => RbConfig::CONFIG["sitedir"],
+      :ruby_version => RbConfig::CONFIG["ruby_version"],
+      :libdir => RbConfig::CONFIG["libdir"],
+      :sitelibdir => RbConfig::CONFIG["sitelibdir"],
+      :arch => RbConfig::CONFIG["arch"],
+      :bindir => RbConfig::CONFIG["bindir"],
+      :EXEEXT => RbConfig::CONFIG["EXEEXT"],
+      :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
+      :ruby_install_name => RbConfig::CONFIG["ruby_install_name"]
+    }
 
-  class << self
+    class << self
 
-    def default_dir
-      if defined? RUBY_FRAMEWORK_VERSION
-        return File.join(File.dirname(ConfigMap[:sitedir]), "Gems")
-      else
-        File.join(ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version])
+      def default_dir
+        if defined? RUBY_FRAMEWORK_VERSION
+          return File.join(File.dirname(ConfigMap[:sitedir]), "Gems")
+        else
+          File.join(ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version])
+        end
       end
-    end
 
-    def dir
-      @gem_home ||= nil
-      set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
-      @gem_home
-    end
+      def dir
+        @gem_home ||= nil
+        set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
+        @gem_home
+      end
 
-    def path
-      @gem_path ||= nil
-      unless @gem_path
-        paths = [ENV['GEM_PATH']]
-        paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
-        set_paths(paths.compact.join(File::PATH_SEPARATOR))
+      def path
+        @gem_path ||= nil
+        unless @gem_path
+          paths = [ENV['GEM_PATH']]
+          paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
+          set_paths(paths.compact.join(File::PATH_SEPARATOR))
+        end
+        @gem_path
       end
-      @gem_path
-    end
 
-    # Set the Gem home directory (as reported by +dir+).
-    def set_home(home)
-      @gem_home = home
-      ensure_gem_subdirectories(@gem_home)
-    end
+      # Set the Gem home directory (as reported by +dir+).
+      def set_home(home)
+        @gem_home = home
+        ensure_gem_subdirectories(@gem_home)
+      end
 
-    def set_paths(gpaths)
-      if gpaths
-        @gem_path = gpaths.split(File::PATH_SEPARATOR)
-        @gem_path << Gem.dir
-      else
-        @gem_path = [Gem.dir]
+      def set_paths(gpaths)
+        if gpaths
+          @gem_path = gpaths.split(File::PATH_SEPARATOR)
+          @gem_path << Gem.dir
+        else
+          @gem_path = [Gem.dir]
+        end
+        @gem_path.uniq!
+        @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
       end
-      @gem_path.uniq!
-      @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
+
+      def ensure_gem_subdirectories(path)
+      end
+
     end
-    
-    def ensure_gem_subdirectories(path)
-    end
 
-  end
+    module QuickLoader
 
-  module QuickLoader
+      class << self
+        def load_full_rubygems_library
+          class << Gem
+            Gem.methods(false).each do |method_name|
+              undef_method method_name
+            end
+          end
 
-    class << self
-      def load_full_rubygems_library
-        class << Gem
-          Gem.methods(false).each do |method_name|
-            undef_method method_name
+          Kernel.module_eval do
+            undef_method :gem if method_defined? :gem
           end
+
+          $".delete File.join(Gem::ConfigMap[:libdir], 'ruby',
+                              Gem::ConfigMap[:ruby_version], 'rubygems.rb')
+
+          require 'rubygems'
         end
+      end
 
-        Kernel.send :undef_method, :gem
+      GemPaths = {}
+      GemVersions = {}
 
-        $".delete File.join(Gem::ConfigMap[:libdir], 'ruby',
-                            Gem::ConfigMap[:ruby_version], 'rubygems.rb')
+      def push_gem_version_on_load_path(gem_name, *version_requirements)
+        if version_requirements.empty?
+          unless GemPaths.has_key?(gem_name)
+            raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n") 
+          end
 
-        require 'rubygems'
-      end
-    end
+          # highest version gems already active
+          return false
+        else
+          if version_requirements.length > 1
+            QuickLoader.load_full_rubygems_library
+            return gem(gem_name, *version_requirements)
+          end
 
-    GemPaths = {}
-    GemVersions = {}
-    
-    def push_gem_version_on_load_path(gem_name, *version_requirements)
-      if version_requirements.empty?
-        unless GemPaths.has_key?(gem_name)
-          raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n") 
-        end
-        # highest version gems already active
-        return false
-      else
-        if version_requirements.length > 1
+          requirement, version = version_requirements[0].split
+          requirement.strip!
+
+          if requirement == ">" || requirement == ">="
+            if (GemVersions[gem_name] <=> Gem.calculate_integers_for_gem_version(version)) >= 0
+              return false 
+            end
+          elsif requirement == "~>"
+            loaded_version = GemVersions[gem_name]
+            required_version = Gem.calculate_integers_for_gem_version(version)
+            if loaded_version && (loaded_version[0] == required_version[0])
+              return false
+            end
+          end
+
           QuickLoader.load_full_rubygems_library
-          return gem(gem_name, *version_requirements)
+          gem(gem_name, *version_requirements)
         end
-        requirement, version = version_requirements[0].split
-        requirement.strip!
-        if requirement == ">" || requirement == ">="
-          if (GemVersions[gem_name] <=> Gem.calculate_integers_for_gem_version(version)) >= 0
-            return false 
-          end
-        elsif requirement == "~>"
-          loaded_version = GemVersions[gem_name]
-          required_version = Gem.calculate_integers_for_gem_version(version)
-          if loaded_version && (loaded_version[0] == required_version[0])
-            return false
-          end
-        end
-        QuickLoader.load_full_rubygems_library
-        gem(gem_name, *version_requirements)
       end
-    end
 
-    def calculate_integers_for_gem_version(gem_version)
-      numbers = gem_version.split(".").collect {|n| n.to_i}
-      numbers.pop while numbers.last == 0
-      numbers << 0 if numbers.empty?
-      numbers
-    end
-  
-    def push_all_highest_version_gems_on_load_path
-      Gem.path.each do |path|
-        gems_directory = File.join(path, "gems")
-        if File.exist?(gems_directory)
-          Dir.entries(gems_directory).each do |gem_directory_name|
-            next if gem_directory_name == "." || gem_directory_name == ".."
-            dash = gem_directory_name.rindex("-")
-            next if dash.nil?
-            gem_name = gem_directory_name[0...dash]
-            current_version = GemVersions[gem_name]
-            new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
-            if current_version
-              if (current_version <=> new_version) == -1
+      def calculate_integers_for_gem_version(gem_version)
+        numbers = gem_version.split(".").collect {|n| n.to_i}
+        numbers.pop while numbers.last == 0
+        numbers << 0 if numbers.empty?
+        numbers
+      end
+
+      def push_all_highest_version_gems_on_load_path
+        Gem.path.each do |path|
+          gems_directory = File.join(path, "gems")
+          if File.exist?(gems_directory)
+            Dir.entries(gems_directory).each do |gem_directory_name|
+              next if gem_directory_name == "." || gem_directory_name == ".."
+              dash = gem_directory_name.rindex("-")
+              next if dash.nil?
+              gem_name = gem_directory_name[0...dash]
+              current_version = GemVersions[gem_name]
+              new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
+              if current_version
+                if (current_version <=> new_version) == -1
+                  GemVersions[gem_name] = new_version
+                  GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
+                end
+              else
                 GemVersions[gem_name] = new_version
                 GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
               end
-            else
-              GemVersions[gem_name] = new_version
-              GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
             end
           end
         end
+
+        require_paths = []
+
+        GemPaths.values.each do |path|
+          if File.exist?(File.join(path, ".require_paths"))
+            require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
+          else
+            require_paths << File.join(path, "bin") if File.exist?(File.join(path, "bin"))
+            require_paths << File.join(path, "lib") if File.exist?(File.join(path, "lib"))
+          end
+        end
+
+        # "tag" the first require_path inserted into the $LOAD_PATH to enable
+        # indexing correctly with rubygems proper when it inserts an explicitly
+        # gem version
+        unless require_paths.empty?
+          require_paths.first.instance_variable_set(:@gem_prelude_index, true)
+        end
+        # gem directories must come after -I and ENV['RUBYLIB']
+        $:[$:.index(ConfigMap[:sitelibdir]),0] = require_paths
       end
-      require_paths = []
-      GemPaths.values.each do |path|
-        if File.exist?(File.join(path, ".require_paths"))
-          require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
+
+      def const_missing(constant)
+        QuickLoader.load_full_rubygems_library
+        if Gem.const_defined?(constant)
+          Gem.const_get(constant)
         else
-          require_paths << File.join(path, "bin") if File.exist?(File.join(path, "bin"))
-          require_paths << File.join(path, "lib") if File.exist?(File.join(path, "lib"))
+          super
         end
       end
-      
-      # "tag" the first require_path inserted into the $LOAD_PATH to enable
-      # indexing correctly with rubygems proper when it inserts an explicitly
-      # gem version
-      unless require_paths.empty?
-        require_paths.first.instance_variable_set(:@gem_prelude_index, true)
+
+      def method_missing(method, *args, &block)
+        QuickLoader.load_full_rubygems_library
+        super unless Gem.respond_to?(method)
+        Gem.send(method, *args, &block)
       end
-      # gem directories must come after -I and ENV['RUBYLIB']
-      $:[$:.index(ConfigMap[:sitelibdir]),0] = require_paths
     end
 
-    def const_missing(constant)
-      QuickLoader.load_full_rubygems_library
-      Gem.const_get(constant)
-    end
+    extend QuickLoader
 
-    def method_missing(method, *args, &block)
-      QuickLoader.load_full_rubygems_library
-      super unless Gem.respond_to?(method)
-      Gem.send(method, *args, &block)
-    end
   end
-  
-  extend QuickLoader
 
-end
+  begin
+    Gem.push_all_highest_version_gems_on_load_path
+    $" << File.join(Gem::ConfigMap[:libdir], "ruby",
+                    Gem::ConfigMap[:ruby_version], "rubygems.rb")
+  rescue Exception => e
+    puts "Error loading gem paths on load path in gem_prelude"
+    puts e
+    puts e.backtrace.join("\n")
+  end
 
-begin
-  Gem.push_all_highest_version_gems_on_load_path
-  $" << File.join(Gem::ConfigMap[:libdir], "ruby",
-                  Gem::ConfigMap[:ruby_version], "rubygems.rb")
-rescue Exception => e
-  puts "Error loading gem paths on load path in gem_prelude"
-  puts e
-  puts e.backtrace.join("\n")
 end
 
-#puts "Gem load in #{Time.now - t} seconds"
-end # Gem::Enable

Modified: MacRuby/trunk/golf_prelude.rb
===================================================================
--- MacRuby/trunk/golf_prelude.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/golf_prelude.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,7 +13,7 @@
   end
 
   def self.const_missing c
-    t = @@golf_hash[ [m,self.class] ] ||= matching_methods(c,constants)[0]
+    t = @@golf_hash[ [c,self.class] ] ||= matching_methods(c,constants)[0]
     t and return const_get(t)
     raise NameError, "uninitialized constant #{c}", caller(1)
   end

Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/hash.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -83,15 +83,16 @@
 rb_any_hash(VALUE a)
 {
     VALUE hval;
+    int hnum;
 
     switch (TYPE(a)) {
       case T_FIXNUM:
       case T_SYMBOL:
-	return (int)a;
+	hnum = (int)a;
 	break;
 
       case T_STRING:
-	return rb_str_hash(a);
+	hnum = rb_str_hash(a);
 	break;
 
       default:
@@ -99,8 +100,14 @@
 	if (!FIXNUM_P(hval)) {
 	    hval = rb_funcall(hval, '%', 1, INT2FIX(536870923));
 	}
-	return (int)FIX2LONG(hval);
+	hnum = (int)FIX2LONG(hval);
     }
+#if WITH_OBJC
+    return hnum;
+#else
+    hnum <<= 1;
+    return RSHIFT(hnum, 1);
+#endif
 }
 
 static const struct st_hash_type objhash = {
@@ -108,6 +115,11 @@
     rb_any_hash,
 };
 
+static const struct st_hash_type identhash = {
+    st_numcmp,
+    st_numhash,
+};
+
 typedef int st_foreach_func(st_data_t, st_data_t, st_data_t);
 
 struct foreach_safe_arg {
@@ -749,7 +761,7 @@
  *     h.default(2)                            #=> "cat"
  *
  *     h = Hash.new {|h,k| h[k] = k.to_i*10}   #=> {}
- *     h.default                               #=> 0
+ *     h.default                               #=> nil
  *     h.default(2)                            #=> 20
  */
 
@@ -1061,6 +1073,7 @@
 VALUE
 rb_hash_delete_if(VALUE hash)
 {
+    RETURN_ENUMERATOR(hash, 0, 0);
     rb_hash_modify(hash);
     rb_hash_foreach(hash, delete_if_i, hash);
     return hash;
@@ -1080,6 +1093,7 @@
 #if WITH_OBJC
     CFIndex n;
 
+    RETURN_ENUMERATOR(hash, 0, 0);
     n = CFDictionaryGetCount((CFDictionaryRef)hash);
     rb_hash_delete_if(hash);
     if (n == CFDictionaryGetCount((CFDictionaryRef)hash))
@@ -1087,6 +1101,8 @@
     return hash;
 #else
     int n;
+
+    RETURN_ENUMERATOR(hash, 0, 0);
     if (!RHASH(hash)->ntbl)
         return Qnil;
     n = RHASH(hash)->ntbl->num_entries;
@@ -1121,7 +1137,7 @@
  *
  *   h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
  *   h.values_at("cow", "cat")  #=> ["bovine", "feline"]
-*/
+ */
 
 VALUE
 rb_hash_values_at(int argc, VALUE *argv, VALUE hash)
@@ -1226,12 +1242,11 @@
 {
     rb_hash_modify(hash);
 #if WITH_OBJC
-//    if (TYPE(key) == T_STRING)
-//	key = rb_obj_dup(key); /* FIXME temporary fix. */
     CFDictionarySetValue((CFMutableDictionaryRef)hash, (const void *)key,
 	(const void *)val);
 #else
-    if (TYPE(key) != T_STRING || st_lookup(RHASH(hash)->ntbl, key, 0)) {
+    if (RHASH(hash)->ntbl->type == &identhash ||
+	TYPE(key) != T_STRING || st_lookup(RHASH(hash)->ntbl, key, 0)) {
 	st_insert(RHASH(hash)->ntbl, key, val);
     }
     else {
@@ -1328,11 +1343,7 @@
 static VALUE
 rb_hash_empty_p(VALUE hash)
 {
-#if WITH_OBJC
-    return CFDictionaryGetCount((CFDictionaryRef)hash) == 0 ? Qtrue : Qfalse;
-#else
     return RHASH_EMPTY_P(hash) ? Qtrue : Qfalse;
-#endif
 }
 
 static int
@@ -1448,7 +1459,7 @@
  *  value</i> <code>]</code> arrays.
  *
  *     h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300  }
- *     h.to_a   #=> [["a", 100], ["c", 300], ["d", 400]]
+ *     h.to_a   #=> [["c", 300], ["a", 100], ["d", 400]]
  */
 
 static VALUE
@@ -1509,13 +1520,13 @@
  * Return the contents of this hash as a string.
  *
  *     h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300  }
- *     h.to_s   #=> "{\"a\"=>100, \"c\"=>300, \"d\"=>400}"
+ *     h.to_s   #=> "{\"c\"=>300, \"a\"=>100, \"d\"=>400}"
  */
 
 static VALUE
 rb_hash_inspect(VALUE hash)
 {
-    if (CFDictionaryGetCount((CFDictionaryRef)hash) == 0)
+    if (RHASH_EMPTY_P(hash))
 	return rb_usascii_str_new2("{}");
     return rb_exec_recursive(inspect_hash, hash, 0);
 }
@@ -1725,6 +1736,8 @@
 #else
     if (!RHASH(hash1)->ntbl || !RHASH(hash2)->ntbl)
         return Qtrue;
+    if (RHASH(hash1)->ntbl->type != RHASH(hash2)->ntbl->type)
+	return Qfalse;
 #if 0
     if (!(rb_equal(RHASH(hash1)->ifnone, RHASH(hash2)->ifnone) &&
 	  FL_TEST(hash1, HASH_PROC_DEFAULT) == FL_TEST(hash2, HASH_PROC_DEFAULT)))
@@ -1835,7 +1848,7 @@
  *  the keys as values.
  *
  *     h = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 }
- *     h.invert   #=> {0=>"a", 100=>"n", 200=>"d", 300=>"y"}
+ *     h.invert   #=> {0=>"a", 100=>"m", 200=>"d", 300=>"y"}
  *
  */
 
@@ -1883,6 +1896,9 @@
  *     h1 = { "a" => 100, "b" => 200 }
  *     h2 = { "b" => 254, "c" => 300 }
  *     h1.merge!(h2)   #=> {"a"=>100, "b"=>254, "c"=>300}
+ *
+ *     h1 = { "a" => 100, "b" => 200 }
+ *     h2 = { "b" => 254, "c" => 300 }
  *     h1.merge!(h2) { |key, v1, v2| v1 }
  *                     #=> {"a"=>100, "b"=>200, "c"=>300}
  */
@@ -2024,11 +2040,6 @@
     return ary;
 }
 
-static const struct st_hash_type identhash = {
-    st_numcmp,
-    st_numhash,
-};
-
 /*
  *  call-seq:
  *     hsh.compare_by_identity => hsh
@@ -2483,12 +2494,13 @@
 }
 
 static VALUE
-env_reject_bang(void)
+env_reject_bang(VALUE ehash)
 {
     volatile VALUE keys;
     long i;
     int del = 0;
 
+    RETURN_ENUMERATOR(ehash, 0, 0);
     rb_secure(4);
     keys = env_keys();
     for (i=0; i<RARRAY_LEN(keys); i++) {
@@ -2506,9 +2518,10 @@
 }
 
 static VALUE
-env_delete_if(void)
+env_delete_if(VALUE ehash)
 {
-    env_reject_bang();
+    RETURN_ENUMERATOR(ehash, 0, 0);
+    env_reject_bang(ehash);
     return envtbl;
 }
 
@@ -2552,8 +2565,8 @@
     return result;
 }
 
-static VALUE
-env_clear(void)
+VALUE
+rb_env_clear(void)
 {
     volatile VALUE keys;
     long i;
@@ -3042,15 +3055,15 @@
     rb_cHash = rb_define_class("Hash", rb_cObject);
 #endif
 
+    rb_include_module(rb_cHash, rb_mEnumerable);
+
     rb_define_alloc_func(rb_cHash, hash_alloc);
     rb_define_singleton_method(rb_cHash, "[]", rb_hash_s_create, -1);
     rb_define_singleton_method(rb_cHash, "try_convert", rb_hash_s_try_convert, 1);
     rb_define_method(rb_cHash,"initialize", rb_hash_initialize, -1);
     rb_define_method(rb_cHash,"initialize_copy", rb_hash_replace, 1);
+    rb_define_method(rb_cHash,"rehash", rb_hash_rehash, 0);
 
-    rb_include_module(rb_cHash, rb_mEnumerable);
-
-    rb_define_method(rb_cHash,"rehash", rb_hash_rehash, 0);
     rb_define_method(rb_cHash,"to_hash", rb_hash_to_hash, 0);
     rb_define_method(rb_cHash,"to_a", rb_hash_to_a, 0);
     rb_define_method(rb_cHash,"to_s", rb_hash_inspect, 0);
@@ -3124,7 +3137,7 @@
     rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
     rb_define_singleton_method(envtbl,"delete", env_delete_m, 1);
     rb_define_singleton_method(envtbl,"delete_if", env_delete_if, 0);
-    rb_define_singleton_method(envtbl,"clear", env_clear, 0);
+    rb_define_singleton_method(envtbl,"clear", rb_env_clear, 0);
     rb_define_singleton_method(envtbl,"reject", env_reject, 0);
     rb_define_singleton_method(envtbl,"reject!", env_reject_bang, 0);
     rb_define_singleton_method(envtbl,"select", env_select, 0);

Modified: MacRuby/trunk/include/ruby/defines.h
===================================================================
--- MacRuby/trunk/include/ruby/defines.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/include/ruby/defines.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -262,6 +262,14 @@
 #define ENV_IGNORECASE
 #endif
 
+#ifndef CASEFOLD_FILESYSTEM
+# if defined DOSISH || defined __VMS
+#   define CASEFOLD_FILESYSTEM 1
+# else
+#   define CASEFOLD_FILESYSTEM 0
+# endif
+#endif
+
 #ifndef DLEXT_MAXLEN
 #define DLEXT_MAXLEN 4
 #endif

Modified: MacRuby/trunk/include/ruby/encoding.h
===================================================================
--- MacRuby/trunk/include/ruby/encoding.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/include/ruby/encoding.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -214,5 +214,6 @@
 VALUE rb_enc_default_external(void);
 void rb_enc_set_default_external(VALUE encoding);
 VALUE rb_locale_charmap(VALUE klass);
+long rb_memsearch(const void*,long,const void*,long,rb_encoding*);
 
 #endif /* RUBY_ENCODING_H */

Modified: MacRuby/trunk/include/ruby/intern.h
===================================================================
--- MacRuby/trunk/include/ruby/intern.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/include/ruby/intern.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   intern.h -
 
-  $Author: naruse $
+  $Author: usa $
   created at: Thu Jun 10 14:22:17 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -127,6 +127,26 @@
 VALUE rb_big_xor(VALUE, VALUE);
 VALUE rb_big_lshift(VALUE, VALUE);
 VALUE rb_big_rshift(VALUE, VALUE);
+/* rational.c */
+VALUE rb_rational_raw(VALUE, VALUE);
+#define rb_rational_raw1(x) rb_rational_raw(x, INT2FIX(1))
+#define rb_rational_raw2(x,y) rb_rational_raw(x, y)
+VALUE rb_rational_new(VALUE, VALUE);
+#define rb_rational_new1(x) rb_rational_new(x, INT2FIX(1))
+#define rb_rational_new2(x,y) rb_rational_new(x, y)
+VALUE rb_Rational(VALUE, VALUE);
+#define rb_Rational1(x) rb_Rational(x, INT2FIX(1))
+#define rb_Rational2(x,y) rb_Rational(x, y)
+/* complex.c */
+VALUE rb_complex_raw(VALUE, VALUE);
+#define rb_complex_raw1(x) rb_complex_raw(x, INT2FIX(0))
+#define rb_complex_raw2(x,y) rb_complex_raw(x, y)
+VALUE rb_complex_new(VALUE, VALUE);
+#define rb_complex_new1(x) rb_complex_new(x, INT2FIX(0))
+#define rb_complex_new2(x,y) rb_complex_new(x, y)
+VALUE rb_Complex(VALUE, VALUE);
+#define rb_Complex1(x) rb_Complex(x, INT2FIX(0))
+#define rb_Complex2(x,y) rb_Complex(x, y)
 /* class.c */
 #if WITH_OBJC
 VALUE rb_objc_import_class(Class);
@@ -221,7 +241,7 @@
 #define rb_fd_copy(d, s, n) (*(d) = *(s))
 #define rb_fd_ptr(f)	(f)
 #define rb_fd_init(f)	FD_ZERO(f)
-#define rb_fd_term(f)	(f)
+#define rb_fd_term(f)	(void)(f)
 #define rb_fd_max(f)	FD_SETSIZE
 #define rb_fd_select(n, rfds, wfds, efds, timeout)	select(n, rfds, wfds, efds, timeout)
 
@@ -303,6 +323,7 @@
 VALUE rb_thread_local_aref(VALUE, ID);
 VALUE rb_thread_local_aset(VALUE, ID, VALUE);
 void rb_thread_atfork(void);
+void rb_thread_atfork_before_exec(void);
 VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE);
 /* file.c */
 VALUE rb_file_s_expand_path(int, VALUE *);
@@ -320,7 +341,6 @@
 NORETURN(void rb_memerror(void));
 int ruby_stack_check(void);
 int ruby_stack_length(VALUE**);
-char *rb_source_filename(const char*);
 #if WITH_OBJC
 void rb_objc_gc_register_thread(void);
 void rb_objc_gc_unregister_thread(void);
@@ -353,6 +373,7 @@
 void rb_hash_foreach(VALUE, int (*)(ANYARGS), VALUE);
 VALUE rb_hash(VALUE);
 VALUE rb_hash_new(void);
+VALUE rb_hash_dup(VALUE);
 VALUE rb_hash_freeze(VALUE);
 VALUE rb_hash_aref(VALUE, VALUE);
 VALUE rb_hash_lookup(VALUE, VALUE);
@@ -362,6 +383,7 @@
 struct st_table *rb_hash_tbl(VALUE);
 int rb_path_check(const char*);
 int rb_env_path_tainted(void);
+VALUE rb_env_clear(void);
 #if WITH_OBJC
 bool rb_objc_hash_is_pure(VALUE);
 #endif
@@ -389,6 +411,8 @@
 VALUE rb_gets(void);
 void rb_write_error(const char*);
 void rb_write_error2(const char*, long);
+int rb_io_mode_modenum(const char *mode);
+void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds);
 /* marshal.c */
 VALUE rb_marshal_dump(VALUE, VALUE);
 VALUE rb_marshal_load(VALUE);
@@ -456,12 +480,17 @@
     int argc;
     VALUE *argv;
     const char *prog;
+    VALUE options;
+    VALUE redirect_fds;
 };
 int rb_proc_exec_n(int, VALUE*, const char*);
 int rb_proc_exec(const char*);
-VALUE rb_check_argv(int, VALUE*);
+VALUE rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e);
+int rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val);
+void rb_exec_arg_fixup(struct rb_exec_arg *e);
+int rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s);
 int rb_exec(const struct rb_exec_arg*);
-rb_pid_t rb_fork(int*, int (*)(void*), void*);
+rb_pid_t rb_fork(int*, int (*)(void*), void*, VALUE);
 VALUE rb_f_exec(int,VALUE*);
 rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags);
 void rb_syswait(rb_pid_t pid);
@@ -477,7 +506,6 @@
 /* re.c */
 #define rb_memcmp memcmp
 int rb_memcicmp(const void*,const void*,long);
-long rb_memsearch(const void*,long,const void*,long);
 VALUE rb_reg_nth_defined(int, VALUE);
 VALUE rb_reg_nth_match(int, VALUE);
 VALUE rb_reg_last_match(VALUE);
@@ -493,8 +521,9 @@
 void rb_set_kcode(const char*);
 const char* rb_get_kcode(void);
 /* ruby.c */
-RUBY_EXTERN VALUE rb_argv;
+#define rb_argv rb_get_argv()
 RUBY_EXTERN VALUE rb_argv0;
+VALUE rb_get_argv(void);
 void *rb_load_file(const char*);
 void ruby_script(const char*);
 void ruby_prog_init(void);

Modified: MacRuby/trunk/include/ruby/missing.h
===================================================================
--- MacRuby/trunk/include/ruby/missing.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/include/ruby/missing.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -87,6 +87,10 @@
 extern double lgamma_r(double, int *);
 #endif
 
+#ifndef HAVE_CBRT
+extern double cbrt(double);
+#endif
+
 #ifndef isinf
 # ifndef HAVE_ISINF
 #  if defined(HAVE_FINITE) && defined(HAVE_ISNAN)

Modified: MacRuby/trunk/include/ruby/node.h
===================================================================
--- MacRuby/trunk/include/ruby/node.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/include/ruby/node.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -480,6 +480,11 @@
 #define NOEX_WITH(n, s) ((s << 8) | n)
 #define NOEX_WITH_SAFE(n) NOEX_WITH(n, rb_safe_level())
 
+#define CALL_PUBLIC 0
+#define CALL_FCALL  1
+#define CALL_VCALL  2
+#define CALL_SUPER  3
+
 VALUE rb_parser_new(void);
 VALUE rb_parser_end_seen_p(VALUE);
 VALUE rb_parser_encoding(VALUE);

Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/include/ruby/ruby.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -62,6 +62,10 @@
 # include <intrinsics.h>
 #endif
 
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
 #include <stddef.h>
 #include <stdio.h>
 
@@ -175,6 +179,14 @@
 # define OFFT2NUM(v) INT2NUM(v)
 #endif
 
+#if SIZEOF_SIZE_T > SIZEOF_LONG && defined(HAVE_LONG_LONG)
+# define SIZET2NUM(v) ULL2NUM(v)
+#elif SIZEOF_SIZE_T == SIZEOF_LONG
+# define SIZET2NUM(v) ULONG2NUM(v)
+#else
+# define SIZET2NUM(v) UINT2NUM(v)
+#endif
+
 #ifndef PIDT2NUM
 #define PIDT2NUM(v) LONG2NUM(v)
 #endif
@@ -197,7 +209,7 @@
 #define FIX2LONG(x) RSHIFT((SIGNED_VALUE)x,1)
 #define FIX2ULONG(x) ((((VALUE)(x))>>1)&LONG_MAX)
 #define FIXNUM_P(f) (((SIGNED_VALUE)(f))&FIXNUM_FLAG)
-#define POSFIXABLE(f) ((f) <= FIXNUM_MAX)
+#define POSFIXABLE(f) ((f) < FIXNUM_MAX+1)
 #define NEGFIXABLE(f) ((f) >= FIXNUM_MIN)
 #define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
 
@@ -235,60 +247,63 @@
 
 enum ruby_value_type {
     RUBY_T_NONE   = 0x00,
+
+    RUBY_T_OBJECT = 0x01,
+    RUBY_T_CLASS  = 0x02,
+    RUBY_T_MODULE = 0x03,
+    RUBY_T_FLOAT  = 0x04,
+    RUBY_T_STRING = 0x05,
+    RUBY_T_REGEXP = 0x06,
+    RUBY_T_ARRAY  = 0x07,
+    RUBY_T_HASH   = 0x08,
+    RUBY_T_STRUCT = 0x09,
+    RUBY_T_BIGNUM = 0x0a,
+    RUBY_T_FILE   = 0x0b,
+    RUBY_T_DATA   = 0x0c,
+    RUBY_T_MATCH  = 0x0d,
+    RUBY_T_COMPLEX  = 0x0e,
+    RUBY_T_RATIONAL = 0x0f,
+
+    RUBY_T_NIL    = 0x11,
+    RUBY_T_TRUE   = 0x12,
+    RUBY_T_FALSE  = 0x13,
+    RUBY_T_SYMBOL = 0x14,
+    RUBY_T_FIXNUM = 0x15,
+
+    RUBY_T_VALUES = 0x1a,
+    RUBY_T_UNDEF  = 0x1b,
+    RUBY_T_NODE   = 0x1c,
+    RUBY_T_ICLASS = 0x1d,
+
+    RUBY_T_MASK   = 0x1f,
+};
+
 #define T_NONE   RUBY_T_NONE
-
-    RUBY_T_NIL    = 0x01,
 #define T_NIL    RUBY_T_NIL
-    RUBY_T_OBJECT = 0x02,
 #define T_OBJECT RUBY_T_OBJECT
-    RUBY_T_CLASS  = 0x03,
 #define T_CLASS  RUBY_T_CLASS
-    RUBY_T_ICLASS = 0x04,
 #define T_ICLASS RUBY_T_ICLASS
-    RUBY_T_MODULE = 0x05,
 #define T_MODULE RUBY_T_MODULE
-    RUBY_T_FLOAT  = 0x06,
 #define T_FLOAT  RUBY_T_FLOAT
-    RUBY_T_STRING = 0x07,
 #define T_STRING RUBY_T_STRING
-    RUBY_T_REGEXP = 0x08,
 #define T_REGEXP RUBY_T_REGEXP
-    RUBY_T_ARRAY  = 0x09,
 #define T_ARRAY  RUBY_T_ARRAY
-    RUBY_T_FIXNUM = 0x0a,
-#define T_FIXNUM RUBY_T_FIXNUM
-    RUBY_T_HASH   = 0x0b,
 #define T_HASH   RUBY_T_HASH
-    RUBY_T_STRUCT = 0x0c,
 #define T_STRUCT RUBY_T_STRUCT
-    RUBY_T_BIGNUM = 0x0d,
 #define T_BIGNUM RUBY_T_BIGNUM
-    RUBY_T_FILE   = 0x0e,
 #define T_FILE   RUBY_T_FILE
-
-    RUBY_T_TRUE   = 0x10,
+#define T_FIXNUM RUBY_T_FIXNUM
 #define T_TRUE   RUBY_T_TRUE
-    RUBY_T_FALSE  = 0x11,
 #define T_FALSE  RUBY_T_FALSE
-    RUBY_T_DATA   = 0x12,
 #define T_DATA   RUBY_T_DATA
-    RUBY_T_MATCH  = 0x13,
 #define T_MATCH  RUBY_T_MATCH
-    RUBY_T_SYMBOL = 0x14,
 #define T_SYMBOL RUBY_T_SYMBOL
-
-    RUBY_T_VALUES = 0x1a,
+#define T_RATIONAL RUBY_T_RATIONAL
+#define T_COMPLEX RUBY_T_COMPLEX
 #define T_VALUES RUBY_T_VALUES
-    RUBY_T_BLOCK  = 0x1b,
-#define T_BLOCK  RUBY_T_BLOCK
-    RUBY_T_UNDEF  = 0x1c,
 #define T_UNDEF  RUBY_T_UNDEF
-    RUBY_T_NODE   = 0x1f,
 #define T_NODE   RUBY_T_NODE
-
-    RUBY_T_MASK   = 0x1f,
 #define T_MASK   RUBY_T_MASK
-};
 
 #define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK)
 
@@ -365,6 +380,12 @@
 # define NUM2OFFT(x) NUM2LONG(x)
 #endif
 
+#if defined(HAVE_LONG_LONG) && SIZEOF_SIZE_T > SIZEOF_LONG
+# define NUM2SIZET(x) ((size_t)NUM2ULL(x))
+#else
+# define NUM2SIZET(x) NUM2ULONG(x)
+#endif
+
 double rb_num2dbl(VALUE);
 #define NUM2DBL(x) rb_num2dbl((VALUE)(x))
 
@@ -582,6 +603,18 @@
     struct rb_io_t *fptr;
 };
 
+struct RRational {
+    struct RBasic basic;
+    VALUE num;
+    VALUE den;
+};
+
+struct RComplex {
+    struct RBasic basic;
+    VALUE real;
+    VALUE image;
+};
+
 struct RData {
     struct RBasic basic;
     void (*dmark)(void*);
@@ -663,6 +696,7 @@
      (long)((RBASIC(b)->flags >> RBIGNUM_EMBED_LEN_SHIFT) & \
             (RBIGNUM_EMBED_LEN_MASK >> RBIGNUM_EMBED_LEN_SHIFT)) : \
      RBIGNUM(b)->as.heap.len)
+/* LSB:RBIGNUM_DIGITS(b)[0], MSB:RBIGNUM_DIGITS(b)[RBIGNUM_LEN(b)-1] */
 #define RBIGNUM_DIGITS(b) \
     ((RBASIC(b)->flags & RBIGNUM_EMBED_FLAG) ? \
      RBIGNUM(b)->as.ary : \
@@ -677,6 +711,7 @@
 #define RSTRING(obj) (R_CAST(RString)(obj))
 #define RREGEXP(obj) (R_CAST(RRegexp)(obj))
 #if !WITH_OBJC
+# define RSTRING(obj) (R_CAST(RString)(obj))
 # define RARRAY(obj)  (R_CAST(RArray)(obj))
 # define RHASH(obj)   (R_CAST(RHash)(obj))
 #endif
@@ -684,6 +719,8 @@
 #define RSTRUCT(obj) (R_CAST(RStruct)(obj))
 #define RBIGNUM(obj) (R_CAST(RBignum)(obj))
 #define RFILE(obj)   (R_CAST(RFile)(obj))
+#define RRATIONAL(obj) (R_CAST(RRational)(obj))
+#define RCOMPLEX(obj) (R_CAST(RComplex)(obj))
 #define RVALUES(obj) (R_CAST(RValues)(obj))
 
 #define FL_SINGLETON FL_USER0
@@ -753,14 +790,8 @@
 #define ALLOCA_N(type,n) (type*)alloca(sizeof(type)*(n))
 
 #define MEMZERO(p,type,n) memset((p), 0, sizeof(type)*(n))
-#if 0//WITH_OBJC
-void *rb_gc_memmove(void *, const void *, size_t); 
-# define MEMCPY(p1,p2,type,n) rb_gc_memmove((p1), (p2), sizeof(type)*(n))
-# define MEMMOVE(p1,p2,type,n) rb_gc_memmove((p1), (p2), sizeof(type)*(n))
-#else
-# define MEMCPY(p1,p2,type,n) memcpy((p1), (p2), sizeof(type)*(n))
-# define MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n))
-#endif
+#define MEMCPY(p1,p2,type,n) memcpy((p1), (p2), sizeof(type)*(n))
+#define MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n))
 #define MEMCMP(p1,p2,type,n) memcmp((p1), (p2), sizeof(type)*(n))
 
 void rb_obj_infect(VALUE,VALUE);
@@ -883,15 +914,13 @@
 
 #ifdef __ia64
 void ruby_init_stack(VALUE*, void*);
-#define RUBY_INIT_STACK \
-    VALUE variable_in_this_stack_frame; \
-    ruby_init_stack(&variable_in_this_stack_frame, rb_ia64_bsp());
+#define ruby_init_stack(addr) ruby_init_stack(addr, rb_ia64_bsp())
 #else
 void ruby_init_stack(VALUE*);
+#endif
 #define RUBY_INIT_STACK \
     VALUE variable_in_this_stack_frame; \
     ruby_init_stack(&variable_in_this_stack_frame);
-#endif
 void ruby_init(void);
 void *ruby_options(int, char**);
 int ruby_run_node(void *);
@@ -920,6 +949,7 @@
 RUBY_EXTERN VALUE rb_cDir;
 RUBY_EXTERN VALUE rb_cData;
 RUBY_EXTERN VALUE rb_cFalseClass;
+RUBY_EXTERN VALUE rb_cEnumerator;
 RUBY_EXTERN VALUE rb_cFile;
 RUBY_EXTERN VALUE rb_cFixnum;
 RUBY_EXTERN VALUE rb_cFloat;
@@ -934,6 +964,8 @@
 RUBY_EXTERN VALUE rb_cNumeric;
 RUBY_EXTERN VALUE rb_cProc;
 RUBY_EXTERN VALUE rb_cRange;
+RUBY_EXTERN VALUE rb_cRational;
+RUBY_EXTERN VALUE rb_cComplex;
 RUBY_EXTERN VALUE rb_cRegexp;
 RUBY_EXTERN VALUE rb_cStat;
 RUBY_EXTERN VALUE rb_cString;

Modified: MacRuby/trunk/include/ruby/win32.h
===================================================================
--- MacRuby/trunk/include/ruby/win32.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/include/ruby/win32.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -89,6 +89,9 @@
 #  define _UINTPTR_T_DEFINED
 # endif
 #endif
+#ifndef __MINGW32__
+# define mode_t int
+#endif
 
 #ifdef _M_IX86
 # define WIN95 1

Modified: MacRuby/trunk/inits.c
===================================================================
--- MacRuby/trunk/inits.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/inits.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   inits.c -
 
-  $Author: akr $
+  $Author: tadf $
   created at: Tue Dec 28 16:01:58 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -15,6 +15,7 @@
 void Init_Bignum(void);
 void Init_Binding(void);
 void Init_Comparable(void);
+void Init_Complex(void);
 void Init_transcode(void);
 void Init_Dir(void);
 void Init_Enumerable(void);
@@ -39,6 +40,7 @@
 void Init_process(void);
 void Init_Random(void);
 void Init_Range(void);
+void Init_Rational(void);
 void Init_Regexp(void);
 void Init_signal(void);
 void Init_String(void);
@@ -100,6 +102,8 @@
     Init_ISeq();
     Init_Thread();
     Init_Cont();
+    Init_Rational();
+    Init_Complex();
     Init_version();
     Init_PostGC();
 #if WITH_OBJC

Modified: MacRuby/trunk/insns.def
===================================================================
--- MacRuby/trunk/insns.def	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/insns.def	2008-05-18 08:10:19 UTC (rev 199)
@@ -237,28 +237,11 @@
 DEFINE_INSN
 setconstant
 (ID id)
-(VALUE val, VALUE klass)
+(VALUE val, VALUE cbase)
 ()
 {
-    if (klass == Qnil) {
-	klass = vm_get_cbase(th);
-    }
-    if (NIL_P(klass)) {
-	rb_raise(rb_eTypeError, "no class/module to define constant");
-    }
-
-    switch (TYPE(klass)) {
-      case T_CLASS:
-      case T_MODULE:
-	break;
-      default: {
-	volatile VALUE tmp = rb_obj_as_string(klass);
-	rb_raise(rb_eTypeError, "%s is not a class/module",
-		 RSTRING_CPTR(tmp));
-      }
-    }
-
-    rb_const_set(klass, id, val);
+    vm_check_if_namespace(cbase);
+    rb_const_set(cbase, id, val);
     INC_VM_STATE_VERSION();
 }
 
@@ -325,6 +308,20 @@
 
 /**
   @c put
+  @e put cbase.
+  @j \x83X\x83^\x83b\x83N\x82\xC9 cbase \x82\xF0\x83v\x83b\x83V\x83\x85\x82\xB7\x82\xE9\x81B
+ */
+DEFINE_INSN
+putcbase
+()
+()
+(VALUE val)
+{
+    val = vm_get_cbase(th);
+}
+
+/**
+  @c put
   @e put some object.
      i.e. Fixnum, true, false, nil, and so on.
   @j \x83I\x83u\x83W\x83F\x83N\x83g val \x82\xF0\x83X\x83^\x83b\x83N\x82Ƀv\x83b\x83V\x83\x85\x82\xB7\x82\xE9\x81B
@@ -965,9 +962,7 @@
 	    super = rb_cObject;
 	}
 
-	if (cbase == Qnil) {
-	    cbase = vm_get_cbase(th);
-	}
+	vm_check_if_namespace(cbase);
 
 	/* find klass */
 	if (rb_const_defined_at(cbase, id)) {
@@ -1003,10 +998,9 @@
       case 2:
 	/* val is dummy.  classdef returns class scope value */
 	/* super is dummy */
-	if (cbase == Qnil) {
-	    cbase = vm_get_cbase(th);
-	}
 
+	vm_check_if_namespace(cbase);
+
 	/* find klass */
 	if (rb_const_defined_at(cbase, id)) {
 	    klass = rb_const_get_at(cbase, id);

Modified: MacRuby/trunk/instruby.rb
===================================================================
--- MacRuby/trunk/instruby.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/instruby.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -80,7 +80,7 @@
   $mflags.unshift(*mflags)
 
   def $mflags.set?(flag)
-    grep(/\A-(?!-).*#{'%s' % flag}/i) { return true }
+    grep(/\A-(?!-).*#{flag.chr}/i) { return true }
     false
   end
   def $mflags.defined?(var)
@@ -183,9 +183,13 @@
   end
 end
 
-def open_for_install(path, mode, &block)
+def open_for_install(path, mode)
+  data = open(realpath = with_destdir(path), "rb") {|f| f.read} rescue nil
+  newdata = yield
   unless $dryrun
-    open(realpath = with_destdir(path), "wb", mode, &block)
+    unless newdata == data
+      open(realpath, "wb", mode) {|f| f.write newdata}
+    end
     File.chmod(mode, realpath)
   end
   $installed_list.puts path if $installed_list
@@ -290,7 +294,7 @@
   makedirs [bindir, rubylibdir]
 
   ruby_shebang = File.join(bindir, ruby_install_name)
-  if $cmdtype
+  if File::ALT_SEPARATOR
     ruby_bin = ruby_shebang.tr(File::SEPARATOR, File::ALT_SEPARATOR)
   end
   for src in Dir["bin/*"]
@@ -304,17 +308,17 @@
     open(src, "rb") do |f|
       shebang = f.gets
       body = f.read
-      end
+    end
     shebang.sub!(/^\#!.*?ruby\b/) {"#!" + ruby_shebang}
     shebang.sub!(/\r$/, '')
     body.gsub!(/\r$/, '')
 
     cmd = File.join(bindir, name)
     cmd << ".#{$cmdtype}" if $cmdtype
-    open_for_install(cmd, $script_mode) do |f|
+    open_for_install(cmd, $script_mode) do
       case $cmdtype
       when "bat"
-        f.print((<<EOH+shebang+body+<<EOF).gsub(/$/, "\r"))
+        "#{<<EOH}#{shebang}#{body}#{<<EOF}".gsub(/$/, "\r")
 @echo off
 @if not "%~d0" == "~d0" goto WinNT
 #{ruby_bin} -x "#{cmd}" %1 %2 %3 %4 %5 %6 %7 %8 %9
@@ -327,12 +331,12 @@
 :endofruby
 EOF
       when "cmd"
-        f.print(<<EOH, shebang, body)
+        "#{<<EOH}#{shebang}#{body}"
 @"%~dp0#{ruby_install_name}" -x "%~f0" %*
 @exit /b %ERRORLEVEL%
 EOH
       else
-        f.print shebang, body
+        shebang + body
       end
     end
   end

Modified: MacRuby/trunk/io.c
===================================================================
--- MacRuby/trunk/io.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/io.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   io.c -
 
-  $Author: nobu $
+  $Author: akr $
   created at: Fri Oct 15 18:08:59 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -14,6 +14,7 @@
 #include "ruby/ruby.h"
 #include "ruby/io.h"
 #include "ruby/signal.h"
+#include "vm_core.h"
 #include <ctype.h>
 #include <errno.h>
 
@@ -123,7 +124,7 @@
 
 static VALUE argf;
 
-static ID id_write, id_read, id_getc, id_flush, id_encode;
+static ID id_write, id_read, id_getc, id_flush, id_encode, id_readpartial;
 
 struct timeval rb_time_interval(VALUE);
 
@@ -138,8 +139,21 @@
     rb_encoding *enc, *enc2;
 };
 
-#define ARGF (*(struct argf *)DATA_PTR(argf))
+static int max_file_descriptor = NOFILE;
+#define UPDATE_MAXFD(fd) \
+    do { \
+        if (max_file_descriptor < (fd)) max_file_descriptor = (fd); \
+    } while (0)
+#define UPDATE_MAXFD_PIPE(filedes) \
+    do { \
+        UPDATE_MAXFD((filedes)[0]); \
+        UPDATE_MAXFD((filedes)[1]); \
+    } while (0)
 
+
+#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
+#define ARGF argf_of(argf)
+
 #ifdef _STDIO_USES_IOSTREAM  /* GNU libc */
 #  ifdef _IO_fpos_t
 #    define STDIO_READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr != (fp)->_IO_read_end)
@@ -479,7 +493,10 @@
 static int
 wsplit_p(rb_io_t *fptr)
 {
+#if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
     int r;
+#endif
+
     if (!(fptr->mode & FMODE_WSPLIT_INITIALIZED)) {
         struct stat buf;
         if (fstat(fptr->fd, &buf) == 0 &&
@@ -500,21 +517,22 @@
     int fd;
     void *buf;
     size_t capa;
-    int is_read;
 };
 
 static VALUE
-internal_io_func(void *ptr)
+internal_read_func(void *ptr)
 {
     struct io_internal_struct *iis = (struct io_internal_struct*)ptr;
-    if (iis->is_read) {
-	return read(iis->fd, iis->buf, iis->capa);
-    }
-    else {
-	return write(iis->fd, iis->buf, iis->capa);
-    }
+    return read(iis->fd, iis->buf, iis->capa);
 }
 
+static VALUE
+internal_write_func(void *ptr)
+{
+    struct io_internal_struct *iis = (struct io_internal_struct*)ptr;
+    return write(iis->fd, iis->buf, iis->capa);
+}
+
 static int
 rb_read_internal(int fd, void *buf, size_t count)
 {
@@ -522,9 +540,8 @@
     iis.fd = fd;
     iis.buf = buf;
     iis.capa = count;
-    iis.is_read = 1;
 
-    return rb_thread_blocking_region(internal_io_func, &iis, RB_UBF_DFL, 0);
+    return rb_thread_blocking_region(internal_read_func, &iis, RB_UBF_DFL, 0);
 }
 
 static int
@@ -534,9 +551,8 @@
     iis.fd = fd;
     iis.buf = buf;
     iis.capa = count;
-    iis.is_read = 0;
 
-    return rb_thread_blocking_region(internal_io_func, &iis, RB_UBF_DFL, 0);
+    return rb_thread_blocking_region(internal_write_func, &iis, RB_UBF_DFL, 0);
 }
 
 static int
@@ -573,8 +589,8 @@
         return 0;
     }
     if (0 <= r) {
-        fptr->wbuf_off = r;
-        fptr->wbuf_len = r;
+        fptr->wbuf_off += r;
+        fptr->wbuf_len -= r;
         errno = EAGAIN;
     }
     if (rb_io_wait_writable(fptr->fd)) {
@@ -684,12 +700,12 @@
 	/* the methods in transcode.c are static, so call indirectly */
 	/* Can't use encode! because puts writes a frozen newline */
 	if (fptr->enc2) {
-	    str = rb_funcall(str, id_encode, 2, 
+	    str = rb_funcall(str, id_encode, 2,
 			     rb_enc_from_encoding(fptr->enc2),
 			     rb_enc_from_encoding(fptr->enc));
 	}
 	else {
-	    str = rb_funcall(str, id_encode, 1, 
+	    str = rb_funcall(str, id_encode, 1,
 			     rb_enc_from_encoding(fptr->enc));
 	}
     }
@@ -1355,7 +1371,7 @@
     if (fptr->enc2) {
 	/* two encodings, so transcode from enc2 to enc */
 	/* the methods in transcode.c are static, so call indirectly */
-	str = rb_funcall(str, id_encode, 2, 
+	str = rb_funcall(str, id_encode, 2,
 			 rb_enc_from_encoding(fptr->enc),
 			 rb_enc_from_encoding(fptr->enc2));
     }
@@ -1389,7 +1405,7 @@
 	READ_CHECK(fptr);
 	n = io_fread(str, bytes, fptr);
 	if (n == 0 && bytes == 0) {
-            break;
+	    break;
 	}
 	bytes += n;
 #if !WITH_OBJC
@@ -1517,7 +1533,7 @@
  *  When readpartial doesn't blocks, it returns or raises immediately.
  *  If the buffer is not empty, it returns the data in the buffer.
  *  Otherwise if the stream has some content,
- *  it returns the data in the stream. 
+ *  it returns the data in the stream.
  *  Otherwise if the stream is reached to EOF, it raises EOFError.
  *
  *     r, w = IO.pipe           #               buffer          pipe content
@@ -1671,7 +1687,7 @@
     if (NIL_P(length)) {
 	if (!NIL_P(str)) StringValue(str);
 	GetOpenFile(io, fptr);
-	rb_io_check_readable(fptr);	
+	rb_io_check_readable(fptr);
 	return read_all(fptr, remain_size(fptr), str);
     }
     len = NUM2LONG(length);
@@ -1921,7 +1937,7 @@
 	}
 	if (fptr->enc2) {
             VALUE rs2;
-	    rs2 = rb_funcall(rs, id_encode, 2, 
+	    rs2 = rb_funcall(rs, id_encode, 2,
 			    rb_enc_from_encoding(fptr->enc2),
 			    rb_enc_from_encoding(fptr->enc));
             if (!RTEST(rb_str_equal(rs, rs2))) {
@@ -1982,7 +1998,7 @@
 	while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
 	    if (c == newline) {
 		const char *s, *p, *pp;
-		
+
 		if (RSTRING_LEN(str) < rslen) continue;
 		s = RSTRING_PTR(str);
 		p = s +  RSTRING_LEN(str) - rslen;
@@ -2110,9 +2126,9 @@
  *     $.                         #=> 1
  *     f.lineno = 1000
  *     f.lineno                   #=> 1000
- *     $. # lineno of last read   #=> 1
+ *     $.                         #=> 1         # lineno of last read
  *     f.gets                     #=> "This is line two\n"
- *     $. # lineno of last read   #=> 1001
+ *     $.                         #=> 1001      # lineno of last read
  */
 
 static VALUE
@@ -2259,46 +2275,171 @@
     return io;
 }
 
+static VALUE
+io_getc(rb_io_t *fptr, rb_encoding *enc)
+{
+    int r, n, cr = 0;
+    VALUE str;
+
+    if (io_fillbuf(fptr) < 0) {
+	return Qnil;
+    }
+#if WITH_OBJC
+    str = rb_str_new(fptr->rbuf+fptr->rbuf_off, 1);
+    fptr->rbuf_off += 1;
+    fptr->rbuf_len -= 1;
+#else
+    if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf[fptr->rbuf_off])) {
+	str = rb_str_new(fptr->rbuf+fptr->rbuf_off, 1);
+	fptr->rbuf_off += 1;
+	fptr->rbuf_len -= 1;
+	cr = ENC_CODERANGE_7BIT;
+    }
+    else {
+	r = rb_enc_precise_mbclen(fptr->rbuf+fptr->rbuf_off, fptr->rbuf+fptr->rbuf_off+fptr->rbuf_len, enc);
+	if (MBCLEN_CHARFOUND_P(r) &&
+	    (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf_len) {
+	    str = rb_str_new(fptr->rbuf+fptr->rbuf_off, n);
+	    fptr->rbuf_off += n;
+	    fptr->rbuf_len -= n;
+	    cr = ENC_CODERANGE_VALID;
+	}
+	else if (MBCLEN_NEEDMORE_P(r)) {
+	    str = rb_str_new(fptr->rbuf+fptr->rbuf_off, fptr->rbuf_len);
+	    fptr->rbuf_len = 0;
+	  getc_needmore:
+	    if (io_fillbuf(fptr) != -1) {
+		rb_str_cat(str, fptr->rbuf+fptr->rbuf_off, 1);
+		fptr->rbuf_off++;
+		fptr->rbuf_len--;
+		r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
+		if (MBCLEN_NEEDMORE_P(r)) {
+		    goto getc_needmore;
+		}
+		else if (MBCLEN_CHARFOUND_P(r)) {
+		    cr = ENC_CODERANGE_VALID;
+		}
+	    }
+	}
+	else {
+	    str = rb_str_new(fptr->rbuf+fptr->rbuf_off, 1);
+	    fptr->rbuf_off++;
+	    fptr->rbuf_len--;
+	}
+    }
+    if (!cr) cr = ENC_CODERANGE_BROKEN;
+#endif
+    str = io_enc_str(str, fptr);
+#if !WITH_OBJC
+    if (!fptr->enc2) {
+	ENC_CODERANGE_SET(str, cr);
+    }
+#endif
+    return str;
+}
+
 /*
  *  call-seq:
- *     str.lines(sep=$/)     => anEnumerator
- *     str.lines(limit)      => anEnumerator
- *     str.lines(sep, limit) => anEnumerator
- *  
- *  Returns an enumerator that gives each line in the string.
+ *     ios.each_char {|c| block }  => ios
+ *
+ *  Calls the given block once for each character in <em>ios</em>,
+ *  passing the character as an argument. The stream must be opened for
+ *  reading or an <code>IOError</code> will be raised.
+ *
+ *     f = File.new("testfile")
+ *     f.each_char {|c| print c, ' ' }   #=> #<File:testfile>
+ */
+
+static VALUE
+rb_io_each_char(VALUE io)
+{
+    rb_io_t *fptr;
+    rb_encoding *enc;
+    VALUE c;
+
+    RETURN_ENUMERATOR(io, 0, 0);
+    GetOpenFile(io, fptr);
+    rb_io_check_readable(fptr);
+
+    enc = io_input_encoding(fptr);
+    READ_CHECK(fptr);
+    while (!NIL_P(c = io_getc(fptr, enc))) {
+        rb_yield(c);
+    }
+    return io;
+}
+
+
+
+/*
+ *  call-seq:
+ *     ios.lines(sep=$/)     => anEnumerator
+ *     ios.lines(limit)      => anEnumerator
+ *     ios.lines(sep, limit) => anEnumerator
+ *
+ *  Returns an enumerator that gives each line in <em>ios</em>.
+ *  The stream must be opened for reading or an <code>IOError</code>
+ *  will be raised.
+ *
+ *     f = File.new("testfile")
+ *     f.lines.to_a  #=> ["foo\n", "bar\n"]
+ *     f.rewind
+ *     f.lines.sort  #=> ["bar\n", "foo\n"]
+ */
+
+static VALUE
+rb_io_lines(int argc, VALUE *argv, VALUE io)
+{
+    return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv);
+}
+
+/*
+ *  call-seq:
+ *     ios.bytes   => anEnumerator
+ *
+ *  Returns an enumerator that gives each byte (0..255) in <em>ios</em>.
+ *  The stream must be opened for reading or an <code>IOError</code>
+ *  will be raised.
  *     
- *     "foo\nbar\n".lines.to_a   #=> ["foo\n", "bar\n"]
- *     "foo\nb ar".lines.sort    #=> ["b ar", "foo\n"]
+ *     f = File.new("testfile")
+ *     f.bytes.to_a  #=> [104, 101, 108, 108, 111]
+ *     f.rewind
+ *     f.bytes.sort  #=> [101, 104, 108, 108, 111]
  */
 
 static VALUE
-rb_io_lines(int argc, VALUE *argv, VALUE str)
+rb_io_bytes(VALUE io)
 {
-    return rb_enumeratorize(str, ID2SYM(rb_intern("each_line")), argc, argv);
+    return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0);
 }
 
 /*
  *  call-seq:
- *     str.bytes   => anEnumerator
+ *     ios.chars   => anEnumerator
  *  
- *  Returns an enumerator that gives each byte in the string.
+ *  Returns an enumerator that gives each character in <em>ios</em>.
+ *  The stream must be opened for reading or an <code>IOError</code>
+ *  will be raised.
  *     
- *     "hello".bytes.to_a        #=> [104, 101, 108, 108, 111]
+ *     f = File.new("testfile")
+ *     f.chars.to_a  #=> ["h", "e", "l", "l", "o"]
+ *     f.rewind
+ *     f.chars.sort  #=> ["e", "h", "l", "l", "o"]
  */
 
 static VALUE
-rb_io_bytes(VALUE str)
+rb_io_chars(VALUE io)
 {
-    return rb_enumeratorize(str, ID2SYM(rb_intern("each_byte")), 0, 0);
+    return rb_enumeratorize(io, ID2SYM(rb_intern("each_char")), 0, 0);
 }
 
 /*
  *  call-seq:
  *     ios.getc   => fixnum or nil
- *  
+ *
  *  Reads a one-character string from <em>ios</em>. Returns
  *  <code>nil</code> if called at end of file.
- *     
+ *
  *     f = File.new("testfile")
  *     f.getc   #=> "8"
  *     f.getc   #=> "1"
@@ -2308,8 +2449,6 @@
 rb_io_getc(VALUE io)
 {
     rb_io_t *fptr;
-    int r, n;
-    VALUE str;
     rb_encoding *enc;
 
     GetOpenFile(io, fptr);
@@ -2317,44 +2456,8 @@
 
     enc = io_input_encoding(fptr);
     READ_CHECK(fptr);
-    if (io_fillbuf(fptr) < 0) {
-	return Qnil;
-    }
-#if WITH_OBJC
-    /* FIXME */
-    if (0) {
-    }
-#else
-    r = rb_enc_precise_mbclen(fptr->rbuf+fptr->rbuf_off, fptr->rbuf+fptr->rbuf_off+fptr->rbuf_len, enc);
-    if (MBCLEN_CHARFOUND_P(r) &&
-        (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf_len) {
-	str = rb_str_new(fptr->rbuf+fptr->rbuf_off, n);
-	fptr->rbuf_off += n;
-	fptr->rbuf_len -= n;
-    }
-    else if (MBCLEN_NEEDMORE_P(r)) {
-	str = rb_str_new(fptr->rbuf+fptr->rbuf_off, fptr->rbuf_len);
-        fptr->rbuf_len = 0;
-      getc_needmore:
-        if (io_fillbuf(fptr) != -1) {
-            rb_str_cat(str, fptr->rbuf+fptr->rbuf_off, 1);
-            fptr->rbuf_off++;
-            fptr->rbuf_len--;
-            r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
-            if (MBCLEN_NEEDMORE_P(r)) {
-                goto getc_needmore;
-            }
-        }
-    }
-#endif
-    else {
-	str = rb_str_new(fptr->rbuf+fptr->rbuf_off, 1);
-	fptr->rbuf_off++;
-	fptr->rbuf_len--;
-    }
-    return io_enc_str(str, fptr);
+    return io_getc(fptr, enc);
 }
-
 int
 rb_getc(FILE *f)
 {
@@ -2468,22 +2571,20 @@
 VALUE
 rb_io_ungetc(VALUE io, VALUE c)
 {
-    rb_encoding *enc;
     rb_io_t *fptr;
 
     GetOpenFile(io, fptr);
     rb_io_check_readable(fptr);
     if (NIL_P(c)) return Qnil;
-    enc = io_read_encoding(fptr);
     if (FIXNUM_P(c)) {
 	int cc = FIX2INT(c);
 #if WITH_OBJC
 	c = rb_str_new((char *)&cc, 1);
 #else
+	rb_encoding *enc = io_read_encoding(fptr);
 	char buf[16];
 
-	rb_enc_mbcput(cc, buf, enc);
-	c = rb_str_new(buf, rb_enc_codelen(cc, enc));
+	c = rb_str_new(buf, rb_enc_mbcput(cc, buf, enc));
 #endif
     }
     else {
@@ -3187,7 +3288,7 @@
     return flags;
 }
 
-static int
+int
 rb_io_mode_modenum(const char *mode)
 {
     int flags = 0;
@@ -3262,7 +3363,7 @@
     const char *p0, *p1;
     char *enc2name;
 #if WITH_OBJC
-    rb_encoding *enc1, enc2;
+    rb_encoding *enc1, *enc2;
 #else
     int idx, idx2;
 #endif
@@ -3380,6 +3481,7 @@
 	    rb_sys_fail(fname);
 	}
     }
+    UPDATE_MAXFD(fd);
     return fd;
 }
 
@@ -3585,7 +3687,7 @@
 
 #ifdef HAVE_FORK
 struct popen_arg {
-    struct rb_exec_arg exec;
+    struct rb_exec_arg *execp;
     int modef;
     int pair[2];
     int write_pair[2];
@@ -3622,26 +3724,40 @@
     }
 }
 
+void
+rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
+{
+    int fd, ret;
+    int max = max_file_descriptor;
+    if (max < maxhint)
+        max = maxhint;
+    for (fd = lowfd; fd <= max; fd++) {
+        if (!NIL_P(noclose_fds) &&
+            RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd))))
+            continue;
+#ifdef FD_CLOEXEC
+	ret = fcntl(fd, F_GETFD);
+	if (ret != -1 && !(ret & FD_CLOEXEC)) {
+            fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
+        }
+#else
+	close(fd);
+#endif
+    }
+}
+
 static int
 popen_exec(void *pp)
 {
     struct popen_arg *p = (struct popen_arg*)pp;
-    int fd;
 
-    rb_thread_atfork();
-    popen_redirect(p);
-    for (fd = 3; fd < NOFILE; fd++) {
-#ifdef FD_CLOEXEC
-	if (fcntl(fd, F_GETFD) & FD_CLOEXEC) continue;
-#endif
-	close(fd);
-    }
-    return rb_exec(&p->exec);
+    rb_thread_atfork_before_exec();
+    return rb_exec(p->execp);
 }
 #endif
 
 static VALUE
-pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
+pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *mode)
 {
     int modef = rb_io_mode_flags(mode);
     int pid = 0;
@@ -3656,12 +3772,36 @@
     int openmode = rb_io_mode_modenum(mode);
     const char *exename = NULL;
     volatile VALUE cmdbuf;
+    struct rb_exec_arg sarg;
 #endif
     FILE *fp = 0;
     int fd = -1;
     int write_fd = -1;
+    const char *cmd = 0;
+    int argc;
+    VALUE *argv;
 
+    if (prog)
+        cmd = StringValueCStr(prog);
+
+    if (!eargp) {
+        /* fork : IO.popen("-") */
+        argc = 0;
+        argv = 0;
+    }
+    else if (eargp->argc) {
+        /* no shell : IO.popen([prog, arg0], arg1, ...) */
+        argc = eargp->argc;
+        argv = eargp->argv;
+    }
+    else {
+        /* with shell : IO.popen(prog) */
+        argc = 0;
+        argv = 0;
+    }
+
 #if defined(HAVE_FORK)
+    arg.execp = eargp;
     arg.modef = modef;
     arg.pair[0] = arg.pair[1] = -1;
     arg.write_pair[0] = arg.write_pair[1] = -1;
@@ -3669,6 +3809,7 @@
       case FMODE_READABLE|FMODE_WRITABLE:
         if (pipe(arg.write_pair) < 0)
             rb_sys_fail(cmd);
+        UPDATE_MAXFD_PIPE(arg.write_pair);
         if (pipe(arg.pair) < 0) {
             int e = errno;
             close(arg.write_pair[0]);
@@ -3676,29 +3817,38 @@
             errno = e;
             rb_sys_fail(cmd);
         }
+        UPDATE_MAXFD_PIPE(arg.pair);
+        if (eargp) {
+            rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(arg.write_pair[0]));
+            rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(arg.pair[1]));
+        }
 	break;
       case FMODE_READABLE:
         if (pipe(arg.pair) < 0)
             rb_sys_fail(cmd);
+        UPDATE_MAXFD_PIPE(arg.pair);
+        if (eargp)
+            rb_exec_arg_addopt(eargp, INT2FIX(1), INT2FIX(arg.pair[1]));
 	break;
       case FMODE_WRITABLE:
         if (pipe(arg.pair) < 0)
             rb_sys_fail(cmd);
+        UPDATE_MAXFD_PIPE(arg.pair);
+        if (eargp)
+            rb_exec_arg_addopt(eargp, INT2FIX(0), INT2FIX(arg.pair[0]));
 	break;
       default:
         rb_sys_fail(cmd);
     }
-    if (cmd) {
-	arg.exec.argc = argc;
-	arg.exec.argv = argv;
-	arg.exec.prog = cmd;
-	pid = rb_fork(&status, popen_exec, &arg);
+    if (eargp) {
+        rb_exec_arg_fixup(arg.execp);
+	pid = rb_fork(&status, popen_exec, &arg, arg.execp->redirect_fds);
     }
     else {
 	fflush(stdin);		/* is it really needed? */
 	rb_io_flush(rb_stdout);
 	rb_io_flush(rb_stderr);
-	pid = rb_fork(&status, 0, 0);
+	pid = rb_fork(&status, 0, 0, Qnil);
 	if (pid == 0) {		/* child */
 	    popen_redirect(&arg);
 	    rb_io_synchronized(RFILE(orig_stdout)->fptr);
@@ -3753,6 +3903,10 @@
 	cmd = rb_w32_join_argv(RSTRING_PTR(cmdbuf), args);
 	rb_str_resize(argbuf, 0);
     }
+    if (eargp) {
+	rb_exec_arg_fixup(eargp);
+	rb_run_exec_options(eargp, &sarg);
+    }
     while ((pid = rb_w32_pipe_exec(cmd, exename, openmode, &fd, &write_fd)) == -1) {
 	/* exec failed */
 	switch (errno) {
@@ -3763,16 +3917,26 @@
 	    rb_thread_sleep(1);
 	    break;
 	  default:
+	    if (eargp)
+		rb_run_exec_options(&sarg, NULL);
 	    rb_sys_fail(cmd);
 	    break;
 	}
     }
+    if (eargp)
+	rb_run_exec_options(&sarg, NULL);
 #else
     if (argc) {
 	prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
 	cmd = StringValueCStr(prog);
     }
+    if (eargp) {
+	rb_exec_arg_fixup(eargp);
+	rb_run_exec_options(eargp, &sarg);
+    }
     fp = popen(cmd, mode);
+    if (eargp)
+	rb_run_exec_options(&sarg, NULL);
     if (!fp) rb_sys_fail(RSTRING_PTR(prog));
     fd = fileno(fp);
 #endif
@@ -3805,27 +3969,30 @@
 static VALUE
 pipe_open_v(int argc, VALUE *argv, const char *mode)
 {
-    VALUE prog = rb_check_argv(argc, argv);
-    const char *cmd;
-
-    if (!RB_GC_GUARD(prog)) prog = argv[0];
-    cmd = StringValueCStr(prog);
-    return pipe_open(cmd, argc, argv, mode);
+    VALUE prog;
+    struct rb_exec_arg earg;
+    prog = rb_exec_arg_init(argc, argv, Qfalse, &earg);
+    return pipe_open(&earg, prog, mode);
 }
 
 static VALUE
 pipe_open_s(VALUE prog, const char *mode)
 {
-    const char *cmd = (rb_check_argv(1, &prog), RSTRING_PTR(prog));
+    const char *cmd = RSTRING_CPTR(prog);
+    int argc = 1;
+    VALUE *argv = &prog;
+    struct rb_exec_arg earg;
 
-    if (strcmp("-", cmd) == 0) {
+    if (RSTRING_CLEN(prog) == 1 && cmd[0] == '-') {
 #if !defined(HAVE_FORK)
 	rb_raise(rb_eNotImpError,
 		 "fork() function is unimplemented on this machine");
 #endif
-	cmd = 0;
+        return pipe_open(0, 0, mode);
     }
-    return pipe_open(cmd, 0, &prog, mode);
+
+    rb_exec_arg_init(argc, argv, Qtrue, &earg);
+    return pipe_open(&earg, prog, mode);
 }
 
 /*
@@ -3838,7 +4005,9 @@
  *  <code>IO</code> object.  If _cmd_ is a +String+
  *  ``<code>-</code>'', then a new instance of Ruby is started as the
  *  subprocess.  If <i>cmd</i> is an +Array+ of +String+, then it will
- *  be used as the subprocess's +argv+ bypassing a shell.  The default
+ *  be used as the subprocess's +argv+ bypassing a shell.
+ *  The array can contains a hash at first for environments and
+ *  a hash at last for options similar to <code>spawn</code>.  The default
  *  mode for the new file object is ``r'', but <i>mode</i> may be set
  *  to any of the modes listed in the description for class IO.
  *
@@ -4028,7 +4197,7 @@
  *  the specified mode (defaulting to ``<code>r</code>'').
  *
  *  The mode_enc is
- *  either a string or an integer.  If it is an integer, it must be 
+ *  either a string or an integer.  If it is an integer, it must be
  *  bitwise-or of open(2) flags, such as File::RDWR or File::EXCL.
  *  If it is a string, it is either "mode", "mode:ext_enc", or
  *  "mode:ext_enc:int_enc".
@@ -4050,7 +4219,7 @@
  *  to int_enc then tagged with the int_enc in read mode,
  *  and in write mode, the output string will be
  *  converted from int_enc to ext_enc before writing.
- *  
+ *
  *  If a file is being created, its initial permissions may be
  *  set using the integer third parameter.
  *
@@ -4173,6 +4342,24 @@
 }
 
 static VALUE
+rb_io_open_with_args(int argc, VALUE *argv)
+{
+    const char *mode;
+    VALUE pname, pmode;
+
+    if (rb_scan_args(argc, argv, "11", &pname, &pmode) == 1) {
+	mode = "r";
+    }
+    else if (FIXNUM_P(pmode)) {
+	mode = rb_io_modenum_mode(FIX2INT(pmode));
+    }
+    else {
+	mode = StringValueCStr(pmode);
+    }
+    return rb_io_open(StringValueCStr(pname), mode);
+}
+
+static VALUE
 io_reopen(VALUE io, VALUE nfile)
 {
     rb_io_t *fptr, *orig;
@@ -4548,6 +4735,9 @@
 static VALUE
 rb_f_putc(VALUE recv, VALUE ch)
 {
+    if (recv == rb_stdout) {
+	return rb_io_putc(recv, ch);
+    }
     return rb_funcall2(rb_stdout, rb_intern("putc"), 1, &ch);
 }
 
@@ -4557,11 +4747,13 @@
     VALUE tmp;
     long i;
 
+    if (recur) {
+	tmp = rb_str_new2("[...]");
+	rb_io_puts(1, &tmp, out);
+	return Qnil;
+    }
     for (i=0; i<RARRAY_LEN(ary); i++) {
 	tmp = RARRAY_AT(ary, i);
-	if (recur) {
-	    tmp = rb_str_new2("[...]");
-	}
 	rb_io_puts(1, &tmp, out);
     }
     return Qnil;
@@ -4625,8 +4817,11 @@
  */
 
 static VALUE
-rb_f_puts(int argc, VALUE *argv)
+rb_f_puts(int argc, VALUE *argv, VALUE recv)
 {
+    if (recv == rb_stdout) {
+	return rb_io_puts(argc, argv, recv);
+    }
     return rb_funcall2(rb_stdout, rb_intern("puts"), argc, argv);
 }
 
@@ -4705,10 +4900,12 @@
 {
     VALUE out;
 
-    if (rb_scan_args(argc, argv, "01", &out) == 0) {
+    if (argc == 0) {
 	out = rb_stdout;
     }
-
+    else {
+	rb_scan_args(argc, argv, "01", &out);
+    }
     rb_io_write(out, self);
 
     return Qnil;
@@ -4841,6 +5038,7 @@
     orig = rb_io_check_io(fnum);
     if (NIL_P(orig)) {
 	fd = NUM2INT(fnum);
+        UPDATE_MAXFD(fd);
 	if (argc != 2) {
 #if defined(HAVE_FCNTL) && defined(F_GETFL)
 	    flags = fcntl(fd, F_GETFL);
@@ -4984,19 +5182,26 @@
     free(p->inplace);
 }
 
+static inline void
+argf_init(struct argf *p, VALUE v)
+{
+    p->filename = Qnil;
+    p->current_file = Qnil;
+    p->lineno = Qnil;
+    p->argv = v;
+}
+
 static VALUE
 argf_alloc(VALUE klass)
 {
     struct argf *p;
     VALUE argf = Data_Make_Struct(klass, struct argf, argf_mark, argf_free, p);
 
-    p->filename = Qnil;
-    p->current_file = Qnil;
-    p->lineno = Qnil;
-    p->argv = Qnil;
+    argf_init(p, Qnil);
     return argf;
 }
 
+#undef rb_argv
 #define filename          ARGF.filename
 #define current_file      ARGF.current_file
 #define gets_lineno       ARGF.gets_lineno
@@ -5012,11 +5217,26 @@
 static VALUE
 argf_initialize(VALUE argf, VALUE argv)
 {
-    rb_argv = argv;
+    memset(&ARGF, 0, sizeof(ARGF));
+    argf_init(&ARGF, argv);
+
     return argf;
 }
 
 static VALUE
+argf_initialize_copy(VALUE argf, VALUE orig)
+{
+    ARGF = argf_of(orig);
+    rb_argv = rb_obj_dup(rb_argv);
+    if (ARGF.inplace) {
+	const char *inplace = ARGF.inplace;
+	ARGF.inplace = 0;
+	ARGF.inplace = ruby_strdup(inplace);
+    }
+    return argf;
+}
+
+static VALUE
 argf_set_lineno(VALUE argf, VALUE val)
 {
     gets_lineno = NUM2INT(val);
@@ -5044,8 +5264,8 @@
 	return argf_forward(argc, argv, argf);\
 } while (0)
 #define NEXT_ARGF_FORWARD(argc, argv) do {\
-     if (!next_argv()) return Qnil;\
-     ARGF_FORWARD(argc, argv);\
+    if (!next_argv()) return Qnil;\
+    ARGF_FORWARD(argc, argv);\
 } while (0)
 
 static void
@@ -5182,7 +5402,7 @@
 }
 
 static VALUE
-argf_getline(int argc, VALUE *argv)
+argf_getline(int argc, VALUE *argv, VALUE argf)
 {
     VALUE line;
 
@@ -5227,6 +5447,8 @@
     lineno = INT2FIX(n);
 }
 
+static VALUE argf_gets(int, VALUE *, VALUE);
+
 /*
  *  call-seq:
  *     gets(sep=$/)    => string or nil
@@ -5261,11 +5483,20 @@
  */
 
 static VALUE
-rb_f_gets(int argc, VALUE *argv)
+rb_f_gets(int argc, VALUE *argv, VALUE recv)
 {
+    if (recv == argf) {
+	return argf_gets(argc, argv, argf);
+    }
+    return rb_funcall2(argf, rb_intern("gets"), argc, argv);
+}
+
+static VALUE
+argf_gets(int argc, VALUE *argv, VALUE argf)
+{
     VALUE line;
 
-    line = argf_getline(argc, argv);
+    line = argf_getline(argc, argv, argf);
     rb_lastline_set(line);
     return line;
 }
@@ -5276,7 +5507,7 @@
     VALUE line;
 
     if (rb_rs != rb_default_rs) {
-	return rb_f_gets(0, 0);
+	return rb_f_gets(0, 0, argf);
     }
 
   retry:
@@ -5296,6 +5527,8 @@
     return line;
 }
 
+static VALUE argf_readline(int, VALUE *, VALUE);
+
 /*
  *  call-seq:
  *     readline(sep=$/)     => string
@@ -5307,13 +5540,22 @@
  */
 
 static VALUE
-rb_f_readline(int argc, VALUE *argv)
+rb_f_readline(int argc, VALUE *argv, VALUE recv)
 {
+    if (recv == argf) {
+	return argf_readline(argc, argv, argf);
+    }
+    return rb_funcall2(argf, rb_intern("readline"), argc, argv);
+}
+
+static VALUE
+argf_readline(int argc, VALUE *argv, VALUE argf)
+{
     VALUE line;
 
     if (!next_argv()) rb_eof_error();
     ARGF_FORWARD(argc, argv);
-    line = rb_f_gets(argc, argv);
+    line = argf_gets(argc, argv, argf);
     if (NIL_P(line)) {
 	rb_eof_error();
     }
@@ -5321,6 +5563,8 @@
     return line;
 }
 
+static VALUE argf_readlines(int, VALUE *, VALUE);
+
 /*
  *  call-seq:
  *     readlines(sep=$/)    => array
@@ -5332,12 +5576,21 @@
  */
 
 static VALUE
-rb_f_readlines(int argc, VALUE *argv)
+rb_f_readlines(int argc, VALUE *argv, VALUE recv)
 {
+    if (recv == argf) {
+	return argf_readlines(argc, argv, argf);
+    }
+    return rb_funcall2(argf, rb_intern("readlines"), argc, argv);
+}
+
+static VALUE
+argf_readlines(int argc, VALUE *argv, VALUE argf)
+{
     VALUE line, ary;
 
     ary = rb_ary_new();
-    while (!NIL_P(line = argf_getline(argc, argv))) {
+    while (!NIL_P(line = argf_getline(argc, argv, argf))) {
 	rb_ary_push(ary, line);
     }
 
@@ -5395,7 +5648,7 @@
     if (!NIL_P(read)) {
 	Check_Type(read, T_ARRAY);
 	for (i=0; i<RARRAY_LEN(read); i++) {
-	    GetOpenFile(rb_io_get_io(RARRAY_AT(read, i)), fptr);
+	    GetOpenFile(rb_io_get_io(RARRAY_PTR(read)[i]), fptr);
 	    rb_fd_set(fptr->fd, &fds[0]);
 	    if (READ_DATA_PENDING(fptr)) { /* check for buffered data */
 		pending++;
@@ -5415,7 +5668,7 @@
     if (!NIL_P(write)) {
 	Check_Type(write, T_ARRAY);
 	for (i=0; i<RARRAY_LEN(write); i++) {
-            VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AT(write, i)));
+            VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_PTR(write)[i]));
 	    GetOpenFile(write_io, fptr);
 	    rb_fd_set(fptr->fd, &fds[1]);
 	    if (max < fptr->fd) max = fptr->fd;
@@ -5428,7 +5681,7 @@
     if (!NIL_P(except)) {
 	Check_Type(except, T_ARRAY);
 	for (i=0; i<RARRAY_LEN(except); i++) {
-            VALUE io = rb_io_get_io(RARRAY_AT(except, i));
+            VALUE io = rb_io_get_io(RARRAY_PTR(except)[i]);
             VALUE write_io = GetWriteIO(io);
 	    GetOpenFile(io, fptr);
 	    rb_fd_set(fptr->fd, &fds[2]);
@@ -5460,7 +5713,7 @@
 
     if (interrupt_flag == 0) {
 	if (rp) {
-	    list = RARRAY_AT(res, 0);
+	    list = RARRAY_PTR(res)[0];
 	    for (i=0; i< RARRAY_LEN(read); i++) {
                 VALUE obj = rb_ary_entry(read, i);
                 VALUE io = rb_io_get_io(obj);
@@ -5473,7 +5726,7 @@
 	}
 
 	if (wp) {
-	    list = RARRAY_AT(res, 1);
+	    list = RARRAY_PTR(res)[1];
 	    for (i=0; i< RARRAY_LEN(write); i++) {
                 VALUE obj = rb_ary_entry(write, i);
                 VALUE io = rb_io_get_io(obj);
@@ -5486,7 +5739,7 @@
 	}
 
 	if (ep) {
-	    list = RARRAY_AT(res, 2);
+	    list = RARRAY_PTR(res)[2];
 	    for (i=0; i< RARRAY_LEN(except); i++) {
                 VALUE obj = rb_ary_entry(except, i);
                 VALUE io = rb_io_get_io(obj);
@@ -5937,6 +6190,7 @@
     rb_scan_args(argc, argv, "02", &v1, &v2);
     if (pipe(pipes) == -1)
 	rb_sys_fail(0);
+    UPDATE_MAXFD_PIPE(pipes);
 
     args[0] = klass;
     args[1] = INT2NUM(pipes[0]);
@@ -6006,28 +6260,19 @@
 	args = rb_ary_new2(RARRAY_LEN(v)+1);
 	rb_ary_push(args, argv[0]);
 	rb_ary_concat(args, v);
-#if WITH_OBJC
-	rb_notimplement();
-#else
 	MEMCPY(RARRAY_PTR(args)+1, RARRAY_PTR(v), VALUE, RARRAY_LEN(v));
 
-	arg->io = rb_f_open(RARRAY_LEN(args), RARRAY_PTR(args));
-#endif
+	arg->io = rb_io_open_with_args(RARRAY_LEN(args), RARRAY_PTR(args));
 	return;
     }
     v = rb_hash_aref(opt, mode);
     if (!NIL_P(v)) {
-	VALUE args[2];
-
-	args[0] = argv[0];
-	args[1] = v;
-	arg->io = rb_f_open(2, args);
+	arg->io = rb_io_open(RSTRING_PTR(argv[0]), StringValueCStr(v));
     }
+    else {
+	arg->io = rb_io_open(RSTRING_PTR(argv[0]), "r");
+    }
 
-	if (!arg->io) {
-	    arg->io = rb_io_open(RSTRING_PTR(argv[0]), "r");
-	}
-
     v = rb_hash_aref(opt, encoding);
     if (!NIL_P(v)) {
 	rb_io_t *fptr;
@@ -6172,9 +6417,540 @@
     return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
 }
 
+struct copy_stream_struct {
+    VALUE src;
+    VALUE dst;
+    off_t copy_length; /* (off_t)-1 if not specified */
+    off_t src_offset; /* (off_t)-1 if not specified */
 
+    int src_fd;
+    int dst_fd;
+    int close_src;
+    int close_dst;
+    off_t total;
+    char *syserr;
+    int error_no;
+    char *notimp;
+    rb_fdset_t fds;
+    rb_thread_t *th;
+};
+
+static int
+copy_stream_wait_read(struct copy_stream_struct *stp)
+{
+    int ret;
+    rb_fd_zero(&stp->fds);
+    rb_fd_set(stp->src_fd, &stp->fds);
+    ret = rb_fd_select(rb_fd_max(&stp->fds), &stp->fds, NULL, NULL, NULL);
+    if (ret == -1) {
+        stp->syserr = "select";
+        stp->error_no = errno;
+        return -1;
+    }
+    return 0;
+}
+
+static int
+copy_stream_wait_write(struct copy_stream_struct *stp)
+{
+    int ret;
+    rb_fd_zero(&stp->fds);
+    rb_fd_set(stp->dst_fd, &stp->fds);
+    ret = rb_fd_select(rb_fd_max(&stp->fds), NULL, &stp->fds, NULL, NULL);
+    if (ret == -1) {
+        stp->syserr = "select";
+        stp->error_no = errno;
+        return -1;
+    }
+    return 0;
+}
+
+#ifdef HAVE_SENDFILE
+
+#ifdef __linux__
+#define USE_SENDFILE
+
+#ifdef HAVE_SYS_SENDFILE_H
+#include <sys/sendfile.h>
+#endif
+
+static ssize_t
+simple_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
+{
+    return sendfile(out_fd, in_fd, offset, count);
+}
+
+#endif
+
+#endif
+
+#ifdef USE_SENDFILE
+static int
+copy_stream_sendfile(struct copy_stream_struct *stp)
+{
+    struct stat src_stat, dst_stat;
+    ssize_t ss;
+    int ret;
+
+    off_t copy_length;
+    off_t src_offset;
+    int use_pread;
+
+    ret = fstat(stp->src_fd, &src_stat);
+    if (ret == -1) {
+        stp->syserr = "fstat";
+        stp->error_no = errno;
+        return -1;
+    }
+    if (!S_ISREG(src_stat.st_mode))
+        return 0;
+
+    ret = fstat(stp->dst_fd, &dst_stat);
+    if (ret == -1) {
+        stp->syserr = "fstat";
+        stp->error_no = errno;
+        return -1;
+    }
+    if ((dst_stat.st_mode & S_IFMT) != S_IFSOCK)
+        return 0;
+
+    src_offset = stp->src_offset;
+    use_pread = src_offset != (off_t)-1;
+
+    copy_length = stp->copy_length;
+    if (copy_length == (off_t)-1) {
+        if (use_pread)
+            copy_length = src_stat.st_size - src_offset;
+        else {
+            off_t cur = lseek(stp->src_fd, 0, SEEK_CUR);
+            if (cur == (off_t)-1) {
+                stp->syserr = "lseek";
+                stp->error_no = errno;
+                return -1;
+            }
+            copy_length = src_stat.st_size - cur;
+        }
+    }
+
+retry_sendfile:
+    if (use_pread) {
+        ss = simple_sendfile(stp->dst_fd, stp->src_fd, &src_offset, copy_length);
+    }
+    else {
+        ss = simple_sendfile(stp->dst_fd, stp->src_fd, NULL, copy_length);
+    }
+    if (0 < ss) {
+        stp->total += ss;
+        copy_length -= ss;
+        if (0 < copy_length) {
+            ss = -1;
+            errno = EAGAIN;
+        }
+    }
+    if (ss == -1) {
+        if (errno == EINVAL || errno == ENOSYS)
+            return 0;
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            if (copy_stream_wait_write(stp) == -1)
+                return -1;
+            if (RUBY_VM_INTERRUPTED(stp->th))
+                return -1;
+            goto retry_sendfile;
+        }
+        stp->syserr = "sendfile";
+        stp->error_no = errno;
+        return -1;
+    }
+    return 1;
+}
+#endif
+
+static ssize_t
+copy_stream_read(struct copy_stream_struct *stp, char *buf, int len, off_t offset)
+{
+    ssize_t ss;
+retry_read:
+    if (offset == (off_t)-1)
+        ss = read(stp->src_fd, buf, len);
+    else {
+#ifdef HAVE_PREAD
+        ss = pread(stp->src_fd, buf, len, offset);
+#else
+        stp->notimp = "pread";
+        return -1;
+#endif
+    }
+    if (ss == 0) {
+        return 0;
+    }
+    if (ss == -1) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            if (copy_stream_wait_read(stp) == -1)
+                return -1;
+            goto retry_read;
+        }
+        if (errno == ENOSYS) {
+            stp->notimp = "pread";
+            return -1;
+        }
+        stp->syserr = offset == (off_t)-1 ?  "read" : "pread";
+        stp->error_no = errno;
+        return -1;
+    }
+    return ss;
+}
+
+static int
+copy_stream_write(struct copy_stream_struct *stp, char *buf, int len)
+{
+    ssize_t ss;
+    int off = 0;
+    while (len) {
+        ss = write(stp->dst_fd, buf+off, len);
+        if (ss == -1) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                if (copy_stream_wait_write(stp) == -1)
+                    return -1;
+                continue;
+            }
+            stp->syserr = "write";
+            stp->error_no = errno;
+            return -1;
+        }
+        off += ss;
+        len -= ss;
+        stp->total += ss;
+    }
+    return 0;
+}
+
+static void
+copy_stream_read_write(struct copy_stream_struct *stp)
+{
+    char buf[1024*16];
+    int len;
+    ssize_t ss;
+    int ret;
+    off_t copy_length;
+    int use_eof;
+    off_t src_offset;
+    int use_pread;
+
+    copy_length = stp->copy_length;
+    use_eof = copy_length == (off_t)-1;
+    src_offset = stp->src_offset;
+    use_pread = src_offset != (off_t)-1;
+
+    if (use_pread && stp->close_src) {
+        off_t r;
+        r = lseek(stp->src_fd, src_offset, SEEK_SET);
+        if (r == (off_t)-1) {
+            stp->syserr = "lseek";
+            stp->error_no = errno;
+            return;
+        }
+        src_offset = (off_t)-1;
+        use_pread = 0;
+    }
+
+    while (use_eof || 0 < copy_length) {
+        if (!use_eof && copy_length < sizeof(buf)) {
+            len = copy_length;
+        }
+        else {
+            len = sizeof(buf);
+        }
+        if (use_pread) {
+            ss = copy_stream_read(stp, buf, len, src_offset);
+            if (0 < ss)
+                src_offset += ss;
+        }
+        else {
+            ss = copy_stream_read(stp, buf, len, (off_t)-1);
+        }
+        if (ss <= 0) /* EOF or error */
+            return;
+
+        ret = copy_stream_write(stp, buf, ss);
+        if (ret < 0)
+            return;
+
+        if (!use_eof)
+            copy_length -= ss;
+
+        if (RUBY_VM_INTERRUPTED(stp->th))
+            return;
+    }
+}
+
+static VALUE
+copy_stream_func(void *arg)
+{
+    struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
+#ifdef USE_SENDFILE
+    int ret;
+#endif
+
+#ifdef USE_SENDFILE
+    ret = copy_stream_sendfile(stp);
+    if (ret != 0)
+        goto finish; /* error or success */
+#endif
+
+    copy_stream_read_write(stp);
+
+#ifdef USE_SENDFILE
+finish:
+#endif
+    return Qnil;
+}
+
+static VALUE
+copy_stream_fallback_body(VALUE arg)
+{
+    struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
+    const int buflen = 16*1024;
+    VALUE n;
+    VALUE buf = rb_str_buf_new(buflen);
+    long rest = stp->copy_length;
+    off_t off = stp->src_offset;
+
+    while (1) {
+        long numwrote;
+        long l;
+        if (stp->copy_length == (off_t)-1) {
+            l = buflen;
+        }
+        else {
+            if (rest == 0)
+                break;
+            l = buflen < rest ? buflen : rest;
+        }
+        if (stp->src_fd == -1) {
+            rb_funcall(stp->src, id_readpartial, 2, INT2FIX(l), buf);
+        }
+        else {
+            ssize_t ss;
+            rb_thread_wait_fd(stp->src_fd);
+            rb_str_resize(buf, buflen);
+            ss = copy_stream_read(stp, RSTRING_PTR(buf), l, off);
+            if (ss == -1)
+                return Qnil;
+            if (ss == 0)
+                rb_eof_error();
+            rb_str_resize(buf, ss);
+            if (off != (off_t)-1)
+                off += ss;
+        }
+        n = rb_io_write(stp->dst, buf);
+        numwrote = NUM2LONG(n);
+        stp->total += numwrote;
+        rest -= numwrote;
+    }
+
+    return Qnil;
+}
+
+static VALUE
+copy_stream_fallback(struct copy_stream_struct *stp)
+{
+    if (stp->src_fd == -1 && stp->src_offset != (off_t)-1) {
+	rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
+    }
+    rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
+               (VALUE (*) (ANYARGS))0, (VALUE)0,
+               rb_eEOFError, (VALUE)0);
+    return Qnil;
+}
+
+static VALUE
+copy_stream_body(VALUE arg)
+{
+    struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
+    VALUE src_io, dst_io;
+    rb_io_t *src_fptr = 0, *dst_fptr = 0;
+    int src_fd, dst_fd;
+
+    stp->th = GET_THREAD();
+
+    stp->total = 0;
+
+    if (stp->src == argf ||
+        !(TYPE(stp->src) == T_FILE ||
+          rb_respond_to(stp->src, rb_intern("to_io")) ||
+          TYPE(stp->src) == T_STRING ||
+          rb_respond_to(stp->src, rb_intern("to_path")))) {
+        src_fd = -1;
+    }
+    else {
+        src_io = rb_check_convert_type(stp->src, T_FILE, "IO", "to_io");
+        if (NIL_P(src_io)) {
+            VALUE args[2];
+            int flags = O_RDONLY;
+#ifdef O_NOCTTY
+            flags |= O_NOCTTY;
+#endif
+            FilePathValue(stp->src);
+            args[0] = stp->src;
+            args[1] = INT2NUM(flags);
+            src_io = rb_class_new_instance(2, args, rb_cFile);
+            stp->src = src_io;
+            stp->close_src = 1;
+        }
+        GetOpenFile(src_io, src_fptr);
+        rb_io_check_readable(src_fptr);
+        src_fd = src_fptr->fd;
+    }
+    stp->src_fd = src_fd;
+
+    if (stp->dst == argf ||
+        !(TYPE(stp->dst) == T_FILE ||
+          rb_respond_to(stp->dst, rb_intern("to_io")) ||
+          TYPE(stp->dst) == T_STRING ||
+          rb_respond_to(stp->dst, rb_intern("to_path")))) {
+        dst_fd = -1;
+    }
+    else {
+        dst_io = rb_check_convert_type(stp->dst, T_FILE, "IO", "to_io");
+        if (NIL_P(dst_io)) {
+            VALUE args[3];
+            int flags = O_WRONLY|O_CREAT|O_TRUNC;
+#ifdef O_NOCTTY
+            flags |= O_NOCTTY;
+#endif
+            FilePathValue(stp->dst);
+            args[0] = stp->dst;
+            args[1] = INT2NUM(flags);
+            args[2] = INT2FIX(0600);
+            dst_io = rb_class_new_instance(3, args, rb_cFile);
+            stp->dst = dst_io;
+            stp->close_dst = 1;
+        }
+        else {
+            dst_io = GetWriteIO(dst_io);
+            stp->dst = dst_io;
+        }
+        GetOpenFile(dst_io, dst_fptr);
+        rb_io_check_writable(dst_fptr);
+        dst_fd = dst_fptr->fd;
+    }
+    stp->dst_fd = dst_fd;
+
+    if (stp->src_offset == (off_t)-1 && src_fptr && src_fptr->rbuf_len) {
+        long len = src_fptr->rbuf_len;
+        VALUE str;
+        if (stp->copy_length != (off_t)-1 && stp->copy_length < len) {
+            len = stp->copy_length;
+        }
+        str = rb_str_buf_new(len);
+        rb_str_resize(str,len);
+        read_buffered_data(RSTRING_PTR(str), len, src_fptr);
+        if (dst_fptr) /* IO or filename */
+            io_fwrite(str, dst_fptr);
+        else /* others such as StringIO */
+            rb_io_write(stp->dst, str);
+        stp->total += len;
+        if (stp->copy_length != (off_t)-1)
+            stp->copy_length -= len;
+    }
+
+    if (dst_fptr && io_fflush(dst_fptr) < 0) {
+	rb_raise(rb_eIOError, "flush failed");
+    }
+
+    if (stp->copy_length == 0)
+        return Qnil;
+
+    if (src_fd == -1 || dst_fd == -1) {
+        return copy_stream_fallback(stp);
+    }
+
+    rb_fd_init(&stp->fds);
+    rb_fd_set(src_fd, &stp->fds);
+    rb_fd_set(dst_fd, &stp->fds);
+
+    return rb_thread_blocking_region(copy_stream_func, (void*)stp, RB_UBF_DFL, 0);
+}
+
+static VALUE
+copy_stream_finalize(VALUE arg)
+{
+    struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
+    if (stp->close_src) {
+        rb_io_close_m(stp->src);
+    }
+    if (stp->close_dst) {
+        rb_io_close_m(stp->dst);
+    }
+    rb_fd_term(&stp->fds);
+    if (stp->syserr) {
+        errno = stp->error_no;
+        rb_sys_fail(stp->syserr);
+    }
+    if (stp->notimp) {
+	rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
+    }
+    return Qnil;
+}
+
 /*
  *  call-seq:
+ *     IO.copy_stream(src, dst)
+ *     IO.copy_stream(src, dst, copy_length)
+ *     IO.copy_stream(src, dst, copy_length, src_offset)
+ *
+ *  IO.copy_stream copies <i>src</i> to <i>dst</i>.
+ *  <i>src</i> and <i>dst</i> is either a filename or an IO.
+ *
+ *  This method returns the number of bytes copied.
+ *
+ *  If optional arguments are not given,
+ *  the start position of the copy is
+ *  the beginning of the filename or
+ *  the current file offset of the IO.
+ *  The end position of the copy is the end of file.
+ *
+ *  If <i>copy_length</i> is given,
+ *  No more than <i>copy_length</i> bytes are copied.
+ *
+ *  If <i>src_offset</i> is given,
+ *  it specifies the start position of the copy.
+ *
+ *  When <i>src_offset</i> is specified and
+ *  <i>src</i> is an IO,
+ *  IO.copy_stream doesn't move the current file offset.
+ *
+ */
+static VALUE
+rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
+{
+    VALUE src, dst, length, src_offset;
+    struct copy_stream_struct st;
+
+    MEMZERO(&st, struct copy_stream_struct, 1);
+
+    rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
+
+    st.src = src;
+    st.dst = dst;
+
+    if (NIL_P(length))
+        st.copy_length = (off_t)-1;
+    else
+        st.copy_length = NUM2OFFT(length);
+
+    if (NIL_P(src_offset))
+        st.src_offset = (off_t)-1;
+    else
+        st.src_offset = NUM2OFFT(src_offset);
+
+    rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
+
+    return OFFT2NUM(st.total);
+}
+
+/*
+ *  call-seq:
  *     io.external_encoding   => encoding
  *
  *  Returns the Encoding object that represents the encoding of the file.
@@ -6274,7 +7050,7 @@
 }
 
 static VALUE
-argf_tell(void)
+argf_tell(VALUE argf)
 {
     if (!next_argv()) {
 	rb_raise(rb_eArgError, "no stream to tell");
@@ -6284,7 +7060,7 @@
 }
 
 static VALUE
-argf_seek_m(int argc, VALUE *argv, VALUE self)
+argf_seek_m(int argc, VALUE *argv, VALUE argf)
 {
     if (!next_argv()) {
 	rb_raise(rb_eArgError, "no stream to seek");
@@ -6294,7 +7070,7 @@
 }
 
 static VALUE
-argf_set_pos(VALUE self, VALUE offset)
+argf_set_pos(VALUE argf, VALUE offset)
 {
     if (!next_argv()) {
 	rb_raise(rb_eArgError, "no stream to set position");
@@ -6304,7 +7080,7 @@
 }
 
 static VALUE
-argf_rewind(void)
+argf_rewind(VALUE argf)
 {
     if (!next_argv()) {
 	rb_raise(rb_eArgError, "no stream to rewind");
@@ -6314,7 +7090,7 @@
 }
 
 static VALUE
-argf_fileno(void)
+argf_fileno(VALUE argf)
 {
     if (!next_argv()) {
 	rb_raise(rb_eArgError, "no stream");
@@ -6324,7 +7100,7 @@
 }
 
 static VALUE
-argf_to_io(void)
+argf_to_io(VALUE argf)
 {
     next_argv();
     ARGF_FORWARD(0, 0);
@@ -6332,7 +7108,7 @@
 }
 
 static VALUE
-argf_eof(void)
+argf_eof(VALUE argf)
 {
     if (current_file) {
 	if (init_p == 0) return Qtrue;
@@ -6445,13 +7221,13 @@
 }
 
 static VALUE
-argf_getc(void)
+argf_getc(VALUE argf)
 {
     VALUE ch;
 
   retry:
     if (!next_argv()) return Qnil;
-    if (current_file == rb_stdin && TYPE(current_file) != T_FILE) {
+    if (ARGF_GENERIC_INPUT_P()) {
 	ch = rb_funcall3(current_file, rb_intern("getc"), 0, 0);
     }
     else {
@@ -6467,7 +7243,7 @@
 }
 
 static VALUE
-argf_getbyte(void)
+argf_getbyte(VALUE argf)
 {
     VALUE ch;
 
@@ -6489,7 +7265,7 @@
 }
 
 static VALUE
-argf_readchar(void)
+argf_readchar(VALUE argf)
 {
     VALUE ch;
 
@@ -6511,12 +7287,12 @@
 }
 
 static VALUE
-argf_readbyte(void)
+argf_readbyte(VALUE argf)
 {
     VALUE c;
 
     NEXT_ARGF_FORWARD(0, 0);
-    c = argf_getbyte();
+    c = argf_getbyte(argf);
     if (NIL_P(c)) {
 	rb_eof_error();
     }
@@ -6524,15 +7300,15 @@
 }
 
 static VALUE
-argf_each_line(int argc, VALUE *argv, VALUE self)
+argf_each_line(int argc, VALUE *argv, VALUE argf)
 {
-    RETURN_ENUMERATOR(self, argc, argv);
+    RETURN_ENUMERATOR(argf, argc, argv);
     for (;;) {
 	if (!next_argv()) return Qnil;
 	rb_block_call(current_file, rb_intern("each_line"), 0, 0, rb_yield, 0);
 	next_p = 1;
     }
-    return self;
+    return argf;
 }
 
 static VALUE
@@ -6547,6 +7323,17 @@
 }
 
 static VALUE
+argf_each_char(VALUE argf)
+{
+    RETURN_ENUMERATOR(argf, 0, 0);
+    for (;;) {
+	if (!next_argv()) return Qnil;
+	rb_block_call(current_file, rb_intern("each_char"), 0, 0, rb_yield, 0);
+	next_p = 1;
+    }
+}
+
+static VALUE
 argf_filename(VALUE argf)
 {
     next_argv();
@@ -6633,9 +7420,9 @@
 	ruby_inplace_mode = 0;
     }
     else {
-    StringValue(val);
-    if (ruby_inplace_mode) free(ruby_inplace_mode);
-    ruby_inplace_mode = 0;
+	StringValue(val);
+	if (ruby_inplace_mode) free(ruby_inplace_mode);
+	ruby_inplace_mode = 0;
 	ruby_inplace_mode = strdup(RSTRING_PTR(val));
     }
     return argf;
@@ -6679,8 +7466,6 @@
     return rb_argv;
 }
 
-#undef rb_argv
-
 /*
  *  Class <code>IO</code> is the basis for all input and output in Ruby.
  *  An I/O stream may be <em>duplexed</em> (that is, bidirectional), and
@@ -6782,6 +7567,7 @@
     id_getc = rb_intern("getc");
     id_flush = rb_intern("flush");
     id_encode = rb_intern("encode");
+    id_readpartial = rb_intern("readpartial");
 
     rb_define_global_function("syscall", rb_f_syscall, -1);
 
@@ -6816,6 +7602,7 @@
     rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
     rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
     rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
+    rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
 
     rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
 
@@ -6843,8 +7630,10 @@
     rb_define_method(rb_cIO, "each",  rb_io_each_line, -1);
     rb_define_method(rb_cIO, "each_line",  rb_io_each_line, -1);
     rb_define_method(rb_cIO, "each_byte",  rb_io_each_byte, 0);
+    rb_define_method(rb_cIO, "each_char",  rb_io_each_char, 0);
     rb_define_method(rb_cIO, "lines",  rb_io_lines, -1);
     rb_define_method(rb_cIO, "bytes",  rb_io_bytes, 0);
+    rb_define_method(rb_cIO, "chars",  rb_io_chars, 0);
 
     rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
     rb_define_method(rb_cIO, "sysread",  rb_io_sysread, -1);
@@ -6909,11 +7698,10 @@
     rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
     rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
 
+    rb_define_variable("$stdin", &rb_stdin);
     rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
-    rb_define_variable("$stdin", &rb_stdin);
+    rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter);
     rb_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO, "<STDOUT>");
-    rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter);
-    rb_stderr = prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
     rb_define_hooked_variable("$stderr", &rb_stderr, 0, stdout_setter);
     rb_stderr = prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
     rb_define_hooked_variable("$>", &rb_stdout, 0, stdout_setter);
@@ -6925,13 +7713,14 @@
     rb_define_global_const("STDOUT", rb_stdout);
     rb_define_global_const("STDERR", rb_stderr);
 
-    argf = argf_alloc(rb_cObject);
-    argf_initialize(argf, rb_ary_new());
-    rb_cARGF = rb_singleton_class(argf);
+    rb_cARGF = rb_class_new(rb_cObject);
+    rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
+    rb_define_alloc_func(rb_cARGF, argf_alloc);
 
     rb_include_module(rb_cARGF, rb_mEnumerable);
 
-    rb_define_method(rb_cARGF, "initialize", argf_initialize, 1);
+    rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
+    rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
     rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
     rb_define_method(rb_cARGF, "argv", argf_argv, 0);
 
@@ -6941,13 +7730,14 @@
     rb_define_method(rb_cARGF, "each",  argf_each_line, -1);
     rb_define_method(rb_cARGF, "each_line",  argf_each_line, -1);
     rb_define_method(rb_cARGF, "each_byte",  argf_each_byte, 0);
+    rb_define_method(rb_cARGF, "each_char",  argf_each_char, 0);
 
     rb_define_method(rb_cARGF, "read",  argf_read, -1);
     rb_define_method(rb_cARGF, "readpartial",  argf_readpartial, -1);
-    rb_define_method(rb_cARGF, "readlines", rb_f_readlines, -1);
-    rb_define_method(rb_cARGF, "to_a", rb_f_readlines, -1);
-    rb_define_method(rb_cARGF, "gets", rb_f_gets, -1);
-    rb_define_method(rb_cARGF, "readline", rb_f_readline, -1);
+    rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
+    rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
+    rb_define_method(rb_cARGF, "gets", argf_gets, -1);
+    rb_define_method(rb_cARGF, "readline", argf_readline, -1);
     rb_define_method(rb_cARGF, "getc", argf_getc, 0);
     rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
     rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
@@ -6978,6 +7768,8 @@
     rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
     rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
 
+    argf = rb_class_new_instance(0, 0, rb_cARGF);
+
     rb_define_readonly_variable("$<", &argf);
     rb_define_global_const("ARGF", argf);
 

Modified: MacRuby/trunk/iseq.c
===================================================================
--- MacRuby/trunk/iseq.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/iseq.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   iseq.c -
 
-  $Author: nobu $
+  $Author: ko1 $
   created at: 2006-07-11(Tue) 09:00:03 +0900
 
   Copyright (C) 2006 Koichi Sasada
@@ -247,6 +247,10 @@
       if (flag == Qtrue)  { o->mem = 1; } \
       else if (flag == Qfalse)  { o->mem = 0; } \
   }
+#define SET_COMPILE_OPTION_NUM(o, h, mem) \
+  { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
+      if (!NIL_P(num)) o->mem = NUM2INT(num); \
+  }
 	SET_COMPILE_OPTION(option, opt, inline_const_cache);
 	SET_COMPILE_OPTION(option, opt, peephole_optimization);
 	SET_COMPILE_OPTION(option, opt, tailcall_optimization);
@@ -255,7 +259,9 @@
 	SET_COMPILE_OPTION(option, opt, instructions_unification);
 	SET_COMPILE_OPTION(option, opt, stack_caching);
 	SET_COMPILE_OPTION(option, opt, trace_instruction);
+	SET_COMPILE_OPTION_NUM(option, opt, debug_level);
 #undef SET_COMPILE_OPTION
+#undef SET_COMPILE_OPTION_NUM
     }
     else {
 	rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
@@ -268,6 +274,8 @@
     VALUE opt = rb_hash_new();
 #define SET_COMPILE_OPTION(o, h, mem) \
   rb_hash_aset(h, ID2SYM(rb_intern(#mem)), o->mem ? Qtrue : Qfalse)
+#define SET_COMPILE_OPTION_NUM(o, h, mem) \
+  rb_hash_aset(h, ID2SYM(rb_intern(#mem)), INT2NUM(o->mem))
     {
 	SET_COMPILE_OPTION(option, opt, inline_const_cache);
 	SET_COMPILE_OPTION(option, opt, peephole_optimization);
@@ -276,8 +284,10 @@
 	SET_COMPILE_OPTION(option, opt, operands_unification);
 	SET_COMPILE_OPTION(option, opt, instructions_unification);
 	SET_COMPILE_OPTION(option, opt, stack_caching);
+	SET_COMPILE_OPTION_NUM(option, opt, debug_level);
     }
 #undef SET_COMPILE_OPTION
+#undef SET_COMPILE_OPTION_NUM
     return opt;
 }
 
@@ -434,7 +444,7 @@
 rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE line, VALUE opt)
 {
     rb_compile_option_t option;
-    NODE *node = compile_string(src, file, line);
+    NODE *node = compile_string(StringValue(src), file, line);
     rb_thread_t *th = GET_THREAD();
     make_compile_option(&option, opt);
 
@@ -603,7 +613,7 @@
 		    int insn, int op_no, VALUE op,
 		    int len, int pos, VALUE *pnop, VALUE child)
 {
-    char *types = insn_op_types(insn);
+    const char *types = insn_op_types(insn);
     char type = types[op_no];
     VALUE ret;
     char buff[0x100];
@@ -655,6 +665,7 @@
       }
       case TS_ID:		/* ID (symbol) */
 	op = ID2SYM(op);
+
       case TS_VALUE:		/* VALUE */
 	ret = rb_inspect(op);
 	if (CLASS_OF(op) == rb_cISeq) {
@@ -712,7 +723,7 @@
     int insn = iseq[pos];
     int len = insn_len(insn);
     int i, j;
-    char *types = insn_op_types(insn);
+    const char *types = insn_op_types(insn);
     VALUE str = rb_str_new(0, 0);
     char buff[0x100];
     char insn_name_buff[0x100];
@@ -730,7 +741,7 @@
     rb_str_cat2(str, buff);
 
     for (j = 0; types[j]; j++) {
-	char *types = insn_op_types(insn);
+	const char *types = insn_op_types(insn);
 	VALUE opstr = insn_operand_intern(iseqdat, insn, j, iseq[pos + j + 1],
 					  len, pos, &iseq[pos + j + 2],
 					  child);

Modified: MacRuby/trunk/lib/cgi.rb
===================================================================
--- MacRuby/trunk/lib/cgi.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/cgi.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -284,7 +284,7 @@
   # Standard internet newline sequence
   EOL = CR + LF
 
-  REVISION = '$Id: cgi.rb 15526 2008-02-17 14:08:27Z kazu $' #:nodoc:
+  REVISION = '$Id: cgi.rb 15781 2008-03-14 08:08:51Z matz $' #:nodoc:
 
   NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM) 
 
@@ -802,11 +802,16 @@
     #
     # These keywords correspond to attributes of the cookie object.
     def initialize(name = "", *value)
-      options = if name.kind_of?(String)
-                  { "name" => name, "value" => value }
-                else
-                  name
-                end
+      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
@@ -890,7 +895,7 @@
       if cookies.has_key?(name)
         values = cookies[name].value + values
       end
-      cookies[name] = Cookie::new({ "name" => name, "value" => values })
+      cookies[name] = Cookie::new(name, *values)
     end
 
     cookies

Modified: MacRuby/trunk/lib/complex.rb
===================================================================
--- MacRuby/trunk/lib/complex.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/complex.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,667 +1,4 @@
-#
-#   complex.rb - 
-#   	$Release Version: 0.5 $
-#   	$Revision: 1.3 $
-#   	by Keiju ISHITSUKA(SHL Japan Inc.)
-#
-# ----
-#
-# complex.rb implements the Complex class for complex numbers.  Additionally,
-# some methods in other Numeric classes are redefined or added to allow greater
-# interoperability with Complex numbers.
-#
-# Complex numbers can be created in the following manner:
-# - <tt>Complex(a, b)</tt>
-# - <tt>Complex.polar(radius, theta)</tt>
-#   
-# Additionally, note the following:
-# - <tt>Complex::I</tt> (the mathematical constant <i>i</i>)
-# - <tt>Numeric#im</tt> (e.g. <tt>5.im -> 0+5i</tt>)
-#
-# The following +Math+ module methods are redefined to handle Complex arguments.
-# They will work as normal with non-Complex arguments.
-#    sqrt exp cos sin tan log log10
-#    cosh sinh tanh acos asin atan atan2 acosh asinh atanh
-#
+require 'cmath'
 
-
-#
-# Numeric is a built-in class on which Fixnum, Bignum, etc., are based.  Here
-# some methods are added so that all number types can be treated to some extent
-# as Complex numbers.
-#
-class Numeric
-  #
-  # Returns a Complex number <tt>(0,<i>self</i>)</tt>.
-  #
-  def im
-    Complex(0, self)
-  end
-  
-  #
-  # The real part of a complex number, i.e. <i>self</i>.
-  #
-  def real
-    self
-  end
-  
-  #
-  # The imaginary part of a complex number, i.e. 0.
-  #
-  def image
-    0
-  end
-  alias imag image
-  
-  #
-  # See Complex#arg.
-  #
-  def arg
-    if self >= 0
-      return 0
-    else
-      return Math::PI
-    end
-  end
-  alias angle arg
-  
-  #
-  # See Complex#polar.
-  #
-  def polar
-    return abs, arg
-  end
-  
-  #
-  # See Complex#conjugate (short answer: returns <i>self</i>).
-  #
-  def conjugate
-    self
-  end
-  alias conj conjugate
-end
-
-
-#
-# Creates a Complex number.  +a+ and +b+ should be Numeric.  The result will be
-# <tt>a+bi</tt>.
-#
-def Complex(a, b = 0)
-  if b == 0 and (a.kind_of?(Complex) or defined? Complex::Unify)
-    a
-  elsif a.scalar? and b.scalar?
-    # Don't delete for -0.0
-    Complex.new(a, b)
-  else
-    Complex.new( a.real-b.imag, a.imag+b.real )
-  end
-end
-
-#
-# The complex number class.  See complex.rb for an overview.
-#
-class Complex < Numeric
-  @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
-
-  undef step
-  undef <, <=, <=>, >, >=
-  undef between?
-  undef div, divmod, modulo
-  undef floor, truncate, ceil, round
-
-  def scalar?
-    false
-  end
-
-  def Complex.generic?(other) # :nodoc:
-    other.kind_of?(Integer) or
-    other.kind_of?(Float) or
-    (defined?(Rational) and other.kind_of?(Rational))
-  end
-
-  #
-  # Creates a +Complex+ number in terms of +r+ (radius) and +theta+ (angle).
-  #
-  def Complex.polar(r, theta)
-    Complex(r*Math.cos(theta), r*Math.sin(theta))
-  end
-
-  #
-  # Creates a +Complex+ number <tt>a</tt>+<tt>b</tt><i>i</i>.
-  #
-  def Complex.new!(a, b=0)
-    new(a,b)
-  end
-
-  def initialize(a, b)
-    raise TypeError, "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric
-    raise TypeError, "`#{a.inspect}' for 1st arg" if a.kind_of? Complex
-    raise TypeError, "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric
-    raise TypeError, "`#{b.inspect}' for 2nd arg" if b.kind_of? Complex
-    @real = a
-    @image = b
-  end
-
-  #
-  # Addition with real or complex number.
-  #
-  def + (other)
-    if other.kind_of?(Complex)
-      re = @real + other.real
-      im = @image + other.image
-      Complex(re, im)
-    elsif Complex.generic?(other)
-      Complex(@real + other, @image)
-    else
-      x , y = other.coerce(self)
-      x + y
-    end
-  end
-  
-  #
-  # Subtraction with real or complex number.
-  #
-  def - (other)
-    if other.kind_of?(Complex)
-      re = @real - other.real
-      im = @image - other.image
-      Complex(re, im)
-    elsif Complex.generic?(other)
-      Complex(@real - other, @image)
-    else
-      x , y = other.coerce(self)
-      x - y
-    end
-  end
-  
-  #
-  # Multiplication with real or complex number.
-  #
-  def * (other)
-    if other.kind_of?(Complex)
-      re = @real*other.real - @image*other.image
-      im = @real*other.image + @image*other.real
-      Complex(re, im)
-    elsif Complex.generic?(other)
-      Complex(@real * other, @image * other)
-    else
-      x , y = other.coerce(self)
-      x * y
-    end
-  end
-  
-  #
-  # Division by real or complex number.
-  #
-  def / (other)
-    if other.kind_of?(Complex)
-      self*other.conjugate/other.abs2
-    elsif Complex.generic?(other)
-      Complex(@real/other, @image/other)
-    else
-      x, y = other.coerce(self)
-      x/y
-    end
-  end
-
-  def quo(other)
-    Complex(@real.quo(1), @image.quo(1)) / other
-  end
-  
-  #
-  # Raise this complex number to the given (real or complex) power.
-  #
-  def ** (other)
-    if other == 0
-      return Complex(1)
-    end
-    if other.kind_of?(Complex)
-      r, theta = polar
-      ore = other.real
-      oim = other.image
-      nr = Math.exp!(ore*Math.log!(r) - oim * theta)
-      ntheta = theta*ore + oim*Math.log!(r)
-      Complex.polar(nr, ntheta)
-    elsif other.kind_of?(Integer)
-      if other > 0
-	x = self
-	z = x
-	n = other - 1
-	while n != 0
-	  while (div, mod = n.divmod(2)
-		 mod == 0)
-	    x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image)
-	    n = div
-	  end
-	  z *= x
-	  n -= 1
-	end
-	z
-      else
-	if defined? Rational
-	  (Rational(1) / self) ** -other
-	else
-	  self ** Float(other)
-	end
-      end
-    elsif Complex.generic?(other)
-      r, theta = polar
-      Complex.polar(r**other, theta*other)
-    else
-      x, y = other.coerce(self)
-      x**y
-    end
-  end
-  
-  #
-  # Remainder after division by a real or complex number.
-  #
-
-=begin
-  def % (other)
-    if other.kind_of?(Complex)
-      Complex(@real % other.real, @image % other.image)
-    elsif Complex.generic?(other)
-      Complex(@real % other, @image % other)
-    else
-      x , y = other.coerce(self)
-      x % y
-    end
-  end
-=end
-
-#--
-#    def divmod(other)
-#      if other.kind_of?(Complex)
-#        rdiv, rmod = @real.divmod(other.real)
-#        idiv, imod = @image.divmod(other.image)
-#        return Complex(rdiv, idiv), Complex(rmod, rmod)
-#      elsif Complex.generic?(other)
-#        Complex(@real.divmod(other), @image.divmod(other))
-#      else
-#        x , y = other.coerce(self)
-#        x.divmod(y)
-#      end
-#    end
-#++
-  
-  #
-  # Absolute value (aka modulus): distance from the zero point on the complex
-  # plane.
-  #
-  def abs
-    Math.hypot(@real, @image)
-  end
-  
-  #
-  # Square of the absolute value.
-  #
-  def abs2
-    @real*@real + @image*@image
-  end
-  
-  #
-  # Argument (angle from (1,0) on the complex plane).
-  #
-  def arg
-    Math.atan2!(@image, @real)
-  end
-  alias angle arg
-  
-  #
-  # Returns the absolute value _and_ the argument.
-  #
-  def polar
-    return abs, arg
-  end
-  
-  #
-  # Complex conjugate (<tt>z + z.conjugate = 2 * z.real</tt>).
-  #
-  def conjugate
-    Complex(@real, - at image)
-  end
-  alias conj conjugate
-
-  #
-  # Test for numerical equality (<tt>a == a + 0<i>i</i></tt>).
-  #
-  def == (other)
-    if other.kind_of?(Complex)
-      @real == other.real and @image == other.image
-    elsif Complex.generic?(other)
-      @real == other and @image == 0
-    else
-      other == self
-    end
-  end
-
-  #
-  # Attempts to coerce +other+ to a Complex number.
-  #
-  def coerce(other)
-    if Complex.generic?(other)
-      return Complex.new!(other), self
-    else
-      super
-    end
-  end
-
-  #
-  # FIXME
-  #
-  def denominator
-    @real.denominator.lcm(@image.denominator)
-  end
-  
-  #
-  # FIXME
-  #
-  def numerator
-    cd = denominator
-    Complex(@real.numerator*(cd/@real.denominator),
-	    @image.numerator*(cd/@image.denominator))
-  end
-  
-  #
-  # Standard string representation of the complex number.
-  #
-  def to_s
-    if @real != 0
-      if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
-	if @image >= 0
-	  @real.to_s+"+("+ at image.to_s+")i"
-	else
-	  @real.to_s+"-("+(- at image).to_s+")i"
-	end
-      else
-	if @image >= 0
-	  @real.to_s+"+"+ at image.to_s+"i"
-	else
-	  @real.to_s+"-"+(- at image).to_s+"i"
-	end
-      end
-    else
-      if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
-	"("+ at image.to_s+")i"
-      else
-	@image.to_s+"i"
-      end
-    end
-  end
-  
-  #
-  # Returns a hash code for the complex number.
-  #
-  def hash
-    @real.hash ^ @image.hash
-  end
-  
-  #
-  # Returns "<tt>Complex(<i>real</i>, <i>image</i>)</tt>".
-  #
-  def inspect
-    sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
-  end
-
-  
-  #
-  # +I+ is the imaginary number.  It exists at point (0,1) on the complex plane.
-  #
-  I = Complex(0,1)
-  
-  # The real part of a complex number.
-  attr_reader :real
-
-  # The imaginary part of a complex number.
-  attr_reader :image
-  alias imag image
-  
-end
-
-class Integer
-
-  unless defined?(1.numerator)
-    def numerator() self end
-    def denominator() 1 end
-
-    def gcd(other)
-      min = self.abs
-      max = other.abs
-      while min > 0
-        tmp = min
-        min = max % min
-        max = tmp
-      end
-      max
-    end
-
-    def lcm(other)
-      if self.zero? or other.zero?
-        0
-      else
-        (self.div(self.gcd(other)) * other).abs
-      end
-    end
-
-  end
-
-end
-
-module Math
-  alias sqrt! sqrt
-  alias exp! exp
-  alias log! log
-  alias log10! log10
-  alias cos! cos
-  alias sin! sin
-  alias tan! tan
-  alias cosh! cosh
-  alias sinh! sinh
-  alias tanh! tanh
-  alias acos! acos
-  alias asin! asin
-  alias atan! atan
-  alias atan2! atan2
-  alias acosh! acosh
-  alias asinh! asinh
-  alias atanh! atanh  
-
-  # Redefined to handle a Complex argument.
-  def sqrt(z)
-    if Complex.generic?(z)
-      if z >= 0
-	sqrt!(z)
-      else
-	Complex(0,sqrt!(-z))
-      end
-    else
-      if z.image < 0
-	sqrt(z.conjugate).conjugate
-      else
-	r = z.abs
-	x = z.real
-	Complex( sqrt!((r+x)/2), sqrt!((r-x)/2) )
-      end
-    end
-  end
-  
-  # Redefined to handle a Complex argument.
-  def exp(z)
-    if Complex.generic?(z)
-      exp!(z)
-    else
-      Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image))
-    end
-  end
-  
-  # Redefined to handle a Complex argument.
-  def cos(z)
-    if Complex.generic?(z)
-      cos!(z)
-    else
-      Complex(cos!(z.real)*cosh!(z.image),
-	      -sin!(z.real)*sinh!(z.image))
-    end
-  end
-    
-  # Redefined to handle a Complex argument.
-  def sin(z)
-    if Complex.generic?(z)
-      sin!(z)
-    else
-      Complex(sin!(z.real)*cosh!(z.image),
-	      cos!(z.real)*sinh!(z.image))
-    end
-  end
-  
-  # Redefined to handle a Complex argument.
-  def tan(z)
-    if Complex.generic?(z)
-      tan!(z)
-    else
-      sin(z)/cos(z)
-    end
-  end
-
-  def sinh(z)
-    if Complex.generic?(z)
-      sinh!(z)
-    else
-      Complex( sinh!(z.real)*cos!(z.image), cosh!(z.real)*sin!(z.image) )
-    end
-  end
-
-  def cosh(z)
-    if Complex.generic?(z)
-      cosh!(z)
-    else
-      Complex( cosh!(z.real)*cos!(z.image), sinh!(z.real)*sin!(z.image) )
-    end
-  end
-
-  def tanh(z)
-    if Complex.generic?(z)
-      tanh!(z)
-    else
-      sinh(z)/cosh(z)
-    end
-  end
-  
-  # Redefined to handle a Complex argument.
-  def log(z)
-    if Complex.generic?(z) and z >= 0
-      log!(z)
-    else
-      r, theta = z.polar
-      Complex(log!(r.abs), theta)
-    end
-  end
-  
-  # Redefined to handle a Complex argument.
-  def log10(z)
-    if Complex.generic?(z)
-      log10!(z)
-    else
-      log(z)/log!(10)
-    end
-  end
-
-  def acos(z)
-    if Complex.generic?(z) and z >= -1 and z <= 1
-      acos!(z)
-    else
-      -1.0.im * log( z + 1.0.im * sqrt(1.0-z*z) )
-    end
-  end
-
-  def asin(z)
-    if Complex.generic?(z) and z >= -1 and z <= 1
-      asin!(z)
-    else
-      -1.0.im * log( 1.0.im * z + sqrt(1.0-z*z) )
-    end
-  end
-
-  def atan(z)
-    if Complex.generic?(z)
-      atan!(z)
-    else
-      1.0.im * log( (1.0.im+z) / (1.0.im-z) ) / 2.0
-    end
-  end
-
-  def atan2(y,x)
-    if Complex.generic?(y) and Complex.generic?(x)
-      atan2!(y,x)
-    else
-      -1.0.im * log( (x+1.0.im*y) / sqrt(x*x+y*y) )
-    end
-  end
-
-  def acosh(z)
-    if Complex.generic?(z) and z >= 1
-      acosh!(z)
-    else
-      log( z + sqrt(z*z-1.0) )
-    end
-  end
-
-  def asinh(z)
-    if Complex.generic?(z)
-      asinh!(z)
-    else
-      log( z + sqrt(1.0+z*z) )
-    end
-  end
-
-  def atanh(z)
-    if Complex.generic?(z) and z >= -1 and z <= 1
-      atanh!(z)
-    else
-      log( (1.0+z) / (1.0-z) ) / 2.0
-    end
-  end
-
-  module_function :sqrt!
-  module_function :sqrt
-  module_function :exp!
-  module_function :exp
-  module_function :log!
-  module_function :log
-  module_function :log10!
-  module_function :log10
-  module_function :cosh!
-  module_function :cosh
-  module_function :cos!
-  module_function :cos
-  module_function :sinh!
-  module_function :sinh
-  module_function :sin!
-  module_function :sin
-  module_function :tan!
-  module_function :tan
-  module_function :tanh!
-  module_function :tanh
-  module_function :acos!
-  module_function :acos
-  module_function :asin!
-  module_function :asin
-  module_function :atan!
-  module_function :atan
-  module_function :atan2!
-  module_function :atan2
-  module_function :acosh!
-  module_function :acosh
-  module_function :asinh!
-  module_function :asinh
-  module_function :atanh!
-  module_function :atanh
-  
-end
-
-# Documentation comments:
-#  - source: original (researched from pickaxe)
-#  - a couple of fixme's
-#  - RDoc output for Bignum etc. is a bit short, with nothing but an
-#    (undocumented) alias.  No big deal.
+Object.instance_eval{remove_const :Math}
+Math = CMath

Modified: MacRuby/trunk/lib/csv.rb
===================================================================
--- MacRuby/trunk/lib/csv.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/csv.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1524,7 +1524,7 @@
     # 
     loop do
       # add another read to the line
-      line  += @io.gets(@row_sep) rescue return nil
+      (line += @io.gets(@row_sep)) rescue return nil
       # copy the line so we can chop it up in parsing
       parse = line.dup
       parse.sub!(@parsers[:line_end], "")

Modified: MacRuby/trunk/lib/date.rb
===================================================================
--- MacRuby/trunk/lib/date.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/date.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1104,10 +1104,10 @@
     def once(*ids) # :nodoc: -- restricted
       for id in ids
 	module_eval <<-"end;"
-	  alias_method :__#{id.to_i}__, :#{id.to_s}
-	  private :__#{id.to_i}__
+	  alias_method :__#{id.object_id}__, :#{id.to_s}
+	  private :__#{id.object_id}__
 	  def #{id.to_s}(*args)
-	    @__ca__[#{id.to_i}] ||= __#{id.to_i}__(*args)
+	    @__ca__[#{id.object_id}] ||= __#{id.object_id}__(*args)
 	  end
 	end;
       end

Modified: MacRuby/trunk/lib/debug.rb
===================================================================
--- MacRuby/trunk/lib/debug.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/debug.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,6 +2,8 @@
 # Copyright (C) 2000  Information-technology Promotion Agency, Japan
 # Copyright (C) 2000-2003  NAKAMURA, Hiroshi  <nahi at ruby-lang.org>
 
+require 'continuation'
+
 if $SAFE > 0
   STDERR.print "-r debug.rb is not available in safe mode\n"
   exit 1
@@ -295,7 +297,7 @@
 	  if break_points.find{|b| b[1] == 0}
 	    n = 1
 	    stdout.print "Breakpoints:\n"
-	    for b in break_points
+	    break_points.each do |b|
 	      if b[0] and b[1] == 0
 		stdout.printf "  %d %s:%s\n", n, b[2], b[3] 
 	      end
@@ -591,7 +593,6 @@
   def display_list(b, e, file, line)
     stdout.printf "[%d, %d] in %s\n", b, e, file
     if lines = SCRIPT_LINES__[file] and lines != true
-      n = 0
       b.upto(e) do |n|
 	if n > 0 && lines[n-1]
 	  if n == line
@@ -780,7 +781,7 @@
   def resume
     MUTEX.synchronize do
       make_thread_list
-      for th, in @thread_list
+      @thread_list.each do |th,|
 	next if th == Thread.current
 	context(th).clear_suspend
       end
@@ -806,7 +807,7 @@
   end
 
   def get_thread(num)
-    th = @thread_list.index(num)
+    th = @thread_list.key(num)
     unless th
       @stdout.print "No thread ##{num}\n"
       throw :debug_error

Modified: MacRuby/trunk/lib/drb/drb.rb
===================================================================
--- MacRuby/trunk/lib/drb/drb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/drb/drb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1476,10 +1476,10 @@
       raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class
       raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id)
       
-      if obj.private_methods.include?(msg_id.to_s)
+      if obj.private_methods.include?(msg_id)
 	desc = any_to_s(obj)
         raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
-      elsif obj.protected_methods.include?(msg_id.to_s)
+      elsif obj.protected_methods.include?(msg_id)
 	desc = any_to_s(obj)
         raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
       else

Modified: MacRuby/trunk/lib/erb.rb
===================================================================
--- MacRuby/trunk/lib/erb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/erb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -236,7 +236,7 @@
 # Rails, the web application framework, uses ERB to create views.
 #
 class ERB
-  Revision = '$Date:: 2008-01-06 08:07:04 -0800#$' 	#'
+  Revision = '$Date:: 2008-04-30 05:40:52 -0700#$' 	#'
 
   # Returns revision information for the erb.rb module.
   def self.version
@@ -799,7 +799,9 @@
     # 	Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
     #
     def url_encode(s)
-      s.to_s.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
+      s.to_s.dup.force_encoding("ASCII-8BIT").gsub(/[^a-zA-Z0-9_\-.]/n) {
+        sprintf("%%%02X", $&.unpack("C")[0])
+      }
     end
     alias u url_encode
     module_function :u

Modified: MacRuby/trunk/lib/getoptlong.rb
===================================================================
--- MacRuby/trunk/lib/getoptlong.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/getoptlong.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -151,7 +151,7 @@
     @argument_flags = Hash.new
 
     #
-    # Whether error messages are output to $deferr.
+    # Whether error messages are output to $stderr.
     #
     @quiet = FALSE
 
@@ -380,7 +380,7 @@
   # Set an error (a protected method).
   #
   def set_error(type, message)
-    $deferr.print("#{$0}: #{message}\n") if !@quiet
+    $stderr.print("#{$0}: #{message}\n") if !@quiet
 
     @error = type
     @error_message = message

Modified: MacRuby/trunk/lib/ipaddr.rb
===================================================================
--- MacRuby/trunk/lib/ipaddr.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/ipaddr.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -7,10 +7,14 @@
 #
 # You can redistribute and/or modify it under the same terms as Ruby.
 #
-# $Id: ipaddr.rb 13629 2007-10-04 19:03:56Z knu $
+# $Id: ipaddr.rb 15821 2008-03-21 12:15:06Z knu $
 #
+# Contact:
+#   - Akinori MUSHA <knu at iDaemons.org> (current maintainer)
+#
 # TODO:
 #   - scope_id support
+#
 require 'socket'
 
 unless Socket.const_defined? "AF_INET6"

Modified: MacRuby/trunk/lib/irb/cmd/help.rb
===================================================================
--- MacRuby/trunk/lib/irb/cmd/help.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/irb/cmd/help.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,27 +1,28 @@
 #
 #   help.rb - helper using ri
 #   	$Release Version: 0.9.5$
-#   	$Revision: 14912 $
+#   	$Revision: 15761 $
 #
 # --
 #
 #   
 #
 
-require 'rdoc/ri/ri_driver'
+require 'rdoc/ri/driver'
+require 'rdoc/ri/util'
 
 module IRB
   module ExtendCommand
     module Help
       begin
-        @ri = RiDriver.new
+        @ri = RDoc::RI::Driver.new
       rescue SystemExit
       else
         def self.execute(context, *names)
           names.each do |name|
             begin
               @ri.get_info_for(name.to_s)
-            rescue RiError
+            rescue RDoc::RI::Error
               puts $!.message
             end
           end

Modified: MacRuby/trunk/lib/irb/workspace.rb
===================================================================
--- MacRuby/trunk/lib/irb/workspace.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/irb/workspace.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,7 +1,7 @@
 #
 #   irb/workspace-binding.rb - 
 #   	$Release Version: 0.9.5$
-#   	$Revision: 15442 $
+#   	$Revision: 15689 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -93,8 +93,10 @@
 	end
       when 2
 	return nil if bt =~ /irb\/.*\.rb/
+	return nil if bt =~ /irb\.rb/
       when 3
 	return nil if bt =~ /irb\/.*\.rb/
+	return nil if bt =~ /irb\.rb/
 	bt.sub!(/:\s*in `irb_binding'/, '')
       end
       bt

Modified: MacRuby/trunk/lib/irb.rb
===================================================================
--- MacRuby/trunk/lib/irb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/irb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,7 +1,7 @@
 #
 #   irb.rb - irb main module
 #   	$Release Version: 0.9.5 $
-#   	$Revision: 15408 $
+#   	$Revision: 15689 $
 #   	by Keiju ISHITSUKA(keiju at ruby-lang.org)
 #
 # --
@@ -22,7 +22,7 @@
 STDOUT.sync = true
 
 module IRB
-  @RCS_ID='-$Id: irb.rb 15408 2008-02-08 15:44:54Z nobu $-'
+  @RCS_ID='-$Id: irb.rb 15689 2008-03-04 12:37:05Z matz $-'
 
   class Abort < Exception;end
 
@@ -156,12 +156,13 @@
 	  end
 	  if exc
 	    print exc.class, ": ", exc, "\n"
-	    if exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/
+	    if exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
+                !(SyntaxError === exc)
 	      irb_bug = true 
 	    else
 	      irb_bug = false
 	    end
-	    
+
 	    messages = []
 	    lasts = []
 	    levels = 0

Modified: MacRuby/trunk/lib/mathn.rb
===================================================================
--- MacRuby/trunk/lib/mathn.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/mathn.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -127,7 +127,7 @@
     if other.kind_of?(Rational)
       other2 = other
       if self < 0
-	return Complex.new!(self, 0) ** other
+	return Complex.__send__(:new!, self, 0) ** other
       elsif other == 0
 	return Rational(1,1)
       elsif self == 0
@@ -175,7 +175,7 @@
 	num = 1
 	den = 1
       end
-      Rational.new!(num, den)
+      Rational(num, den)
     elsif other.kind_of?(Float)
       Float(self) ** other
     else
@@ -187,7 +187,7 @@
   def power2(other)
     if other.kind_of?(Rational)
       if self < 0
-	return Complex(self, 0) ** other
+	return Complex.__send__(:new!, self, 0) ** other
       elsif other == 0
 	return Rational(1,1)
       elsif self == 0
@@ -219,7 +219,7 @@
 	num = 1
 	den = 1
       end
-      Rational.new!(num, den)
+      Rational(num, den)
     elsif other.kind_of?(Float)
       Float(self) ** other
     else
@@ -306,4 +306,3 @@
 class Complex
   Unify = true
 end
-

Modified: MacRuby/trunk/lib/mkmf.rb
===================================================================
--- MacRuby/trunk/lib/mkmf.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/mkmf.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -66,6 +66,8 @@
 $solaris = /solaris/ =~ RUBY_PLATFORM
 $dest_prefix_pattern = (File::PATH_SEPARATOR == ';' ? /\A([[:alpha:]]:)?/ : /\A/)
 
+# :stopdoc:
+
 def config_string(key, config = CONFIG)
   s = config[key] and !s.empty? and block_given? ? yield(s) : s
 end
@@ -171,14 +173,18 @@
 CONFTEST_C = "conftest.c".freeze
 
 class String
+  # Wraps a string in escaped quotes if it contains whitespace.
   def quote
     /\s/ =~ self ? "\"#{self}\"" : "#{self}"
   end
+
+  # Generates a string used as cpp macro name.
   def tr_cpp
     strip.upcase.tr_s("^A-Z0-9_", "_")
   end
 end
 class Array
+  # Wraps all strings in escaped quotes if they contain whitespace.
   def quote
     map {|s| s.quote}
   end
@@ -188,6 +194,8 @@
   FileUtils.rm_f(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)
   (t = File.mtime(target)) rescue return nil
   Array === times or times = [times]
@@ -210,6 +218,12 @@
   end
 end
 
+# This is a custom logging module. It generates an mkmf.log file when you
+# run your extconf.rb script. This can be useful for debugging unexpected
+# failures.
+#
+# This module and its associated methods are meant for internal use only.
+#
 module Logging
   @log = nil
   @logfile = 'mkmf.log'
@@ -538,6 +552,7 @@
   log_src(src)
 end
 
+# This is used internally by the have_macro? method.
 def macro_defined?(macro, src, opt = "", &b)
   src = src.sub(/[^\n]\z/, "\\&\n")
   try_compile(src + <<"SRC", opt, &b)
@@ -606,7 +621,7 @@
   install_files(mfile, [["lib/**/*.rb", dest, "lib"]], nil, srcdir)
 end
 
-def append_library(libs, lib)
+def append_library(libs, lib) # :no-doc:
   format(LIBARG, lib) + " " + libs
 end
 
@@ -617,6 +632,11 @@
   end
 end
 
+# This emits a string to stdout that allows users to see the results of the
+# various have* and find* methods as they are tested.
+#
+# Internal use only.
+#
 def checking_for(m, fmt = nil)
   f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim #'
   m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... "
@@ -646,6 +666,8 @@
   end
 end
 
+# :startdoc:
+
 # Returns whether or not +macro+ is defined either in the common header
 # files or within any +headers+ you provide.
 #
@@ -665,7 +687,7 @@
 # If +headers+ are provided, it will include those header files as the
 # header files it looks in when searching for +func+.
 #
-# Real name of the library to be linked can be altered by
+# The real name of the library to be linked can be altered by
 # '--with-FOOlib' configuration option.
 #
 def have_library(lib, func = nil, headers = nil, &b)
@@ -948,6 +970,10 @@
   end
 end
 
+# :stopdoc:
+
+# Used internally by the what_type? method to determine if +type+ is a scalar
+# pointer.
 def scalar_ptr_type?(type, member = nil, headers = nil, &b)
   try_compile(<<"SRC", &b)   # pointer
 #{COMMON_HEADERS}
@@ -959,6 +985,8 @@
 SRC
 end
 
+# Used internally by the what_type? method to determine if +type+ is a scalar
+# pointer.
 def scalar_type?(type, member = nil, headers = nil, &b)
   try_compile(<<"SRC", &b)   # pointer
 #{COMMON_HEADERS}
@@ -1002,6 +1030,10 @@
   end
 end
 
+# This method is used internally by the find_executable method.
+#
+# Internal use only.
+#
 def find_executable0(bin, path = nil)
   ext = config_string('EXEEXT')
   if File.expand_path(bin) == bin
@@ -1022,12 +1054,25 @@
   nil
 end
 
+# :startdoc:
+
+# Searches for the executable +bin+ on +path+. The default path is your
+# PATH environment variable. If that isn't defined, it will resort to
+# searching /usr/local/bin, /usr/ucb, /usr/bin and /bin.
+#
+# If found, it will return the full path, including the executable name,
+# of where it was found.
+#
+# Note that this method does not actually affect the generated Makefile.
+#
 def find_executable(bin, path = nil)
   checking_for checking_message(bin, path) do
     find_executable0(bin, path)
   end
 end
 
+# :stopdoc:
+
 def arg_config(config, default=nil, &block)
   $arg_config << [config, default]
   defaults = []
@@ -1039,6 +1084,20 @@
   $configure_args.fetch(config.tr('_', '-'), *defaults, &block)
 end
 
+# :startdoc:
+
+# Tests for the presence of a --with-<tt>config</tt> or --without-<tt>config</tt>
+# option. Returns true if the with option is given, false if the without
+# option is given, and the default value otherwise.
+#
+# This can be useful for adding custom definitions, such as debug information.
+#
+# Example:
+#
+#    if with_config("debug")
+#       $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
+#    end
+#
 def with_config(config, default=nil)
   config = config.sub(/^--with[-_]/, '')
   val = arg_config("--with-"+config) do
@@ -1060,6 +1119,18 @@
   end
 end
 
+# Tests for the presence of an --enable-<tt>config</tt> or
+# --disable-<tt>config</tt> option. Returns true if the enable option is given,
+# false if the disable option is given, and the default value otherwise.
+#
+# This can be useful for adding custom definitions, such as debug information.
+#
+# Example:
+#
+#    if enable_config("debug")
+#       $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
+#    end
+#
 def enable_config(config, default=nil)
   if arg_config("--enable-"+config)
     true
@@ -1072,6 +1143,32 @@
   end
 end
 
+# Generates a header file consisting of the various macro definitions generated
+# by other methods such as have_func and have_header. These are then wrapped in
+# a custom #ifndef based on the +header+ file name, which defaults to
+# 'extconf.h'.
+#
+# For example:
+# 
+#    # extconf.rb
+#    require 'mkmf'
+#    have_func('realpath')
+#    have_header('sys/utime.h')
+#    create_header
+#    create_makefile('foo')
+#
+# The above script would generate the following extconf.h file:
+#
+#    #ifndef EXTCONF_H
+#    #define EXTCONF_H
+#    #define HAVE_REALPATH 1
+#    #define HAVE_SYS_UTIME_H 1
+#    #endif
+#
+# Given that the create_header method generates a file based on definitions
+# set earlier in your extconf.rb file, you will probably want to make this
+# one of the last methods you call in your script.
+#
 def create_header(header = "extconf.h")
   message "creating %s\n", header
     # FIXME: cannot use this in MacRuby yet
@@ -1141,6 +1238,10 @@
   [idir, ldir]
 end
 
+# :stopdoc:
+
+# Handles meta information about installed libraries. Uses your platform's
+# pkg-config program if it has one.
 def pkg_config(pkg)
   if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
     # iff package specific config command is given
@@ -1178,6 +1279,10 @@
   /\A\$[\(\{]/ =~ dir ? dir : "$(DESTDIR)"+dir
 end
 
+# Converts forward slashes to backslashes. Aimed at MS Windows.
+#
+# Internal use only.
+#
 def winsep(s)
   s.tr('/', '\\')
 end
@@ -1212,7 +1317,7 @@
 VPATH = #{vpath.join(CONFIG['PATH_SEPARATOR'])}
 }
   if $extmk
-    mk << "RUBYLIB = -\nRUBYOPT = -rpurelib.rb\n"
+    mk << "RUBYLIB = -\nRUBYOPT = -r$(top_srcdir)/ext/purelib.rb\n"
   end
   if destdir = CONFIG["prefix"][$dest_prefix_pattern, 1]
     mk << "\nDESTDIR = #{destdir}\n"
@@ -1288,6 +1393,7 @@
   end
   mk
 end
+# :startdoc:
 
 def dummy_makefile(srcdir)
   configuration(srcdir) << <<RULES << CLEANINGS
@@ -1403,6 +1509,10 @@
 # instead of copying files around manually, because some third party
 # libraries may depend on the +target_prefix+ being set properly.
 #
+# The +srcprefix+ argument can be used to override the default source
+# directory, i.e. the current directory . It is included as part of the VPATH
+# and added to the list of INCFLAGS.
+#
 def create_makefile(target, srcprefix = nil)
   $target = target
   libpath = $DEFLIBPATH|$LIBPATH
@@ -1634,6 +1744,8 @@
   mfile.close if mfile
 end
 
+# :stopdoc:
+
 def init_mkmf(config = CONFIG)
   $makefile_created = false
   $arg_config = []
@@ -1687,6 +1799,11 @@
 Provided configuration options:
 MESSAGE
 
+# Returns whether or not the Makefile was successfully generated. If not,
+# the script will abort with an error message.
+#
+# Internal use only.
+#
 def mkmf_failed(path)
   unless $makefile_created or File.exist?("Makefile")
     opts = $arg_config.collect {|t, n| "\t#{t}#{n ? "=#{n}" : ""}\n"}
@@ -1694,6 +1811,8 @@
   end
 end
 
+# :startdoc:
+
 init_mkmf
 
 $make = with_config("make-prog", ENV["MAKE"] || "make")

Modified: MacRuby/trunk/lib/net/http.rb
===================================================================
--- MacRuby/trunk/lib/net/http.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/net/http.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -19,10 +19,10 @@
 # See Net::HTTP for an overview and examples. 
 # 
 # NOTE: You can find Japanese version of this document here:
-# http://www.ruby-lang.org/ja/man/?cmd=view;name=net%2Fhttp.rb
+# http://www.ruby-lang.org/ja/man/html/net_http.html
 # 
 #--
-# $Id: http.rb 15442 2008-02-12 06:18:06Z naruse $
+# $Id: http.rb 16033 2008-04-15 08:12:30Z kazu $
 #++ 
 
 require 'net/protocol'
@@ -284,7 +284,7 @@
   class HTTP < Protocol
 
     # :stopdoc:
-    Revision = %q$Revision: 15442 $.split[1]
+    Revision = %q$Revision: 16033 $.split[1]
     HTTPVersion = '1.1'
     @newimpl = true
     begin

Modified: MacRuby/trunk/lib/net/pop.rb
===================================================================
--- MacRuby/trunk/lib/net/pop.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/net/pop.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,9 +13,9 @@
 # Ruby Distribute License.
 # 
 # NOTE: You can find Japanese version of this document at:
-# http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=net%2Fpop.rb
+# http://www.ruby-lang.org/ja/man/html/net_pop.html
 # 
-#   $Id: pop.rb 14479 2007-12-22 08:31:53Z gotoyuzo $
+#   $Id: pop.rb 16033 2008-04-15 08:12:30Z kazu $
 # 
 # See Net::POP3 for documentation.
 #
@@ -196,7 +196,7 @@
   # 
   class POP3 < Protocol
 
-    Revision = %q$Revision: 14479 $.split[1]
+    Revision = %q$Revision: 16033 $.split[1]
 
     #
     # Class Parameters
@@ -577,6 +577,8 @@
 
     def do_finish
       @mails = nil
+      @n_mails = nil
+      @n_bytes = nil
       @command.quit if @command
     ensure
       @started = false

Modified: MacRuby/trunk/lib/net/smtp.rb
===================================================================
--- MacRuby/trunk/lib/net/smtp.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/net/smtp.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -12,9 +12,9 @@
 # modify this program under the same terms as Ruby itself.
 # 
 # NOTE: You can find Japanese version of this document at:
-# http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=net%2Fsmtp.rb
+# http://www.ruby-lang.org/ja/man/html/net_smtp.html
 # 
-# $Id: smtp.rb 13824 2007-11-04 20:36:20Z matz $
+# $Id: smtp.rb 16033 2008-04-15 08:12:30Z kazu $
 #
 # See Net::SMTP for documentation. 
 # 
@@ -172,7 +172,7 @@
   #
   class SMTP
 
-    Revision = %q$Revision: 13824 $.split[1]
+    Revision = %q$Revision: 16033 $.split[1]
 
     # The default SMTP port number, 25.
     def SMTP.default_port

Modified: MacRuby/trunk/lib/net/telnet.rb
===================================================================
--- MacRuby/trunk/lib/net/telnet.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/net/telnet.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -164,7 +164,7 @@
     CR   = "\015"   
     LF   = "\012" 
     EOL  = CR + LF 
-    REVISION = '$Id: telnet.rb 13781 2007-10-25 22:12:53Z jeg2 $'
+    REVISION = '$Id: telnet.rb 16257 2008-05-01 14:57:40Z jeg2 $'
     # :startdoc:
 
     #
@@ -523,10 +523,15 @@
     #            value specified when this instance was created will be
     #            used, or, failing that, the default value of 0 seconds,
     #            which means not to wait for more input.
+    # FailEOF:: if true, when the remote end closes the connection then an
+    #           EOFError will be raised. Otherwise, defaults to the old
+    #           behaviour that the function will return whatever data
+    #           has been received already, or nil if nothing was received.
     #           
     def waitfor(options) # :yield: recvdata
       time_out = @options["Timeout"]
       waittime = @options["Waittime"]
+      fail_eof = @options["FailEOF"]
 
       if options.kind_of?(Hash)
         prompt   = if options.has_key?("Match")
@@ -538,6 +543,7 @@
                    end
         time_out = options["Timeout"]  if options.has_key?("Timeout")
         waittime = options["Waittime"] if options.has_key?("Waittime")
+        fail_eof = options["FailEOF"]  if options.has_key?("FailEOF")
       else
         prompt = options
       end
@@ -562,7 +568,8 @@
                Integer(c.rindex(/#{IAC}#{SB}/no))
               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)
+            elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) ||
+                       c.rindex(/\r\z/no)
               buf = preprocess(c[0 ... pt])
               rest = c[pt .. -1]
             else
@@ -574,14 +581,21 @@
            #
            # We cannot use preprocess() on this data, because that
            # method makes some Telnetmode-specific assumptions.
-           buf = c
-           buf.gsub!(/#{EOL}/no, "\n") unless @options["Binmode"]
+           buf = rest + c
            rest = ''
+           unless @options["Binmode"]
+             if pt = buf.rindex(/\r\z/no)
+               buf = buf[0 ... pt]
+               rest = buf[pt .. -1]
+             end
+             buf.gsub!(/#{EOL}/no, "\n")
+           end
           end
           @log.print(buf) if @options.has_key?("Output_log")
           line += buf
           yield buf if block_given?
         rescue EOFError # End of file reached
+          raise if fail_eof
           if line == ''
             line = nil
             yield nil if block_given?

Modified: MacRuby/trunk/lib/open3.rb
===================================================================
--- MacRuby/trunk/lib/open3.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/open3.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -9,77 +9,75 @@
 #
 
 #
-# Open3 grants you access to stdin, stdout, and stderr when running another
-# program. Example:
+# Open3 grants you access to stdin, stdout, stderr and a thread to wait the
+# child process when running another program.
 #
+# Example:
+#
 #   require "open3"
 #   include Open3
 #   
-#   stdin, stdout, stderr = popen3('nroff -man')
+#   stdin, stdout, stderr, wait_thr = popen3('nroff -man')
 #
-# Open3.popen3 can also take a block which will receive stdin, stdout and
-# stderr as parameters.  This ensures stdin, stdout and stderr are closed
-# once the block exits. Example:
+# Open3.popen3 can also take a block which will receive stdin, stdout,
+# stderr and wait_thr as parameters.
+# This ensures stdin, stdout and stderr are closed and
+# the process is terminated once the block exits.
 #
+# Example:
+#
 #   require "open3"
 #
-#   Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
+#   Open3.popen3('nroff -man') { |stdin, stdout, stderr, wait_thr| ... }
 #
 
 module Open3
   # 
   # Open stdin, stdout, and stderr streams and start external executable.
+  # In addition, a thread for waiting the started process is noticed.
+  # The thread has a thread variable :pid which is the pid of the started
+  # process.
+  #
   # Non-block form:
   #   
-  #   require 'open3'
+  #   stdin, stdout, stderr, wait_thr = Open3.popen3(cmd)
+  #   pid = wait_thr[:pid]  # pid of the started process.
+  #   ...
+  #   stdin.close  # stdin, stdout and stderr should be closed in this form.
+  #   stdout.close
+  #   stderr.close
+  #   exit_status = wait_thr.value  # Process::Status object returned.
   #
-  #   [stdin, stdout, stderr] = Open3.popen3(cmd)
-  #
   # Block form:
   #
-  #   require 'open3'
+  #   Open3.popen3(cmd) { |stdin, stdout, stderr, wait_thr| ... }
   #
-  #   Open3.popen3(cmd) { |stdin, stdout, stderr| ... }
+  # The parameter +cmd+ is passed directly to Kernel#spawn.
   #
-  # The parameter +cmd+ is passed directly to Kernel#exec.
+  # wait_thr.value waits the termination of the process.
+  # The block form also waits the process when it returns.
   #
+  # Closing stdin, stdout and stderr does not wait the process.
+  #
   def popen3(*cmd)
     pw = IO::pipe   # pipe[0] for read, pipe[1] for write
     pr = IO::pipe
     pe = IO::pipe
 
-    pid = fork{
-      # child
-      fork{
-	# grandchild
-	pw[1].close
-	STDIN.reopen(pw[0])
-	pw[0].close
-
-	pr[0].close
-	STDOUT.reopen(pr[1])
-	pr[1].close
-
-	pe[0].close
-	STDERR.reopen(pe[1])
-	pe[1].close
-
-	exec(*cmd)
-      }
-      exit!(0)
-    }
-
+    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
-    Process.waitpid(pid)
-    pi = [pw[1], pr[0], pe[0]]
+    pi = [pw[1], pr[0], pe[0], wait_thr]
     pw[1].sync = true
     if defined? yield
       begin
 	return yield(*pi)
       ensure
-	pi.each{|p| p.close unless p.closed?}
+	[pw[1], pr[0], pe[0]].each{|p| p.close unless p.closed?}
+        wait_thr.join
       end
     end
     pi

Modified: MacRuby/trunk/lib/pstore.rb
===================================================================
--- MacRuby/trunk/lib/pstore.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/pstore.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,12 +3,14 @@
 # pstore.rb -
 #   originally by matz
 #   documentation by Kev Jackson and James Edward Gray II
+#   improved by Hongli Lai
 #
 # See PStore for documentation.
 
 
 require "fileutils"
 require "digest/md5"
+require "thread"
 
 #
 # PStore implements a file based persistance mechanism based on a Hash.  User
@@ -77,6 +79,20 @@
 #    end
 #  end
 #
+# == Transaction modes
+#
+# By default, file integrity is only ensured as long as the operating system
+# (and the underlying hardware) doesn't raise any unexpected I/O errors. If an
+# I/O error occurs while PStore is writing to its file, then the file will
+# become corrupted.
+#
+# You can prevent this by setting <em>pstore.ultra_safe = true</em>.
+# However, this results in a minor performance loss, and only works on platforms
+# that support atomic file renames. Please consult the documentation for
+# +ultra_safe+ for details.
+#
+# Needless to say, if you're storing valuable data with PStore, then you should
+# backup the PStore files from time to time.
 class PStore
   binmode = defined?(File::BINARY) ? File::BINARY : 0
   RDWR_ACCESS = File::RDWR | File::CREAT | binmode
@@ -86,12 +102,24 @@
   # The error type thrown by all PStore methods.
   class Error < StandardError
   end
+  
+  # Whether PStore should do its best to prevent file corruptions, even when under
+  # unlikely-to-occur error conditions such as out-of-space conditions and other
+  # unusual OS filesystem errors. Setting this flag comes at the price in the form
+  # of a performance loss.
+  #
+  # This flag only has effect on platforms on which file renames are atomic (e.g.
+  # all POSIX platforms: Linux, MacOS X, FreeBSD, etc). The default value is false.
+  attr_accessor :ultra_safe
 
   # 
   # To construct a PStore object, pass in the _file_ path where you would like 
   # the data to be stored.
+  #
+  # PStore objects are always reentrant. But if _thread_safe_ is set to true,
+  # then it will become thread-safe at the cost of a minor performance hit.
   # 
-  def initialize(file)
+  def initialize(file, thread_safe = false)
     dir = File::dirname(file)
     unless File::directory? dir
       raise PStore::Error, format("directory %s does not exist", dir)
@@ -102,6 +130,12 @@
     @transaction = false
     @filename = file
     @abort = false
+    @ultra_safe = false
+    if @thread_safe
+      @lock = Mutex.new
+    else
+      @lock = DummyMutex.new
+    end
   end
 
   # Raises PStore::Error if the calling code is not in a PStore#transaction.
@@ -142,10 +176,10 @@
   def fetch(name, default=PStore::Error)
     in_transaction
     unless @table.key? name
-      if default==PStore::Error
-	raise PStore::Error, format("undefined root name `%s'", name)
+      if default == PStore::Error
+        raise PStore::Error, format("undefined root name `%s'", name)
       else
-	return default
+        return default
       end
     end
     @table[name]
@@ -281,94 +315,208 @@
   # 
   # Note that PStore does not support nested transactions.
   #
-  def transaction(read_only=false)  # :yields:  pstore
+  def transaction(read_only = false, &block)  # :yields:  pstore
+    value = nil
     raise PStore::Error, "nested transaction" if @transaction
-    begin
+    @lock.synchronize do
       @rdonly = read_only
+      @transaction = true
       @abort = false
-      @transaction = true
-      value = nil
-      new_file = @filename + ".new"
-
-      content = nil
-      unless read_only
-        file = File.open(@filename, RDWR_ACCESS)
-        file.flock(File::LOCK_EX)
-        commit_new(file) if FileTest.exist?(new_file)
-        content = file.read()
+      file = open_and_lock_file(@filename, read_only)
+      if file
+        begin
+          @table, checksum, original_data_size = load_data(file, read_only)
+          
+          catch(:pstore_abort_transaction) do
+            value = yield(self)
+          end
+          
+          if !@abort && !read_only
+            save_data(checksum, original_data_size, file)
+          end
+        ensure
+          file.close if !file.closed?
+        end
       else
+        # This can only occur if read_only == true.
+        @table = {}
+        catch(:pstore_abort_transaction) do
+          value = yield(self)
+        end
+      end
+    end
+  ensure
+    @transaction = false
+    value
+  end
+  
+  private
+  # Constant for relieving Ruby's garbage collector.
+  EMPTY_STRING = ""
+  EMPTY_MARSHAL_DATA = Marshal.dump({})
+  EMPTY_MARSHAL_CHECKSUM = Digest::MD5.digest(EMPTY_MARSHAL_DATA)
+  
+  class DummyMutex
+    def synchronize
+      yield
+    end
+  end
+  
+  #
+  # Open the specified filename (either in read-only mode or in
+  # read-write mode) and lock it for reading or writing.
+  #
+  # The opened File object will be returned. If _read_only_ is true,
+  # and the file does not exist, then nil will be returned.
+  #
+  # All exceptions are propagated.
+  #
+  def open_and_lock_file(filename, read_only)
+    if read_only
+      begin
+        file = File.new(filename, RD_ACCESS)
         begin
-          file = File.open(@filename, RD_ACCESS)
           file.flock(File::LOCK_SH)
-          content = (File.open(new_file, RD_ACCESS) {|n| n.read} rescue file.read())
-        rescue Errno::ENOENT
-          content = ""
+          return file
+        rescue
+          file.close
+          raise
         end
+      rescue Errno::ENOENT
+        return nil
       end
-
-      if content != ""
-	@table = load(content)
-        if !read_only
-          size = content.size
-          md5 = Digest::MD5.digest(content)
+    else
+      file = File.new(filename, RDWR_ACCESS)
+      file.flock(File::LOCK_EX)
+      return file
+    end
+  end
+  
+  # Load the given PStore file.
+  # If +read_only+ is true, the unmarshalled Hash will be returned.
+  # If +read_only+ is false, a 3-tuple will be returned: the unmarshalled
+  # Hash, an MD5 checksum of the data, and the size of the data.
+  def load_data(file, read_only)
+    if read_only
+      begin
+        table = load(file)
+        if !table.is_a?(Hash)
+          raise Error, "PStore file seems to be corrupted."
         end
+      rescue EOFError
+        # This seems to be a newly-created file.
+        table = {}
+      end
+      table
+    else
+      data = file.read
+      if data.empty?
+        # This seems to be a newly-created file.
+        table = {}
+        checksum = empty_marshal_checksum
+        size = empty_marshal_data.size
       else
-	@table = {}
+        table = load(data)
+        checksum = Digest::MD5.digest(data)
+        size = data.size
+        if !table.is_a?(Hash)
+          raise Error, "PStore file seems to be corrupted."
+        end
       end
-      content = nil		# unreference huge data
-
-      begin
-	catch(:pstore_abort_transaction) do
-	  value = yield(self)
-	end
-      rescue Exception
-	@abort = true
-	raise
-      ensure
-	if !read_only and !@abort
-          tmp_file = @filename + ".tmp"
-	  content = dump(@table)
-	  if !md5 || size != content.size || md5 != Digest::MD5.digest(content)
-            File.open(tmp_file, WR_ACCESS) {|t| t.write(content)}
-            File.rename(tmp_file, new_file)
-            commit_new(file)
-          end
-          content = nil		# unreference huge data
-	end
+      data.replace(EMPTY_STRING)
+      [table, checksum, size]
+    end
+  end
+  
+  def on_windows?
+    is_windows = RUBY_PLATFORM =~ /mswin/  ||
+                 RUBY_PLATFORM =~ /mingw/  ||
+                 RUBY_PLATFORM =~ /bbcwin/ ||
+                 RUBY_PLATFORM =~ /wince/
+    self.class.__send__(:define_method, :on_windows?) do
+      is_windows
+    end
+    is_windows
+  end
+  
+  # Check whether Marshal.dump supports the 'canonical' option. This option
+  # makes sure that Marshal.dump always dumps data structures in the same order.
+  # This is important because otherwise, the checksums that we generate may differ.
+  def marshal_dump_supports_canonical_option?
+    begin
+      Marshal.dump(nil, -1, true)
+      result = true
+    rescue
+      result = false
+    end
+    self.class.__send__(:define_method, :marshal_dump_supports_canonical_option?) do
+      result
+    end
+    result
+  end
+  
+  def save_data(original_checksum, original_file_size, file)
+    # We only want to save the new data if the size or checksum has changed.
+    # This results in less filesystem calls, which is good for performance.
+    if marshal_dump_supports_canonical_option?
+      new_data = Marshal.dump(@table, -1, true)
+    else
+      new_data = dump(@table)
+    end
+    new_checksum = Digest::MD5.digest(new_data)
+    
+    if new_data.size != original_file_size || new_checksum != original_checksum
+      if @ultra_safe && !on_windows?
+        # Windows doesn't support atomic file renames.
+        save_data_with_atomic_file_rename_strategy(new_data, file)
+      else
+        save_data_with_fast_strategy(new_data, file)
       end
+    end
+    
+    new_data.replace(EMPTY_STRING)
+  end
+  
+  def save_data_with_atomic_file_rename_strategy(data, file)
+    temp_filename = "#{@filename}.tmp.#{Process.pid}.#{rand 1000000}"
+    temp_file = File.new(temp_filename, WR_ACCESS)
+    begin
+      temp_file.flock(File::LOCK_EX)
+      temp_file.write(data)
+      temp_file.flush
+      File.rename(temp_filename, @filename)
+    rescue
+      File.unlink(temp_file) rescue nil
+      raise
     ensure
-      @table = nil
-      @transaction = false
-      file.close if file
+      temp_file.close
     end
-    value
   end
+  
+  def save_data_with_fast_strategy(data, file)
+    file.rewind
+    file.truncate(0)
+    file.write(data)
+  end
 
-  # This method is just a wrapped around Marshal.dump.
+
+  # This method is just a wrapped around Marshal.dump
+  # to allow subclass overriding used in YAML::Store.
   def dump(table)  # :nodoc:
     Marshal::dump(table)
   end
 
   # This method is just a wrapped around Marshal.load.
+  # to allow subclass overriding used in YAML::Store.
   def load(content)  # :nodoc:
     Marshal::load(content)
   end
 
-  # This method is just a wrapped around Marshal.load.
-  def load_file(file)  # :nodoc:
-    Marshal::load(file)
+  def empty_marshal_data
+    EMPTY_MARSHAL_DATA
   end
-
-  private
-  # Commits changes to the data store file.
-  def commit_new(f)
-    f.truncate(0)
-    f.rewind
-    new_file = @filename + ".new"
-    File.open(new_file, RD_ACCESS) do |nf|
-      FileUtils.copy_stream(nf, f)
-    end
-    File.unlink(new_file)
+  def empty_marshal_checksum
+    EMPTY_MARSHAL_CHECKSUM
   end
 end
 

Modified: MacRuby/trunk/lib/rational.rb
===================================================================
--- MacRuby/trunk/lib/rational.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rational.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,557 +1,19 @@
-#
-#   rational.rb -
-#       $Release Version: 0.5 $
-#       $Revision: 1.7 $
-#       by Keiju ISHITSUKA(SHL Japan Inc.)
-#
-# Documentation by Kevin Jackson and Gavin Sinclair.
-# 
-# When you <tt>require 'rational'</tt>, all interactions between numbers
-# potentially return a rational result.  For example:
-#
-#   1.quo(2)              # -> 0.5
-#   require 'rational'
-#   1.quo(2)              # -> Rational(1,2)
-# 
-# See Rational for full documentation.
-#
-
-#
-# Creates a Rational number (i.e. a fraction).  +a+ and +b+ should be Integers:
-# 
-#   Rational(1,3)           # -> 1/3
-#
-# Note: trying to construct a Rational with floating point or real values
-# produces errors:
-#
-#   Rational(1.1, 2.3)      # -> NoMethodError
-#
-def Rational(a, b = 1)
-  if a.kind_of?(Rational) && b == 1
-    a
-  else
-    Rational.reduce(a, b)
-  end
-end
-
-#
-# Rational implements a rational class for numbers.
-#
-# <em>A rational number is a number that can be expressed as a fraction p/q
-# where p and q are integers and q != 0.  A rational number p/q is said to have
-# numerator p and denominator q.  Numbers that are not rational are called
-# irrational numbers.</em> (http://mathworld.wolfram.com/RationalNumber.html)
-#
-# To create a Rational Number:
-#   Rational(a,b)             # -> a/b
-#   Rational.new!(a,b)        # -> a/b
-#
-# Examples:
-#   Rational(5,6)             # -> 5/6
-#   Rational(5)               # -> 5/1
-# 
-# Rational numbers are reduced to their lowest terms:
-#   Rational(6,10)            # -> 3/5
-#
-# But not if you use the unusual method "new!":
-#   Rational.new!(6,10)       # -> 6/10
-#
-# Division by zero is obviously not allowed:
-#   Rational(3,0)             # -> ZeroDivisionError
-#
-class Rational < Numeric
-  @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-'
-
-  #
-  # Reduces the given numerator and denominator to their lowest terms.  Use
-  # Rational() instead.
-  #
-  def Rational.reduce(num, den = 1)
-    raise ZeroDivisionError, "denominator is zero" if den == 0
-
-    if den < 0
-      num = -num
-      den = -den
-    end
-    gcd = num.gcd(den)
-    num = num.div(gcd)
-    den = den.div(gcd)
-    if den == 1 && defined?(Unify)
-      num
-    else
-      new!(num, den)
-    end
-  end
-
-  #
-  # Implements the constructor.  This method does not reduce to lowest terms or
-  # check for division by zero.  Therefore #Rational() should be preferred in
-  # normal use.
-  #
-  def Rational.new!(num, den = 1)
-    new(num, den)
-  end
-
-  private_class_method :new
-
-  #
-  # This method is actually private.
-  #
-  def initialize(num, den)
-    if den < 0
-      num = -num
-      den = -den
-    end
-    if num.kind_of?(Integer) and den.kind_of?(Integer)
-      @numerator = num
-      @denominator = den
-    else
-      @numerator = num.to_i
-      @denominator = den.to_i
-    end
-  end
-
-  #
-  # Returns the addition of this value and +a+.
-  #
-  # Examples:
-  #   r = Rational(3,4)      # -> Rational(3,4)
-  #   r + 1                  # -> Rational(7,4)
-  #   r + 0.5                # -> 1.25
-  #
-  def + (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.denominator
-      num_a = a.numerator * @denominator
-      Rational(num + num_a, @denominator * a.denominator)
-    elsif a.kind_of?(Integer)
-      self + Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) + a
-    else
-      x, y = a.coerce(self)
-      x + y
-    end
-  end
-
-  #
-  # Returns the difference of this value and +a+.
-  # subtracted.
-  #
-  # Examples:
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r - 1                # -> Rational(-1,4)
-  #   r - 0.5              # -> 0.25
-  #
-  def - (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.denominator
-      num_a = a.numerator * @denominator
-      Rational(num - num_a, @denominator*a.denominator)
-    elsif a.kind_of?(Integer)
-      self - Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) - a
-    else
-      x, y = a.coerce(self)
-      x - y
-    end
-  end
-
-  #
-  # Returns the product of this value and +a+.
-  #
-  # Examples:
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r * 2                # -> Rational(3,2)
-  #   r * 4                # -> Rational(3,1)
-  #   r * 0.5              # -> 0.375
-  #   r * Rational(1,2)    # -> Rational(3,8)
-  #
-  def * (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.numerator
-      den = @denominator * a.denominator
-      Rational(num, den)
-    elsif a.kind_of?(Integer)
-      self * Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) * a
-    else
-      x, y = a.coerce(self)
-      x * y
-    end
-  end
-
-  #
-  # Returns the quotient of this value and +a+.
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r / 2                # -> Rational(3,8)
-  #   r / 2.0              # -> 0.375
-  #   r / Rational(1,2)    # -> Rational(3,2)
-  #
-  def / (a)
-    if a.kind_of?(Rational)
-      num = @numerator * a.denominator
-      den = @denominator * a.numerator
-      Rational(num, den)
-    elsif a.kind_of?(Integer)
-      raise ZeroDivisionError, "division by zero" if a == 0
-      self / Rational.new!(a, 1)
-    elsif a.kind_of?(Float)
-      Float(self) / a
-    else
-      x, y = a.coerce(self)
-      x / y
-    end
-  end
-
-  #
-  # Returns this value raised to the given power.
-  #
-  # Examples:
-  #   r = Rational(3,4)    # -> Rational(3,4)
-  #   r ** 2               # -> Rational(9,16)
-  #   r ** 2.0             # -> 0.5625
-  #   r ** Rational(1,2)   # -> 0.866025403784439
-  #
-  def ** (other)
-    if other.kind_of?(Rational)
-      Float(self) ** other
-    elsif other.kind_of?(Integer)
-      if other > 0
-	num = @numerator ** other
-	den = @denominator ** other
-      elsif other < 0
-	num = @denominator ** -other
-	den = @numerator ** -other
-      elsif other == 0
-	num = 1
-	den = 1
-      end
-      Rational.new!(num, den)
-    elsif other.kind_of?(Float)
-      Float(self) ** other
-    else
-      x, y = other.coerce(self)
-      x ** y
-    end
-  end
-
-  def div(other)
-    (self / other).floor
-  end
-
-  #
-  # Returns the remainder when this value is divided by +other+.
-  #
-  # Examples:
-  #   r = Rational(7,4)    # -> Rational(7,4)
-  #   r % Rational(1,2)    # -> Rational(1,4)
-  #   r % 1                # -> Rational(3,4)
-  #   r % Rational(1,7)    # -> Rational(1,28)
-  #   r % 0.26             # -> 0.19
-  #
-  def % (other)
-    value = (self / other).floor
-    return self - other * value
-  end
-
-  #
-  # Returns the quotient _and_ remainder.
-  #
-  # Examples:
-  #   r = Rational(7,4)        # -> Rational(7,4)
-  #   r.divmod Rational(1,2)   # -> [3, Rational(1,4)]
-  #
-  def divmod(other)
-    value = (self / other).floor
-    return value, self - other * value
-  end
-
-  #
-  # Returns the absolute value.
-  #
-  def abs
-    if @numerator > 0
-      self
-    else
-      Rational.new!(- at numerator, @denominator)
-    end
-  end
-
-  #
-  # Returns +true+ iff this value is numerically equal to +other+.
-  #
-  # But beware:
-  #   Rational(1,2) == Rational(4,8)          # -> true
-  #   Rational(1,2) == Rational.new!(4,8)     # -> false
-  #
-  # Don't use Rational.new!
-  #
-  def == (other)
-    if other.kind_of?(Rational)
-      @numerator == other.numerator and @denominator == other.denominator
-    elsif other.kind_of?(Integer)
-      self == Rational.new!(other, 1)
-    elsif other.kind_of?(Float)
-      Float(self) == other
-    else
-      other == self
-    end
-  end
-
-  #
-  # Standard comparison operator.
-  #
-  def <=> (other)
-    if other.kind_of?(Rational)
-      num = @numerator * other.denominator
-      num_a = other.numerator * @denominator
-      v = num - num_a
-      if v > 0
-	return 1
-      elsif v < 0
-	return  -1
-      else
-	return 0
-      end
-    elsif other.kind_of?(Integer)
-      return self <=> Rational.new!(other, 1)
-    elsif other.kind_of?(Float)
-      return Float(self) <=> other
-    elsif defined? other.coerce
-      x, y = other.coerce(self)
-      return x <=> y
-    else
-      return nil
-    end
-  end
-
-  def coerce(other)
-    if other.kind_of?(Float)
-      return other, self.to_f
-    elsif other.kind_of?(Integer)
-      return Rational.new!(other, 1), self
-    else
-      super
-    end
-  end
-
-  #
-  # Converts the rational to an Integer.  Not the _nearest_ integer, the
-  # truncated integer.  Study the following example carefully:
-  #   Rational(+7,4).to_i             # -> 1
-  #   Rational(-7,4).to_i             # -> -2
-  #   (-1.75).to_i                    # -> -1
-  #
-  # In other words:
-  #   Rational(-7,4) == -1.75                 # -> true
-  #   Rational(-7,4).to_i == (-1.75).to_i     # false
-  #
-
-  def floor()
-    @numerator.div(@denominator)
-  end
-
-  def ceil()
-    -((- at numerator).div(@denominator))
-  end
-
-  def truncate()
-    if @numerator < 0
-      return -((- at numerator).div(@denominator))
-    end
-    @numerator.div(@denominator)
-  end
-
-  alias_method :to_i, :truncate
-
-  def round()
-    if @numerator < 0
-      num = - at numerator
-      num = num * 2 + @denominator
-      den = @denominator * 2
-      -(num.div(den))
-    else
-      num = @numerator * 2 + @denominator
-      den = @denominator * 2
-      num.div(den)
-    end
-  end
-
-  #
-  # Converts the rational to a Float.
-  #
-  def to_f
-    @numerator.quof(@denominator)
-  end
-
-  #
-  # Returns a string representation of the rational number.
-  #
-  # Example:
-  #   Rational(3,4).to_s          #  "3/4"
-  #   Rational(8).to_s            #  "8"
-  #
-  def to_s
-    if @denominator == 1
-      @numerator.to_s
-    else
-      @numerator.to_s+"/"+ at denominator.to_s
-    end
-  end
-
-  #
-  # Returns +self+.
-  #
-  def to_r
-    self
-  end
-
-  #
-  # Returns a reconstructable string representation:
-  #
-  #   Rational(5,8).inspect     # -> "Rational(5, 8)"
-  #
-  def inspect
-    sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
-  end
-
-  #
-  # Returns a hash code for the object.
-  #
-  def hash
-    @numerator.hash ^ @denominator.hash
-  end
-
-  attr :numerator
-  attr :denominator
-
-  private :initialize
-end
-
-class Integer
-  #
-  # In an integer, the value _is_ the numerator of its rational equivalent.
-  # Therefore, this method returns +self+.
-  #
-  def numerator
-    self
-  end
-
-  #
-  # In an integer, the denominator is 1.  Therefore, this method returns 1.
-  #
-  def denominator
-    1
-  end
-
-  #
-  # Returns a Rational representation of this integer.
-  #
-  def to_r
-    Rational(self, 1)
-  end
-
-  #
-  # Returns the <em>greatest common denominator</em> of the two numbers (+self+
-  # and +n+).
-  #
-  # Examples:
-  #   72.gcd 168           # -> 24
-  #   19.gcd 36            # -> 1
-  #
-  # The result is positive, no matter the sign of the arguments.
-  #
-  def gcd(other)
-    min = self.abs
-    max = other.abs
-    while min > 0
-      tmp = min
-      min = max % min
-      max = tmp
-    end
-    max
-  end
-
-  # Examples:
-  #   6.lcm 7        # -> 42
-  #   6.lcm 9        # -> 18
-  #
-  def lcm(other)
-    if self.zero? or other.zero?
-      0
-    else
-      (self.div(self.gcd(other)) * other).abs
-    end
-  end
-  
-  #
-  # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments
-  # (+self+ and +other+).  This is more efficient than calculating them
-  # separately.
-  #
-  # Example:
-  #   6.gcdlcm 9     # -> [3, 18]
-  #
-  def gcdlcm(other)
-    gcd = self.gcd(other)
-    if self.zero? or other.zero?
-      [gcd, 0]
-    else
-      [gcd, (self.div(gcd) * other).abs]
-    end
-  end
-end
-
 class Fixnum
-  alias quof quo
-  remove_method :quo
 
-  # If Rational is defined, returns a Rational number instead of a Float.
-  def quo(other)
-    Rational.new!(self, 1) / other
-  end
+  alias quof fdiv
   alias rdiv quo
 
-  # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
-  def rpower (other)
-    if other >= 0
-      self.power!(other)
-    else
-      Rational.new!(self, 1)**other
-    end
-  end
+  alias power! **
+  alias rpower **
+
 end
 
 class Bignum
-  alias quof quo
-  remove_method :quo
 
-  # If Rational is defined, returns a Rational number instead of a Float.
-  def quo(other)
-    Rational.new!(self, 1) / other
-  end
+  alias quof fdiv
   alias rdiv quo
 
-  # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
-  def rpower (other)
-    if other >= 0
-      self.power!(other)
-    else
-      Rational.new!(self, 1)**other
-    end
-  end
-end
+  alias power! **
+  alias rpower **
 
-unless defined? 1.power!
-  class Fixnum
-    alias power! **
-    alias ** rpower
-  end
-  class Bignum
-    alias power! **
-    alias ** rpower
-  end
 end

Modified: MacRuby/trunk/lib/rdoc/code_objects.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/code_objects.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/code_objects.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -410,8 +410,8 @@
       end
       if result && method
         if !result.respond_to?(:find_local_symbol)
-          p result.name
-          p method
+          #p result.name
+          #p method
           fail
         end
         result = result.find_local_symbol(method)

Modified: MacRuby/trunk/lib/rdoc/generator/html.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/generator/html.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/generator/html.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -68,6 +68,7 @@
   def initialize(options) #:not-new:
     @options = options
     load_html_template
+    @main_page_path = nil
   end
 
   ##
@@ -247,7 +248,7 @@
     @main_page = @options.main_page
     @main_page_ref = nil
     if @main_page
-      @main_page_ref = AllReferences[@main_page]
+      @main_page_ref = RDoc::Generator::AllReferences[@main_page]
       if @main_page_ref then
         @main_page_path = @main_page_ref.path
       else
@@ -256,7 +257,7 @@
     end
 
     unless @main_page_path then
-      file = @files.find { |file| file.document_self }
+      file = @files.find { |context| context.document_self }
       @main_page_path = file.path if file
     end
 

Modified: MacRuby/trunk/lib/rdoc/generator.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/generator.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/generator.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -921,26 +921,27 @@
     def params
       # params coming from a call-seq in 'C' will start with the
       # method name
-      if p !~ /^\w/
-        p = @context.params.gsub(/\s*\#.*/, '')
-        p = p.tr("\n", " ").squeeze(" ")
-        p = "(" + p + ")" unless p[0] == ?(
+      params = @context.params
+      if params !~ /^\w/
+        params = @context.params.gsub(/\s*\#.*/, '')
+        params = params.tr("\n", " ").squeeze(" ")
+        params = "(" + params + ")" unless params[0] == ?(
 
         if (block = @context.block_params)
          # If this method has explicit block parameters, remove any
          # explicit &block
 
-         p.sub!(/,?\s*&\w+/, '')
+         params.sub!(/,?\s*&\w+/, '')
 
           block.gsub!(/\s*\#.*/, '')
           block = block.tr("\n", " ").squeeze(" ")
           if block[0] == ?(
             block.sub!(/^\(/, '').sub!(/\)/, '')
           end
-          p << " {|#{block.strip}| ...}"
+          params << " {|#{block.strip}| ...}"
         end
       end
-      CGI.escapeHTML(p)
+      CGI.escapeHTML(params)
     end
 
     def create_source_code_file(code_body)

Modified: MacRuby/trunk/lib/rdoc/markup/inline.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/markup/inline.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/markup/inline.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -39,12 +39,12 @@
     end
   end
 
+  AttrChanger = Struct.new(:turn_on, :turn_off)
+
   ##
   # An AttrChanger records a change in attributes. It contains a bitmap of the
   # attributes to turn on, and a bitmap of those to turn off.
 
-  AttrChanger = Struct.new(:turn_on, :turn_off)
-
   class AttrChanger
     def to_s
       "Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}"
@@ -96,266 +96,6 @@
 
   end
 
-  class AttributeManager
-
-    NULL = "\000".freeze
-
-    ##
-    # We work by substituting non-printing characters in to the text. For now
-    # I'm assuming that I can substitute a character in the range 0..8 for a 7
-    # bit character without damaging the encoded string, but this might be
-    # optimistic
-
-    A_PROTECT  = 004
-    PROTECT_ATTR  = A_PROTECT.chr
-
-    ##
-    # This maps delimiters that occur around words (such as *bold* or +tt+)
-    # where the start and end delimiters and the same. This lets us optimize
-    # the regexp
-
-    MATCHING_WORD_PAIRS = {}
-
-    ##
-    # And this is used when the delimiters aren't the same. In this case the
-    # hash maps a pattern to the attribute character
-
-    WORD_PAIR_MAP = {}
-
-    ##
-    # This maps HTML tags to the corresponding attribute char
-
-    HTML_TAGS = {}
-
-    ##
-    # And this maps _special_ sequences to a name. A special sequence is
-    # something like a WikiWord
-
-    SPECIAL = {}
-
-    ##
-    # Return an attribute object with the given turn_on and turn_off bits set
-
-    def attribute(turn_on, turn_off)
-      AttrChanger.new(turn_on, turn_off)
-    end
-
-    def change_attribute(current, new)
-      diff = current ^ new
-      attribute(new & diff, current & diff)
-    end
-
-    def changed_attribute_by_name(current_set, new_set)
-      current = new = 0
-      current_set.each {|name| current |= Attribute.bitmap_for(name) }
-      new_set.each {|name| new |= Attribute.bitmap_for(name) }
-      change_attribute(current, new)
-    end
-
-    def copy_string(start_pos, end_pos)
-      res = @str[start_pos...end_pos]
-      res.gsub!(/\000/, '')
-      res
-    end
-
-    ##
-    # Map attributes like <b>text</b>to the sequence
-    # \001\002<char>\001\003<char>, where <char> is a per-attribute specific
-    # character
-
-    def convert_attrs(str, attrs)
-      # first do matching ones
-      tags = MATCHING_WORD_PAIRS.keys.join("")
-
-      re = /(^|\W)([#{tags}])([#\\]?[\w.\/]+?\S?)\2(\W|$)/
-
-      1 while str.gsub!(re) do
-        attr = MATCHING_WORD_PAIRS[$2]
-        attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr)
-        $1 + NULL * $2.length + $3 + NULL * $2.length + $4
-      end
-
-      # then non-matching
-      unless WORD_PAIR_MAP.empty? then
-        WORD_PAIR_MAP.each do |regexp, attr|
-          str.gsub!(regexp) {
-            attrs.set_attrs($`.length + $1.length, $2.length, attr)
-            NULL * $1.length + $2 + NULL * $3.length
-          }
-        end
-      end
-    end
-
-    def convert_html(str, attrs)
-      tags = HTML_TAGS.keys.join '|'
-
-      1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) {
-        attr = HTML_TAGS[$1.downcase]
-        html_length = $1.length + 2
-        seq = NULL * html_length
-        attrs.set_attrs($`.length + html_length, $2.length, attr)
-        seq + $2 + seq + NULL
-      }
-    end
-
-    def convert_specials(str, attrs)
-      unless SPECIAL.empty?
-        SPECIAL.each do |regexp, attr|
-          str.scan(regexp) do
-            attrs.set_attrs($`.length, $&.length, attr | Attribute::SPECIAL)
-          end
-        end
-      end
-    end
-
-    ##
-    # A \ in front of a character that would normally be processed turns off
-    # processing. We do this by turning \< into <#{PROTECT}
-
-    PROTECTABLE = %w[<\\]
-
-    def mask_protected_sequences
-      protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])")
-      @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}")
-    end
-
-    def unmask_protected_sequences
-      @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000")
-    end
-
-    def initialize
-      add_word_pair("*", "*", :BOLD)
-      add_word_pair("_", "_", :EM)
-      add_word_pair("+", "+", :TT)
-
-      add_html("em", :EM)
-      add_html("i",  :EM)
-      add_html("b",  :BOLD)
-      add_html("tt",   :TT)
-      add_html("code", :TT)
-
-      add_special(/<!--(.*?)-->/, :COMMENT)
-    end
-
-    def add_word_pair(start, stop, name)
-      raise "Word flags may not start '<'" if start[0] == ?<
-      bitmap = Attribute.bitmap_for(name)
-      if start == stop
-        MATCHING_WORD_PAIRS[start] = bitmap
-      else
-        pattern = Regexp.new("(" + Regexp.escape(start) + ")" +
-#                             "([A-Za-z]+)" +
-                             "(\\S+)" +
-                             "(" + Regexp.escape(stop) +")")
-        WORD_PAIR_MAP[pattern] = bitmap
-      end
-      PROTECTABLE << start[0,1]
-      PROTECTABLE.uniq!
-    end
-
-    def add_html(tag, name)
-      HTML_TAGS[tag.downcase] = Attribute.bitmap_for(name)
-    end
-
-    def add_special(pattern, name)
-      SPECIAL[pattern] = Attribute.bitmap_for(name)
-    end
-
-    def flow(str)
-      @str = str
-
-      puts("Before flow, str='#{@str.dump}'") if $DEBUG_RDOC
-      mask_protected_sequences
-
-      @attrs = 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
-
-    def display_attributes
-      puts
-      puts @str.tr(NULL, "!")
-      bit = 1
-      16.times do |bno|
-        line = ""
-        @str.length.times do |i|
-          if (@attrs[i] & bit) == 0
-            line << " "
-          else
-            if bno.zero?
-              line << "S"
-            else
-              line << ("%d" % (bno+1))
-            end
-          end
-        end
-        puts(line) unless line =~ /^ *$/
-        bit <<= 1
-      end
-    end
-
-    def split_into_flow
-      display_attributes if $DEBUG_RDOC
-
-      res = []
-      current_attr = 0
-      str = ""
-
-      str_len = @str.length
-
-      # skip leading invisible text
-      i = 0
-      i += 1 while i < str_len and @str[i] == "\0"
-      start_pos = i
-
-      # then scan the string, chunking it on attribute changes
-      while i < str_len
-        new_attr = @attrs[i]
-        if new_attr != current_attr
-          if i > start_pos
-            res << copy_string(start_pos, i)
-            start_pos = i
-          end
-
-          res << change_attribute(current_attr, new_attr)
-          current_attr = new_attr
-
-          if (current_attr & Attribute::SPECIAL) != 0
-            i += 1 while i < str_len and (@attrs[i] & Attribute::SPECIAL) != 0
-            res << Special.new(current_attr, copy_string(start_pos, i))
-            start_pos = i
-            next
-          end
-        end
-
-        # move on, skipping any invisible characters
-        begin
-          i += 1
-        end while i < str_len and @str[i] == "\0"
-      end
-
-      # tidy up trailing text
-      if start_pos < str_len
-        res << copy_string(start_pos, str_len)
-      end
-
-      # and reset to all attributes off
-      res << change_attribute(current_attr, 0) if current_attr != 0
-
-      return res
-    end
-
-  end
-
 end
 
+require 'rdoc/markup/attribute_manager'

Modified: MacRuby/trunk/lib/rdoc/markup/to_html.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/markup/to_html.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/markup/to_html.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,7 @@
 require 'rdoc/markup/formatter'
 require 'rdoc/markup/fragments'
 require 'rdoc/markup/inline'
+require 'rdoc/generator'
 
 require 'cgi'
 
@@ -47,7 +48,7 @@
       url = if path[0, 1] == '#' then # is this meaningful?
               path
             else
-              HTML.gen_url @from_path, path
+              RDoc::Generator.gen_url @from_path, path
             end
     end
 

Modified: MacRuby/trunk/lib/rdoc/markup.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/markup.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/markup.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -11,8 +11,8 @@
 # RDoc::Markup itself does no output formatting: this is left to a different
 # set of classes.
 #
-# RDoc::Markup is extendable at runtime: you can add new markup elements to be
-# recognised in the documents that RDoc::Markup parses.
+# RDoc::Markup is extendable at runtime: you can add \new markup elements to
+# be recognised in the documents that RDoc::Markup parses.
 #
 # 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
@@ -29,10 +29,9 @@
 #   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:
+#   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.
@@ -102,7 +101,7 @@
 #   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
+#   text</b> and \\\*bold* produce \<b>bold text</b> and \*bold*
 #   respectively.
 #
 # * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
@@ -118,17 +117,15 @@
 #
 # == Synopsis
 #
-# This code converts <tt>input_string</tt> to HTML.  The conversion
-# takes place in the +convert+ method, so you can use the same
-# RDoc::Markup object to convert multiple input strings.
+# This code converts +input_string+ to HTML.  The conversion takes place in
+# the +convert+ method, so you can use the same RDoc::Markup converter to
+# convert multiple input strings.
 #
-#   require 'rdoc/markup'
 #   require 'rdoc/markup/to_html'
 #   
-#   p = RDoc::Markup.new
 #   h = RDoc::Markup::ToHtml.new
 #   
-#   puts p.convert(input_string, h)
+#   puts h.convert(input_string)
 #
 # You can extend the RDoc::Markup parser to recognise new markup
 # sequences, and to add special processing for text that matches a
@@ -152,10 +149,10 @@
 #   
 #   m.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
 #   
-#   h = WikiHtml.new
-#   h.add_tag(:STRIKE, "<strike>", "</strike>")
+#   wh = WikiHtml.new
+#   wh.add_tag(:STRIKE, "<strike>", "</strike>")
 #   
-#   puts "<body>" + m.convert(ARGF.read, h) + "</body>"
+#   puts "<body>#{wh.convert ARGF.read}</body>"
 #
 #--
 # Author::   Dave Thomas,  dave at pragmaticprogrammer.com

Modified: MacRuby/trunk/lib/rdoc/options.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/options.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/options.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -189,7 +189,7 @@
   def parse(argv)
     accessors = []
 
-    opt = OptionParser.new do |opt|
+    opts = OptionParser.new do |opt|
       opt.program_name = File.basename $0
       opt.version = RDoc::VERSION
       opt.summary_indent = ' ' * 4
@@ -513,7 +513,7 @@
       end
     end
 
-    opt.parse! argv
+    opts.parse! argv
 
     @files = argv.dup
 
@@ -539,7 +539,7 @@
     end
 
   rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
-    puts opt
+    puts opts
     puts
     puts e
     exit 1

Modified: MacRuby/trunk/lib/rdoc/parsers/parse_rb.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/parsers/parse_rb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/parsers/parse_rb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -23,6 +23,7 @@
 
 require "rdoc/parsers/parserfactory"
 
+$TOKEN_DEBUG ||= nil
 #$TOKEN_DEBUG = $DEBUG_RDOC
 
 # Definitions of all tokens involved in the lexical analysis
@@ -2315,7 +2316,7 @@
 
       when "section"
         context.set_current_section(param, comment)
-        comment.clear
+        comment.replace ''
         break
 
       else

Modified: MacRuby/trunk/lib/rdoc/rdoc.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/rdoc.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/rdoc.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -228,37 +228,37 @@
     def document(argv)
       TopLevel::reset
 
-      options = Options.new GENERATORS
-      options.parse argv
+      @options = Options.new GENERATORS
+      @options.parse argv
 
       @last_created = nil
 
-      unless options.all_one_file
-        @last_created = setup_output_dir(options.op_dir, options.force_update)
+      unless @options.all_one_file then
+        @last_created = setup_output_dir @options.op_dir, @options.force_update
       end
 
       start_time = Time.now
 
-      file_info = parse_files(options)
+      file_info = parse_files @options
 
       if file_info.empty?
-        $stderr.puts "\nNo newer files." unless options.quiet
+        $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
 
         gen_class = ::RDoc::Generator.const_get gen.class_name
-        gen = gen_class.for(options)
+        gen = gen_class.for @options
 
         pwd = Dir.pwd
 
-        Dir.chdir(options.op_dir)  unless options.all_one_file
+        Dir.chdir @options.op_dir unless @options.all_one_file
 
         begin
-          Diagram.new(file_info, options).draw if options.diagram
+          Diagram.new(file_info, @options).draw if @options.diagram
           gen.generate(file_info)
           update_output_dir(".", start_time)
         ensure
@@ -266,7 +266,7 @@
         end
       end
 
-      unless options.quiet
+      unless @options.quiet
         puts
         @stats.print
       end

Modified: MacRuby/trunk/lib/rdoc/ri/descriptions.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/ri/descriptions.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/ri/descriptions.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -8,11 +8,12 @@
 # the documentation
 #++
 
-class RDoc::RI::RDoc::RI::NamedThing
+class RDoc::RI::NamedThing
   attr_reader :name
   def initialize(name)
     @name = name
   end
+
   def <=>(other)
     @name <=> other.name
   end
@@ -26,10 +27,11 @@
   end
 end
 
-class RDoc::RI::AliasName < RDoc::RI::RDoc::RI::NamedThing; end
+class RDoc::RI::AliasName < RDoc::RI::NamedThing; end
 
-class RDoc::RI::Attribute < RDoc::RI::RDoc::RI::NamedThing
+class RDoc::RI::Attribute < RDoc::RI::NamedThing
   attr_reader :rw, :comment
+
   def initialize(name, rw, comment)
     super(name)
     @rw = rw
@@ -39,6 +41,7 @@
 
 class RDoc::RI::Constant < RDoc::RI::NamedThing
   attr_reader :value, :comment
+
   def initialize(name, value, comment)
     super(name)
     @value = value

Modified: MacRuby/trunk/lib/rdoc/ri/display.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/ri/display.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/ri/display.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,9 +2,9 @@
 
 ##
 # This is a kind of 'flag' module. If you want to write your own 'ri' display
-# module (perhaps because you'r writing an IDE or somesuch beast), you simply
-# write a class which implements the various 'display' methods in
-# 'DefaultDisplay', and include the 'RiDisplay' module in that class.
+# module (perhaps because you're writing an IDE), you write a class which
+# implements the various 'display' methods in RDoc::RI::DefaultDisplay, and
+# include the RDoc::RI::Display module in that class.
 #
 # To access your class from the command line, you can do
 #
@@ -32,26 +32,14 @@
 
   include RDoc::RI::Display
 
-  def initialize(formatter, width, use_stdout)
+  def initialize(formatter, width, use_stdout, output = $stdout)
     @use_stdout = use_stdout
-    @formatter = formatter.new $stdout, width, "     "
+    @formatter = formatter.new output, width, "     "
   end
 
-  def display_method_info(method)
-    page do
-      @formatter.draw_line(method.full_name)
-      display_params(method)
-      @formatter.draw_line
-      display_flow(method.comment)
-      if method.aliases && !method.aliases.empty?
-        @formatter.blankline
-        aka = "(also known as "
-        aka << method.aliases.map {|a| a.name }.join(", ")
-        aka << ")"
-        @formatter.wrap(aka)
-      end
-    end
-  end
+  ##
+  # Display information about +klass+.  Fetches additional information from
+  # +ri_reader+ as necessary.
 
   def display_class_info(klass, ri_reader)
     page do
@@ -90,89 +78,150 @@
       unless klass.constants.empty?
         @formatter.blankline
         @formatter.display_heading("Constants:", 2, "")
-        len = 0
-        klass.constants.each { |c| len = c.name.length if c.name.length > len }
-        len += 2
-        klass.constants.each do |c|
-          @formatter.wrap(c.value,
-                          @formatter.indent+((c.name+":").ljust(len)))
+
+        constants = klass.constants.sort_by { |constant| constant.name }
+
+        constants.each do |constant|
+          if constant.comment then
+            @formatter.wrap "#{constant.name}:"
+
+            @formatter.indent do
+              @formatter.display_flow constant.comment
+            end
+          else
+            @formatter.wrap constant.name
+          end
         end
       end
 
-      unless klass.class_methods.empty?
-        @formatter.blankline
-        @formatter.display_heading("Class methods:", 2, "")
-        @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', '))
-      end
+      class_data = [
+        :class_methods,
+        :class_method_extensions,
+        :instance_methods,
+        :instance_method_extensions,
+      ]
 
-      unless klass.class_method_extensions.empty?
-        @formatter.blankline
-        @formatter.display_heading("Class Method Extensions:", 2, "")
-        @formatter.wrap(klass.class_method_extensions.map{|m| m.name}.sort.join(', '))
+      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.instance_methods.empty?
+      unless klass.attributes.empty? then
         @formatter.blankline
-        @formatter.display_heading("Instance methods:", 2, "")
-        @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', '))
-      end
 
-      unless klass.instance_method_extensions.empty?
-        @formatter.blankline
-        @formatter.display_heading("Instance Method Extensions:", 2, "")
-        @formatter.wrap(klass.instance_method_extensions.map{|m| m.name}.sort.join(', '))
+        @formatter.display_heading 'Attributes:', 2, ''
+
+        attributes = klass.attributes.sort_by { |attribute| attribute.name }
+
+        attributes.each do |attribute|
+          if attribute.comment then
+            @formatter.wrap "#{attribute.name} (#{attribute.rw}):"
+            @formatter.indent do
+              @formatter.display_flow attribute.comment
+            end
+          else
+            @formatter.wrap "#{attribute.name} (#{attribute.rw})"
+          end
+        end
       end
+    end
+  end
 
-      unless klass.attributes.empty?
+  ##
+  # Display an Array of RDoc::Markup::Flow objects, +flow+.
+
+  def display_flow(flow)
+    if flow and not flow.empty? then
+      @formatter.display_flow flow
+    else
+      @formatter.wrap '[no description]'
+    end
+  end
+
+  ##
+  # Display information about +method+.
+
+  def display_method_info(method)
+    page do
+      @formatter.draw_line(method.full_name)
+      display_params(method)
+
+      @formatter.draw_line
+      display_flow(method.comment)
+
+      if method.aliases and not method.aliases.empty? then
         @formatter.blankline
-        @formatter.wrap("Attributes:", "")
-        @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', '))
+        aka = "(also known as #{method.aliases.map { |a| a.name }.join(', ')})"
+        @formatter.wrap aka
       end
     end
   end
 
   ##
-  # Display a list of method names
+  # Display the list of +methods+.
 
   def display_method_list(methods)
     page do
-      @formatter.raw_print_line("More than one method matched your request. You can refine")
-      @formatter.raw_print_line("your search by asking for information on one of:\n\n")
-      @formatter.wrap(methods.map {|m| m.full_name} .join(", "))
+      @formatter.wrap "More than one method matched your request.  You can refine your search by asking for information on one of:"
+
+      @formatter.blankline
+
+      @formatter.wrap methods.map { |m| m.full_name }.join(", ")
     end
   end
 
-  def display_class_list(namespaces)
-    page do
-      @formatter.raw_print_line("More than one class or module matched your request. You can refine")
-      @formatter.raw_print_line("your search by asking for information on one of:\n\n")
-      @formatter.wrap(namespaces.map {|m| m.full_name}.join(", "))
+  ##
+  # Display the params for +method+.
+
+  def display_params(method)
+    params = method.params
+
+    if params[0,1] == "(" then
+      if method.is_singleton
+        params = method.full_name + params
+      else
+        params = method.name + params
+      end
     end
+
+    params.split(/\n/).each do |param|
+      @formatter.wrap param
+      @formatter.break_to_newline
+    end
+
+    if method.source_path then
+      @formatter.blankline
+      @formatter.wrap("Extension from #{method.source_path}")
+    end
   end
 
+  ##
+  # List the classes in +classes+.
+
   def list_known_classes(classes)
     if classes.empty?
       warn_no_database
     else
       page do
-        @formatter.draw_line("Known classes and modules")
+        @formatter.draw_line "Known classes and modules"
         @formatter.blankline
-        @formatter.wrap(classes.sort.join(", "))
-      end
-    end
-  end
 
-  def list_known_names(names)
-    if names.empty?
-      warn_no_database
-    else
-      page do
-        names.each {|n| @formatter.raw_print_line(n)}
+        @formatter.wrap classes.sort.join(', ')
       end
     end
   end
 
-  private
+  ##
+  # Paginates output through a pager program.
 
   def page
     if pager = setup_pager then
@@ -190,6 +239,9 @@
   rescue Errno::EPIPE
   end
 
+  ##
+  # Sets up a pager program to pass output through.
+
   def setup_pager
     unless @use_stdout then
       for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
@@ -200,45 +252,23 @@
     end
   end
 
-  def display_params(method)
-    params = method.params
+  ##
+  # Displays a message that describes how to build RI data.
 
-    if params[0,1] == "("
-      if method.is_singleton
-        params = method.full_name + params
-      else
-        params = method.name + params
-      end
-    end
-    params.split(/\n/).each do |p|
-      @formatter.wrap(p)
-      @formatter.break_to_newline
-    end
-    if method.source_path then
-      @formatter.blankline
-      @formatter.wrap("Extension from #{method.source_path}")
-    end
-  end
+  def warn_no_database
+    output = @formatter.output
 
-  def display_flow(flow)
-    if !flow || flow.empty?
-      @formatter.wrap("(no description...)")
-    else
-      @formatter.display_flow(flow)
-    end
+    output.puts "No ri data found"
+    output.puts
+    output.puts "If you've installed Ruby yourself, you need to generate documentation using:"
+    output.puts
+    output.puts "  make install-doc"
+    output.puts
+    output.puts "from the same place you ran `make` to build ruby."
+    output.puts
+    output.puts "If you installed Ruby from a packaging system, then you may need to"
+    output.puts "install an additional package, or ask the packager to enable ri generation."
   end
 
-  def warn_no_database
-    puts "No ri data found"
-    puts
-    puts "If you've installed Ruby yourself, you need to generate documentation using:"
-    puts
-    puts "  make install-doc"
-    puts
-    puts "from the same place you ran `make` to build ruby."
-    puts
-    puts "If you installed Ruby from a packaging system, then you may need to"
-    puts "install an additional package, or ask the packager to enable ri generation."
-  end
 end
 

Modified: MacRuby/trunk/lib/rdoc/ri/driver.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/ri/driver.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/ri/driver.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -200,7 +200,10 @@
     ri.run
   end
 
-  def initialize(options)
+  def initialize(options={})
+    options[:formatter] ||= RDoc::RI::Formatter.for('plain')
+    options[:use_stdout] ||= !$stdout.tty?
+    options[:width] ||= 72
     @names = options[:names]
 
     @class_cache_name = 'classes'
@@ -226,7 +229,7 @@
     end.max
 
     up_to_date = (File.exist?(class_cache_file_path) and
-                  newest < File.mtime(class_cache_file_path))
+                  newest and newest < File.mtime(class_cache_file_path))
 
     @class_cache = if up_to_date then
                      load_cache_for @class_cache_name
@@ -341,9 +344,18 @@
   end
 
   def read_yaml(path)
-    YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI|SM).*/, '')
+    data = File.read path
+    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
   end
 
+  def get_info_for(arg)
+    @names = [arg]
+    run
+  end
+
   def run
     if @names.empty? then
       @display.list_known_classes class_cache.keys.sort
@@ -410,7 +422,7 @@
 
 end
 
-class Hash
+class Hash # HACK don't add stuff to Hash.
   def method_missing method, *args
     self[method.to_s]
   end
@@ -420,7 +432,12 @@
       if self[k] then
         case v
         when Array then
-          self[k] += v
+          # 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

Modified: MacRuby/trunk/lib/rdoc/ri/formatter.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/ri/formatter.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/ri/formatter.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,7 +3,7 @@
 
 class RDoc::RI::Formatter
 
-  attr_reader :indent
+  attr_writer :indent
   attr_accessor :output
 
   FORMATTERS = { }
@@ -20,6 +20,7 @@
     @output = output
     @width  = width
     @indent = indent
+    @original_indent = indent.dup
   end
 
   def draw_line(label=nil)
@@ -42,6 +43,18 @@
     end
   end
 
+  def indent
+    return @indent unless block_given?
+
+    begin
+      indent = @indent.dup
+      @indent += @original_indent
+      yield
+    ensure
+      @indent = indent
+    end
+  end
+
   def wrap(txt, prefix=@indent, linelen=@width)
     return unless txt && !txt.empty?
 
@@ -481,13 +494,13 @@
     when :LABELED then
       list_type = "dl"
       prefixer = proc do |li|
-          "<dt><b>" + escape(li.label) + "</b><dd>"
+        "<dt><b>" + escape(li.label) + "</b><dd>"
       end
 
     when :NOTE then
       list_type = "table"
       prefixer = proc do |li|
-          %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
+        %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
       end
     else
       fail "unknown list type"

Modified: MacRuby/trunk/lib/rdoc/ri/util.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/ri/util.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/ri/util.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -62,7 +62,7 @@
       end
 
       if @method_name =~ /::|\.|#/ or !tokens.empty?
-        raise RiError.new("Bad argument: #{arg}") 
+        raise RDoc::RI::Error.new("Bad argument: #{arg}") 
       end
       if separator && separator != '.'
         @is_class_method = separator == "::"

Modified: MacRuby/trunk/lib/rdoc/ri/writer.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/ri/writer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/ri/writer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -12,7 +12,11 @@
   # form (where punctuation is replaced by %xx)
 
   def self.internal_to_external(name)
-    name.gsub(/\W/) { "%%%02x" % $&[0].ord }
+    if ''.respond_to? :ord then
+      name.gsub(/\W/) { "%%%02x" % $&[0].ord }
+    else
+      name.gsub(/\W/) { "%%%02x" % $&[0] }
+    end
   end
 
   ##

Modified: MacRuby/trunk/lib/rdoc/template.rb
===================================================================
--- MacRuby/trunk/lib/rdoc/template.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc/template.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,10 +1,12 @@
 require 'erb'
 
+module RDoc; end
+
 ##
-# An ERB wrapper.
+# An ERb wrapper that allows nesting of one ERb template inside another.
 #
 # This TemplatePage operates similarly to RDoc 1.x's TemplatePage, but uses
-# ERB instead of a custom template language.
+# ERb instead of a custom template language.
 #
 # Converting from a RDoc 1.x template to an RDoc 2.x template is fairly easy.
 #
@@ -24,8 +26,6 @@
 #
 # So you can see what is being used inside which loop.
 
-module RDoc
-end
 class RDoc::TemplatePage
 
   ##

Modified: MacRuby/trunk/lib/rdoc.rb
===================================================================
--- MacRuby/trunk/lib/rdoc.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rdoc.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,246 @@
+$DEBUG_RDOC = nil
+
 ##
-# :include: rdoc/README
+# = 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
+# to JavaDoc, parsing the source, and extracting the definition for classes,
+# modules, and methods (along with includes and requires).  We associate with
+# these optional documentation contained in the immediately preceding comment
+# block, and then render 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 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)
+# 
+#   % rdoc [options] [names...]
+# 
+# Type "rdoc --help" for an up-to-date option summary.
+# 
+# A typical use might be to generate documentation for a package of Ruby
+# 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'.
+# 
+# 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 +.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.
+# 
+# = 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
+# 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
+# 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.
+#   #--
+#   # FIXME: fails if the birthday falls on February 29th
+#   #++
+#   # The DOB is returned as a Time object.
+#   
+#   def get_dob(person)
+#     # ...
+#   end
+# 
+# Names of classes, source files, and any method names containing an
+# underscore or preceded by a hash character are automatically hyperlinked
+# 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.
+# 
+# == 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.
+#   
+#     module MyModule # :nodoc:
+#       class Input
+#       end
+#     end
+#     
+#     module OtherModule # :nodoc: all
+#       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.
+# 
+# [+: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
+#   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
+#   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
+#   the section is used as introductory text.  Subsequent methods, aliases,
+#   attributes, and classes will be documented in this section.  A :section:
+#   comment block may have one or more lines before the :section: directive.
+#   These will be removed, and any identical lines at the end of the block are
+#   also removed.  This allows you to add visual cues such as:
+#     
+#     # ----------------------------------------
+#     # :section: My Section
+#     # 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.
+# 
+# [+: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,
+#   disables documentation for the entire class or module.
+# 
+# = 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.
 
 module RDoc
 

Modified: MacRuby/trunk/lib/resolv.rb
===================================================================
--- MacRuby/trunk/lib/resolv.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/resolv.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -160,7 +160,7 @@
   # DNS::Hosts is a hostname resolver that uses the system hosts file.
 
   class Hosts
-    if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
+    if /mswin32|mingw|bccwin/ =~ RUBY_PLATFORM
       require 'win32/resolv'
       DefaultFileName = Win32::Resolv.get_hosts_path
     else
@@ -777,6 +777,7 @@
           config_hash = Config.parse_resolv_conf(filename)
         else
           if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
+            require 'win32/resolv'
             search, nameserver = Win32::Resolv.get_resolv_info
             config_hash = {}
             config_hash[:nameserver] = nameserver if nameserver

Modified: MacRuby/trunk/lib/rexml/document.rb
===================================================================
--- MacRuby/trunk/lib/rexml/document.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rexml/document.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -184,7 +184,7 @@
         output = Output.new( output, xml_decl.encoding )
       end
       formatter = if indent > -1
-          if trans
+          if transitive
             REXML::Formatters::Transitive.new( indent, ie_hack )
           else
             REXML::Formatters::Pretty.new( indent, ie_hack )

Modified: MacRuby/trunk/lib/rubygems/builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/builder.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/builder.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -65,13 +65,20 @@
     end
 
     def write_package
-      Package.open(@spec.file_name, "w", @signer) do |pkg|
-        pkg.metadata = @spec.to_yaml
-        @spec.files.each do |file|
-          next if File.directory? file
-          pkg.add_file_simple(file, File.stat(@spec.file_name).mode & 0777,
-                              File.size(file)) do |os|
-              os.write File.open(file, "rb"){|f|f.read}
+      open @spec.file_name, 'wb' do |gem_io|
+        Gem::Package.open gem_io, 'w', @signer do |pkg|
+          pkg.metadata = @spec.to_yaml
+
+          @spec.files.each do |file|
+            next if File.directory? file
+
+            stat = File.stat file
+            mode = stat.mode & 0777
+            size = stat.size
+
+            pkg.add_file_simple file, mode, size do |tar_io|
+              tar_io.write open(file, "rb") { |f| f.read }
+            end
           end
         end
       end

Modified: MacRuby/trunk/lib/rubygems/command_manager.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/command_manager.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/command_manager.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -93,7 +93,7 @@
         say Gem::Command::HELP
         terminate_interaction(0)
       when '-v', '--version'
-        say Gem::RubyGemsPackageVersion
+        say Gem::RubyGemsVersion
         terminate_interaction(0)
       when /^-/
         alert_error "Invalid option: #{args[0]}.  See 'gem --help'."
@@ -123,6 +123,7 @@
     end
     
     private
+
     def load_and_instantiate(command_name)
       command_name = command_name.to_s
       retried = false

Modified: MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,92 +2,90 @@
 require 'rubygems/source_index'
 require 'rubygems/dependency_list'
 
-module Gem
-  module Commands
-    class CleanupCommand < Command
-      def initialize
-        super(
-          'cleanup',
+class Gem::Commands::CleanupCommand < Gem::Command
+
+  def initialize
+    super 'cleanup',
           'Clean up old versions of installed gems in the local repository',
-          {
-            :force => false, 
-            :test => false, 
-            :install_dir => Gem.dir
-          })
-        add_option('-d', '--dryrun', "") do |value, options|
-          options[:dryrun] = true
-        end
-      end
+          :force => false, :test => false, :install_dir => Gem.dir
 
-      def arguments # :nodoc:
-        "GEMNAME       name of gem to cleanup"
-      end
+    add_option('-d', '--dryrun', "") do |value, options|
+      options[:dryrun] = true
+    end
+  end
 
-      def defaults_str # :nodoc:
-        "--no-dryrun"
-      end
+  def arguments # :nodoc:
+    "GEMNAME       name of gem to cleanup"
+  end
 
-      def usage # :nodoc:
-        "#{program_name} [GEMNAME ...]"
-      end
+  def defaults_str # :nodoc:
+    "--no-dryrun"
+  end
 
-      def execute
-        say "Cleaning up installed gems..."
-        srcindex = Gem::SourceIndex.from_installed_gems
-        primary_gems = {}
+  def usage # :nodoc:
+    "#{program_name} [GEMNAME ...]"
+  end
 
-        srcindex.each do |name, spec|
-          if primary_gems[spec.name].nil? or primary_gems[spec.name].version < spec.version
-            primary_gems[spec.name] = spec
-          end
-        end
+  def execute
+    say "Cleaning up installed gems..."
+    primary_gems = {}
 
-        gems_to_cleanup = []
+    Gem.source_index.each do |name, spec|
+      if primary_gems[spec.name].nil? or
+         primary_gems[spec.name].version < spec.version then
+        primary_gems[spec.name] = spec
+      end
+    end
 
-        unless options[:args].empty? then
-          options[:args].each do |gem_name|
-            specs = Gem.cache.search(/^#{gem_name}$/i)
-            specs.each do |spec|
-              gems_to_cleanup << spec
-            end
-          end
-        else
-          srcindex.each do |name, spec|
-              gems_to_cleanup << spec
-          end
+    gems_to_cleanup = []
+
+    unless options[:args].empty? then
+      options[:args].each do |gem_name|
+        specs = Gem.cache.search(/^#{gem_name}$/i)
+        specs.each do |spec|
+          gems_to_cleanup << spec
         end
+      end
+    else
+      Gem.source_index.each do |name, spec|
+        gems_to_cleanup << spec
+      end
+    end
 
-        gems_to_cleanup = gems_to_cleanup.select { |spec|
-          primary_gems[spec.name].version != spec.version
-        }
+    gems_to_cleanup = gems_to_cleanup.select { |spec|
+      primary_gems[spec.name].version != spec.version
+    }
 
-        uninstall_command = Gem::CommandManager.instance['uninstall']
-        deplist = DependencyList.new
-        gems_to_cleanup.uniq.each do |spec| deplist.add(spec) end
+    uninstall_command = Gem::CommandManager.instance['uninstall']
+    deplist = Gem::DependencyList.new
+    gems_to_cleanup.uniq.each do |spec| deplist.add spec end
 
-        deplist.dependency_order.each do |spec|
-          if options[:dryrun] then
-            say "Dry Run Mode: Would uninstall #{spec.full_name}"
-          else
-            say "Attempting uninstall on #{spec.full_name}"
+    deps = deplist.strongly_connected_components.flatten.reverse
 
-            options[:args] = [spec.name]
-            options[:version] = "= #{spec.version}"
-            options[:executables] = true
+    deps.each do |spec|
+      if options[:dryrun] then
+        say "Dry Run Mode: Would uninstall #{spec.full_name}"
+      else
+        say "Attempting to uninstall #{spec.full_name}"
 
-            uninstall_command.merge_options(options)
+        options[:args] = [spec.name]
+        options[:version] = "= #{spec.version}"
+        options[:executables] = false
 
-            begin
-              uninstall_command.execute
-            rescue Gem::DependencyRemovalException => ex
-              say "Unable to uninstall #{spec.full_name} ... continuing with remaining gems"
-            end
-          end
-        end
+        uninstaller = Gem::Uninstaller.new spec.name, options
 
-        say "Clean Up Complete"
+        begin
+          uninstaller.uninstall
+        rescue Gem::DependencyRemovalException,
+               Gem::GemNotInHomeException => e
+          say "Unable to uninstall #{spec.full_name}:"
+          say "\t#{e.class}: #{e.message}"
+        end
       end
     end
-      
+
+    say "Clean Up Complete"
   end
+
 end
+

Modified: MacRuby/trunk/lib/rubygems/commands/environment_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/environment_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/environment_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -25,22 +25,21 @@
   def execute
     out = ''
     arg = options[:args][0]
-    if begins?("packageversion", arg) then
+    case arg
+    when /^packageversion/ then
       out << Gem::RubyGemsPackageVersion
-    elsif begins?("version", arg) then
+    when /^version/ then
       out << Gem::RubyGemsVersion
-    elsif begins?("gemdir", arg) then
+    when /^gemdir/, /^gemhome/, /^home/, /^GEM_HOME/ then
       out << Gem.dir
-    elsif begins?("gempath", arg) then
-      out << Gem.path.join("\n")
-    elsif begins?("remotesources", arg) then
+    when /^gempath/, /^path/, /^GEM_PATH/ then
+      out << Gem.path.join(File::PATH_SEPARATOR)
+    when /^remotesources/ then
       out << Gem.sources.join("\n")
-    elsif arg then
-      fail Gem::CommandLineError, "Unknown enviroment option [#{arg}]"
-    else
+    when nil then
       out = "RubyGems Environment:\n"
 
-      out << "  - RUBYGEMS VERSION: #{Gem::RubyGemsVersion} (#{Gem::RubyGemsPackageVersion})\n"
+      out << "  - RUBYGEMS VERSION: #{Gem::RubyGemsVersion}\n"
 
       out << "  - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
       out << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
@@ -75,6 +74,9 @@
       Gem.sources.each do |s|
         out << "     - #{s}\n"
       end
+
+    else
+      fail Gem::CommandLineError, "Unknown enviroment option [#{arg}]"
     end
     say out
     true

Modified: MacRuby/trunk/lib/rubygems/commands/fetch_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/fetch_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/fetch_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -44,17 +44,15 @@
 
       spec, source_uri = specs_and_sources.last
 
-      gem_file = "#{spec.full_name}.gem"
-
-      gem_path = File.join source_uri, 'gems', gem_file
-
-      gem = Gem::RemoteFetcher.fetcher.fetch_path gem_path
-
-      File.open gem_file, 'wb' do |fp|
-        fp.write gem
+      if spec.nil? then
+        alert_error "Could not find #{gem_name} in any repository"
+        next
       end
 
-      say "Downloaded #{gem_file}"
+      path = Gem::RemoteFetcher.fetcher.download spec, source_uri
+      FileUtils.mv path, "#{spec.full_name}.gem"
+
+      say "Downloaded #{spec.full_name}"
     end
   end
 

Modified: MacRuby/trunk/lib/rubygems/commands/install_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/install_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/install_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -62,13 +62,15 @@
       :install_dir => options[:install_dir],
       :security_policy => options[:security_policy],
       :wrappers => options[:wrappers],
+      :bin_dir => options[:bin_dir]
     }
 
+    exit_code = 0
+
     get_all_gem_names.each do |gem_name|
       begin
-        inst = Gem::DependencyInstaller.new gem_name, options[:version],
-                                            install_options
-        inst.install
+        inst = Gem::DependencyInstaller.new install_options
+        inst.install gem_name, options[:version]
 
         inst.installed_gems.each do |spec|
           say "Successfully installed #{spec.full_name}"
@@ -77,8 +79,10 @@
         installed_gems.push(*inst.installed_gems)
       rescue Gem::InstallError => e
         alert_error "Error installing #{gem_name}:\n\t#{e.message}"
+        exit_code |= 1
       rescue Gem::GemNotFoundException => e
         alert_error e.message
+        exit_code |= 2
 #      rescue => e
 #        # TODO: Fix this handle to allow the error to propagate to
 #        # the top level handler.  Examine the other errors as
@@ -121,6 +125,8 @@
         end
       end
     end
+
+    raise Gem::SystemExitException, exit_code
   end
 
 end

Modified: MacRuby/trunk/lib/rubygems/commands/list_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/list_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/list_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -6,10 +6,8 @@
     class ListCommand < QueryCommand
 
       def initialize
-        super(
-          'list',
-          'Display all gems whose name starts with STRING'
-        )
+        super 'list', 'Display gems whose name starts with STRING'
+
         remove_option('--name-matches')
       end
 

Modified: MacRuby/trunk/lib/rubygems/commands/mirror_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/mirror_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/mirror_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 require 'zlib'
 
 require 'rubygems/command'
-require 'rubygems/gem_open_uri'
+require 'open-uri'
 
 class Gem::Commands::MirrorCommand < Gem::Command
 

Modified: MacRuby/trunk/lib/rubygems/commands/pristine_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/pristine_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/pristine_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -126,6 +126,7 @@
       end
 
       installer.generate_bin
+      installer.build_extensions
     end
   end
 

Modified: MacRuby/trunk/lib/rubygems/commands/query_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/query_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/query_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,16 +1,26 @@
 require 'rubygems/command'
 require 'rubygems/local_remote_options'
 require 'rubygems/source_info_cache'
+require 'rubygems/version_option'
 
 class Gem::Commands::QueryCommand < Gem::Command
 
   include Gem::LocalRemoteOptions
+  include Gem::VersionOption
 
   def initialize(name = 'query',
                  summary = 'Query gem information in local or remote repositories')
     super name, summary,
-         :name => /.*/, :domain => :local, :details => false, :versions => true
+         :name => //, :domain => :local, :details => false, :versions => true,
+         :installed => false, :version => Gem::Requirement.default
 
+    add_option('-i', '--[no-]installed',
+               'Check for installed gem') do |value, options|
+      options[:installed] = value
+    end
+
+    add_version_option
+
     add_option('-n', '--name-matches REGEXP',
                'Name of gem(s) to query on matches the',
                'provided REGEXP') do |value, options|
@@ -28,33 +38,72 @@
       options[:details] = false unless value
     end
 
+    add_option('-a', '--all',
+               'Display all gem versions') do |value, options|
+      options[:all] = value
+    end
+
     add_local_remote_options
   end
 
   def defaults_str # :nodoc:
-    "--local --name-matches '.*' --no-details --versions"
+    "--local --name-matches // --no-details --versions --no-installed"
   end
 
   def execute
+    exit_code = 0
+
     name = options[:name]
 
+    if options[:installed] then
+      if name.source.empty? then
+        alert_error "You must specify a gem name"
+        exit_code |= 4
+      elsif installed? name.source, options[:version] then
+        say "true"
+      else
+        say "false"
+        exit_code |= 1
+      end
+
+      raise Gem::SystemExitException, exit_code
+    end
+
     if local? then
       say
       say "*** LOCAL GEMS ***"
       say
-      output_query_results Gem.cache.search(name)
+
+      output_query_results Gem.source_index.search(name)
     end
 
     if remote? then
       say
       say "*** REMOTE GEMS ***"
       say
-      output_query_results Gem::SourceInfoCache.search(name)
+
+      all = options[:all]
+
+      begin
+        Gem::SourceInfoCache.cache all
+      rescue Gem::RemoteFetcher::FetchError
+        # no network
+      end
+
+      output_query_results Gem::SourceInfoCache.search(name, false, all)
     end
   end
 
   private
 
+  ##
+  # Check if gem +name+ version +version+ is installed.
+
+  def installed?(name, version = Gem::Requirement.default)
+    dep = Gem::Dependency.new name, version
+    !Gem.source_index.search(dep).empty?
+  end
+
   def output_query_results(gemspecs)
     output = []
     gem_list_with_version = {}
@@ -98,7 +147,7 @@
 
   ##
   # Used for wrapping and indenting text
-  #
+
   def format_text(text, wrap, indent=0)
     result = []
     work = text.dup

Modified: MacRuby/trunk/lib/rubygems/commands/sources_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/sources_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/sources_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -39,8 +39,11 @@
     options[:list] = !(options[:add] || options[:remove] || options[:clear_all] || options[:update])
 
     if options[:clear_all] then
-      remove_cache_file("user", Gem::SourceInfoCache.user_cache_file)
-      remove_cache_file("system", Gem::SourceInfoCache.system_cache_file)
+      sic = Gem::SourceInfoCache
+      remove_cache_file 'user',          sic.user_cache_file
+      remove_cache_file 'latest user',   sic.latest_user_cache_file
+      remove_cache_file 'system',        sic.system_cache_file
+      remove_cache_file 'latest system', sic.latest_system_cache_file
     end
 
     if options[:add] then
@@ -48,7 +51,7 @@
 
       sice = Gem::SourceInfoCacheEntry.new nil, nil
       begin
-        sice.refresh source_uri
+        sice.refresh source_uri, true
 
         Gem::SourceInfoCache.cache_data[source_uri] = sice
         Gem::SourceInfoCache.cache.update
@@ -66,7 +69,7 @@
     end
 
     if options[:update] then
-      Gem::SourceInfoCache.cache.refresh
+      Gem::SourceInfoCache.cache true
       Gem::SourceInfoCache.cache.flush
 
       say "source cache successfully updated"
@@ -78,6 +81,11 @@
       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
@@ -100,11 +108,12 @@
 
   private
 
-  def remove_cache_file(desc, fn)
-    FileUtils.rm_rf fn rescue nil
-    if ! File.exist?(fn)
+  def remove_cache_file(desc, path)
+    FileUtils.rm_rf path
+
+    if not File.exist?(path) then
       say "*** Removed #{desc} source cache ***"
-    elsif ! File.writable?(fn)
+    elsif not File.writable?(path) then
       say "*** Unable to remove #{desc} source cache (write protected) ***"
     else
       say "*** Unable to remove #{desc} source cache ***"

Modified: MacRuby/trunk/lib/rubygems/commands/specification_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/specification_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/specification_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,6 +3,7 @@
 require 'rubygems/local_remote_options'
 require 'rubygems/version_option'
 require 'rubygems/source_info_cache'
+require 'rubygems/format'
 
 class Gem::Commands::SpecificationCommand < Gem::Command
 
@@ -41,13 +42,16 @@
     gem = get_one_gem_name
 
     if local? then
-      source_index = Gem::SourceIndex.from_installed_gems
-      specs.push(*source_index.search(/\A#{gem}\z/, options[:version]))
+      if File.exist? gem then
+        specs << Gem::Format.from_file_by_path(gem).spec rescue nil
+      end
+
+      if specs.empty? then
+        specs.push(*Gem.source_index.search(/\A#{gem}\z/, options[:version]))
+      end
     end
 
     if remote? then
-      alert_warning "Remote information is not complete\n\n"
-
       Gem::SourceInfoCache.cache_data.each do |_,sice|
         specs.push(*sice.source_index.search(gem, options[:version]))
       end

Modified: MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -35,6 +35,11 @@
           options[:install_dir] = File.expand_path(value)
         end
 
+        add_option('-n', '--bindir DIR',
+                   'Directory to remove binaries from') do |value, options|
+          options[:bin_dir] = File.expand_path(value)
+        end
+
         add_version_option
         add_platform_option
       end
@@ -54,7 +59,13 @@
 
       def execute
         get_all_gem_names.each do |gem_name|
-          Gem::Uninstaller.new(gem_name, options).uninstall
+          begin
+            Gem::Uninstaller.new(gem_name, options).uninstall
+          rescue Gem::GemNotInHomeException => e
+            spec = e.spec
+            alert("In order to remove #{spec.name}, please execute:\n" \
+                  "\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
+          end
         end
       end
     end

Modified: MacRuby/trunk/lib/rubygems/commands/unpack_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/unpack_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/unpack_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -38,6 +38,7 @@
   def execute
     gemname = get_one_gem_name
     path = get_path(gemname, options[:version])
+
     if path then
       basename = File.basename(path).sub(/\.gem$/, '')
       target_dir = File.expand_path File.join(options[:target], basename)
@@ -66,16 +67,27 @@
   # source directories?
   def get_path(gemname, version_req)
     return gemname if gemname =~ /\.gem$/i
-    specs = Gem::SourceIndex.from_installed_gems.search(/\A#{gemname}\z/, version_req)
+
+    specs = Gem::source_index.search(/\A#{gemname}\z/, version_req)
+
     selected = specs.sort_by { |s| s.version }.last
+
     return nil if selected.nil?
+
     # We expect to find (basename).gem in the 'cache' directory.
     # Furthermore, the name match must be exact (ignoring case).
     if gemname =~ /^#{selected.name}$/i
       filename = selected.full_name + '.gem'
-      return File.join(Gem.dir, 'cache', filename)
+      path = nil
+
+      Gem.path.find do |gem_dir|
+        path = File.join gem_dir, 'cache', filename
+        File.exist? path
+      end
+
+      path
     else
-      return nil
+      nil
     end
   end
 

Modified: MacRuby/trunk/lib/rubygems/commands/update_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/update_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/commands/update_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,8 +1,10 @@
 require 'rubygems/command'
+require 'rubygems/command_manager'
 require 'rubygems/install_update_options'
 require 'rubygems/local_remote_options'
 require 'rubygems/source_info_cache'
 require 'rubygems/version_option'
+require 'rubygems/commands/install_command'
 
 class Gem::Commands::UpdateCommand < Gem::Command
 
@@ -45,7 +47,7 @@
 
   def execute
     if options[:system] then
-      say "Updating RubyGems..."
+      say "Updating RubyGems"
 
       unless options[:args].empty? then
         fail "No gem names are allowed with the --system option"
@@ -53,10 +55,10 @@
 
       options[:args] = ["rubygems-update"]
     else
-      say "Updating installed gems..."
+      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
@@ -64,25 +66,30 @@
       end
     end
 
-    remote_gemspecs = Gem::SourceInfoCache.search(//)
+    pattern = if options[:args].empty? then
+                //
+              else
+                Regexp.union(*options[:args])
+              end
 
-    gems_to_update = if options[:args].empty? then
-                       which_to_update(highest_installed_gems, remote_gemspecs)
-                     else
-                       options[:args]
-                     end
+    remote_gemspecs = Gem::SourceInfoCache.search pattern
 
-    options[:domain] = :remote # install from remote source
+    gems_to_update = which_to_update hig, remote_gemspecs
 
-    # HACK use the real API
-    install_command = Gem::CommandManager.instance['install']
+    updated = []
 
+    installer = Gem::DependencyInstaller.new options
+
     gems_to_update.uniq.sort.each do |name|
-      say "Attempting remote update of #{name}"
-      options[:args] = [name]
-      options[:ignore_dependencies] = true # HACK skip seen gems instead
-      install_command.merge_options(options)
-      install_command.execute
+      next if updated.any? { |spec| spec.name == name }
+
+      say "Updating #{name}"
+      installer.install name
+
+      installer.installed_gems.each do |spec|
+        updated << spec
+        say "Successfully installed #{spec.full_name}"
+      end
     end
 
     if gems_to_update.include? "rubygems-update" then
@@ -97,12 +104,10 @@
 
       say "RubyGems system software updated" if installed
     else
-      updated = gems_to_update.uniq.sort.collect { |g| g.to_s }
-
       if updated.empty? then
         say "Nothing to update"
       else
-        say "Gems updated: #{updated.join ', '}"
+        say "Gems updated: #{updated.map { |spec| spec.name }.join ', '}"
       end
     end
   end
@@ -112,6 +117,7 @@
     args.push '--prefix', Gem.prefix unless Gem.prefix.nil?
     args << '--no-rdoc' unless options[:generate_rdoc]
     args << '--no-ri' unless options[:generate_ri]
+    args << '--no-format-executable' if options[:no_format_executable]
 
     update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}"
 

Modified: MacRuby/trunk/lib/rubygems/custom_require.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/custom_require.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/custom_require.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -28,7 +28,7 @@
   rescue LoadError => load_error
     if load_error.message =~ /\A[Nn]o such file to load -- #{Regexp.escape path}\z/ and
        spec = Gem.searcher.find(path) then
-      Gem.activate(spec.name, false, "= #{spec.version}")
+      Gem.activate(spec.name, "= #{spec.version}")
       gem_original_require path
     else
       raise load_error

Modified: MacRuby/trunk/lib/rubygems/defaults.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/defaults.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/defaults.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -11,6 +11,9 @@
     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]
     end
@@ -29,7 +32,11 @@
 
   # The default directory for binaries
   def self.default_bindir
-    Config::CONFIG['bindir']
+    if defined? RUBY_FRAMEWORK_VERSION then # mac framework support
+      '/usr/bin'
+    else # generic install
+      ConfigMap[:bindir]
+    end
   end
 
   # The default system-wide source info cache directory.

Modified: MacRuby/trunk/lib/rubygems/dependency_installer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/dependency_installer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/dependency_installer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -22,8 +22,7 @@
   }
 
   ##
-  # Creates a new installer instance that will install +gem_name+ using
-  # version requirement +version+ and +options+.
+  # Creates a new installer instance.
   #
   # Options are:
   # :env_shebang:: See Gem::Installer::new.
@@ -36,7 +35,7 @@
   # :install_dir: See Gem::Installer#install.
   # :security_policy: See Gem::Installer::new and Gem::Security.
   # :wrappers: See Gem::Installer::new
-  def initialize(gem_name, version = nil, options = {})
+  def initialize(options = {})
     options = DEFAULT_OPTIONS.merge options
     @env_shebang = options[:env_shebang]
     @domain = options[:domain]
@@ -46,49 +45,9 @@
     @install_dir = options[:install_dir] || Gem.dir
     @security_policy = options[:security_policy]
     @wrappers = options[:wrappers]
+    @bin_dir = options[:bin_dir]
 
     @installed_gems = []
-
-    spec_and_source = nil
-
-    glob = if File::ALT_SEPARATOR then
-             gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
-           else
-             gem_name
-           end
-
-    local_gems = Dir["#{glob}*"].sort.reverse
-
-    unless local_gems.empty? then
-      local_gems.each do |gem_file|
-        next unless gem_file =~ /gem$/
-        begin
-          spec = Gem::Format.from_file_by_path(gem_file).spec
-          spec_and_source = [spec, gem_file]
-          break
-        rescue SystemCallError, Gem::Package::FormatError
-        end
-      end
-    end
-
-    if spec_and_source.nil? then
-      version ||= Gem::Requirement.default
-      @dep = Gem::Dependency.new gem_name, version
-      spec_and_sources = find_gems_with_sources(@dep).reverse
-
-      spec_and_source = spec_and_sources.find do |spec, source|
-        Gem::Platform.match spec.platform
-      end
-    end
-
-    if spec_and_source.nil? then
-      raise Gem::GemNotFoundException,
-        "could not find #{gem_name} locally or in a repository"
-    end
-
-    @specs_and_sources = [spec_and_source]
-
-    gather_dependencies
   end
 
   ##
@@ -107,71 +66,30 @@
     end
 
     if @domain == :both or @domain == :remote then
-      gems_and_sources.push(*Gem::SourceInfoCache.search_with_source(dep, true))
-    end
+      begin
+        requirements = dep.version_requirements.requirements.map do |req, ver|
+          req
+        end
 
-    gems_and_sources.sort_by do |gem, source|
-      [gem, source !~ /^http:\/\// ? 1 : 0] # local gems win
-    end
-  end
+        all = requirements.length > 1 ||
+                (requirements.first != ">=" and requirements.first != ">")
 
-  ##
-  # 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)
-    gem_file_name = "#{spec.full_name}.gem"
-    local_gem_path = File.join @install_dir, 'cache', gem_file_name
+        found = Gem::SourceInfoCache.search_with_source dep, true, all
 
-    Gem.ensure_gem_subdirectories @install_dir
+        gems_and_sources.push(*found)
 
-    source_uri = URI.parse source_uri unless URI::Generic === source_uri
-    scheme = source_uri.scheme
-
-    # URI.parse gets confused by MS Windows paths with forward slashes.
-    scheme = nil if scheme =~ /^[a-z]$/i
-
-    case scheme
-    when 'http' then
-      unless File.exist? local_gem_path then
-        begin
-          say "Downloading gem #{gem_file_name}" if
-            Gem.configuration.really_verbose
-
-          remote_gem_path = source_uri + "gems/#{gem_file_name}"
-
-          gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
-        rescue Gem::RemoteFetcher::FetchError
-          raise if spec.original_platform == spec.platform
-
-          alternate_name = "#{spec.name}-#{spec.version}-#{spec.original_platform}.gem"
-
-          say "Failed, downloading gem #{alternate_name}" if
-            Gem.configuration.really_verbose
-
-          remote_gem_path = source_uri + "gems/#{alternate_name}"
-
-          gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
+      rescue Gem::RemoteFetcher::FetchError => e
+        if Gem.configuration.really_verbose then
+          say "Error fetching remote data:\t\t#{e.message}"
+          say "Falling back to local-only install"
         end
-
-        File.open local_gem_path, 'wb' do |fp|
-          fp.write gem
-        end
+        @domain = :local
       end
-    when nil, 'file' then # TODO test for local overriding cache
-      begin
-        FileUtils.cp source_uri.to_s, local_gem_path
-      rescue Errno::EACCES
-        local_gem_path = source_uri.to_s
-      end
-
-      say "Using local gem #{local_gem_path}" if
-        Gem.configuration.really_verbose
-    else
-      raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
     end
 
-    local_gem_path
+    gems_and_sources.sort_by do |gem, source|
+      [gem, source =~ /^http:\/\// ? 0 : 1] # local gems win
+    end
   end
 
   ##
@@ -208,9 +126,57 @@
     @gems_to_install = dependency_list.dependency_order.reverse
   end
 
+  def find_spec_by_name_and_version gem_name, version = Gem::Requirement.default
+    spec_and_source = nil
+
+    glob = if File::ALT_SEPARATOR then
+             gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
+           else
+             gem_name
+           end
+
+    local_gems = Dir["#{glob}*"].sort.reverse
+
+    unless local_gems.empty? then
+      local_gems.each do |gem_file|
+        next unless gem_file =~ /gem$/
+        begin
+          spec = Gem::Format.from_file_by_path(gem_file).spec
+          spec_and_source = [spec, gem_file]
+          break
+        rescue SystemCallError, Gem::Package::FormatError
+        end
+      end
+    end
+
+    if spec_and_source.nil? then
+      dep = Gem::Dependency.new gem_name, version
+      spec_and_sources = find_gems_with_sources(dep).reverse
+
+      spec_and_source = spec_and_sources.find { |spec, source|
+        Gem::Platform.match spec.platform
+      }
+    end
+
+    if spec_and_source.nil? then
+      raise Gem::GemNotFoundException,
+        "could not find #{gem_name} locally or in a repository"
+    end
+
+    @specs_and_sources = [spec_and_source]
+  end
+
   ##
   # Installs the gem and all its dependencies.
-  def install
+  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
+    else
+      @specs_and_sources = [find_gems_with_sources(dep_or_name).last]
+    end
+
+    gather_dependencies
+
     spec_dir = File.join @install_dir, 'specifications'
     source_index = Gem::SourceIndex.from_gems_in spec_dir
 
@@ -219,10 +185,17 @@
       # HACK is this test for full_name acceptable?
       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
 
       _, source_uri = @specs_and_sources.assoc spec
-      local_gem_path = download spec, source_uri
+      begin
+        local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri,
+                                                             @install_dir
+      rescue Gem::RemoteFetcher::FetchError
+        next if @force
+        raise
+      end
 
       inst = Gem::Installer.new local_gem_path,
                                 :env_shebang => @env_shebang,
@@ -231,7 +204,8 @@
                                 :ignore_dependencies => @ignore_dependencies,
                                 :install_dir => @install_dir,
                                 :security_policy => @security_policy,
-                                :wrappers => @wrappers
+                                :wrappers => @wrappers,
+                                :bin_dir => @bin_dir
 
       spec = inst.install
 

Modified: MacRuby/trunk/lib/rubygems/doc_manager.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/doc_manager.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/doc_manager.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -65,6 +65,12 @@
       FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
 
       begin
+        gem 'rdoc'
+      rescue Gem::LoadError
+        # use built-in RDoc
+      end
+
+      begin
         require 'rdoc/rdoc'
       rescue LoadError => e
         raise Gem::DocumentError,

Modified: MacRuby/trunk/lib/rubygems/exceptions.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/exceptions.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/exceptions.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,8 +13,11 @@
 
 ##
 # Raised when attempting to uninstall a gem that isn't in GEM_HOME.
-class Gem::GemNotInHomeException < Gem::Exception; end
 
+class Gem::GemNotInHomeException < Gem::Exception
+  attr_accessor :spec
+end
+
 class Gem::DocumentError < Gem::Exception; end
 
 ##
@@ -65,3 +68,17 @@
 
 class Gem::VerificationError < Gem::Exception; end
 
+##
+# Raised to indicate that a system exit should occur with the specified
+# exit_code
+
+class Gem::SystemExitException < SystemExit
+  attr_accessor :exit_code
+
+  def initialize(exit_code)
+    @exit_code = exit_code
+
+    super "Exiting RubyGems with exit_code #{exit_code}"
+  end
+
+end

Modified: MacRuby/trunk/lib/rubygems/format.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/format.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/format.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -43,15 +43,12 @@
 
       # check for old version gem
       if File.read(file_path, 20).include?("MD5SUM =")
-        #alert_warning "Gem #{file_path} is in old format."
         require 'rubygems/old_format'
+
         format = OldFormat.from_file_by_path(file_path)
       else
-        begin
-          f = File.open(file_path, 'rb')
-          format = from_io(f, file_path, security_policy)
-        ensure
-          f.close unless f.closed?
+        open file_path, Gem.binary_mode do |io|
+          format = from_io io, file_path, security_policy
         end
       end
 
@@ -65,15 +62,24 @@
     # io:: [IO] Stream from which to read the gem
     #
     def self.from_io(io, gem_path="(io)", security_policy = nil)
-      format = self.new(gem_path)
-      Package.open_from_io(io, 'r', security_policy) do |pkg|
+      format = new gem_path
+
+      Package.open io, 'r', security_policy do |pkg|
         format.spec = pkg.metadata
         format.file_entries = []
+
         pkg.each do |entry|
-          format.file_entries << [{"size" => entry.size, "mode" => entry.mode,
-              "path" => entry.full_name}, entry.read]
+          size = entry.header.size
+          mode = entry.header.mode
+
+          format.file_entries << [{
+              "size" => size, "mode" => mode, "path" => entry.full_name,
+            },
+            entry.read
+          ]
         end
       end
+
       format
     end
 

Modified: MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -22,16 +22,18 @@
     @files = []
   end
 
+  ##
   # Build a Gem index.  Yields to block to handle the details of the
   # actual building.  Calls +begin_index+, +end_index+ and +cleanup+ at
   # appropriate times to customize basic operations.
+
   def build
     FileUtils.mkdir_p @directory unless File.exist? @directory
     raise "not a directory: #{@directory}" unless File.directory? @directory
 
     file_path = File.join @directory, @filename
 
-    @files << file_path
+    @files << @filename
 
     File.open file_path, "wb" do |file|
       @file = file
@@ -39,14 +41,20 @@
       yield
       end_index
     end
+
     cleanup
   ensure
     @file = nil
   end
 
+  ##
   # Compress the given file.
+
   def compress(filename, ext="rz")
-    zipped = zip(File.open(filename, 'rb'){ |fp| fp.read })
+    data = open filename, 'rb' do |fp| fp.read end
+
+    zipped = zip data
+
     File.open "#{filename}.#{ext}", "wb" do |file|
       file.write zipped
     end

Modified: MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,8 @@
 require 'rubygems/indexer'
 
+##
 # Construct the master Gem index file.
+
 class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
 
   def start_index
@@ -10,6 +12,7 @@
 
   def end_index
     super
+
     @file.puts "--- !ruby/object:#{@index.class}"
     @file.puts "gems:"
 
@@ -28,11 +31,9 @@
     index_file_name = File.join @directory, @filename
 
     compress index_file_name, "Z"
-    compressed_file_name = "#{index_file_name}.Z"
+    paranoid index_file_name, "#{index_file_name}.Z"
 
-    paranoid index_file_name, compressed_file_name
-
-    @files << compressed_file_name
+    @files << "#{@filename}.Z"
   end
 
   def add(spec)
@@ -41,12 +42,12 @@
 
   private
 
-  def paranoid(fn, compressed_fn)
-    data = File.open(fn, 'rb') do |fp| fp.read end
-    compressed_data = File.open(compressed_fn, 'rb') do |fp| fp.read end
+  def paranoid(path, compressed_path)
+    data = Gem.read_binary path
+    compressed_data = Gem.read_binary compressed_path
 
     if data != unzip(compressed_data) then
-      fail "Compressed file #{compressed_fn} does not match uncompressed file #{fn}"
+      raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
     end
   end
 

Modified: MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,7 +1,9 @@
 require 'rubygems/indexer'
 
+##
 # Construct a quick index file and all of the individual specs to support
 # incremental loading.
+
 class Gem::Indexer::QuickIndexBuilder < Gem::Indexer::AbstractIndexBuilder
 
   def initialize(filename, directory)
@@ -13,12 +15,12 @@
   def cleanup
     super
 
-    quick_index_file = File.join(@directory, @filename)
+    quick_index_file = File.join @directory, @filename
     compress quick_index_file
 
     # the complete quick index is in a directory, so move it as a whole
-    @files.delete quick_index_file
-    @files << @directory
+    @files.delete 'index'
+    @files << 'quick'
   end
 
   def add(spec)

Modified: MacRuby/trunk/lib/rubygems/indexer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/indexer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -11,6 +11,7 @@
 
 ##
 # Top level class for building the gem repository index.
+
 class Gem::Indexer
 
   include Gem::UserInteraction
@@ -25,7 +26,9 @@
 
   attr_reader :directory
 
+  ##
   # Create an indexer that will index the gems in +directory+.
+
   def initialize(directory)
     unless ''.respond_to? :to_xs then
       fail "Gem::Indexer requires that the XML Builder library be installed:" \
@@ -39,52 +42,60 @@
 
     @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
+    @quick_index = Gem::Indexer::QuickIndexBuilder.new 'index', @directory
+
+    quick_dir = File.join @directory, 'quick'
+    @latest_index = Gem::Indexer::LatestIndexBuilder.new 'latest_index', quick_dir
   end
 
+  ##
   # Build the index.
+
   def build_index
     @master_index.build do
       @quick_index.build do
         @marshal_index.build do
-          progress = ui.progress_reporter gem_file_list.size,
+          @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"
 
-          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})"
+                                          gem_file_list.each do |gemfile|
+              if File.size(gemfile.to_s) == 0 then
+                alert_warning "Skipping zero-length gem: #{gemfile}"
                 next
               end
 
-              abbreviate spec
-              sanitize spec
+              begin
+                spec = Gem::Format.from_file_by_path(gemfile).spec
 
-              @master_index.add spec
-              @quick_index.add spec
-              @marshal_index.add 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
 
-              progress.updated spec.original_name
+                abbreviate spec
+                sanitize spec
 
-            rescue SignalException => e
-              alert_error "Recieved 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
+                @master_index.add spec
+                @quick_index.add spec
+                @marshal_index.add spec
+                @latest_index.add spec
 
-          progress.done
+                progress.updated spec.original_name
 
-          say "Generating master indexes (this may take a while)"
+              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
+
+            say "Generating master indexes (this may take a while)"
+          end
         end
       end
     end
@@ -95,14 +106,15 @@
 
     say "Moving index into production dir #{@dest_directory}" if verbose
 
-    files = @master_index.files + @quick_index.files + @marshal_index.files
+    files = @master_index.files + @quick_index.files + @marshal_index.files +
+            @latest_index.files
 
     files.each do |file|
-      relative_name = file[/\A#{Regexp.escape @directory}.(.*)/, 1]
-      dest_name = File.join @dest_directory, relative_name
+      src_name = File.join @directory, file
+      dst_name = File.join @dest_directory, file
 
-      FileUtils.rm_rf dest_name, :verbose => verbose
-      FileUtils.mv file, @dest_directory, :verbose => verbose
+      FileUtils.rm_rf dst_name, :verbose => verbose
+      FileUtils.mv src_name, @dest_directory, :verbose => verbose
     end
   end
 
@@ -160,4 +172,5 @@
 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/trunk/lib/rubygems/install_update_options.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/install_update_options.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/install_update_options.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -25,6 +25,12 @@
       options[:install_dir] = File.expand_path(value)
     end
 
+    add_option(:"Install/Update", '-n', '--bindir DIR',
+	       'Directory where binary files are',
+	       'located') do |value, options|
+      options[:bin_dir] = File.expand_path(value)
+    end
+
     add_option(:"Install/Update", '-d', '--[no-]rdoc',
                'Generate RDoc documentation for the gem on',
                'install') do |value, options|

Modified: MacRuby/trunk/lib/rubygems/installer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/installer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/installer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -63,7 +63,8 @@
       :force => false,
       :install_dir => Gem.dir,
       :exec_format => false,
-      :env_shebang => false
+      :env_shebang => false,
+      :bin_dir => nil
     }.merge options
 
     @env_shebang = options[:env_shebang]
@@ -74,6 +75,7 @@
     @format_executable = options[:format_executable]
     @security_policy = options[:security_policy]
     @wrappers = options[:wrappers]
+    @bin_dir = options[:bin_dir]
 
     begin
       @format = Gem::Format.from_file_by_path @gem, @security_policy
@@ -104,7 +106,7 @@
 
     unless @force then
       if rrv = @spec.required_ruby_version then
-        unless rrv.satisfied_by? Gem::Version.new(RUBY_VERSION) then
+        unless rrv.satisfied_by? Gem.ruby_version then
           raise Gem::InstallError, "#{@spec.name} requires Ruby version #{rrv}"
         end
       end
@@ -225,7 +227,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 = 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
@@ -303,7 +305,7 @@
   # necessary.
   def shebang(bin_file_name)
     if @env_shebang then
-      "#!/usr/bin/env ruby"
+      "#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
     else
       path = File.join @gem_dir, @spec.bindir, bin_file_name
 
@@ -352,10 +354,10 @@
     <<-TEXT
 @ECHO OFF
 IF NOT "%~f0" == "~f0" GOTO :WinNT
-@"#{Gem.ruby}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
+@"#{File.basename(Gem.ruby)}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
 GOTO :EOF
 :WinNT
-"%~dp0ruby.exe" "%~dpn0" %*
+@"#{File.basename(Gem.ruby)}" "%~dpn0" %*
 TEXT
   end
 

Modified: MacRuby/trunk/lib/rubygems/package.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/package.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -45,770 +45,17 @@
   class TooLongFileName < Error; end
   class FormatError < Error; end
 
-  module FSyncDir
-    private
-    def fsync_dir(dirname)
-      # make sure this hits the disc
-      begin
-        dir = open(dirname, "r")
-        dir.fsync
-      rescue # ignore IOError if it's an unpatched (old) Ruby
-      ensure
-        dir.close if dir rescue nil
-      end
-    end
-  end
+  def self.open(io, mode = "r", signer = nil, &block)
+    tar_type = case mode
+               when 'r' then TarInput
+               when 'w' then TarOutput
+               else
+                 raise "Unknown Package open mode"
+               end
 
-  class TarHeader
-    FIELDS = [:name, :mode, :uid, :gid, :size, :mtime, :checksum, :typeflag,
-      :linkname, :magic, :version, :uname, :gname, :devmajor,
-      :devminor, :prefix]
-    FIELDS.each {|x| attr_reader x}
-
-    def self.new_from_stream(stream)
-      data = stream.read(512)
-      fields = data.unpack("A100" +   # record name
-                           "A8A8A8" + # mode, uid, gid
-                           "A12A12" + # size, mtime
-                           "A8A" +    # checksum, typeflag
-                           "A100" +   # linkname
-                           "A6A2" +   # magic, version
-                           "A32" +    # uname
-                           "A32" +    # gname
-                           "A8A8" +   # devmajor, devminor
-                           "A155")    # prefix
-      name = fields.shift
-      mode = fields.shift.oct
-      uid = fields.shift.oct
-      gid = fields.shift.oct
-      size = fields.shift.oct
-      mtime = fields.shift.oct
-      checksum = fields.shift.oct
-      typeflag = fields.shift
-      linkname = fields.shift
-      magic = fields.shift
-      version = fields.shift.oct
-      uname = fields.shift
-      gname = fields.shift
-      devmajor = fields.shift.oct
-      devminor = fields.shift.oct
-      prefix = fields.shift
-
-      empty = (data == "\0" * 512)
-
-      new(:name=>name, :mode=>mode, :uid=>uid, :gid=>gid, :size=>size,
-          :mtime=>mtime, :checksum=>checksum, :typeflag=>typeflag,
-          :magic=>magic, :version=>version, :uname=>uname, :gname=>gname,
-          :devmajor=>devmajor, :devminor=>devminor, :prefix=>prefix,
-          :empty => empty )
-    end
-
-    def initialize(vals)
-      unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode]
-        raise ArgumentError, ":name, :size, :prefix and :mode required"
-      end
-      vals[:uid] ||= 0
-      vals[:gid] ||= 0
-      vals[:mtime] ||= 0
-      vals[:checksum] ||= ""
-      vals[:typeflag] ||= "0"
-      vals[:magic] ||= "ustar"
-      vals[:version] ||= "00"
-      vals[:uname] ||= "wheel"
-      vals[:gname] ||= "wheel"
-      vals[:devmajor] ||= 0
-      vals[:devminor] ||= 0
-      FIELDS.each {|x| instance_variable_set "@#{x.to_s}", vals[x]}
-      @empty = vals[:empty]
-    end
-
-    def empty?
-      @empty
-    end
-
-    def to_s
-      update_checksum
-      header(checksum)
-    end
-
-    def update_checksum
-      h = header(" " * 8)
-      @checksum = oct(calculate_checksum(h), 6)
-    end
-
-    private
-    def oct(num, len)
-      "%0#{len}o" % num
-    end
-
-    def calculate_checksum(hdr)
-      #hdr.split('').map { |c| c[0] }.inject { |a, b| a + b } # HACK rubinius
-      hdr.unpack("C*").inject{|a,b| a+b}
-    end
-
-    def header(chksum)
-      # struct tarfile_entry_posix {
-      #   char name[100];   # ASCII + (Z unless filled)
-      #   char mode[8];     # 0 padded, octal, null
-      #   char uid[8];      # ditto
-      #   char gid[8];      # ditto
-      #   char size[12];    # 0 padded, octal, null
-      #   char mtime[12];   # 0 padded, octal, null
-      #   char checksum[8]; # 0 padded, octal, null, space
-      #   char typeflag[1]; # file: "0"  dir: "5"
-      #   char linkname[100]; # ASCII + (Z unless filled)
-      #   char magic[6];      # "ustar\0"
-      #   char version[2];    # "00"
-      #   char uname[32];     # ASCIIZ
-      #   char gname[32];     # ASCIIZ
-      #   char devmajor[8];   # 0 padded, octal, null
-      #   char devminor[8];   # o padded, octal, null
-      #   char prefix[155];   # ASCII + (Z unless filled)
-      # };
-      arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),
-        oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version,
-        uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
-      str = arr.pack("a100a8a8a8a12a12" + # name, mode, uid, gid, size, mtime
-                     "a7aaa100a6a2" + # chksum, typeflag, linkname, magic, version
-                     "a32a32a8a8a155") # uname, gname, devmajor, devminor, prefix
-      str + "\0" * ((512 - str.size) % 512)
-    end
+    tar_type.open(io, signer, &block)
   end
 
-  class TarWriter
-    class FileOverflow < StandardError; end
-    class BlockNeeded < StandardError; end
-
-    class BoundedStream
-      attr_reader :limit, :written
-      def initialize(io, limit)
-        @io = io
-        @limit = limit
-        @written = 0
-      end
-
-      def write(data)
-        if data.size + @written > @limit
-          raise FileOverflow,
-                  "You tried to feed more data than fits in the file."
-        end
-        @io.write data
-        @written += data.size
-        data.size
-      end
-    end
-
-    class RestrictedStream
-      def initialize(anIO)
-        @io = anIO
-      end
-
-      def write(data)
-        @io.write data
-      end
-    end
-
-    def self.new(anIO)
-      writer = super(anIO)
-      return writer unless block_given?
-      begin
-        yield writer
-      ensure
-        writer.close
-      end
-      nil
-    end
-
-    def initialize(anIO)
-      @io = anIO
-      @closed = false
-    end
-
-    def add_file_simple(name, mode, size)
-      raise BlockNeeded unless block_given?
-      raise ClosedIO if @closed
-      name, prefix = split_name(name)
-      header = TarHeader.new(:name => name, :mode => mode,
-                             :size => size, :prefix => prefix).to_s
-      @io.write header
-      os = BoundedStream.new(@io, size)
-      yield os
-      #FIXME: what if an exception is raised in the block?
-      min_padding = size - os.written
-      @io.write("\0" * min_padding)
-      remainder = (512 - (size % 512)) % 512
-      @io.write("\0" * remainder)
-    end
-
-    def add_file(name, mode)
-      raise BlockNeeded unless block_given?
-      raise ClosedIO if @closed
-      raise NonSeekableIO unless @io.respond_to? :pos=
-      name, prefix = split_name(name)
-      init_pos = @io.pos
-      @io.write "\0" * 512 # placeholder for the header
-      yield RestrictedStream.new(@io)
-      #FIXME: what if an exception is raised in the block?
-      #FIXME: what if an exception is raised in the block?
-      size = @io.pos - init_pos - 512
-      remainder = (512 - (size % 512)) % 512
-      @io.write("\0" * remainder)
-      final_pos = @io.pos
-      @io.pos = init_pos
-      header = TarHeader.new(:name => name, :mode => mode,
-                             :size => size, :prefix => prefix).to_s
-      @io.write header
-      @io.pos = final_pos
-    end
-
-    def mkdir(name, mode)
-      raise ClosedIO if @closed
-      name, prefix = split_name(name)
-      header = TarHeader.new(:name => name, :mode => mode, :typeflag => "5",
-                             :size => 0, :prefix => prefix).to_s
-      @io.write header
-      nil
-    end
-
-    def flush
-      raise ClosedIO if @closed
-      @io.flush if @io.respond_to? :flush
-    end
-
-    def close
-      #raise ClosedIO if @closed
-      return if @closed
-      @io.write "\0" * 1024
-      @closed = true
-    end
-
-    private
-    def split_name name
-      raise TooLongFileName if name.size > 256
-      if name.size <= 100
-        prefix = ""
-      else
-        parts = name.split(/\//)
-        newname = parts.pop
-        nxt = ""
-        loop do
-          nxt = parts.pop
-          break if newname.size + 1 + nxt.size > 100
-          newname = nxt + "/" + newname
-        end
-        prefix = (parts + [nxt]).join "/"
-        name = newname
-        raise TooLongFileName if name.size > 100 || prefix.size > 155
-      end
-      return name, prefix
-    end
-  end
-
-  class TarReader
-
-    include Gem::Package
-
-    class UnexpectedEOF < StandardError; end
-
-    module InvalidEntry
-      def read(len=nil); raise ClosedIO; end
-      def getc; raise ClosedIO;  end
-      def rewind; raise ClosedIO;  end
-    end
-
-    class Entry
-      TarHeader::FIELDS.each{|x| attr_reader x}
-
-      def initialize(header, anIO)
-        @io = anIO
-        @name = header.name
-        @mode = header.mode
-        @uid = header.uid
-        @gid = header.gid
-        @size = header.size
-        @mtime = header.mtime
-        @checksum = header.checksum
-        @typeflag = header.typeflag
-        @linkname = header.linkname
-        @magic = header.magic
-        @version = header.version
-        @uname = header.uname
-        @gname = header.gname
-        @devmajor = header.devmajor
-        @devminor = header.devminor
-        @prefix = header.prefix
-        @read = 0
-        @orig_pos = @io.pos
-      end
-
-      def read(len = nil)
-        return nil if @read >= @size
-        len ||= @size - @read
-        max_read = [len, @size - @read].min
-        ret = @io.read(max_read)
-        @read += ret.size
-        ret
-      end
-
-      def getc
-        return nil if @read >= @size
-        ret = @io.getc
-        @read += 1 if ret
-        ret
-      end
-
-      def is_directory?
-        @typeflag == "5"
-      end
-
-      def is_file?
-        @typeflag == "0"
-      end
-
-      def eof?
-        @read >= @size
-      end
-
-      def pos
-        @read
-      end
-
-      def rewind
-        raise NonSeekableIO unless @io.respond_to? :pos=
-          @io.pos = @orig_pos
-        @read = 0
-      end
-
-      alias_method :is_directory, :is_directory?
-      alias_method :is_file, :is_file?
-
-      def bytes_read
-        @read
-      end
-
-      def full_name
-        if @prefix != ""
-          File.join(@prefix, @name)
-        else
-          @name
-        end
-      end
-
-      def close
-        invalidate
-      end
-
-      private
-      def invalidate
-        extend InvalidEntry
-      end
-    end
-
-    def self.new(anIO)
-      reader = super(anIO)
-      return reader unless block_given?
-      begin
-        yield reader
-      ensure
-        reader.close
-      end
-      nil
-    end
-
-    def initialize(anIO)
-      @io = anIO
-      @init_pos = anIO.pos
-    end
-
-    def each(&block)
-      each_entry(&block)
-    end
-
-    # do not call this during a #each or #each_entry iteration
-    def rewind
-      if @init_pos == 0
-        raise NonSeekableIO unless @io.respond_to? :rewind
-        @io.rewind
-      else
-        raise NonSeekableIO unless @io.respond_to? :pos=
-          @io.pos = @init_pos
-      end
-    end
-
-    def each_entry
-      loop do
-        return if @io.eof?
-        header = TarHeader.new_from_stream(@io)
-        return if header.empty?
-        entry = Entry.new header, @io
-        size = entry.size
-        yield entry
-        skip = (512 - (size % 512)) % 512
-        if @io.respond_to? :seek
-          # avoid reading...
-          @io.seek(size - entry.bytes_read, IO::SEEK_CUR)
-        else
-          pending = size - entry.bytes_read
-          while pending > 0
-            bread = @io.read([pending, 4096].min).size
-            raise UnexpectedEOF if @io.eof?
-            pending -= bread
-          end
-        end
-        @io.read(skip) # discard trailing zeros
-        # make sure nobody can use #read, #getc or #rewind anymore
-        entry.close
-      end
-    end
-
-    def close
-    end
-
-  end
-
-  class TarInput
-
-    include FSyncDir
-    include Enumerable
-
-    attr_reader :metadata
-
-    class << self; private :new end
-
-    def initialize(io, security_policy = nil)
-      @io = io
-      @tarreader = TarReader.new(@io)
-      has_meta = false
-      data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil
-      dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil
-
-      @tarreader.each do |entry|
-        case entry.full_name
-        when "metadata"
-          @metadata = load_gemspec(entry.read)
-          has_meta = true
-          break
-        when "metadata.gz"
-          begin
-            # if we have a security_policy, then pre-read the metadata file
-            # and calculate it's digest
-            sio = nil
-            if security_policy
-              Gem.ensure_ssl_available
-              sio = StringIO.new(entry.read)
-              meta_dgst = dgst_algo.digest(sio.string)
-              sio.rewind
-            end
-
-            gzis = Zlib::GzipReader.new(sio || entry)
-            # YAML wants an instance of IO
-            @metadata = load_gemspec(gzis)
-            has_meta = true
-          ensure
-            gzis.close unless gzis.nil?
-          end
-        when 'metadata.gz.sig'
-          meta_sig = entry.read
-        when 'data.tar.gz.sig'
-          data_sig = entry.read
-        when 'data.tar.gz'
-          if security_policy
-            Gem.ensure_ssl_available
-            data_dgst = dgst_algo.digest(entry.read)
-          end
-        end
-      end
-
-      if security_policy then
-        Gem.ensure_ssl_available
-
-        # map trust policy from string to actual class (or a serialized YAML
-        # file, if that exists)
-        if String === security_policy then
-          if Gem::Security::Policy.key? security_policy then
-            # load one of the pre-defined security policies
-            security_policy = Gem::Security::Policy[security_policy]
-          elsif File.exist? security_policy then
-            # FIXME: this doesn't work yet
-            security_policy = YAML.load File.read(security_policy)
-          else
-            raise Gem::Exception, "Unknown trust policy '#{security_policy}'"
-          end
-        end
-
-        if data_sig && data_dgst && meta_sig && meta_dgst then
-          # the user has a trust policy, and we have a signed gem
-          # file, so use the trust policy to verify the gem signature
-
-          begin
-            security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain)
-          rescue Exception => e
-            raise "Couldn't verify data signature: #{e}"
-          end
-
-          begin
-            security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain)
-          rescue Exception => e
-            raise "Couldn't verify metadata signature: #{e}"
-          end
-        elsif security_policy.only_signed
-          raise Gem::Exception, "Unsigned gem"
-        else
-          # FIXME: should display warning here (trust policy, but
-          # either unsigned or badly signed gem file)
-        end
-      end
-
-      @tarreader.rewind
-      @fileops = Gem::FileOperations.new
-      raise FormatError, "No metadata found!" unless has_meta
-    end
-
-    # Attempt to YAML-load a gemspec from the given _io_ parameter.  Return
-    # nil if it fails.
-    def load_gemspec(io)
-      Gem::Specification.from_yaml(io)
-    rescue Gem::Exception
-      nil
-    end
-
-    def self.open(filename, security_policy = nil, &block)
-      open_from_io(File.open(filename, "rb"), security_policy, &block)
-    end
-
-    def self.open_from_io(io, security_policy = nil,  &block)
-      raise "Want a block" unless block_given?
-      begin
-        is = new(io, security_policy)
-        yield is
-      ensure
-        is.close if is
-      end
-    end
-
-    def each(&block)
-      @tarreader.each do |entry|
-        next unless entry.full_name == "data.tar.gz"
-        is = zipped_stream(entry)
-        begin
-          TarReader.new(is) do |inner|
-            inner.each(&block)
-          end
-        ensure
-          is.close if is
-        end
-      end
-      @tarreader.rewind
-    end
-
-    # Return an IO stream for the zipped entry.
-    #
-    # NOTE:  Originally this method used two approaches, Return a GZipReader
-    # directly, or read the GZipReader into a string and return a StringIO on
-    # the string.  The string IO approach was used for versions of ZLib before
-    # 1.2.1 to avoid buffer errors on windows machines.  Then we found that
-    # errors happened with 1.2.1 as well, so we changed the condition.  Then
-    # we discovered errors occurred with versions as late as 1.2.3.  At this
-    # point (after some benchmarking to show we weren't seriously crippling
-    # the unpacking speed) we threw our hands in the air and declared that
-    # this method would use the String IO approach on all platforms at all
-    # times.  And that's the way it is.
-    def zipped_stream(entry)
-      if defined? Rubinius then
-        zis = Zlib::GzipReader.new entry
-        dis = zis.read
-        is = StringIO.new(dis)
-      else
-        # This is Jamis Buck's ZLib workaround for some unknown issue
-        entry.read(10) # skip the gzip header
-        zis = Zlib::Inflate.new(-Zlib::MAX_WBITS)
-        is = StringIO.new(zis.inflate(entry.read))
-      end
-    ensure
-      zis.finish if zis
-    end
-
-    def extract_entry(destdir, entry, expected_md5sum = nil)
-      if entry.is_directory?
-        dest = File.join(destdir, entry.full_name)
-        if file_class.dir? dest
-          @fileops.chmod entry.mode, dest, :verbose=>false
-        else
-          @fileops.mkdir_p(dest, :mode => entry.mode, :verbose=>false)
-        end
-        fsync_dir dest
-        fsync_dir File.join(dest, "..")
-        return
-      end
-      # it's a file
-      md5 = Digest::MD5.new if expected_md5sum
-      destdir = File.join(destdir, File.dirname(entry.full_name))
-      @fileops.mkdir_p(destdir, :mode => 0755, :verbose=>false)
-      destfile = File.join(destdir, File.basename(entry.full_name))
-      @fileops.chmod(0600, destfile, :verbose=>false) rescue nil  # Errno::ENOENT
-      file_class.open(destfile, "wb", entry.mode) do |os|
-        loop do
-          data = entry.read(4096)
-          break unless data
-          md5 << data if expected_md5sum
-          os.write(data)
-        end
-        os.fsync
-      end
-      @fileops.chmod(entry.mode, destfile, :verbose=>false)
-      fsync_dir File.dirname(destfile)
-      fsync_dir File.join(File.dirname(destfile), "..")
-      if expected_md5sum && expected_md5sum != md5.hexdigest
-        raise BadCheckSum
-      end
-    end
-
-    def close
-      @io.close
-      @tarreader.close
-    end
-
-    private
-
-    def file_class
-      File
-    end
-  end
-
-  class TarOutput
-
-    class << self; private :new end
-
-    def initialize(io)
-      @io = io
-      @external = TarWriter.new @io
-    end
-
-    def external_handle
-      @external
-    end
-
-    def self.open(filename, signer = nil, &block)
-      io = File.open(filename, "wb")
-      open_from_io(io, signer, &block)
-      nil
-    end
-
-    def self.open_from_io(io, signer = nil, &block)
-      outputter = new(io)
-      metadata = nil
-      set_meta = lambda{|x| metadata = x}
-      raise "Want a block" unless block_given?
-      begin
-        data_sig, meta_sig = nil, nil
-
-        outputter.external_handle.add_file("data.tar.gz", 0644) do |inner|
-          begin
-            sio = signer ? StringIO.new : nil
-            os = Zlib::GzipWriter.new(sio || inner)
-
-            TarWriter.new(os) do |inner_tar_stream|
-              klass = class << inner_tar_stream; self end
-              klass.send(:define_method, :metadata=, &set_meta)
-              block.call inner_tar_stream
-            end
-          ensure
-            os.flush
-            os.finish
-            #os.close
-
-            # if we have a signing key, then sign the data
-            # digest and return the signature
-            data_sig = nil
-            if signer
-              dgst_algo = Gem::Security::OPT[:dgst_algo]
-              dig = dgst_algo.digest(sio.string)
-              data_sig = signer.sign(dig)
-              inner.write(sio.string)
-            end
-          end
-        end
-
-        # if we have a data signature, then write it to the gem too
-        if data_sig
-          sig_file = 'data.tar.gz.sig'
-          outputter.external_handle.add_file(sig_file, 0644) do |os|
-            os.write(data_sig)
-          end
-        end
-
-        outputter.external_handle.add_file("metadata.gz", 0644) do |os|
-          begin
-            sio = signer ? StringIO.new : nil
-            gzos = Zlib::GzipWriter.new(sio || os)
-            gzos.write metadata
-          ensure
-            gzos.flush
-            gzos.finish
-
-            # if we have a signing key, then sign the metadata
-            # digest and return the signature
-            if signer
-              dgst_algo = Gem::Security::OPT[:dgst_algo]
-              dig = dgst_algo.digest(sio.string)
-              meta_sig = signer.sign(dig)
-              os.write(sio.string)
-            end
-          end
-        end
-
-        # if we have a metadata signature, then write to the gem as
-        # well
-        if meta_sig
-          sig_file = 'metadata.gz.sig'
-          outputter.external_handle.add_file(sig_file, 0644) do |os|
-            os.write(meta_sig)
-          end
-        end
-
-      ensure
-        outputter.close
-      end
-      nil
-    end
-
-    def close
-      @external.close
-      @io.close
-    end
-
-  end
-
-  #FIXME: refactor the following 2 methods
-
-  def self.open(dest, mode = "r", signer = nil, &block)
-    raise "Block needed" unless block_given?
-
-    case mode
-    when "r"
-      security_policy = signer
-      TarInput.open(dest, security_policy, &block)
-    when "w"
-      TarOutput.open(dest, signer, &block)
-    else
-      raise "Unknown Package open mode"
-    end
-  end
-
-  def self.open_from_io(io, mode = "r", signer = nil, &block)
-    raise "Block needed" unless block_given?
-
-    case mode
-    when "r"
-      security_policy = signer
-      TarInput.open_from_io(io, security_policy, &block)
-    when "w"
-      TarOutput.open_from_io(io, signer, &block)
-    else
-      raise "Unknown Package open mode"
-    end
-  end
-
   def self.pack(src, destname, signer = nil)
     TarOutput.open(destname, signer) do |outp|
       dir_class.chdir(src) do
@@ -836,19 +83,13 @@
     end
   end
 
-  class << self
-    def file_class
-      File
-    end
-
-    def dir_class
-      Dir
-    end
-
-    def find_class # HACK kill me
-      Find
-    end
-  end
-
 end
 
+require 'rubygems/package/f_sync_dir'
+require 'rubygems/package/tar_header'
+require 'rubygems/package/tar_input'
+require 'rubygems/package/tar_output'
+require 'rubygems/package/tar_reader'
+require 'rubygems/package/tar_reader/entry'
+require 'rubygems/package/tar_writer'
+

Modified: MacRuby/trunk/lib/rubygems/remote_fetcher.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/remote_fetcher.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/remote_fetcher.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,6 @@
 require 'uri'
 
 require 'rubygems'
-require 'rubygems/gem_open_uri'
 
 ##
 # RemoteFetcher handles the details of fetching gems and gem information from
@@ -10,6 +9,8 @@
 
 class Gem::RemoteFetcher
 
+  include Gem::UserInteraction
+
   class FetchError < Gem::Exception; end
 
   @fetcher = nil
@@ -29,6 +30,10 @@
   #        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
+
+    @connections = {}
+    @requests = Hash.new 0
     @proxy_uri =
       case proxy
       when :no_proxy then nil
@@ -38,6 +43,65 @@
       end
   end
 
+  ##
+  # 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)
+    gem_file_name = "#{spec.full_name}.gem"
+    local_gem_path = File.join install_dir, 'cache', gem_file_name
+
+    Gem.ensure_gem_subdirectories install_dir
+
+    source_uri = URI.parse source_uri unless URI::Generic === source_uri
+    scheme = source_uri.scheme
+
+    # URI.parse gets confused by MS Windows paths with forward slashes.
+    scheme = nil if scheme =~ /^[a-z]$/i
+
+    case scheme
+    when 'http' then
+      unless File.exist? local_gem_path then
+        begin
+          say "Downloading gem #{gem_file_name}" if
+            Gem.configuration.really_verbose
+
+          remote_gem_path = source_uri + "gems/#{gem_file_name}"
+
+          gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
+        rescue Gem::RemoteFetcher::FetchError
+          raise if spec.original_platform == spec.platform
+
+          alternate_name = "#{spec.original_name}.gem"
+
+          say "Failed, downloading gem #{alternate_name}" if
+            Gem.configuration.really_verbose
+
+          remote_gem_path = source_uri + "gems/#{alternate_name}"
+
+          gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
+        end
+
+        File.open local_gem_path, 'wb' do |fp|
+          fp.write gem
+        end
+      end
+    when nil, 'file' then # TODO test for local overriding cache
+      begin
+        FileUtils.cp source_uri.to_s, local_gem_path
+      rescue Errno::EACCES
+        local_gem_path = source_uri.to_s
+      end
+
+      say "Using local gem #{local_gem_path}" if
+        Gem.configuration.really_verbose
+    else
+      raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
+    end
+
+    local_gem_path
+  end
+
   # Downloads +uri+.
   def fetch_path(uri)
     open_uri_or_path(uri) do |input|
@@ -47,9 +111,8 @@
     raise FetchError, "timed out fetching #{uri}"
   rescue IOError, SocketError, SystemCallError => e
     raise FetchError, "#{e.class}: #{e} reading #{uri}"
-  rescue OpenURI::HTTPError => e
-    body = e.io.readlines.join "\n\t"
-    message = "#{e.class}: #{e} reading #{uri}\n\t#{body}"
+  rescue => e
+    message = "#{e.class}: #{e} reading #{uri}"
     raise FetchError, message
   end
 
@@ -83,7 +146,8 @@
     end
 
   rescue SocketError, SystemCallError, Timeout::Error => e
-    raise FetchError, "#{e.message} (#{e.class})\n\tgetting size of #{uri}"
+    raise Gem::RemoteFetcher::FetchError,
+          "#{e.message} (#{e.class})\n\tgetting size of #{uri}"
   end
 
   private
@@ -131,26 +195,79 @@
 
   # 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, &block)
+  def open_uri_or_path(uri, depth = 0, &block)
     if file_uri?(uri)
       open(get_file_uri_path(uri), &block)
     else
-      connection_options = {
-        "User-Agent" => "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
-      }
+      uri = URI.parse uri unless URI::Generic === uri
+      net_http_args = [uri.host, uri.port]
 
-      if @proxy_uri
-        http_proxy_url = "#{@proxy_uri.scheme}://#{@proxy_uri.host}:#{@proxy_uri.port}"  
-        connection_options[:proxy_http_basic_authentication] = [http_proxy_url, unescape(@proxy_uri.user)||'', unescape(@proxy_uri.password)||'']
+      if @proxy_uri then
+        net_http_args += [  @proxy_uri.host,
+                            @proxy_uri.port,
+                            @proxy_uri.user,
+                            @proxy_uri.password
+        ]
       end
 
-      uri = URI.parse uri unless URI::Generic === uri
+      connection_id = net_http_args.join ':'
+      @connections[connection_id] ||= Net::HTTP.new(*net_http_args)
+      connection = @connections[connection_id]
+
+      if uri.scheme == 'https' && ! connection.started?
+        http_obj.use_ssl = true
+        http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
+      end
+
+      connection.start unless connection.started?
+
+      request = Net::HTTP::Get.new(uri.request_uri)
       unless uri.nil? || uri.user.nil? || uri.user.empty? then
-        connection_options[:http_basic_authentication] =
-          [unescape(uri.user), unescape(uri.password)]
+        request.basic_auth(uri.user, uri.password)
       end
 
-      open(uri, connection_options, &block)
+      ua = "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
+      ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
+      ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+      ua << ")"
+
+      request.add_field 'User-Agent', ua
+      request.add_field 'Connection', 'keep-alive'
+      request.add_field 'Keep-Alive', '30'
+
+      # 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
+
+        raise Gem::RemoteFetcher::FetchError, 'too many connection resets' if
+          retried
+
+        @requests[connection_id] = 0
+
+        connection.finish
+        connection.start
+        retried = true
+        retry
+      end
+
+      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
     end
   end
 

Modified: MacRuby/trunk/lib/rubygems/requirement.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/requirement.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/requirement.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -16,6 +16,8 @@
 
   include Comparable
 
+  attr_reader :requirements
+
   OPS = {
     "="  =>  lambda { |v, r| v == r },
     "!=" =>  lambda { |v, r| v != r },

Modified: MacRuby/trunk/lib/rubygems/rubygems_version.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/rubygems_version.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/rubygems_version.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,5 +2,5 @@
 # This file is auto-generated by build scripts.
 # See:  rake update_version
 module Gem
-  RubyGemsVersion = '1.0.1'
+  RubyGemsVersion = '1.1.1'
 end

Modified: MacRuby/trunk/lib/rubygems/security.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/security.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/security.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -4,6 +4,7 @@
 # See LICENSE.txt for permissions.
 #++
 
+require 'rubygems'
 require 'rubygems/gem_openssl'
 
 # = Signed Gems README

Modified: MacRuby/trunk/lib/rubygems/server.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/server.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/server.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,7 +1,7 @@
 require 'webrick'
-require 'rdoc/template'
 require 'yaml'
 require 'zlib'
+require 'erb'
 
 require 'rubygems'
 
@@ -27,107 +27,87 @@
 
   include Gem::UserInteraction
 
-  DOC_TEMPLATE = <<-WEBPAGE
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE html 
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+  DOC_TEMPLATE = <<-'WEBPAGE'
+  <?xml version="1.0" encoding="iso-8859-1"?>
+  <!DOCTYPE html
+       PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
-<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>
-  <div id="fileHeader">
-    <h1>RubyGems Documentation Index</h1>
-  </div>
-  <!-- banner header -->
+  <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>
+    <div id="fileHeader">
+      <h1>RubyGems Documentation Index</h1>
+    </div>
+    <!-- banner header -->
 
-<div id="bodyContent">
-  <div id="contextContent">
-    <div id="description">
-      <h1>Summary</h1>
-<p>There are %gem_count% gems installed:</p>
-<p>
-START:specs
-IFNOT:is_last
-<a href="#%name%">%name%</a>,
-ENDIF:is_last
-IF:is_last
-<a href="#%name%">%name%</a>.
-ENDIF:is_last
-END:specs
-<h1>Gems</h1>
+  <div id="bodyContent">
+    <div id="contextContent">
+      <div id="description">
+        <h1>Summary</h1>
+  <p>There are <%=values["gem_count"]%> gems installed:</p>
+  <p>
+  <%= values["specs"].map { |v| "<a href=\"##{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
+  <h1>Gems</h1>
 
-<dl>
-START:specs
-<dt>
-IF:first_name_entry
-  <a name="%name%"></a>
-ENDIF:first_name_entry
-<b>%name% %version%</b>
-IF:rdoc_installed
-  <a href="%doc_path%">[rdoc]</a>
-ENDIF:rdoc_installed
-IFNOT:rdoc_installed
-  <span title="rdoc not installed">[rdoc]</span>
-ENDIF:rdoc_installed
-IF:homepage
-<a href="%homepage%" title="%homepage%">[www]</a>
-ENDIF:homepage
-IFNOT:homepage
-<span title="no homepage available">[www]</span>
-ENDIF:homepage
-IF:has_deps
- - depends on
-START:dependencies
-IFNOT:is_last
-<a href="#%name%" title="%version%">%name%</a>,
-ENDIF:is_last
-IF:is_last
-<a href="#%name%" title="%version%">%name%</a>.
-ENDIF:is_last
-END:dependencies
-ENDIF:has_deps
-</dt>
-<dd>
-%summary%
-IF:executables
-  <br/>
+  <dl>
+  <% values["specs"].each do |spec| %>
+  	<dt>
+  	<% if spec["first_name_entry"] then %>
+  	  <a name="<%=spec["name"]%>"></a>
+  	<% end %>
 
-IF:only_one_executable
-    Executable is
-ENDIF:only_one_executable
-  
-IFNOT:only_one_executable
-    Executables are
-ENDIF:only_one_executable
- 
-START:executables
-IFNOT:is_last
-      <span class="context-item-name">%executable%</span>,
-ENDIF:is_last
-IF:is_last
-      <span class="context-item-name">%executable%</span>.
-ENDIF:is_last
-END:executables
-ENDIF:executables
-<br/>
-<br/>
-</dd>
-END:specs
-</dl>
+  	<b><%=spec["name"]%> <%=spec["version"]%></b>
 
+  	<% if spec["rdoc_installed"] then %>
+  	  <a href="<%=spec["doc_path"]%>">[rdoc]</a>
+  	<% else %>
+  	  <span title="rdoc not installed">[rdoc]</span>
+  	<% end %>
+
+  	<% if spec["homepage"] then %>
+  		<a href="<%=spec["homepage"]%>" title="<%=spec["homepage"]%>">[www]</a>
+  	<% else %>
+  		<span title="no homepage available">[www]</span>
+  	<% end %>
+
+  	<% if spec["has_deps"] then %>
+  	 - depends on
+  		<%= spec["dependencies"].map { |v| "<a href=\"##{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
+  	<% end %>
+  	</dt>
+  	<dd>
+  	<%=spec["summary"]%>
+  	<% if spec["executables"] then %>
+  	  <br/>
+
+  		<% if spec["only_one_executable"] then %>
+  		    Executable is
+  		<% else %>
+  		    Executables are
+  		<%end%>
+
+  		<%= spec["executables"].map { |v| "<span class=\"context-item-name\">#{v["executable"]}</span>"}.join ', ' %>.
+
+  	<%end%>
+  	<br/>
+  	<br/>
+  	</dd>
+  <% end %>
+  </dl>
+
+      </div>
+     </div>
     </div>
-   </div>
+  <div id="validator-badges">
+    <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
   </div>
-<div id="validator-badges">
-  <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
-</div>
-</body>
-</html>
+  </body>
+  </html>
   WEBPAGE
 
   # CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
@@ -496,11 +476,12 @@
       end
 
       # create page from template
-      template = TemplatePage.new(DOC_TEMPLATE)
+      template = ERB.new(DOC_TEMPLATE)
       res['content-type'] = 'text/html'
-      template.write_html_on res.body,
-                             "gem_count" => specs.size.to_s, "specs" => specs,
-                             "total_file_count" => total_file_count.to_s
+      values = { "gem_count" => specs.size.to_s, "specs" => specs,
+                             "total_file_count" => total_file_count.to_s }
+      result = template.result binding
+      res.body = result
     end
 
     paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }

Modified: MacRuby/trunk/lib/rubygems/source_index.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/source_index.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/source_index.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -8,437 +8,512 @@
 require 'rubygems/user_interaction'
 require 'rubygems/specification'
 
-module Gem
+##
+# The SourceIndex object indexes all the gems available from a
+# particular source (e.g. a list of gem directories, or a remote
+# source).  A SourceIndex maps a gem full name to a gem
+# specification.
+#
+# NOTE:: The class used to be named Cache, but that became
+#        confusing when cached source fetchers where introduced. The
+#        constant Gem::Cache is an alias for this class to allow old
+#        YAMLized source index objects to load properly.
 
-  # The SourceIndex object indexes all the gems available from a
-  # particular source (e.g. a list of gem directories, or a remote
-  # source).  A SourceIndex maps a gem full name to a gem
-  # specification.
-  #
-  # NOTE:: The class used to be named Cache, but that became
-  #        confusing when cached source fetchers where introduced. The
-  #        constant Gem::Cache is an alias for this class to allow old
-  #        YAMLized source index objects to load properly.
-  #
-  class SourceIndex
+class Gem::SourceIndex
 
-    include Enumerable
+  include Enumerable
 
+  include Gem::UserInteraction
+
+  attr_reader :gems # :nodoc:
+
+  class << self
     include Gem::UserInteraction
 
-    # Class Methods. -------------------------------------------------
-    class << self
-      include Gem::UserInteraction
-    
-      # Factory method to construct a source index instance for a given
-      # path.
-      #
-      # deprecated::
-      #   If supplied, from_installed_gems will act just like
-      #   +from_gems_in+.  This argument is deprecated and is provided
-      #   just for backwards compatibility, and should not generally
-      #   be used.
-      # 
-      # return::
-      #   SourceIndex instance
-      #
-      def from_installed_gems(*deprecated)
-        if deprecated.empty?
-          from_gems_in(*installed_spec_directories)
-        else
-          from_gems_in(*deprecated) # HACK warn
-        end
+    ##
+    # Factory method to construct a source index instance for a given
+    # path.
+    #
+    # deprecated::
+    #   If supplied, from_installed_gems will act just like
+    #   +from_gems_in+.  This argument is deprecated and is provided
+    #   just for backwards compatibility, and should not generally
+    #   be used.
+    # 
+    # return::
+    #   SourceIndex instance
+
+    def from_installed_gems(*deprecated)
+      if deprecated.empty?
+        from_gems_in(*installed_spec_directories)
+      else
+        from_gems_in(*deprecated) # HACK warn
       end
-      
-      # Return a list of directories in the current gem path that
-      # contain specifications.
-      # 
-      # return::
-      #   List of directory paths (all ending in "../specifications").
-      #
-      def installed_spec_directories
-        Gem.path.collect { |dir| File.join(dir, "specifications") }        
-      end
+    end
 
-      # Factory method to construct a source index instance for a
-      #   given path.
-      # 
-      # spec_dirs::
-      #   List of directories to search for specifications.  Each
-      #   directory should have a "specifications" subdirectory
-      #   containing the gem specifications.
-      #
-      # return::
-      #   SourceIndex instance
-      #
-      def from_gems_in(*spec_dirs)
-        self.new.load_gems_in(*spec_dirs)
-      end
-      
-      # Load a specification from a file (eval'd Ruby code)
-      # 
-      # file_name:: [String] The .gemspec file
-      # return:: Specification instance or nil if an error occurs
-      #
-      def load_specification(file_name)
-        begin
-          spec_code = File.read(file_name).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 SyntaxError => e
-          alert_warning e
-          alert_warning spec_code
-        rescue Exception => e
-          alert_warning(e.inspect.to_s + "\n" + spec_code)
-          alert_warning "Invalid .gemspec format in '#{file_name}'"
+    ##
+    # Returns a list of directories from Gem.path that contain specifications.
+
+    def installed_spec_directories
+      Gem.path.collect { |dir| File.join(dir, "specifications") }
+    end
+
+    ##
+    # Creates a new SourceIndex from the ruby format gem specifications in
+    # +spec_dirs+.
+
+    def from_gems_in(*spec_dirs)
+      self.new.load_gems_in(*spec_dirs)
+    end
+
+    ##
+    # Loads a ruby-format specification from +file_name+ and returns the
+    # loaded spec.
+
+    def load_specification(file_name)
+      begin
+        spec_code = File.read(file_name).untaint
+        gemspec = eval spec_code, binding, file_name
+        if gemspec.is_a?(Gem::Specification)
+          gemspec.loaded_from = file_name
+          return gemspec
         end
-        return nil
+        alert_warning "File '#{file_name}' does not evaluate to a gem specification"
+      rescue SyntaxError => e
+        alert_warning e
+        alert_warning spec_code
+      rescue Exception => e
+        alert_warning(e.inspect.to_s + "\n" + spec_code)
+        alert_warning "Invalid .gemspec format in '#{file_name}'"
       end
-      
+      return nil
     end
 
-    # Instance Methods -----------------------------------------------
+  end
 
-    # Constructs a source index instance from the provided
-    # specifications
-    #
-    # specifications::
-    #   [Hash] hash of [Gem name, Gem::Specification] pairs
-    #
-    def initialize(specifications={})
-      @gems = specifications
-    end
-    
-    # Reconstruct the source index from the list of source
-    # directories.
-    def load_gems_in(*spec_dirs)
-      @gems.clear
-      specs = Dir.glob File.join("{#{spec_dirs.join(',')}}", "*.gemspec")
+  ##
+  # Constructs a source index instance from the provided
+  # specifications
+  #
+  # specifications::
+  #   [Hash] hash of [Gem name, Gem::Specification] pairs
 
-      specs.each do |file_name|
-        gemspec = self.class.load_specification(file_name.untaint)
-        add_spec(gemspec) if gemspec
+  def initialize(specifications={})
+    @gems = specifications
+  end
+
+  ##
+  # Reconstruct the source index from the specifications in +spec_dirs+.
+
+  def load_gems_in(*spec_dirs)
+    @gems.clear
+
+    spec_dirs.reverse_each do |spec_dir|
+      spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
+
+      spec_files.each do |spec_file|
+        gemspec = self.class.load_specification spec_file.untaint
+        add_spec gemspec if gemspec
       end
-      self
     end
 
-    # Returns a Hash of name => Specification of the latest versions of each
-    # gem in this index.
-    def latest_specs
-      result, latest = Hash.new { |h,k| h[k] = [] }, {}
+    self
+  end
 
-      self.each do |_, spec| # SourceIndex is not a hash, so we're stuck with each
-        name = spec.name
-        curr_ver = spec.version
-        prev_ver = latest[name]
+  ##
+  # Returns a Hash of name => Specification of the latest versions of each
+  # gem in this index.
 
-        next unless prev_ver.nil? or curr_ver >= prev_ver
+  def latest_specs
+    result = Hash.new { |h,k| h[k] = [] }
+    latest = {}
 
-        if prev_ver.nil? or curr_ver > prev_ver then
-          result[name].clear
-          latest[name] = curr_ver
-        end
+    sort.each do |_, spec|
+      name = spec.name
+      curr_ver = spec.version
+      prev_ver = latest.key?(name) ? latest[name].version : nil
 
-        result[name] << spec
+      next unless prev_ver.nil? or curr_ver >= prev_ver or
+                  latest[name].platform != Gem::Platform::RUBY
+
+      if prev_ver.nil? or
+         (curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
+        result[name].clear
+        latest[name] = spec
       end
 
-      result.values.flatten
-    end
+      if spec.platform != Gem::Platform::RUBY then
+        result[name].delete_if do |result_spec|
+          result_spec.platform == spec.platform
+        end
+      end
 
-    # Add a gem specification to the source index.
-    def add_spec(gem_spec)
-      @gems[gem_spec.full_name] = gem_spec
+      result[name] << spec
     end
 
-    # Remove a gem specification named +full_name+.
-    def remove_spec(full_name)
-      @gems.delete(full_name)
-    end
+    result.values.flatten
+  end
 
-    # Iterate over the specifications in the source index.
-    def each(&block) # :yields: gem.full_name, gem
-      @gems.each(&block)
-    end
+  ##
+  # Add a gem specification to the source index.
 
-    # The gem specification given a full gem spec name.
-    def specification(full_name)
-      @gems[full_name]
-    end
+  def add_spec(gem_spec)
+    @gems[gem_spec.full_name] = gem_spec
+  end
 
-    # The signature for the source index.  Changes in the signature
-    # indicate a change in the index.
-    def index_signature
-      require 'rubygems/digest/sha2'
+  ##
+  # Add gem specifications to the source index.
 
-      Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
+  def add_specs(*gem_specs)
+    gem_specs.each do |spec|
+      add_spec spec
     end
+  end
 
-    # The signature for the given gem specification.
-    def gem_signature(gem_full_name)
-      require 'rubygems/digest/sha2'
+  ##
+  # Remove a gem specification named +full_name+.
 
-      Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
+  def remove_spec(full_name)
+    @gems.delete(full_name)
+  end
+
+  ##
+  # Iterate over the specifications in the source index.
+
+  def each(&block) # :yields: gem.full_name, gem
+    @gems.each(&block)
+  end
+
+  ##
+  # The gem specification given a full gem spec name.
+
+  def specification(full_name)
+    @gems[full_name]
+  end
+
+  ##
+  # The signature for the source index.  Changes in the signature indicate a
+  # change in the index.
+
+  def index_signature
+    require 'rubygems/digest/sha2'
+
+    Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
+  end
+
+  ##
+  # The signature for the given gem specification.
+
+  def gem_signature(gem_full_name)
+    require 'rubygems/digest/sha2'
+
+    Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
+  end
+
+  def size
+    @gems.size
+  end
+  alias length size
+
+  ##
+  # 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)
+  end
+
+  ##
+  # Search for a gem by Gem::Dependency +gem_pattern+.  If +only_platform+
+  # is true, only gems matching Gem::Platform.local will be returned.  An
+  # Array of matching Gem::Specification objects is returned.
+  #
+  # For backwards compatibility, a String or Regexp pattern may be passed as
+  # +gem_pattern+, and a Gem::Requirement for +platform_only+.  This
+  # behavior is deprecated and will be removed.
+
+  def search(gem_pattern, platform_only = false)
+    version_requirement = nil
+    only_platform = false
+
+    case gem_pattern # TODO warn after 2008/03, remove three months after
+    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
+                      //
+                    else
+                      /^#{Regexp.escape gem_pattern.name}$/
+                    end
+    else
+      version_requirement = platform_only || Gem::Requirement.default
+      gem_pattern = /#{gem_pattern}/i
     end
 
-    def size
-      @gems.size
+    unless Gem::Requirement === version_requirement then
+      version_requirement = Gem::Requirement.create version_requirement
     end
-    alias length size
 
-    # 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)
+    specs = @gems.values.select do |spec|
+      spec.name =~ gem_pattern and
+      version_requirement.satisfied_by? spec.version
     end
 
-    # Search for a gem by Gem::Dependency +gem_pattern+.  If +only_platform+
-    # is true, only gems matching Gem::Platform.local will be returned.  An
-    # Array of matching Gem::Specification objects is returned.
-    #
-    # For backwards compatibility, a String or Regexp pattern may be passed as
-    # +gem_pattern+, and a Gem::Requirement for +platform_only+.  This
-    # behavior is deprecated and will be removed.
-    def search(gem_pattern, platform_only = false)
-      version_requirement = nil
-      only_platform = false
-
-      case gem_pattern # TODO warn after 2008/03, remove three months after
-      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
-                        //
-                      else
-                        /^#{Regexp.escape gem_pattern.name}$/
-                      end
-      else
-        version_requirement = platform_only || Gem::Requirement.default
-        gem_pattern = /#{gem_pattern}/i
+    if only_platform then
+      specs = specs.select do |spec|
+        Gem::Platform.match spec.platform
       end
+    end
 
-      unless Gem::Requirement === version_requirement then
-        version_requirement = Gem::Requirement.create version_requirement
-      end
+    specs.sort_by { |s| s.sort_obj }
+  end
 
-      specs = @gems.values.select do |spec|
-        spec.name =~ gem_pattern and
-          version_requirement.satisfied_by? spec.version
-      end
+  ##
+  # Replaces the gems in the source index from specifications in the
+  # installed_spec_directories,
 
-      if only_platform then
-        specs = specs.select do |spec|
-          Gem::Platform.match spec.platform
-        end
-      end
+  def refresh!
+    load_gems_in(*self.class.installed_spec_directories)
+  end
 
-      specs.sort_by { |s| s.sort_obj }
-    end
+  ##
+  # Returns an Array of Gem::Specifications that are not up to date.
 
-    # Refresh the source index from the local file system.
-    #
-    # return:: Returns a pointer to itself.
-    #
-    def refresh!
-      load_gems_in(self.class.installed_spec_directories)
-    end
+  def outdated
+    dep = Gem::Dependency.new '', Gem::Requirement.default
 
-    # 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
 
-      remotes = Gem::SourceInfoCache.search dep, true
+    outdateds = []
 
-      outdateds = []
+    latest_specs.each do |local|
+      name = local.name
+      remote = remotes.select { |spec| spec.name == name }.
+        sort_by { |spec| spec.version.to_ints }.
+        last
 
-      latest_specs.each do |local|
-        name = local.name
-        remote = remotes.select  { |spec| spec.name == name }.
-                         sort_by { |spec| spec.version.to_ints }.
-                         last
-        outdateds << name if remote and local.version < remote.version
-      end
-
-      outdateds
+      outdateds << name if remote and local.version < remote.version
     end
 
-    def update(source_uri)
-      use_incremental = false
+    outdateds
+  end
 
-      begin
-        gem_names = fetch_quick_index source_uri
-        remove_extra gem_names
-        missing_gems = find_missing gem_names
+  ##
+  # Updates this SourceIndex from +source_uri+.  If +all+ is false, only the
+  # latest gems are fetched.
 
-        return false if missing_gems.size.zero?
+  def update(source_uri, all)
+    source_uri = URI.parse source_uri unless URI::Generic === source_uri
+    source_uri.path += '/' unless source_uri.path =~ /\/$/
 
-        say "missing #{missing_gems.size} gems" if
-          missing_gems.size > 0 and Gem.configuration.really_verbose
+    use_incremental = false
 
-        use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
-      rescue Gem::OperationNotSupportedError => ex
-        alert_error "Falling back to bulk fetch: #{ex.message}" if
-          Gem.configuration.really_verbose
-        use_incremental = false
-      end
+    begin
+      gem_names = fetch_quick_index source_uri, all
+      remove_extra gem_names
+      missing_gems = find_missing gem_names
 
-      if use_incremental then
-        update_with_missing(source_uri, missing_gems)
-      else
-        new_index = fetch_bulk_index(source_uri)
-        @gems.replace(new_index.gems)
-      end
+      return false if missing_gems.size.zero?
 
-      true
-    end
+      say "Missing metadata for #{missing_gems.size} gems" if
+      missing_gems.size > 0 and Gem.configuration.really_verbose
 
-    def ==(other) # :nodoc:
-      self.class === other and @gems == other.gems 
+      use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
+    rescue Gem::OperationNotSupportedError => ex
+      alert_error "Falling back to bulk fetch: #{ex.message}" if
+      Gem.configuration.really_verbose
+      use_incremental = false
     end
 
-    def dump
-      Marshal.dump(self)
+    if use_incremental then
+      update_with_missing(source_uri, missing_gems)
+    else
+      new_index = fetch_bulk_index(source_uri)
+      @gems.replace(new_index.gems)
     end
 
-    protected
+    true
+  end
 
-    attr_reader :gems
+  def ==(other) # :nodoc:
+    self.class === other and @gems == other.gems 
+  end
 
-    private
+  def dump
+    Marshal.dump(self)
+  end
 
-    def fetcher
-      require 'rubygems/remote_fetcher'
+  private
 
-      Gem::RemoteFetcher.fetcher
-    end
+  def fetcher
+    require 'rubygems/remote_fetcher'
 
-    def fetch_index_from(source_uri)
-      @fetch_error = nil
+    Gem::RemoteFetcher.fetcher
+  end
 
-      indexes = %W[
+  def fetch_index_from(source_uri)
+    @fetch_error = nil
+
+    indexes = %W[
         Marshal.#{Gem.marshal_version}.Z
         Marshal.#{Gem.marshal_version}
         yaml.Z
         yaml
       ]
 
-      indexes.each do |name|
-        spec_data = nil
-        begin
-          spec_data = fetcher.fetch_path("#{source_uri}/#{name}")
-          spec_data = unzip(spec_data) if name =~ /\.Z$/
-          if name =~ /Marshal/ then
-            return Marshal.load(spec_data)
-          else
-            return YAML.load(spec_data)
-          end
-        rescue => e
-          if Gem.configuration.really_verbose then
-            alert_error "Unable to fetch #{name}: #{e.message}"
-          end
-          @fetch_error = e
+    indexes.each do |name|
+      spec_data = nil
+      index = source_uri + name
+      begin
+        spec_data = fetcher.fetch_path index
+        spec_data = unzip(spec_data) if name =~ /\.Z$/
+
+        if name =~ /Marshal/ then
+          return Marshal.load(spec_data)
+        else
+          return YAML.load(spec_data)
         end
+      rescue => e
+        if Gem.configuration.really_verbose then
+          alert_error "Unable to fetch #{name}: #{e.message}"
+        end
+
+        @fetch_error = e
       end
-      nil
     end
 
-    def fetch_bulk_index(source_uri)
-      say "Bulk updating Gem source index for: #{source_uri}"
+    nil
+  end
 
-      index = fetch_index_from(source_uri)
-      if index.nil? then
-        raise Gem::RemoteSourceException,
+  def fetch_bulk_index(source_uri)
+    say "Bulk updating Gem source index for: #{source_uri}"
+
+    index = fetch_index_from(source_uri)
+    if index.nil? then
+      raise Gem::RemoteSourceException,
               "Error fetching remote gem cache: #{@fetch_error}"
-      end
-      @fetch_error = nil
-      index
     end
+    @fetch_error = nil
+    index
+  end
 
-    # Get the quick index needed for incremental updates.
-    def fetch_quick_index(source_uri)
-      zipped_index = fetcher.fetch_path source_uri + '/quick/index.rz'
-      unzip(zipped_index).split("\n")
-    rescue ::Exception => ex
+  ##
+  # Get the quick index needed for incremental updates.
+
+  def fetch_quick_index(source_uri, all)
+    index = all ? 'index' : 'latest_index'
+
+    zipped_index = fetcher.fetch_path source_uri + "quick/#{index}.rz"
+
+    unzip(zipped_index).split("\n")
+  rescue ::Exception => e
+    unless all then
+      say "Latest index not found, using quick index" if
+        Gem.configuration.really_verbose
+
+      fetch_quick_index source_uri, true
+    else
       raise Gem::OperationNotSupportedError,
-            "No quick index found: " + ex.message
+            "No quick index found: #{e.message}"
     end
+  end
 
-    # Make a list of full names for all the missing gemspecs.
-    def find_missing(spec_names)
-      spec_names.find_all { |full_name|
-        specification(full_name).nil?
-      }
-    end
+  ##
+  # Make a list of full names for all the missing gemspecs.
 
-    def remove_extra(spec_names)
-      dictionary = spec_names.inject({}) { |h, k| h[k] = true; h }
-      each do |name, spec|
-        remove_spec name unless dictionary.include? name
+  def find_missing(spec_names)
+    unless defined? @originals then
+      @originals = {}
+      each do |full_name, spec|
+        @originals[spec.original_name] = spec
       end
     end
 
-    # Unzip the given string.
-    def unzip(string)
-      require 'zlib'
-      Zlib::Inflate.inflate(string)
+    spec_names.find_all { |full_name|
+      @originals[full_name].nil?
+    }
+  end
+
+  def remove_extra(spec_names)
+    dictionary = spec_names.inject({}) { |h, k| h[k] = true; h }
+    each do |name, spec|
+      remove_spec name unless dictionary.include? spec.original_name
     end
+  end
 
-    # Tries to fetch Marshal representation first, then YAML
-    def fetch_single_spec(source_uri, spec_name)
-      @fetch_error = nil
-      begin
-        marshal_uri = source_uri + "/quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
-        zipped = fetcher.fetch_path marshal_uri
-        return Marshal.load(unzip(zipped))
-      rescue => ex
-        @fetch_error = ex
-        if Gem.configuration.really_verbose then
-          say "unable to fetch marshal gemspec #{marshal_uri}: #{ex.class} - #{ex}"
-        end
+  ##
+  # Unzip the given string.
+
+  def unzip(string)
+    require 'zlib'
+    Zlib::Inflate.inflate(string)
+  end
+
+  ##
+  # Tries to fetch Marshal representation first, then YAML
+
+  def fetch_single_spec(source_uri, spec_name)
+    @fetch_error = nil
+
+    begin
+      marshal_uri = source_uri + "quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
+      zipped = fetcher.fetch_path marshal_uri
+      return Marshal.load(unzip(zipped))
+    rescue => ex
+      @fetch_error = ex
+
+      if Gem.configuration.really_verbose then
+        say "unable to fetch marshal gemspec #{marshal_uri}: #{ex.class} - #{ex}"
       end
+    end
 
-      begin
-        yaml_uri = source_uri + "/quick/#{spec_name}.gemspec.rz"
-        zipped = fetcher.fetch_path yaml_uri
-        return YAML.load(unzip(zipped))
-      rescue => ex
-        @fetch_error = ex
-        if Gem.configuration.really_verbose then
-          say "unable to fetch YAML gemspec #{yaml_uri}: #{ex.class} - #{ex}"
-        end
+    begin
+      yaml_uri = source_uri + "quick/#{spec_name}.gemspec.rz"
+      zipped = fetcher.fetch_path yaml_uri
+      return YAML.load(unzip(zipped))
+    rescue => ex
+      @fetch_error = ex
+      if Gem.configuration.really_verbose then
+        say "unable to fetch YAML gemspec #{yaml_uri}: #{ex.class} - #{ex}"
       end
-      nil
     end
 
-    # Update the cached source index with the missing names.
-    def update_with_missing(source_uri, missing_names)
-      progress = ui.progress_reporter(missing_names.size,
+    nil
+  end
+
+  ##
+  # Update the cached source index with the missing names.
+
+  def update_with_missing(source_uri, missing_names)
+    progress = ui.progress_reporter(missing_names.size,
         "Updating metadata for #{missing_names.size} gems from #{source_uri}")
-      missing_names.each do |spec_name|
-        gemspec = fetch_single_spec(source_uri, spec_name)
-        if gemspec.nil? then
-          ui.say "Failed to download spec #{spec_name} from #{source_uri}:\n" \
+    missing_names.each do |spec_name|
+      gemspec = fetch_single_spec(source_uri, spec_name)
+      if gemspec.nil? then
+        ui.say "Failed to download spec #{spec_name} from #{source_uri}:\n" \
                  "\t#{@fetch_error.message}"
-        else
-          add_spec gemspec
-          progress.updated spec_name
-        end
-        @fetch_error = nil
+      else
+        add_spec gemspec
+        progress.updated spec_name
       end
-      progress.done
-      progress.count
+      @fetch_error = nil
     end
-
+    progress.done
+    progress.count
   end
 
-  # Cache is an alias for SourceIndex to allow older YAMLized source
-  # index objects to load properly.
+end
+
+module Gem
+
+  # :stopdoc:
+
+  # Cache is an alias for SourceIndex to allow older YAMLized source index
+  # objects to load properly.
   Cache = SourceIndex
 
+  # :starddoc:
+
 end
 

Modified: MacRuby/trunk/lib/rubygems/source_info_cache.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/source_info_cache.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/source_info_cache.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -4,6 +4,7 @@
 require 'rubygems/source_info_cache_entry'
 require 'rubygems/user_interaction'
 
+##
 # 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:
@@ -21,23 +22,23 @@
 #   Gem::SourceInfoCache
 #     @cache_data = {
 #       source_uri => Gem::SourceInfoCacheEntry
-#         @size => source index size
-#         @source_index => Gem::SourceIndex
+#         @size = source index size
+#         @source_index = Gem::SourceIndex
 #       ...
 #     }
-#
+
 class Gem::SourceInfoCache
 
   include Gem::UserInteraction
 
-  @cache = nil
-  @system_cache_file = nil
-  @user_cache_file = nil
+  ##
+  # The singleton Gem::SourceInfoCache.  If +all+ is true, a full refresh will
+  # be performed if the singleton instance is being initialized.
 
-  def self.cache
+  def self.cache(all = false)
     return @cache if @cache
     @cache = new
-    @cache.refresh if Gem.configuration.update_sources
+    @cache.refresh all if Gem.configuration.update_sources
     @cache
   end
 
@@ -45,71 +46,85 @@
     cache.cache_data
   end
 
-  # Search all source indexes for +pattern+.
-  def self.search(pattern, platform_only = false)
-    cache.search pattern, platform_only
+  ##
+  # The name of the system cache file.
+
+  def self.latest_system_cache_file
+    File.join File.dirname(system_cache_file),
+              "latest_#{File.basename system_cache_file}"
   end
 
-  # Search all source indexes for +pattern+.  Only returns gems matching
-  # Gem.platforms when +only_platform+ is true.  See #search_with_source.
-  def self.search_with_source(pattern, only_platform = false)
-    cache.search_with_source(pattern, only_platform)
+  ##
+  # The name of the latest user cache file.
+
+  def self.latest_user_cache_file
+    File.join File.dirname(user_cache_file),
+              "latest_#{File.basename user_cache_file}"
   end
 
+  ##
+  # Reset all singletons, discarding any changes.
+
+  def self.reset
+    @cache = nil
+    @system_cache_file = nil
+    @user_cache_file = nil
+  end
+
+  ##
+  # Search all source indexes.  See Gem::SourceInfoCache#search.
+
+  def self.search(*args)
+    cache.search(*args)
+  end
+
+  ##
+  # Search all source indexes returning the source_uri.  See
+  # Gem::SourceInfoCache#search_with_source.
+
+  def self.search_with_source(*args)
+    cache.search_with_source(*args)
+  end
+
+  ##
+  # The name of the system cache file. (class method)
+
+  def self.system_cache_file
+    @system_cache_file ||= Gem.default_system_source_cache_dir
+  end
+
+  ##
+  # The name of the user cache file.
+
+  def self.user_cache_file
+    @user_cache_file ||=
+      ENV['GEMCACHE'] || Gem.default_user_source_cache_dir
+  end
+
   def initialize # :nodoc:
     @cache_data = nil
     @cache_file = nil
     @dirty = false
+    @only_latest = true
   end
 
+  ##
   # The most recent cache data.
+
   def cache_data
     return @cache_data if @cache_data
     cache_file # HACK writable check
 
-    begin
-      # Marshal loads 30-40% faster from a String, and 2MB on 20061116 is small
-      data = File.open cache_file, 'rb' do |fp| fp.read end
-      @cache_data = Marshal.load data
+    @only_latest = true
 
-      @cache_data.each do |url, sice|
-        next unless sice.is_a?(Hash)
-        update
-        cache = sice['cache']
-        size  = sice['size']
-        if cache.is_a?(Gem::SourceIndex) and size.is_a?(Numeric) then
-          new_sice = Gem::SourceInfoCacheEntry.new cache, size
-          @cache_data[url] = new_sice
-        else # irreperable, force refetch.
-          reset_cache_for(url)
-        end
-      end
-      @cache_data
-    rescue => e
-      if Gem.configuration.really_verbose then
-        say "Exception during cache_data handling: #{ex.class} - #{ex}"
-        say "Cache file was: #{cache_file}"
-        say "\t#{e.backtrace.join "\n\t"}"
-      end
-      reset_cache_data
-    end
-  end
+    @cache_data = read_cache_data latest_cache_file
 
-  def reset_cache_for(url)
-    say "Reseting cache for #{url}" if Gem.configuration.really_verbose
-
-    sice = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
-    sice.refresh url # HACK may be unnecessary, see ::cache and #refresh
-
-    @cache_data[url] = sice
     @cache_data
   end
 
-  def reset_cache_data
-    @cache_data = {}
-  end
+  ##
+  # The name of the cache file.
 
-  # The name of the cache file to be read
   def cache_file
     return @cache_file if @cache_file
     @cache_file = (try_file(system_cache_file) or
@@ -117,14 +132,113 @@
       raise "unable to locate a writable cache file")
   end
 
+  ##
   # Write the cache to a local file (if it is dirty).
+
   def flush
     write_cache if @dirty
     @dirty = false
   end
 
-  # Refreshes each source in the cache from its repository.
-  def refresh
+  def latest_cache_data
+    latest_cache_data = {}
+
+    cache_data.each do |repo, sice|
+      latest = sice.source_index.latest_specs
+
+      new_si = Gem::SourceIndex.new
+      new_si.add_specs(*latest)
+
+      latest_sice = Gem::SourceInfoCacheEntry.new new_si, sice.size
+      latest_cache_data[repo] = latest_sice
+    end
+
+    latest_cache_data
+  end
+
+  ##
+  # The name of the latest cache file.
+
+  def latest_cache_file
+    File.join File.dirname(cache_file), "latest_#{File.basename cache_file}"
+  end
+
+  ##
+  # The name of the latest system cache file.
+
+  def latest_system_cache_file
+    self.class.latest_system_cache_file
+  end
+
+  ##
+  # The name of the latest user cache file.
+
+  def latest_user_cache_file
+    self.class.latest_user_cache_file
+  end
+
+  ##
+  # Merges the complete cache file into this Gem::SourceInfoCache.
+
+  def read_all_cache_data
+    if @only_latest then
+      @only_latest = false
+      all_data = read_cache_data cache_file
+
+      cache_data.update all_data do |source_uri, latest_sice, all_sice|
+        all_sice.source_index.gems.update latest_sice.source_index.gems
+
+        Gem::SourceInfoCacheEntry.new all_sice.source_index, latest_sice.size
+      end
+
+      begin
+        refresh true
+      rescue Gem::RemoteFetcher::FetchError
+      end
+    end
+  end
+
+  ##
+  # Reads cached data from +file+.
+
+  def read_cache_data(file)
+    # Marshal loads 30-40% faster from a String, and 2MB on 20061116 is small
+    data = open file, 'rb' do |fp| fp.read end
+    cache_data = Marshal.load data
+
+    cache_data.each do |url, sice|
+      next unless sice.is_a?(Hash)
+      update
+
+      cache = sice['cache']
+      size  = sice['size']
+
+      if cache.is_a?(Gem::SourceIndex) and size.is_a?(Numeric) then
+        new_sice = Gem::SourceInfoCacheEntry.new cache, size
+        cache_data[url] = new_sice
+      else # irreperable, force refetch.
+        reset_cache_for url, cache_data
+      end
+    end
+
+    cache_data
+  rescue Errno::ENOENT
+    {}
+  rescue => e
+    if Gem.configuration.really_verbose then
+      say "Exception during cache_data handling: #{e.class} - #{e}"
+      say "Cache file was: #{file}"
+      say "\t#{e.backtrace.join "\n\t"}"
+    end
+
+    {}
+  end
+
+  ##
+  # Refreshes each source in the cache from its repository.  If +all+ is
+  # false, only latest gems are updated.
+
+  def refresh(all)
     Gem.sources.each do |source_uri|
       cache_entry = cache_data[source_uri]
       if cache_entry.nil? then
@@ -132,14 +246,42 @@
         cache_data[source_uri] = cache_entry
       end
 
-      update if cache_entry.refresh source_uri
+      update if cache_entry.refresh source_uri, all
     end
 
     flush
   end
 
-  # Searches all source indexes for +pattern+.
-  def search(pattern, platform_only = false)
+  def reset_cache_for(url, cache_data)
+    say "Reseting cache for #{url}" if Gem.configuration.really_verbose
+
+    sice = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
+    sice.refresh url, false # HACK may be unnecessary, see ::cache and #refresh
+
+    cache_data[url] = sice
+    cache_data
+  end
+
+  def reset_cache_data
+    @cache_data = nil
+    @only_latest = true
+  end
+
+  ##
+  # Force cache file to be reset, useful for integration testing of rubygems
+
+  def reset_cache_file
+    @cache_file = nil
+  end
+
+  ##
+  # Searches all source indexes.  See Gem::SourceIndex#search for details on
+  # +pattern+ and +platform_only+.  If +all+ is set to true, the full index
+  # will be loaded before searching.
+
+  def search(pattern, platform_only = false, all = false)
+    read_all_cache_data if all
+
     cache_data.map do |source_uri, sic_entry|
       next unless Gem.sources.include? source_uri
       sic_entry.source_index.search pattern, platform_only
@@ -150,7 +292,9 @@
   # only gems matching Gem.platforms will be selected.  Returns an Array of
   # pairs containing the Gem::Specification found and the source_uri it was
   # found at.
-  def search_with_source(pattern, only_platform = false)
+  def search_with_source(pattern, only_platform = false, all = false)
+    read_all_cache_data if all
+
     results = []
 
     cache_data.map do |source_uri, sic_entry|
@@ -164,69 +308,77 @@
     results
   end
 
-  # Mark the cache as updated (i.e. dirty).
-  def update
-    @dirty = true
+  ##
+  # Set the source info cache data directly.  This is mainly used for unit
+  # testing when we don't want to read a file system to grab the cached source
+  # index information.  The +hash+ should map a source URL into a
+  # SourceInfoCacheEntry.
+
+  def set_cache_data(hash)
+    @cache_data = hash
+    update
   end
 
+  ##
   # The name of the system cache file.
+
   def system_cache_file
     self.class.system_cache_file
   end
 
-  # The name of the system cache file. (class method)
-  def self.system_cache_file
-    @system_cache_file ||= Gem.default_system_source_cache_dir
+  ##
+  # Determine if +path+ is a candidate for a cache file.  Returns +path+ if
+  # it is, nil if not.
+
+  def try_file(path)
+    return path if File.writable? path
+    return nil if File.exist? path
+
+    dir = File.dirname path
+
+    unless File.exist? dir then
+      begin
+        FileUtils.mkdir_p dir
+      rescue RuntimeError, SystemCallError
+        return nil
+      end
+    end
+
+    return path if File.writable? dir
+
+    nil
   end
 
+  ##
+  # Mark the cache as updated (i.e. dirty).
+
+  def update
+    @dirty = true
+  end
+
+  ##
   # The name of the user cache file.
+
   def user_cache_file
     self.class.user_cache_file
   end
 
-  # The name of the user cache file. (class method)
-  def self.user_cache_file
-    @user_cache_file ||=
-      ENV['GEMCACHE'] || Gem.default_user_source_cache_dir
-  end
+  ##
+  # Write data to the proper cache files.
 
-  # Write data to the proper cache.
   def write_cache
-    open cache_file, "wb" do |f|
-      f.write Marshal.dump(cache_data)
+    if not File.exist?(cache_file) or not @only_latest then
+      open cache_file, 'wb' do |io|
+        io.write Marshal.dump(cache_data)
+      end
     end
-  end
 
-  # Set the source info cache data directly.  This is mainly used for unit
-  # testing when we don't want to read a file system to grab the cached source
-  # index information.  The +hash+ should map a source URL into a
-  # SourceInfoCacheEntry.
-  def set_cache_data(hash)
-    @cache_data = hash
-    update
+    open latest_cache_file, 'wb' do |io|
+      io.write Marshal.dump(latest_cache_data)
+    end
   end
 
-  private
+  reset
 
-  # Determine if +fn+ is a candidate for a cache file.  Return fn if
-  # it is.  Return nil if it is not.
-  def try_file(fn)
-    return fn if File.writable?(fn)
-    return nil if File.exist?(fn)
-    dir = File.dirname(fn)
-    unless File.exist? dir then
-      begin
-        FileUtils.mkdir_p(dir)
-      rescue RuntimeError, SystemCallError
-        return nil
-      end
-    end
-    if File.writable?(dir)
-      File.open(fn, "wb") { |f| f << Marshal.dump({}) }
-      return fn
-    end
-    nil
-  end
-
 end
 

Modified: MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,24 +3,31 @@
 require 'rubygems/remote_fetcher'
 
 ##
-# Entrys held by a SourceInfoCache.
+# Entries held by a SourceInfoCache.
 
 class Gem::SourceInfoCacheEntry
 
+  ##
   # The source index for this cache entry.
+
   attr_reader :source_index
 
+  ##
   # The size of the of the source entry.  Used to determine if the
   # source index has changed.
+
   attr_reader :size
 
+  ##
   # Create a cache entry.
+
   def initialize(si, size)
     @source_index = si || Gem::SourceIndex.new({})
     @size = size
+    @all = false
   end
 
-  def refresh(source_uri)
+  def refresh(source_uri, all)
     begin
       marshal_uri = URI.join source_uri.to_s, "Marshal.#{Gem.marshal_version}"
       remote_size = Gem::RemoteFetcher.fetcher.fetch_size marshal_uri
@@ -29,9 +36,12 @@
       remote_size = Gem::RemoteFetcher.fetcher.fetch_size yaml_uri
     end
 
-    return false if @size == remote_size # TODO Use index_signature instead of size?
-    updated = @source_index.update source_uri
+    # TODO Use index_signature instead of size?
+    return false if @size == remote_size and @all
+
+    updated = @source_index.update source_uri, all
     @size = remote_size
+    @all = all
 
     updated
   end

Modified: MacRuby/trunk/lib/rubygems/specification.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/specification.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/specification.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,7 +13,7 @@
 if RUBY_VERSION < '1.9' then
   def Time.today
     t = Time.now
-    t - ((t.to_i + t.gmt_offset) % 86400)
+    t - ((t.to_f + t.gmt_offset) % 86400)
   end unless defined? Time.today
 end
 # :startdoc:

Modified: MacRuby/trunk/lib/rubygems/uninstaller.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/uninstaller.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/uninstaller.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -12,7 +12,7 @@
 
 ##
 # An Uninstaller.
-#
+
 class Gem::Uninstaller
 
   include Gem::UserInteraction
@@ -21,8 +21,8 @@
   # Constructs an Uninstaller instance
   #
   # gem:: [String] The Gem name to uninstall
-  #
-  def initialize(gem, options)
+
+  def initialize(gem, options = {})
     @gem = gem
     @version = options[:version] || Gem::Requirement.default
     gem_home = options[:install_dir] || Gem.dir
@@ -30,12 +30,13 @@
     @force_executables = options[:executables]
     @force_all = options[:all]
     @force_ignore = options[:ignore]
+    @bin_dir = options[:bin_dir] 
   end
 
   ##
   # 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)
 
@@ -66,19 +67,15 @@
   end
   
   ##
-  # Remove executables and batch files (windows only) for the gem as
-  # it is being installed
-  #
-  # gemspec::[Specification] the gem whose executables need to be removed.
-  #
+  # Removes installed executables and batch files (windows only) for
+  # +gemspec+.
+
   def remove_executables(gemspec)
     return if gemspec.nil?
 
     if gemspec.executables.size > 0 then
-      bindir = Gem.bindir @gem_home
+      bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
 
-      raise Gem::FilePermissionError, bindir unless File.writable? bindir
-
       list = Gem.source_index.search(gemspec.name).delete_if { |spec|
         spec.version == gemspec.version
       }
@@ -93,14 +90,19 @@
 
       return if executables.size == 0
 
-      answer = @force_executables || ask_yes_no(
-        "Remove executables:\n" \
-        "\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?",
-        true) # " # appease ruby-mode - don't ask
+      answer = if @force_executables.nil? then
+                 ask_yes_no("Remove executables:\n" \
+                            "\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?",
+                            true) # " # appease ruby-mode - don't ask
+               else
+                 @force_executables
+               end
 
       unless answer then
         say "Executables and scripts will remain installed."
       else
+        raise Gem::FilePermissionError, bindir unless File.writable? bindir
+
         gemspec.executables.each do |exe_name|
           say "Removing #{exe_name}"
           FileUtils.rm_f File.join(bindir, exe_name)
@@ -110,23 +112,22 @@
     end
   end
   
+  ##
+  # Removes all gems in +list+.
   #
-  # list:: the list of all gems to remove
-  #
-  # Warning: this method modifies the +list+ parameter.  Once it has
-  # uninstalled a gem, it is removed from that list.
-  #
+  # NOTE: removes uninstalled gems from +list+.
+
   def remove_all(list)
-    list.dup.each { |gem| remove(gem, list) }
+    list.dup.each { |spec| remove spec, list }
   end
 
-  #
+  ##
   # spec:: the spec of the gem to be uninstalled
   # list:: the list of all such gems
   #
   # Warning: this method modifies the +list+ parameter.  Once it has
   # uninstalled a gem, it is removed from that list.
-  #
+
   def remove(spec, list)
     unless dependencies_ok? spec then
       raise Gem::DependencyRemovalException,
@@ -134,10 +135,11 @@
     end
 
     unless path_ok? spec then
-      alert("In order to remove #{spec.name}, please execute:\n" \
-            "\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
-      raise Gem::GemNotInHomeException,
+      e = Gem::GemNotInHomeException.new \
             "Gem is not installed in directory #{@gem_home}"
+      e.spec = spec
+
+      raise e
     end
 
     raise Gem::FilePermissionError, spec.installation_path unless
@@ -182,8 +184,8 @@
   def dependencies_ok?(spec)
     return true if @force_ignore
 
-    srcindex = Gem::SourceIndex.from_installed_gems
-    deplist = Gem::DependencyList.from_source_index srcindex
+    source_index = Gem::SourceIndex.from_installed_gems
+    deplist = Gem::DependencyList.from_source_index source_index
     deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
   end
 

Modified: MacRuby/trunk/lib/rubygems/user_interaction.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/user_interaction.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/user_interaction.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -68,7 +68,7 @@
     include DefaultUserInteraction
     [
       :choose_from_list, :ask, :ask_yes_no, :say, :alert, :alert_warning,
-      :alert_error, :terminate_interaction!, :terminate_interaction
+      :alert_error, :terminate_interaction
     ].each do |methname|
       class_eval %{
         def #{methname}(*args)
@@ -182,16 +182,10 @@
       ask(question) if question
     end
 
-    # Terminate the application immediately without running any exit
-    # handlers.
-    def terminate_interaction!(status=-1)
-      exit!(status)
-    end
-    
     # Terminate the appliation normally, running any exit handlers
     # that might have been defined.
-    def terminate_interaction(status=0)
-      exit(status)
+    def terminate_interaction(status = 0)
+      raise Gem::SystemExitException, status
     end
 
     # Return a progress reporter object

Modified: MacRuby/trunk/lib/rubygems/version_option.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/version_option.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems/version_option.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -23,8 +23,7 @@
                "Specify the platform of gem to #{task}", *wrap) do
                  |value, options|
       unless options[:added_platform] then
-        Gem.platforms.clear
-        Gem.platforms << Gem::Platform::RUBY
+        Gem.platforms = [Gem::Platform::RUBY]
         options[:added_platform] = true
       end
 

Modified: MacRuby/trunk/lib/rubygems.rb
===================================================================
--- MacRuby/trunk/lib/rubygems.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/rubygems.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -17,96 +17,213 @@
 
 module Kernel
 
-  # Adds a Ruby Gem to the $LOAD_PATH.  Before a Gem is loaded, its
-  # required Gems are loaded.  If the version information is omitted,
-  # the highest version Gem of the supplied name is loaded.  If a Gem
-  # is not found that meets the version requirement and/or a required
-  # Gem is not found, a Gem::LoadError is raised. More information on
-  # version requirements can be found in the Gem::Version
-  # documentation.
+  ##
+  # Use Kernel#gem to activate a specific version of +gem_name+.
   #
-  # The +gem+ directive should be executed *before* any require
-  # statements (otherwise rubygems might select a conflicting library
-  # version).
+  # +version_requirements+ is a list of version requirements that the
+  # specified gem must match, most commonly "= example.version.number".  See
+  # Gem::Requirement for how to specify a version requirement.
   #
-  # You can define the environment variable GEM_SKIP as a way to not
-  # load specified gems.  You might do this to test out changes that
-  # haven't been installed yet.  Example:
+  # If you will be activating the latest version of a gem, there is no need to
+  # call Kernel#gem, Kernel#require will do the right thing for you.
   #
-  #   GEM_SKIP=libA:libB ruby-I../libA -I../libB ./mycode.rb
+  # Kernel#gem returns true if the gem was activated, otherwise false.  If the
+  # gem could not be found, didn't match the version requirements, or a
+  # different version was already activated, an exception will be raised.
   #
-  # gem:: [String or Gem::Dependency] The gem name or dependency
-  #       instance.
+  # Kernel#gem should be called *before* any require statements (otherwise
+  # RubyGems may load a conflicting library version).
   #
-  # version_requirement:: [default=">= 0"] The version
-  #                       requirement.
+  # In older RubyGems versions, the environment variable GEM_SKIP could be
+  # used to skip activation of specified gems, for example to test out changes
+  # that haven't been installed yet.  Now RubyGems defers to -I and the
+  # RUBYLIB environment variable to skip activation of a gem.
   #
-  # return:: [Boolean] true if the Gem is loaded, otherwise false.
+  # Example:
   #
-  # raises:: [Gem::LoadError] if Gem cannot be found, is listed in
-  #          GEM_SKIP, or version requirement not met.
-  #
+  #   GEM_SKIP=libA:libB ruby -I../libA -I../libB ./mycode.rb
+
   def gem(gem_name, *version_requirements)
-    active_gem_with_options(gem_name, version_requirements)
-  end
-
-  # Return the file name (string) and line number (integer) of the caller of
-  # the caller of this method.
-  def location_of_caller
-    file, lineno = caller[1].split(':')
-    lineno = lineno.to_i
-    [file, lineno]
-  end
-  private :location_of_caller
-
-  def active_gem_with_options(gem_name, version_requirements, options={})
     skip_list = (ENV['GEM_SKIP'] || "").split(/:/)
     raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name
-    Gem.activate(gem_name, options[:auto_require], *version_requirements)
+    Gem.activate(gem_name, *version_requirements)
   end
-  private :active_gem_with_options
+
 end
 
+##
 # Main module to hold all RubyGem classes/modules.
-#
+
 module Gem
 
   ConfigMap = {} unless defined?(ConfigMap)
   require 'rbconfig'
   RbConfig = Config unless defined? ::RbConfig
+
   ConfigMap.merge!(
-      :BASERUBY => RbConfig::CONFIG["BASERUBY"],
-      :EXEEXT => RbConfig::CONFIG["EXEEXT"],
-      :RUBY_INSTALL_NAME => RbConfig::CONFIG["RUBY_INSTALL_NAME"],
-      :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
-      :arch => RbConfig::CONFIG["arch"],
-      :bindir => RbConfig::CONFIG["bindir"],
-      :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"]
+    :BASERUBY => RbConfig::CONFIG["BASERUBY"],
+    :EXEEXT => RbConfig::CONFIG["EXEEXT"],
+    :RUBY_INSTALL_NAME => RbConfig::CONFIG["RUBY_INSTALL_NAME"],
+    :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
+    :arch => RbConfig::CONFIG["arch"],
+    :bindir => RbConfig::CONFIG["bindir"],
+    :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"]
   )
 
+  DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES)
+
   MUTEX = Mutex.new
 
   RubyGemsPackageVersion = RubyGemsVersion
 
-  DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES)
+  ##
+  # An Array of Regexps that match windows ruby platforms.
 
+  WIN_PATTERNS = [
+    /bccwin/i,
+    /cygwin/i,
+    /djgpp/i,
+    /mingw/i,
+    /mswin/i,
+    /wince/i,
+  ]
+
   @@source_index = nil
   @@win_platform = nil
 
   @configuration = nil
   @loaded_specs = {}
-  @platforms = nil
+  @platforms = []
   @ruby = nil
   @sources = []
 
+  ##
+  # Activates an installed gem matching +gem+.  The gem must satisfy
+  # +version_requirements+.
+  #
+  # Returns true if the gem is activated, false if it is already
+  # loaded, or an exception otherwise.
+  #
+  # Gem#activate adds the library paths in +gem+ to $LOAD_PATH.  Before a Gem
+  # is activated its required Gems are activated.  If the version information
+  # is omitted, the highest version Gem of the supplied name is loaded.  If a
+  # Gem is not found that meets the version requirements or a required Gem is
+  # not found, a Gem::LoadError is raised.
+  #
+  # More information on version requirements can be found in the
+  # Gem::Requirement and Gem::Version documentation.
+
+  def self.activate(gem, *version_requirements)
+    if version_requirements.empty? then
+      version_requirements = Gem::Requirement.default
+    end
+
+    unless gem.respond_to?(:name) and
+           gem.respond_to?(:version_requirements) then
+      gem = Gem::Dependency.new(gem, version_requirements)
+    end
+
+    matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
+    report_activate_error(gem) if matches.empty?
+
+    if @loaded_specs[gem.name] then
+      # This gem is already loaded.  If the currently loaded gem is not in the
+      # list of candidate gems, then we have a version conflict.
+      existing_spec = @loaded_specs[gem.name]
+
+      unless matches.any? { |spec| spec.version == existing_spec.version } then
+        raise Gem::Exception,
+              "can't activate #{gem}, already activated #{existing_spec.full_name}]"
+      end
+
+      return false
+    end
+
+    # new load
+    spec = matches.last
+    return false if spec.loaded?
+
+    spec.loaded = true
+    @loaded_specs[spec.name] = spec
+
+    # Load dependent gems first
+    spec.dependencies.each do |dep_gem|
+      activate dep_gem
+    end
+
+    # bin directory must come before library directories
+    spec.require_paths.unshift spec.bindir if spec.bindir
+
+    require_paths = spec.require_paths.map do |path|
+      File.join spec.full_gem_path, path
+    end
+
+    sitelibdir = ConfigMap[:sitelibdir]
+
+    # gem directories must come after -I and ENV['RUBYLIB']
+    insert_index = load_path_insert_index
+
+    if insert_index then
+      # gem directories must come after -I and ENV['RUBYLIB']
+      $LOAD_PATH.insert(insert_index, *require_paths)
+    else
+      # we are probably testing in core, -I and RUBYLIB don't apply
+      $LOAD_PATH.unshift(*require_paths)
+    end
+
+    return true
+  end
+
+  ##
+  # An Array of all possible load paths for all versions of all gems in the
+  # Gem installation.
+
+  def self.all_load_paths
+    result = []
+
+    Gem.path.each do |gemdir|
+      each_load_path all_partials(gemdir) do |load_path|
+        result << load_path
+      end
+    end
+
+    result
+  end
+
+  ##
+  # Return all the partial paths in +gemdir+.
+
+  def self.all_partials(gemdir)
+    Dir[File.join(gemdir, 'gems/*')]
+  end
+
+  private_class_method :all_partials
+
+  ##
+  # The mode needed to read a file as straight binary.
+
+  def self.binary_mode
+    @binary_mode ||= RUBY_VERSION > '1.9' ? 'rb:ascii-8bit' : 'rb'
+  end
+
+  ##
+  # The path where gem executables are to be installed.
+
+  def self.bindir(install_dir=Gem.dir)
+    return File.join(install_dir, 'bin') unless
+      install_dir.to_s == Gem.default_dir
+    Gem.default_bindir
+  end
+
+  ##
   # Reset the +dir+ and +path+ values.  The next time +dir+ or +path+
   # is requested, the values will be calculated from scratch.  This is
   # mainly used by the unit tests to provide test isolation.
-  #
+
   def self.clear_paths
     @gem_home = nil
     @gem_path = nil
@@ -116,448 +233,462 @@
     end
   end
 
-  # The version of the Marshal format for your Ruby.
-  def self.marshal_version
-    "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
+  ##
+  # The path to standard location of the user's .gemrc file.
+
+  def self.config_file
+    File.join Gem.user_home, '.gemrc'
   end
 
   ##
-  # The directory prefix this RubyGems was installed at.
+  # The standard configuration object for gems.
 
-  def self.prefix
-    prefix = File.dirname File.expand_path(__FILE__)
-    if prefix == ConfigMap[:sitelibdir] then
-      nil
-    else
-      File.dirname prefix
-    end
+  def self.configuration
+    return @configuration if @configuration
+    require 'rubygems/config_file'
+    @configuration = Gem::ConfigFile.new []
   end
 
-  # Returns an Cache of specifications that are in the Gem.path
-  #
-  # return:: [Gem::SourceIndex] Index of installed Gem::Specifications
-  #
-  def self.source_index
-    @@source_index ||= SourceIndex.from_installed_gems
+  ##
+  # Use the given configuration object (which implements the ConfigFile
+  # protocol) as the standard configuration object.
+
+  def self.configuration=(config)
+    @configuration = config
   end
 
   ##
-  # An Array of Regexps that match windows ruby platforms.
+  # The path the the data directory specified by the gem name.  If the
+  # package is not available as a gem, return nil.
 
-  WIN_PATTERNS = [
-    /bccwin/i,
-    /cygwin/i,
-    /djgpp/i,
-    /mingw/i,
-    /mswin/i,
-    /wince/i,
-  ]
+  def self.datadir(gem_name)
+    spec = @loaded_specs[gem_name]
+    return nil if spec.nil?
+    File.join(spec.full_gem_path, 'data', gem_name)
+  end
 
   ##
-  # Is this a windows platform?
+  # The path where gems are to be installed.
 
-  def self.win_platform?
-    if @@win_platform.nil? then
-      @@win_platform = !!WIN_PATTERNS.find { |r| RUBY_PLATFORM =~ r }
-    end
-
-    @@win_platform
+  def self.dir
+    @gem_home ||= nil
+    set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
+    @gem_home
   end
 
-  class << self
+  ##
+  # Expand each partial gem path with each of the required paths specified
+  # in the Gem spec.  Each expanded path is yielded.
 
-    attr_reader :loaded_specs
-
-    # Quietly ensure the named Gem directory contains all the proper
-    # subdirectories.  If we can't create a directory due to a permission
-    # problem, then we will silently continue.
-    def ensure_gem_subdirectories(gemdir)
-      require 'fileutils'
-
-      Gem::DIRECTORIES.each do |filename|
-        fn = File.join gemdir, filename
-        FileUtils.mkdir_p fn rescue nil unless File.exist? fn
+  def self.each_load_path(partials)
+    partials.each do |gp|
+      base = File.basename(gp)
+      specfn = File.join(dir, "specifications", base + ".gemspec")
+      if File.exist?(specfn)
+        spec = eval(File.read(specfn))
+        spec.require_paths.each do |rp|
+          yield(File.join(gp, rp))
+        end
+      else
+        filename = File.join(gp, 'lib')
+        yield(filename) if File.exist?(filename)
       end
     end
+  end
 
-    def platforms
-      @platforms ||= [Gem::Platform::RUBY, Gem::Platform.local]
-    end
+  private_class_method :each_load_path
 
-    # Returns an Array of sources to fetch remote gems from.  If the sources
-    # list is empty, attempts to load the "sources" gem, then uses
-    # default_sources if it is not installed.
-    def sources
-      if @sources.empty? then
-        begin
-          gem 'sources', '> 0.0.1'
-          require 'sources'
-        rescue LoadError
-          @sources = default_sources
-        end
-      end
+  ##
+  # Quietly ensure the named Gem directory contains all the proper
+  # subdirectories.  If we can't create a directory due to a permission
+  # problem, then we will silently continue.
 
-      @sources
+  def self.ensure_gem_subdirectories(gemdir)
+    require 'fileutils'
+
+    Gem::DIRECTORIES.each do |filename|
+      fn = File.join gemdir, filename
+      FileUtils.mkdir_p fn rescue nil unless File.exist? fn
     end
+  end
 
+  ##
+  # Finds the user's home directory.
+  #--
+  # Some comments from the ruby-talk list regarding finding the home
+  # directory:
+  #
+  #   I have HOME, USERPROFILE and HOMEDRIVE + HOMEPATH. Ruby seems
+  #   to be depending on HOME in those code samples. I propose that
+  #   it should fallback to USERPROFILE and HOMEDRIVE + HOMEPATH (at
+  #   least on Win32).
 
-    # Provide an alias for the old name.
-    alias cache source_index
-
-    # The directory path where Gems are to be installed.
-    #
-    # return:: [String] The directory path
-    #
-    def dir
-      @gem_home ||= nil
-      set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
-      @gem_home
+  def self.find_home
+    ['HOME', 'USERPROFILE'].each do |homekey|
+      return ENV[homekey] if ENV[homekey]
     end
 
-    # The directory path where executables are to be installed.
-    #
-    def bindir(install_dir=Gem.dir)
-      return File.join(install_dir, 'bin') unless
-        install_dir.to_s == Gem.default_dir
-
-      if defined? RUBY_FRAMEWORK_VERSION then # mac framework support
-        '/usr/bin'
-      else # generic install
-        ConfigMap[:bindir]
-      end
+    if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
+      return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
     end
 
-    # List of directory paths to search for Gems.
-    #
-    # return:: [List<String>] List of directory paths.
-    #
-    def path
-      @gem_path ||= nil
-      unless @gem_path
-        paths = [ENV['GEM_PATH']]
-        paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
-        set_paths(paths.compact.join(File::PATH_SEPARATOR))
+    begin
+      File.expand_path("~")
+    rescue
+      if File::ALT_SEPARATOR then
+          "C:/"
+      else
+          "/"
       end
-      @gem_path
     end
+  end
 
-    # The home directory for the user.
-    def user_home
-      @user_home ||= find_home
-    end
+  private_class_method :find_home
 
-    # Return the path to standard location of the users .gemrc file.
-    def config_file
-      File.join(Gem.user_home, '.gemrc')
-    end
+  ##
+  # Return a list of all possible load paths for the latest version for all
+  # gems in the Gem installation.
 
-    # The standard configuration object for gems.
-    def configuration
-      return @configuration if @configuration
-      require 'rubygems/config_file'
-      @configuration = Gem::ConfigFile.new []
-    end
+  def self.latest_load_paths
+    result = []
 
-    # Use the given configuration object (which implements the
-    # ConfigFile protocol) as the standard configuration object.
-    def configuration=(config)
-      @configuration = config
+    Gem.path.each do |gemdir|
+      each_load_path(latest_partials(gemdir)) do |load_path|
+        result << load_path
+      end
     end
 
-    # Return the path the the data directory specified by the gem
-    # name.  If the package is not available as a gem, return nil.
-    def datadir(gem_name)
-      spec = @loaded_specs[gem_name]
-      return nil if spec.nil?
-      File.join(spec.full_gem_path, 'data', gem_name)
-    end
+    result
+  end
 
-    # Return the searcher object to search for matching gems.
-    def searcher
-      MUTEX.synchronize do
-        @searcher ||= Gem::GemPathSearcher.new
+  ##
+  # Return only the latest partial paths in the given +gemdir+.
+
+  def self.latest_partials(gemdir)
+    latest = {}
+    all_partials(gemdir).each do |gp|
+      base = File.basename(gp)
+      if base =~ /(.*)-((\d+\.)*\d+)/ then
+        name, version = $1, $2
+        ver = Gem::Version.new(version)
+        if latest[name].nil? || ver > latest[name][0]
+          latest[name] = [ver, gp]
+        end
       end
     end
+    latest.collect { |k,v| v[1] }
+  end
 
-    # Return the Ruby command to use to execute the Ruby interpreter.
-    def ruby
-      if @ruby.nil? then
-        @ruby = File.join(ConfigMap[:bindir],
-                          ConfigMap[:ruby_install_name])
-        @ruby << ConfigMap[:EXEEXT]
-      end
+  private_class_method :latest_partials
 
-      @ruby
-    end
+  ##
+  # The index to insert activated gem paths into the $LOAD_PATH.
+  #
+  # Defaults to the site lib directory unless gem_prelude.rb has loaded paths,
+  # then it inserts the activated gem's paths before the gem_prelude.rb paths
+  # so you can override the gem_prelude.rb default $LOAD_PATH paths.
 
-    # Return the index to insert activated gem paths into the $LOAD_PATH
-    # Defaults to the site lib directory unless gem_prelude.rb has loaded
-    # paths then it inserts the path before those paths so you can override
-    # the gem_prelude.rb default $LOAD_PATH paths.
-    def load_path_insert_index
-      index = $LOAD_PATH.index ConfigMap[:sitelibdir]
+  def self.load_path_insert_index
+    index = $LOAD_PATH.index ConfigMap[:sitelibdir]
 
-      $LOAD_PATH.each_with_index do |path, i|
-        if path.instance_variables.include?(:@gem_prelude_index) or
-           path.instance_variables.include?('@gem_prelude_index') then
-          index = i
-          break
-        end
+    $LOAD_PATH.each_with_index do |path, i|
+      if path.instance_variables.include?(:@gem_prelude_index) or
+        path.instance_variables.include?('@gem_prelude_index') then
+        index = i
+        break
       end
-
-      index
     end
 
-    # Activate a gem (i.e. add it to the Ruby load path).  The gem
-    # must satisfy all the specified version constraints.  If
-    # +autorequire+ is true, then automatically require the specified
-    # autorequire file in the gem spec.
-    #
-    # Returns true if the gem is loaded by this call, false if it is
-    # already loaded, or an exception otherwise.
-    #
-    def activate(gem, autorequire, *version_requirements)
-      if version_requirements.empty? then
-        version_requirements = Gem::Requirement.default
-      end
+    index
+  end
 
-      unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
-        gem = Gem::Dependency.new(gem, version_requirements)
-      end
+  ##
+  # The file name and line number of the caller of the caller of this method.
 
-      matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
-      report_activate_error(gem) if matches.empty?
+  def self.location_of_caller
+    file, lineno = caller[1].split(':')
+    lineno = lineno.to_i
+    [file, lineno]
+  end
 
-      if @loaded_specs[gem.name]
-        # This gem is already loaded.  If the currently loaded gem is
-        # not in the list of candidate gems, then we have a version
-        # conflict.
-        existing_spec = @loaded_specs[gem.name]
-        if ! matches.any? { |spec| spec.version == existing_spec.version }
-          fail Gem::Exception, "can't activate #{gem}, already activated #{existing_spec.full_name}]"
-        end
-        return false
-      end
+  private_class_method :location_of_caller
 
-      # new load
-      spec = matches.last
-      if spec.loaded?
-        return false unless autorequire
-        result = spec.autorequire ? require(spec.autorequire) : false
-        return result || false
-      end
+  ##
+  # manage_gems is useless and deprecated.  Don't call it anymore.
+  #--
+  # TODO warn w/ RubyGems 1.2.x release.
 
-      spec.loaded = true
-      @loaded_specs[spec.name] = spec
+  def self.manage_gems
+    #file, lineno = location_of_caller
 
-      # Load dependent gems first
-      spec.dependencies.each do |dep_gem|
-        activate(dep_gem, autorequire)
-      end
+    #warn "#{file}:#{lineno}:Warning: Gem#manage_gems is deprecated and will be removed on or after September 2008."
+  end
 
-      # bin directory must come before library directories
-      spec.require_paths.unshift spec.bindir if spec.bindir
+  ##
+  # The version of the Marshal format for your Ruby.
 
-      require_paths = spec.require_paths.map do |path|
-        File.join spec.full_gem_path, path
-      end
+  def self.marshal_version
+    "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
+  end
 
-      sitelibdir = ConfigMap[:sitelibdir]
+  ##
+  # Array of paths to search for Gems.
 
-      # gem directories must come after -I and ENV['RUBYLIB']
-      insert_index = load_path_insert_index
+  def self.path
+    @gem_path ||= nil
 
-      if insert_index then
-        # gem directories must come after -I and ENV['RUBYLIB']
-        $LOAD_PATH.insert(insert_index, *require_paths)
-      else
-        # we are probably testing in core, -I and RUBYLIB don't apply
-        $LOAD_PATH.unshift(*require_paths)
-      end
+    unless @gem_path then
+      paths = [ENV['GEM_PATH']] || [default_path]
 
-      # Now autorequire
-      if autorequire && spec.autorequire then # DEPRECATED
-        Array(spec.autorequire).each do |a_lib|
-          require a_lib
-        end
+      if defined?(APPLE_GEM_HOME) and not ENV['GEM_PATH'] then
+        paths << APPLE_GEM_HOME
       end
 
-      return true
+      set_paths paths.compact.join(File::PATH_SEPARATOR)
     end
 
-    # Report a load error during activation.  The message of load
-    # error depends on whether it was a version mismatch or if there
-    # are not gems of any version by the requested name.
-    def report_activate_error(gem)
-      matches = Gem.source_index.find_name(gem.name)
+    @gem_path
+  end
 
-      if matches.empty? then
-        error = Gem::LoadError.new(
-          "Could not find RubyGem #{gem.name} (#{gem.version_requirements})\n")
-      else
-        error = Gem::LoadError.new(
-          "RubyGem version error: " +
-          "#{gem.name}(#{matches.first.version} not #{gem.version_requirements})\n")
-      end
+  ##
+  # Set array of platforms this RubyGems supports (primarily for testing).
 
-      error.name = gem.name
-      error.version_requirement = gem.version_requirements
-      raise error
-    end
-    private :report_activate_error
+  def self.platforms=(platforms)
+    @platforms = platforms
+  end
 
-    # Use the +home+ and (optional) +paths+ values for +dir+ and +path+.
-    # Used mainly by the unit tests to provide environment isolation.
-    #
-    def use_paths(home, paths=[])
-      clear_paths
-      set_home(home) if home
-      set_paths(paths.join(File::PATH_SEPARATOR)) if paths
+  ##
+  # Array of platforms this RubyGems supports.
+  
+  def self.platforms
+    @platforms ||= []
+    if @platforms.empty?
+      @platforms = [Gem::Platform::RUBY, Gem::Platform.local]
     end
+    @platforms
+  end
 
-    # Return a list of all possible load paths for all versions for
-    # all gems in the Gem installation.
-    #
-    def all_load_paths
-      result = []
-      Gem.path.each do |gemdir|
-        each_load_path(all_partials(gemdir)) do |load_path|
-          result << load_path
-        end
-      end
-      result
-    end
+  ##
+  # The directory prefix this RubyGems was installed at.
 
-    # Return a list of all possible load paths for the latest version
-    # for all gems in the Gem installation.
-    def latest_load_paths
-      result = []
-      Gem.path.each do |gemdir|
-        each_load_path(latest_partials(gemdir)) do |load_path|
-          result << load_path
-        end
-      end
-      result
-    end
+  def self.prefix
+    prefix = File.dirname File.expand_path(__FILE__)
 
-    def required_location(gemname, libfile, *version_constraints)
-      version_constraints = Gem::Requirement.default if version_constraints.empty?
-      matches = Gem.source_index.find_name(gemname, version_constraints)
-      return nil if matches.empty?
-      spec = matches.last
-      spec.require_paths.each do |path|
-        result = File.join(spec.full_gem_path, path, libfile)
-        return result if File.exist?(result)
-      end
+    if File.dirname(prefix) == File.expand_path(ConfigMap[:sitelibdir]) or
+       File.dirname(prefix) == File.expand_path(ConfigMap[:libdir]) or
+       'lib' != File.basename(prefix) then
       nil
+    else
+      File.dirname prefix
     end
+  end
 
-    def suffixes
-      ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
+  ##
+  # Refresh source_index from disk and clear searcher.
+
+  def self.refresh
+    source_index.refresh!
+
+    MUTEX.synchronize do
+      @searcher = nil
     end
+  end
 
-    def suffix_pattern
-      @suffix_pattern ||= "{#{suffixes.join(',')}}"
+  ##
+  # Safely read a file in binary mode on all platforms.
+
+  def self.read_binary(path)
+    File.open path, binary_mode do |f| f.read end
+  end
+
+  ##
+  # Report a load error during activation.  The message of load error
+  # depends on whether it was a version mismatch or if there are not gems of
+  # any version by the requested name.
+
+  def self.report_activate_error(gem)
+    matches = Gem.source_index.find_name(gem.name)
+
+    if matches.empty? then
+      error = Gem::LoadError.new(
+          "Could not find RubyGem #{gem.name} (#{gem.version_requirements})\n")
+    else
+      error = Gem::LoadError.new(
+          "RubyGem version error: " +
+          "#{gem.name}(#{matches.first.version} not #{gem.version_requirements})\n")
     end
 
-    # manage_gems is useless and deprecated.  Don't call it anymore.  This
-    # will warn in two releases.
-    def manage_gems
-      # do nothing
+    error.name = gem.name
+    error.version_requirement = gem.version_requirements
+    raise error
+  end
+
+  private_class_method :report_activate_error
+
+  def self.required_location(gemname, libfile, *version_constraints)
+    version_constraints = Gem::Requirement.default if version_constraints.empty?
+    matches = Gem.source_index.find_name(gemname, version_constraints)
+    return nil if matches.empty?
+    spec = matches.last
+    spec.require_paths.each do |path|
+      result = File.join(spec.full_gem_path, path, libfile)
+      return result if File.exist?(result)
     end
+    nil
+  end
 
-    private
+  ##
+  # The path to the running Ruby interpreter.
 
-    # Return all the partial paths in the given +gemdir+.
-    def all_partials(gemdir)
-      Dir[File.join(gemdir, 'gems/*')]
+  def self.ruby
+    if @ruby.nil? then
+      @ruby = File.join(ConfigMap[:bindir],
+                        ConfigMap[:ruby_install_name])
+      @ruby << ConfigMap[:EXEEXT]
     end
 
-    # Return only the latest partial paths in the given +gemdir+.
-    def latest_partials(gemdir)
-      latest = {}
-      all_partials(gemdir).each do |gp|
-        base = File.basename(gp)
-        if base =~ /(.*)-((\d+\.)*\d+)/ then
-          name, version = $1, $2
-          ver = Gem::Version.new(version)
-          if latest[name].nil? || ver > latest[name][0]
-            latest[name] = [ver, gp]
-          end
-        end
-      end
-      latest.collect { |k,v| v[1] }
+    @ruby
+  end
+
+  ##
+  # A Gem::Version for the currently running ruby.
+
+  def self.ruby_version
+    return @ruby_version if defined? @ruby_version
+    version = RUBY_VERSION.dup
+    version << ".#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+    @ruby_version = Gem::Version.new version
+  end
+
+  ##
+  # The GemPathSearcher object used to search for matching installed gems.
+
+  def self.searcher
+    MUTEX.synchronize do
+      @searcher ||= Gem::GemPathSearcher.new
     end
+  end
 
-    # Expand each partial gem path with each of the required paths
-    # specified in the Gem spec.  Each expanded path is yielded.
-    def each_load_path(partials)
-      partials.each do |gp|
-        base = File.basename(gp)
-        specfn = File.join(dir, "specifications", base + ".gemspec")
-        if File.exist?(specfn)
-          spec = eval(File.read(specfn))
-          spec.require_paths.each do |rp|
-            yield(File.join(gp, rp))
-          end
-        else
-          filename = File.join(gp, 'lib')
-          yield(filename) if File.exist?(filename)
+  ##
+  # Set the Gem home directory (as reported by Gem.dir).
+
+  def self.set_home(home)
+    home = home.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
+    @gem_home = home
+    ensure_gem_subdirectories(@gem_home)
+  end
+
+  private_class_method :set_home
+
+  ##
+  # Set the Gem search path (as reported by Gem.path).
+
+  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
+      @gem_path = [Gem.dir]
     end
 
-    # Set the Gem home directory (as reported by +dir+).
-    def set_home(home)
-      @gem_home = home
-      ensure_gem_subdirectories(@gem_home)
-    end
+    @gem_path.uniq!
+    @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
+  end
 
-    # Set the Gem search path (as reported by +path+).
-    def set_paths(gpaths)
-      if gpaths
-        @gem_path = gpaths.split(File::PATH_SEPARATOR)
-        @gem_path << Gem.dir
-      else
-        @gem_path = [Gem.dir]
-      end
-      @gem_path.uniq!
-      @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
-    end
+  private_class_method :set_paths
 
-    # Some comments from the ruby-talk list regarding finding the home
-    # directory:
-    #
-    #   I have HOME, USERPROFILE and HOMEDRIVE + HOMEPATH. Ruby seems
-    #   to be depending on HOME in those code samples. I propose that
-    #   it should fallback to USERPROFILE and HOMEDRIVE + HOMEPATH (at
-    #   least on Win32).
-    #
-    def find_home
-      ['HOME', 'USERPROFILE'].each do |homekey|
-        return ENV[homekey] if ENV[homekey]
-      end
-      if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
-        return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
-      end
+  ##
+  # Returns the Gem::SourceIndex of specifications that are in the Gem.path
+
+  def self.source_index
+    @@source_index ||= SourceIndex.from_installed_gems
+  end
+
+  ##
+  # Returns an Array of sources to fetch remote gems from.  If the sources
+  # list is empty, attempts to load the "sources" gem, then uses
+  # default_sources if it is not installed.
+
+  def self.sources
+    if @sources.empty? then
       begin
-        File.expand_path("~")
-      rescue StandardError => ex
-        if File::ALT_SEPARATOR
-          "C:/"
-        else
-          "/"
-        end
+        gem 'sources', '> 0.0.1'
+        require 'sources'
+      rescue LoadError
+        @sources = default_sources
       end
     end
 
+    @sources
   end
 
+  ##
+  # Glob pattern for require-able path suffixes.
+
+  def self.suffix_pattern
+    @suffix_pattern ||= "{#{suffixes.join(',')}}"
+  end
+
+  ##
+  # Suffixes for require-able paths.
+
+  def self.suffixes
+    ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
+  end
+
+  ##
+  # Use the +home+ and +paths+ values for Gem.dir and Gem.path.  Used mainly
+  # by the unit tests to provide environment isolation.
+
+  def self.use_paths(home, paths=[])
+    clear_paths
+    set_home(home) if home
+    set_paths(paths.join(File::PATH_SEPARATOR)) if paths
+  end
+
+  ##
+  # The home directory for the user.
+
+  def self.user_home
+    @user_home ||= find_home
+  end
+
+  ##
+  # Is this a windows platform?
+
+  def self.win_platform?
+    if @@win_platform.nil? then
+      @@win_platform = !!WIN_PATTERNS.find { |r| RUBY_PLATFORM =~ r }
+    end
+
+    @@win_platform
+  end
+
+  class << self
+
+    attr_reader :loaded_specs
+
+    # :stopdoc:
+
+    alias cache source_index # an alias for the old name
+
+    # :startdoc:
+
+  end
+
 end
 
 # Modify the non-gem version of datadir to handle gem package names.
 
 require 'rbconfig/datadir'
+
 module Config # :nodoc:
   class << self
     alias gem_original_datadir datadir

Modified: MacRuby/trunk/lib/set.rb
===================================================================
--- MacRuby/trunk/lib/set.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/set.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,14 +2,14 @@
 #--
 # set.rb - defines the Set class
 #++
-# Copyright (c) 2002 Akinori MUSHA <knu at iDaemons.org>
+# Copyright (c) 2002-2008 Akinori MUSHA <knu at iDaemons.org>
 #
 # Documentation by Akinori MUSHA and Gavin Sinclair. 
 #
 # All rights reserved.  You can redistribute and/or modify it under the same
 # terms as Ruby.
 #
-#   $Id: set.rb 12104 2007-03-20 02:09:10Z knu $
+#   $Id: set.rb 16169 2008-04-23 02:58:46Z knu $
 #
 # == Overview 
 # 
@@ -47,6 +47,10 @@
 #   s1.subset? s2                         # -> false
 #   s2.subset? s1                         # -> true
 #
+# == Contact
+#
+#   - Akinori MUSHA <knu at iDaemons.org> (current maintainer)
+#
 class Set
   include Enumerable
 
@@ -200,8 +204,10 @@
   end
 
   # Calls the given block once for each element in the set, passing
-  # the element as parameter.
+  # the element as parameter.  Returns an enumerator if no block is
+  # given.
   def each
+    block_given? or return enum_for(__method__)
     @hash.each_key { |o| yield(o) }
     self
   end
@@ -507,6 +513,7 @@
 	  end
 
 	  def each
+	    block_given? or return enum_for(__method__)
 	    to_a.each { |o| yield(o) }
 	  end
 
@@ -921,9 +928,8 @@
     ary = [1,3,5,7,10,20]
     set = Set.new(ary)
 
-    assert_raises(LocalJumpError) {
-      set.each
-    }
+    e = set.each
+    assert_instance_of(Enumerable::Enumerator, e)
 
     assert_nothing_raised {
       set.each { |o|

Modified: MacRuby/trunk/lib/shellwords.rb
===================================================================
--- MacRuby/trunk/lib/shellwords.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/shellwords.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,6 +13,9 @@
 #   - Wakou Aoyama
 #   - Akinori MUSHA <knu at iDaemons.org>
 #
+# Contact:
+#   - Akinori MUSHA <knu at iDaemons.org> (current maintainer)
+#
 module Shellwords
   #
   # Splits a string into an array of tokens in the same way the UNIX

Modified: MacRuby/trunk/lib/webrick/httprequest.rb
===================================================================
--- MacRuby/trunk/lib/webrick/httprequest.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/webrick/httprequest.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -23,7 +23,7 @@
     attr_reader :request_method, :unparsed_uri, :http_version
 
     # Request-URI
-    attr_reader :request_uri, :host, :port, :path
+    attr_reader :request_uri, :path
     attr_accessor :script_name, :path_info, :query_string
 
     # Header and entity body

Modified: MacRuby/trunk/lib/webrick/httpservlet/filehandler.rb
===================================================================
--- MacRuby/trunk/lib/webrick/httpservlet/filehandler.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/webrick/httpservlet/filehandler.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -163,6 +163,7 @@
             end
           end
         end
+        prevent_directory_traversal(req, res)
         super(req, res)
       end
 
@@ -198,6 +199,22 @@
 
       private
 
+      def prevent_directory_traversal(req, res)
+        # Preventing directory traversal on DOSISH platforms;
+        # Backslashes (0x5c) in path_info are not interpreted as special
+        # character in URI notation. So the value of path_info should be
+        # normalize before accessing to the filesystem.
+        if File::ALT_SEPARATOR
+          # File.expand_path removes the trailing path separator.
+          # Adding a character is a workaround to save it.
+          #  File.expand_path("/aaa/")        #=> "/aaa"
+          #  File.expand_path("/aaa/" + "x")  #=> "/aaa/x"
+          expanded = File.expand_path(req.path_info + "x")
+          expanded[-1, 1] = ""  # remove trailing "x"
+          req.path_info = expanded
+        end
+      end
+
       def exec_handler(req, res)
         raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root
         if set_filename(req, res)
@@ -256,7 +273,7 @@
 
       def check_filename(req, res, name)
         @options[:NondisclosureName].each{|pattern|
-          if File.fnmatch("/#{pattern}", name)
+          if File.fnmatch("/#{pattern}", name, File::FNM_CASEFOLD)
             @logger.warn("the request refers nondisclosure name `#{name}'.")
             raise HTTPStatus::NotFound, "`#{req.path}' not found."
           end
@@ -310,7 +327,7 @@
 
       def nondisclosure_name?(name)
         @options[:NondisclosureName].each{|pattern|
-          if File.fnmatch(pattern, name)
+          if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
             return true
           end
         }

Modified: MacRuby/trunk/lib/xmlrpc/client.rb
===================================================================
--- MacRuby/trunk/lib/xmlrpc/client.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/xmlrpc/client.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -268,7 +268,7 @@
 
 
 = History
-    $Id: client.rb 13769 2007-10-24 20:00:10Z jeg2 $
+    $Id: client.rb 16042 2008-04-15 14:10:18Z kou $
 
 =end
 
@@ -565,8 +565,13 @@
         raise "Wrong size. Was #{data.size}, should be #{expected}"
       end
 
-      c = resp["Set-Cookie"]
-      @cookie = c if c
+      set_cookies = resp.get_fields("Set-Cookie")
+      if set_cookies and !set_cookies.empty?
+        @cookie = set_cookies.collect do |set_cookie|
+          cookie = WEBrick::Cookie.parse_set_cookie(set_cookie)
+          WEBrick::Cookie.new(cookie.name, cookie.value).to_s
+        end.join("; ")
+      end
 
       return data
     end

Modified: MacRuby/trunk/lib/yaml/store.rb
===================================================================
--- MacRuby/trunk/lib/yaml/store.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/lib/yaml/store.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -20,10 +20,24 @@
   end
 
   def load(content)
-    YAML::load(content)
+    table = YAML::load(content)
+    if table == false
+      {}
+    else
+      table
+    end
   end
 
-  def load_file(file)
-    YAML::load(file)
+  def marshal_dump_supports_canonical_option?
+    false
   end
+
+  EMPTY_MARSHAL_DATA = {}.to_yaml
+  EMPTY_MARSHAL_CHECKSUM = Digest::MD5.digest(EMPTY_MARSHAL_DATA)
+  def empty_marshal_data
+    EMPTY_MARSHAL_DATA
+  end
+  def empty_marshal_checksum
+    EMPTY_MARSHAL_CHECKSUM
+  end
 end

Modified: MacRuby/trunk/load.c
===================================================================
--- MacRuby/trunk/load.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/load.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -23,11 +23,10 @@
     0
 };
 
-VALUE rb_load_path;		/* to be moved to VM */
-static VALUE
-get_load_path(void)
+VALUE
+rb_get_load_path(void)
 {
-    VALUE load_path = rb_load_path;
+    VALUE load_path = GET_VM()->load_path;
     VALUE ary = rb_ary_new2(RARRAY_LEN(load_path));
     long i;
 
@@ -38,6 +37,12 @@
 }
 
 static VALUE
+load_path_getter(ID id, rb_vm_t *vm)
+{
+    return vm->load_path;
+}
+
+static VALUE
 get_loaded_features(void)
 {
     return GET_VM()->loaded_features;
@@ -126,7 +131,7 @@
 	if ((n = RSTRING_CLEN(v)) < len) continue;
 	if (strncmp(f, feature, len) != 0) {
 	    if (expanded) continue;
-	    if (!load_path) load_path = get_load_path();
+	    if (!load_path) load_path = rb_get_load_path();
 	    if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
 		continue;
 	    f += RSTRING_CLEN(p) + 1;
@@ -151,7 +156,7 @@
 	    fs.name = feature;
 	    fs.len = len;
 	    fs.type = type;
-	    fs.load_path = load_path ? load_path : get_load_path();
+	    fs.load_path = load_path ? load_path : rb_get_load_path();
 	    fs.result = 0;
 	    st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
 	    if ((f = fs.result) != 0) {
@@ -191,7 +196,13 @@
 rb_provided(const char *feature)
 {
     const char *ext = strrchr(feature, '.');
+    volatile VALUE fullpath = 0;
 
+    if (*feature == '.' &&
+	(feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
+	fullpath = rb_file_expand_path(rb_str_new2(feature), Qnil);
+	feature = RSTRING_CPTR(fullpath);
+    }
     if (ext && !strchr(ext, '/')) {
 	if (IS_RBEXT(ext)) {
 	    if (rb_feature_p(feature, ext, Qtrue, Qfalse, 0)) return Qtrue;
@@ -514,8 +525,6 @@
     } volatile saved;
     char *volatile ftptr = 0;
 
-    FilePathValue(fname);
-    RB_GC_GUARD(fname) = rb_str_new4(fname);
     PUSH_TAG();
     saved.safe = rb_safe_level();
     if ((state = EXEC_TAG()) == 0) {
@@ -524,6 +533,8 @@
 	int found;
 
 	rb_set_safe_level_force(safe);
+	FilePathValue(fname);
+	RB_GC_GUARD(fname) = rb_str_new4(fname);
 	found = search_required(fname, &path);
 	if (found) {
 	    if (!path || !(ftptr = load_lock(RSTRING_CPTR(path)))) {
@@ -664,12 +675,15 @@
 void
 Init_load()
 {
-    rb_define_readonly_variable("$:", &rb_load_path);
-    rb_define_readonly_variable("$-I", &rb_load_path);
-    rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
-    rb_load_path = rb_ary_new();
-    GC_ROOT(&rb_load_path);
+    rb_vm_t *vm = GET_VM();
+    const char *var_load_path = "$:";
+    ID id_load_path = rb_intern(var_load_path);
 
+    rb_define_hooked_variable(var_load_path, (VALUE*)GET_VM(), load_path_getter, 0);
+    rb_alias_variable((rb_intern)("$-I"), id_load_path);
+    rb_alias_variable((rb_intern)("$LOAD_PATH"), id_load_path);
+    vm->load_path = rb_ary_new();
+
     rb_define_virtual_variable("$\"", get_loaded_features, 0);
     rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
     GC_WB(&GET_VM()->loaded_features, rb_ary_new());

Modified: MacRuby/trunk/marshal.c
===================================================================
--- MacRuby/trunk/marshal.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/marshal.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   marshal.c -
 
-  $Author: akr $
+  $Author: matz $
   created at: Thu Apr 27 16:30:01 JST 1995
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -487,6 +487,7 @@
     name = rb_enc_name2(enc);
 #else
     int encidx = rb_enc_get_index(obj);
+    rb_encoding *enc = 0;
     st_data_t name;
 
     if (encidx <= 0 || !(enc = rb_enc_from_index(encidx))) {
@@ -616,8 +617,10 @@
         }
 
 	if (rb_respond_to(obj, s_mdump)) {
-	    VALUE v;
+	    volatile VALUE v;
 
+            st_add_direct(arg->data, obj, arg->data->num_entries);
+
 	    v = rb_funcall(obj, s_mdump, 0, 0);
 	    w_class(TYPE_USRMARSHAL, obj, arg, Qfalse);
 	    w_object(v, arg, limit);
@@ -644,10 +647,29 @@
             else if (hasiv) {
 		w_ivar(obj, ivtbl, &c_arg);
 	    }
+            st_add_direct(arg->data, obj, arg->data->num_entries);
 	    return;
 	}
 
-	switch (TYPE(obj)) {
+        st_add_direct(arg->data, obj, arg->data->num_entries);
+
+#if WITH_OBJC
+	if (!rb_objc_is_non_native(obj))
+#endif
+        {
+            st_data_t compat_data;
+            rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass);
+            if (st_lookup(compat_allocator_tbl,
+                          (st_data_t)allocator,
+                          &compat_data)) {
+                marshal_compat_t *compat = (marshal_compat_t*)compat_data;
+                VALUE real_obj = obj;
+                obj = compat->dumper(real_obj);
+                st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj);
+            }
+        }
+
+	switch (/*BUILTIN_*/TYPE(obj)) {
 	  case T_CLASS:
 	    if (FL_TEST(obj, FL_SINGLETON)) {
 		rb_raise(rb_eTypeError, "singleton class can't be dumped");
@@ -1102,9 +1124,9 @@
         rb_hash_aset(arg->data, INT2FIX(RHASH_SIZE(arg->data)), v);
     }
     if (arg->taint) {
-	rb_obj_taint(v);
+        OBJ_TAINT(v);
         if ((VALUE)real_obj != Qundef)
-            rb_obj_taint((VALUE)real_obj);
+            OBJ_TAINT((VALUE)real_obj);
     }
     return v;
 }
@@ -1680,9 +1702,9 @@
  * first two bytes of marshaled data.
  *
  *     str = Marshal.dump("thing")
- *     RUBY_VERSION   #=> "1.8.0"
- *     str[0]         #=> 4
- *     str[1]         #=> 8
+ *     RUBY_VERSION   #=> "1.9.0"
+ *     str[0].ord     #=> 4
+ *     str[1].ord     #=> 8
  *
  * Some objects cannot be dumped: if the objects to be dumped include
  * bindings, procedure or method objects, instances of class IO, or

Modified: MacRuby/trunk/math.c
===================================================================
--- MacRuby/trunk/math.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/math.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   math.c -
 
-  $Author: akr $
+  $Author: matz $
   created at: Tue Jan 25 14:12:56 JST 1994
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -15,7 +15,20 @@
 
 VALUE rb_mMath;
 
-#define Need_Float(x) (x) = rb_Float(x)
+static VALUE
+to_flo(VALUE x)
+{
+    if (!rb_obj_is_kind_of(x, rb_cNumeric)) {
+	rb_raise(rb_eTypeError, "can't convert %s into Float",
+		 NIL_P(x) ? "nil" :
+		 x == Qtrue ? "true" :
+		 x == Qfalse ? "false" :
+		 rb_obj_classname(x));
+    }
+    return rb_convert_type(x, T_FLOAT, "Float", "to_f");
+}
+
+#define Need_Float(x) (x) = to_flo(x)
 #define Need_Float2(x,y) do {\
     Need_Float(x);\
     Need_Float(y);\
@@ -50,7 +63,7 @@
  *     
  */
 
-static VALUE
+VALUE
 math_atan2(VALUE obj, VALUE y, VALUE x)
 {
     Need_Float2(y, x);
@@ -66,7 +79,7 @@
  *  -1..1.
  */
 
-static VALUE
+VALUE
 math_cos(VALUE obj, VALUE x)
 {
     Need_Float(x);
@@ -81,7 +94,7 @@
  *  -1..1.
  */
 
-static VALUE
+VALUE
 math_sin(VALUE obj, VALUE x)
 {
     Need_Float(x);
@@ -172,7 +185,7 @@
  *  Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
  */
 
-static VALUE
+VALUE
 math_cosh(VALUE obj, VALUE x)
 {
     Need_Float(x);
@@ -196,7 +209,7 @@
  *  radians).
  */
 
-static VALUE
+VALUE
 math_sinh(VALUE obj, VALUE x)
 {
     Need_Float(x);
@@ -285,7 +298,7 @@
  *  Returns e**x.
  */
 
-static VALUE
+VALUE
 math_exp(VALUE obj, VALUE x)
 {
     Need_Float(x);
@@ -311,7 +324,7 @@
  *  of logarithm.
  */
 
-static VALUE
+VALUE
 math_log(int argc, VALUE *argv)
 {
     VALUE x, base;
@@ -388,7 +401,7 @@
  *  Returns the non-negative square root of <i>numeric</i>.
  */
 
-static VALUE
+VALUE
 math_sqrt(VALUE obj, VALUE x)
 {
     double d;
@@ -465,7 +478,7 @@
  *     Math.hypot(3, 4)   #=> 5.0
  */
 
-static VALUE
+VALUE
 math_hypot(VALUE obj, VALUE x, VALUE y)
 {
     Need_Float2(x, y);

Modified: MacRuby/trunk/misc/README
===================================================================
--- MacRuby/trunk/misc/README	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/misc/README	2008-05-18 08:10:19 UTC (rev 199)
@@ -4,5 +4,5 @@
 rubydb2x.el       ruby debugger support for emacs 19.2x or before
 rubydb3x.el       ruby debugger support for emacs 19.3x or later
 ruby-electric.el  emacs minor mode providing electric commands
-rdebug.el         ruby-debug (rdebug) support for emacs 19.3x or later
-xcode-templates   ruby templates for Apple's Xcode IDE
+
+Check out http://rubyforge.org/projects/ruby-debug/ also.

Modified: MacRuby/trunk/misc/ruby-mode.el
===================================================================
--- MacRuby/trunk/misc/ruby-mode.el	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/misc/ruby-mode.el	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,11 +1,11 @@
 ;;;
 ;;;  ruby-mode.el -
 ;;;
-;;;  $Author: nobu $
+;;;  $Author: matz $
 ;;;  created at: Fri Feb  4 14:49:13 JST 1994
 ;;;
 
-(defconst ruby-mode-revision "$Revision: 15297 $"
+(defconst ruby-mode-revision "$Revision: 16266 $"
   "Ruby mode revision string.")
 
 (defconst ruby-mode-version
@@ -162,6 +162,14 @@
   "Default deep indent style."
   :options '(t nil space) :group 'ruby)
 
+(defcustom ruby-encoding-map '((shift_jis . cp932) (shift-jis . cp932))
+  "Alist to map encoding name from emacs to ruby."
+  :group 'ruby)
+
+(defcustom ruby-use-encoding-map t
+  "*Use `ruby-encoding-map' to set encoding magic comment if this is non-nil."
+  :type 'boolean :group 'ruby)
+
 (eval-when-compile (require 'cl))
 (defun ruby-imenu-create-index-in-block (prefix beg end)
   (let ((index-alist '()) (case-fold-search nil)
@@ -234,11 +242,6 @@
   (make-local-variable 'paragraph-ignore-fill-prefix)
   (setq paragraph-ignore-fill-prefix t))
 
-(eval-when-compile
-  (unless (fboundp 'coding-system-to-mime-charset)
-    (defun coding-system-to-mime-charset (coding-system)
-      (coding-system-change-eol-conversion coding-system nil))))
-
 (defun ruby-mode-set-encoding ()
   (save-excursion
     (widen)
@@ -246,18 +249,29 @@
     (when (re-search-forward "[^\0-\177]" nil t)
       (goto-char (point-min))
       (let ((coding-system
-	     (coding-system-to-mime-charset
-	      (or coding-system-for-write
-		  buffer-file-coding-system))))
+	     (or coding-system-for-write
+		 buffer-file-coding-system)))
+	(if coding-system
+	    (setq coding-system
+		  (or (coding-system-get coding-system 'mime-charset)
+		      (coding-system-change-eol-conversion coding-system nil))))
 	(setq coding-system
 	      (if coding-system
-		  (symbol-name coding-system)
+		  (symbol-name
+		   (or (and ruby-use-encoding-map
+			    (cdr (assq coding-system ruby-encoding-map)))
+		       coding-system))
 		"ascii-8bit"))
 	(if (looking-at "^#![^\n]*ruby") (beginning-of-line 2))
-	(cond ((looking-at "\\s *#.*-\*-\\s *\\(en\\)?coding\\s *:\\s *\\([-a-z0-9_]+\\)")
+	(cond ((looking-at "\\s *#.*-\*-\\s *\\(en\\)?coding\\s *:\\s *\\([-a-z0-9_]*\\)\\s *\\(;\\|-\*-\\)")
 	       (unless (string= (match-string 2) coding-system)
 		 (goto-char (match-beginning 2))
 		 (delete-region (point) (match-end 2))
+		 (and (looking-at "-\*-")
+		      (let ((n (skip-chars-backward " ")))
+			(cond ((= n 0) (insert "  ") (backward-char))
+			      ((= n -1) (insert " "))
+			      ((forward-char)))))
 		 (insert coding-system)))
 	      ((looking-at "\\s *#.*coding\\s *[:=]"))
 	      (t (insert "# -*- coding: " coding-system " -*-\n"))
@@ -285,11 +299,21 @@
   (make-local-variable 'add-log-current-defun-function)
   (setq add-log-current-defun-function 'ruby-add-log-current-method)
 
-  (make-local-variable 'before-save-hook)
-  (add-hook 'before-save-hook 'ruby-mode-set-encoding)
+  (add-hook
+   (cond ((boundp 'before-save-hook)
+	  (make-local-variable 'before-save-hook)
+	  'before-save-hook)
+	 ((boundp 'write-contents-functions) 'write-contents-functions)
+	 ((boundp 'write-contents-hooks) 'write-contents-hooks))
+   'ruby-mode-set-encoding)
 
-  (run-hooks 'ruby-mode-hook))
+  (set (make-local-variable 'font-lock-defaults) '((ruby-font-lock-keywords) nil nil))
+  (set (make-local-variable 'font-lock-keywords) ruby-font-lock-keywords)
+  (set (make-local-variable 'font-lock-syntax-table) ruby-font-lock-syntax-table)
+  (set (make-local-variable 'font-lock-syntactic-keywords) ruby-font-lock-syntactic-keywords)
 
+  (run-mode-hooks 'ruby-mode-hook))
+
 (defun ruby-current-indentation ()
   (save-excursion
     (beginning-of-line)
@@ -713,7 +737,7 @@
 	      (setq end nil))
 	    (goto-char (or end pos))
 	    (skip-chars-backward " \t")
-	    (setq begin (if (nth 0 state) pos (cdr (nth 1 state))))
+	    (setq begin (if (and end (nth 0 state)) pos (cdr (nth 1 state))))
 	    (setq state (ruby-parse-region parse-start (point))))
 	  (or (bobp) (forward-char -1))
 	  (and
@@ -1001,17 +1025,19 @@
   "Return current method string."
   (condition-case nil
       (save-excursion
-	(let ((mlist nil) (indent 0))
+	(let (mname mlist (indent 0))
 	  ;; get current method (or class/module)
 	  (if (re-search-backward
 	       (concat "^[ \t]*\\(def\\|class\\|module\\)[ \t]+"
-		       "\\(" 
-		       ;; \\. for class method
-			"\\(" ruby-symbol-re "\\|\\." "\\)" 
+		       "\\("
+		       ;; \\. and :: for class method
+			"\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)" 
 			"+\\)")
 	       nil t)
 	      (progn
-		(setq mlist (list (match-string 2)))
+		(setq mname (match-string 2))
+		(unless (string-equal "def" (match-string 1))
+		  (setq mlist (list mname) mname nil))
 		(goto-char (match-beginning 1))
 		(setq indent (current-column))
 		(beginning-of-line)))
@@ -1020,7 +1046,7 @@
 		      (re-search-backward
 		       (concat
 			"^[ \t]*\\(class\\|module\\)[ \t]+"
-			"\\([A-Z]" ruby-symbol-re "+\\)")
+			"\\([A-Z]" ruby-symbol-re "*\\)")
 		       nil t))
 	    (goto-char (match-beginning 1))
 	    (if (< (current-column) indent)
@@ -1028,10 +1054,33 @@
 		  (setq mlist (cons (match-string 2) mlist))
 		  (setq indent (current-column))
 		  (beginning-of-line))))
+	  (when mname
+	    (let ((mn (split-string mname "\\.\\|::")))
+	      (if (cdr mn)
+		  (progn
+		    (cond
+		     ((string-equal "" (car mn))
+		      (setq mn (cdr mn) mlist nil))
+		     ((string-equal "self" (car mn))
+		      (setq mn (cdr mn)))
+		     ((let ((ml (nreverse mlist)))
+			(while ml
+			  (if (string-equal (car ml) (car mn))
+			      (setq mlist (nreverse (cdr ml)) ml nil))
+			  (or (setq ml (cdr ml)) (nreverse mlist))))))
+		    (if mlist
+			(setcdr (last mlist) mn)
+		      (setq mlist mn))
+		    (setq mn (last mn 2))
+		    (setq mname (concat "." (cadr mn)))
+		    (setcdr mn nil))
+		(setq mname (concat "#" mname)))))
 	  ;; generate string
 	  (if (consp mlist)
-	      (mapconcat (function identity) mlist "::")
-	    nil)))))
+	      (setq mlist (mapconcat (function identity) mlist "::")))
+	  (if mname
+	      (if mlist (concat mlist mname) mname)
+	    mlist)))))
 
 (cond
  ((featurep 'font-lock)
@@ -1057,24 +1106,13 @@
 	  ("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil))
 	  ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))))
 
-  (cond ((featurep 'xemacs)
-	 (put 'ruby-mode 'font-lock-defaults
-	      '((ruby-font-lock-keywords)
-		nil nil nil
-		beginning-of-line
-		(font-lock-syntactic-keywords
-		 . ruby-font-lock-syntactic-keywords))))
-	(t
-	 (add-hook 'ruby-mode-hook
-	    '(lambda ()
-	       (make-local-variable 'font-lock-defaults)
-	       (make-local-variable 'font-lock-keywords)
-	       (make-local-variable 'font-lock-syntax-table)
-	       (make-local-variable 'font-lock-syntactic-keywords)
-	       (setq font-lock-defaults '((ruby-font-lock-keywords) nil nil))
-	       (setq font-lock-keywords ruby-font-lock-keywords)
-	       (setq font-lock-syntax-table ruby-font-lock-syntax-table)
-	       (setq font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)))))
+  (if (featurep 'xemacs)
+      (put 'ruby-mode 'font-lock-defaults
+	   '((ruby-font-lock-keywords)
+	     nil nil nil
+	     beginning-of-line
+	     (font-lock-syntactic-keywords
+	      . ruby-font-lock-syntactic-keywords))))
 
   (defun ruby-font-lock-docs (limit)
     (if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t)

Modified: MacRuby/trunk/misc/ruby-style.el
===================================================================
--- MacRuby/trunk/misc/ruby-style.el	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/misc/ruby-style.el	2008-05-18 08:10:19 UTC (rev 199)
@@ -4,11 +4,11 @@
 ;;;
 ;;; C/C++ mode style for Ruby.
 ;;;
-;;;  $Author: akr $
+;;;  $Author: nobu $
 ;;;  created at: Thu Apr 26 13:54:01 JST 2007
 ;;;
 
-(defconst ruby-style-revision "$Revision: 14912 $"
+(defconst ruby-style-revision "$Revision: 16153 $"
   "Ruby style revision string.")
 
 (defconst ruby-style-version
@@ -19,6 +19,7 @@
 
 (defun ruby-style-case-indent (x)
   (save-excursion
+    (back-to-indentation)
     (unless (progn (backward-up-list) (back-to-indentation)
 		   (> (point) (cdr x)))
       (goto-char (cdr x))
@@ -26,8 +27,9 @@
 
 (defun ruby-style-label-indent (x)
   (save-excursion
+    (back-to-indentation)
     (unless (progn (backward-up-list) (back-to-indentation)
-		   (> (point) (cdr x)))
+		   (>= (point) (cdr x)))
       (goto-char (cdr x))
       (condition-case ()
 	  (progn

Modified: MacRuby/trunk/missing/lgamma_r.c
===================================================================
--- MacRuby/trunk/missing/lgamma_r.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/missing/lgamma_r.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -34,6 +34,8 @@
 {
     double v, w;
 
+    if (x == 1.0 || x == 2.0) return 0.0;
+
     v = 1;
     while (x < N) {  v *= x;  x++;  }
     w = 1 / (x * x);

Modified: MacRuby/trunk/missing/tgamma.c
===================================================================
--- MacRuby/trunk/missing/tgamma.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/missing/tgamma.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -9,9 +9,9 @@
 /***********************************************************
     gamma.c -- Gamma function
 ***********************************************************/
+#include "ruby/config.h"
 #include <math.h>
 #include <errno.h>
-#include "ruby/config.h"
 
 #ifdef HAVE_LGAMMA_R
 

Modified: MacRuby/trunk/missing/vsnprintf.c
===================================================================
--- MacRuby/trunk/missing/vsnprintf.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/missing/vsnprintf.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -550,7 +550,7 @@
 	int fieldsz;		/* field size expanded by sign, etc */
 	int realsz;		/* field size expanded by dprec */
 	int size;		/* size of converted field or string */
-	char *xdigs;		/* digits for [xX] conversion */
+	char *xdigs = 0;	/* digits for [xX] conversion */
 #define NIOV 8
 	struct __suio uio;	/* output information: summary */
 	struct __siov iov[NIOV];/* ... and individual io vectors */
@@ -908,10 +908,11 @@
 			/* leading 0x/X only if non-zero */
 			if (flags & ALT &&
 #ifdef _HAVE_SANE_QUAD_
-			    (flags & QUADINT ? uqval != 0 : ulval != 0))
+			    (flags & QUADINT ? uqval != 0 : ulval != 0)
 #else /* _HAVE_SANE_QUAD_ */
-			    ulval != 0)
+			    ulval != 0
 #endif /* _HAVE_SANE_QUAD_ */
+			    )
 				flags |= HEXPREFIX;
 
 			/* unsigned conversions */
@@ -935,10 +936,10 @@
 				if (uqval != 0 || prec != 0)
 					cp = BSD__uqtoa(uqval, cp, base,
 					    flags & ALT, xdigs);
-			} else {
+			} else
 #else /* _HAVE_SANE_QUAD_ */
+#endif /* _HAVE_SANE_QUAD_ */
 			{
-#endif /* _HAVE_SANE_QUAD_ */
 				if (ulval != 0 || prec != 0)
 					cp = BSD__ultoa(ulval, cp, base,
 					    flags & ALT, xdigs);

Modified: MacRuby/trunk/numeric.c
===================================================================
--- MacRuby/trunk/numeric.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/numeric.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -249,15 +249,14 @@
 /*
  *  call-seq:
  *     num.quo(numeric)    =>   result
- *     num.fdiv(numeric)   =>   result
  *
- *  Equivalent to <code>Numeric#/</code>, but overridden in subclasses.
+ *  Returns most exact division (rational for integers, float for floats).
  */
 
 static VALUE
 num_quo(VALUE x, VALUE y)
 {
-    return rb_funcall(x, '/', 1, y);
+    return rb_funcall(rb_rational_raw1(x), '/', 1, y);
 }
 
 
@@ -312,6 +311,7 @@
  *
  *
  *  Examples
+ *
  *     11.divmod(3)         #=> [3, 2]
  *     11.divmod(-3)        #=> [-4, -1]
  *     11.divmod(3.5)       #=> [3, 0.5]
@@ -645,6 +645,11 @@
     }
 }
 
+static VALUE
+flo_quo(VALUE x, VALUE y)
+{
+    return rb_funcall(x, '/', 1, y);
+}
 
 static void
 flodivmod(double x, double y, double *divp, double *modp)
@@ -707,6 +712,22 @@
     return DOUBLE2NUM(mod);
 }
 
+static VALUE
+dbl2ival(double d)
+{
+    if (FIXABLE(d)) {
+	d = round(d);
+	return LONG2FIX((long)d);
+    }
+    else if (isnan(d) || isinf(d)) {
+	/* special case: cannot return integer value */
+	return rb_float_new(d);
+    }
+    else {
+	return rb_dbl2big(d);
+    }
+}
+
 /*
  *  call-seq:
  *     flt.divmod(numeric)    => array
@@ -717,7 +738,7 @@
 static VALUE
 flo_divmod(VALUE x, VALUE y)
 {
-    double fy, div, mod, val;
+    double fy, div, mod;
     volatile VALUE a, b;
 
     switch (TYPE(y)) {
@@ -734,16 +755,7 @@
 	return rb_num_coerce_bin(x, y, rb_intern("divmod"));
     }
     flodivmod(RFLOAT_VALUE(x), fy, &div, &mod);
-    if (FIXABLE(div)) {
-	val = round(div);
-	a = LONG2FIX(val);
-    }
-    else if (isnan(div) || isinf(div)) {
-	a = rb_float_new(div);
-    }
-    else {
-	a = rb_dbl2big(div);
-    }
+    a = dbl2ival(div);
     b = DOUBLE2NUM(mod);
     return rb_assoc_new(a, b);
 }
@@ -1263,7 +1275,7 @@
     int ndigits = 0, i;
     long val;
 
-    if (rb_scan_args(argc, argv, "01", &nd) == 1) {
+    if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) {
 	ndigits = NUM2INT(nd);
     }
     number  = RFLOAT_VALUE(num);
@@ -1492,6 +1504,7 @@
 SIGNED_VALUE
 rb_num2long(VALUE val)
 {
+  again:
     if (NIL_P(val)) {
 	rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
     }
@@ -1518,7 +1531,7 @@
 
       default:
 	val = rb_to_int(val);
-	return NUM2LONG(val);
+	goto again;
     }
 }
 
@@ -1690,7 +1703,18 @@
 
 #endif  /* HAVE_LONG_LONG */
 
+static VALUE
+num_numerator(VALUE num)
+{
+    return rb_funcall(rb_Rational1(num), rb_intern("numerator"), 0);
+}
 
+static VALUE
+num_denominator(VALUE num)
+{
+    return rb_funcall(rb_Rational1(num), rb_intern("denominator"), 0);
+}
+
 /*
  * Document-class: Integer
  *
@@ -1876,6 +1900,18 @@
 #endif
 }
 
+static VALUE
+int_numerator(VALUE num)
+{
+    return num;
+}
+
+static VALUE
+int_denominator(VALUE num)
+{
+    return INT2FIX(1);
+}
+
 /********************************************************************
  *
  * Document-class: Fixnum
@@ -1924,6 +1960,7 @@
       case T_BIGNUM:
 	return x;
       case T_FLOAT:
+      case T_RATIONAL:
 	return rb_funcall(x, id_to_i, 0);
       default:
 	rb_raise(rb_eTypeError, "failed to convert %s into Integer",
@@ -1944,6 +1981,7 @@
     switch (TYPE(x)) {
       case T_FIXNUM:
       case T_BIGNUM:
+      case T_RATIONAL:
 	return rb_funcall(x, rb_intern("to_f"), 0);
       case T_FLOAT:
 	return x;
@@ -2013,13 +2051,16 @@
 static VALUE
 fix_to_s(int argc, VALUE *argv, VALUE x)
 {
-    VALUE b;
     int base;
 
-    rb_scan_args(argc, argv, "01", &b);
     if (argc == 0) base = 10;
-    else base = NUM2INT(b);
+    else {
+	VALUE b;
 
+	rb_scan_args(argc, argv, "01", &b);
+	base = NUM2INT(b);
+    }
+
     return rb_fix2str(x, base);
 }
 
@@ -2178,19 +2219,18 @@
 
 /*
  *  call-seq:
- *     fix.quo(numeric)    => float
  *     fix.fdiv(numeric)   => float
  *
  *  Returns the floating point result of dividing <i>fix</i> by
  *  <i>numeric</i>.
  *
- *     654321.quo(13731)      #=> 47.6528293642124
- *     654321.quo(13731.24)   #=> 47.6519964693647
+ *     654321.fdiv(13731)      #=> 47.6528293642124
+ *     654321.fdiv(13731.24)   #=> 47.6519964693647
  *
  */
 
 static VALUE
-fix_quo(VALUE x, VALUE y)
+fix_fdiv(VALUE x, VALUE y)
 {
     if (FIXNUM_P(y)) {
 	return DOUBLE2NUM((double)FIX2LONG(x) / (double)FIX2LONG(y));
@@ -2201,12 +2241,12 @@
       case T_FLOAT:
 	return DOUBLE2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
       default:
-	return rb_num_coerce_bin(x, y, rb_intern("quo"));
+	return rb_num_coerce_bin(x, y, rb_intern("fdiv"));
     }
 }
 
 static VALUE
-fix_divide(VALUE x, VALUE y, int flo)
+fix_divide(VALUE x, VALUE y, ID op)
 {
     if (FIXNUM_P(y)) {
 	long div;
@@ -2219,15 +2259,17 @@
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_div(x, y);
       case T_FLOAT:
-	if (flo) {
-	    return DOUBLE2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
+	{
+	    double div = (double)FIX2LONG(x) / RFLOAT_VALUE(y);
+	    if (op == '/') {
+		return DOUBLE2NUM(div);
+	    }
+	    else {
+		return rb_dbl2big(floor(div));
+	    }
 	}
-	else {
-	    long div = (double)FIX2LONG(x) / RFLOAT_VALUE(y);
-	    return LONG2NUM(div);
-	}
       default:
-	return rb_num_coerce_bin(x, y, flo ? '/' : rb_intern("div"));
+	return rb_num_coerce_bin(x, y, op);
     }
 }
 
@@ -2243,7 +2285,7 @@
 static VALUE
 fix_div(VALUE x, VALUE y)
 {
-    return fix_divide(x, y, Qtrue);
+    return fix_divide(x, y, '/');
 }
 
 /*
@@ -2256,7 +2298,7 @@
 static VALUE
 fix_idiv(VALUE x, VALUE y)
 {
-    return fix_divide(x, y, Qfalse);
+    return fix_divide(x, y, rb_intern("div"));
 }
 
 /*
@@ -2319,7 +2361,7 @@
 	    volatile VALUE a, b;
 
 	    flodivmod((double)FIX2LONG(x), RFLOAT_VALUE(y), &div, &mod);
-	    a = DOUBLE2NUM(div);
+	    a = dbl2ival(div);
 	    b = DOUBLE2NUM(mod);
 	    return rb_assoc_new(a, b);
 	}
@@ -2385,6 +2427,9 @@
     if (FIXNUM_P(y)) {
 	long b = FIX2LONG(y);
 
+	if (b < 0)
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+
 	if (b == 0) return INT2FIX(1);
 	if (b == 1) return x;
 	if (a == 0) {
@@ -2398,13 +2443,14 @@
 	    else 
 		return INT2FIX(-1);
 	}
-	if (b > 0) {
-	    return int_pow(a, b);
-	}
-	return DOUBLE2NUM(pow((double)a, (double)b));
+	return int_pow(a, b);
     }
     switch (TYPE(y)) {
       case T_BIGNUM:
+
+	if (rb_funcall(y, '<', 1, INT2FIX(0)))
+	  return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
+
 	if (a == 0) return INT2FIX(0);
 	if (a == 1) return INT2FIX(1);
 	if (a == -1) {
@@ -2594,6 +2640,18 @@
     return LONG2NUM(val);
 }
 
+static VALUE
+bit_coerce(VALUE x)
+{
+    while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) {
+	if (TYPE(x) == T_FLOAT) {
+	    rb_raise(rb_eTypeError, "can't convert Float into Integer");
+	}
+	x = rb_to_int(x);
+    }
+    return x;
+}
+
 /*
  * call-seq:
  *   fix & other     => integer
@@ -2606,10 +2664,10 @@
 {
     long val;
 
-    if (TYPE(y) == T_BIGNUM) {
+    if (!FIXNUM_P(y = bit_coerce(y))) {
 	return rb_big_and(y, x);
     }
-    val = FIX2LONG(x) & NUM2LONG(y);
+    val = FIX2LONG(x) & FIX2LONG(y);
     return LONG2NUM(val);
 }
 
@@ -2625,10 +2683,10 @@
 {
     long val;
 
-    if (TYPE(y) == T_BIGNUM) {
+    if (!FIXNUM_P(y = bit_coerce(y))) {
 	return rb_big_or(y, x);
     }
-    val = FIX2LONG(x) | NUM2LONG(y);
+    val = FIX2LONG(x) | FIX2LONG(y);
     return LONG2NUM(val);
 }
 
@@ -2644,10 +2702,10 @@
 {
     long val;
 
-    if (TYPE(y) == T_BIGNUM) {
+    if (!FIXNUM_P(y = bit_coerce(y))) {
 	return rb_big_xor(y, x);
     }
-    val = FIX2LONG(x) ^ NUM2LONG(y);
+    val = FIX2LONG(x) ^ FIX2LONG(y);
     return LONG2NUM(val);
 }
 
@@ -2741,7 +2799,8 @@
     long val = FIX2LONG(fix);
     long i;
 
-    if (TYPE(idx) == T_BIGNUM) {
+    idx = rb_to_int(idx);
+    if (!FIXNUM_P(idx)) {
 	idx = rb_big_norm(idx);
 	if (!FIXNUM_P(idx)) {
 	    if (!RBIGNUM_SIGN(idx) || val >= 0)
@@ -2749,7 +2808,7 @@
 	    return INT2FIX(1);
 	}
     }
-    i = NUM2LONG(idx);
+    i = FIX2LONG(idx);
 
     if (i < 0) return INT2FIX(0);
     if (SIZEOF_LONG*CHAR_BIT-1 < i) {
@@ -2800,56 +2859,10 @@
     return LONG2NUM(i);
 }
 
-/*
- *  call-seq:
- *     fix.id2name -> string or nil
- *
- *  Returns the name of the object whose symbol id is <i>fix</i>. If
- *  there is no symbol in the symbol table with this value, returns
- *  <code>nil</code>. <code>id2name</code> has nothing to do with the
- *  <code>Object.id</code> method. See also <code>Fixnum#to_sym</code>,
- *  <code>String#intern</code>, and class <code>Symbol</code>.
- *
- *     symbol = :@inst_var    #=> :@inst_var
- *     id     = symbol.to_i   #=> 9818
- *     id.id2name             #=> "@inst_var"
- */
 
-static VALUE
-fix_id2name(VALUE fix)
-{
-    VALUE name = rb_id2str(FIX2UINT(fix));
-    if (name) return rb_str_dup(name);
-    return Qnil;
-}
 
-
 /*
  *  call-seq:
- *     fix.to_sym -> aSymbol
- *
- *  Returns the symbol whose integer value is <i>fix</i>. See also
- *  <code>Fixnum#id2name</code>.
- *
- *     fred = :fred.to_i
- *     fred.id2name   #=> "fred"
- *     fred.to_sym    #=> :fred
- */
-
-static VALUE
-fix_to_sym(VALUE fix)
-{
-    ID id = FIX2UINT(fix);
-
-    if (rb_id2name(id)) {
-	return ID2SYM(id);
-    }
-    return Qnil;
-}
-
-
-/*
- *  call-seq:
  *     fix.size -> fixnum
  *
  *  Returns the number of <em>bytes</em> in the machine representation
@@ -3120,6 +3133,9 @@
     rb_define_method(rb_cNumeric, "truncate", num_truncate, 0);
     rb_define_method(rb_cNumeric, "step", num_step, -1);
 
+    rb_define_method(rb_cNumeric, "numerator", num_numerator, 0);
+    rb_define_method(rb_cNumeric, "denominator", num_denominator, 0);
+
     rb_cInteger = rb_define_class("Integer", rb_cNumeric);
     rb_undef_alloc_func(rb_cInteger);
     rb_undef_method(CLASS_OF(rb_cInteger), "new");
@@ -3147,11 +3163,11 @@
     rb_define_singleton_method(rb_cFixnum, "induced_from", rb_fix_induced_from, 1);
     rb_define_singleton_method(rb_cInteger, "induced_from", rb_int_induced_from, 1);
 
+    rb_define_method(rb_cInteger, "numerator", int_numerator, 0);
+    rb_define_method(rb_cInteger, "denominator", int_denominator, 0);
+
     rb_define_method(rb_cFixnum, "to_s", fix_to_s, -1);
 
-    rb_define_method(rb_cFixnum, "id2name", fix_id2name, 0);
-    rb_define_method(rb_cFixnum, "to_sym", fix_to_sym, 0);
-
     rb_define_method(rb_cFixnum, "-@", fix_uminus, 0);
     rb_define_method(rb_cFixnum, "+", fix_plus, 1);
     rb_define_method(rb_cFixnum, "-", fix_minus, 1);
@@ -3161,8 +3177,7 @@
     rb_define_method(rb_cFixnum, "%", fix_mod, 1);
     rb_define_method(rb_cFixnum, "modulo", fix_mod, 1);
     rb_define_method(rb_cFixnum, "divmod", fix_divmod, 1);
-    rb_define_method(rb_cFixnum, "quo", fix_quo, 1);
-    rb_define_method(rb_cFixnum, "fdiv", fix_quo, 1);
+    rb_define_method(rb_cFixnum, "fdiv", fix_fdiv, 1);
     rb_define_method(rb_cFixnum, "**", fix_pow, 1);
 
     rb_define_method(rb_cFixnum, "abs", fix_abs, 0);
@@ -3217,6 +3232,8 @@
     rb_define_method(rb_cFloat, "-", flo_minus, 1);
     rb_define_method(rb_cFloat, "*", flo_mul, 1);
     rb_define_method(rb_cFloat, "/", flo_div, 1);
+    rb_define_method(rb_cFloat, "quo", flo_quo, 1);
+    rb_define_method(rb_cFloat, "fdiv", flo_quo, 1);
     rb_define_method(rb_cFloat, "%", flo_mod, 1);
     rb_define_method(rb_cFloat, "modulo", flo_mod, 1);
     rb_define_method(rb_cFloat, "divmod", flo_divmod, 1);

Modified: MacRuby/trunk/object.c
===================================================================
--- MacRuby/trunk/object.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/object.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   object.c -
 
-  $Author: naruse $
+  $Author: matz $
   created at: Thu Jul 15 12:01:24 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -396,7 +396,7 @@
  *  generate the string.
  *     
  *     [ 1, 2, 3..4, 'five' ].inspect   #=> "[1, 2, 3..4, \"five\"]"
- *     Time.new.inspect                 #=> "Wed Apr 09 08:54:39 CDT 2003"
+ *     Time.new.inspect                 #=> "2008-03-08 19:43:39 +0900"
  */
 
 
@@ -1137,8 +1137,8 @@
  *       end
  *     end
  *     Mod.class              #=> Module
- *     Mod.constants          #=> ["E", "PI", "CONST"]
- *     Mod.instance_methods   #=> ["meth"]
+ *     Mod.constants          #=> [:CONST, :PI, :E]
+ *     Mod.instance_methods   #=> [:meth]
  *     
  */
 
@@ -1184,7 +1184,7 @@
 static VALUE
 rb_mod_freeze(VALUE mod)
 {
-    rb_mod_to_s(mod);
+    rb_class_name(mod);
     return rb_obj_freeze(mod);
 }
 
@@ -1406,10 +1406,11 @@
     if (RCLASS_SUPER(klass) != 0) {
 	rb_raise(rb_eTypeError, "already initialized class");
     }
-    if (rb_scan_args(argc, argv, "01", &super) == 0) {
+    if (argc == 0) {
 	super = rb_cObject;
     }
     else {
+	rb_scan_args(argc, argv, "01", &super);
 	rb_check_inheritable(super);
     }
     RCLASS_SUPER(klass) = super;
@@ -1498,9 +1499,10 @@
  *  
  *  Returns the superclass of <i>class</i>, or <code>nil</code>.
  *     
- *     File.superclass     #=> IO
- *     IO.superclass       #=> Object
- *     Object.superclass   #=> nil
+ *     File.superclass          #=> IO
+ *     IO.superclass            #=> Object
+ *     Object.superclass        #=> BasicObject
+ *     BasicObject.superclass   #=> nil
  *     
  */
 
@@ -1585,7 +1587,7 @@
  *     module Mod
  *       attr_accessor(:one, :two)
  *     end
- *     Mod.instance_methods.sort   #=> ["one", "one=", "two", "two="]
+ *     Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]
  */
 
 static VALUE
@@ -1701,8 +1703,8 @@
  *     end
  *     k = Klass.new
  *     k.methods[0..9]    #=> ["kMethod", "freeze", "nil?", "is_a?", 
- *                             "class", "instance_variable_set",
- *                              "methods", "extend", "__send__", "instance_eval"]
+ *                        #    "class", "instance_variable_set",
+ *                        #    "methods", "extend", "__send__", "instance_eval"]
  *     k.methods.length   #=> 42
  */
 
@@ -2103,7 +2105,7 @@
  *     
  *     Integer(123.999)    #=> 123
  *     Integer("0x1a")     #=> 26
- *     Integer(Time.new)   #=> 1049896590
+ *     Integer(Time.new)   #=> 1204973019
  */
 
 static VALUE
@@ -2124,16 +2126,16 @@
 
     if (!p) return 0.0;
     q = p;
-	while (ISSPACE(*p)) p++;
+    while (ISSPACE(*p)) p++;
     d = strtod(p, &end);
     if (errno == ERANGE) {
 	OutOfRange();
-	rb_warn("Float %.*s%s out of range", w, p, ellipsis);
+	rb_warning("Float %.*s%s out of range", w, p, ellipsis);
 	errno = 0;
     }
     if (p == end) {
+	if (badcheck) {
 	  bad:
-	if (badcheck) {
 	    rb_invalid_str(q, "Float()");
 	}
 	return d;
@@ -2142,26 +2144,31 @@
 	char buf[DBL_DIG * 4 + 10];
 	char *n = buf;
 	char *e = buf + sizeof(buf) - 1;
+	char prev = 0;
 
-	while (p < end && n < e) *n++ = *p++;
-	while (n < e && *p) {
+	while (p < end && n < e) prev = *n++ = *p++;
+	while (*p) {
 	    if (*p == '_') {
 		/* remove underscores between digits */
-		if (n == buf || !ISDIGIT(n[-1])) goto bad;
-		while (*++p == '_');
-		if (!ISDIGIT(*p)) {
-		    if (badcheck) goto bad;
-		    break;
+		if (badcheck) {
+		    if (n == buf || !ISDIGIT(prev)) goto bad;
+		    ++p;
+		    if (!ISDIGIT(*p)) goto bad;
 		}
+		else {
+		    while (*++p == '_');
+		    continue;
+		}
 	    }
-	    *n++ = *p++;
+	    prev = *p++;
+	    if (n < e) *n++ = prev;
 	}
 	*n = '\0';
 	p = buf;
 	d = strtod(p, &end);
 	if (errno == ERANGE) {
 	    OutOfRange();
-	    rb_warn("Float %.*s%s out of range", w, p, ellipsis);
+	    rb_warning("Float %.*s%s out of range", w, p, ellipsis);
 	    errno = 0;
 	}
 	if (badcheck) {
@@ -2223,13 +2230,7 @@
 	break;
 
       default:
-      {
-	  VALUE f = rb_convert_type(val, T_FLOAT, "Float", "to_f");
-	  if (isnan(RFLOAT_VALUE(f))) {
-	      rb_raise(rb_eArgError, "invalid value for Float()");
-	  }
-	  return f;
-      }
+	return rb_convert_type(val, T_FLOAT, "Float", "to_f");
     }
 }
 

Modified: MacRuby/trunk/pack.c
===================================================================
--- MacRuby/trunk/pack.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/pack.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   pack.c -
 
-  $Author: akr $
+  $Author: nobu $
   created at: Thu Feb 10 15:17:05 JST 1994
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -1888,8 +1888,8 @@
 
 	  case 'P':
 	    if (sizeof(char *) <= send - s) {
+		VALUE tmp = Qnil;
 		char *t;
-		VALUE tmp;
 
 		memcpy(&t, s, sizeof(char *));
 		s += sizeof(char *);
@@ -1927,8 +1927,8 @@
 		    p = RARRAY_PTR(a);
 		    pend = p + RARRAY_LEN(a);
 		    while (p < pend) {
-			if (TYPE(*p) == T_STRING && RSTRING_CPTR(*p) == t) {
-			    if (len < RSTRING_CLEN(*p)) {
+			if (TYPE(*p) == T_STRING && RSTRING_PTR(*p) == t) {
+			    if (len < RSTRING_LEN(*p)) {
 				tmp = rb_tainted_str_new(t, len);
 				rb_str_associate(tmp, a);
 			    }
@@ -1958,7 +1958,7 @@
 		if (send - s < sizeof(char *))
 		    break;
 		else {
-		    VALUE tmp;
+		    VALUE tmp = Qnil;
 		    char *t;
 
 		    memcpy(&t, s, sizeof(char *));

Modified: MacRuby/trunk/parse.y
===================================================================
--- MacRuby/trunk/parse.y	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/parse.y	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   parse.y -
 
-  $Author: matz $
+  $Author: usa $
   created at: Fri May 28 18:02:42 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -571,10 +571,8 @@
 static void ripper_warnI(struct parser_params*, const char*, int);
 static void ripper_warnS(struct parser_params*, const char*, const char*);
 static void ripper_warning0(struct parser_params*, const char*);
-#if 0				/* unused in ripper right now */
 static void ripper_warningS(struct parser_params*, const char*, const char*);
 #endif
-#endif
 
 #ifdef RIPPER
 static void ripper_compile_error(struct parser_params*, const char *fmt, ...);
@@ -1805,9 +1803,11 @@
 		| lhs '=' arg modifier_rescue arg
 		    {
 		    /*%%%*/
-			$$ = node_assign($1, NEW_RESCUE($3, NEW_RESBODY(0,$5,0), 0));
+			value_expr($3);
+		        $3 = NEW_RESCUE($3, NEW_RESBODY(0,$5,0), 0);
+			$$ = node_assign($1, $3);
 		    /*%
-			$$ = dispatch2(assign, $1, dispatch2(rescue_mod,$3,$5));
+			$$ = dispatch2(assign, $1, dispatch2(rescue_mod, $3, $5));
 		    %*/
 		    }
 		| var_lhs tOP_ASGN arg
@@ -1839,6 +1839,37 @@
 			$$ = dispatch3(opassign, $1, $2, $3);
 		    %*/
 		    }
+		| var_lhs tOP_ASGN arg modifier_rescue arg
+		    {
+		    /*%%%*/
+			value_expr($3);
+		        $3 = NEW_RESCUE($3, NEW_RESBODY(0,$5,0), 0);
+			if ($1) {
+			    ID vid = $1->nd_vid;
+			    if ($2 == tOROP) {
+				$1->nd_value = $3;
+				$$ = NEW_OP_ASGN_OR(gettable(vid), $1);
+				if (is_asgn_or_id(vid)) {
+				    $$->nd_aid = vid;
+				}
+			    }
+			    else if ($2 == tANDOP) {
+				$1->nd_value = $3;
+				$$ = NEW_OP_ASGN_AND(gettable(vid), $1);
+			    }
+			    else {
+				$$ = $1;
+				$$->nd_value = NEW_CALL(gettable(vid), $2, NEW_LIST($3));
+			    }
+			}
+			else {
+			    $$ = NEW_BEGIN(0);
+			}
+		    /*%
+			$3 = dispatch2(rescue_mod, $3, $5);
+			$$ = dispatch3(opassign, $1, $2, $3);
+		    %*/
+		    }
 		| primary_value '[' opt_call_args rbracket tOP_ASGN arg
 		    {
 		    /*%%%*/
@@ -2927,7 +2958,7 @@
 		    /*%%%*/
 			NODE *body = remove_begin($5);
 			reduce_nodes(&body);
-			$$ = NEW_DEFN(cur_mid, $4, body, NOEX_PRIVATE);
+			$$ = NEW_DEFN($2, $4, body, NOEX_PRIVATE);
 			fixpos($$, $4);
 			if (in_def_named_args > 0
 			    && in_def_named_args != 
@@ -4740,11 +4771,8 @@
 	VALUE hash = rb_const_get_at(rb_cObject, rb_intern("SCRIPT_LINES__"));
 	if (TYPE(hash) == T_HASH) {
 	    VALUE fname = rb_str_new2(f);
-	    VALUE lines = rb_hash_lookup(hash, fname);
-	    if (NIL_P(lines)) {
-		lines = rb_ary_new();
-		rb_hash_aset(hash, fname, lines);
-	    }
+	    VALUE lines = rb_ary_new();
+	    rb_hash_aset(hash, fname, lines);
 	    return lines;
 	}
     }
@@ -4801,7 +4829,7 @@
 static NODE*
 yycompile(struct parser_params *parser, const char *f, int line)
 {
-    ruby_sourcefile = rb_source_filename(f);
+    ruby_sourcefile = ruby_strdup(f);
     ruby_sourceline = line - 1;
     return (NODE *)ruby_suppress_tracing(yycompile0, (VALUE)parser, Qtrue);
 }
@@ -5036,7 +5064,7 @@
 #ifdef RIPPER
 	    ripper_flush(parser);
 #endif
-	    lex_lastline =v;
+	    lex_lastline = v;
 	}
     }
     c = (unsigned char)*lex_p++;
@@ -5386,7 +5414,7 @@
 	return -1;
 
       default:
-	    tokadd('\\');
+        tokadd('\\');
 	tokadd(c);
     }
     return 0;
@@ -5426,6 +5454,7 @@
 static void
 dispose_string(VALUE str)
 {
+    /* TODO: should use another API? */
 #if !WITH_OBJC
     if (RBASIC(str)->flags & RSTRING_NOEMBED)
 	xfree(RSTRING_PTR(str));
@@ -6764,7 +6793,7 @@
 		if (c == 'o' || c == 'O') {
 		    /* prefixed octal */
 		    c = nextc();
-		    if (c == '_') {
+		    if (c == '_' || !ISDIGIT(c)) {
 			yyerror("numeric literal without digits");
 		    }
 		}
@@ -6877,7 +6906,7 @@
 	    if (is_float) {
 		double d = strtod(tok(), 0);
 		if (errno == ERANGE) {
-		    rb_warnS("Float %s out of range", tok());
+		    rb_warningS("Float %s out of range", tok());
 		    errno = 0;
 		}
                 set_yylval_literal(DOUBLE2NUM(d));
@@ -7299,11 +7328,17 @@
 	if (tokadd_mbchar(c) == -1) return 0;
 	c = nextc();
     } while (parser_is_identchar());
-    if ((c == '!' || c == '?') && !peek('=')) {
-	tokadd(c);
-    }
-    else {
+    switch (tok()[0]) {
+      case '@': case '$':
 	pushback(c);
+	break;
+      default:
+	if ((c == '!' || c == '?') && !peek('=')) {
+	    tokadd(c);
+	}
+	else {
+	    pushback(c);
+	}
     }
     tokfix();
 
@@ -7457,7 +7492,6 @@
 {
     NODE *n = (rb_node_newnode)(type, a0, a1, a2);
     nd_set_line(n, ruby_sourceline);
-    n->nd_file = ruby_sourcefile;
     return n;
 }
 
@@ -7489,21 +7523,22 @@
     if (!node) return;
     if (!orig) return;
     if (orig == (NODE*)1) return;
-    node->nd_file = orig->nd_file;
     nd_set_line(node, nd_line(orig));
 }
 
 static void
-parser_warning(NODE *node, const char *mesg)
+parser_warning(struct parser_params *parser, NODE *node, const char *mesg)
 {
-    rb_compile_warning(node->nd_file, nd_line(node), "%s", mesg);
+    rb_compile_warning(ruby_sourcefile, nd_line(node), "%s", mesg);
 }
+#define parser_warning(node, mesg) parser_warning(parser, node, mesg)
 
 static void
-parser_warn(NODE *node, const char *mesg)
+parser_warn(struct parser_params *parser, NODE *node, const char *mesg)
 {
-    rb_compile_warn(node->nd_file, nd_line(node), "%s", mesg);
+    rb_compile_warn(ruby_sourcefile, nd_line(node), "%s", mesg);
 }
+#define parser_warn(node, mesg) parser_warn(parser, node, mesg)
 
 static NODE*
 block_append_gen(struct parser_params *parser, NODE *head, NODE *tail)
@@ -7603,7 +7638,7 @@
     return head;
 }
 
-static void
+static int
 literal_concat0(struct parser_params *parser, VALUE head, VALUE tail)
 {
 #if !WITH_OBJC
@@ -7611,10 +7646,14 @@
 	compile_error(PARSER_ARG "string literal encodings differ (%s / %s)",
 		      rb_enc_name(rb_enc_get(head)),
 		      rb_enc_name(rb_enc_get(tail)));
+	rb_str_resize(head, 0);
+	rb_str_resize(tail, 0);
+	return 0;
     }
 #endif
     RSTRING_SYNC(head);
     rb_str_buf_append(head, tail);
+    return 1;
 }
 
 /* concat two string literals */
@@ -7634,7 +7673,12 @@
     switch (nd_type(tail)) {
       case NODE_STR:
 	if (htype == NODE_STR) {
-	    literal_concat0(parser, head->nd_lit, tail->nd_lit);
+	    if (!literal_concat0(parser, head->nd_lit, tail->nd_lit)) {
+	      error:
+		rb_gc_force_recycle((VALUE)head);
+		rb_gc_force_recycle((VALUE)tail);
+		return 0;
+	    }
 	    rb_gc_force_recycle((VALUE)tail);
 	}
 	else {
@@ -7644,7 +7688,8 @@
 
       case NODE_DSTR:
 	if (htype == NODE_STR) {
-	    literal_concat0(parser, head->nd_lit, tail->nd_lit);
+	    if (!literal_concat0(parser, head->nd_lit, tail->nd_lit))
+		goto error;
 	    tail->nd_lit = head->nd_lit;
 	    rb_gc_force_recycle((VALUE)head);
 	    head = tail;
@@ -8278,23 +8323,23 @@
 }
 
 static int
-e_option_supplied(NODE *node)
+e_option_supplied(struct parser_params *parser)
 {
-    if (strcmp(node->nd_file, "-e") == 0)
+    if (strcmp(ruby_sourcefile, "-e") == 0)
 	return Qtrue;
     return Qfalse;
 }
 
 static void
-warn_unless_e_option(NODE *node, const char *str)
+warn_unless_e_option(struct parser_params *parser, NODE *node, const char *str)
 {
-    if (!e_option_supplied(node)) parser_warn(node, str);
+    if (!e_option_supplied(parser)) parser_warn(node, str);
 }
 
 static void
-warning_unless_e_option(NODE *node, const char *str)
+warning_unless_e_option(struct parser_params *parser, NODE *node, const char *str)
 {
-    if (!e_option_supplied(node)) parser_warning(node, str);
+    if (!e_option_supplied(parser)) parser_warning(node, str);
 }
 
 static NODE *cond0(struct parser_params*,NODE*);
@@ -8304,14 +8349,14 @@
 {
     enum node_type type;
 
-    if (!e_option_supplied(node)) return node;
+    if (!e_option_supplied(parser)) return node;
     if (node == 0) return 0;
 
     value_expr(node);
     node = cond0(parser, node);
     type = nd_type(node);
     if (type == NODE_LIT && FIXNUM_P(node->nd_lit)) {
-	warn_unless_e_option(node, "integer literal in conditional range");
+	warn_unless_e_option(parser, node, "integer literal in conditional range");
 	return NEW_CALL(node, tEQ, NEW_LIST(NEW_GVAR(rb_intern("$."))));
     }
     return node;
@@ -8353,7 +8398,7 @@
 
       case NODE_DREGX:
       case NODE_DREGX_ONCE:
-	warning_unless_e_option(node, "regex literal in condition");
+	warning_unless_e_option(parser, node, "regex literal in condition");
 	return NEW_MATCH2(node, NEW_GVAR(rb_intern("$_")));
 
       case NODE_AND:
@@ -8368,7 +8413,7 @@
 	node->nd_end = range_op(parser, node->nd_end);
 	if (nd_type(node) == NODE_DOT2) nd_set_type(node,NODE_FLIP2);
 	else if (nd_type(node) == NODE_DOT3) nd_set_type(node, NODE_FLIP3);
-	if (!e_option_supplied(node)) {
+	if (!e_option_supplied(parser)) {
 	    int b = literal_node(node->nd_beg);
 	    int e = literal_node(node->nd_end);
 	    if ((b == 1 && e == 1) || (b + e >= 2 && RTEST(ruby_verbose))) {
@@ -8383,7 +8428,7 @@
 
       case NODE_LIT:
 	if (TYPE(node->nd_lit) == T_REGEXP) {
-	    warn_unless_e_option(node, "regex literal in condition");
+	    warn_unless_e_option(parser, node, "regex literal in condition");
 	    nd_set_type(node, NODE_MATCH);
 	}
 	else {
@@ -9372,7 +9417,7 @@
 		VALUE str = global_symbols.op_sym[i];
 		if (!str) {
 		    str = rb_usascii_str_new2(op_tbl[i].name);
-		    // TODO OBJ_FREEZE(str);
+		    OBJ_FREEZE(str);
 		    GC_WB(&global_symbols.op_sym[i], str);
 		}
 		return str;
@@ -9389,9 +9434,8 @@
 #else
     if (st_lookup(global_symbols.id_str, id, &data)) {
         VALUE str = (VALUE)data;
-        if (RBASIC(str)->klass == 0 && rb_cString != 0) {
+        if (RBASIC(str)->klass == 0)
             RBASIC(str)->klass = rb_cString;
-	}
 	return str;
     }
 #endif
@@ -9560,8 +9604,6 @@
 #endif
 }
 
-extern void rb_mark_source_filename(char *);
-
 #ifdef RIPPER
 #define parser_mark ripper_parser_mark
 #define parser_free ripper_parser_free
@@ -9580,7 +9622,6 @@
     rb_gc_mark((VALUE)p->parser_eval_tree_begin) ;
     rb_gc_mark((VALUE)p->parser_eval_tree) ;
     rb_gc_mark(p->debug_lines);
-    rb_mark_source_filename(p->parser_ruby_sourcefile);
 #else
     rb_gc_mark(p->parser_ruby_sourcefile_string);
     rb_gc_mark(p->delayed);
@@ -9607,6 +9648,9 @@
 	prev = local->prev;
 	xfree(local);
     }
+#ifndef RIPPER
+    xfree(p->parser_ruby_sourcefile);
+#endif
     xfree(p);
 }
 
@@ -9988,14 +10032,12 @@
     rb_funcall(parser->value, rb_intern("warning"), 1, STR_NEW2(fmt));
 }
 
-#if 0				/* unused in ripper right now */
 static void
 ripper_warningS(struct parser_params *parser, const char *fmt, const char *str)
 {
     rb_funcall(parser->value, rb_intern("warning"), 2,
-    	       STR_NEW2(fmt), STR_NEW2(str));
+               STR_NEW2(fmt), STR_NEW2(str));
 }
-#endif
 
 static VALUE
 ripper_lex_get_generic(struct parser_params *parser, VALUE src)
@@ -10033,7 +10075,6 @@
 {
     struct parser_params *parser;
     VALUE src, fname, lineno;
-    VALUE fname2;
 
     Data_Get_Struct(self, struct parser_params, parser);
     rb_scan_args(argc, argv, "12", &src, &fname, &lineno);
@@ -10047,17 +10088,15 @@
     parser->parser_lex_input = src;
     parser->eofp = Qfalse;
     if (NIL_P(fname)) {
-        fname2 = STR_NEW2(" (ripper)");
+        fname = STR_NEW2("(ripper)");
     }
     else {
         StringValue(fname);
-        fname2 = rb_usascii_str_new2(" ");
-        rb_str_append(fname2, fname);
     }
     parser_initialize(parser);
 
-    parser->parser_ruby_sourcefile_string = fname2;
-    parser->parser_ruby_sourcefile = RSTRING_CPTR(fname2)+1;
+    parser->parser_ruby_sourcefile_string = fname;
+    parser->parser_ruby_sourcefile = RSTRING_PTR(fname);
     parser->parser_ruby_sourceline = NIL_P(lineno) ? 0 : NUM2INT(lineno) - 1;
 
     return Qnil;

Modified: MacRuby/trunk/prelude.rb
===================================================================
--- MacRuby/trunk/prelude.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/prelude.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -23,3 +23,13 @@
   end
 end
 
+def require_relative(relative_feature)
+  c = caller.first
+  e = c.rindex(/:\d+:in /)
+  file = $`
+  if /\A\((.*)\)/ =~ file # eval, etc.
+    raise LoadError, "require_relative is called in #{$1}"
+  end
+  absolute_feature = File.expand_path(File.join(File.dirname(file), relative_feature))
+  require absolute_feature
+end

Modified: MacRuby/trunk/proc.c
===================================================================
--- MacRuby/trunk/proc.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/proc.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   proc.c - Proc, Binding, Env
 
-  $Author: mame $
+  $Author: matz $
   created at: Wed Jan 17 12:13:14 2007
 
   Copyright (C) 2004-2007 Koichi Sasada
@@ -95,6 +95,7 @@
     dst->envval = src->envval;
     dst->safe_level = dst->safe_level;
     dst->special_cref_stack = src->special_cref_stack;
+    dst->is_lambda = src->is_lambda;
 
     return procval;
 }
@@ -921,7 +922,7 @@
 
 /*
  *  call-seq:
- *     meth.name    => string
+ *     meth.name    => symbol
  *  
  *  Returns the name of the method.
  */
@@ -932,7 +933,7 @@
     struct METHOD *data;
 
     Data_Get_Struct(obj, struct METHOD, data);
-    return rb_str_dup(rb_id2str(data->id));
+    return ID2SYM(data->id);
 }
 
 /*
@@ -1603,7 +1604,6 @@
  *     
  *     b = fred(99)
  *     eval("param", b.binding)   #=> 99
- *     eval("param", b)           #=> 99
  */
 static VALUE
 proc_binding(VALUE self)
@@ -1615,7 +1615,7 @@
     GetProcPtr(self, proc);
     GetBindingPtr(bindval, bind);
 
-    if (TYPE(proc->block.iseq) == T_NODE) {
+    if (BUILTIN_TYPE(proc->block.iseq) == T_NODE) {
 	rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
     }
 

Modified: MacRuby/trunk/process.c
===================================================================
--- MacRuby/trunk/process.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/process.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   process.c -
 
-  $Author: akr $
+  $Author: usa $
   created at: Tue Aug 10 14:30:50 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -13,6 +13,8 @@
 
 #include "ruby/ruby.h"
 #include "ruby/signal.h"
+#include "ruby/io.h"
+#include "ruby/util.h"
 #include "vm_core.h"
 
 #include <stdio.h>
@@ -49,12 +51,20 @@
 #ifdef HAVE_SYS_RESOURCE_H
 # include <sys/resource.h>
 #endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
 #include "ruby/st.h"
 
 #ifdef __EMX__
 #undef HAVE_GETPGRP
 #endif
 
+#include <sys/stat.h>
+
 #ifdef HAVE_SYS_TIMES_H
 #include <sys/times.h>
 #endif
@@ -64,7 +74,7 @@
 #endif
 
 #if defined(HAVE_TIMES) || defined(_WIN32)
-static VALUE S_Tms;
+static VALUE rb_cProcessTms;
 #endif
 
 #ifndef WIFEXITED
@@ -116,6 +126,17 @@
 #endif
 #endif
 
+#if SIZEOF_RLIM_T == SIZEOF_INT
+# define RLIM2NUM(v) UINT2NUM(v)
+# define NUM2RLIM(v) NUM2UINT(v)
+#elif SIZEOF_RLIM_T == SIZEOF_LONG
+# define RLIM2NUM(v) ULONG2NUM(v)
+# define NUM2RLIM(v) NUM2ULONG(v)
+#elif SIZEOF_RLIM_T == SIZEOF_LONG_LONG
+# define RLIM2NUM(v) ULL2NUM(v)
+# define NUM2RLIM(v) NUM2ULL(v)
+#endif
+
 #define preserving_errno(stmts) \
 	do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
 
@@ -196,7 +217,7 @@
  *  _stat_, we're referring to this 16 bit value.
  */
 
-static VALUE rb_cProcStatus;
+static VALUE rb_cProcessStatus;
 
 VALUE
 rb_last_status_get(void)
@@ -208,7 +229,7 @@
 rb_last_status_set(int status, rb_pid_t pid)
 {
     rb_vm_t *vm = GET_VM();
-    vm->last_status = rb_obj_alloc(rb_cProcStatus);
+    vm->last_status = rb_obj_alloc(rb_cProcessStatus);
     rb_iv_set(vm->last_status, "status", INT2FIX(status));
     rb_iv_set(vm->last_status, "pid", PIDT2NUM(pid));
 }
@@ -740,11 +761,11 @@
  *     $?.exitstatus                    #=> 99
  *
  *     pid = fork { sleep 3 }           #=> 27440
- *     Time.now                         #=> Wed Apr 09 08:57:09 CDT 2003
+ *     Time.now                         #=> 2008-03-08 19:56:16 +0900
  *     waitpid(pid, Process::WNOHANG)   #=> nil
- *     Time.now                         #=> Wed Apr 09 08:57:09 CDT 2003
+ *     Time.now                         #=> 2008-03-08 19:56:16 +0900
  *     waitpid(pid, 0)                  #=> 27440
- *     Time.now                         #=> Wed Apr 09 08:57:12 CDT 2003
+ *     Time.now                         #=> 2008-03-08 19:56:19 +0900
  */
 
 static VALUE
@@ -756,11 +777,11 @@
 
     rb_secure(2);
     flags = 0;
-    rb_scan_args(argc, argv, "02", &vpid, &vflags);
     if (argc == 0) {
 	pid = -1;
     }
     else {
+	rb_scan_args(argc, argv, "02", &vpid, &vflags);
 	pid = NUM2PIDT(vpid);
 	if (argc == 2 && !NIL_P(vflags)) {
 	    flags = NUM2UINT(vflags);
@@ -948,7 +969,7 @@
 #define after_exec() \
   (rb_thread_start_timer_thread(), rb_disable_interrupt())
 
-extern char *dln_find_exe(const char *fname, const char *path);
+#include "dln.h"
 
 static void
 security(const char *str)
@@ -963,9 +984,11 @@
 static int
 proc_exec_v(char **argv, const char *prog)
 {
+    char fbuf[MAXPATHLEN];
+
     if (!prog)
 	prog = argv[0];
-    prog = dln_find_exe(prog, 0);
+    prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
     if (!prog) {
 	errno = ENOENT;
 	return -1;
@@ -1000,7 +1023,7 @@
 		    *p = '\\';
 	    new_argv[0] = COMMAND;
 	    argv = new_argv;
-	    prog = dln_find_exe(argv[0], 0);
+	    prog = dln_find_exe_r(argv[0], 0, fbuf, sizeof(fbuf));
 	    if (!prog) {
 		errno = ENOENT;
 		return -1;
@@ -1034,9 +1057,11 @@
 int
 rb_proc_exec(const char *str)
 {
+#ifndef _WIN32
     const char *s = str;
     char *ss, *t;
     char **argv, **a;
+#endif
 
     while (*str && ISSPACE(*str))
 	str++;
@@ -1064,7 +1089,8 @@
 	    if (status != -1)
 		exit(status);
 #elif defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__)
-	    char *shell = dln_find_exe("sh", 0);
+	    char fbuf[MAXPATHLEN];
+	    char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
 	    int status = -1;
 	    before_exec();
 	    if (shell)
@@ -1111,13 +1137,14 @@
 static rb_pid_t
 proc_spawn_v(char **argv, char *prog)
 {
+    char fbuf[MAXPATHLEN];
     char *extension;
     rb_pid_t status;
 
     if (!prog)
 	prog = argv[0];
     security(prog);
-    prog = dln_find_exe(prog, 0);
+    prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
     if (!prog)
 	return -1;
 
@@ -1138,7 +1165,7 @@
 		*p = '\\';
 	new_argv[0] = COMMAND;
 	argv = new_argv;
-	prog = dln_find_exe(argv[0], 0);
+	prog = dln_find_exe_r(argv[0], 0, fbuf, sizeof(fbuf));
 	if (!prog) {
 	    errno = ENOENT;
 	    return -1;
@@ -1175,13 +1202,14 @@
 static rb_pid_t
 proc_spawn(char *str)
 {
+    char fbuf[MAXPATHLEN];
     char *s, *t;
     char **argv, **a;
     rb_pid_t status;
 
     for (s = str; *s; s++) {
 	if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
-	    char *shell = dln_find_exe("sh", 0);
+	    char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
 	    before_exec();
 	    status = shell?spawnl(P_WAIT,shell,"sh","-c",str,(char*)NULL):system(str);
 	    rb_last_status_set(status == -1 ? 127 : status, 0);
@@ -1202,7 +1230,347 @@
 #endif
 #endif
 
-VALUE
+static VALUE
+hide_obj(VALUE obj)
+{
+#if !WITH_OBJC
+    RBASIC(obj)->klass = 0;
+#endif
+    return obj;
+}
+
+enum {
+    EXEC_OPTION_PGROUP,
+    EXEC_OPTION_RLIMIT,
+    EXEC_OPTION_UNSETENV_OTHERS,
+    EXEC_OPTION_ENV,
+    EXEC_OPTION_CHDIR,
+    EXEC_OPTION_UMASK,
+    EXEC_OPTION_DUP2,
+    EXEC_OPTION_CLOSE,
+    EXEC_OPTION_OPEN,
+    EXEC_OPTION_CLOSE_OTHERS,
+};
+
+static VALUE
+check_exec_redirect_fd(VALUE v)
+{
+    VALUE tmp;
+    int fd;
+    if (FIXNUM_P(v)) {
+        fd = FIX2INT(v);
+    }
+    else if (!NIL_P(tmp = rb_check_convert_type(v, T_FILE, "IO", "to_io"))) {
+        rb_io_t *fptr;
+        GetOpenFile(tmp, fptr);
+        if (fptr->tied_io_for_writing)
+            rb_raise(rb_eArgError, "duplex IO redirection");
+        fd = fptr->fd;
+    }
+    else {
+        rb_raise(rb_eArgError, "wrong exec redirect");
+    }
+    if (fd < 0) {
+        rb_raise(rb_eArgError, "negative file descriptor");
+    }
+    return INT2FIX(fd);
+}
+
+static void
+check_exec_redirect(VALUE key, VALUE val, VALUE options)
+{
+    int index;
+    VALUE ary, param;
+    VALUE path, flags, perm;
+    ID id;
+
+    switch (TYPE(val)) {
+      case T_SYMBOL:
+        id = SYM2ID(val);
+        if (id == rb_intern("close")) {
+            index = EXEC_OPTION_CLOSE;
+            param = Qnil;
+        }
+        else {
+            rb_raise(rb_eArgError, "wrong exec redirect symbol: %s",
+                                   rb_id2name(id));
+        }
+        break;
+
+      case T_FILE:
+        val = check_exec_redirect_fd(val);
+        /* fall through */
+      case T_FIXNUM:
+        index = EXEC_OPTION_DUP2;
+        param = val;
+        break;
+
+      case T_ARRAY:
+        index = EXEC_OPTION_OPEN;
+        path = rb_ary_entry(val, 0);
+        FilePathValue(path);
+        flags = rb_ary_entry(val, 1);
+        if (NIL_P(flags))
+            flags = INT2NUM(O_RDONLY);
+        else if (TYPE(flags) == T_STRING)
+            flags = INT2NUM(rb_io_mode_modenum(StringValueCStr(flags)));
+        else
+            flags = rb_to_int(flags);
+        perm = rb_ary_entry(val, 2);
+        perm = NIL_P(perm) ? INT2FIX(0644) : rb_to_int(perm);
+        param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
+                                        flags, perm));
+        break;
+
+      case T_STRING:
+        index = EXEC_OPTION_OPEN;
+        path = val;
+        FilePathValue(path);
+        if ((FIXNUM_P(key) && (FIX2INT(key) == 1 || FIX2INT(key) == 2)) ||
+            key == rb_stdout || key == rb_stderr)
+            flags = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
+        else
+            flags = INT2NUM(O_RDONLY);
+        perm = INT2FIX(0644);
+        param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
+                                        flags, perm));
+        break;
+
+      default:
+        rb_raise(rb_eArgError, "wrong exec redirect action");
+    }
+
+    ary = rb_ary_entry(options, index);
+    if (NIL_P(ary)) {
+        ary = hide_obj(rb_ary_new());
+        rb_ary_store(options, index, ary);
+    }
+    if (TYPE(key) != T_ARRAY) {
+        VALUE fd = check_exec_redirect_fd(key);
+        rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
+    }
+    else {
+        int i, n=0;
+        for (i = 0 ; i < RARRAY_LEN(key); i++) {
+            VALUE v = RARRAY_AT(key, i);
+            VALUE fd = check_exec_redirect_fd(v);
+            rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
+            n++;
+        }
+    }
+}
+
+#ifdef RLIM2NUM
+static int rlimit_type_by_lname(const char *name);
+#endif
+
+int
+rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val)
+{
+    VALUE options = e->options;
+    ID id;
+#ifdef RLIM2NUM
+    int rtype;
+#endif
+
+    rb_secure(2);
+
+    switch (TYPE(key)) {
+      case T_SYMBOL:
+        id = SYM2ID(key);
+#ifdef HAVE_SETPGID
+        if (id == rb_intern("pgroup")) {
+            if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_PGROUP))) {
+                rb_raise(rb_eArgError, "pgroup option specified twice");
+            }
+            if (!RTEST(val))
+                val = Qfalse;
+            else if (val == Qtrue)
+                val = INT2FIX(0);
+            else {
+                pid_t pgroup = NUM2PIDT(val);
+                if (pgroup < 0) {
+                    rb_raise(rb_eArgError, "negative process group ID : %ld", (long)pgroup);
+                }
+                val = PIDT2NUM(pgroup);
+            }
+            rb_ary_store(options, EXEC_OPTION_PGROUP, val);
+        }
+        else
+#endif
+#ifdef RLIM2NUM
+        if (strncmp("rlimit_", rb_id2name(id), 7) == 0 &&
+            (rtype = rlimit_type_by_lname(rb_id2name(id)+7)) != -1) {
+            VALUE ary = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
+            VALUE tmp, softlim, hardlim;
+            if (NIL_P(ary)) {
+                ary = hide_obj(rb_ary_new());
+                rb_ary_store(options, EXEC_OPTION_RLIMIT, ary);
+            }
+            tmp = rb_check_array_type(val);
+            if (!NIL_P(tmp)) {
+                if (RARRAY_LEN(tmp) == 1)
+                    softlim = hardlim = rb_to_int(rb_ary_entry(tmp, 0));
+                else if (RARRAY_LEN(tmp) == 2) {
+                    softlim = rb_to_int(rb_ary_entry(tmp, 0));
+                    hardlim = rb_to_int(rb_ary_entry(tmp, 1));
+                }
+                else {
+                    rb_raise(rb_eArgError, "wrong exec rlimit option");
+                }
+            }
+            else {
+                softlim = hardlim = rb_to_int(val);
+            }
+            tmp = hide_obj(rb_ary_new3(3, INT2NUM(rtype), softlim, hardlim));
+            rb_ary_push(ary, tmp);
+        }
+        else
+#endif
+        if (id == rb_intern("unsetenv_others")) {
+            if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_UNSETENV_OTHERS))) {
+                rb_raise(rb_eArgError, "unsetenv_others option specified twice");
+            }
+            val = RTEST(val) ? Qtrue : Qfalse;
+            rb_ary_store(options, EXEC_OPTION_UNSETENV_OTHERS, val);
+        }
+        else if (id == rb_intern("chdir")) {
+            if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_CHDIR))) {
+                rb_raise(rb_eArgError, "chdir option specified twice");
+            }
+            FilePathValue(val);
+            rb_ary_store(options, EXEC_OPTION_CHDIR,
+                                  hide_obj(rb_str_dup(val)));
+        }
+        else if (id == rb_intern("umask")) {
+            mode_t cmask = NUM2LONG(val);
+            if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_UMASK))) {
+                rb_raise(rb_eArgError, "umask option specified twice");
+            }
+            rb_ary_store(options, EXEC_OPTION_UMASK, LONG2NUM(cmask));
+        }
+        else if (id == rb_intern("close_others")) {
+            if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS))) {
+                rb_raise(rb_eArgError, "close_others option specified twice");
+            }
+            val = RTEST(val) ? Qtrue : Qfalse;
+            rb_ary_store(options, EXEC_OPTION_CLOSE_OTHERS, val);
+        }
+        else if (id == rb_intern("in")) {
+            key = INT2FIX(0);
+            goto redirect;
+        }
+        else if (id == rb_intern("out")) {
+            key = INT2FIX(1);
+            goto redirect;
+        }
+        else if (id == rb_intern("err")) {
+            key = INT2FIX(2);
+            goto redirect;
+        }
+        else {
+            rb_raise(rb_eArgError, "wrong exec option symbol: %s",
+                                   rb_id2name(id));
+        }
+        break;
+
+      case T_FIXNUM:
+      case T_FILE:
+      case T_ARRAY:
+redirect:
+        check_exec_redirect(key, val, options);
+        break;
+
+      default:
+        rb_raise(rb_eArgError, "wrong exec option");
+    }
+
+    return ST_CONTINUE;
+}
+
+static int
+check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
+{
+    VALUE key = (VALUE)st_key;
+    VALUE val = (VALUE)st_val;
+    struct rb_exec_arg *e = (struct rb_exec_arg *)arg;
+    return rb_exec_arg_addopt(e, key, val);
+}
+
+static VALUE
+check_exec_fds(VALUE options)
+{
+    VALUE h = rb_hash_new();
+    VALUE ary;
+    int index, i;
+    int maxhint = -1;
+
+    for (index = EXEC_OPTION_DUP2; index <= EXEC_OPTION_OPEN; index++) {
+        ary = rb_ary_entry(options, index);
+        if (NIL_P(ary))
+            continue;
+        for (i = 0; i < RARRAY_LEN(ary); i++) {
+            VALUE elt = RARRAY_AT(ary, i);
+            int fd = FIX2INT(RARRAY_AT(elt, 0));
+            if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
+                rb_raise(rb_eArgError, "fd %d specified twice", fd);
+            }
+            rb_hash_aset(h, INT2FIX(fd), Qtrue);
+            if (maxhint < fd)
+                maxhint = fd;
+            if (index == EXEC_OPTION_DUP2) {
+                fd = FIX2INT(RARRAY_AT(elt, 1));
+                if (maxhint < fd)
+                    maxhint = fd;
+            }
+        }
+    }
+    if (rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS) != Qfalse) {
+        rb_ary_store(options, EXEC_OPTION_CLOSE_OTHERS, INT2FIX(maxhint));
+    }
+    return h;
+}
+
+static void
+rb_check_exec_options(VALUE opthash, struct rb_exec_arg *e)
+{
+    if (RHASH_EMPTY_P(opthash))
+        return;
+    rb_hash_foreach(opthash, check_exec_options_i, (VALUE)e);
+}
+
+static int
+check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
+{
+    VALUE key = (VALUE)st_key;
+    VALUE val = (VALUE)st_val;
+    VALUE env = (VALUE)arg;
+    char *k;
+
+    k = StringValueCStr(key);
+    if (strchr(k, '='))
+        rb_raise(rb_eArgError, "environment name contains a equal : %s", k);
+
+    if (!NIL_P(val))
+        StringValueCStr(val);
+
+    rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
+
+    return ST_CONTINUE;
+}
+
+static VALUE
+rb_check_exec_env(VALUE hash)
+{
+    VALUE env;
+
+    env = hide_obj(rb_ary_new());
+    rb_hash_foreach(hash, check_exec_env_i, env);
+
+    return env;
+}
+
+static VALUE
 rb_check_argv(int argc, VALUE *argv)
 {
     VALUE tmp, prog;
@@ -1235,16 +1603,85 @@
     return prog;
 }
 
+static VALUE
+rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret, struct rb_exec_arg *e)
+{
+    VALUE hash, prog;
+
+    if (0 < *argc_p) {
+        hash = rb_check_convert_type((*argv_p)[*argc_p-1], T_HASH, "Hash", "to_hash");
+        if (!NIL_P(hash)) {
+            *opthash_ret = hash;
+            (*argc_p)--;
+        }
+    }
+
+    if (0 < *argc_p) {
+        hash = rb_check_convert_type((*argv_p)[0], T_HASH, "Hash", "to_hash");
+        if (!NIL_P(hash)) {
+            *env_ret = hash;
+            (*argc_p)--;
+            (*argv_p)++;
+        }
+    }
+    prog = rb_check_argv(*argc_p, *argv_p);
+    if (!prog) {
+        prog = (*argv_p)[0];
+        if (accept_shell && *argc_p == 1) {
+            *argc_p = 0;
+            *argv_p = 0;
+        }
+    }
+    return prog;
+}
+
+static void
+rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, struct rb_exec_arg *e)
+{
+    VALUE options;
+    MEMZERO(e, struct rb_exec_arg, 1);
+    options = hide_obj(rb_ary_new());
+    e->options = options;
+
+    if (!NIL_P(opthash)) {
+        rb_check_exec_options(opthash, e);
+    }
+    if (!NIL_P(env)) {
+        env = rb_check_exec_env(env);
+        rb_ary_store(options, EXEC_OPTION_ENV, env);
+    }
+
+    e->argc = argc;
+    e->argv = argv;
+    e->prog = prog ? RSTRING_CPTR(prog) : 0;
+}
+
+VALUE
+rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e)
+{
+    VALUE prog;
+    VALUE env = Qnil, opthash = Qnil;
+    prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash, e);
+    rb_exec_fillarg(prog, argc, argv, env, opthash, e);
+    return prog;
+}
+
+void
+rb_exec_arg_fixup(struct rb_exec_arg *e)
+{
+    e->redirect_fds = check_exec_fds(e->options);
+}
+
 /*
  *  call-seq:
- *     exec(command [, arg, ...])
+ *     exec([env,] command [, arg, ...] [,options])
  *
  *  Replaces the current process by running the given external _command_.
- *  If +exec+ is given a single argument, that argument is
+ *  If optional arguments, sequence of +arg+, are not given, that argument is
  *  taken as a line that is subject to shell expansion before being
- *  executed. If multiple arguments are given, the second and subsequent
- *  arguments are passed as parameters to _command_ with no shell
- *  expansion. If the first argument is a two-element array, the first
+ *  executed. If one or more +arg+ given, they
+ *  are passed as parameters to _command_ with no shell
+ *  expansion. If +command+ is a two-element array, the first
  *  element is the command to be executed, and the second argument is
  *  used as the <code>argv[0]</code> value, which may show up in process
  *  listings. In MSDOS environments, the command is executed in a
@@ -1252,6 +1689,10 @@
  *  used, so the running command may inherit some of the environment of
  *  the original program (including open file descriptors).
  *
+ *  The hash arguments, env and options, are same as
+ *  <code>system</code> and <code>spawn</code>.
+ *  See <code>spawn</code> for details.
+ *
  *  Raises SystemCallError if the _command_ couldn't execute (typically
  *  <code>Errno::ENOENT</code> when it was not found).
  *
@@ -1266,32 +1707,476 @@
 VALUE
 rb_f_exec(int argc, VALUE *argv)
 {
-    struct rb_exec_arg e;
-    VALUE prog;
+    struct rb_exec_arg earg;
 
-    prog = rb_check_argv(argc, argv);
-    if (!prog && argc == 1) {
-	e.argc = 0;
-	e.argv = 0;
-	e.prog = RSTRING_CPTR(argv[0]);
+    rb_exec_arg_init(argc, argv, Qtrue, &earg);
+    if (NIL_P(rb_ary_entry(earg.options, EXEC_OPTION_CLOSE_OTHERS)))
+        rb_exec_arg_addopt(&earg, ID2SYM(rb_intern("close_others")), Qfalse);
+    rb_exec_arg_fixup(&earg);
+
+    rb_exec(&earg);
+    rb_sys_fail(earg.prog);
+    return Qnil;		/* dummy */
+}
+
+/*#define DEBUG_REDIRECT*/
+#if defined(DEBUG_REDIRECT)
+
+#include <stdarg.h>
+
+static void
+ttyprintf(const char *fmt, ...)
+{
+    va_list ap;
+    FILE *tty;
+    int save = errno;
+    tty = fopen("/dev/tty", "w");
+    if (!tty)
+        return;
+
+    va_start(ap, fmt);
+    vfprintf(tty, fmt, ap);
+    va_end(ap);
+    fclose(tty);
+    errno = save;
+}
+
+static int
+redirect_dup(int oldfd)
+{
+    int ret;
+    ret = dup(oldfd);
+    ttyprintf("dup(%d) => %d\n", oldfd, ret);
+    return ret;
+}
+
+static int
+redirect_dup2(int oldfd, int newfd)
+{
+    int ret;
+    ret = dup2(oldfd, newfd);
+    ttyprintf("dup2(%d, %d)\n", oldfd, newfd);
+    return ret;
+}
+
+static int
+redirect_close(int fd)
+{
+    int ret;
+    ret = close(fd);
+    ttyprintf("close(%d)\n", fd);
+    return ret;
+}
+
+static int
+redirect_open(const char *pathname, int flags, mode_t perm)
+{
+    int ret;
+    ret = open(pathname, flags, perm);
+    ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
+    return ret;
+}
+
+#else
+#define redirect_dup(oldfd) dup(oldfd)
+#define redirect_dup2(oldfd, newfd) dup2(oldfd, newfd)
+#define redirect_close(fd) close(fd)
+#define redirect_open(pathname, flags, perm) open(pathname, flags, perm)
+#endif
+
+static int
+save_redirect_fd(int fd, VALUE save)
+{
+    if (!NIL_P(save)) {
+        VALUE newary;
+        int save_fd = redirect_dup(fd);
+        if (save_fd == -1) return -1;
+        newary = rb_ary_entry(save, EXEC_OPTION_DUP2);
+        if (NIL_P(newary)) {
+            newary = hide_obj(rb_ary_new());
+            rb_ary_store(save, EXEC_OPTION_DUP2, newary);
+        }
+        rb_ary_push(newary,
+                    hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd))));
+
+        newary = rb_ary_entry(save, EXEC_OPTION_CLOSE);
+        if (NIL_P(newary)) {
+            newary = hide_obj(rb_ary_new());
+            rb_ary_store(save, EXEC_OPTION_CLOSE, newary);
+        }
+        rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
     }
-    else {
-	e.argc = argc;
-	e.argv = argv;
-	e.prog = prog ? RSTRING_CPTR(prog) : 0;
+
+    return 0;
+}
+
+static VALUE
+save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv)
+{
+    rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
+    return Qnil;
+}
+
+static void
+save_env(VALUE save)
+{
+    if (!NIL_P(save) && NIL_P(rb_ary_entry(save, EXEC_OPTION_ENV))) {
+        VALUE env = rb_const_get(rb_cObject, rb_intern("ENV"));
+        if (RTEST(env)) {
+            VALUE ary = hide_obj(rb_ary_new());
+            rb_block_call(env, rb_intern("each"), 0, 0, save_env_i,
+                          (VALUE)ary);
+            rb_ary_store(save, EXEC_OPTION_ENV, ary);
+        }
+        rb_ary_store(save, EXEC_OPTION_UNSETENV_OTHERS, Qtrue);
     }
-    rb_exec(&e);
-    rb_sys_fail(e.prog);
-    return Qnil;		/* dummy */
 }
 
+static int
+intcmp(const void *a, const void *b)
+{
+    return *(int*)a - *(int*)b;
+}
+
+static int
+run_exec_dup2(VALUE ary, VALUE save)
+{
+    int n, i;
+    int ret;
+    int extra_fd = -1;
+    struct fd_pair {
+        int oldfd;
+        int newfd;
+        int older_index;
+        int num_newer;
+    } *pairs = 0;
+
+    n = RARRAY_LEN(ary);
+    pairs = ALLOC_N(struct fd_pair, n);
+
+    /* initialize oldfd and newfd: O(n) */
+    for (i = 0; i < n; i++) {
+        VALUE elt = RARRAY_AT(ary, i);
+        pairs[i].oldfd = FIX2INT(RARRAY_AT(elt, 1));
+        pairs[i].newfd = FIX2INT(RARRAY_AT(elt, 0)); /* unique */
+        pairs[i].older_index = -1;
+    }
+
+    /* sort the table by oldfd: O(n log n) */
+    qsort(pairs, n, sizeof(struct fd_pair), intcmp);
+
+    /* initialize older_index and num_newer: O(n log n) */
+    for (i = 0; i < n; i++) {
+        int newfd = pairs[i].newfd;
+        struct fd_pair key, *found;
+        key.oldfd = newfd;
+        found = bsearch(&key, pairs, n, sizeof(struct fd_pair), intcmp);
+        pairs[i].num_newer = 0;
+        if (found) {
+            while (pairs < found && (found-1)->oldfd == newfd)
+                found--;
+            while (found < pairs+n && found->oldfd == newfd) {
+                pairs[i].num_newer++;
+                found->older_index = i;
+                found++;
+            }
+        }
+    }
+
+    /* non-cyclic redirection: O(n) */
+    for (i = 0; i < n; i++) {
+        int j = i;
+        while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
+            if (save_redirect_fd(pairs[j].newfd, save) < 0)
+                return -1;
+            ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
+            if (ret == -1)
+                goto fail;
+            pairs[j].oldfd = -1;
+            j = pairs[j].older_index;
+            if (j != -1)
+                pairs[j].num_newer--;
+        }
+    }
+
+    /* cyclic redirection: O(n) */
+    for (i = 0; i < n; i++) {
+        int j;
+        if (pairs[i].oldfd == -1)
+            continue;
+        if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
+#ifdef F_GETFD
+            int fd = pairs[i].oldfd;
+            ret = fcntl(fd, F_GETFD);
+            if (ret == -1)
+                goto fail;
+            if (ret & FD_CLOEXEC) {
+                ret &= ~FD_CLOEXEC;
+                ret = fcntl(fd, F_SETFD, ret);
+                if (ret == -1)
+                    goto fail;
+            }
+#endif
+            pairs[i].oldfd = -1;
+            continue;
+        }
+        if (extra_fd == -1) {
+            extra_fd = redirect_dup(pairs[i].oldfd);
+            if (extra_fd == -1)
+                goto fail;
+        }
+        else {
+            ret = redirect_dup2(pairs[i].oldfd, extra_fd);
+            if (ret == -1)
+                goto fail;
+        }
+        pairs[i].oldfd = extra_fd;
+        j = pairs[i].older_index;
+        pairs[i].older_index = -1;
+        while (j != -1) {
+            ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
+            if (ret == -1)
+                goto fail;
+            pairs[j].oldfd = -1;
+            j = pairs[j].older_index;
+        }
+    }
+    if (extra_fd != -1) {
+        ret = redirect_close(extra_fd);
+        if (ret == -1)
+            goto fail;
+    }
+
+    return 0;
+
+fail:
+    if (pairs)
+        xfree(pairs);
+    return -1;
+}
+
+static int
+run_exec_close(VALUE ary)
+{
+    int i, ret;
+
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+        VALUE elt = RARRAY_AT(ary, i);
+        int fd = FIX2INT(RARRAY_AT(elt, 0));
+        ret = redirect_close(fd);
+        if (ret == -1)
+            return -1;
+    }
+    return 0;
+}
+
+static int
+run_exec_open(VALUE ary, VALUE save)
+{
+    int i, ret;
+
+    for (i = 0; i < RARRAY_LEN(ary);) {
+        VALUE elt = RARRAY_AT(ary, i);;
+        int fd = FIX2INT(RARRAY_AT(elt, 0));
+        VALUE param = RARRAY_AT(elt, 1);
+        const char *path = RSTRING_CPTR(RARRAY_AT(param, 0));
+        int flags = NUM2INT(RARRAY_AT(param, 1));
+        int perm = NUM2INT(RARRAY_AT(param, 2));
+        int need_close = 1;
+        int fd2 = redirect_open(path, flags, perm);
+        if (fd2 == -1) return -1;
+        while (i < RARRAY_LEN(ary) &&
+               (elt = RARRAY_AT(ary, i), RARRAY_AT(elt, 1) == param)) {
+            fd = FIX2INT(RARRAY_AT(elt, 0));
+            if (fd == fd2) {
+                need_close = 0;
+            }
+            else {
+                if (save_redirect_fd(fd, save) < 0)
+                    return -1;
+                ret = redirect_dup2(fd2, fd);
+                if (ret == -1) return -1;
+            }
+            i++;
+        }
+        if (need_close) {
+            ret = redirect_close(fd2);
+            if (ret == -1) return -1;
+        }
+    }
+    return 0;
+}
+
+#ifdef HAVE_SETPGID
+static int
+run_exec_pgroup(VALUE obj, VALUE save)
+{
+    /*
+     * If FD_CLOEXEC is available, rb_fork waits the child's execve.
+     * So setpgid is done in the child when rb_fork is returned in the parent.
+     * No race condition, even without setpgid from the parent.
+     * (Is there an environment which has setpgid but FD_CLOEXEC?)
+     */
+    if (!NIL_P(save)) {
+        /* maybe meaningless with no fork environment... */
+        rb_ary_store(save, EXEC_OPTION_PGROUP, PIDT2NUM(getpgrp()));
+    }
+    pid_t pgroup = NUM2PIDT(obj);
+    if (pgroup == 0) {
+        pgroup = getpid();
+    }
+    return setpgid(getpid(), pgroup);
+}
+#endif
+
+#ifdef RLIM2NUM
+static int
+run_exec_rlimit(VALUE ary, VALUE save)
+{
+    int i;
+    for (i = 0; i < RARRAY_LEN(ary); i++) {
+        VALUE elt = RARRAY_AT(ary, i);
+        int rtype = NUM2INT(RARRAY_AT(elt, 0));
+        struct rlimit rlim;
+        if (!NIL_P(save)) {
+            if (getrlimit(rtype, &rlim) == -1)
+                return -1;
+            VALUE tmp = hide_obj(rb_ary_new3(3, RARRAY_AT(elt, 0),
+                                             RLIM2NUM(rlim.rlim_cur),
+                                             RLIM2NUM(rlim.rlim_max)));
+            VALUE newary = rb_ary_entry(save, EXEC_OPTION_RLIMIT);
+            if (NIL_P(newary)) {
+                newary = hide_obj(rb_ary_new());
+                rb_ary_store(save, EXEC_OPTION_RLIMIT, newary);
+            }
+            rb_ary_push(newary, tmp);
+        }
+        rlim.rlim_cur = NUM2RLIM(RARRAY_AT(elt, 1));
+        rlim.rlim_max = NUM2RLIM(RARRAY_AT(elt, 2));
+        if (setrlimit(rtype, &rlim) == -1)
+            return -1;
+    }
+    return 0;
+}
+#endif
+
 int
+rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
+{
+    VALUE options = e->options;
+    VALUE soptions = Qnil;
+    VALUE obj;
+
+    if (!RTEST(options))
+        return 0;
+
+    if (s) {
+        s->argc = 0;
+        s->argv = NULL;
+        s->prog = NULL;
+        s->options = soptions = hide_obj(rb_ary_new());
+        s->redirect_fds = Qnil;
+    }
+
+#ifdef HAVE_SETPGID
+    obj = rb_ary_entry(options, EXEC_OPTION_PGROUP);
+    if (RTEST(obj)) {
+        if (run_exec_pgroup(obj, soptions) == -1)
+            return -1;
+    }
+#endif
+
+#ifdef RLIM2NUM
+    obj = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
+    if (!NIL_P(obj)) {
+        if (run_exec_rlimit(obj, soptions) == -1)
+            return -1;
+    }
+#endif
+
+    obj = rb_ary_entry(options, EXEC_OPTION_UNSETENV_OTHERS);
+    if (RTEST(obj)) {
+        save_env(soptions);
+        rb_env_clear();
+    }
+
+    obj = rb_ary_entry(options, EXEC_OPTION_ENV);
+    if (!NIL_P(obj)) {
+        int i;
+        save_env(soptions);
+        for (i = 0; i < RARRAY_LEN(obj); i++) {
+            VALUE pair = RARRAY_AT(obj, i);
+            VALUE key = RARRAY_AT(pair, 0);
+            VALUE val = RARRAY_AT(pair, 1);
+            if (NIL_P(val))
+                ruby_setenv(StringValueCStr(key), 0);
+            else
+                ruby_setenv(StringValueCStr(key), StringValueCStr(val));
+        }
+    }
+
+    obj = rb_ary_entry(options, EXEC_OPTION_CHDIR);
+    if (!NIL_P(obj)) {
+        if (!NIL_P(soptions)) {
+            char *cwd = my_getcwd();
+            rb_ary_store(soptions, EXEC_OPTION_CHDIR,
+                         hide_obj(rb_str_new2(cwd)));
+        }
+        if (chdir(RSTRING_CPTR(obj)) == -1)
+            return -1;
+    }
+
+    obj = rb_ary_entry(options, EXEC_OPTION_UMASK);
+    if (!NIL_P(obj)) {
+        mode_t mask = NUM2LONG(obj);
+        mode_t oldmask = umask(mask); /* never fail */
+        if (!NIL_P(soptions))
+            rb_ary_store(soptions, EXEC_OPTION_UMASK, LONG2NUM(oldmask));
+    }
+
+    obj = rb_ary_entry(options, EXEC_OPTION_DUP2);
+    if (!NIL_P(obj)) {
+        if (run_exec_dup2(obj, soptions) == -1)
+            return -1;
+    }
+
+    obj = rb_ary_entry(options, EXEC_OPTION_CLOSE);
+    if (!NIL_P(obj)) {
+        if (!NIL_P(soptions))
+            rb_warn("cannot close fd before spawn");
+        else {
+            if (run_exec_close(obj) == -1)
+                return -1;
+        }
+    }
+
+#ifdef HAVE_FORK
+    obj = rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS);
+    if (obj != Qfalse) {
+        rb_close_before_exec(3, FIX2LONG(obj), e->redirect_fds);
+    }
+#endif
+
+    obj = rb_ary_entry(options, EXEC_OPTION_OPEN);
+    if (!NIL_P(obj)) {
+        if (run_exec_open(obj, soptions) == -1)
+            return -1;
+    }
+
+    return 0;
+}
+
+int
 rb_exec(const struct rb_exec_arg *e)
 {
     int argc = e->argc;
     VALUE *argv = e->argv;
     const char *prog = e->prog;
 
+    if (rb_run_exec_options(e, NULL) < 0) {
+        return -1;
+    }
+
     if (argc == 0) {
 	rb_proc_exec(prog);
     }
@@ -1307,12 +2192,14 @@
     return -1;
 }
 
+#ifdef HAVE_FORK
 static int
 rb_exec_atfork(void* arg)
 {
-    rb_thread_atfork();
+    rb_thread_atfork_before_exec();
     return rb_exec(arg);
 }
+#endif
 
 #ifdef HAVE_FORK
 #ifdef FD_CLOEXEC
@@ -1328,6 +2215,47 @@
 #endif
 #endif
 
+static int
+move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
+{
+    long min = 0;
+    int i;
+    for (i = 0; i < n; i++) {
+        int ret;
+        while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
+            if (min <= fdp[i])
+                min = fdp[i]+1;
+            while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
+                min++;
+            ret = fcntl(fdp[i], F_DUPFD, min);
+            if (ret == -1)
+                return -1;
+            close(fdp[i]);
+            fdp[i] = ret;
+        }
+    }
+    return 0;
+}
+
+static int
+pipe_nocrash(int filedes[2], VALUE fds)
+{
+    int ret;
+    ret = pipe(filedes);
+    if (ret == -1)
+        return -1;
+    if (RTEST(fds)) {
+        int save = errno;
+        if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
+            close(filedes[0]);
+            close(filedes[1]);
+            return -1;
+        }
+        errno = save;
+    }
+    return ret;
+}
+
 /*
  * Forks child process, and returns the process ID in the parent
  * process.
@@ -1346,10 +2274,13 @@
  * returns -1 in the parent process.  On the other platforms, just
  * returns pid.
  *
+ * If fds is not Qnil, internal pipe for the errno propagation is
+ * arranged to avoid conflicts of the hash keys in +fds+.
+ *
  * +chfunc+ must not raise any exceptions.
  */
 rb_pid_t
-rb_fork(int *status, int (*chfunc)(void*), void *charg)
+rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
 {
     rb_pid_t pid;
     int err, state = 0;
@@ -1370,7 +2301,7 @@
 
 #ifdef FD_CLOEXEC
     if (chfunc) {
-	if (pipe(ep)) return -1;
+	if (pipe_nocrash(ep, fds)) return -1;
 	if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
 	    preserving_errno((close(ep[0]), close(ep[1])));
 	    return -1;
@@ -1473,7 +2404,7 @@
 
     rb_secure(2);
 
-    switch (pid = rb_fork(0, 0, 0)) {
+    switch (pid = rb_fork(0, 0, 0, Qnil)) {
       case 0:
 #ifdef linux
 	after_exec();
@@ -1518,7 +2449,7 @@
     int istatus;
 
     rb_secure(4);
-    if (rb_scan_args(argc, argv, "01", &status) == 1) {
+    if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
 	switch (status) {
 	  case Qtrue:
 	    istatus = EXIT_SUCCESS;
@@ -1599,7 +2530,7 @@
     int istatus;
 
     rb_secure(4);
-    if (rb_scan_args(argc, argv, "01", &status) == 1) {
+    if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
 	switch (status) {
 	  case Qtrue:
 	    istatus = EXIT_SUCCESS;
@@ -1673,12 +2604,12 @@
 {
     static int overriding;
 #ifdef SIGHUP
-    RETSIGTYPE (*hfunc)(int);
+    RETSIGTYPE (*hfunc)(int) = 0;
 #endif
 #ifdef SIGQUIT
-    RETSIGTYPE (*qfunc)(int);
+    RETSIGTYPE (*qfunc)(int) = 0;
 #endif
-    RETSIGTYPE (*ifunc)(int);
+    RETSIGTYPE (*ifunc)(int) = 0;
     int status;
     int i, hooked = Qfalse;
 
@@ -1710,51 +2641,65 @@
     }
 }
 
-rb_pid_t
-rb_spawn(int argc, VALUE *argv)
+static rb_pid_t
+rb_spawn_internal(int argc, VALUE *argv, int default_close_others)
 {
     rb_pid_t status;
     VALUE prog;
+    struct rb_exec_arg earg;
+#if !defined HAVE_FORK
+    struct rb_exec_arg sarg;
+#endif
 
-    prog = rb_check_argv(argc, argv);
+    prog = rb_exec_arg_init(argc, argv, Qtrue, &earg);
+    if (NIL_P(rb_ary_entry(earg.options, EXEC_OPTION_CLOSE_OTHERS))) {
+        VALUE v = default_close_others ? Qtrue : Qfalse;
+        rb_exec_arg_addopt(&earg, ID2SYM(rb_intern("close_others")), v);
+    }
+    rb_exec_arg_fixup(&earg);
 
-    if (!prog && argc == 1) {
-	--argc;
-	prog = *argv++;
-    }
 #if defined HAVE_FORK
-    {
-	struct rb_exec_arg earg;
-	earg.argc = argc;
-	earg.argv = argv;
-	earg.prog = prog ? RSTRING_CPTR(prog) : 0;
-	status = rb_fork(&status, rb_exec_atfork, &earg);
-	if (prog && argc) argv[0] = prog;
+    status = rb_fork(&status, rb_exec_atfork, &earg, earg.redirect_fds);
+    if (prog && earg.argc) earg.argv[0] = prog;
+#else
+    if (rb_run_exec_options(&earg, &sarg) < 0) {
+        return -1;
     }
-#elif defined HAVE_SPAWNV
+
+    argc = earg.argc;
+    argv = earg.argv;
+    if (prog && argc) argv[0] = prog;
+# if defined HAVE_SPAWNV
     if (!argc) {
 	status = proc_spawn(RSTRING_CPTR(prog));
     }
     else {
 	status = proc_spawn_n(argc, argv, prog);
     }
-    if (prog && argc) argv[0] = prog;
-#else
-    if (prog && argc) argv[0] = prog;
+# else
     if (argc) prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
     status = system(StringValuePtr(prog));
-# if defined(__human68k__) || defined(__DJGPP__)
+#  if defined(__human68k__) || defined(__DJGPP__)
     rb_last_status_set(status == -1 ? 127 : status, 0);
-# else
+#  else
     rb_last_status_set((status & 0xff) << 8, 0);
+#  endif
 # endif
+
+    rb_run_exec_options(&sarg, NULL);
 #endif
     return status;
 }
 
+rb_pid_t
+rb_spawn(int argc, VALUE *argv)
+{
+    return rb_spawn_internal(argc, argv, Qtrue);
+}
+
 /*
  *  call-seq:
- *     system(cmd [, arg, ...])    => true or false
+ *     system([env,] cmd [, arg, ...] [,options])    => true, false or nil
  *
  *  Executes _cmd_ in a subshell, returning +true+ if the command
  *  gives zero exit status, +false+ for non zero exit status. Returns
@@ -1762,6 +2707,10 @@
  *  <code>$?</code>. The arguments are processed in the same way as
  *  for <code>Kernel::exec</code>.
  *
+ *  The hash arguments, env and options, are same as
+ *  <code>exec</code> and <code>spawn</code>.
+ *  See <code>spawn</code> for details.
+ *
  *     system("echo *")
  *     system("echo", "*")
  *
@@ -1785,7 +2734,7 @@
 
     chfunc = signal(SIGCHLD, SIG_DFL);
 #endif
-    status = rb_spawn(argc, argv);
+    status = rb_spawn_internal(argc, argv, Qfalse);
 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
     if (status > 0) {
 	rb_syswait(status);
@@ -1804,10 +2753,143 @@
 
 /*
  *  call-seq:
- *     spawn(cmd [, arg, ...])     => pid
+ *     spawn([env,] cmd [, arg, ...] [,options])     => pid
  *
  *  Similar to <code>Kernel::system</code> except for not waiting for
  *  end of _cmd_, but returns its <i>pid</i>.
+ *
+ *  If a hash is given as +env+, the environment is
+ *  updated by +env+ before <code>exec(2)</code> in the child process.
+ *
+ *  If a hash is given as +options+,
+ *  it specifies
+ *  process group,
+ *  resource limit, 
+ *  current directory,
+ *  umask and
+ *  redirects for the child process.
+ *  Also, it can be specified to clear environment variables.
+ *
+ *  The <code>:unsetenv_others</code> key in +options+ specifies
+ *  to clear environment variables, other than specified by +env+.
+ *
+ *    pid = spawn(command, :unsetenv_others=>true) # no environment variable
+ *    pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
+ *
+ *  The <code>:pgroup</code> key in +options+ specifies a process group.
+ *  The corresponding value should be true, zero or positive integer.
+ *  true and zero means the process should be a process leader.
+ *  Other values specifies a process group to be belongs.
+ *
+ *    pid = spawn(command, :pgroup=>true) # process leader
+ *    pid = spawn(command, :pgroup=>10) # belongs to the process group 10
+ *
+ *  The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
+ *  <em>foo</em> should be one of resource types such as <code>core</code>
+ *  The corresponding value should be an integer or an array which have one or
+ *  two integers: same as cur_limit and max_limit arguments for
+ *  Process.setrlimit.
+ *
+ *    pid = spawn(command, :rlimit_core=>0) # never dump core.
+ *    cur, max = Process.getrlimit(:CORE)
+ *    pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
+ *    pid = spawn(command, :rlimit_core=>max) # enable core dump
+ *
+ *  The <code>:chdir</code> key in +options+ specifies the current directory.
+ *
+ *    pid = spawn(command, :chdir=>"/var/tmp")
+ *
+ *  The <code>:umask</code> key in +options+ specifies the umask.
+ *
+ *    pid = spawn(command, :umask=>077)
+ *
+ *  The :in, :out, :err, a fixnum, an IO and an array key specifies a redirect.
+ *  The redirection maps a file descriptor in the child process.
+ *
+ *  For example, stderr can be merged into stdout:
+ *
+ *    pid = spawn(command, :err=>:out)
+ *    pid = spawn(command, STDERR=>STDOUT)
+ *    pid = spawn(command, 2=>1)
+ *
+ *  The hash keys specifies a file descriptor
+ *  in the child process started by <code>spawn</code>.
+ *  :err, STDERR and 2 specifies the standard error stream.
+ *
+ *  The hash values specifies a file descriptor
+ *  in the parent process which invokes <code>spawn</code>.
+ *  :out, STDOUT and 1 specifies the standard output stream.
+ *
+ *  The standard output in the child process is not specified.
+ *  So it is inherited from the parent process.
+ *
+ *  The standard input stream can be specifed by :in, STDIN and 0.
+ *  
+ *  A filename can be specified as a hash value.
+ *
+ *    pid = spawn(command, STDIN=>"/dev/null") # read mode
+ *    pid = spawn(command, STDOUT=>"/dev/null") # write mode
+ *    pid = spawn(command, STDERR=>"log") # write mode
+ *    pid = spawn(command, 3=>"/dev/null") # read mode
+ *
+ *  For standard output and standard error,
+ *  it is opened in write mode.
+ *  Otherwise read mode is used.
+ *
+ *  For specifying flags and permission of file creation explicitly,
+ *  an array is used instead.
+ *
+ *    pid = spawn(command, STDIN=>["file"]) # read mode is assumed
+ *    pid = spawn(command, STDIN=>["file", "r"])
+ *    pid = spawn(command, STDOUT=>["log", "w"]) # 0644 assumed
+ *    pid = spawn(command, STDOUT=>["log", "w", 0600])
+ *    pid = spawn(command, STDOUT=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
+ *
+ *  The array specifies a filename, flags and permission.
+ *  The flags can be a string or an integer.
+ *  If the flags is ommitted or nil, File::RDONLY is assumed.
+ *  The permission should be an integer.
+ *  If the permission is ommitted or nil, 0644 is assumed.
+ *
+ *  If an array of IOs and integers are specified as a hash key,
+ *  all the elemetns are redirected.
+ *
+ *    # standard output and standard error is redirected to log file.
+ *    pid = spawn(command, [STDOUT, STDERR]=>["log", "w"])
+ *
+ *  spawn closes all non-standard unspecified descriptors by default.
+ *  The "standard" descriptors are 0, 1 and 2.
+ *  This behavior is specified by :close_others option.
+ *  :close_others doesn't affect the standard descriptors which are
+ *  closed only if :close is specified explicitly.
+ *
+ *    pid = spawn(command, :close_others=>true)  # close 3,4,5,... (default)
+ *    pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
+ *
+ *  :close_others is true by default for spawn and IO.popen.
+ *
+ *  So IO.pipe and spawn can be used as IO.popen.
+ *
+ *    # similar to r = IO.popen(command)
+ *    r, w = IO.pipe
+ *    pid = spawn(command, STDOUT=>w)   # r, w is closed in the child process.
+ *    w.close
+ *
+ *  :close is specified as a hash value to close a fd individualy.
+ *
+ *    f = open(foo)
+ *    system(command, f=>:close)        # don't inherit f.
+ *
+ *  It is also possible to exchange file descriptors.
+ *
+ *    pid = spawn(command, STDOUT=>STDERR, STDERR=>STDOUT)
+ *
+ *  The hash keys specify file descriptors in the child process.
+ *  The hash values specifies file descriptors in the parent process.
+ *  So the above specifies exchanging STDOUT and STDERR.
+ *  Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
+ *  file descriptor mapping.
+ *
  */
 
 static VALUE
@@ -1834,11 +2916,11 @@
  *  thread calls <code>Thread#run</code>. Zero arguments causes +sleep+ to sleep
  *  forever.
  *
- *     Time.new    #=> Wed Apr 09 08:56:32 CDT 2003
+ *     Time.new    #=> 2008-03-08 19:56:19 +0900
  *     sleep 1.2   #=> 1
- *     Time.new    #=> Wed Apr 09 08:56:33 CDT 2003
+ *     Time.new    #=> 2008-03-08 19:56:20 +0900
  *     sleep 1.9   #=> 2
- *     Time.new    #=> Wed Apr 09 08:56:35 CDT 2003
+ *     Time.new    #=> 2008-03-08 19:56:22 +0900
  */
 
 static VALUE
@@ -1877,7 +2959,9 @@
 static VALUE
 proc_getpgrp(void)
 {
+#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID) || defined(HAVE_GETPGID)
     rb_pid_t pgrp;
+#endif
 
     rb_secure(2);
 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
@@ -2091,42 +3175,22 @@
 #endif
 }
 
-#if SIZEOF_RLIM_T == SIZEOF_INT
-# define RLIM2NUM(v) UINT2NUM(v)
-# define NUM2RLIM(v) NUM2UINT(v)
-#elif SIZEOF_RLIM_T == SIZEOF_LONG
-# define RLIM2NUM(v) ULONG2NUM(v)
-# define NUM2RLIM(v) NUM2ULONG(v)
-#elif SIZEOF_RLIM_T == SIZEOF_LONG_LONG
-# define RLIM2NUM(v) ULL2NUM(v)
-# define NUM2RLIM(v) NUM2ULL(v)
-#endif
-
 #if defined(RLIM2NUM)
 static int
-rlimit_resource_type(VALUE rtype)
+rlimit_resource_name2int(const char *name, int casetype)
 {
-    const char *name;
-    VALUE v;
-
-    switch (TYPE(rtype)) {
-      case T_SYMBOL:
-        name = rb_id2name(SYM2ID(rtype));
-        break;
-
-      default:
-        v = rb_check_string_type(rtype);
-        if (!NIL_P(v)) {
-            rtype = v;
-      case T_STRING:
-            name = StringValueCStr(rtype);
-            break;
+    size_t len = strlen(name);
+    if (16 < len) return -1;
+    if (casetype == 1) {
+        int i;
+        char *name2 = ALLOCA_N(char, len+1);
+        for (i = 0; i < len; i++) {
+            if (!ISLOWER(name[i]))
+                return -1;
+            name2[i] = TOUPPER(name[i]);
         }
-        /* fall through */
-
-      case T_FIXNUM:
-      case T_BIGNUM:
-        return NUM2INT(rtype);
+        name2[len] = '\0';
+        name = name2;
     }
 
     switch (*name) {
@@ -2187,6 +3251,52 @@
 #endif
         break;
     }
+    return -1;
+}
+
+static int
+rlimit_type_by_hname(const char *name)
+{
+    return rlimit_resource_name2int(name, 0);
+}
+
+static int
+rlimit_type_by_lname(const char *name)
+{
+    return rlimit_resource_name2int(name, 1);
+}
+
+static int
+rlimit_resource_type(VALUE rtype)
+{
+    const char *name;
+    VALUE v;
+    int r;
+
+    switch (TYPE(rtype)) {
+      case T_SYMBOL:
+        name = rb_id2name(SYM2ID(rtype));
+        break;
+
+      default:
+        v = rb_check_string_type(rtype);
+        if (!NIL_P(v)) {
+            rtype = v;
+      case T_STRING:
+            name = StringValueCStr(rtype);
+            break;
+        }
+        /* fall through */
+
+      case T_FIXNUM:
+      case T_BIGNUM:
+        return NUM2INT(rtype);
+    }
+
+    r = rlimit_type_by_hname(name);
+    if (r != -1)
+        return r;
+
     rb_raise(rb_eArgError, "invalid resource name: %s", name);
 }
 
@@ -2213,7 +3323,7 @@
 
       case T_FIXNUM:
       case T_BIGNUM:
-        return NUM2INT(rval);
+        return NUM2RLIM(rval);
     }
 
 #ifdef RLIM_INFINITY
@@ -3112,7 +4222,9 @@
 proc_daemon(int argc, VALUE *argv)
 {
     VALUE nochdir, noclose;
+#if defined(HAVE_DAEMON) || defined(HAVE_FORK)
     int n;
+#endif
 
     rb_secure(2);
     rb_scan_args(argc, argv, "02", &nochdir, &noclose);
@@ -3122,7 +4234,7 @@
     if (n < 0) rb_sys_fail("daemon");
     return INT2FIX(n);
 #elif defined(HAVE_FORK)
-    switch (rb_fork(0, 0, 0)) {
+    switch (rb_fork(0, 0, 0, Qnil)) {
       case -1:
 	return (-1);
       case 0:
@@ -3916,7 +5028,7 @@
     volatile VALUE utime, stime, cutime, sctime;
 
     times(&buf);
-    return rb_struct_new(S_Tms,
+    return rb_struct_new(rb_cProcessTms,
 			 utime = DOUBLE2NUM(buf.tms_utime / hertz),
 			 stime = DOUBLE2NUM(buf.tms_stime / hertz),
 			 cutime = DOUBLE2NUM(buf.tms_cutime / hertz),
@@ -3979,27 +5091,27 @@
     rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
     rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
 
-    rb_cProcStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
-    rb_undef_method(CLASS_OF(rb_cProcStatus), "new");
+    rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
+    rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
 
-    rb_define_method(rb_cProcStatus, "==", pst_equal, 1);
-    rb_define_method(rb_cProcStatus, "&", pst_bitand, 1);
-    rb_define_method(rb_cProcStatus, ">>", pst_rshift, 1);
-    rb_define_method(rb_cProcStatus, "to_i", pst_to_i, 0);
-    rb_define_method(rb_cProcStatus, "to_int", pst_to_i, 0);
-    rb_define_method(rb_cProcStatus, "to_s", pst_to_s, 0);
-    rb_define_method(rb_cProcStatus, "inspect", pst_inspect, 0);
+    rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
+    rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
+    rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
+    rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
+    rb_define_method(rb_cProcessStatus, "to_int", pst_to_i, 0);
+    rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
+    rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
 
-    rb_define_method(rb_cProcStatus, "pid", pst_pid, 0);
+    rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
 
-    rb_define_method(rb_cProcStatus, "stopped?", pst_wifstopped, 0);
-    rb_define_method(rb_cProcStatus, "stopsig", pst_wstopsig, 0);
-    rb_define_method(rb_cProcStatus, "signaled?", pst_wifsignaled, 0);
-    rb_define_method(rb_cProcStatus, "termsig", pst_wtermsig, 0);
-    rb_define_method(rb_cProcStatus, "exited?", pst_wifexited, 0);
-    rb_define_method(rb_cProcStatus, "exitstatus", pst_wexitstatus, 0);
-    rb_define_method(rb_cProcStatus, "success?", pst_success_p, 0);
-    rb_define_method(rb_cProcStatus, "coredump?", pst_wcoredump, 0);
+    rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
+    rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
+    rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
+    rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
+    rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
+    rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
+    rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
+    rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
 
     rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
     rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
@@ -4089,7 +5201,7 @@
     rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
 
 #if defined(HAVE_TIMES) || defined(_WIN32)
-    S_Tms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
+    rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
 #endif
 
     SAVED_USER_ID = geteuid();

Modified: MacRuby/trunk/random.c
===================================================================
--- MacRuby/trunk/random.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/random.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   random.c -
 
-  $Author: akr $
+  $Author: matz $
   created at: Fri Dec 24 16:39:21 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -332,9 +332,12 @@
     VALUE seed, old;
 
     rb_secure(4);
-    if (rb_scan_args(argc, argv, "01", &seed) == 0) {
+    if (argc == 0) {
 	seed = random_seed();
     }
+    else {
+	rb_scan_args(argc, argv, "01", &seed);
+    }
     old = rand_init(seed);
 
     return old;

Modified: MacRuby/trunk/range.c
===================================================================
--- MacRuby/trunk/range.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/range.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   range.c -
 
-  $Author: nobu $
+  $Author: matz $
   created at: Thu Aug 19 17:46:47 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -223,10 +223,12 @@
 }
 
 static void
-range_each_func(VALUE range, VALUE (*func) (VALUE, void *), VALUE v, VALUE e,
-		void *arg)
+range_each_func(VALUE range, VALUE (*func) (VALUE, void *), void *arg)
 {
     int c;
+    VALUE b = RANGE_BEG(range);
+    VALUE e = RANGE_END(range);
+    VALUE v = b;
 
     if (EXCL(range)) {
 	while (r_lt(v, e)) {
@@ -267,7 +269,7 @@
  *     rng.step(n=1) {| obj | block }    => rng
  *  
  *  Iterates over <i>rng</i>, passing each <i>n</i>th element to the block. If
- *  the range contains numbers or strings, natural ordering is used.  Otherwise
+ *  the range contains numbers, <i>n</i> is added for each iteration.  Otherwise
  *  <code>step</code> invokes <code>succ</code> to iterate through range
  *  elements. The following code uses class <code>Xs</code>, which is defined
  *  in the class-level documentation.
@@ -293,33 +295,31 @@
 static VALUE
 range_step(int argc, VALUE *argv, VALUE range)
 {
-    VALUE b, e, step;
-    long unit;
+    VALUE b, e, step, tmp;
 
     RETURN_ENUMERATOR(range, argc, argv);
 
     b = RANGE_BEG(range);
     e = RANGE_END(range);
-    if (rb_scan_args(argc, argv, "01", &step) == 0) {
+    if (argc == 0) {
 	step = INT2FIX(1);
-	unit = 1;
     }
-    else if (FIXNUM_P(step)) {
-	unit = NUM2LONG(step);
-    }
     else {
-	VALUE tmp = rb_to_int(step);
-	unit = rb_cmpint(tmp, step, INT2FIX(0));
-	step = tmp;
+	rb_scan_args(argc, argv, "01", &step);
+	if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
+	    step = rb_to_int(step);
+	}
+	if (rb_funcall(step, '<', 1, INT2FIX(0))) {
+	    rb_raise(rb_eArgError, "step can't be negative");
+	}
+	else if (!rb_funcall(step, '>', 1, INT2FIX(0))) {
+	    rb_raise(rb_eArgError, "step can't be 0");
+	}
     }
-    if (unit < 0) {
-	rb_raise(rb_eArgError, "step can't be negative");
-    }
-    if (unit == 0)
-	rb_raise(rb_eArgError, "step can't be 0");
+
     if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
 	long end = FIX2LONG(e);
-	long i;
+	long i, unit = FIX2LONG(step);
 
 	if (!EXCL(range))
 	    end += 1;
@@ -329,9 +329,20 @@
 	    if (i + unit < i) break;
 	    i += unit;
 	}
+
     }
+    else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
+	     !NIL_P(rb_check_to_integer(b, "to_int")) ||
+	     !NIL_P(rb_check_to_integer(e, "to_int"))) {
+	ID op = EXCL(range) ? '<' : rb_intern("<=");
+
+	while (RTEST(rb_funcall(b, op, 1, e))) {
+	    rb_yield(b);
+	    b = rb_funcall(b, '+', 1, step);
+	}
+    }
     else {
-	VALUE tmp = rb_check_string_type(b);
+	tmp = rb_check_string_type(b);
 
 	if (!NIL_P(tmp)) {
 	    VALUE args[2], iter[2];
@@ -343,16 +354,6 @@
 	    iter[1] = step;
 	    rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter);
 	}
-	else if (rb_obj_is_kind_of(b, rb_cNumeric)) {
-	    ID c = rb_intern(EXCL(range) ? "<" : "<=");
-
-	    if (rb_equal(step, INT2FIX(0)))
-		rb_raise(rb_eArgError, "step can't be 0");
-	    while (RTEST(rb_funcall(b, c, 1, e))) {
-		rb_yield(b);
-		b = rb_funcall(b, '+', 1, step);
-	    }
-	}
 	else {
 	    VALUE args[2];
 
@@ -362,7 +363,7 @@
 	    }
 	    args[0] = INT2FIX(1);
 	    args[1] = step;
-	    range_each_func(range, step_i, b, e, args);
+	    range_each_func(range, step_i, args);
 	}
     }
     return range;
@@ -414,7 +415,7 @@
 	if (!EXCL(range))
 	    lim += 1;
 	for (i = FIX2LONG(beg); i < lim; i++) {
-	    rb_yield(LONG2NUM(i));
+	    rb_yield(LONG2FIX(i));
 	}
     }
     else if (TYPE(beg) == T_STRING) {
@@ -425,7 +426,7 @@
 	rb_block_call(beg, rb_intern("upto"), 2, args, rb_yield, 0);
     }
     else {
-	range_each_func(range, each_i, beg, end, NULL);
+	range_each_func(range, each_i, NULL);
     }
     return range;
 }
@@ -717,7 +718,8 @@
  *     rng.include?(val) =>  true or false
  *  
  *  Returns <code>true</code> if <i>obj</i> is an element of
- *  <i>rng</i>, <code>false</code> otherwise.
+ *  <i>rng</i>, <code>false</code> otherwise.  If beg and end are
+ *  numeric, comparison is done according magnitude of values.
  *     
  *     ("a".."z").include?("g")  # => true
  *     ("a".."z").include?("A")  # => false

Added: MacRuby/trunk/rational.c
===================================================================
--- MacRuby/trunk/rational.c	                        (rev 0)
+++ MacRuby/trunk/rational.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,1614 @@
+/*
+  rational.c: Coded by Tadayoshi Funaba 2008
+
+  This implementation is based on Keiju Ishitsuka's Rational library
+  which is written in ruby.
+*/
+
+#include "ruby.h"
+#include <math.h>
+#include <float.h>
+
+#define NDEBUG
+#include <assert.h>
+
+#ifndef RATIONAL_NAME
+#define RATIONAL_NAME "Rational"
+#endif
+
+#define ZERO INT2FIX(0)
+#define ONE INT2FIX(1)
+#define TWO INT2FIX(2)
+
+VALUE rb_cRational;
+
+static ID id_Unify, id_abs, id_cmp, id_convert, id_equal_p,
+  id_expt, id_floor, id_format, id_idiv, id_inspect, id_negate, id_new,
+  id_new_bang, id_to_f, id_to_i, id_to_s, id_truncate;
+
+#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
+
+#define binop(n,op) \
+inline static VALUE \
+f_##n(VALUE x, VALUE y)\
+{\
+  return rb_funcall(x, op, 1, y);\
+}
+
+#define fun1(n) \
+inline static VALUE \
+f_##n(VALUE x)\
+{\
+    return rb_funcall(x, id_##n, 0);\
+}
+
+#define fun2(n) \
+inline static VALUE \
+f_##n(VALUE x, VALUE y)\
+{\
+    return rb_funcall(x, id_##n, 1, y);\
+}
+
+inline static VALUE
+f_add(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y)) {
+	if (FIX2LONG(y) == 0)
+	    r = x;
+	else
+	    r = rb_funcall(x, '+', 1, y);
+    }
+    else if (FIXNUM_P(x)) {
+	if (FIX2LONG(x) == 0)
+	    r = y;
+	else
+	    r = rb_funcall(x, '+', 1, y);
+    }
+    else
+	r = rb_funcall(x, '+', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_cmp(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y)) {
+	long c = FIX2LONG(x) - FIX2LONG(y);
+	if (c > 0)
+	    c = 1;
+	else if (c < 0)
+	    c = -1;
+	r = INT2FIX(c);
+    }
+    else
+	r = rb_funcall(x, id_cmp, 1, y);
+    return r;
+}
+
+inline static VALUE
+f_div(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y) && FIX2LONG(y) == 1)
+	r = x;
+    else
+	r = rb_funcall(x, '/', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_gt_p(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y))
+	r = f_boolcast(FIX2LONG(x) > FIX2LONG(y));
+    else
+	r = rb_funcall(x, '>', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_lt_p(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y))
+	r = f_boolcast(FIX2LONG(x) < FIX2LONG(y));
+    else
+	r = rb_funcall(x, '<', 1, y);
+    return r;
+}
+
+binop(mod, '%')
+
+inline static VALUE
+f_mul(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y)) {
+	long _iy = FIX2LONG(y);
+	if (_iy == 0) {
+	    if (TYPE(x) == T_FLOAT)
+		r = rb_float_new(0.0);
+	    else
+		r = ZERO;
+	}
+	else if (_iy == 1)
+	    r = x;
+	else
+	    r = rb_funcall(x, '*', 1, y);
+    }
+    else if (FIXNUM_P(x)) {
+	long _ix = FIX2LONG(x);
+	if (_ix == 0) {
+	    if (TYPE(y) == T_FLOAT)
+		r = rb_float_new(0.0);
+	    else
+		r = ZERO;
+	}
+	else if (_ix == 1)
+	    r = y;
+	else
+	    r = rb_funcall(x, '*', 1, y);
+    }
+    else
+	r = rb_funcall(x, '*', 1, y);
+    return r;
+}
+
+inline static VALUE
+f_sub(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(y)) {
+	if (FIX2LONG(y) == 0)
+	    r = x;
+	else
+	    r = rb_funcall(x, '-', 1, y);
+    }
+    else
+	r = rb_funcall(x, '-', 1, y);
+    return r;
+}
+
+binop(xor, '^')
+
+fun1(abs)
+fun1(floor)
+fun1(inspect)
+fun1(negate)
+fun1(to_f)
+fun1(to_i)
+fun1(to_s)
+fun1(truncate)
+
+inline static VALUE
+f_equal_p(VALUE x, VALUE y)
+{
+    VALUE r;
+    if (FIXNUM_P(x) && FIXNUM_P(y))
+	r = f_boolcast(FIX2LONG(x) == FIX2LONG(y));
+    else
+	r = rb_funcall(x, id_equal_p, 1, y);
+    return r;
+}
+
+fun2(expt)
+fun2(idiv)
+
+inline static VALUE
+f_negative_p(VALUE x)
+{
+    VALUE r;
+    if (FIXNUM_P(x))
+	r = f_boolcast(FIX2LONG(x) < 0);
+    else
+	r = rb_funcall(x, '<', 1, ZERO);
+    return r;
+}
+
+inline static VALUE
+f_zero_p(VALUE x)
+{
+    VALUE r;
+    if (FIXNUM_P(x))
+	r = f_boolcast(FIX2LONG(x) == 0);
+    else
+	r = rb_funcall(x, id_equal_p, 1, ZERO);
+    return r;
+}
+
+inline static VALUE
+f_one_p(VALUE x)
+{
+    VALUE r;
+    if (FIXNUM_P(x))
+	r = f_boolcast(FIX2LONG(x) == 1);
+    else
+	r = rb_funcall(x, id_equal_p, 1, ONE);
+    return r;
+}
+
+inline static VALUE
+f_kind_of_p(VALUE x, VALUE c)
+{
+    return rb_obj_is_kind_of(x, c);
+}
+
+inline static VALUE
+k_numeric_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cNumeric);
+}
+
+inline static VALUE
+k_integer_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cInteger);
+}
+
+inline static VALUE
+k_float_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cFloat);
+}
+
+inline static VALUE
+k_rational_p(VALUE x)
+{
+    return f_kind_of_p(x, rb_cRational);
+}
+
+#ifndef NDEBUG
+#define f_gcd f_gcd_orig
+#endif
+
+inline static long
+i_gcd(long x, long y)
+{
+    long b;
+
+    if (x < 0)
+	x = -x;
+    if (y < 0)
+	y = -y;
+
+    if (x == 0)
+	return y;
+    if (y == 0)
+	return x;
+
+    b = 0;
+    while ((x & 1) == 0 && (y & 1) == 0) {
+	b += 1;
+	x >>= 1;
+	y >>= 1;
+    }
+
+    while ((x & 1) == 0)
+	x >>= 1;
+
+    while ((y & 1) == 0)
+	y >>= 1;
+
+    while (x != y) {
+	if (y > x) {
+	    long t;
+	    t = x;
+	    x = y;
+	    y = t;
+	}
+	x -= y;
+	while ((x & 1) == 0)
+	    x >>= 1;
+    }
+
+    return x << b;
+}
+
+inline static VALUE
+f_gcd(VALUE x, VALUE y)
+{
+    VALUE z;
+
+    if (FIXNUM_P(x) && FIXNUM_P(y))
+	return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
+
+    if (f_negative_p(x))
+	x = f_negate(x);
+    if (f_negative_p(y))
+	y = f_negate(y);
+
+    if (f_zero_p(x))
+	return y;
+    if (f_zero_p(y))
+	return x;
+
+    for (;;) {
+	if (FIXNUM_P(x)) {
+	    if (FIX2LONG(x) == 0)
+		return y;
+	    if (FIXNUM_P(y))
+		return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
+	}
+	z = x;
+	x = f_mod(y, x);
+	y = z;
+    }
+    /* NOTREACHED */
+}
+
+#ifndef NDEBUG
+#undef f_gcd
+
+inline static VALUE
+f_gcd(VALUE x, VALUE y)
+{
+    VALUE r = f_gcd_orig(x, y);
+    if (!f_zero_p(r)) {
+	assert(f_zero_p(f_mod(x, r)));
+	assert(f_zero_p(f_mod(y, r)));
+    }
+    return r;
+}
+#endif
+
+inline static VALUE
+f_lcm(VALUE x, VALUE y)
+{
+    if (f_zero_p(x) || f_zero_p(y))
+	return ZERO;
+    else
+	return f_abs(f_mul(f_div(x, f_gcd(x, y)), y));
+}
+
+#define get_dat1(x) \
+    struct RRational *dat;\
+    dat = ((struct RRational *)(x))
+
+#define get_dat2(x,y) \
+    struct RRational *adat, *bdat;\
+    adat = ((struct RRational *)(x));\
+    bdat = ((struct RRational *)(y))
+
+inline static VALUE
+nurat_s_new_internal(VALUE klass, VALUE num, VALUE den)
+{
+    NEWOBJ(obj, struct RRational);
+    OBJSETUP(obj, klass, T_RATIONAL);
+
+    obj->num = num;
+    obj->den = den;
+
+    return (VALUE)obj;
+}
+
+static VALUE
+nurat_s_alloc(VALUE klass)
+{
+    return nurat_s_new_internal(klass, ZERO, ONE);
+}
+
+static VALUE
+nurat_s_new_bang(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE num, den;
+
+    switch (rb_scan_args(argc, argv, "11", &num, &den)) {
+      case 1:
+	if (!k_integer_p(num))
+	    num = f_to_i(num);
+	den = ONE;
+	break;
+      default:
+	if (!k_integer_p(num))
+	    num = f_to_i(num);
+	if (!k_integer_p(den))
+	    den = f_to_i(den);
+
+	switch (FIX2INT(f_cmp(den, ZERO))) {
+	  case -1:
+	    num = f_negate(num);
+	    den = f_negate(den);
+	    break;
+	  case 0:
+	    rb_raise(rb_eZeroDivError, "devided by zero");
+	    break;
+	}
+	break;
+    }
+
+    return nurat_s_new_internal(klass, num, den);
+}
+
+inline static VALUE
+f_rational_new_bang1(VALUE klass, VALUE x)
+{
+    return nurat_s_new_internal(klass, x, ONE);
+}
+
+inline static VALUE
+f_rational_new_bang2(VALUE klass, VALUE x, VALUE y)
+{
+    assert(!f_negative_p(y));
+    assert(!f_zero_p(y));
+    return nurat_s_new_internal(klass, x, y);
+}
+
+#define f_unify_p(klass) rb_const_defined(klass, id_Unify)
+
+inline static void
+nurat_int_check(VALUE num)
+{
+    switch (TYPE(num)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	break;
+      default:
+	rb_raise(rb_eArgError, "not an integer");
+    }
+}
+
+inline static VALUE
+nurat_s_canonicalize_internal(VALUE klass, VALUE num, VALUE den)
+{
+    VALUE gcd;
+
+    switch (FIX2INT(f_cmp(den, ZERO))) {
+      case -1:
+	num = f_negate(num);
+	den = f_negate(den);
+	break;
+      case 0:
+	rb_raise(rb_eZeroDivError, "devided by zero");
+	break;
+    }
+
+    gcd = f_gcd(num, den);
+    num = f_idiv(num, gcd);
+    den = f_idiv(den, gcd);
+
+    if (f_one_p(den) && f_unify_p(klass))
+	return num;
+    else
+	return nurat_s_new_internal(klass, num, den);
+}
+
+inline static VALUE
+nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den)
+{
+    switch (FIX2INT(f_cmp(den, ZERO))) {
+      case -1:
+	num = f_negate(num);
+	den = f_negate(den);
+	break;
+      case 0:
+	rb_raise(rb_eZeroDivError, "devided by zero");
+	break;
+    }
+
+    if (f_equal_p(den, ONE) && f_unify_p(klass))
+	return num;
+    else
+	return nurat_s_new_internal(klass, num, den);
+}
+
+#if 0
+static VALUE
+nurat_s_canonicalize(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE num, den;
+
+    if (rb_scan_args(argc, argv, "11", &num, &den) == 1) {
+	den = ONE;
+    }
+
+    nurat_int_check(num);
+    nurat_int_check(den);
+
+    return nurat_s_canonicalize_internal(klass, num, den);
+}
+#endif
+
+static VALUE
+nurat_s_new(VALUE klass, VALUE num, VALUE den)
+{
+    nurat_int_check(num);
+    nurat_int_check(den);
+
+    return nurat_s_canonicalize_internal(klass, num, den);
+}
+
+static VALUE
+nurat_s_new_m(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE num, den;
+
+    if (rb_scan_args(argc, argv, "11", &num, &den) == 1) {
+	den = ONE;
+    }
+    return nurat_s_new(klass, num, den);
+}
+
+inline static VALUE
+f_rational_new1(VALUE klass, VALUE x)
+{
+    assert(!k_rational_p(x));
+    return nurat_s_canonicalize_internal(klass, x, ONE);
+}
+
+inline static VALUE
+f_rational_new2(VALUE klass, VALUE x, VALUE y)
+{
+    assert(!k_rational_p(x));
+    assert(!k_rational_p(y));
+    return nurat_s_canonicalize_internal(klass, x, y);
+}
+
+inline static VALUE
+f_rational_new_no_reduce1(VALUE klass, VALUE x)
+{
+    assert(!k_rational_p(x));
+    return nurat_s_canonicalize_internal_no_reduce(klass, x, ONE);
+}
+
+inline static VALUE
+f_rational_new_no_reduce2(VALUE klass, VALUE x, VALUE y)
+{
+    assert(!k_rational_p(x));
+    assert(!k_rational_p(y));
+    return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
+}
+
+static VALUE
+nurat_f_rational(int argc, VALUE *argv, VALUE klass)
+{
+    return rb_funcall2(rb_cRational, id_convert, argc, argv);
+}
+
+static VALUE
+nurat_numerator(VALUE self)
+{
+    get_dat1(self);
+    return dat->num;
+}
+
+static VALUE
+nurat_denominator(VALUE self)
+{
+    get_dat1(self);
+    return dat->den;
+}
+
+#ifndef NDEBUG
+#define f_imul f_imul_orig
+#endif
+
+inline static VALUE
+f_imul(long a, long b)
+{
+    VALUE r;
+    long c;
+
+    if (a == 0 || b == 0)
+	return ZERO;
+    else if (a == 1)
+	return LONG2NUM(b);
+    else if (b == 1)
+	return LONG2NUM(a);
+
+    c = a * b;
+    r = LONG2NUM(c);
+    if (NUM2LONG(r) != c || (c / a) != b)
+	r = rb_big_mul(rb_int2big(a), rb_int2big(b));
+    return r;
+}
+
+#ifndef NDEBUG
+#undef f_imul
+
+inline static VALUE
+f_imul(long x, long y)
+{
+    VALUE r = f_imul_orig(x, y);
+    assert(f_equal_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
+    return r;
+}
+#endif
+
+inline static VALUE
+f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
+{
+    VALUE num, den;
+
+    if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
+	FIXNUM_P(bnum) && FIXNUM_P(bden)) {
+	long an = FIX2LONG(anum);
+	long ad = FIX2LONG(aden);
+	long bn = FIX2LONG(bnum);
+	long bd = FIX2LONG(bden);
+	long ig = i_gcd(ad, bd);
+
+	VALUE g = LONG2NUM(ig);
+	VALUE a = f_imul(an, bd / ig);
+	VALUE b = f_imul(bn, ad / ig);
+	VALUE c;
+
+	if (k == '+')
+	    c = f_add(a, b);
+	else
+	    c = f_sub(a, b);
+
+	b = f_idiv(aden, g);
+	g = f_gcd(c, g);
+	num = f_idiv(c, g);
+	a = f_idiv(bden, g);
+	den = f_mul(a, b);
+    }
+    else {
+	VALUE g = f_gcd(aden, bden);
+	VALUE a = f_mul(anum, f_idiv(bden, g));
+	VALUE b = f_mul(bnum, f_idiv(aden, g));
+	VALUE c;
+
+	if (k == '+')
+	    c = f_add(a, b);
+	else
+	    c = f_sub(a, b);
+
+	b = f_idiv(aden, g);
+	g = f_gcd(c, g);
+	num = f_idiv(c, g);
+	a = f_idiv(bden, g);
+	den = f_mul(a, b);
+    }
+    return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
+}
+
+static VALUE
+nurat_add(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	{
+	    get_dat1(self);
+
+	    return f_addsub(self,
+			    dat->num, dat->den,
+			    other, ONE, '+');
+	}
+      case T_FLOAT:
+	return f_add(f_to_f(self), other);
+      case T_RATIONAL:
+	{
+	    get_dat2(self, other);
+
+	    return f_addsub(self,
+			    adat->num, adat->den,
+			    bdat->num, bdat->den, '+');
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '+');
+    }
+}
+
+static VALUE
+nurat_sub(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	{
+	    get_dat1(self);
+
+	    return f_addsub(self,
+			    dat->num, dat->den,
+			    other, ONE, '-');
+	}
+      case T_FLOAT:
+	return f_sub(f_to_f(self), other);
+      case T_RATIONAL:
+	{
+	    get_dat2(self, other);
+
+	    return f_addsub(self,
+			    adat->num, adat->den,
+			    bdat->num, bdat->den, '-');
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '-');
+    }
+}
+
+inline static VALUE
+f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
+{
+    VALUE num, den;
+
+    if (k == '/') {
+	VALUE t;
+
+	if (f_negative_p(bnum)) {
+	    anum = f_negate(anum);
+	    bnum = f_negate(bnum);
+	}
+	t = bnum;
+	bnum = bden;
+	bden = t;
+    }
+
+    if (FIXNUM_P(anum) && FIXNUM_P(aden) &&
+	FIXNUM_P(bnum) && FIXNUM_P(bden)) {
+	long an = FIX2LONG(anum);
+	long ad = FIX2LONG(aden);
+	long bn = FIX2LONG(bnum);
+	long bd = FIX2LONG(bden);
+	long g1 = i_gcd(an, bd);
+	long g2 = i_gcd(ad, bn);
+
+	num = f_imul(an / g1, bn / g2);
+	den = f_imul(ad / g2, bd / g1);
+    }
+    else {
+	VALUE g1 = f_gcd(anum, bden);
+	VALUE g2 = f_gcd(aden, bnum);
+
+	num = f_mul(f_idiv(anum, g1), f_idiv(bnum, g2));
+	den = f_mul(f_idiv(aden, g2), f_idiv(bden, g1));
+    }
+    return f_rational_new_no_reduce2(CLASS_OF(self), num, den);
+}
+
+static VALUE
+nurat_mul(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	{
+	    get_dat1(self);
+
+	    return f_muldiv(self,
+			    dat->num, dat->den,
+			    other, ONE, '*');
+	}
+      case T_FLOAT:
+	return f_mul(f_to_f(self), other);
+      case T_RATIONAL:
+	{
+	    get_dat2(self, other);
+
+	    return f_muldiv(self,
+			    adat->num, adat->den,
+			    bdat->num, bdat->den, '*');
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '*');
+    }
+}
+
+static VALUE
+nurat_div(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	if (f_zero_p(other))
+	    rb_raise(rb_eZeroDivError, "devided by zero");
+	{
+	    get_dat1(self);
+
+	    return f_muldiv(self,
+			    dat->num, dat->den,
+			    other, ONE, '/');
+	}
+      case T_FLOAT:
+	return rb_funcall(f_to_f(self), '/', 1, other);
+      case T_RATIONAL:
+	if (f_zero_p(other))
+	    rb_raise(rb_eZeroDivError, "devided by zero");
+	{
+	    get_dat2(self, other);
+
+	    return f_muldiv(self,
+			    adat->num, adat->den,
+			    bdat->num, bdat->den, '/');
+	}
+      default:
+	return rb_num_coerce_bin(self, other, '/');
+    }
+}
+
+static VALUE
+nurat_fdiv(VALUE self, VALUE other)
+{
+    return f_div(f_to_f(self), other);
+}
+
+static VALUE
+nurat_expt(VALUE self, VALUE other)
+{
+    if (f_zero_p(other))
+	return f_rational_new_bang1(CLASS_OF(self), ONE);
+
+    if (k_rational_p(other)) {
+	get_dat1(other);
+
+	if (f_one_p(dat->den))
+	    other = dat->num; /* good? */
+    }
+
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	{
+	    VALUE num, den;
+
+	    get_dat1(self);
+
+	    switch (FIX2INT(f_cmp(other, ZERO))) {
+	      case 1:
+		num = f_expt(dat->num, other);
+		den = f_expt(dat->den, other);
+		break;
+	      case -1:
+		num = f_expt(dat->den, f_negate(other));
+		den = f_expt(dat->num, f_negate(other));
+		break;
+	      default:
+		num = ONE;
+		den = ONE;
+		break;
+	    }
+	    return f_rational_new2(CLASS_OF(self), num, den);
+	}
+      case T_FLOAT:
+      case T_RATIONAL:
+	return f_expt(f_to_f(self), other);
+      default:
+	return rb_num_coerce_bin(self, other, id_expt);
+    }
+}
+
+static VALUE
+nurat_cmp(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	{
+	    get_dat1(self);
+
+	    if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1)
+		return f_cmp(dat->num, other);
+	    else
+		return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other));
+	}
+      case T_FLOAT:
+	return f_cmp(f_to_f(self), other);
+      case T_RATIONAL:
+	{
+	    VALUE num1, num2;
+
+	    get_dat2(self, other);
+
+	    if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) &&
+		FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) {
+		num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den));
+		num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den));
+	    }
+	    else {
+		num1 = f_mul(adat->num, bdat->den);
+		num2 = f_mul(bdat->num, adat->den);
+	    }
+	    return f_cmp(f_sub(num1, num2), ZERO);
+	}
+      default:
+	return rb_num_coerce_bin(self, other, id_cmp);
+    }
+}
+
+static VALUE
+nurat_equal_p(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	{
+	    get_dat1(self);
+
+	    if (!FIXNUM_P(dat->den))
+		return Qfalse;
+	    if (FIX2LONG(dat->den) != 1)
+		return Qfalse;
+	    if (f_equal_p(dat->num, other))
+		return Qtrue;
+	    else
+		return Qfalse;
+	}
+      case T_FLOAT:
+	return f_equal_p(f_to_f(self), other);
+      case T_RATIONAL:
+	{
+	    get_dat2(self, other);
+
+	    return f_boolcast(f_equal_p(adat->num, bdat->num) &&
+			      f_equal_p(adat->den, bdat->den));
+	}
+      default:
+	return f_equal_p(other, self);
+    }
+}
+
+static VALUE
+nurat_coerce(VALUE self, VALUE other)
+{
+    switch (TYPE(other)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self), other), self);
+      case T_FLOAT:
+	return rb_assoc_new(other, f_to_f(self));
+    }
+
+    rb_raise(rb_eTypeError, "%s can't be coerced into %s",
+	     rb_obj_classname(other), rb_obj_classname(self));
+    return Qnil;
+}
+
+static VALUE
+nurat_idiv(VALUE self, VALUE other)
+{
+    return f_floor(f_div(self, other));
+}
+
+static VALUE
+nurat_mod(VALUE self, VALUE other)
+{
+    VALUE val = f_floor(f_div(self, other));
+    return f_sub(self, f_mul(other, val));
+}
+
+static VALUE
+nurat_divmod(VALUE self, VALUE other)
+{
+    VALUE val = f_floor(f_div(self, other));
+    return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
+}
+
+#if 0
+static VALUE
+nurat_quot(VALUE self, VALUE other)
+{
+    return f_truncate(f_div(self, other));
+}
+#endif
+
+static VALUE
+nurat_rem(VALUE self, VALUE other)
+{
+    VALUE val = f_truncate(f_div(self, other));
+    return f_sub(self, f_mul(other, val));
+}
+
+#if 0
+static VALUE
+nurat_quotrem(VALUE self, VALUE other)
+{
+    VALUE val = f_truncate(f_div(self, other));
+    return rb_assoc_new(val, f_sub(self, f_mul(other, val)));
+}
+#endif
+
+static VALUE
+nurat_abs(VALUE self)
+{
+    if (!f_negative_p(self))
+	return self;
+    else
+	return f_negate(self);
+}
+
+#if 0
+static VALUE
+nurat_true(VALUE self)
+{
+    return Qtrue;
+}
+#endif
+
+static VALUE
+nurat_floor(VALUE self)
+{
+    get_dat1(self);
+    return f_idiv(dat->num, dat->den);
+}
+
+static VALUE
+nurat_ceil(VALUE self)
+{
+    get_dat1(self);
+    return f_negate(f_idiv(f_negate(dat->num), dat->den));
+}
+
+static VALUE
+nurat_truncate(VALUE self)
+{
+    get_dat1(self);
+    if (f_negative_p(dat->num))
+	return f_negate(f_idiv(f_negate(dat->num), dat->den));
+    return f_idiv(dat->num, dat->den);
+}
+
+static VALUE
+nurat_round(VALUE self)
+{
+    get_dat1(self);
+
+    if (f_negative_p(dat->num)) {
+	VALUE num, den;
+
+	num = f_negate(dat->num);
+	num = f_add(f_mul(num, TWO), dat->den);
+	den = f_mul(dat->den, TWO);
+	return f_negate(f_idiv(num, den));
+    }
+    else {
+	VALUE num = f_add(f_mul(dat->num, TWO), dat->den);
+	VALUE den = f_mul(dat->den, TWO);
+	return f_idiv(num, den);
+    }
+}
+
+#define f_size(x) rb_funcall(x, rb_intern("size"), 0)
+#define f_rshift(x,y) rb_funcall(x, rb_intern(">>"), 1, y)
+
+inline static long
+i_ilog2(VALUE x)
+{
+    long q, r, fx;
+
+    assert(!f_lt_p(x, ONE));
+
+    q = (NUM2LONG(f_size(x)) - sizeof(long)) * 8 + 1;
+
+    if (q > 0)
+	x = f_rshift(x, LONG2NUM(q));
+
+    fx = NUM2LONG(x);
+
+    r = -1;
+    while (fx) {
+	fx >>= 1;
+	r += 1;
+    }
+
+    return q + r;
+}
+
+static VALUE
+nurat_to_f(VALUE self)
+{
+    VALUE num, den;
+    int minus = 0;
+    long nl, dl, ml, ne, de;
+    int e;
+    double f;
+
+    {
+	get_dat1(self);
+
+	if (f_zero_p(dat->num))
+	    return rb_float_new(0.0);
+
+	num = dat->num;
+	den = dat->den;
+    }
+
+    if (f_negative_p(num)) {
+	num = f_negate(num);
+	minus = 1;
+    }
+
+    nl = i_ilog2(num);
+    dl = i_ilog2(den);
+    ml = (long)(log(DBL_MAX) / log(2.0) - 1); /* should be a static */
+
+    ne = 0;
+    if (nl > ml) {
+	ne = nl - ml;
+	num = f_rshift(num, LONG2NUM(ne));
+    }
+
+    de = 0;
+    if (dl > ml) {
+	de = dl - ml;
+	den = f_rshift(den, LONG2NUM(de));
+    }
+
+    e = (int)(ne - de);
+
+    if ((e > DBL_MAX_EXP) || (e < DBL_MIN_EXP)) {
+	rb_warning("%s out of Float range", rb_obj_classname(self));
+	return rb_float_new(e > 0 ? HUGE_VAL : 0.0);
+    }
+
+    f = NUM2DBL(num) / NUM2DBL(den);
+    if (minus)
+	f = -f;
+    f = ldexp(f, e);
+
+    if (isinf(f) || isnan(f))
+	rb_warning("%s out of Float range", rb_obj_classname(self));
+
+    return rb_float_new(f);
+}
+
+static VALUE
+nurat_to_r(VALUE self)
+{
+    return self;
+}
+
+static VALUE
+nurat_hash(VALUE self)
+{
+    get_dat1(self);
+    return f_xor(dat->num, dat->den);
+}
+
+static VALUE
+nurat_to_s(VALUE self)
+{
+    get_dat1(self);
+
+    if (f_one_p(dat->den))
+	return f_to_s(dat->num);
+    else
+	return rb_funcall(rb_mKernel, id_format, 3,
+			  rb_str_new2("%d/%d"), dat->num, dat->den);
+}
+
+static VALUE
+nurat_inspect(VALUE self)
+{
+    get_dat1(self);
+    return rb_funcall(rb_mKernel, id_format, 3,
+		      rb_str_new2("Rational(%d, %d)"), dat->num, dat->den);
+}
+
+static VALUE
+nurat_marshal_dump(VALUE self)
+{
+    get_dat1(self);
+    return rb_assoc_new(dat->num, dat->den);
+}
+
+static VALUE
+nurat_marshal_load(VALUE self, VALUE a)
+{
+    get_dat1(self);
+    dat->num = RARRAY_PTR(a)[0];
+    dat->den = RARRAY_PTR(a)[1];
+
+    if (f_zero_p(dat->den))
+	rb_raise(rb_eZeroDivError, "devided by zero");
+
+    return self;
+}
+
+/* --- */
+
+VALUE
+rb_gcd(VALUE self, VALUE other)
+{
+    nurat_int_check(other);
+    return f_gcd(self, other);
+}
+
+VALUE
+rb_lcm(VALUE self, VALUE other)
+{
+    nurat_int_check(other);
+    return f_lcm(self, other);
+}
+
+VALUE
+rb_gcdlcm(VALUE self, VALUE other)
+{
+    nurat_int_check(other);
+    return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
+}
+
+VALUE
+rb_rational_raw(VALUE x, VALUE y)
+{
+    return nurat_s_new_internal(rb_cRational, x, y);
+}
+
+VALUE
+rb_rational_new(VALUE x, VALUE y)
+{
+    return nurat_s_canonicalize_internal(rb_cRational, x, y);
+}
+
+static VALUE nurat_s_convert(int argc, VALUE *argv, VALUE klass);
+
+VALUE
+rb_Rational(VALUE x, VALUE y)
+{
+    VALUE a[2];
+    a[0] = x;
+    a[1] = y;
+    return nurat_s_convert(2, a, rb_cRational);
+}
+
+static VALUE
+nilclass_to_r(VALUE self)
+{
+    return rb_rational_new1(INT2FIX(0));
+}
+
+static VALUE
+integer_to_r(VALUE self)
+{
+    return rb_rational_new1(self);
+}
+
+static VALUE
+float_decode(VALUE self)
+{
+    double f;
+    int n;
+
+    f = frexp(RFLOAT_VALUE(self), &n);
+    f = ldexp(f, DBL_MANT_DIG);
+    n -= DBL_MANT_DIG;
+    return rb_assoc_new(f_to_i(rb_float_new(f)), INT2FIX(n));
+}
+
+static VALUE
+float_to_r(VALUE self)
+{
+    VALUE a = float_decode(self);
+    return f_mul(RARRAY_PTR(a)[0],
+		 f_expt(INT2FIX(FLT_RADIX), RARRAY_PTR(a)[1]));
+}
+
+static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
+
+#define DIGITS "(?:\\d(?:_\\d|\\d)*)"
+#define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
+#define DENOMINATOR "[-+]?" DIGITS
+#define PATTERN "\\A([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?"
+
+static void
+make_patterns(void)
+{
+    static char rat_pat_source[] = PATTERN;
+    static char an_e_pat_source[] = "[eE]";
+    static char a_dot_pat_source[] = "\\.";
+    static char underscores_pat_source[] = "_+";
+
+    rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
+    rb_global_variable(&rat_pat);
+
+    an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
+    rb_global_variable(&an_e_pat);
+
+    a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
+    rb_global_variable(&a_dot_pat);
+
+    underscores_pat = rb_reg_new(underscores_pat_source,
+				 sizeof underscores_pat_source - 1, 0);
+    rb_global_variable(&underscores_pat);
+
+    an_underscore = rb_str_new2("_");
+    rb_global_variable(&an_underscore);
+}
+
+#define id_strip rb_intern("strip")
+#define f_strip(x) rb_funcall(x, id_strip, 0)
+
+#define id_match rb_intern("match")
+#define f_match(x,y) rb_funcall(x, id_match, 1, y)
+
+#define id_aref rb_intern("[]")
+#define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
+
+#define id_post_match rb_intern("post_match")
+#define f_post_match(x) rb_funcall(x, id_post_match, 0)
+
+#define id_split rb_intern("split")
+#define f_split(x,y) rb_funcall(x, id_split, 1, y)
+
+#include <ctype.h>
+
+static VALUE
+string_to_r_internal(VALUE self)
+{
+    VALUE s, m;
+
+    s = f_strip(self);
+
+    if (RSTRING_LEN(s) == 0)
+	return rb_assoc_new(Qnil, self);
+
+    m = f_match(rat_pat, s);
+
+    if (!NIL_P(m)) {
+	VALUE v, ifp, exp, ip, fp;
+	VALUE si = f_aref(m, INT2FIX(1));
+	VALUE nu = f_aref(m, INT2FIX(2));
+	VALUE de = f_aref(m, INT2FIX(3));
+	VALUE re = f_post_match(m);
+
+	{
+	    VALUE a;
+
+	    a = f_split(nu, an_e_pat);
+	    ifp = RARRAY_PTR(a)[0];
+	    if (RARRAY_LEN(a) != 2)
+		exp = Qnil;
+	    else
+		exp = RARRAY_PTR(a)[1];
+
+	    a = f_split(ifp, a_dot_pat);
+	    ip = RARRAY_PTR(a)[0];
+	    if (RARRAY_LEN(a) != 2)
+		fp = Qnil;
+	    else
+		fp = RARRAY_PTR(a)[1];
+	}
+
+	v = rb_rational_new1(f_to_i(ip));
+
+	if (!NIL_P(fp)) {
+	    char *p = StringValuePtr(fp);
+	    long count = 0;
+	    VALUE l;
+
+	    while (*p) {
+		if (isdigit(*p))
+		    count++;
+		p++;
+	    }
+
+	    l = f_expt(INT2FIX(10), LONG2NUM(count));
+	    v = f_mul(v, l);
+	    v = f_add(v, f_to_i(fp));
+	    v = f_div(v, l);
+	}
+	if (!NIL_P(exp))
+	    v = f_mul(v, f_expt(INT2FIX(10), f_to_i(exp)));
+	if (!NIL_P(si) && *StringValuePtr(si) == '-')
+	    v = f_negate(v);
+	if (!NIL_P(de))
+	    v = f_div(v, f_to_i(de));
+
+	return rb_assoc_new(v, re);
+    }
+    return rb_assoc_new(Qnil, self);
+}
+
+static VALUE
+string_to_r_strict(VALUE self)
+{
+    VALUE a = string_to_r_internal(self);
+    if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
+	VALUE s = f_inspect(self);
+	rb_raise(rb_eArgError, "invalid value for Rational: %s",
+		 StringValuePtr(s));
+    }
+    return RARRAY_PTR(a)[0];
+}
+
+#define id_gsub rb_intern("gsub")
+#define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
+
+static VALUE
+string_to_r(VALUE self)
+{
+    VALUE s = f_gsub(self, underscores_pat, an_underscore);
+    VALUE a = string_to_r_internal(s);
+    if (!NIL_P(RARRAY_PTR(a)[0]))
+	return RARRAY_PTR(a)[0];
+    return rb_rational_new1(INT2FIX(0));
+}
+
+#define id_to_r rb_intern("to_r")
+#define f_to_r(x) rb_funcall(x, id_to_r, 0)
+
+static VALUE
+nurat_s_convert(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE a1, a2;
+
+    if (rb_scan_args(argc, argv, "02", &a1, &a2) == 1) {
+	a2 = ONE;
+    }
+
+    switch (TYPE(a1)) {
+      case T_COMPLEX:
+	if (k_float_p(RCOMPLEX(a1)->image) || !f_zero_p(RCOMPLEX(a1)->image)) {
+	    VALUE s = f_to_s(a1);
+	    rb_raise(rb_eRangeError, "can't accept %s",
+		     StringValuePtr(s));
+	}
+	a1 = RCOMPLEX(a1)->real;
+    }
+
+    switch (TYPE(a2)) {
+      case T_COMPLEX:
+	if (k_float_p(RCOMPLEX(a2)->image) || !f_zero_p(RCOMPLEX(a2)->image)) {
+	    VALUE s = f_to_s(a2);
+	    rb_raise(rb_eRangeError, "can't accept %s",
+		     StringValuePtr(s));
+	}
+	a2 = RCOMPLEX(a2)->real;
+    }
+
+    switch (TYPE(a1)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	break;
+      case T_FLOAT:
+	a1 = f_to_r(a1);
+	break;
+      case T_STRING:
+	a1 = string_to_r_strict(a1);
+	break;
+    }
+
+    switch (TYPE(a2)) {
+      case T_FIXNUM:
+      case T_BIGNUM:
+	break;
+      case T_FLOAT:
+	a2 = f_to_r(a2);
+	break;
+      case T_STRING:
+	a2 = string_to_r_strict(a2);
+	break;
+    }
+
+    switch (TYPE(a1)) {
+      case T_RATIONAL:
+	if (NIL_P(a2) || f_zero_p(a2))
+	    return a1;
+	else
+	    return f_div(a1, a2);
+    }
+
+    switch (TYPE(a2)) {
+      case T_RATIONAL:
+	return f_div(a1, a2);
+    }
+
+    return nurat_s_new(klass, a1, a2);
+}
+
+static VALUE
+nurat_s_induced_from(VALUE klass, VALUE n)
+{
+    return f_to_r(n);
+}
+
+void
+Init_Rational(void)
+{
+    assert(fprintf(stderr, "assert() is now active\n"));
+
+    id_Unify = rb_intern("Unify");
+    id_abs = rb_intern("abs");
+    id_cmp = rb_intern("<=>");
+    id_convert = rb_intern("convert");
+    id_equal_p = rb_intern("==");
+    id_expt = rb_intern("**");
+    id_floor = rb_intern("floor");
+    id_format = rb_intern("format");
+    id_idiv = rb_intern("div");
+    id_inspect = rb_intern("inspect");
+    id_negate = rb_intern("-@");
+    id_new = rb_intern("new");
+    id_new_bang = rb_intern("new!");
+    id_to_f = rb_intern("to_f");
+    id_to_i = rb_intern("to_i");
+    id_to_s = rb_intern("to_s");
+    id_truncate = rb_intern("truncate");
+
+    rb_cRational = rb_define_class(RATIONAL_NAME, rb_cNumeric);
+
+    rb_define_alloc_func(rb_cRational, nurat_s_alloc);
+    rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("allocate")));
+
+    rb_define_singleton_method(rb_cRational, "new!", nurat_s_new_bang, -1);
+    rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("new!")));
+
+    rb_define_singleton_method(rb_cRational, "new", nurat_s_new_m, -1);
+    rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("new")));
+
+    rb_define_global_function(RATIONAL_NAME, nurat_f_rational, -1);
+
+    rb_define_method(rb_cRational, "numerator", nurat_numerator, 0);
+    rb_define_method(rb_cRational, "denominator", nurat_denominator, 0);
+
+    rb_define_method(rb_cRational, "+", nurat_add, 1);
+    rb_define_method(rb_cRational, "-", nurat_sub, 1);
+    rb_define_method(rb_cRational, "*", nurat_mul, 1);
+    rb_define_method(rb_cRational, "/", nurat_div, 1);
+    rb_define_method(rb_cRational, "quo", nurat_div, 1);
+    rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
+    rb_define_method(rb_cRational, "**", nurat_expt, 1);
+
+    rb_define_method(rb_cRational, "<=>", nurat_cmp, 1);
+    rb_define_method(rb_cRational, "==", nurat_equal_p, 1);
+    rb_define_method(rb_cRational, "coerce", nurat_coerce, 1);
+
+    rb_define_method(rb_cRational, "div", nurat_idiv, 1);
+#if NUBY
+    rb_define_method(rb_cRational, "//", nurat_idiv, 1);
+#endif
+    rb_define_method(rb_cRational, "modulo", nurat_mod, 1);
+    rb_define_method(rb_cRational, "%", nurat_mod, 1);
+    rb_define_method(rb_cRational, "divmod", nurat_divmod, 1);
+
+#if 0
+    rb_define_method(rb_cRational, "quot", nurat_quot, 1);
+#endif
+    rb_define_method(rb_cRational, "remainder", nurat_rem, 1);
+#if 0
+    rb_define_method(rb_cRational, "quotrem", nurat_quotrem, 1);
+#endif
+
+    rb_define_method(rb_cRational, "abs", nurat_abs, 0);
+
+#if 0
+    rb_define_method(rb_cRational, "rational?", nurat_true, 0);
+    rb_define_method(rb_cRational, "exact?", nurat_true, 0);
+#endif
+
+    rb_define_method(rb_cRational, "floor", nurat_floor, 0);
+    rb_define_method(rb_cRational, "ceil", nurat_ceil, 0);
+    rb_define_method(rb_cRational, "truncate", nurat_truncate, 0);
+    rb_define_method(rb_cRational, "round", nurat_round, 0);
+
+    rb_define_method(rb_cRational, "to_i", nurat_truncate, 0);
+    rb_define_method(rb_cRational, "to_f", nurat_to_f, 0);
+    rb_define_method(rb_cRational, "to_r", nurat_to_r, 0);
+
+    rb_define_method(rb_cRational, "hash", nurat_hash, 0);
+
+    rb_define_method(rb_cRational, "to_s", nurat_to_s, 0);
+    rb_define_method(rb_cRational, "inspect", nurat_inspect, 0);
+
+    rb_define_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
+    rb_define_method(rb_cRational, "marshal_load", nurat_marshal_load, 1);
+
+    /* --- */
+
+    rb_define_method(rb_cInteger, "gcd", rb_gcd, 1);
+    rb_define_method(rb_cInteger, "lcm", rb_lcm, 1);
+    rb_define_method(rb_cInteger, "gcdlcm", rb_gcdlcm, 1);
+
+    rb_define_method(rb_cNilClass, "to_r", nilclass_to_r, 0);
+    rb_define_method(rb_cInteger, "to_r", integer_to_r, 0);
+    rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
+
+    make_patterns();
+
+    rb_define_method(rb_cString, "to_r", string_to_r, 0);
+
+    rb_define_singleton_method(rb_cRational, "convert", nurat_s_convert, -1);
+    rb_funcall(rb_cRational, rb_intern("private_class_method"), 1,
+	       ID2SYM(rb_intern("convert")));
+
+    rb_include_module(rb_cRational, rb_mPrecision);
+    rb_define_singleton_method(rb_cRational, "induced_from",
+			       nurat_s_induced_from, 1);
+}


Property changes on: MacRuby/trunk/rational.c
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: MacRuby/trunk/re.c
===================================================================
--- MacRuby/trunk/re.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/re.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -95,45 +95,152 @@
     return memcmp(p1, p2, len);
 }
 
-long
-rb_memsearch(const void *x0, long m, const void *y0, long n)
+static inline long
+rb_memsearch_ss(const unsigned char *xs, long m, const unsigned char *ys, long n)
 {
-    const unsigned char *x = x0, *y = y0;
-    const unsigned char *s, *e;
-    long i;
-    int d;
-    unsigned long hx, hy;
+    const unsigned char *x = xs, *xe = xs + m;
+    const unsigned char *y = ys, *ye = ys + n;
+#ifndef VALUE_MAX
+# if SIZEOF_VALUE == 8
+#  define VALUE_MAX 0xFFFFFFFFFFFFFFFFULL
+# elif SIZEOF_VALUE == 4
+#  define VALUE_MAX 0xFFFFFFFFUL
+# endif
+#endif
+    VALUE hx, hy, mask = VALUE_MAX >> ((SIZEOF_VALUE - m) * CHAR_BIT);
 
-#define KR_REHASH(a, b, h) (((h) << 1) - (((unsigned long)(a))<<d) + (b))
+    if (m > SIZEOF_VALUE)
+	rb_bug("!!too long pattern string!!");
 
-    if (m > n) return -1;
-    s = y; e = s + n - m;
+    	/* Prepare hash value */
+    for (hx = *x++, hy = *y++; x < xe; ++x, ++y) {
+	hx <<= CHAR_BIT;
+	hy <<= CHAR_BIT;
+	hx |= *x;
+	hy |= *y;
+    }
+    /* Searching */
+    while (hx != hy) {
+	if (y == ye)
+	    return -1;
+	hy <<= CHAR_BIT;
+	hy |= *y;
+	hy &= mask;
+	y++;
+    }
+    return y - ys - m;
+}
 
+static inline long
+rb_memsearch_qs(const unsigned char *xs, long m, const unsigned char *ys, long n)
+{
+    const unsigned char *x = xs, *xe = xs + m;
+    const unsigned char *y = ys;
+    VALUE i, qstable[256];
+
     /* Preprocessing */
-    /* computes d = 2^(m-1) with
-       the left-shift operator */
-    d = sizeof(hx) * CHAR_BIT - 1;
-    if (d > m) d = m;
+    for (i = 0; i < 256; ++i)
+	qstable[i] = m + 1;
+    for (; x < xe; ++x)
+	qstable[*x] = xe - x;
+    /* Searching */
+    for (; y + m <= ys + n; y += *(qstable + y[m])) {
+	if (*xs == *y && memcmp(xs, y, m) == 0)
+	    return y - ys;
+    }
+    return -1;
+}
 
-    if (n == m) {
-	return memcmp(x, s, m) == 0 ? 0 : -1;
+static inline unsigned int
+rb_memsearch_qs_utf8_hash(const unsigned char *x)
+{
+    register const unsigned int mix = 8353;
+    register unsigned int h = *x;
+    if (h < 0xC0) {
+	return h + 256;
     }
-    /* Prepare hash value */
-    for (hy = hx = i = 0; i < d; ++i) {
-	hx = KR_REHASH(0, x[i], hx);
-	hy = KR_REHASH(0, s[i], hy);
+    else if (h < 0xE0) {
+	h *= mix;
+	h += x[1];
     }
+    else if (h < 0xF0) {
+	h *= mix;
+	h += x[1];
+	h *= mix;
+	h += x[2];
+    }
+    else if (h < 0xF5) {
+	h *= mix;
+	h += x[1];
+	h *= mix;
+	h += x[2];
+	h *= mix;
+	h += x[3];
+    }
+    else {
+	return h + 256;
+    }
+    return (unsigned char)h;
+}
+
+static inline long
+rb_memsearch_qs_utf8(const unsigned char *xs, long m, const unsigned char *ys, long n)
+{
+    const unsigned char *x = xs, *xe = xs + m;
+    const unsigned char *y = ys;
+    VALUE i, qstable[512];
+
+    /* Preprocessing */
+    for (i = 0; i < 512; ++i) {
+	qstable[i] = m + 1;
+    }
+    for (; x < xe; ++x) {
+	qstable[rb_memsearch_qs_utf8_hash(x)] = xe - x;
+    }
     /* Searching */
-    while (hx != hy || memcmp(x, s, m)) {
-	if (s >= e) return -1;
-	hy = KR_REHASH(*s, *(s+d), hy);
-	s++;
+    for (; y + m <= ys + n; y += qstable[rb_memsearch_qs_utf8_hash(y+m)]) {
+	if (*xs == *y && memcmp(xs, y, m) == 0)
+	    return y - ys;
     }
-    return s-y;
+    return -1;
 }
 
+long
+rb_memsearch(const void *x0, long m, const void *y0, long n, rb_encoding *enc)
+{
+    const unsigned char *x = x0, *y = y0;
+
+    if (m > n) return -1;
+    else if (m == n) {
+	return memcmp(x0, y0, m) == 0 ? 0 : -1;
+    }
+    else if (m < 1) {
+	return 0;
+    }
+    else if (m == 1) {
+	const unsigned char *ys = y, *ye = ys + n;
+	for (; y < ye; ++y) {
+	    if (*x == *y)
+		return y - ys;
+	}
+	return -1;
+    }
+    else if (m <= SIZEOF_VALUE) {
+	return rb_memsearch_ss(x0, m, y0, n);
+    }
+#if !WITH_OBJC
+    else if (enc == rb_utf8_encoding()){
+	return rb_memsearch_qs_utf8(x0, m, y0, n);
+    }
+#endif
+    else {
+	return rb_memsearch_qs(x0, m, y0, n);
+    }
+}
+
 #define REG_LITERAL FL_USER5
 #define REG_ENCODING_NONE FL_USER6
+#define REG_BUSY FL_USER7
 
 #define KCODE_FIXED FL_USER4
 
@@ -357,7 +464,7 @@
  *
  *      /ab+c/ix.inspect        #=> "/ab+c/ix"
  *
-*/
+ */
 
 static VALUE
 rb_reg_inspect(VALUE re)
@@ -604,7 +711,7 @@
  *     /(?<foo>.)(?<foo>.)/.names
  *     #=> ["foo"]
  *
- *     /(.)(.)/.names' 
+ *     /(.)(.)/.names
  *     #=> []
  */
 
@@ -645,12 +752,12 @@
  *    /(?<foo>.)(?<bar>.)/.named_captures
  *    #=> {"foo"=>[1], "bar"=>[2]}
  *
- *    /(?<foo>.)(?<foo>.)/.named_captures'
+ *    /(?<foo>.)(?<foo>.)/.named_captures
  *    #=> {"foo"=>[1, 2]}
  *
  * If there are no named captures, an empty hash is returned.
  *
- *    /(.)(.)/.named_captures' 
+ *    /(.)(.)/.named_captures
  *    #=> {}
  */
 
@@ -789,8 +896,7 @@
     for (i = 0; i < num_pos; i++) {
         q = s + pairs[i].byte_pos;
 #if WITH_OBJC
-	//long n = strlen(p);
-	c += q-p;//(n > (q-p) ? q-p : n);
+	c += q-p;
 #else
         c += rb_enc_strlen(p, q, enc);
 #endif
@@ -1071,16 +1177,16 @@
  *
  *      r = /a/u
  *      r.fixed_encoding?                               #=> true
- *      r.encoding                                      #=> <Encoding:UTF-8>
+ *      r.encoding                                      #=> #<Encoding:UTF-8>
  *      r =~ "\u{6666} a"                               #=> 2
- *      r =~ "\xa1\xa2".force_encoding("euc-jp")        # ArgumentError
+ *      r =~ "\xa1\xa2".force_encoding("euc-jp")        #=> ArgumentError
  *      r =~ "abc".force_encoding("euc-jp")             #=> 0
  *
  *      r = /\u{6666}/
  *      r.fixed_encoding?                               #=> true
- *      r.encoding                                      #=> <Encoding:UTF-8>
+ *      r.encoding                                      #=> #<Encoding:UTF-8>
  *      r =~ "\u{6666} a"                               #=> 0
- *      r =~ "\xa1\xa2".force_encoding("euc-jp")        # ArgumentError
+ *      r =~ "\xa1\xa2".force_encoding("euc-jp")        #=> ArgumentError
  *      r =~ "abc".force_encoding("euc-jp")             #=> nil
  */
 
@@ -1097,15 +1203,22 @@
 rb_reg_preprocess(const char *p, const char *end, rb_encoding *enc,
         rb_encoding **fixed_enc, onig_errmsg_buffer err);
 
+
 static void
-rb_reg_prepare_re(VALUE re, VALUE str, int enable_warning)
+reg_enc_error(VALUE re, VALUE str)
 {
-    int need_recompile = 0;
-    rb_encoding *enc;
+    rb_raise(rb_eArgError,
+	     "incompatible encoding regexp match (%s regexp with %s string)",
+	     rb_enc_name(rb_enc_get(re)),
+	     rb_enc_name(rb_enc_get(str)));
+}
 
-#if WITH_OBJC
-    need_recompile = 0;
-#else
+static rb_encoding*
+rb_reg_prepare_enc(VALUE re, VALUE str, int warn)
+{
+    rb_encoding *enc = 0;
+
+#if !WITH_OBJC
     if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
         rb_raise(rb_eArgError,
             "broken %s string",
@@ -1114,81 +1227,84 @@
 #endif
 
     rb_reg_check(re);
-    /* ignorecase status */
+    enc = rb_enc_get(str);
 #if !WITH_OBJC
-    if (rb_reg_fixed_encoding_p(re) || !rb_enc_str_asciicompat_p(str)) {
-        if (ENCODING_GET(re) != rb_enc_get_index(str) &&
-            rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
-            rb_raise(rb_eArgError,
-                "incompatible encoding regexp match (%s regexp with %s string)",
-		rb_enc_name(rb_enc_get(re)),
-                rb_enc_name(rb_enc_get(str)));
-        }
+    if (!rb_enc_str_asciicompat_p(str)) {
+        if (RREGEXP(re)->ptr->enc != enc) {
+	    reg_enc_error(re, str);
+	}
     }
-    else {
-        if ((enc = rb_enc_get(str)) != 0 &&
-	     RREGEXP(re)->ptr->enc != enc) {
-            need_recompile = 1;
-        }
-        if (enable_warning &&
-            (RBASIC(re)->flags & REG_ENCODING_NONE) &&
-	    enc != rb_ascii8bit_encoding() &&
-            rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
-            rb_warn("regexp match /.../n against to %s string",
-                    rb_enc_name(enc));
-        }
+    else if (rb_reg_fixed_encoding_p(re)) {
+        if (RREGEXP(re)->ptr->enc != enc &&
+	    (!rb_enc_asciicompat(RREGEXP(re)->ptr->enc) ||
+	     rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT)) {
+	    reg_enc_error(re, str);
+	}
+	enc = RREGEXP(re)->ptr->enc;
     }
+    if (warn && (RBASIC(re)->flags & REG_ENCODING_NONE) &&
+	enc != rb_ascii8bit_encoding() &&
+	rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
+	rb_warn("regexp match /.../n against to %s string",
+		rb_enc_name(enc));
+    }
 #endif
+    return enc;
+}
 
-    if (need_recompile) {
-	onig_errmsg_buffer err = "";
-	int r;
-	OnigErrorInfo einfo;
-	regex_t *reg, *reg2;
-	UChar *pattern;
-        VALUE unescaped;
-        rb_encoding *fixed_enc = 0;
+regex_t *
+rb_reg_prepare_re(VALUE re, VALUE str)
+{
+    regex_t *reg = RREGEXP(re)->ptr;
+    onig_errmsg_buffer err = "";
+    int r;
+    OnigErrorInfo einfo;
+    const char *pattern;
+    VALUE unescaped;
+    rb_encoding *fixed_enc = 0;
+    rb_encoding *enc = rb_reg_prepare_enc(re, str, 1);
 
-	rb_reg_check(re);
-	reg = RREGEXP(re)->ptr;
-	pattern = ((UChar*)RREGEXP(re)->str);
+#if !WITH_OBJC
+    if (reg->enc == enc) return reg;
+#endif
 
-        unescaped = rb_reg_preprocess(
-            RREGEXP(re)->str, RREGEXP(re)->str + RREGEXP(re)->len, enc,
-            &fixed_enc, err);
+    rb_reg_check(re);
+    reg = RREGEXP(re)->ptr;
+    pattern = RREGEXP(re)->str;
 
-        if (unescaped == Qnil) {
-            rb_raise(rb_eArgError, "regexp preprocess failed: %s", err);
-        }
+    unescaped = rb_reg_preprocess(
+	pattern, pattern + RREGEXP(re)->len, enc,
+	&fixed_enc, err);
 
+    if (unescaped == Qnil) {
+	rb_raise(rb_eArgError, "regexp preprocess failed: %s", err);
+    }
+
 #if WITH_OBJC
-	enc = (rb_encoding *)ONIG_ENCODING_ASCII;
+    enc = (rb_encoding *)ONIG_ENCODING_ASCII;
 #endif
 
-	r = onig_new(&reg2, (UChar* )RSTRING_CPTR(unescaped),
-		     (UChar* )(RSTRING_CPTR(unescaped) 
-			 + RSTRING_CLEN(unescaped)),
-		     reg->options, (OnigEncoding)enc,
-		     OnigDefaultSyntax, &einfo);
-	if (r) {
-	    onig_error_code_to_str((UChar*)err, r, &einfo);
-	    rb_reg_raise((char* )pattern, RREGEXP(re)->len, err, re);
-	}
+    r = onig_new(&reg, (UChar* )RSTRING_PTR(unescaped),
+		 (UChar* )(RSTRING_PTR(unescaped) + RSTRING_LEN(unescaped)),
+		 reg->options, (OnigEncoding)enc,
+		 OnigDefaultSyntax, &einfo);
+    if (r) {
+	onig_error_code_to_str((UChar*)err, r, &einfo);
+	rb_reg_raise(pattern, RREGEXP(re)->len, err, re);
+    }
 
-	GC_WB(&RREGEXP(re)->ptr, reg2);
-	onig_free(reg);
-        RB_GC_GUARD(unescaped);
-    }
+    RB_GC_GUARD(unescaped);
+    return reg;
 }
 
 int
 rb_reg_adjust_startpos(VALUE re, VALUE str, int pos, int reverse)
 {
     int range;
-    OnigEncoding enc;
+    rb_encoding *enc;
     UChar *p, *string;
 
-    rb_reg_prepare_re(re, str, 0);
+    enc = rb_reg_prepare_enc(re, str, 0);
 
     if (reverse) {
 	range = -pos;
@@ -1197,8 +1313,7 @@
 	range = RSTRING_CLEN(str) - pos;
     }
 
-    enc = (RREGEXP(re)->ptr)->enc;
-
+#if !WITH_OBJC
     if (pos > 0 && ONIGENC_MBC_MAXLEN(enc) != 1 && pos < RSTRING_CLEN(str)) {
 	 string = (UChar*)RSTRING_CPTR(str);
 
@@ -1210,6 +1325,7 @@
 	 }
 	 return p - string;
     }
+#endif
 
     return pos;
 }
@@ -1222,6 +1338,8 @@
     struct re_registers *pregs;
     const char *cstr, *range;
     long clen;
+    regex_t *reg0 = RREGEXP(re)->ptr, *reg;
+    int busy = FL_TEST(re, REG_BUSY);
 
     cstr = range = RSTRING_CPTR(str);
     clen = RSTRING_CLEN(str);
@@ -1242,11 +1360,13 @@
 	return -1;
     }
 
-    rb_reg_prepare_re(re, str, 1);
+    reg = rb_reg_prepare_re(re, str);
 
+    FL_SET(re, REG_BUSY);
     if (!reverse) {
 	range += RSTRING_CLEN(str);
     }
+    MEMZERO(&regs, struct re_registers, 1);
     result = onig_search(RREGEXP(re)->ptr,
 			 (UChar*)cstr,
 			 ((UChar*)cstr + clen),
@@ -1254,7 +1374,18 @@
 			 ((UChar*)range),
 			 pregs, ONIG_OPTION_NONE);
 
+    if (RREGEXP(re)->ptr != reg) {
+	if (busy) {
+	    onig_free(reg);
+	}
+	else {
+	    onig_free(reg0);
+	    RREGEXP(re)->ptr = reg;
+	}
+    }
+    if (!busy) FL_UNSET(re, REG_BUSY);
     if (result < 0) {
+	onig_region_free(pregs, 0);
 	if (result == ONIG_MISMATCH) {
 	    rb_backref_set(Qnil);
 	    return result;
@@ -1282,6 +1413,7 @@
 #endif
 
     onig_region_copy(RMATCH_REGS(match), pregs);
+    onig_region_free(pregs, 0);
     GC_WB(&RMATCH(match)->str, rb_str_new4(str));
     GC_WB(&RMATCH(match)->regexp, re);
     RMATCH(match)->rmatch->char_offset_updated = 0;
@@ -1604,7 +1736,6 @@
  *  call-seq:
  *
  *     mtch.values_at([index]*)   => array
- *     mtch.select([index]*)   => array
  *
  *  Uses each <i>index</i> to access the matching values, returning an array of
  *  the corresponding matches.
@@ -3317,7 +3448,7 @@
  *  <em>n</em> can be a string or symbol to reference a named capture.
  *
  *     /c(.)t/ =~ 'cat'        #=> 0
- *     Regexp.last_match       #=> #<MatchData "cat" "a">
+ *     Regexp.last_match       #=> #<MatchData "cat" 1:"a">
  *     Regexp.last_match(0)    #=> "cat"
  *     Regexp.last_match(1)    #=> "a"
  *     Regexp.last_match(2)    #=> nil
@@ -3333,7 +3464,7 @@
 {
     VALUE nth;
 
-    if (rb_scan_args(argc, argv, "01", &nth) == 1) {
+    if (argc > 0 && rb_scan_args(argc, argv, "01", &nth) == 1) {
         VALUE match = rb_backref_get();
         int n;
         if (NIL_P(match)) return Qnil;
@@ -3429,7 +3560,6 @@
     rb_define_method(rb_cMatch, "[]", match_aref, -1);
     rb_define_method(rb_cMatch, "captures", match_captures, 0);
     rb_define_method(rb_cMatch, "values_at", match_values_at, -1);
-    rb_define_method(rb_cMatch, "select", match_values_at, -1);
     rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0);
     rb_define_method(rb_cMatch, "post_match", rb_reg_match_post, 0);
     rb_define_method(rb_cMatch, "to_s", match_to_s, 0);

Modified: MacRuby/trunk/regexec.c
===================================================================
--- MacRuby/trunk/regexec.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/regexec.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -186,6 +186,7 @@
     region->allocated = n;
   }
   else if (region->allocated < n) {
+    region->allocated = 0;
     GC_WB(&region->beg, (int* )xrealloc(region->beg, n * sizeof(int)));
     GC_WB(&region->end, (int* )xrealloc(region->end, n * sizeof(int)));
 
@@ -240,7 +241,8 @@
   OnigRegion* r;
 
   r = (OnigRegion* )xmalloc(sizeof(OnigRegion));
-  onig_region_init(r);
+  if (r)
+    onig_region_init(r);
   return r;
 }
 
@@ -268,19 +270,7 @@
 
   if (to == from) return;
 
-  if (to->allocated == 0) {
-    if (from->num_regs > 0) {
-      GC_WB(&to->beg, (int* )xmalloc(RREGC_SIZE));
-      GC_WB(&to->end, (int* )xmalloc(RREGC_SIZE));
-      to->allocated = from->num_regs;
-    }
-  }
-  else if (to->allocated < from->num_regs) {
-    GC_WB(to->beg, (int* )xrealloc(to->beg, RREGC_SIZE));
-    GC_WB(to->end, (int* )xrealloc(to->end, RREGC_SIZE));
-    to->allocated = from->num_regs;
-  }
-
+  onig_region_resize(to, from->num_regs);
   for (i = 0; i < from->num_regs; i++) {
     GC_WB(&to->beg[i], from->beg[i]);
     GC_WB(&to->end[i], from->end[i]);
@@ -352,8 +342,10 @@
     unsigned int size = (unsigned int )(((str_len) + 1) * (state_num) + 7) >> 3;\
     offset = ((offset) * (state_num)) >> 3;\
     if (size > 0 && offset < size && size < STATE_CHECK_BUFF_MAX_SIZE) {\
-      if (size >= STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE) \
+      if (size >= STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE) {\
         (msa).state_check_buff = (void* )xmalloc(size);\
+        CHECK_NULL_RETURN_MEMERR((msa).state_check_buff);\
+      }\
       else \
         (msa).state_check_buff = (void* )xalloca(size);\
       xmemset(((char* )((msa).state_check_buff)+(offset)), 0, \
@@ -378,7 +370,6 @@
   }\
 } while(0)
 #else
-#define STATE_CHECK_BUFF_INIT(msa, str_len, offset, state_num)
 #define MATCH_ARG_FREE(msa)  if ((msa).stack_p) xfree((msa).stack_p)
 #endif
 

Modified: MacRuby/trunk/regint.h
===================================================================
--- MacRuby/trunk/regint.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/regint.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -84,8 +84,7 @@
 /* */
 /* escape other system UChar definition */
 #ifndef RUBY_DEFINES_H
-#include "ruby/config.h"
-#include "ruby/defines.h"
+#include "ruby/ruby.h"
 #endif
 #ifdef ONIG_ESCAPE_UCHAR_COLLISION
 #undef ONIG_ESCAPE_UCHAR_COLLISION
@@ -110,10 +109,10 @@
 #define xfree       free
 #endif
 
-#define CHECK_INTERRUPT_IN_MATCH_AT
-
 #ifdef RUBY
 
+#include "vm_core.h"
+#define CHECK_INTERRUPT_IN_MATCH_AT RUBY_VM_CHECK_INTS()
 #define onig_st_init_table                  st_init_table
 #define onig_st_init_table_with_size        st_init_table_with_size
 #define onig_st_init_numtable               st_init_numtable
@@ -156,6 +155,8 @@
 /* */
 #define onig_st_is_member              st_is_member
 
+#define CHECK_INTERRUPT_IN_MATCH_AT
+
 #endif
 
 #define STATE_CHECK_STRING_THRESHOLD_LEN             7

Modified: MacRuby/trunk/regparse.c
===================================================================
--- MacRuby/trunk/regparse.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/regparse.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -825,6 +825,7 @@
 
   switch (e->back_num) {
   case 0:
+    *nums = 0;
     break;
   case 1:
     *nums = &(e->back_ref1);

Modified: MacRuby/trunk/ruby.1
===================================================================
--- MacRuby/trunk/ruby.1	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ruby.1	2008-05-18 08:10:19 UTC (rev 199)
@@ -23,7 +23,8 @@
 .Op Fl i Ns Op Ar extension
 .Op Fl r Ar library
 .Op Fl x Ns Op Ar directory
-.Op Fl -disable-gems
+.Op - Ns Bro Cm enable Ns | Ns Cm disable Brc Ns - Ns Ar FEATURE
+.Op Fl -verbose
 .Op Fl -
 .Op Ar program_file
 .Op Ar argument ...
@@ -301,7 +302,6 @@
 .Xr csh 1 .
 .Pp
 .It Fl v
-.It Fl -verbose
 Enables verbose mode.  Ruby will print its version at the beginning,
 and set the variable
 .Li "$VERBOSE"
@@ -337,9 +337,36 @@
 state messages during compiling scripts.  You don't have to specify
 this switch, unless you are going to debug the Ruby interpreter.
 .Pp
+.It Fl -disable- Ns Ar FEATURE
+.It Fl -enable- Ns Ar FEATURE
+Disables (or enables) the specified
+.Ar FEATURE Ns
+\&.
+.Pp
 .It Fl -disable-gems
-Disables RubyGems libraries.  By default, Ruby will load the latest
-version of each installed gem.
+.It Fl -enable-gems
+Disables (or enables) RubyGems libraries.  By default, Ruby will load the latest
+version of each installed gem. The
+.Li Gem::Enable
+constant is true if RubyGems is enabled, false if otherwise.
+.Pp
+.It Fl -disable-rubyopt
+.It Fl -enable-rubyopt
+Ignores (or considers) the
+.Ev RUBYOPT
+environment variable. By default, Ruby considers the variable.
+.Pp
+.It Fl -disable-all
+.It Fl -enable-all
+Disables (or enables) all features.
+.Pp
+.It Fl -verbose
+Enables verbose mode without printing version message at the
+beginning.  It sets the
+.Li "$VERBOSE"
+variable to true.
+If this switch is given, and no other switches are present, Ruby quits
+after printing its version.
 .El
 .Pp
 .Sh ENVIRONMENT

Modified: MacRuby/trunk/ruby.c
===================================================================
--- MacRuby/trunk/ruby.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/ruby.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -66,9 +66,6 @@
 const char *ruby_get_inplace_mode(void);
 void ruby_set_inplace_mode(const char *);
 
-extern VALUE rb_get_argv(void);
-#define rb_argv rb_get_argv()
-
 #define DISABLE_BIT(bit) (1U << disable_##bit)
 enum disable_flag_bits {
     disable_gems,
@@ -87,6 +84,7 @@
     int verbose;
     int yydebug;
     char *script;
+    VALUE script_name;
     VALUE e_script;
     struct {
 	struct {
@@ -134,7 +132,6 @@
 	"-Fpattern       split() pattern for autosplit (-a)",
 	"-i[extension]   edit ARGV files in place (make backup if extension supplied)",
 	"-Idirectory     specify $LOAD_PATH directory (may be used more than once)",
-	"-Kkcode         specifies KANJI (Japanese) code-set",
 	"-l              enable line ending processing",
 	"-n              assume 'while gets(); ... end' loop around your script",
 	"-p              assume loop like -n but print line also like sed",
@@ -146,8 +143,6 @@
 	"-w              turn warnings on for your script",
 	"-W[level]       set warning level; 0=silence, 1=medium, 2=verbose (default)",
 	"-x[directory]   strip off text before #!ruby line and perhaps cd to directory",
-	"--enable/--disable-FEATURE --enable/--disable=FEATURE  enable/disable FEATUREs",
-	"                gems: gem libraries, rubyopt: RUBYOPT env, or all",
 	"--copyright     print the copyright",
 	"--version       print the version",
 	NULL
@@ -159,7 +154,7 @@
 	printf("  %s\n", *p++);
 }
 
-extern VALUE rb_load_path;
+VALUE rb_get_load_path(void);
 
 #ifndef CharNext		/* defined as CharNext[AW] on Windows. */
 #define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
@@ -211,7 +206,7 @@
 	return rb_str_new(s, l);
     }
     ret = rb_str_new(0, l + newl - oldl);
-    ptr = RSTRING_CPTR(ret); /* ok */
+    ptr = RSTRING_PTR(ret); /* ok */
     memcpy(ptr, newp, newl);
     memcpy(ptr + newl, s + oldl, l - oldl);
     ptr[l + newl - oldl] = 0;
@@ -234,6 +229,7 @@
 {
     const char sep = PATH_SEP_CHAR;
     const char *p, *s;
+    VALUE load_path = GET_VM()->load_path;
 
     p = path;
     while (*p) {
@@ -241,7 +237,7 @@
 	    p++;
 	if (!*p) break;
 	for (s = p; *s && *s != sep; s = CharNext(s));
-	rb_ary_push(rb_load_path, (*filter)(rubylib_mangled_path(p, s - p)));
+	rb_ary_push(load_path, (*filter)(rubylib_mangled_path(p, s - p)));
 	p = s;
     }
 }
@@ -340,6 +336,7 @@
 void
 ruby_init_loadpath(void)
 {
+    VALUE load_path;
 #if defined LOAD_RELATIVE
     char libpath[MAXPATHLEN + 1];
     char *p;
@@ -386,7 +383,8 @@
 #else
 #define RUBY_RELATIVE(path) (path)
 #endif
-#define incpush(path) rb_ary_push(rb_load_path, rubylib_mangled_path2(path))
+#define incpush(path) rb_ary_push(load_path, rubylib_mangled_path2(path))
+    load_path = GET_VM()->load_path;
 
     if (rb_safe_level() == 0) {
 	ruby_incpush(getenv("RUBYLIB"));
@@ -850,26 +848,26 @@
             }
 	    else if (strncmp("enable", s, n = 6) == 0 &&
 		     (!s[n] || s[n] == '-' || s[n] == '=')) {
-		if (!(s += n + 1)[-1] && (!--argc || !(s = *++argv))) {
+		if ((s += n + 1)[-1] ? !*s : (!--argc || !(s = *++argv))) {
 		    rb_raise(rb_eRuntimeError, "missing argument for --enable");
 		}
 		ruby_each_words(s, enable_option, &opt->disable);
 	    }
 	    else if (strncmp("disable", s, n = 7) == 0 &&
 		     (!s[n] || s[n] == '-' || s[n] == '=')) {
-		if (!(s += n + 1)[-1] && (!--argc || !(s = *++argv))) {
+		if ((s += n + 1)[-1] ? !*s : (!--argc || !(s = *++argv))) {
 		    rb_raise(rb_eRuntimeError, "missing argument for --disable");
 		}
 		ruby_each_words(s, disable_option, &opt->disable);
-            }
+	    }
 	    else if (strncmp("encoding", s, n = 8) == 0 && (!s[n] || s[n] == '=')) {
 		s += n;
 		if (!*s++) {
 		  next_encoding:
-		if (!--argc || !(s = *++argv)) {
-		    rb_raise(rb_eRuntimeError, "missing argument for --encoding");
+		    if (!--argc || !(s = *++argv)) {
+			rb_raise(rb_eRuntimeError, "missing argument for --encoding");
+		    }
 		}
-		}
 	      encoding:
 		opt->ext.enc.name = rb_str_new2(s);
 	    }
@@ -924,9 +922,7 @@
 static void
 ruby_init_gems(int enable)
 {
-    VALUE gem;
-    gem = rb_define_module("Gem");
-    rb_const_set(gem, rb_intern("Enable"), enable ? Qtrue : Qfalse);
+    if (enable) rb_define_module("Gem");
     Init_prelude();
 }
 
@@ -957,6 +953,9 @@
 }
 #endif
 
+VALUE rb_progname;
+VALUE rb_argv0;
+
 #if WITH_OBJC
 static rb_encoding *src_encoding;
 #else
@@ -972,9 +971,11 @@
     char **argv = argp->argv;
     NODE *tree = 0;
     VALUE parser;
-    rb_encoding *enc;
+    rb_encoding *enc, *lenc;
     const char *s;
+    char fbuf[MAXPATHLEN];
     int i = proc_options(argc, argv, opt);
+    int safe;
 
     argc -= i;
     argv += i;
@@ -1034,7 +1035,7 @@
 
     if (rb_safe_level() >= 4) {
 	OBJ_TAINT(rb_argv);
-	OBJ_TAINT(rb_load_path);
+	OBJ_TAINT(GET_VM()->load_path);
     }
 
     if (!opt->e_script) {
@@ -1053,29 +1054,38 @@
 
 		opt->script = 0;
 		if (path) {
-		    opt->script = dln_find_file(argv[0], path);
+		    opt->script = dln_find_file_r(argv[0], path, fbuf, sizeof(fbuf));
 		}
 		if (!opt->script) {
-		    opt->script = dln_find_file(argv[0], getenv(PATH_ENV));
+		    opt->script = dln_find_file_r(argv[0], getenv(PATH_ENV), fbuf, sizeof(fbuf));
 		}
 		if (!opt->script)
 		    opt->script = argv[0];
 	    }
-#if defined DOSISH || defined __CYGWIN__
-	    /* assume that we can change argv[n] if never change its length. */
-	    translate_char(opt->script, '\\', '/');
-#endif
 	    argc--;
 	    argv++;
 	}
     }
 
     ruby_script(opt->script);
+#if defined DOSISH || defined __CYGWIN__
+    translate_char(RSTRING_CPTR(rb_progname), '\\', '/');
+#endif
+    opt->script_name = rb_str_new4(rb_progname);
+    opt->script = RSTRING_PTR(opt->script_name);
     ruby_set_argv(argc, argv);
     process_sflag(opt);
 
     ruby_init_loadpath();
-    ruby_init_gems(!(opt->disable && DISABLE_BIT(gems)));
+    safe = rb_safe_level();
+    rb_set_safe_level_force(0);
+    ruby_init_gems(!(opt->disable & DISABLE_BIT(gems)));
+    lenc = rb_locale_encoding();
+#if !WITH_OBJC
+    for (i = 0; i < RARRAY_LEN(rb_argv); i++) {
+	rb_enc_associate(RARRAY_PTR(rb_argv)[i], lenc);
+    }
+#endif
     parser = rb_parser_new();
     if (opt->yydebug) rb_parser_set_yydebug(parser, Qtrue);
     if (opt->ext.enc.name != 0) {
@@ -1104,10 +1114,11 @@
     }
 #endif
     else {
-	enc = rb_locale_encoding();
+	enc = lenc;
     }
     rb_enc_set_default_external(rb_enc_from_encoding(enc));
 
+    rb_set_safe_level_force(safe);
     if (opt->e_script) {
 	rb_encoding *eenc;
 #if WITH_OBJC
@@ -1120,7 +1131,7 @@
 	}
 #endif
 	else {
-	    eenc = rb_locale_encoding();
+	    eenc = lenc;
 	}
 #if !WITH_OBJC
 	rb_enc_associate(opt->e_script, eenc);
@@ -1142,7 +1153,7 @@
 
     if (rb_safe_level() >= 4) {
 	FL_UNSET(rb_argv, FL_TAINT);
-	FL_UNSET(rb_load_path, FL_TAINT);
+	FL_UNSET(GET_VM()->load_path, FL_TAINT);
     }
 
     if (opt->do_check) {
@@ -1150,16 +1161,15 @@
 	return Qtrue;
     }
 
-    if (tree) {
-	if (opt->do_print) {
-	    tree = rb_parser_append_print(parser, tree);
-	}
-	if (opt->do_loop) {
-	    tree = rb_parser_while_loop(parser, tree, opt->do_line, opt->do_split);
-	}
+    if (opt->do_print) {
+	tree = rb_parser_append_print(parser, tree);
     }
+    if (opt->do_loop) {
+	tree = rb_parser_while_loop(parser, tree, opt->do_line, opt->do_split);
+    }
 
-    return (VALUE)tree;
+    return rb_iseq_new(tree, rb_str_new2("<main>"),
+		       opt->script_name, Qfalse, ISEQ_TYPE_TOP);
 }
 
 static NODE *
@@ -1199,6 +1209,11 @@
 	int no_src_enc = !opt->src.enc.name;
 	int no_ext_enc = !opt->ext.enc.name;
 
+#if !WITH_OBJC
+	enc = rb_usascii_encoding();
+	rb_funcall(f, rb_intern("set_encoding"), 1, rb_enc_from_encoding(enc));
+#endif
+
 	if (opt->xflag) {
 	    forbid_setid("-x");
 	    opt->xflag = Qfalse;
@@ -1341,9 +1356,6 @@
     return load_file(rb_parser_new(), fname, 0, &opt);
 }
 
-VALUE rb_progname;
-VALUE rb_argv0;
-
 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
 #if !defined(_WIN32) && !(defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
 #define USE_ENVSPACE_FOR_ARG0
@@ -1359,6 +1371,7 @@
     char *s = argv[0];
     int i;
 
+    if (!argc) return 0;
     s += strlen(s);
     /* See if all the arguments are contiguous in memory */
     for (i = 1; i < argc; i++) {

Modified: MacRuby/trunk/sample/test.rb
===================================================================
--- MacRuby/trunk/sample/test.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/sample/test.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1463,7 +1463,6 @@
 
 test_check "string & char"
 
-"abcd" =~ /ab/
 test_ok("abcd" == "abcd")
 test_ok("abcd" =~ /abcd/)
 test_ok("abcd" === "abcd")

Modified: MacRuby/trunk/signal.c
===================================================================
--- MacRuby/trunk/signal.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/signal.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   signal.c -
 
-  $Author: usa $
+  $Author: nobu $
   created at: Tue Dec 20 10:13:44 JST 1994
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -36,7 +36,7 @@
 # endif
 #endif
 
-static struct signals {
+static const struct signals {
     const char *signm;
     int  signo;
 } siglist [] = {
@@ -178,7 +178,7 @@
 static int
 signm2signo(const char *nm)
 {
-    struct signals *sigs;
+    const struct signals *sigs;
 
     for (sigs = siglist; sigs->signm; sigs++)
 	if (strcmp(sigs->signm, nm) == 0)
@@ -189,7 +189,7 @@
 static const char*
 signo2signm(int no)
 {
-    struct signals *sigs;
+    const struct signals *sigs;
 
     for (sigs = siglist; sigs->signm; sigs++)
 	if (sigs->signo == no)
@@ -381,7 +381,9 @@
     VALUE cmd;
 } trap_list[NSIG];
 static rb_atomic_t trap_pending_list[NSIG];
+#if 0
 static char rb_trap_accept_nativethreads[NSIG];
+#endif
 rb_atomic_t rb_trap_pending;
 rb_atomic_t rb_trap_immediate;
 int rb_prohibit_interrupt = 1;
@@ -417,7 +419,9 @@
 {
     struct sigaction sigact, old;
 
+#if 0
     rb_trap_accept_nativethreads[signum] = 0;
+#endif
 
     sigemptyset(&sigact.sa_mask);
 #ifdef SA_SIGINFO
@@ -443,8 +447,8 @@
 }
 
 #else /* !POSIX_SIGNAL */
-#define ruby_signal(sig,handler) (rb_trap_accept_nativethreads[sig] = 0, signal((sig),(handler)))
-#ifdef HAVE_NATIVETHREAD
+#define ruby_signal(sig,handler) (/* rb_trap_accept_nativethreads[sig] = 0,*/ signal((sig),(handler)))
+#if 0 /* def HAVE_NATIVETHREAD */
 static sighandler_t
 ruby_nativethread_signal(int signum, sighandler_t handler)
 {
@@ -469,13 +473,14 @@
 #endif
 }
 
+#if USE_TRAP_MASK
 # ifdef HAVE_SIGPROCMASK
 static sigset_t trap_last_mask;
 # else
 static int trap_last_mask;
 # endif
+#endif
 
-
 #if HAVE_PTHREAD_H
 #include <pthread.h>
 #endif
@@ -938,7 +943,7 @@
 sig_list(void)
 {
     VALUE h = rb_hash_new();
-    struct signals *sigs;
+    const struct signals *sigs;
 
     for (sigs = siglist; sigs->signm; sigs++) {
 	rb_hash_aset(h, rb_str_new2(sigs->signm), INT2FIX(sigs->signo));
@@ -957,6 +962,7 @@
     }
 }
 
+#if defined(SIGCLD) || defined(SIGCHLD)
 static void
 init_sigchld(int sig)
 {
@@ -997,6 +1003,7 @@
     trap_last_mask = mask;
 #endif
 }
+#endif
 
 void
 ruby_sig_finalize()

Modified: MacRuby/trunk/sprintf.c
===================================================================
--- MacRuby/trunk/sprintf.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/sprintf.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   sprintf.c -
 
-  $Author: matz $
+  $Author: akr $
   created at: Fri Oct 15 10:39:26 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -144,89 +144,237 @@
  *     sprintf(format_string [, arguments...] )  => string
  *  
  *  Returns the string resulting from applying <i>format_string</i> to
- *  any additional arguments. Within the format string, any characters
- *  other than format sequences are copied to the result. A format
+ *  any additional arguments.  Within the format string, any characters
+ *  other than format sequences are copied to the result. 
+ *
+ *  The syntax of a format sequence is follows.
+ *
+ *    %[flags][width][.precision]type
+ *
+ *  A format
  *  sequence consists of a percent sign, followed by optional flags,
  *  width, and precision indicators, then terminated with a field type
- *  character. The field type controls how the corresponding
+ *  character.  The field type controls how the corresponding
  *  <code>sprintf</code> argument is to be interpreted, while the flags
- *  modify that interpretation. The field type characters are listed
- *  in the table at the end of this section. The flag characters are:
+ *  modify that interpretation.
  *
- *    Flag     | Applies to   | Meaning
- *    ---------+--------------+-----------------------------------------
- *    space    | bdeEfgGiouxX | Leave a space at the start of 
- *             |              | positive numbers.
- *    ---------+--------------+-----------------------------------------
- *    (digit)$ | all          | Specifies the absolute argument number
- *             |              | for this field. Absolute and relative
- *             |              | argument numbers cannot be mixed in a
- *             |              | sprintf string.
- *    ---------+--------------+-----------------------------------------
- *     #       | beEfgGoxX    | Use an alternative format. For the
- *             |              | conversions `o', `x', `X', and `b', 
- *             |              | prefix the result with ``0'', ``0x'', ``0X'',
- *             |              |  and ``0b'', respectively. For `e',
- *             |              | `E', `f', `g', and 'G', force a decimal
- *             |              | point to be added, even if no digits follow.
- *             |              | For `g' and 'G', do not remove trailing zeros.
- *    ---------+--------------+-----------------------------------------
- *    +        | bdeEfgGiouxX | Add a leading plus sign to positive numbers.
- *    ---------+--------------+-----------------------------------------
- *    -        | all          | Left-justify the result of this conversion.
- *    ---------+--------------+-----------------------------------------
- *    0 (zero) | bdeEfgGiouxX | Pad with zeros, not spaces.
- *    ---------+--------------+-----------------------------------------
- *    *        | all          | Use the next argument as the field width. 
- *             |              | If negative, left-justify the result. If the
- *             |              | asterisk is followed by a number and a dollar 
- *             |              | sign, use the indicated argument as the width.
+ *  The field type characters are:
  *
- *     
- *  The field width is an optional integer, followed optionally by a
- *  period and a precision. The width specifies the minimum number of
- *  characters that will be written to the result for this field. For
- *  numeric fields, the precision controls the number of decimal places
- *  displayed. For string fields, the precision determines the maximum
- *  number of characters to be copied from the string. (Thus, the format
- *  sequence <code>%10.10s</code> will always contribute exactly ten
- *  characters to the result.)
- *
- *  The field types are:
- *
- *      Field |  Conversion
+ *      Field |  Integer Format
  *      ------+--------------------------------------------------------------
  *        b   | Convert argument as a binary number.
- *        c   | Argument is the numeric code for a single character.
+ *            | Negative numbers will be displayed as a two's complement
+ *            | prefixed with `..1'.
+ *        B   | Equivalent to `b', but uses an uppercase 0B for prefix
+ *            | in the alternative format by #.
  *        d   | Convert argument as a decimal number.
+ *        i   | Identical to `d'.
+ *        o   | Convert argument as an octal number.
+ *            | Negative numbers will be displayed as a two's complement
+ *            | prefixed with `..7'.
+ *        u   | Identical to `d'.
+ *        x   | Convert argument as a hexadecimal number.
+ *            | Negative numbers will be displayed as a two's complement
+ *            | prefixed with `..f' (representing an infinite string of
+ *            | leading 'ff's).
+ *        X   | Equivalent to `x', but uses uppercase letters.
+ *
+ *      Field |  Float Format
+ *      ------+--------------------------------------------------------------
+ *        e   | Convert floating point argument into exponential notation 
+ *            | with one digit before the decimal point as [-]d.dddddde[+-]dd.
+ *            | The precision specifies the number of digits after the decimal
+ *            | point (defaulting to six).
  *        E   | Equivalent to `e', but uses an uppercase E to indicate
  *            | the exponent.
- *        e   | Convert floating point argument into exponential notation 
- *            | with one digit before the decimal point. The precision
- *            | determines the number of fractional digits (defaulting to six).
- *        f   | Convert floating point argument as [-]ddd.ddd, 
- *            |  where the precision determines the number of digits after
+ *        f   | Convert floating point argument as [-]ddd.dddddd, 
+ *            | where the precision specifies the number of digits after
  *            | the decimal point.
- *        G   | Equivalent to `g', but use an uppercase `E' in exponent form.
  *        g   | Convert a floating point number using exponential form
  *            | if the exponent is less than -4 or greater than or
- *            | equal to the precision, or in d.dddd form otherwise.
- *        i   | Identical to `d'.
- *        o   | Convert argument as an octal number.
+ *            | equal to the precision, or in dd.dddd form otherwise.
+ *            | The precision specifies the number of significant digits.
+ *        G   | Equivalent to `g', but use an uppercase `E' in exponent form.
+ *
+ *      Field |  Other Format
+ *      ------+--------------------------------------------------------------
+ *        c   | Argument is the numeric code for a single character or
+ *            | a single character string itself.
  *        p   | The valuing of argument.inspect.
- *        s   | Argument is a string to be substituted. If the format
+ *        s   | Argument is a string to be substituted.  If the format
  *            | sequence contains a precision, at most that many characters
  *            | will be copied.
- *        u   | Identical to `d'.
- *        X   | Convert argument as a hexadecimal number using uppercase
- *            | letters. Negative numbers will be displayed with two
- *            | leading periods (representing an infinite string of
- *            | leading 'FF's.
- *        x   | Convert argument as a hexadecimal number.
- *            | Negative numbers will be displayed with two
- *            | leading periods (representing an infinite string of
- *            | leading 'ff's.
  *     
+ *  The flags modifies the behavior of the formats.
+ *  The flag characters are:
+ *
+ *    Flag     | Applies to    | Meaning
+ *    ---------+---------------+-----------------------------------------
+ *    space    | bBdiouxX      | Leave a space at the start of 
+ *             | eEfgG         | non-negative numbers.
+ *             | (numeric fmt) | For `o', `x', `X', `b' and `B', use
+ *             |               | a minus sign with absolute value for
+ *             |               | negative values.
+ *    ---------+---------------+-----------------------------------------
+ *    (digit)$ | all           | Specifies the absolute argument number
+ *             |               | for this field.  Absolute and relative
+ *             |               | argument numbers cannot be mixed in a
+ *             |               | sprintf string.
+ *    ---------+---------------+-----------------------------------------
+ *     #       | bBoxX         | Use an alternative format.
+ *             | eEfgG         | For the conversions `o', increase the precision
+ *             |               | until the first digit will be `0' if
+ *             |               | it is not formatted as complements.
+ *             |               | For the conversions `x', `X', `b' and `B'
+ *             |               | on non-zero, prefix the result with ``0x'',
+ *             |               | ``0X'', ``0b'' and ``0B'', respectively.
+ *             |               | For `e', `E', `f', `g', and 'G',
+ *             |               | force a decimal point to be added,
+ *             |               | even if no digits follow.
+ *             |               | For `g' and 'G', do not remove trailing zeros.
+ *    ---------+---------------+-----------------------------------------
+ *    +        | bBdiouxX      | Add a leading plus sign to non-negative
+ *             | eEfgG         | numbers.
+ *             | (numeric fmt) | For `o', `x', `X', `b' and `B', use
+ *             |               | a minus sign with absolute value for
+ *             |               | negative values.
+ *    ---------+---------------+-----------------------------------------
+ *    -        | all           | Left-justify the result of this conversion.
+ *    ---------+---------------+-----------------------------------------
+ *    0 (zero) | bBdiouxX      | Pad with zeros, not spaces.
+ *             | eEfgG         | For `o', `x', `X', `b' and `B', radix-1
+ *             | (numeric fmt) | is used for negative numbers formatted as
+ *             |               | complements.
+ *    ---------+---------------+-----------------------------------------
+ *    *        | all           | Use the next argument as the field width. 
+ *             |               | If negative, left-justify the result. If the
+ *             |               | asterisk is followed by a number and a dollar 
+ *             |               | sign, use the indicated argument as the width.
+ *
+ *  Examples of flags:
+ *
+ *   # `+' and space flag specifies the sign of non-negative numbers.
+ *   sprintf("%d", 123)  #=> "123"
+ *   sprintf("%+d", 123) #=> "+123"
+ *   sprintf("% d", 123) #=> " 123"
+ *
+ *   # `#' flag for `o' increases number of digits to show `0'.
+ *   # `+' and space flag changes format of negative numbers.
+ *   sprintf("%o", 123)   #=> "173"
+ *   sprintf("%#o", 123)  #=> "0173"
+ *   sprintf("%+o", -123) #=> "-173"
+ *   sprintf("%o", -123)  #=> "..7605"
+ *   sprintf("%#o", -123) #=> "..7605"
+ *
+ *   # `#' flag for `x' add a prefix `0x' for non-zero numbers.
+ *   # `+' and space flag disables complements for negative numbers.
+ *   sprintf("%x", 123)   #=> "7b"
+ *   sprintf("%#x", 123)  #=> "0x7b"
+ *   sprintf("%+x", -123) #=> "-7b"
+ *   sprintf("%x", -123)  #=> "..f85"
+ *   sprintf("%#x", -123) #=> "0x..f85"
+ *   sprintf("%#x", 0)    #=> "0"
+ *
+ *   # `#' for `X' uses the prefix `0X'.
+ *   sprintf("%X", 123)  #=> "7B"
+ *   sprintf("%#X", 123) #=> "0X7B"
+ *
+ *   # `#' flag for `b' add a prefix `0b' for non-zero numbers.
+ *   # `+' and space flag disables complements for negative numbers.
+ *   sprintf("%b", 123)   #=> "1111011"
+ *   sprintf("%#b", 123)  #=> "0b1111011"
+ *   sprintf("%+b", -123) #=> "-1111011"
+ *   sprintf("%b", -123)  #=> "..10000101"
+ *   sprintf("%#b", -123) #=> "0b..10000101"
+ *   sprintf("%#b", 0)    #=> "0"
+ *
+ *   # `#' for `B' uses the prefix `0B'.
+ *   sprintf("%B", 123)  #=> "1111011"
+ *   sprintf("%#B", 123) #=> "0B1111011"
+ *
+ *   # `#' for `e' forces to show the decimal point.
+ *   sprintf("%.0e", 1)  #=> "1e+00"
+ *   sprintf("%#.0e", 1) #=> "1.e+00"
+ *
+ *   # `#' for `f' forces to show the decimal point.
+ *   sprintf("%.0f", 1234)  #=> "1234"
+ *   sprintf("%#.0f", 1234) #=> "1234."
+ *
+ *   # `#' for `g' forces to show the decimal point.
+ *   # It also disables stripping lowest zeros.
+ *   sprintf("%g", 123.4)   #=> "123.4"
+ *   sprintf("%#g", 123.4)  #=> "123.400"
+ *   sprintf("%g", 123456)  #=> "123456"
+ *   sprintf("%#g", 123456) #=> "123456."
+ *     
+ *  The field width is an optional integer, followed optionally by a
+ *  period and a precision.  The width specifies the minimum number of
+ *  characters that will be written to the result for this field.
+ *
+ *  Examples of width:
+ *
+ *   # padding is done by spaces,       width=20
+ *   # 0 or radix-1.             <------------------>
+ *   sprintf("%20d", 123)   #=> "                 123"
+ *   sprintf("%+20d", 123)  #=> "                +123"
+ *   sprintf("%020d", 123)  #=> "00000000000000000123"
+ *   sprintf("%+020d", 123) #=> "+0000000000000000123"
+ *   sprintf("% 020d", 123) #=> " 0000000000000000123"
+ *   sprintf("%-20d", 123)  #=> "123                 "
+ *   sprintf("%-+20d", 123) #=> "+123                "
+ *   sprintf("%- 20d", 123) #=> " 123                "
+ *   sprintf("%020x", -123) #=> "..ffffffffffffffff85"
+ *
+ *  For
+ *  numeric fields, the precision controls the number of decimal places
+ *  displayed.  For string fields, the precision determines the maximum
+ *  number of characters to be copied from the string.  (Thus, the format
+ *  sequence <code>%10.10s</code> will always contribute exactly ten
+ *  characters to the result.)
+ *
+ *  Examples of precisions:
+ *
+ *   # precision for `d', 'o', 'x' and 'b' is
+ *   # minimum number of digits               <------>
+ *   sprintf("%20.8d", 123)  #=> "            00000123"
+ *   sprintf("%20.8o", 123)  #=> "            00000173"
+ *   sprintf("%20.8x", 123)  #=> "            0000007b"
+ *   sprintf("%20.8b", 123)  #=> "            01111011"
+ *   sprintf("%20.8d", -123) #=> "           -00000123"
+ *   sprintf("%20.8o", -123) #=> "            ..777605"
+ *   sprintf("%20.8x", -123) #=> "            ..ffff85"
+ *   sprintf("%20.8b", -11)  #=> "            ..110101"
+ *
+ *   # "0x" and "0b" for `#x' and `#b' is not counted for
+ *   # precision but "0" for `#o' is counted.  <------>
+ *   sprintf("%#20.8d", 123)  #=> "            00000123"
+ *   sprintf("%#20.8o", 123)  #=> "            00000173"
+ *   sprintf("%#20.8x", 123)  #=> "          0x0000007b"
+ *   sprintf("%#20.8b", 123)  #=> "          0b01111011"
+ *   sprintf("%#20.8d", -123) #=> "           -00000123"
+ *   sprintf("%#20.8o", -123) #=> "            ..777605"
+ *   sprintf("%#20.8x", -123) #=> "          0x..ffff85"
+ *   sprintf("%#20.8b", -11)  #=> "          0b..110101"
+ *
+ *   # precision for `e' is number of
+ *   # digits after the decimal point           <------>
+ *   sprintf("%20.8e", 1234.56789) #=> "      1.23456789e+03"
+ *                                    
+ *   # precision for `f' is number of
+ *   # digits after the decimal point               <------>
+ *   sprintf("%20.8f", 1234.56789) #=> "       1234.56789000"
+ *
+ *   # precision for `g' is number of
+ *   # significant digits                          <------->
+ *   sprintf("%20.8g", 1234.56789) #=> "           1234.5679"
+ *
+ *   #                                         <------->
+ *   sprintf("%20.8g", 123456789)  #=> "       1.2345679e+08"
+ *
+ *   # precision for `s' is
+ *   # maximum number of characters                    <------>
+ *   sprintf("%20.8s", "string test") #=> "            string t"
+ *     
  *  Examples:
  *
  *     sprintf("%d %04x", 123, 123)               #=> "123 007b"
@@ -767,7 +915,7 @@
 		if (isnan(fval) || isinf(fval)) {
 		    const char *expr;
 
-		    if  (isnan(fval)) {
+		    if (isnan(fval)) {
 			expr = "NaN";
 		    }
 		    else {
@@ -790,29 +938,13 @@
 			    blen++;
 			strncpy(&buf[blen], expr, strlen(expr));
 		    }
-		    else if (flags & FZERO) {
-			if (!isnan(fval) && fval < 0.0) {
-			    buf[blen++] = '-';
-			    need--;
-			}
-			else if (flags & FPLUS) {
-			    buf[blen++] = '+';
-			    need--;
-			}
-			else if (flags & FSPACE) {
-			    blen++;
-			    need--;
-			}
-			while (need-- - strlen(expr) > 0) {
-			    buf[blen++] = '0';
-			}
-			strncpy(&buf[blen], expr, strlen(expr));
-		    }
 		    else {
 			if (!isnan(fval) && fval < 0.0)
 			    buf[blen + need - strlen(expr) - 1] = '-';
 			else if (flags & FPLUS)
 			    buf[blen + need - strlen(expr) - 1] = '+';
+			else if ((flags & FSPACE) && need > width)
+			    blen++;
 			strncpy(&buf[blen + need - strlen(expr)], expr,
 				strlen(expr));
 		    }

Modified: MacRuby/trunk/st.c
===================================================================
--- MacRuby/trunk/st.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/st.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -83,7 +83,7 @@
 /*
 Table of prime numbers 2^n+a, 2<=n<=30.
 */
-static long primes[] = {
+static const long primes[] = {
 	8 + 3,
 	16 + 3,
 	32 + 5,

Modified: MacRuby/trunk/string.c
===================================================================
--- MacRuby/trunk/string.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/string.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   string.c -
 
-  $Author: matz $
+  $Author: mame $
   created at: Mon Aug  9 17:12:58 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -251,9 +251,9 @@
 static inline const char *
 search_nonascii(const char *p, const char *e)
 {
-#if ULONG_MAX == 18446744073709551615UL
-# define NONASCII_MASK 0x8080808080808080UL
-#elif ULONG_MAX == 4294967295UL
+#if SIZEOF_VALUE == 8
+# define NONASCII_MASK 0x8080808080808080LL
+#elif SIZEOF_VALUE == 4
 # define NONASCII_MASK 0x80808080UL
 #endif
 #ifdef NONASCII_MASK
@@ -1190,8 +1190,8 @@
  *  the values to be substituted. See <code>Kernel::sprintf</code> for details
  *  of the format string.
  *     
- *     "%05d" % 123                       #=> "00123"
- *     "%-5s: %08x" % [ "ID", self.id ]   #=> "ID   : 200e14d6"
+ *     "%05d" % 123                              #=> "00123"
+ *     "%-5s: %08x" % [ "ID", self.object_id ]   #=> "ID   : 200e14d6"
  */
 
 static VALUE
@@ -1205,7 +1205,7 @@
     return rb_str_format(1, &arg, str);
 }
 
-static void
+static inline void
 str_modifiable(VALUE str)
 {
 #if WITH_OBJC
@@ -2645,6 +2645,7 @@
  *     "hello".index('e')             #=> 1
  *     "hello".index('lo')            #=> 3
  *     "hello".index('a')             #=> nil
+ *     "hello".index(?e)              #=> 1
  *     "hello".index(101)             #=> 1
  *     "hello".index(/[aeiou]/, -3)   #=> 4
  */
@@ -2772,6 +2773,7 @@
  *     "hello".rindex('e')             #=> 1
  *     "hello".rindex('l')             #=> 3
  *     "hello".rindex('a')             #=> nil
+ *     "hello".rindex(?e)              #=> 1
  *     "hello".rindex(101)             #=> 1
  *     "hello".rindex(/[aeiou]/, -2)   #=> 1
  */
@@ -2842,7 +2844,7 @@
  *  <code>=~</code> in <code>Object</code> returns <code>false</code>.
  *     
  *     "cat o' 9 tails" =~ /\d/   #=> 7
- *     "cat o' 9 tails" =~ 9      #=> false
+ *     "cat o' 9 tails" =~ 9      #=> nil
  */
 
 static VALUE
@@ -2873,7 +2875,7 @@
  *  parameter is present, it specifies the position in the string to begin the
  *  search.
  *     
- *     'hello'.match('(.)\1')      #=> #<MatchData "ll" "l">
+ *     'hello'.match('(.)\1')      #=> #<MatchData "ll" 1:"l">
  *     'hello'.match('(.)\1')[0]   #=> "ll"
  *     'hello'.match(/(.)\1/)[0]   #=> "ll"
  *     'hello'.match('xx')         #=> nil
@@ -3693,7 +3695,7 @@
  *  deleted.
  *     
  *     string = "this is a string"
- *     string.slice!(2)        #=> 105
+ *     string.slice!(2)        #=> "i"
  *     string.slice!(3..6)     #=> " is "
  *     string.slice!(/s.*t/)   #=> "sa st"
  *     string.slice!("r")      #=> "r"
@@ -3891,7 +3893,7 @@
  *     
  *     "hello".sub(/[aeiou]/, '*')                  #=> "h*llo"
  *     "hello".sub(/([aeiou])/, '<\1>')             #=> "h<e>llo"
- *     "hello".sub(/./) {|s| s[0].to_s + ' ' }      #=> "104 ello"
+ *     "hello".sub(/./) {|s| s[0].ord.to_s + ' ' }  #=> "104 ello"
  *     "hello".sub(/(?<foo>[aeiou])/, '*\k<foo>*')  #=> "h*e*llo"
  */
 
@@ -3926,7 +3928,7 @@
 	if (NIL_P(hash)) {
 	    StringValue(repl);
 	}
-	if (rb_obj_tainted(repl) == Qtrue) tainted = 1;
+	if (OBJ_TAINTED(repl)) tainted = 1;
 	break;
       default:
 	rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc);
@@ -3978,7 +3980,7 @@
 	    val = rb_reg_regsub(repl, str, regs, pat);
 	}
 
-	if (rb_obj_tainted(val) == Qtrue) tainted = 1;
+	if (OBJ_TAINTED(val)) tainted = 1;
 
 	len = beg - offset;	/* copy pre-match substr */
         if (len) {
@@ -4083,7 +4085,7 @@
  *     
  *     "hello".gsub(/[aeiou]/, '*')                  #=> "h*ll*"
  *     "hello".gsub(/([aeiou])/, '<\1>')             #=> "h<e>ll<o>"
- *     "hello".gsub(/./) {|s| s[0].to_s + ' '}       #=> "104 101 108 108 111 "
+ *     "hello".gsub(/./) {|s| s[0].ord.to_s + ' '}   #=> "104 101 108 108 111 "
  *     "hello".gsub(/(?<foo>[aeiou])/, '{\k<foo>}')  #=> "h{e}ll{o}"
  */
 
@@ -4389,13 +4391,15 @@
 static VALUE
 rb_str_to_i(int argc, VALUE *argv, VALUE str)
 {
-    VALUE b;
     int base;
 
-    rb_scan_args(argc, argv, "01", &b);
     if (argc == 0) base = 10;
-    else base = NUM2INT(b);
+    else {
+	VALUE b;
 
+	rb_scan_args(argc, argv, "01", &b);
+	base = NUM2INT(b);
+    }
     if (base < 0) {
 	rb_raise(rb_eArgError, "invalid radix %d", base);
     }
@@ -4478,7 +4482,7 @@
  *
  *    str = "hello"
  *    str[3] = "\b"
- *    str.inspect       #=> "\"hel\bo\""
+ *    str.inspect       #=> "\"hel\\bo\""
  */
 
 VALUE
@@ -6409,9 +6413,8 @@
  *  
  *  Splits <i>str</i> using the supplied parameter as the record separator
  *  (<code>$/</code> by default), passing each substring in turn to the supplied
- *  block. If a zero-length record separator is supplied, the string is split on
- *  <code>\n</code> characters, except that multiple successive newlines are
- *  appended together.
+ *  block. If a zero-length record separator is supplied, the string is split
+ *  into paragraphs delimited by multiple successive newlines.
  *     
  *     print "Example one\n"
  *     "hello\nworld".each {|s| p s}
@@ -6513,9 +6516,12 @@
     VALUE line;
     int n;
 
-    if (rb_scan_args(argc, argv, "01", &rs) == 0) {
+    if (argc == 0) {
 	rs = rb_rs;
     }
+    else {
+	rb_scan_args(argc, argv, "01", &rs);
+    }
     RETURN_ENUMERATOR(str, argc, argv);
     if (NIL_P(rs)) {
 	rb_yield(str);
@@ -7484,11 +7490,13 @@
     char *ptr, *p, *pend;
     long len;
 
-    if (rb_scan_args(argc, argv, "01", &vbits) == 0) {
+    if (argc == 0) {
 	bits = 16;
     }
-    else bits = NUM2INT(vbits);
-
+    else {
+	rb_scan_args(argc, argv, "01", &vbits);
+	bits = NUM2INT(vbits);
+    }
     ptr = p = RSTRING_PTR(str);
     len = RSTRING_LEN(str);
     pend = p + len;
@@ -7981,9 +7989,9 @@
  *     def Fred()
  *     end
  *     $f3 = :Fred
- *     $f1.id   #=> 2514190
- *     $f2.id   #=> 2514190
- *     $f3.id   #=> 2514190
+ *     $f1.object_id   #=> 2514190
+ *     $f2.object_id   #=> 2514190
+ *     $f3.object_id   #=> 2514190
  *     
  */
 
@@ -8007,26 +8015,6 @@
 
 /*
  *  call-seq:
- *     sym.to_i      => fixnum
- *  
- *  Returns an integer that is unique for each symbol within a
- *  particular execution of a program.
- *     
- *     :fred.to_i           #=> 9809
- *     "fred".to_sym.to_i   #=> 9809
- */
-
-static VALUE
-sym_to_i(VALUE sym)
-{
-    ID id = SYM2ID(sym);
-
-    return LONG2FIX(id);
-}
-
-
-/*
- *  call-seq:
  *     sym.inspect    => string
  *  
  *  Returns the representation of <i>sym</i> as a symbol literal.
@@ -8542,7 +8530,6 @@
     rb_define_singleton_method(rb_cSymbol, "all_symbols", rb_sym_all_symbols, 0); /* in parse.y */
 
     rb_define_method(rb_cSymbol, "==", sym_equal, 1);
-    rb_define_method(rb_cSymbol, "to_i", sym_to_i, 0);
     rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
     rb_define_method(rb_cSymbol, "to_s", rb_sym_to_s, 0);
     rb_define_method(rb_cSymbol, "id2name", rb_sym_to_s, 0);

Modified: MacRuby/trunk/struct.c
===================================================================
--- MacRuby/trunk/struct.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/struct.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   struct.c -
 
-  $Author: akr $
+  $Author: matz $
   created at: Tue Mar 22 18:44:30 JST 1995
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -86,7 +86,7 @@
  *     
  *     Customer = Struct.new(:name, :address, :zip)
  *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
- *     joe.members   #=> ["name", "address", "zip"]
+ *     joe.members   #=> [:name, :address, :zip]
  */
 
 static VALUE
@@ -131,7 +131,7 @@
 
 #define N_REF_FUNC (sizeof(ref_func) / sizeof(ref_func[0]))
 
-static VALUE (*ref_func[])(VALUE) = {
+static VALUE (*const ref_func[])(VALUE) = {
     rb_struct_ref0,
     rb_struct_ref1,
     rb_struct_ref2,
@@ -185,14 +185,14 @@
 	rb_class_inherited(klass, nstr);
     }
     else {
-	char *cname = StringValuePtr(name);
-
-	id = rb_intern(cname);
+	/* old style: should we warn? */
+	name = rb_str_to_str(name);
+	id = rb_to_id(name);
 	if (!rb_is_const_id(id)) {
-	    rb_name_error(id, "identifier %s needs to be constant", cname);
+	    rb_name_error(id, "identifier %s needs to be constant", StringValuePtr(name));
 	}
 	if (rb_const_defined_at(klass, id)) {
-	    rb_warn("redefining constant Struct::%s", cname);
+	    rb_warn("redefining constant Struct::%s", StringValuePtr(name));
 	    rb_mod_remove_const(klass, ID2SYM(id));
 	}
 	nstr = rb_define_class_under(klass, rb_id2name(id), klass);
@@ -312,11 +312,11 @@
  *     
  *     # Create a structure with a name in Struct
  *     Struct.new("Customer", :name, :address)    #=> Struct::Customer
- *     Struct::Customer.new("Dave", "123 Main")   #=> #<Struct::Customer name="Dave", address="123 Main">
+ *     Struct::Customer.new("Dave", "123 Main")   #=> #<struct Struct::Customer name="Dave", address="123 Main">
  *     
  *     # Create a structure named by its constant
  *     Customer = Struct.new(:name, :address)     #=> Customer
- *     Customer.new("Dave", "123 Main")           #=> #<Customer name="Dave", address="123 Main">
+ *     Customer.new("Dave", "123 Main")           #=> #<struct Customer name="Dave", address="123 Main">
  */
 
 static VALUE
@@ -328,14 +328,14 @@
     ID id;
 
     rb_scan_args(argc, argv, "1*", &name, &rest);
-    for (i=0; i<RARRAY_LEN(rest); i++) {
-	id = rb_to_id(RARRAY_AT(rest, i));
-	rb_ary_store(rest, i, ID2SYM(id));
-    }
     if (!NIL_P(name) && SYMBOL_P(name)) {
 	rb_ary_unshift(rest, name);
 	name = Qnil;
     }
+    for (i=0; i<RARRAY_LEN(rest); i++) {
+	id = rb_to_id(RARRAY_PTR(rest)[i]);
+	rb_ary_store(rest, i, ID2SYM(id));
+    }
     st = make_struct(name, rest, klass);
     if (rb_block_given_p()) {
 	rb_mod_module_eval(0, 0, st);

Modified: MacRuby/trunk/template/insns.inc.tmpl
===================================================================
--- MacRuby/trunk/template/insns.inc.tmpl	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/template/insns.inc.tmpl	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,9 +13,10 @@
 /* BIN : Basic Instruction Name */
 #define BIN(n) YARVINSN_##n
 
-enum{
+enum ruby_vminsn_type {
 <%= insns %>
 };
 
 #define VM_INSTRUCTION_SIZE <%= @insns.size %>
 
+

Modified: MacRuby/trunk/template/insns_info.inc.tmpl
===================================================================
--- MacRuby/trunk/template/insns_info.inc.tmpl	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/template/insns_info.inc.tmpl	2008-05-18 08:10:19 UTC (rev 199)
@@ -11,20 +11,20 @@
 
 <%= insn_type_chars %>
 
-static char *insn_name_info[] = {
+static const char *const insn_name_info[] = {
 <%= insn_names %>
 };
 
-static char *insn_operand_info[] = {
+static const char *const insn_operand_info[] = {
 <%= operands_info %>
 };
 
-static int insn_len_info[] = {
+static const int insn_len_info[] = {
 <%= operands_num_info %>
 };
 
 #ifdef USE_INSN_RET_NUM
-static int insn_stack_push_num_info[] = {
+static const int insn_stack_push_num_info[] = {
 <%= stack_num_info %>
 };
 #endif
@@ -50,13 +50,13 @@
   return insn_len_info[insn];
 }
 
-static char *
+static const char *
 insn_name(int insn)
 {
   return insn_name_info[insn];
 }
 
-static char *
+static const char *
 insn_op_types(int insn)
 {
   return insn_operand_info[insn];

Modified: MacRuby/trunk/template/opt_sc.inc.tmpl
===================================================================
--- MacRuby/trunk/template/opt_sc.inc.tmpl	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/template/opt_sc.inc.tmpl	2008-05-18 08:10:19 UTC (rev 199)
@@ -22,11 +22,11 @@
 
 #define SC_ERROR 0xffffffff
 
-static VALUE sc_insn_info[][SC_STATE_SIZE] = {
+static const VALUE sc_insn_info[][SC_STATE_SIZE] = {
 <%= sc_insn_info %>
 };
 
-static VALUE sc_insn_next[] = {
+static const VALUE sc_insn_next[] = {
 <%= sc_insn_next %>
 };
 

Modified: MacRuby/trunk/template/optunifs.inc.tmpl
===================================================================
--- MacRuby/trunk/template/optunifs.inc.tmpl	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/template/optunifs.inc.tmpl	2008-05-18 08:10:19 UTC (rev 199)
@@ -13,16 +13,16 @@
  */
 
 /*
-  static int UNIFIED_insn_name_1[] = {id, size, ...};
-  static int UNIFIED_insn_name_2[] = {id, size, ...};
+  static const int UNIFIED_insn_name_1[] = {id, size, ...};
+  static const int UNIFIED_insn_name_2[] = {id, size, ...};
   ...
 
-  static *int UNIFIED_insn_name[] = {size,
+  static const int *const UNIFIED_insn_name[] = {size,
     UNIFIED_insn_name_1,
     UNIFIED_insn_name_2, ...};
   ...
   
-  static **int unified_insns_data[] = {
+  static const int *const *const unified_insns_data[] = {
     UNIFIED_insn_nameA,
     UNIFIED_insn_nameB, ...};
  */

Added: MacRuby/trunk/test/erb/hello.erb
===================================================================
--- MacRuby/trunk/test/erb/hello.erb	                        (rev 0)
+++ MacRuby/trunk/test/erb/hello.erb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,4 @@
+= hello
+<% 3.times do |n| %>
+* <%= n %>
+<% end %>

Modified: MacRuby/trunk/test/erb/test_erb.rb
===================================================================
--- MacRuby/trunk/test/erb/test_erb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/erb/test_erb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -9,7 +9,7 @@
     e = assert_raise(MyError) {
       erb.result
     }
-    assert_equal("(erb):1:in `raise'", e.backtrace[0])
+    assert_match(/\A\(erb\):1\b/, e.backtrace[0])
   end
 
   def test_with_filename
@@ -18,7 +18,7 @@
     e = assert_raise(MyError) {
       erb.result
     }
-    assert_equal("test filename:1:in `raise'", e.backtrace[0])
+    assert_match(/\Atest filename:1\b/, e.backtrace[0])
   end
 
   def test_without_filename_with_safe_level
@@ -26,7 +26,7 @@
     e = assert_raise(MyError) {
       erb.result
     }
-    assert_equal("(erb):1:in `raise'", e.backtrace[0])
+    assert_match(/\A\(erb\):1\b/, e.backtrace[0])
   end
 
   def test_with_filename_and_safe_level
@@ -35,6 +35,387 @@
     e = assert_raise(MyError) {
       erb.result
     }
-    assert_equal("test filename:1:in `raise'", e.backtrace[0])
+    assert_match(/\Atest filename:1\b/, e.backtrace[0])
   end
 end
+
+class TestERBCore < Test::Unit::TestCase
+  def setup
+    @erb = ERB
+  end
+
+  def test_core
+    _test_core(nil)
+    _test_core(0)
+    _test_core(1)
+    _test_core(2)
+    _test_core(3)
+  end
+
+  def _test_core(safe)
+    erb = @erb.new("hello")
+    assert_equal(erb.result, "hello")
+
+    erb = @erb.new("hello", safe, 0)
+    assert_equal(erb.result, "hello")
+
+    erb = @erb.new("hello", safe, 1)
+    assert_equal(erb.result, "hello")
+
+    erb = @erb.new("hello", safe, 2)
+    assert_equal(erb.result, "hello")
+
+    src = <<EOS
+%% hi
+= hello
+<% 3.times do |n| %>
+% n=0
+* <%= n %>
+<% end %>
+EOS
+      
+    ans = <<EOS
+%% hi
+= hello
+
+% n=0
+* 0
+
+% n=0
+* 1
+
+% n=0
+* 2
+
+EOS
+    erb = @erb.new(src)
+    assert_equal(ans, erb.result)
+    erb = @erb.new(src, safe, 0)
+    assert_equal(ans, erb.result)
+    erb = @erb.new(src, safe, '')
+    assert_equal(ans, erb.result)
+
+    ans = <<EOS
+%% hi
+= hello
+% n=0
+* 0% n=0
+* 1% n=0
+* 2
+EOS
+    erb = @erb.new(src, safe, 1)
+    assert_equal(ans.chomp, erb.result)
+    erb = @erb.new(src, safe, '>')
+    assert_equal(ans.chomp, erb.result)
+
+    ans  = <<EOS
+%% hi
+= hello
+% n=0
+* 0
+% n=0
+* 1
+% n=0
+* 2
+EOS
+      
+    erb = @erb.new(src, safe, 2)
+    assert_equal(ans, erb.result)
+    erb = @erb.new(src, safe, '<>')
+    assert_equal(ans, erb.result)
+
+    ans = <<EOS
+% hi
+= hello
+
+* 0
+
+* 0
+
+* 0
+
+EOS
+    erb = @erb.new(src, safe, '%')
+    assert_equal(ans, erb.result)
+
+    ans = <<EOS
+% hi
+= hello
+* 0* 0* 0
+EOS
+    erb = @erb.new(src, safe, '%>')
+    assert_equal(ans.chomp, erb.result)
+
+    ans = <<EOS
+% hi
+= hello
+* 0
+* 0
+* 0
+EOS
+    erb = @erb.new(src, safe, '%<>')
+    assert_equal(ans, erb.result)
+  end
+
+  def test_safe_04
+    erb = @erb.new('<%=$SAFE%>', 4)
+    assert_equal(erb.result(TOPLEVEL_BINDING.taint), '4')
+  end
+
+  class Foo; end
+
+  def test_def_class
+    erb = @erb.new('hello')
+    cls = erb.def_class
+    assert_equal(Object, cls.superclass)
+    assert(cls.new.respond_to?('result'))
+    cls = erb.def_class(Foo)
+    assert_equal(Foo, cls.superclass)
+    assert(cls.new.respond_to?('result'))
+    cls = erb.def_class(Object, 'erb')
+    assert_equal(Object, cls.superclass)
+    assert(cls.new.respond_to?('erb'))
+  end
+
+  def test_percent
+    src = <<EOS
+%n = 1
+<%= n%>
+EOS
+    assert_equal("1\n", ERB.new(src, nil, '%').result)
+
+    src = <<EOS
+<%
+%>
+EOS
+    ans = "\n"
+    assert_equal(ans, ERB.new(src, nil, '%').result)
+
+    src = "<%\n%>"
+    # ans = "\n"
+    ans = ""
+    assert_equal(ans, ERB.new(src, nil, '%').result)
+
+    src = <<EOS
+<%
+n = 1
+%><%= n%>
+EOS
+    assert_equal("1\n", ERB.new(src, nil, '%').result)
+
+    src = <<EOS
+%n = 1
+%% <% n = 2
+n.times do |i|%>
+%% %%><%%<%= i%><%
+end%>
+EOS
+    ans = <<EOS
+% 
+% %%><%0
+% %%><%1
+EOS
+    assert_equal(ans, ERB.new(src, nil, '%').result)
+  end
+
+  class Bar; end
+
+  def test_def_method
+    assert(! Bar.new.respond_to?('hello'))
+    Bar.module_eval do
+      extend ERB::DefMethod
+      fname = File.join(File.dirname(File.expand_path(__FILE__)), 'hello.erb')
+      def_erb_method('hello', fname)
+    end
+    assert(Bar.new.respond_to?('hello'))
+
+    assert(! Bar.new.respond_to?('hello_world'))
+    erb = @erb.new('hello, world')
+    Bar.module_eval do
+      def_erb_method('hello_world', erb)
+    end
+    assert(Bar.new.respond_to?('hello_world'))    
+  end
+
+  def test_escape
+    src = <<EOS
+1.<%% : <%="<%%"%>
+2.%%> : <%="%%>"%>
+3.
+% x = "foo"
+<%=x%>
+4.
+%% print "foo"
+5.
+%% <%="foo"%>
+6.<%="
+% print 'foo'
+"%>
+7.<%="
+%% print 'foo'
+"%>
+EOS
+    ans = <<EOS
+1.<% : <%%
+2.%%> : %>
+3.
+foo
+4.
+% print "foo"
+5.
+% foo
+6.
+% print 'foo'
+
+7.
+%% print 'foo'
+
+EOS
+    assert_equal(ans, ERB.new(src, nil, '%').result)
+  end
+
+  def test_keep_lineno
+    src = <<EOS
+Hello, 
+% x = "World"
+<%= x%>
+% raise("lineno")
+EOS
+
+    erb = ERB.new(src, nil, '%')
+    begin
+      erb.result
+      assert(false)
+    rescue
+      assert_match(/\A\(erb\):4\b/, $@[0].to_s)
+    end
+
+    src = <<EOS
+%>
+Hello, 
+<% x = "World%%>
+"%>
+<%= x%>
+EOS
+
+    ans = <<EOS
+%>Hello, 
+World%>
+EOS
+    assert_equal(ans, ERB.new(src, nil, '>').result)
+
+    ans = <<EOS
+%>
+Hello, 
+
+World%>
+EOS
+    assert_equal(ans, ERB.new(src, nil, '<>').result)
+
+    ans = <<EOS
+%>
+Hello, 
+
+World%>
+
+EOS
+    assert_equal(ans, ERB.new(src).result)
+
+    src = <<EOS
+Hello, 
+<% x = "World%%>
+"%>
+<%= x%>
+<% raise("lineno") %>
+EOS
+
+    erb = ERB.new(src)
+    begin
+      erb.result
+      assert(false)
+    rescue
+      assert_match(/\A\(erb\):5\b/, $@[0].to_s)
+    end
+
+    erb = ERB.new(src, nil, '>')
+    begin
+      erb.result
+      assert(false)
+    rescue
+      assert_match(/\A\(erb\):5\b/, $@[0].to_s)
+    end
+
+    erb = ERB.new(src, nil, '<>')
+    begin
+      erb.result
+      assert(false)
+    rescue
+      assert_match(/\A\(erb\):5\b/, $@[0].to_s)
+    end
+
+    src = <<EOS
+% y = 'Hello'
+<%- x = "World%%>
+"-%>
+<%= x %><%- x = nil -%> 
+<% raise("lineno") %>
+EOS
+
+    erb = ERB.new(src, nil, '-')
+    begin
+      erb.result
+      assert(false)
+    rescue
+      assert_match(/\A\(erb\):5\b/, $@[0].to_s)
+    end
+
+    erb = ERB.new(src, nil, '%-')
+    begin
+      erb.result
+      assert(false)
+    rescue
+      assert_match(/\A\(erb\):5\b/, $@[0].to_s)
+    end
+  end
+
+  def test_explicit
+    src = <<EOS
+<% x = %w(hello world) -%>
+NotSkip <%- y = x -%> NotSkip
+<% x.each do |w| -%>
+  <%- up = w.upcase -%>
+  * <%= up %>
+<% end -%>
+ <%- z = nil -%> NotSkip <%- z = x %>
+ <%- z.each do |w| -%>
+   <%- down = w.downcase -%>
+   * <%= down %>
+   <%- up = w.upcase -%>
+   * <%= up %>
+ <%- end -%>
+KeepNewLine <%- z = nil -%> 
+EOS
+
+   ans = <<EOS
+NotSkip  NotSkip
+  * HELLO
+  * WORLD
+ NotSkip 
+   * hello
+   * HELLO
+   * world
+   * WORLD
+KeepNewLine  
+EOS
+   assert_equal(ans, ERB.new(src, nil, '-').result)
+   assert_equal(ans, ERB.new(src, nil, '-%').result)
+  end
+
+  def test_url_encode
+    assert_equal("Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide",
+                 ERB::Util.url_encode("Programming Ruby:  The Pragmatic Programmer's Guide"))
+
+    assert_equal("%A5%B5%A5%F3%A5%D7%A5%EB",
+                 ERB::Util.url_encode("\xA5\xB5\xA5\xF3\xA5\xD7\xA5\xEB".force_encoding("EUC-JP")))
+  end
+end

Modified: MacRuby/trunk/test/gdbm/test_gdbm.rb
===================================================================
--- MacRuby/trunk/test/gdbm/test_gdbm.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/gdbm/test_gdbm.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -92,8 +92,8 @@
       end
     end
     def test_s_open_no_create
-      # this test is failed on libgdbm 1.8.0
-      assert_nil(gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", nil))
+      assert_nil(gdbm = GDBM.open("#{@tmpdir}/#{@prefix}", nil),
+                 "this test is failed on libgdbm 1.8.0")
     ensure
       gdbm.close if gdbm
     end

Modified: MacRuby/trunk/test/io/nonblock/test_flush.rb
===================================================================
--- MacRuby/trunk/test/io/nonblock/test_flush.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/io/nonblock/test_flush.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -5,7 +5,6 @@
 rescue LoadError
 end
 
-Thread.abort_on_exception = true
 class TestIONonblock < Test::Unit::TestCase
   def test_flush
     r,w = IO.pipe

Modified: MacRuby/trunk/test/net/imap/test_imap.rb
===================================================================
--- MacRuby/trunk/test/net/imap/test_imap.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/net/imap/test_imap.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -67,6 +67,7 @@
   end
 
   def test_starttls
+    imap = nil
     if defined?(OpenSSL)
       starttls_test do |port|
         imap = Net::IMAP.new("localhost", :port => port)
@@ -74,6 +75,10 @@
         imap
       end
     end
+  ensure
+    if imap && !imap.disconnected?
+      imap.disconnect
+    end
   end
 
   private
@@ -105,9 +110,12 @@
       end
     end
     begin
-      imap = yield(port)
-      imap.logout
-      imap.disconnect
+      begin
+        imap = yield(port)
+        imap.logout
+      ensure
+        imap.disconnect if imap
+      end
     ensure
       ssl_server.close
     end
@@ -143,9 +151,12 @@
       end
     end
     begin
-      imap = yield(port)
-      imap.logout
-      imap.disconnect
+      begin
+        imap = yield(port)
+        imap.logout
+      ensure
+        imap.disconnect if imap
+      end
     ensure
       server.close
     end

Modified: MacRuby/trunk/test/openssl/test_ssl.rb
===================================================================
--- MacRuby/trunk/test/openssl/test_ssl.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/openssl/test_ssl.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -58,28 +58,84 @@
     OpenSSL::TestUtils.issue_crl(*arg)
   end
 
-  def start_server(port0, verify_mode, start_immediately, &block)
-    server = nil
+  def readwrite_loop(ctx, ssl)
+    while line = ssl.gets
+      if line =~ /^STARTTLS$/
+        ssl.accept
+        next
+      end
+      ssl.write(line)
+    end
+  rescue OpenSSL::SSL::SSLError
+  rescue IOError
+  ensure
+    ssl.close rescue nil
+  end
+
+  def server_loop(ctx, ssls, server_proc)
+    loop do
+      ssl = nil
+      begin
+        ssl = ssls.accept
+      rescue OpenSSL::SSL::SSLError
+      	retry
+      end
+
+      Thread.start do
+        Thread.current.abort_on_exception = true  
+        server_proc.call(ctx, ssl)
+      end
+    end
+  rescue Errno::EBADF, IOError
+  end
+
+  def start_server(port0, verify_mode, start_immediately, args = {}, &block)
+    ctx_proc = args[:ctx_proc]
+    server_proc = args[:server_proc]
+    server_proc ||= method(:readwrite_loop)
+  
+    store = OpenSSL::X509::Store.new
+    store.add_cert(@ca_cert)
+    store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
+    ctx = OpenSSL::SSL::SSLContext.new
+    ctx.cert_store = store
+    #ctx.extra_chain_cert = [ ca_cert ]
+    ctx.cert = @svr_cert
+    ctx.key = @svr_key
+    ctx.verify_mode = verify_mode
+    ctx_proc.call(ctx) if ctx_proc
+
+    Socket.do_not_reverse_lookup = true
+    tcps = nil
+    port = port0
     begin
-      cmd = [RUBY]
-      cmd << "-d" if $DEBUG
-      cmd << SSL_SERVER << port0.to_s << verify_mode.to_s
-      cmd << (start_immediately ? "yes" : "no")
-      server = IO.popen(cmd, "w+")
-      server.write(@ca_cert.to_pem)
-      server.write(@svr_cert.to_pem)
-      server.write(@svr_key.to_pem)
-      pid = Integer(server.gets)
-      if port = server.gets
-        if $DEBUG
-          $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, pid, port)
-        end
-        block.call(server, port.to_i)
+      tcps = TCPServer.new("127.0.0.1", port)
+    rescue Errno::EADDRINUSE
+      port += 1
+      retry
+    end
+
+    ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
+    ssls.start_immediately = start_immediately
+
+    begin
+      server = Thread.new do
+        Thread.current.abort_on_exception = true  
+        server_loop(ctx, ssls, server_proc)
       end
+
+      $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, pid, port) if $DEBUG
+
+      block.call(server, port.to_i)
     ensure
-      if server
-        Process.kill(:KILL, pid)
-        server.close
+      tcps.close if (tcps)
+      if (server)
+        server.join(5)
+        if server.alive?
+          server.kill
+          server.join
+          flunk("TCPServer was closed and SSLServer is still alive") unless $!
+        end
       end
     end
   end
@@ -93,6 +149,12 @@
     ssl.connect
   end
 
+  def test_ctx_setup
+    ctx = OpenSSL::SSL::SSLContext.new
+    assert_equal(ctx.setup, true)
+    assert_equal(ctx.setup, nil)
+  end
+
   def test_connect_and_close
     start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
       sock = TCPSocket.new("127.0.0.1", port)
@@ -182,7 +244,7 @@
 
       called = nil
       ctx = OpenSSL::SSL::SSLContext.new
-      ctx.client_cert_cb = Proc.new{|ssl|
+      ctx.client_cert_cb = Proc.new{ |sslconn|
         called = true
         [@cli_cert, @cli_key]
       }
@@ -360,6 +422,120 @@
       assert(!OpenSSL::SSL.verify_certificate_identity(cert, "foo.example.com"))
     }
   end
+
+  def test_client_session
+    last_session = nil
+    start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) do |server, port|
+      2.times do
+        sock = TCPSocket.new("127.0.0.1", port)
+        ssl = OpenSSL::SSL::SSLSocket.new(sock)
+        ssl.sync_close = true
+        ssl.session = last_session if last_session
+        ssl.connect
+
+        session = ssl.session
+        if last_session
+          assert(ssl.session_reused?)
+
+          if session.respond_to?(:id)
+            assert_equal(session.id, last_session.id)
+          end
+          assert_equal(session.to_pem, last_session.to_pem)
+          assert_equal(session.to_der, last_session.to_der)
+          # Older version of OpenSSL may not be consistent.  Look up which versions later.
+          assert_equal(session.to_text, last_session.to_text)
+        else
+          assert(!ssl.session_reused?)
+        end
+        last_session = session
+
+        str = "x" * 100 + "\n"
+        ssl.puts(str)
+        assert_equal(str, ssl.gets)
+
+        ssl.close
+      end
+    end
+  end
+
+  def test_server_session
+    connections = 0
+    saved_session = nil
+
+    ctx_proc = Proc.new do |ctx, ssl|
+# add test for session callbacks here
+    end
+
+    server_proc = Proc.new do |ctx, ssl|
+      session = ssl.session
+      stats = ctx.session_cache_stats
+
+      case connections
+      when 0
+        assert_equal(stats[:cache_num], 1)
+        assert_equal(stats[:cache_hits], 0)
+        assert_equal(stats[:cache_misses], 0)
+        assert(!ssl.session_reused?)
+      when 1
+        assert_equal(stats[:cache_num], 1)
+        assert_equal(stats[:cache_hits], 1)
+        assert_equal(stats[:cache_misses], 0)
+        assert(ssl.session_reused?)
+        ctx.session_remove(session)
+        saved_session = session
+      when 2
+        assert_equal(stats[:cache_num], 1)
+        assert_equal(stats[:cache_hits], 1)
+        assert_equal(stats[:cache_misses], 1)
+        assert(!ssl.session_reused?)
+        ctx.session_add(saved_session)
+      when 3
+        assert_equal(stats[:cache_num], 2)
+        assert_equal(stats[:cache_hits], 2)
+        assert_equal(stats[:cache_misses], 1)
+        assert(ssl.session_reused?)
+        ctx.flush_sessions(Time.now + 5000)
+      when 4
+        assert_equal(stats[:cache_num], 1)
+        assert_equal(stats[:cache_hits], 2)
+        assert_equal(stats[:cache_misses], 2)
+        assert(!ssl.session_reused?)
+        ctx.session_add(saved_session)
+      end
+      connections += 1
+      
+      readwrite_loop(ctx, ssl)
+    end
+
+    first_session = nil
+    start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true, :ctx_proc => ctx_proc, :server_proc => server_proc) do |server, port|
+      10.times do |i|
+        sock = TCPSocket.new("127.0.0.1", port)
+        ssl = OpenSSL::SSL::SSLSocket.new(sock)
+        ssl.sync_close = true
+        ssl.session = first_session if first_session
+        ssl.connect
+
+        session = ssl.session
+        if first_session
+          case i
+          when 1; assert(ssl.session_reused?)
+          when 2; assert(!ssl.session_reused?)
+          when 3; assert(ssl.session_reused?)
+          when 4; assert(!ssl.session_reused?)
+          when 5..10; assert(ssl.session_reused?)
+          end
+        end
+        first_session ||= session
+
+        str = "x" * 100 + "\n"
+        ssl.puts(str)
+        assert_equal(str, ssl.gets)
+
+        ssl.close
+      end
+    end
+  end
 end
 
 end

Modified: MacRuby/trunk/test/openssl/utils.rb
===================================================================
--- MacRuby/trunk/test/openssl/utils.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/openssl/utils.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -103,9 +103,9 @@
     crl.version = 1
     crl.last_update = lastup
     crl.next_update = nextup
-    revoke_info.each{|serial, time, reason_code|
+    revoke_info.each{|rserial, time, reason_code|
       revoked = OpenSSL::X509::Revoked.new
-      revoked.serial = serial
+      revoked.serial = rserial
       revoked.time = time
       enum = OpenSSL::ASN1::Enumerated(reason_code)
       ext = OpenSSL::X509::Extension.new("CRLReason", enum)

Modified: MacRuby/trunk/test/rdoc/test_rdoc_c_parser.rb
===================================================================
--- MacRuby/trunk/test/rdoc/test_rdoc_c_parser.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rdoc/test_rdoc_c_parser.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -226,7 +226,7 @@
     assert_equal "  \n   a comment for class Foo\n   ", klass.comment
   end
 
-  def test_find_class_comment_define_class
+  def test_find_class_comment_define_class_Init_Foo
     content = <<-EOF
 /*
  * a comment for class Foo on Init

Modified: MacRuby/trunk/test/rdoc/test_rdoc_markup_attribute_manager.rb
===================================================================
--- MacRuby/trunk/test/rdoc/test_rdoc_markup_attribute_manager.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rdoc/test_rdoc_markup_attribute_manager.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -43,6 +43,29 @@
     #assert_equal(["cat {and} dog" ], @am.flow("cat \\{and} dog"))
   end
 
+  def test_add_word_pair
+    @am.add_word_pair '%', '&', 'percent and'
+
+    assert RDoc::Markup::AttributeManager::WORD_PAIR_MAP.include?(/(%)(\S+)(&)/)
+    assert RDoc::Markup::AttributeManager::PROTECTABLE.include?('%')
+    assert !RDoc::Markup::AttributeManager::PROTECTABLE.include?('&')
+  end
+
+  def test_add_word_pair_angle
+    e = assert_raise ArgumentError do
+      @am.add_word_pair '<', '>', 'angles'
+    end
+
+    assert_equal "Word flags may not start with '<'", e.message
+  end
+
+  def test_add_word_pair_matching
+    @am.add_word_pair '^', '^', 'caret'
+
+    assert RDoc::Markup::AttributeManager::MATCHING_WORD_PAIRS.include?('^')
+    assert RDoc::Markup::AttributeManager::PROTECTABLE.include?('^')
+  end
+
   def test_basic
     assert_equal(["cat"], @am.flow("cat"))
 
@@ -79,7 +102,6 @@
 
     assert_equal(["cat ", @em_on, "_", @em_off, " dog"],
                   @am.flow("cat ___ dog"))
-
   end
 
   def test_bold
@@ -101,6 +123,29 @@
                   @am.flow("cat _a__nd_ *dog*"))
   end
 
+  def test_convert_attrs
+    str = '+foo+'
+    attrs = RDoc::Markup::AttrSpan.new str.length
+
+    @am.convert_attrs str, attrs
+
+    assert_equal "\000foo\000", str
+
+    str = '+:foo:+'
+    attrs = RDoc::Markup::AttrSpan.new str.length
+
+    @am.convert_attrs str, attrs
+
+    assert_equal "\000:foo:\000", str
+
+    str = '+x-y+'
+    attrs = RDoc::Markup::AttrSpan.new str.length
+
+    @am.convert_attrs str, attrs
+
+    assert_equal "\000x-y\000", str
+  end
+
   def test_html_like_em_bold
     assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off],
                   @am.flow("cat <i>and </i><b>dog</b>")

Added: MacRuby/trunk/test/rdoc/test_rdoc_ri_default_display.rb
===================================================================
--- MacRuby/trunk/test/rdoc/test_rdoc_ri_default_display.rb	                        (rev 0)
+++ MacRuby/trunk/test/rdoc/test_rdoc_ri_default_display.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,295 @@
+require 'stringio'
+require 'test/unit'
+require 'rdoc/ri/formatter'
+require 'rdoc/ri/display'
+require 'rdoc/ri/driver'
+
+class TestRDocRIDefaultDisplay < Test::Unit::TestCase
+
+  def setup
+    @output = StringIO.new
+    @width = 78
+    @indent = '  '
+
+    @dd = RDoc::RI::DefaultDisplay.new RDoc::RI::Formatter, @width, true,
+                                       @output
+
+    @some_method = {
+      'aliases' => [{'name' => 'some_method_alias'}],
+      'block_params' => 'block_param',
+      'comment' => [RDoc::Markup::Flow::P.new('some comment')],
+      'full_name' => 'SomeClass#some_method',
+      'is_singleton' => false,
+      'name' => 'some_method',
+      'params' => '(arg1, arg2) {|block_param| ...}',
+      'source_path' => '/nonexistent',
+      'visibility' => 'public',
+    }
+  end
+
+  def test_display_class_info
+    ri_reader = nil
+    klass = {
+      'attributes' => [
+        { 'name' => 'attribute', 'rw' => 'RW',
+          'comment' => [RDoc::Markup::Flow::P.new('attribute comment')] },
+        { 'name' => 'attribute_no_comment', 'rw' => 'RW',
+          'comment' => nil },
+      ],
+      'class_methods' => [
+        { 'name' => 'class_method' },
+      ],
+      'class_method_extensions' => [
+        { 'name' => 'class_method_extension' },
+      ],
+      'comment' => [RDoc::Markup::Flow::P.new('SomeClass comment')],
+      'constants' => [
+        { 'name' => 'CONSTANT', 'value' => '"value"',
+          'comment' => [RDoc::Markup::Flow::P.new('CONSTANT value')] },
+        { 'name' => 'CONSTANT_NOCOMMENT', 'value' => '"value"',
+          'comment' => nil },
+      ],
+      'display_name' => 'Class',
+      'full_name' => 'SomeClass',
+      'includes' => [],
+      'instance_methods' => [
+        { 'name' => 'instance_method' },
+      ],
+      'instance_method_extensions' => [
+        { 'name' => 'instance_method_extension' },
+      ],
+      'superclass_string' => 'Object',
+    }
+
+    @dd.display_class_info klass, ri_reader
+
+    expected = <<-EOF
+---------------------------------------------------- Class: SomeClass < Object
+     SomeClass comment
+
+------------------------------------------------------------------------------
+
+
+Constants:
+----------
+
+     CONSTANT:
+          CONSTANT value
+
+     CONSTANT_NOCOMMENT
+
+
+Class methods:
+--------------
+
+     class_method
+
+
+Class method extensions:
+------------------------
+
+     class_method_extension
+
+
+Instance methods:
+-----------------
+
+     instance_method
+
+
+Instance method extensions:
+---------------------------
+
+     instance_method_extension
+
+
+Attributes:
+-----------
+
+     attribute (RW):
+          attribute comment
+
+     attribute_no_comment (RW)
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_flow
+    flow = [RDoc::Markup::Flow::P.new('flow')]
+
+    @dd.display_flow flow
+
+    assert_equal "     flow\n\n", @output.string
+  end
+
+  def test_display_flow_empty
+    @dd.display_flow []
+
+    assert_equal "     [no description]\n", @output.string
+  end
+
+  def test_display_flow_nil
+    @dd.display_flow nil
+
+    assert_equal "     [no description]\n", @output.string
+  end
+
+  def test_display_method_info
+    @dd.display_method_info @some_method
+
+    expected = <<-EOF
+-------------------------------------------------------- SomeClass#some_method
+     some_method(arg1, arg2) {|block_param| ...}
+
+     Extension from /nonexistent
+------------------------------------------------------------------------------
+     some comment
+
+
+     (also known as some_method_alias)
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_method_info_singleton
+    method = {
+      'aliases' => [],
+      'block_params' => nil,
+      'comment' => nil,
+      'full_name' => 'SomeClass::some_method',
+      'is_singleton' => true,
+      'name' => 'some_method',
+      'params' => '(arg1, arg2)',
+      'visibility' => 'public',
+    }
+
+    @dd.display_method_info method
+
+    expected = <<-EOF
+------------------------------------------------------- SomeClass::some_method
+     SomeClass::some_method(arg1, arg2)
+------------------------------------------------------------------------------
+     [no description]
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_method_list
+    methods = [
+      {
+        "aliases" => [],
+        "block_params" => nil,
+        "comment" =>  nil,
+        "full_name" => "SomeClass#some_method",
+        "is_singleton" => false,
+        "name" => "some_method",
+        "params" => "()",
+        "visibility" => "public",
+      },
+      {
+        "aliases" => [],
+        "block_params" => nil,
+        "comment" => nil,
+        "full_name" => "SomeClass#some_other_method",
+        "is_singleton" => false,
+        "name" => "some_other_method",
+        "params" => "()",
+        "visibility" => "public",
+      },
+    ]
+
+    @dd.display_method_list methods
+
+    expected = <<-EOF
+     More than one method matched your request.  You can refine your search by
+     asking for information on one of:
+
+     SomeClass#some_method, SomeClass#some_other_method
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_params
+    @dd.display_params @some_method
+
+    expected = <<-EOF
+     some_method(arg1, arg2) {|block_param| ...}
+
+     Extension from /nonexistent
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_params_multiple
+    @some_method['params'] = <<-EOF
+some_method(index)
+some_method(start, length)
+    EOF
+
+    @dd.display_params @some_method
+
+    expected = <<-EOF
+     some_method(index)
+     some_method(start, length)
+
+     Extension from /nonexistent
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_params_singleton
+    @some_method['is_singleton'] = true
+    @some_method['full_name'] = 'SomeClass::some_method'
+
+    @dd.display_params @some_method
+
+    expected = <<-EOF
+     SomeClass::some_method(arg1, arg2) {|block_param| ...}
+
+     Extension from /nonexistent
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_list_known_classes
+    klasses = %w[SomeClass SomeModule]
+
+    @dd.list_known_classes klasses
+
+    expected = <<-EOF
+---------------------------------------------------- Known classes and modules
+
+     SomeClass, SomeModule
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_list_known_classes_empty
+    @dd.list_known_classes []
+
+    expected = <<-EOF
+No ri data found
+
+If you've installed Ruby yourself, you need to generate documentation using:
+
+  make install-doc
+
+from the same place you ran `make` to build ruby.
+
+If you installed Ruby from a packaging system, then you may need to
+install an additional package, or ask the packager to enable ri generation.
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+end
+

Modified: MacRuby/trunk/test/rdoc/test_rdoc_ri_formatter.rb
===================================================================
--- MacRuby/trunk/test/rdoc/test_rdoc_ri_formatter.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rdoc/test_rdoc_ri_formatter.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -149,43 +149,6 @@
     assert_equal "  *   a b c\n\n", @output.string
   end
 
-  def test_display_heading_1
-    @f.display_heading 'heading', 1, '  '
-
-    assert_equal "\nHEADING\n=======\n\n", @output.string
-  end
-
-  def test_display_heading_2
-    @f.display_heading 'heading', 2, '  '
-
-    assert_equal "\nheading\n-------\n\n", @output.string
-  end
-
-  def test_display_heading_3
-    @f.display_heading 'heading', 3, '  '
-
-    assert_equal "  heading\n\n", @output.string
-  end
-
-  def test_display_list
-    list = RDoc::Markup::Flow::LIST.new :NUMBER
-    list << RDoc::Markup::Flow::LI.new(nil, 'a b c')
-    list << RDoc::Markup::Flow::LI.new(nil, 'd e f')
-
-    @f.display_list list
-
-    assert_equal "  1.  a b c\n\n  2.  d e f\n\n", @output.string
-  end
-
-  def test_display_list_bullet
-    list = RDoc::Markup::Flow::LIST.new :BULLET
-    list << RDoc::Markup::Flow::LI.new(nil, 'a b c')
-
-    @f.display_list list
-
-    assert_equal "  *   a b c\n\n", @output.string
-  end
-
   def test_display_list_labeled
     list = RDoc::Markup::Flow::LIST.new :LABELED
     list << RDoc::Markup::Flow::LI.new('label', 'a b c')

Added: MacRuby/trunk/test/ruby/allpairs.rb
===================================================================
--- MacRuby/trunk/test/ruby/allpairs.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/allpairs.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,103 @@
+module AllPairs
+  module_function
+
+  def make_prime(v)
+    return 2 if v < 2
+    ary = [true] * (v*2)
+    2.upto(Math.sqrt(ary.length).ceil) {|i|
+      return i if ary[i] && v <= i
+      (i*2).step(ary.length, i) {|j|
+        ary[j] = false
+      }
+    }
+    v.upto(ary.length-1) {|i|
+      return i if ary[i]
+    }
+    raise "[bug] prime not found greater than #{v}"
+  end
+
+  def make_basic_block(prime)
+    prime.times {|i|
+      prime.times {|j|
+        row = [i]
+        0.upto(prime-1) {|m|
+          row << (i*m + j) % prime
+        }
+        yield row
+      }
+    }
+  end 
+
+  def combine_block(tbl1, tbl2)
+    result = []
+    tbl2.each {|row|
+      result << row * tbl1.first.length
+    }
+    tbl1.each_with_index {|row, k|
+      next if k == 0
+      result << row.map {|i| [i] * tbl2.first.length }.flatten
+    }
+    result
+  end
+
+  def make_large_block(v, prime)
+    if prime <= v+1
+      make_basic_block(v) {|row|
+        yield row
+      }
+    else
+      tbl = []
+      make_basic_block(v) {|row|
+        tbl << row
+      } 
+      tbls = [tbl]
+      while tbl.first.length ** 2 < prime
+        tbl = combine_block(tbl, tbl)
+        tbls << tbl
+      end
+      tbl1 = tbls.find {|t| prime <= t.first.length * tbl.first.length }
+      tbl = combine_block(tbl, tbl1)
+      tbl.each {|row|
+        yield row
+      }
+    end
+  end
+
+  def each_index(*vs)
+    n = vs.length
+    max_v = vs.max
+    prime = make_prime(max_v)
+    h = {}
+    make_large_block(max_v, n) {|row|
+      row = vs.zip(row).map {|v, i| i % v }
+      next if h[row]
+      h[row] = true
+      yield row
+    }
+  end
+
+  # generate all pairs test.
+  def each(*args)
+    args.map! {|a| a.to_a }
+    each_index(*args.map {|a| a.length}) {|is|
+      yield is.zip(args).map {|i, a| a[i] }
+    }
+  end
+
+  # generate all combination in cartesian product.  (not all-pairs test)
+  def exhaustive_each(*args)
+    args = args.map {|a| a.to_a }
+    i = 0
+    while true
+      n = i
+      as = []
+      args.reverse_each {|a|
+        n, m = n.divmod(a.length)
+        as.unshift a[m]
+      }
+      break if 0 < n
+      yield as
+      i += 1
+    end
+  end
+end

Modified: MacRuby/trunk/test/ruby/envutil.rb
===================================================================
--- MacRuby/trunk/test/ruby/envutil.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/envutil.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,3 +1,6 @@
+require "open3"
+require "timeout"
+
 module EnvUtil
   def rubybin
     unless ENV["RUBYOPT"]
@@ -13,7 +16,7 @@
         return File.expand_path(ruby)
       end
       if File.exist? rubyexe and File.executable? rubyexe
-        return File.expand_path(ruby)
+        return File.expand_path(rubyexe)
       end
       ruby = File.join("..", ruby)
     end
@@ -28,4 +31,69 @@
     end
   end
   module_function :rubybin
+
+  LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
+  def rubyexec(*args)
+    if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+      flunk("cannot test in win32")
+      return
+    end
+
+    ruby = EnvUtil.rubybin
+    c = "C"
+    env = {}
+    LANG_ENVS.each {|lc| env[lc], ENV[lc] = ENV[lc], c}
+    stdin = stdout = stderr = nil
+    Timeout.timeout(10) do
+      stdin, stdout, stderr = Open3.popen3(*([ruby] + args))
+      env.each_pair {|lc, v|
+        if v
+          ENV[lc] = v
+        else
+          ENV.delete(lc)
+        end
+      }
+      env = nil
+      yield(stdin, stdout, stderr)
+    end
+
+  ensure
+    env.each_pair {|lc, v|
+      if v
+        ENV[lc] = v
+      else
+        ENV.delete(lc)
+      end
+    } if env
+    stdin .close unless !stdin  || stdin .closed?
+    stdout.close unless !stdout || stdout.closed?
+    stderr.close unless !stderr || stderr.closed?
+  end
+  module_function :rubyexec
 end
+
+module Test
+  module Unit
+    module Assertions
+      public
+      def assert_normal_exit(testsrc, message = '')
+        IO.popen([EnvUtil.rubybin, '-W0'], 'w') {|io|
+          io.write testsrc
+        }
+        status = $?
+        faildesc = nil
+        if status.signaled?
+          signo = status.termsig
+          signame = Signal.list.invert[signo]
+          sigdesc = "signal #{signo}"
+          if signame
+            sigdesc = "SIG#{signame} (#{sigdesc})"
+          end
+          full_message = build_message(message, "killed by ?", sigdesc)
+        end
+        assert_block(full_message) { !status.signaled? }
+      end
+    end
+  end
+end
+

Added: MacRuby/trunk/test/ruby/lbtest.rb
===================================================================
--- MacRuby/trunk/test/ruby/lbtest.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/lbtest.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,48 @@
+require 'thread'
+
+class LocalBarrier
+  def initialize(n)
+    @wait = Queue.new
+    @done = Queue.new
+    @keeper = begin_keeper(n)
+  end
+
+  def sync
+    @done.push(true)
+    @wait.pop
+  end
+
+  def join
+    @keeper.join
+  end
+
+  private
+  def begin_keeper(n)
+    Thread.start do
+      n.times do
+        @done.pop
+      end
+      n.times do
+        @wait.push(true)
+      end
+    end
+  end
+end
+
+n = 10
+
+lb = LocalBarrier.new(n)
+
+(n - 1).times do |i|
+  Thread.start do
+    sleep((rand(n) + 1) / 10.0)
+    puts "#{i}: done"
+    lb.sync
+    puts "#{i}: cont"
+  end
+end
+
+lb.sync
+puts "#{n-1}: cone"
+
+puts "exit."

Modified: MacRuby/trunk/test/ruby/marshaltestlib.rb
===================================================================
--- MacRuby/trunk/test/ruby/marshaltestlib.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/marshaltestlib.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -383,6 +383,11 @@
     marshal_equal(o1) {|o| o.instance_eval { @iv }}
   end
 
+  def test_time_in_array
+    t = Time.now
+    assert_equal([t,t], Marshal.load(Marshal.dump([t, t])), "[ruby-dev:34159]")
+  end
+
   def test_true
     marshal_equal(true)
   end

Modified: MacRuby/trunk/test/ruby/test_array.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_array.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_array.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,16 @@
 require 'test/unit'
 
 class TestArray < Test::Unit::TestCase
+  def setup
+    @verbose = $VERBOSE
+    $VERBOSE = nil
+    @cls = Array
+  end
+
+  def teardown
+    $VERBOSE = @verbose
+  end
+
   def test_0_literal
     assert_equal([1, 2, 3, 4], [1, 2] + [3, 4])
     assert_equal([1, 2, 1, 2], [1, 2] * 2)
@@ -176,10 +186,6 @@
 
   # From rubicon
 
-  def setup
-    @cls = Array
-  end
-
   def test_00_new
     a = @cls.new()
     assert_kind_of(@cls, a)
@@ -531,6 +537,14 @@
     assert_equal([1, 2, 3, 1, 2, 3], a)
   end
 
+  def test_count
+    a = @cls[1, 2, 3, 1, 2]
+    assert_equal(2, a.count(1))
+    assert_equal(3, a.count {|x| x % 2 == 1 })
+    assert_equal(2, a.count(1) {|x| x % 2 == 1 })
+    assert_raise(ArgumentError) { a.count(0, 1) }
+  end
+
   def test_delete
     a = @cls[*('cab'..'cat').to_a]
     assert_equal('cap', a.delete('cap'))
@@ -1119,6 +1133,25 @@
     assert_equal(@cls[], @cls[].sort!)
   end
 
+  def test_sort_with_callcc
+    respond_to?(:callcc) or require 'continuation'
+    n = 1000
+    cont = nil
+    ary = (1..100).to_a
+    begin
+      ary.sort! {|a,b|
+        callcc {|k| cont = k} unless cont
+        assert_equal(100, ary.size, '[ruby-core:16679]')
+        a <=> b
+      }
+    rescue => e
+    end
+    n -= 1
+    cont.call if 0 < n
+    assert_instance_of(RuntimeError, e, '[ruby-core:16679]')
+    assert_match(/reentered/, e.message, '[ruby-core:16679]')
+  end
+
   def test_to_a
     a = @cls[ 1, 2, 3 ]
     a_id = a.__id__
@@ -1229,4 +1262,289 @@
     assert_equal(@cls[].permutation(0).to_a, @cls[[]])
 
   end
+
+  def test_take
+    assert_equal([1,2,3], [1,2,3,4,5,0].take(3))
+    assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].take(-1) }
+    assert_equal([1,2], [1,2].take(1000000000), '[ruby-dev:34123]')
+  end
+
+  def test_take_while
+    assert_equal([1,2], [1,2,3,4,5,0].take_while {|i| i < 3 })
+  end
+
+  def test_drop
+    assert_equal([4,5,0], [1,2,3,4,5,0].drop(3))
+    assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].drop(-1) }
+    assert_equal([], [1,2].drop(1000000000), '[ruby-dev:34123]')
+  end
+
+  def test_drop_while
+    assert_equal([3,4,5,0], [1,2,3,4,5,0].drop_while {|i| i < 3 })
+  end
+
+  def test_modify_check
+    a = []
+    a.freeze
+    assert_raise(RuntimeError) { a.shift }
+    a = [1, 2]
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+       a.shift
+      end.value
+    end
+  end
+
+  def test_ary_new
+    assert_raise(ArgumentError) { [].to_enum.first(-1) }
+    assert_raise(ArgumentError) { [].to_enum.first(2**31-1) }
+  end
+
+  def test_try_convert
+    assert_equal([1], Array.try_convert([1]))
+    assert_equal(nil, Array.try_convert("1"))
+  end
+
+  def test_initialize
+    assert_nothing_raised { [].instance_eval { initialize } }
+    assert_nothing_raised { Array.new { } }
+    assert_equal([1, 2, 3], Array.new([1, 2, 3]))
+    assert_raise(ArgumentError) { Array.new(-1, 1) }
+    assert_raise(ArgumentError) { Array.new(2**31-1, 1) }
+    assert_equal([1, 1, 1], Array.new(3, 1))
+    assert_equal([1, 1, 1], Array.new(3) { 1 })
+    assert_equal([1, 1, 1], Array.new(3, 1) { 1 })
+  end
+
+  def test_aset
+    assert_raise(IndexError) { [0][-2] = 1 }
+    assert_raise(ArgumentError) { [0][2**31-1] = 2 }
+    assert_raise(ArgumentError) { [0][2**30-1] = 3 }
+    a = [0]
+    a[2] = 4
+    assert_equal([0, nil, 4], a)
+    assert_raise(ArgumentError) { [0][0, 0, 0] = 0 }
+  end
+
+  def test_first2
+    assert_equal([0], [0].first(2))
+    assert_raise(ArgumentError) { [0].first(-1) }
+  end
+
+  def test_shift2
+    assert_equal(0, ([0] * 16).shift)
+    # check
+    a = [0, 1, 2]
+    a[3] = 3
+    a.shift(2)
+    assert_equal([2, 3], a)
+  end
+
+  def test_unshift2
+    Struct.new(:a, :b, :c)
+  end
+
+  def test_aref
+    assert_raise(ArgumentError) { [][0, 0, 0] }
+  end
+
+  def test_fetch
+    assert_equal(1, [].fetch(0, 0) { 1 })
+    assert_equal(1, [0, 1].fetch(-1))
+    assert_raise(IndexError) { [0, 1].fetch(2) }
+    assert_raise(IndexError) { [0, 1].fetch(-3) }
+    assert_equal(2, [0, 1].fetch(2, 2))
+  end
+
+  def test_index2
+    a = [0, 1, 2]
+    assert_equal(a, a.index.to_a)
+    assert_equal(1, a.index {|x| x == 1 })
+  end
+
+  def test_rindex2
+    a = [0, 1, 2]
+    assert_equal([2, 1, 0], a.rindex.to_a)
+    assert_equal(1, a.rindex {|x| x == 1 })
+
+    a = [0, 1]
+    e = a.rindex
+    assert_equal(1, e.next)
+    a.clear
+    assert_raise(StopIteration) { e.next }
+
+    o = Object.new
+    class << o; self; end.class_eval do
+      define_method(:==) {|x| a.clear; false }
+    end
+    a = [nil, o]
+    assert_equal(nil, a.rindex(0))
+  end
+
+  def test_ary_to_ary
+    o = Object.new
+    def o.to_ary; [1, 2, 3]; end
+    a, b, c = o
+    assert_equal([1, 2, 3], [a, b, c])
+  end
+
+  def test_splice
+    a = [0]
+    assert_raise(IndexError) { a[-2, 0] = nil }
+  end
+
+  def test_insert
+    a = [0]
+    assert_equal([0], a.insert(1))
+    assert_equal([0, 1], a.insert(1, 1))
+    assert_raise(ArgumentError) { a.insert }
+    assert_equal([0, 1, 2], a.insert(-1, 2))
+    assert_equal([0, 1, 3, 2], a.insert(-2, 3))
+  end
+
+  def test_join2
+    a = []
+    a << a
+    assert_equal("[...]", a.join)
+  end
+
+  def test_to_a2
+    klass = Class.new(Array)
+    a = klass.new.to_a
+    assert_equal([], a)
+    assert_equal(Array, a.class)
+  end
+
+  def test_values_at2
+    a = [0, 1, 2, 3, 4, 5]
+    assert_equal([1, 2, 3], a.values_at(1..3))
+    assert_equal([], a.values_at(7..8))
+    assert_equal([nil], a.values_at(2**31-1))
+  end
+
+  def test_select
+    assert_equal([0, 2], [0, 1, 2, 3].select {|x| x % 2 == 0 })
+  end
+
+  def test_delete2
+    a = [0] * 1024 + [1] + [0] * 1024
+    a.delete(0)
+    assert_equal([1], a)
+  end
+
+  def test_reject
+    assert_equal([1, 3], [0, 1, 2, 3].reject {|x| x % 2 == 0 })
+  end
+
+  def test_zip
+    assert_equal([[1, :a, "a"], [2, :b, "b"], [3, nil, "c"]],
+      [1, 2, 3].zip([:a, :b], ["a", "b", "c", "d"]))
+    a = []
+    [1, 2, 3].zip([:a, :b], ["a", "b", "c", "d"]) {|x| a << x }
+    assert_equal([[1, :a, "a"], [2, :b, "b"], [3, nil, "c"]], a)
+  end
+
+  def test_transpose
+    assert_equal([[1, :a], [2, :b], [3, :c]],
+      [[1, 2, 3], [:a, :b, :c]].transpose)
+    assert_raise(IndexError) { [[1, 2, 3], [:a, :b]].transpose }
+  end
+
+  def test_clear2
+    assert_equal([], ([0] * 1024).clear)
+  end
+
+  def test_fill2
+    assert_raise(ArgumentError) { [].fill(0, 1, 2**31-1) }
+  end
+
+  def test_times
+    assert_raise(ArgumentError) { [0, 0, 0, 0] * (2**29) }
+  end
+
+  def test_equal
+    o = Object.new
+    def o.to_ary; end
+    def o.==(x); :foo; end
+    assert(:foo, [0, 1, 2] == o)
+    assert([0, 1, 2] != [0, 1, 3])
+  end
+
+  def test_hash2
+    a = []
+    a << a
+    b = []
+    b << b
+    assert_equal(a.hash, b.hash)
+  end
+
+  def test_nitems2
+    assert_equal(3, [5,6,7,8,9].nitems { |x| x % 2 != 0 })
+  end
+
+  def test_flatten2
+    a = []
+    a << a
+    assert_raise(ArgumentError) { a.flatten }
+  end
+
+  def test_shuffle
+    100.times do
+      assert_equal([0, 1, 2], [2, 1, 0].shuffle.sort)
+    end
+  end
+
+  def test_choice
+    100.times do
+      assert([0, 1, 2].include?([2, 1, 0].choice))
+    end
+  end
+
+  def test_cycle
+    a = []
+    [0, 1, 2].cycle do |i|
+      a << i
+      break if a.size == 10
+    end
+    assert_equal([0, 1, 2, 0, 1, 2, 0, 1, 2, 0], a)
+
+    a = [0, 1, 2]
+    assert_nil(a.cycle { a.clear })
+
+    a = []
+    [0, 1, 2].cycle(3) {|i| a << i }
+    assert_equal([0, 1, 2, 0, 1, 2, 0, 1, 2], a)
+  end
+
+  def test_reverse_each2
+    a = [0, 1, 2, 3, 4, 5]
+    r = []
+    a.reverse_each do |x|
+      r << x
+      a.pop
+      a.pop
+    end
+    assert_equal([5, 3, 1], r)
+  end
+
+  def test_combination2
+    assert_raise(RangeError) do
+      (0..100).to_a.combination(50) {}
+    end
+  end
+
+  def test_product2
+    a = (0..100).to_a
+    assert_raise(RangeError) do
+      a.product(a, a, a, a, a, a, a, a, a, a) {}
+    end
+  end
+
+  class Array2 < Array
+  end
+
+  def test_array_subclass
+    assert_equal(Array2, Array2[1,2,3].uniq.class, "[ruby-dev:34581]")
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_assignment.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_assignment.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_assignment.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -490,7 +490,6 @@
   end
 end
 
-require 'require_relative'
 require_relative 'sentence'
 class TestAssignmentGen < Test::Unit::TestCase
   Syntax = {

Modified: MacRuby/trunk/test/ruby/test_beginendblock.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_beginendblock.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_beginendblock.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,5 @@
 require 'test/unit'
 require 'tempfile'
-require 'require_relative'
 require_relative 'envutil'
 
 class TestBeginEndBlock < Test::Unit::TestCase

Modified: MacRuby/trunk/test/ruby/test_bignum.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_bignum.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_bignum.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -163,7 +163,7 @@
 
   def test_to_s2
     assert_raise(ArgumentError) { T31P.to_s(37) }
-    assert_equal(32768, (10**32768-1).to_s.size)
+    assert_equal("9" * 32768, (10**32768-1).to_s)
     assert_raise(RangeError) { Process.wait(1, T64P) }
     assert_equal("0", T_ZERO.to_s)
     assert_equal("1", T_ONE.to_s)
@@ -236,8 +236,13 @@
   def test_div
     assert_equal(T32.to_f, T32 / 1.0)
     assert_raise(TypeError) { T32 / "foo" }
+    assert_equal(0x20000000, 0x40000001.div(2.0), "[ruby-dev:34553]")
   end
 
+  def test_idiv
+    assert_equal(715827882, 1073741824.div(Rational(3,2)), ' [ruby-dev:34066]')
+  end
+
   def test_modulo
     assert_raise(TypeError) { T32 % "foo" }
   end
@@ -258,17 +263,14 @@
     assert_equal(T32.to_f, T32.quo(1.0))
     assert_equal(T32.to_f, T32.quo(T_ONE))
 
-    ### rational changes the behavior of Bignum#quo
-    #assert_raise(TypeError) { T32.quo("foo") }
-    assert_raise(TypeError, NoMethodError) { T32.quo("foo") }
+    assert_raise(TypeError) { T32.quo("foo") }
 
     assert_equal(1024**1024, (1024**1024).quo(1))
     assert_equal(1024**1024, (1024**1024).quo(1.0))
     assert_equal(1024**1024*2, (1024**1024*2).quo(1))
     inf = 1 / 0.0; nan = inf / inf
 
-    ### rational changes the behavior of Bignum#quo
-    #assert_raise(FloatDomainError) { (1024**1024*2).quo(nan) }
+    assert((1024**1024*2).quo(nan).nan?)
   end
 
   def test_pow
@@ -377,4 +379,12 @@
   def test_interrupt
     assert(interrupt { (65536 ** 65536).to_s })
   end
+
+  def test_too_big_to_s
+    if (big = 2**31-1).is_a?(Fixnum)
+      return
+    end
+    e = assert_raise(RangeError) {(1 << big).to_s}
+    assert_match(/too big to convert/, e.message)
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_class.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_class.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_class.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -77,4 +77,32 @@
     assert_equal(BasicObject, ClassTwo.superclass.superclass.superclass)
   end
 
+  def test_class_cmp
+    assert_raise(TypeError) { Class.new <= 1 }
+    assert_raise(TypeError) { Class.new >= 1 }
+    assert_nil(Class.new <=> 1)
+  end
+
+  def test_class_initialize
+    assert_raise(TypeError) do
+      Class.new.instance_eval { initialize }
+    end
+  end
+
+  def test_instanciate_singleton_class
+    c = class << Object.new; self; end
+    assert_raise(TypeError) { c.new }
+  end
+
+  def test_superclass_of_basicobject
+    assert_equal(nil, BasicObject.superclass)
+  end
+
+  def test_module_function
+    c = Class.new
+    assert_raise(TypeError) do
+      Module.instance_method(:module_function).bind(c).call(:foo)
+    end
+  end
+
 end

Added: MacRuby/trunk/test/ruby/test_comparable.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_comparable.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_comparable.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,66 @@
+require 'test/unit'
+
+class TestComparable < Test::Unit::TestCase
+  def setup
+    @o = Object.new
+    @o.extend(Comparable)
+  end
+
+  def test_equal
+    def @o.<=>(x); 0; end
+    assert_equal(true, @o == nil)
+    def @o.<=>(x); 1; end
+    assert_equal(false, @o == nil)
+    def @o.<=>(x); raise; end
+    assert_equal(false, @o == nil)
+  end
+
+  def test_gt
+    def @o.<=>(x); 1; end
+    assert_equal(true, @o > nil)
+    def @o.<=>(x); 0; end
+    assert_equal(false, @o > nil)
+    def @o.<=>(x); -1; end
+    assert_equal(false, @o > nil)
+  end
+
+  def test_ge
+    def @o.<=>(x); 1; end
+    assert_equal(true, @o >= nil)
+    def @o.<=>(x); 0; end
+    assert_equal(true, @o >= nil)
+    def @o.<=>(x); -1; end
+    assert_equal(false, @o >= nil)
+  end
+
+  def test_lt
+    def @o.<=>(x); 1; end
+    assert_equal(false, @o < nil)
+    def @o.<=>(x); 0; end
+    assert_equal(false, @o < nil)
+    def @o.<=>(x); -1; end
+    assert_equal(true, @o < nil)
+  end
+
+  def test_le
+    def @o.<=>(x); 1; end
+    assert_equal(false, @o <= nil)
+    def @o.<=>(x); 0; end
+    assert_equal(true, @o <= nil)
+    def @o.<=>(x); -1; end
+    assert_equal(true, @o <= nil)
+  end
+
+  def test_between
+    def @o.<=>(x); 0 <=> x end
+    assert_equal(false, @o.between?(1, 2))
+    assert_equal(false, @o.between?(-2, -1))
+    assert_equal(true, @o.between?(-1, 1))
+    assert_equal(true, @o.between?(0, 0))
+  end
+
+  def test_err
+    assert_raise(ArgumentError) { 1.0 < nil }
+    assert_raise(ArgumentError) { 1.0 < Object.new }
+  end
+end

Added: MacRuby/trunk/test/ruby/test_complex.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_complex.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_complex.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,1120 @@
+require 'test/unit'
+
+class ComplexSub < Complex; end
+
+class Complex_Test < Test::Unit::TestCase
+
+  def test_compsub
+    c = ComplexSub.__send__(:new, 1)
+    cc = ComplexSub.__send__(:convert, 1)
+    if defined?(ComplexSub::Unify)
+      assert_instance_of(Fixnum, c)
+      assert_instance_of(Fixnum, cc)
+    else
+      assert_instance_of(ComplexSub, c)
+      assert_instance_of(ComplexSub, cc)
+
+      c2 = c + 1
+      assert_instance_of(ComplexSub, c2)
+      c2 = c - 1
+      assert_instance_of(ComplexSub, c2)
+
+      c3 = c - c2
+      assert_instance_of(ComplexSub, c3)
+
+      s = Marshal.dump(c)
+      c5 = Marshal.load(s)
+      assert_equal(c, c5)
+      assert_instance_of(ComplexSub, c5)
+    end
+
+  end
+
+  def test_eql_p
+    c = Complex(0)
+    c2 = Complex(0)
+    c3 = Complex(1)
+
+    assert_equal(true, c.eql?(c2))
+    assert_equal(false, c.eql?(c3))
+
+    if defined?(Complex::Unify)
+      assert_equal(true, c.eql?(0))
+    else
+      assert_equal(false, c.eql?(0))
+    end
+  end
+
+  def test_hash
+    assert_instance_of(Fixnum, Complex(1,2).hash)
+
+    h = {}
+    h[Complex(0)] = 0
+    h[Complex(0,1)] = 1
+    h[Complex(1,0)] = 2
+    h[Complex(1,1)] = 3
+
+    assert_equal(4, h.size)
+    assert_equal(2, h[Complex(1,0)])
+
+    h[Complex(0,0)] = 9
+    assert_equal(4, h.size)
+  end
+
+  def test_freeze
+    c = Complex(1)
+    c.freeze
+    unless defined?(Complex::Unify)
+      assert_equal(true, c.frozen?)
+    end
+    assert_instance_of(String, c.to_s)
+  end
+
+  def test_new_bang # no unify
+    assert_instance_of(Complex, Complex.__send__(:new!, 2,0))
+    assert_equal([2,0], Complex.__send__(:new!, 2,0).
+		 instance_eval{[real, image]})
+    assert_equal([2,4], Complex.__send__(:new!, 2,4).
+		 instance_eval{[real, image]})
+    assert_equal([-2,4], Complex.__send__(:new!, -2,4).
+		 instance_eval{[real, image]})
+    assert_equal([2,-4], Complex.__send__(:new!, 2,-4).
+		 instance_eval{[real, image]})
+    assert_equal([-2,-4], Complex.__send__(:new!, -2,-4).
+		 instance_eval{[real, image]})
+
+    assert_equal([2,0], Complex.__send__(:new!, Complex(2)).
+		 instance_eval{[real, image]})
+    assert_equal([2,3], Complex.__send__(:new!, Complex(2), Complex(3)).
+		 instance_eval{[real, image]})
+    assert_equal([2,3], Complex.__send__(:new!, 2, Complex(3)).
+		 instance_eval{[real, image]})
+
+    assert_equal([1.1,0], Complex.__send__(:new!, 1.1).
+		 instance_eval{[real, image]})
+    assert_equal([-1.1,0], Complex.__send__(:new!, -1.1).
+		 instance_eval{[real, image]})
+    assert_equal([1,0], Complex.__send__(:new!, '1').
+		 instance_eval{[real, image]})
+    assert_equal([0,0], Complex.__send__(:new!, nil).
+		 instance_eval{[real, image]})
+  end
+
+  def test_new
+    if defined?(Complex::Unify)
+      assert_instance_of(Fixnum, Complex.__send__(:new, 2,0))
+    else
+      assert_instance_of(Complex, Complex.__send__(:new, 2,0))
+      assert_equal([2,0], Complex.__send__(:new, 2,0). instance_eval{[real, image]})
+    end
+    assert_equal([2,4], Complex.__send__(:new, 2,4).instance_eval{[real, image]})
+    assert_equal([-2,4], Complex.__send__(:new, -2,4).instance_eval{[real, image]})
+    assert_equal([2,-4], Complex.__send__(:new, 2,-4).instance_eval{[real, image]})
+    assert_equal([-2,-4], Complex.__send__(:new, -2,-4).instance_eval{[real, image]})
+
+    assert_raise(ArgumentError){Complex.__send__(:new, Complex(1,2),2)}
+    assert_raise(ArgumentError){Complex.__send__(:new, 2,Complex(1,2))}
+    assert_raise(ArgumentError){Complex.__send__(:new, Complex(1,2),Complex(1,2))}
+
+    assert_raise(ArgumentError){Complex.__send__(:new, '1')}
+    assert_raise(ArgumentError){Complex.__send__(:new, nil)}
+=begin
+    assert_raise(ArgumentError){Complex.__send__(:new, Complex(1))}
+=end
+  end
+
+  def test_conv
+    c = Complex(0,0)
+    assert_equal(Complex.__send__(:new, 0,0), c)
+
+    c = Complex(2**32, 2**32)
+    assert_equal(Complex.__send__(:new, 2**32,2**32), c)
+    assert_equal([2**32,2**32], [c.real,c.image])
+
+    c = Complex(-2**32, 2**32)
+    assert_equal(Complex.__send__(:new, -2**32,2**32), c)
+    assert_equal([-2**32,2**32], [c.real,c.image])
+
+    c = Complex(2**32, -2**32)
+    assert_equal(Complex.__send__(:new, 2**32,-2**32), c)
+    assert_equal([2**32,-2**32], [c.real,c.image])
+
+    c = Complex(-2**32, -2**32)
+    assert_equal(Complex.__send__(:new, -2**32,-2**32), c)
+    assert_equal([-2**32,-2**32], [c.real,c.image])
+
+    c = Complex(Complex(1),0)
+    assert_equal(Complex.__send__(:new, 1,0), c)
+
+    c = Complex(0,Complex(1))
+    assert_equal(Complex.__send__(:new, 0,1), c)
+
+    c = 5.re
+    assert_equal(Complex.__send__(:new, 5,0), c)
+
+    c = Complex(1,2).re
+    assert_equal(Complex.__send__(:new, 1,2), c)
+
+    c = 5.im
+    assert_equal(Complex.__send__(:new, 0,5), c)
+
+    c = Complex(2,0).im
+    assert_equal(Complex.__send__(:new, 0,2), c)
+    assert_raise(ArgumentError){Complex(1,2).im}
+
+    c = Complex::I
+    assert_equal(Complex.__send__(:new, 0,1), c)
+
+    assert_equal(Complex.__send__(:new, 1),Complex(1))
+    assert_equal(Complex.__send__(:new, 1),Complex('1'))
+    assert_raise(ArgumentError){Complex(nil)}
+  end
+
+  def test_attr
+    c = Complex(4)
+
+    assert_equal(4, c.real)
+    assert_equal(0, c.image)
+
+    c = Complex(4,5)
+
+    assert_equal(4, c.real)
+    assert_equal(5, c.image)
+
+    c = Complex(-0.0,-0.0)
+
+    assert_equal('-0.0', c.real.to_s)
+    assert_equal('-0.0', c.image.to_s)
+
+    c = Complex.__send__(:new, 4)
+
+    assert_equal(4, c.real)
+    assert_equal(0, c.image)
+    assert_equal(c.imag, c.image)
+
+    c = Complex.__send__(:new, 4,5)
+
+    assert_equal(4, c.real)
+    assert_equal(5, c.image)
+    assert_equal(c.imag, c.image)
+
+    c = Complex.__send__(:new, -0.0,-0.0)
+
+    assert_equal('-0.0', c.real.to_s)
+    assert_equal('-0.0', c.image.to_s)
+    assert_equal(c.imag.to_s, c.image.to_s)
+
+    c = Complex.__send__(:new!, 4)
+
+    assert_equal(4, c.real)
+    assert_equal(c.imag, c.image)
+    assert_equal(0, c.image)
+
+    c = Complex.__send__(:new!, 4,5)
+
+    assert_equal(4, c.real)
+    assert_equal(5, c.image)
+    assert_equal(c.imag, c.image)
+
+    c = Complex.__send__(:new!, -0.0,-0.0)
+
+    assert_equal('-0.0', c.real.to_s)
+    assert_equal('-0.0', c.image.to_s)
+    assert_equal(c.imag.to_s, c.image.to_s)
+  end
+
+  def test_attr2
+    c = Complex(1)
+
+    if defined?(Complex::Unify)
+      assert_equal(true, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(true, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(true, c.rational?)
+      assert_equal(true, c.real?)
+      assert_equal(false, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    else
+      assert_equal(false, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(false, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(false, c.rational?)
+      assert_equal(false, c.real?)
+      assert_equal(true, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    end
+
+=begin
+    assert_equal(0, Complex(0).sign)
+    assert_equal(1, Complex(2).sign)
+    assert_equal(-1, Complex(-2).sign)
+=end
+
+    assert_equal(true, Complex(0).zero?)
+    assert_equal(true, Complex(0,0).zero?)
+    assert_equal(false, Complex(1,0).zero?)
+    assert_equal(false, Complex(0,1).zero?)
+    assert_equal(false, Complex(1,1).zero?)
+
+    assert_equal(nil, Complex(0).nonzero?)
+    assert_equal(nil, Complex(0,0).nonzero?)
+    assert_equal(Complex(1,0), Complex(1,0).nonzero?)
+    assert_equal(Complex(0,1), Complex(0,1).nonzero?)
+    assert_equal(Complex(1,1), Complex(1,1).nonzero?)
+  end
+
+  def test_uplus
+    assert_equal(Complex(1), +Complex(1))
+    assert_equal(Complex(-1), +Complex(-1))
+    assert_equal(Complex(1,1), +Complex(1,1))
+    assert_equal(Complex(-1,1), +Complex(-1,1))
+    assert_equal(Complex(1,-1), +Complex(1,-1))
+    assert_equal(Complex(-1,-1), +Complex(-1,-1))
+  end
+
+  def test_negate
+    assert_equal(Complex(-1), -Complex(1))
+    assert_equal(Complex(1), -Complex(-1))
+    assert_equal(Complex(-1,-1), -Complex(1,1))
+    assert_equal(Complex(1,-1), -Complex(-1,1))
+    assert_equal(Complex(-1,1), -Complex(1,-1))
+    assert_equal(Complex(1,1), -Complex(-1,-1))
+
+=begin
+    assert_equal(0, Complex(0).negate)
+    assert_equal(-2, Complex(2).negate)
+    assert_equal(2, Complex(-2).negate)
+=end
+  end
+
+  def test_add
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(3,5), c + c2)
+
+    assert_equal(Complex(3,2), c + 2)
+    assert_equal(Complex(3.0,2), c + 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(3,1),Rational(2)), c + Rational(2))
+      assert_equal(Complex(Rational(5,3),Rational(2)), c + Rational(2,3))
+    end
+  end
+
+  def test_sub
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(-1,-1), c - c2)
+
+    assert_equal(Complex(-1,2), c - 2)
+    assert_equal(Complex(-1.0,2), c - 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(-1,1),Rational(2)), c - Rational(2))
+      assert_equal(Complex(Rational(1,3),Rational(2)), c - Rational(2,3))
+    end
+  end
+
+  def test_mul
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(-4,7), c * c2)
+
+    assert_equal(Complex(2,4), c * 2)
+    assert_equal(Complex(2.0,4.0), c * 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(2,1),Rational(4)), c * Rational(2))
+      assert_equal(Complex(Rational(2,3),Rational(4,3)), c * Rational(2,3))
+    end
+
+  end
+
+  def test_div
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Complex::Unify)
+      assert_equal(Complex(Rational(8,13),Rational(1,13)), c / c2)
+    else
+      assert_equal(Complex(0,0), c / c2)
+    end
+
+    c = Complex(1.0,2.0)
+    c2 = Complex(2.0,3.0)
+
+    r = c / c2
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Complex::Unify)
+      assert_equal(Complex(Rational(1,2),1), c / 2)
+    else
+      assert_equal(Complex(0,1), c / 2)
+    end
+    assert_equal(Complex(0.5,1.0), c / 2.0)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2))
+      assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3))
+    end
+  end
+
+  def test_quo
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(8,13),Rational(1,13)), c.quo(c2))
+    else
+      r = c.quo(c2)
+      assert_in_delta(0.615, r.real, 0.001)
+      assert_in_delta(0.076, r.image, 0.001)
+    end
+
+    c = Complex(1.0,2.0)
+    c2 = Complex(2.0,3.0)
+
+    r = c.quo(c2)
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(1,2),1), c.quo(2))
+    else
+      assert_equal(Complex(0.5,1.0), c.quo(2))
+    end
+    assert_equal(Complex(0.5,1.0), c.quo(2.0))
+
+    if defined?(Rational)
+      assert_equal(Complex(Rational(1,2),Rational(1)), c / Rational(2))
+      assert_equal(Complex(Rational(3,2),Rational(3)), c / Rational(2,3))
+    end
+  end
+
+  def test_fdiv
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    r = c.fdiv(c2)
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1.0,2.0)
+    c2 = Complex(2.0,3.0)
+
+    r = c.fdiv(c2)
+    assert_in_delta(0.615, r.real, 0.001)
+    assert_in_delta(0.076, r.image, 0.001)
+
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    assert_equal(Complex(0.5,1.0), c.fdiv(2))
+    assert_equal(Complex(0.5,1.0), c.fdiv(2.0))
+  end
+
+  def test_expt
+    c = Complex(1,2)
+    c2 = Complex(2,3)
+
+    r = c ** c2
+    assert_in_delta(-0.015, r.real, 0.001)
+    assert_in_delta(-0.179, r.image, 0.001)
+
+    assert_equal(Complex(-3,4), c ** 2)
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Complex(Rational(-3,25),Rational(-4,25)), c ** -2)
+    else
+      r = c ** -2
+      assert_in_delta(-0.12, r.real, 0.001)
+      assert_in_delta(-0.16, r.image, 0.001)
+    end
+    r = c ** 2.0
+    assert_in_delta(-3.0, r.real, 0.001)
+    assert_in_delta(4.0, r.image, 0.001)
+
+    r = c ** -2.0
+    assert_in_delta(-0.12, r.real, 0.001)
+    assert_in_delta(-0.16, r.image, 0.001)
+
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Complex(-3,4), c ** Rational(2))
+#=begin
+      assert_equal(Complex(Rational(-3,25),Rational(-4,25)),
+		   c ** Rational(-2)) # why failed?
+#=end
+
+      r = c ** Rational(2,3)
+      assert_in_delta(1.264, r.real, 0.001)
+      assert_in_delta(1.150, r.image, 0.001)
+
+      r = c ** Rational(-2,3)
+      assert_in_delta(0.432, r.real, 0.001)
+      assert_in_delta(-0.393, r.image, 0.001)
+    end
+  end
+
+  def test_cmp
+    assert_raise(NoMethodError){1 <=> Complex(1,1)}
+    assert_raise(NoMethodError){Complex(1,1) <=> 1}
+    assert_raise(NoMethodError){Complex(1,1) <=> Complex(1,1)}
+  end
+
+  def test_equal
+    assert(Complex(1,0) == Complex(1))
+    assert(Complex(1,0) == Complex.__send__(:new, 1))
+    assert(Complex(1,0) == Complex.__send__(:new, 1,0))
+    assert(Complex(1,0) == Complex.__send__(:new!, 1))
+    assert(Complex(1,0) == Complex.__send__(:new!, 1,0))
+
+    assert(Complex(-1,0) == Complex(-1))
+    assert(Complex(-1,0) == Complex.__send__(:new, -1))
+    assert(Complex(-1,0) == Complex.__send__(:new, -1,0))
+    assert(Complex(-1,0) == Complex.__send__(:new!, -1))
+    assert(Complex(-1,0) == Complex.__send__(:new!, -1,0))
+
+    assert_equal(false, Complex(2,1) == Complex(1))
+    assert_equal(true, Complex(2,1) != Complex(1))
+    assert_equal(false, Complex(1) == nil)
+    assert_equal(false, Complex(1) == '')
+  end
+
+  def test_math
+    c = Complex(1,2)
+
+    assert_in_delta(2.236, c.abs, 0.001)
+    assert_equal(5, c.abs2)
+
+    assert_equal(c.abs, Math.sqrt(c * c.conj))
+    assert_equal(c.abs, Math.sqrt(c.real**2 + c.image**2))
+    assert_equal(c.abs2, c * c.conj)
+    assert_equal(c.abs2, c.real**2 + c.image**2)
+
+    assert_in_delta(1.107, c.arg, 0.001)
+    assert_in_delta(1.107, c.angle, 0.001)
+
+    r = c.polar
+    assert_in_delta(2.236, r[0], 0.001)
+    assert_in_delta(1.107, r[1], 0.001)
+    assert_equal(Complex(1,-2), c.conjugate)
+    assert_equal(Complex(1,-2), c.conj)
+#    assert_equal(Complex(1,-2), ~c)
+#    assert_equal(5, c * ~c)
+
+    assert_equal(Complex(1,2), c.numerator)
+    assert_equal(1, c.denominator)
+  end
+
+  def test_to_s
+    c = Complex(1,2)
+
+    assert_instance_of(String, c.to_s)
+    assert_equal('1+2i', c.to_s)
+
+    assert_equal('2i', Complex(0,2).to_s)
+    assert_equal('-2i', Complex(0,-2).to_s)
+    assert_equal('1+2i', Complex(1,2).to_s)
+    assert_equal('-1+2i', Complex(-1,2).to_s)
+    assert_equal('-1-2i', Complex(-1,-2).to_s)
+    assert_equal('1-2i', Complex(1,-2).to_s)
+    assert_equal('-1-2i', Complex(-1,-2).to_s)
+
+    assert_equal('2.0i', Complex(0,2.0).to_s)
+    assert_equal('-2.0i', Complex(0,-2.0).to_s)
+    assert_equal('1.0+2.0i', Complex(1.0,2.0).to_s)
+    assert_equal('-1.0+2.0i', Complex(-1.0,2.0).to_s)
+    assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s)
+    assert_equal('1.0-2.0i', Complex(1.0,-2.0).to_s)
+    assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s)
+
+    if defined?(Rational)
+      assert_equal('2i', Complex(0,Rational(2)).to_s)
+      assert_equal('-2i', Complex(0,Rational(-2)).to_s)
+      assert_equal('1+2i', Complex(1,Rational(2)).to_s)
+      assert_equal('-1+2i', Complex(-1,Rational(2)).to_s)
+      assert_equal('-1-2i', Complex(-1,Rational(-2)).to_s)
+      assert_equal('1-2i', Complex(1,Rational(-2)).to_s)
+      assert_equal('-1-2i', Complex(-1,Rational(-2)).to_s)
+
+      assert_equal('(2/3)i', Complex(0,Rational(2,3)).to_s)
+      assert_equal('(-2/3)i', Complex(0,Rational(-2,3)).to_s)
+      assert_equal('1+(2/3)i', Complex(1,Rational(2,3)).to_s)
+      assert_equal('-1+(2/3)i', Complex(-1,Rational(2,3)).to_s)
+      assert_equal('-1-(2/3)i', Complex(-1,Rational(-2,3)).to_s)
+      assert_equal('1-(2/3)i', Complex(1,Rational(-2,3)).to_s)
+      assert_equal('-1-(2/3)i', Complex(-1,Rational(-2,3)).to_s)
+    end
+  end
+
+  def test_inspect
+    c = Complex(1,2)
+
+    assert_instance_of(String, c.inspect)
+    assert_equal('Complex(1, 2)', c.inspect)
+  end
+
+  def test_marshal
+    c = Complex(1,2)
+
+    s = Marshal.dump(c)
+    c2 = Marshal.load(s)
+    assert_equal(c, c2)
+    assert_instance_of(Complex, c2)
+
+    if defined?(Rational)
+      c = Complex(Rational(1,2),Rational(2,3))
+
+      s = Marshal.dump(c)
+      c2 = Marshal.load(s)
+      assert_equal(c, c2)
+      assert_instance_of(Complex, c2)
+    end
+  end
+
+  def test_parse
+    assert_equal(Complex(0), ''.to_c)
+    assert_equal(Complex(0), ' '.to_c)
+    assert_equal(Complex(5), '5'.to_c)
+    assert_equal(Complex(-5), '-5'.to_c)
+    assert_equal(Complex(5,3), '5+3i'.to_c)
+    assert_equal(Complex(-5,3), '-5+3i'.to_c)
+    assert_equal(Complex(5,-3), '5-3i'.to_c)
+    assert_equal(Complex(-5,-3), '-5-3i'.to_c)
+    assert_equal(Complex(0,3), '3i'.to_c)
+    assert_equal(Complex(0,-3), '-3i'.to_c)
+
+    assert_equal(Complex(5,3), '5+3I'.to_c)
+    assert_equal(Complex(5,3), '5+3j'.to_c)
+    assert_equal(Complex(5,3), '5+3J'.to_c)
+    assert_equal(Complex(0,3), '3I'.to_c)
+    assert_equal(Complex(0,3), '3j'.to_c)
+    assert_equal(Complex(0,3), '3J'.to_c)
+
+    assert_equal(Complex(5.0), '5.0'.to_c)
+    assert_equal(Complex(-5.0), '-5.0'.to_c)
+    assert_equal(Complex(5.0,3.0), '5.0+3.0i'.to_c)
+    assert_equal(Complex(-5.0,3.0), '-5.0+3.0i'.to_c)
+    assert_equal(Complex(5.0,-3.0), '5.0-3.0i'.to_c)
+    assert_equal(Complex(-5.0,-3.0), '-5.0-3.0i'.to_c)
+    assert_equal(Complex(0.0,3.0), '3.0i'.to_c)
+    assert_equal(Complex(0.0,-3.0), '-3.0i'.to_c)
+
+    assert_equal(Complex(5.0), '5e0'.to_c)
+    assert_equal(Complex(-5.0), '-5e0'.to_c)
+    assert_equal(Complex(5.0,3.0), '5e0+3e0i'.to_c)
+    assert_equal(Complex(-5.0,3.0), '-5e0+3e0i'.to_c)
+    assert_equal(Complex(5.0,-3.0), '5e0-3e0i'.to_c)
+    assert_equal(Complex(-5.0,-3.0), '-5e0-3e0i'.to_c)
+    assert_equal(Complex(0.0,3.0), '3e0i'.to_c)
+    assert_equal(Complex(0.0,-3.0), '-3e0i'.to_c)
+
+    assert_equal(Complex(5), Complex('5'))
+    assert_equal(Complex(-5), Complex('-5'))
+    assert_equal(Complex(5,3), Complex('5+3i'))
+    assert_equal(Complex(-5,3), Complex('-5+3i'))
+    assert_equal(Complex(5,-3), Complex('5-3i'))
+    assert_equal(Complex(-5,-3), Complex('-5-3i'))
+    assert_equal(Complex(0,3), Complex('3i'))
+    assert_equal(Complex(0,-3), Complex('-3i'))
+
+    assert_equal(Complex(5,3), Complex('5+3I'))
+    assert_equal(Complex(5,3), Complex('5+3j'))
+    assert_equal(Complex(5,3), Complex('5+3J'))
+    assert_equal(Complex(0,3), Complex('3I'))
+    assert_equal(Complex(0,3), Complex('3j'))
+    assert_equal(Complex(0,3), Complex('3J'))
+
+    assert_equal(Complex(5.0), Complex('5.0'))
+    assert_equal(Complex(-5.0), Complex('-5.0'))
+    assert_equal(Complex(5.0,3.0), Complex('5.0+3.0i'))
+    assert_equal(Complex(-5.0,3.0), Complex('-5.0+3.0i'))
+    assert_equal(Complex(5.0,-3.0), Complex('5.0-3.0i'))
+    assert_equal(Complex(-5.0,-3.0), Complex('-5.0-3.0i'))
+    assert_equal(Complex(0.0,3.0), Complex('3.0i'))
+    assert_equal(Complex(0.0,-3.0), Complex('-3.0i'))
+
+    assert_equal(Complex(5.0), Complex('5e0'))
+    assert_equal(Complex(-5.0), Complex('-5e0'))
+    assert_equal(Complex(5.0,3.0), Complex('5e0+3e0i'))
+    assert_equal(Complex(-5.0,3.0), Complex('-5e0+3e0i'))
+    assert_equal(Complex(5.0,-3.0), Complex('5e0-3e0i'))
+    assert_equal(Complex(-5.0,-3.0), Complex('-5e0-3e0i'))
+    assert_equal(Complex(0.0,3.0), Complex('3e0i'))
+    assert_equal(Complex(0.0,-3.0), Complex('-3e0i'))
+
+    assert_equal(Complex(0), '_'.to_c)
+    assert_equal(Complex(0), '_5'.to_c)
+    assert_equal(Complex(5), '5_'.to_c)
+    assert_equal(Complex(5), '5x'.to_c)
+    assert_equal(Complex(5), '5+_3i'.to_c)
+    assert_equal(Complex(5), '5+3_i'.to_c)
+    assert_equal(Complex(5,3), '5+3i_'.to_c)
+    assert_equal(Complex(5,3), '5+3ix'.to_c)
+    assert_raise(ArgumentError){ Complex('')}
+    assert_raise(ArgumentError){ Complex('_')}
+    assert_raise(ArgumentError){ Complex('_5')}
+    assert_raise(ArgumentError){ Complex('5_')}
+    assert_raise(ArgumentError){ Complex('5x')}
+    assert_raise(ArgumentError){ Complex('5+_3i')}
+    assert_raise(ArgumentError){ Complex('5+3_i')}
+    assert_raise(ArgumentError){ Complex('5+3i_')}
+    assert_raise(ArgumentError){ Complex('5+3ix')}
+
+    if defined?(Rational) && defined?(''.to_r)
+      assert_equal(Complex(Rational(1,5)), '1/5'.to_c)
+      assert_equal(Complex(Rational(-1,5)), '-1/5'.to_c)
+      assert_equal(Complex(Rational(1,5),3), '1/5+3i'.to_c)
+      assert_equal(Complex(Rational(1,5),-3), '1/5-3i'.to_c)
+      assert_equal(Complex(Rational(-1,5),3), '-1/5+3i'.to_c)
+      assert_equal(Complex(Rational(-1,5),-3), '-1/5-3i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+3/2i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+(3/2)i'.to_c)
+      assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-(3/2)i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+(3/2)i'.to_c)
+      assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-(3/2)i'.to_c)
+    end
+
+    assert_equal(Complex(5, 3), Complex('5', '3'))
+  end
+
+  def test_respond
+    c = Complex(1,1)
+    assert_equal(false, c.respond_to?(:<))
+    assert_equal(false, c.respond_to?(:<=))
+    assert_equal(false, c.respond_to?(:<=>))
+    assert_equal(false, c.respond_to?(:>))
+    assert_equal(false, c.respond_to?(:>=))
+    assert_equal(false, c.respond_to?(:between?))
+#    assert_equal(false, c.respond_to?(:div)) # ?
+    assert_equal(false, c.respond_to?(:divmod))
+    assert_equal(false, c.respond_to?(:floor))
+    assert_equal(false, c.respond_to?(:ceil))
+    assert_equal(false, c.respond_to?(:modulo))
+    assert_equal(false, c.respond_to?(:round))
+    assert_equal(false, c.respond_to?(:step))
+    assert_equal(false, c.respond_to?(:tunrcate))
+
+    assert_equal(false, c.respond_to?(:positive?))
+    assert_equal(false, c.respond_to?(:negative?))
+#    assert_equal(false, c.respond_to?(:sign))
+
+    assert_equal(false, c.respond_to?(:quotient))
+    assert_equal(false, c.respond_to?(:quot))
+    assert_equal(false, c.respond_to?(:quotrem))
+
+    assert_equal(false, c.respond_to?(:gcd))
+    assert_equal(false, c.respond_to?(:lcm))
+    assert_equal(false, c.respond_to?(:gcdlcm))
+  end
+
+  def test_to_i
+    assert_equal(3, Complex(3).to_i)
+    assert_equal(3, Integer(Complex(3)))
+    assert_raise(RangeError){Complex(3,2).to_i}
+    assert_raise(RangeError){Integer(Complex(3,2))}
+  end
+
+  def test_to_f
+    assert_equal(3.0, Complex(3).to_f)
+    assert_equal(3.0, Float(Complex(3)))
+    assert_raise(RangeError){Complex(3,2).to_f}
+    assert_raise(RangeError){Float(Complex(3,2))}
+  end
+
+  def test_to_r
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Rational(3), Complex(3).to_r)
+      assert_equal(Rational(3), Rational(Complex(3)))
+      assert_raise(RangeError){Complex(3,2).to_r}
+      assert_raise(RangeError){Rational(Complex(3,2))}
+    end
+  end
+
+  def test_to_c
+    c = nil.to_c
+    assert_equal([0,0] , [c.real, c.image])
+
+    c = 0.to_c
+    assert_equal([0,0] , [c.real, c.image])
+
+    c = 1.to_c
+    assert_equal([1,0] , [c.real, c.image])
+
+    c = 1.1.to_c
+    assert_equal([1.1, 0], [c.real, c.image])
+
+    if defined?(Rational)
+      c = Rational(1,2).to_c
+      assert_equal([Rational(1,2), 0], [c.real, c.image])
+    end
+
+    c = Complex(1,2).to_c
+    assert_equal([1, 2], [c.real, c.image])
+  end
+
+  def test_prec
+    assert_equal(nil, Complex < Precision)
+  end
+
+  def test_supp
+    assert_equal(true, 1.scalar?)
+    assert_equal(true, 1.1.scalar?)
+
+    assert_equal(1, 1.real)
+    assert_equal(0, 1.image)
+    assert_equal(0, 1.imag)
+
+    assert_equal(1.1, 1.1.real)
+    assert_equal(0, 1.1.image)
+    assert_equal(0, 1.1.imag)
+
+    assert_equal(0, 1.arg)
+    assert_equal(0, 1.angle)
+
+    assert_equal(0, 1.0.arg)
+    assert_equal(0, 1.0.angle)
+
+    assert_equal(Math::PI, -1.arg)
+    assert_equal(Math::PI, -1.angle)
+
+    assert_equal(Math::PI, -1.0.arg)
+    assert_equal(Math::PI, -1.0.angle)
+
+    assert_equal([1,0], 1.polar)
+    assert_equal([1, Math::PI], -1.polar)
+
+    assert_equal([1.0,0], 1.0.polar)
+    assert_equal([1.0, Math::PI], -1.0.polar)
+
+    assert_equal(1, 1.conjugate)
+    assert_equal(-1, -1.conjugate)
+    assert_equal(1, 1.conj)
+    assert_equal(-1, -1.conj)
+
+    assert_equal(1.1, 1.1.conjugate)
+    assert_equal(-1.1, -1.1.conjugate)
+    assert_equal(1.1, 1.1.conj)
+    assert_equal(-1.1, -1.1.conj)
+
+    assert_equal(1, 1.numerator)
+    assert_equal(9, 9.numerator)
+    assert_equal(1, 1.denominator)
+    assert_equal(1, 9.denominator)
+
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(1.0, 1.0.numerator)
+      assert_equal(9.0, 9.0.numerator)
+      assert_equal(1.0, 1.0.denominator)
+      assert_equal(1.0, 9.0.denominator)
+    end
+
+=begin
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Rational(1,9), 9.reciprocal)
+      assert_equal(Rational(1,9), 9.0.reciprocal)
+      assert_equal(Rational(1,9), 9.inverse)
+      assert_equal(Rational(1,9), 9.0.inverse)
+    end
+=end
+
+    if defined?(Rational)
+      assert_equal(Rational(1,2), 1.quo(2))
+      assert_equal(Rational(5000000000), 10000000000.quo(2))
+      assert_equal(0.5, 1.0.quo(2))
+      assert_equal(Rational(1,4), Rational(1,2).quo(2))
+      assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2))
+    else
+      assert_equal(0.5, 1.quo(2))
+      assert_equal(5000000000.0, 10000000000.quo(2))
+      assert_equal(0.5, 1.0.quo(2))
+      assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2))
+    end
+
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Rational(1,2), 1.quo(2))
+      assert_equal(Rational(5000000000), 10000000000.quo(2))
+      assert_equal(Rational(1,2), 1.0.quo(2))
+      assert_equal(Rational(1,4), Rational(1,2).quo(2))
+      assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2))
+    end
+
+    assert_equal(0.5, 1.fdiv(2))
+    assert_equal(5000000000.0, 10000000000.fdiv(2))
+    assert_equal(0.5, 1.0.fdiv(2))
+    if defined?(Rational)
+      assert_equal(0.25, Rational(1,2).fdiv(2))
+    end
+    assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2))
+
+    unless $".grep(/(\A|\/)complex/).empty?
+      assert_equal(Complex(0,2), Math.sqrt(-4.0))
+#      assert_equal(true, Math.sqrt(-4.0).inexact?)
+      assert_equal(Complex(0,2), Math.sqrt(-4))
+#      assert_equal(true, Math.sqrt(-4).exact?)
+      if defined?(Rational)
+	assert_equal(Complex(0,2), Math.sqrt(Rational(-4)))
+#	assert_equal(true, Math.sqrt(Rational(-4)).exact?)
+      end
+
+      assert_equal(Complex(0,3), Math.sqrt(-9.0))
+#      assert_equal(true, Math.sqrt(-9.0).inexact?)
+      assert_equal(Complex(0,3), Math.sqrt(-9))
+#      assert_equal(true, Math.sqrt(-9).exact?)
+      if defined?(Rational)
+	assert_equal(Complex(0,3), Math.sqrt(Rational(-9)))
+#	assert_equal(true, Math.sqrt(Rational(-9)).exact?)
+      end
+
+      c = Math.sqrt(Complex(1, 2))
+      assert_in_delta(1.272, c.real, 0.001)
+      assert_in_delta(0.786, c.image, 0.001)
+
+      c = Math.sqrt(-9)
+      assert_in_delta(0.0, c.real, 0.001)
+      assert_in_delta(3.0, c.image, 0.001)
+
+      c = Math.exp(Complex(1, 2))
+      assert_in_delta(-1.131, c.real, 0.001)
+      assert_in_delta(2.471, c.image, 0.001)
+
+      c = Math.sin(Complex(1, 2))
+      assert_in_delta(3.165, c.real, 0.001)
+      assert_in_delta(1.959, c.image, 0.001)
+
+      c = Math.cos(Complex(1, 2))
+      assert_in_delta(2.032, c.real, 0.001)
+      assert_in_delta(-3.051, c.image, 0.001)
+
+      c = Math.tan(Complex(1, 2))
+      assert_in_delta(0.033, c.real, 0.001)
+      assert_in_delta(1.014, c.image, 0.001)
+
+      c = Math.sinh(Complex(1, 2))
+      assert_in_delta(-0.489, c.real, 0.001)
+      assert_in_delta(1.403, c.image, 0.001)
+
+      c = Math.cosh(Complex(1, 2))
+      assert_in_delta(-0.642, c.real, 0.001)
+      assert_in_delta(1.068, c.image, 0.001)
+
+      c = Math.tanh(Complex(1, 2))
+      assert_in_delta(1.166, c.real, 0.001)
+      assert_in_delta(-0.243, c.image, 0.001)
+
+      c = Math.log(Complex(1, 2))
+      assert_in_delta(0.804, c.real, 0.001)
+      assert_in_delta(1.107, c.image, 0.001)
+
+      c = Math.log(Complex(1, 2), Math::E)
+      assert_in_delta(0.804, c.real, 0.001)
+      assert_in_delta(1.107, c.image, 0.001)
+
+      c = Math.log(-1)
+      assert_in_delta(0.0, c.real, 0.001)
+      assert_in_delta(Math::PI, c.image, 0.001)
+
+      c = Math.log(8, 2)
+      assert_in_delta(3.0, c.real, 0.001)
+      assert_in_delta(0.0, c.image, 0.001)
+
+      c = Math.log(-8, -2)
+      assert_in_delta(1.092, c.real, 0.001)
+      assert_in_delta(-0.420, c.image, 0.001)
+
+      c = Math.log10(Complex(1, 2))
+      assert_in_delta(0.349, c.real, 0.001)
+      assert_in_delta(0.480, c.image, 0.001)
+
+      c = Math.asin(Complex(1, 2))
+      assert_in_delta(0.427, c.real, 0.001)
+      assert_in_delta(1.528, c.image, 0.001)
+
+      c = Math.acos(Complex(1, 2))
+      assert_in_delta(1.143, c.real, 0.001)
+      assert_in_delta(-1.528, c.image, 0.001)
+
+      c = Math.atan(Complex(1, 2))
+      assert_in_delta(1.338, c.real, 0.001)
+      assert_in_delta(0.402, c.image, 0.001)
+
+      c = Math.atan2(Complex(1, 2), 1)
+      assert_in_delta(1.338, c.real, 0.001)
+      assert_in_delta(0.402, c.image, 0.001)
+
+      c = Math.asinh(Complex(1, 2))
+      assert_in_delta(1.469, c.real, 0.001)
+      assert_in_delta(1.063, c.image, 0.001)
+
+      c = Math.acosh(Complex(1, 2))
+      assert_in_delta(1.528, c.real, 0.001)
+      assert_in_delta(1.143, c.image, 0.001)
+
+      c = Math.atanh(Complex(1, 2))
+      assert_in_delta(0.173, c.real, 0.001)
+      assert_in_delta(1.178, c.image, 0.001)
+    end
+
+  end
+
+  def test_canonicalize
+    f = defined?(Complex::Unify)
+    Complex.const_set(:Unify, true) unless f
+
+    assert_same(1, Complex.instance_eval { new(1, 0) })
+    assert_not_same(1.0, Complex.instance_eval { new(1.0, 0) })
+    assert_equal(Complex(1.0, 0), Complex.instance_eval { new(1.0, 0) })
+
+    Complex.instance_eval { remove_const(:Unify) } unless f
+  end
+
+  def test_polar
+    c = Complex.polar(2, 2)
+    assert_in_delta(2*Math.cos(2), c.real , 0.001)
+    assert_in_delta(2*Math.sin(2), c.image, 0.001)
+
+    c = Complex.polar(1, Complex(0, 1))
+    assert_in_delta(1/Math::E, c.real , 0.001)
+    assert_in_delta(        0, c.image, 0.001)
+  end
+
+  def test_generic?
+    assert_equal(true, Complex.generic?(1))
+    assert_equal(true, Complex.generic?(2**100))
+    assert_equal(true, Complex.generic?(Rational(1, 2)))
+    assert_equal(true, Complex.generic?(1.0))
+    assert_equal(false, Complex.generic?(Complex(1, 1)))
+  end
+
+  def test_new_bang2
+    o = Object.new
+    def o.to_i; 1; end
+    assert_equal(Complex(1, 1), Complex.instance_eval { new!(o, o) })
+  end
+
+  def test_denominator
+    f = defined?(Complex::Unify)
+    unify_val = f && Complex::Unify
+    Complex.instance_eval { remove_const(:Unify) } if f
+
+    dummy_rational = Class.new(Rational)
+    o1 = dummy_rational.instance_eval { new(1, 1) }
+    o2 = dummy_rational.instance_eval { new(1, 1) }
+    d1 = d2 = nil
+    class << o1; self; end.instance_eval { define_method(:denominator) { d1 } rescue nil }
+    class << o2; self; end.instance_eval { define_method(:denominator) { d2 } rescue nil }
+    # o1.denominator returns d1 and o1.denominator returns d2
+
+    c = Complex(o1, o2)
+
+    d1 = d2 = 0
+    assert_equal(0, c.denominator)
+
+    d1 = d2 = -1
+    assert_equal(1, c.denominator)
+
+    d1 = d2 = 256
+    assert_equal(256, c.denominator)
+
+    d1, d2 = 512, 256
+    assert_equal(512, c.denominator)
+
+    d1, d2 = 256, 512
+    assert_equal(512, c.denominator)
+
+    d1, d2 = -(2**100), -(3**100)
+    assert_equal(6**100, c.denominator)
+
+    d1, d2 = 1, 2**100
+    assert_equal(2**100, c.denominator)
+
+    Complex.const_set(:Unify, unify_val) if f
+  end
+
+=begin
+  def test_abs
+    b = 2**100
+    def b.*(x); self; end rescue nil
+    def b.+(x); -1; end rescue nil
+    assert_equal(Complex(0, 1), Complex(b, 1).abs)
+
+    def b.+(x); Complex(0, 1); end rescue nil
+    c = Complex(b, 1).abs
+    assert_in_delta(1/Math.sqrt(2), c.real , 0.001)
+    assert_in_delta(1/Math.sqrt(2), c.image, 0.001)
+
+    def b.+(x); Complex(0, -1); end rescue nil
+    c = Complex(b, 1).abs
+    assert_in_delta( 1/Math.sqrt(2), c.real , 0.001)
+    assert_in_delta(-1/Math.sqrt(2), c.image, 0.001)
+
+    inf = 1.0/0.0
+    nan = inf/inf
+    assert_raise(Errno::EDOM, Errno::ERANGE) { Complex(1, nan).abs }
+  end
+=end
+
+  def test_coerce
+    c = Complex(6, 3)
+    assert_equal(Complex(42, 0), c.coerce(42).first)
+    assert_raise(TypeError) { c.coerce(Object.new) }
+
+    o = Object.new
+    def o.coerce(x); [x.real, x.image]; end
+    assert_equal(9, c + o)
+    assert_equal(3, c - o)
+    assert_equal(18, c * o)
+    assert_equal(2, c / o)
+    assert_equal(216, c ** o)
+  end
+
+  def test_add2
+    assert_equal(Complex(2**100, 1), Complex(0, 1) + 2**100)
+  end
+
+  def test_mul2
+    assert_equal(Complex(0.0, 0.0), Complex(1.0, 1.0) * 0)
+    assert_equal(Complex(0, 0), Complex(0, 0) * (2**100))
+  end
+
+  def test_expt2
+    assert_equal(Complex(1, 0), Complex(2, 2) ** 0)
+    assert_equal(Complex(0, -1), Complex(0, 1) ** (2**100-1))
+    assert_equal(Complex(1, 0), Complex(1, 0) ** Rational(1, 2**100))
+  end
+
+  def test_fixed_bug
+    if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID')
+      assert_equal(Complex(1), 1 ** Complex(1))
+    end
+    assert_equal('-1.0-0.0i', Complex(-1.0, -0.0).to_s)
+  end
+
+  def test_known_bug
+  end
+
+end

Modified: MacRuby/trunk/test/ruby/test_continuation.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_continuation.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_continuation.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,7 @@
 require 'test/unit'
 require 'continuation'
 require 'fiber'
+require_relative 'envutil'
 
 class TestContinuation < Test::Unit::TestCase
   def test_create

Modified: MacRuby/trunk/test/ruby/test_enum.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_enum.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_enum.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -43,8 +43,10 @@
   end
 
   def test_find_index
+    assert_equal(1, @obj.find_index(2))
     assert_equal(1, @obj.find_index {|x| x % 2 == 0 })
     assert_equal(nil, @obj.find_index {|x| false })
+    assert_raise(ArgumentError) { @obj.find_index(0, 1) }
   end
 
   def test_find_all

Modified: MacRuby/trunk/test/ruby/test_enumerator.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_enumerator.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_enumerator.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -57,7 +57,6 @@
 
   def test_initialize
     assert_equal([1, 2, 3], @obj.to_enum(:foo, 1, 2, 3).to_a)
-    assert_equal([2, 3, 4], @obj.to_enum(:foo, 1, 2, 3) {|x| x + 1 }.to_a)
     assert_equal([1, 2, 3], Enumerable::Enumerator.new(@obj, :foo, 1, 2, 3).to_a)
     assert_raise(ArgumentError) { Enumerable::Enumerator.new }
   end

Modified: MacRuby/trunk/test/ruby/test_env.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_env.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_env.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -266,7 +266,7 @@
     assert_raise(ArgumentError) { ENV.assoc("foo\0bar") }
   end
 
-  def test_has_value
+  def test_has_value2
     ENV.clear
     assert(!ENV.has_value?("foo"))
     ENV["test"] = "foo"

Modified: MacRuby/trunk/test/ruby/test_eval.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_eval.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_eval.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -358,4 +358,21 @@
     }
   end
 
+  def test_eval_using_integer_as_binding
+    assert_raise(TypeError) { eval("", 1) }
+  end
+
+  def test_eval_raise
+    assert_raise(RuntimeError) { eval("raise ''") }
+  end
+
+  def test_eval_using_untainted_binding_under_safe4
+    assert_raise(SecurityError) do
+      Thread.new do
+        b = binding
+        $SAFE = 4
+        eval("", b)
+      end.join
+    end
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_exception.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_exception.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_exception.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,11 @@
 require 'test/unit'
+require_relative 'envutil'
 
 class TestException < Test::Unit::TestCase
+  def ruby(*r, &b)
+    EnvUtil.rubyexec(*r, &b)
+  end
+
   def test_exception
     begin
       raise "this must be handled"
@@ -184,4 +189,61 @@
       assert(false)
     end
   end
+
+  def test_raise_with_wrong_number_of_arguments
+    assert_raise(TypeError) { raise nil }
+    assert_raise(TypeError) { raise 1, 1 }
+    assert_raise(ArgumentError) { raise 1, 1, 1, 1 }
+  end
+
+  def test_errat
+    ruby do |w, r, e|
+      w.puts "p $@"
+      w.close
+      assert_equal("nil", r.read.chomp)
+      assert_equal("", e.read.chomp)
+    end
+
+    ruby do |w, r, e|
+      w.puts "$@ = 1"
+      w.close
+      assert_equal("", r.read.chomp)
+      assert_match(/\$! not set \(ArgumentError\)$/, e.read.chomp)
+    end
+
+    ruby do |w, r, e|
+      w.puts "begin"
+      w.puts "  raise"
+      w.puts "rescue"
+      w.puts "  $@ = 1"
+      w.puts "end"
+      w.close
+      assert_equal("", r.read.chomp)
+      assert_match(/backtrace must be Array of String \(TypeError\)$/, e.read.chomp)
+    end
+
+    ruby do |w, r, e|
+      w.puts "begin"
+      w.puts "  raise"
+      w.puts "rescue"
+      w.puts "  $@ = 'foo'"
+      w.puts "  raise"
+      w.puts "end"
+      w.close
+      assert_equal("", r.read.chomp)
+      assert_match(/^foo: unhandled exception$/, e.read.chomp)
+    end
+
+    ruby do |w, r, e|
+      w.puts "begin"
+      w.puts "  raise"
+      w.puts "rescue"
+      w.puts "  $@ = %w(foo bar baz)"
+      w.puts "  raise"
+      w.puts "end"
+      w.close
+      assert_equal("", r.read.chomp)
+      assert_match(/^foo: unhandled exception\s+from bar\s+from baz$/, e.read.chomp)
+    end
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_file.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_file.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_file.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,5 @@
 require 'test/unit'
 require 'tempfile'
-require 'require_relative'
 require_relative 'ut_eof'
 
 class TestFile < Test::Unit::TestCase

Modified: MacRuby/trunk/test/ruby/test_file_exhaustive.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_file_exhaustive.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_file_exhaustive.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -51,7 +51,7 @@
   end
 
   def assert_integer(n)
-    assert(n.is_a?(Fixnum), n.inspect + " is not Fixnum.")
+    assert(n.is_a?(Integer), n.inspect + " is not Fixnum.")
   end
 
   def assert_integer_or_nil(n)
@@ -75,7 +75,7 @@
       assert_integer_or_nil(fs1.rdev_minor)
       assert_integer(fs1.ino)
       assert_integer(fs1.mode)
-      unless /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+      unless /emx/ =~ RUBY_PLATFORM
         assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink)
       end
       assert_integer(fs1.uid)
@@ -139,7 +139,7 @@
   end
 
   def test_readable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0200, @file)
     assert(!(File.readable?(@file)))
     File.chmod(0600, @file)
@@ -148,7 +148,7 @@
   end
 
   def test_readable_real_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0200, @file)
     assert(!(File.readable_real?(@file)))
     File.chmod(0600, @file)
@@ -157,7 +157,7 @@
   end
 
   def test_world_readable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0006, @file)
     assert(File.world_readable?(@file))
     File.chmod(0060, @file)
@@ -168,7 +168,7 @@
   end
 
   def test_writable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0400, @file)
     assert(!(File.writable?(@file)))
     File.chmod(0600, @file)
@@ -177,7 +177,7 @@
   end
 
   def test_writable_real_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0400, @file)
     assert(!(File.writable_real?(@file)))
     File.chmod(0600, @file)
@@ -186,7 +186,7 @@
   end
 
   def test_world_writable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0006, @file)
     assert(File.world_writable?(@file))
     File.chmod(0060, @file)
@@ -197,7 +197,7 @@
   end
 
   def test_executable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0100, @file)
     assert(File.executable?(@file))
     File.chmod(0600, @file)
@@ -206,7 +206,7 @@
   end
 
   def test_executable_real_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0100, @file)
     assert(File.executable_real?(@file))
     File.chmod(0600, @file)
@@ -235,7 +235,7 @@
   end
 
   def test_owned_p ## xxx
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     assert(File.owned?(@file))
     assert(File.grpowned?(@file))
   end
@@ -296,7 +296,7 @@
   end
 
   def test_chmod
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     assert_equal(1, File.chmod(0444, @file))
     assert_equal(0444, File.stat(@file).mode % 01000)
     assert_equal(0, File.new(@file).chmod(0222))
@@ -306,11 +306,9 @@
   end
 
   def test_lchmod
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     assert_equal(1, File.lchmod(0444, @file))
     assert_equal(0444, File.stat(@file).mode % 01000)
-    assert_equal(0, File.new(@file).lchmod(0222))
-    assert_equal(0222, File.stat(@file).mode % 01000)
     File.lchmod(0600, @file)
     assert_raise(Errno::ENOENT) { File.lchmod(0600, @nofile) }
   rescue NotImplementedError
@@ -341,7 +339,7 @@
     assert_raise(Errno::EEXIST) { File.link(@file, @file) }
   end
 
-  def test_symlink
+  def test_symlink2
     return unless @symlinkfile
     assert_equal(@file, File.readlink(@symlinkfile))
     assert_raise(Errno::EINVAL) { File.readlink(@file) }
@@ -364,7 +362,7 @@
   end
 
   def test_umask
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     prev = File.umask(0777)
     assert_equal(0777, File.umask)
     open(@nofile, "w") { }
@@ -376,6 +374,11 @@
 
   def test_expand_path
     assert_equal(@file, File.expand_path(File.basename(@file), File.dirname(@file)))
+    if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM
+      assert_equal(@file, File.expand_path(@file + " "))
+      assert_equal(@file, File.expand_path(@file + "."))
+      assert_equal(@file, File.expand_path(@file + "::$DATA"))
+    end
   end
 
   def test_basename
@@ -384,6 +387,20 @@
     assert_equal("foo", File.basename("foo"))
     assert_equal("foo", File.basename("foo", ".ext"))
     assert_equal("foo", File.basename("foo.ext", ".ext"))
+    assert_equal("foo", File.basename("foo.ext", ".*"))
+    if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM
+      basename = File.basename(@file)
+      assert_equal(basename, File.basename(@file + " "))
+      assert_equal(basename, File.basename(@file + "."))
+      assert_equal(basename, File.basename(@file + "::$DATA"))
+      basename.chomp!(".test")
+      assert_equal(basename, File.basename(@file + " ", ".test"))
+      assert_equal(basename, File.basename(@file + ".", ".test"))
+      assert_equal(basename, File.basename(@file + "::$DATA", ".test"))
+      assert_equal(basename, File.basename(@file + " ", ".*"))
+      assert_equal(basename, File.basename(@file + ".", ".*"))
+      assert_equal(basename, File.basename(@file + "::$DATA", ".*"))
+    end
   end
 
   def test_dirname
@@ -395,6 +412,13 @@
     assert(".test", File.extname(@file))
     assert_equal("", File.extname("foo"))
     assert_equal("", File.extname(""))
+    if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM
+      assert_equal("", File.extname("foo "))
+      assert_equal(".ext", File.extname("foo.ext "))
+      assert_equal(".ext", File.extname("foo.ext."))
+      assert_equal(".ext", File.extname("foo.ext::$DATA"))
+      assert_equal("", File.extname("foo::$DATA.ext"))
+    end
   end
 
   def test_split
@@ -479,13 +503,15 @@
     assert_equal(false, test(?-, @dir, @file))
     assert_equal(true, test(?-, @file, @file))
     assert_equal(true, test(?=, @file, @file))
-    assert_equal(false, test(?=, @file, @file + "2"))
     assert_equal(false, test(?>, @file, @file))
-    assert_equal(false, test(?>, @file, @file + "2"))
-    assert_equal(true, test(?>, @file + "2", @file))
     assert_equal(false, test(?<, @file, @file))
-    assert_equal(true, test(?<, @file, @file + "2"))
-    assert_equal(false, test(?<, @file + "2", @file))
+    unless /cygwin/ =~ RUBY_PLATFORM
+      assert_equal(false, test(?=, @file, @file + "2"))
+      assert_equal(false, test(?>, @file, @file + "2"))
+      assert_equal(true, test(?>, @file + "2", @file))
+      assert_equal(true, test(?<, @file, @file + "2"))
+      assert_equal(false, test(?<, @file + "2", @file))
+    end
     assert_raise(ArgumentError) { test }
     assert_raise(Errno::ENOENT) { test(?A, @nofile) }
     assert_raise(ArgumentError) { test(?a) }
@@ -509,7 +535,7 @@
       assert_integer_or_nil(fs1.rdev_minor)
       assert_integer(fs1.ino)
       assert_integer(fs1.mode)
-      unless /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+      unless /emx/ =~ RUBY_PLATFORM
         assert_equal(@hardlinkfile ? 2 : 1, fs1.nlink)
       end
       assert_integer(fs1.uid)
@@ -571,7 +597,7 @@
   end
 
   def test_stat_readable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0200, @file)
     assert(!(File::Stat.new(@file).readable?))
     File.chmod(0600, @file)
@@ -579,7 +605,7 @@
   end
 
   def test_stat_readable_real_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0200, @file)
     assert(!(File::Stat.new(@file).readable_real?))
     File.chmod(0600, @file)
@@ -587,7 +613,7 @@
   end
 
   def test_stat_world_readable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0006, @file)
     assert(File::Stat.new(@file).world_readable?)
     File.chmod(0060, @file)
@@ -597,7 +623,7 @@
   end
 
   def test_stat_writable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0400, @file)
     assert(!(File::Stat.new(@file).writable?))
     File.chmod(0600, @file)
@@ -605,7 +631,7 @@
   end
 
   def test_stat_writable_real_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0400, @file)
     assert(!(File::Stat.new(@file).writable_real?))
     File.chmod(0600, @file)
@@ -613,7 +639,7 @@
   end
 
   def test_stat_world_writable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0006, @file)
     assert(File::Stat.new(@file).world_writable?)
     File.chmod(0060, @file)
@@ -623,7 +649,7 @@
   end
 
   def test_stat_executable_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0100, @file)
     assert(File::Stat.new(@file).executable?)
     File.chmod(0600, @file)
@@ -631,7 +657,7 @@
   end
 
   def test_stat_executable_real_p
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     File.chmod(0100, @file)
     assert(File::Stat.new(@file).executable_real?)
     File.chmod(0600, @file)
@@ -656,7 +682,7 @@
   end
 
   def test_stat_owned_p ## xxx
-    return if /(mswin|bccwin|mingw|emx)/ =~ RUBY_PLATFORM
+    return if /cygwin|mswin|bccwin|mingw|emx/ =~ RUBY_PLATFORM
     assert(File::Stat.new(@file).owned?)
     assert(File::Stat.new(@file).grpowned?)
   end

Modified: MacRuby/trunk/test/ruby/test_fixnum.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_fixnum.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_fixnum.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -134,7 +134,7 @@
     assert_raise(ArgumentError) { 10.to_s(1) }
   end
 
-  def test_plus
+  def test_plus2
     assert_equal(2, 1 + 1)
     assert_equal(4294967297, 1 + 2**32)
     assert_equal(2.0, 1 + 1.0)
@@ -238,11 +238,4 @@
     assert(!(1.send(:<=, 0.0)))
     assert_raise(ArgumentError) { 1.send(:<=, nil) }
   end
-
-  def test_id2name
-    assert_equal("foo", :foo.to_i.id2name)
-    assert_nil(0.id2name)
-    assert_equal(:foo, :foo.to_i.to_sym)
-    assert_nil(0.to_sym)
-  end
 end

Modified: MacRuby/trunk/test/ruby/test_float.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_float.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_float.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -81,7 +81,9 @@
     assert_raise(ArgumentError){Float("-")}
     assert_raise(ArgumentError){Float("-.")}
     assert_raise(ArgumentError){Float("1e")}
+    assert_raise(ArgumentError){Float("1__1")}
     # add expected behaviour here.
+    assert_equal(10, Float("1_0"))
   end
 
   def test_divmod
@@ -275,4 +277,154 @@
     assert_equal(1.0, Float.induced_from(1.0))
     assert_raise(TypeError) { Float.induced_from(nil) }
   end
+
+
+  VS = [
+    18446744073709551617.0,
+    18446744073709551616.0,
+    18446744073709551615.8,
+    18446744073709551615.5,
+    18446744073709551615.2,
+    18446744073709551615.0,
+    18446744073709551614.0,
+
+    4611686018427387905.0,
+    4611686018427387904.0,
+    4611686018427387903.8,
+    4611686018427387903.5,
+    4611686018427387903.2,
+    4611686018427387903.0,
+    4611686018427387902.0,
+
+    4294967297.0,
+    4294967296.0,
+    4294967295.8,
+    4294967295.5,
+    4294967295.2,
+    4294967295.0,
+    4294967294.0,
+
+    1073741825.0,
+    1073741824.0,
+    1073741823.8,
+    1073741823.5,
+    1073741823.2,
+    1073741823.0,
+    1073741822.0,
+
+    -1073741823.0,
+    -1073741824.0,
+    -1073741824.2,
+    -1073741824.5,
+    -1073741824.8,
+    -1073741825.0,
+    -1073741826.0,
+
+    -4294967295.0,
+    -4294967296.0,
+    -4294967296.2,
+    -4294967296.5,
+    -4294967296.8,
+    -4294967297.0,
+    -4294967298.0,
+
+    -4611686018427387903.0,
+    -4611686018427387904.0,
+    -4611686018427387904.2,
+    -4611686018427387904.5,
+    -4611686018427387904.8,
+    -4611686018427387905.0,
+    -4611686018427387906.0,
+
+    -18446744073709551615.0,
+    -18446744073709551616.0,
+    -18446744073709551616.2,
+    -18446744073709551616.5,
+    -18446744073709551616.8,
+    -18446744073709551617.0,
+    -18446744073709551618.0,
+  ]
+
+  def test_truncate
+    VS.each {|f|
+      i = f.truncate
+      assert_equal(i, f.to_i)
+      if f < 0
+        assert_operator(i, :<, 0)
+      else
+        assert_operator(i, :>, 0)
+      end
+      assert_operator(i.abs, :<=, f.abs)
+      d = f.abs - i.abs
+      assert_operator(0, :<=, d)
+      assert_operator(d, :<, 1)
+    }
+  end
+
+  def test_ceil
+    VS.each {|f|
+      i = f.ceil
+      if f < 0
+        assert_operator(i, :<, 0)
+      else
+        assert_operator(i, :>, 0)
+      end
+      assert_operator(i, :>=, f)
+      d = f - i
+      assert_operator(-1, :<, d)
+      assert_operator(d, :<=, 0)
+    }
+  end
+
+  def test_floor
+    VS.each {|f|
+      i = f.floor
+      if f < 0
+        assert_operator(i, :<, 0)
+      else
+        assert_operator(i, :>, 0)
+      end
+      assert_operator(i, :<=, f)
+      d = f - i
+      assert_operator(0, :<=, d)
+      assert_operator(d, :<, 1)
+    }
+  end
+
+  def test_round
+    VS.each {|f|
+      i = f.round
+      if f < 0
+        assert_operator(i, :<, 0)
+      else
+        assert_operator(i, :>, 0)
+      end
+      d = f - i
+      assert_operator(-0.5, :<=, d)
+      assert_operator(d, :<=, 0.5)
+    }
+  end
+
+  def test_Float
+    assert_in_delta(0.125, Float("0.1_2_5"), 0.00001)
+    assert_in_delta(0.125, "0.1_2_5__".to_f, 0.00001)
+    assert(Float(([1] * 10000).join).infinite?)
+    assert(!Float(([1] * 10000).join("_")).infinite?) # is it really OK?
+    assert_raise(ArgumentError) { Float("1.0\x001") }
+    assert(Float("1e10_00").infinite?)
+    assert_raise(TypeError) { Float(nil) }
+    o = Object.new
+    def o.to_f; inf = 1.0/0.0; inf/inf; end
+    assert(Float(o).nan?)
+  end
+
+  def test_num2dbl
+    assert_raise(TypeError) do
+      1.0.step(2.0, "0.5") {}
+    end
+    assert_raise(TypeError) do
+      1.0.step(2.0, nil) {}
+    end
+  end
+
 end

Modified: MacRuby/trunk/test/ruby/test_hash.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_hash.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_hash.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -671,6 +671,9 @@
     assert_equal({1=>2, 3=>4}, Hash[[[1,2],[3,4]]])
     assert_raise(ArgumentError) { Hash[0, 1, 2] }
     assert_equal({1=>2, 3=>4}, Hash[1,2,3,4])
+    o = Object.new
+    def o.to_hash() {1=>2} end
+    assert_equal({1=>2}, Hash[o], "[ruby-dev:34555]")
   end
 
   def test_rehash2
@@ -718,7 +721,7 @@
     assert_equal({3=>4,5=>6}, {1=>2,3=>4,5=>6}.select {|k, v| k + v >= 7 })
   end
 
-  def test_clear
+  def test_clear2
     assert_equal({}, {1=>2,3=>4,5=>6}.clear)
     h = {1=>2,3=>4,5=>6}
     h.each { h.clear }

Modified: MacRuby/trunk/test/ruby/test_integer.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_integer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_integer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,112 +1,6 @@
 require 'test/unit'
 
 class TestInteger < Test::Unit::TestCase
-  VS = [
-    -0x1000000000000000000000000000000000000000000000002,
-    -0x1000000000000000000000000000000000000000000000001,
-    -0x1000000000000000000000000000000000000000000000000,
-    -0xffffffffffffffffffffffffffffffffffffffffffffffff,
-    -0x1000000000000000000000002,
-    -0x1000000000000000000000001,
-    -0x1000000000000000000000000,
-    -0xffffffffffffffffffffffff,
-    -0x10000000000000002,
-    -0x10000000000000001,
-    -0x10000000000000000,
-    -0xffffffffffffffff,
-    -0x4000000000000002,
-    -0x4000000000000001,
-    -0x4000000000000000,
-    -0x3fffffffffffffff,
-    -0x100000002,
-    -0x100000001,
-    -0x100000000,
-    -0xffffffff,
-    -0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001
-    -0x80000002,
-    -0x80000001,
-    -0x80000000,
-    -0x7fffffff,
-    -0x524b2245,
-    -0x40000002,
-    -0x40000001,
-    -0x40000000,
-    -0x3fffffff,
-    -0x10002,
-    -0x10001,
-    -0x10000,
-    -0xffff,
-    -0x8101, # 0x8101 * 0x7f01 = 0x40000001
-    -0x8002,
-    -0x8001,
-    -0x8000,
-    -0x7fff,
-    -0x7f01,
-    -65,
-    -64,
-    -63,
-    -62,
-    -33,
-    -32,
-    -31,
-    -30,
-    -3,
-    -2,
-    -1,
-    0,
-    1,
-    2,
-    3,
-    30,
-    31,
-    32,
-    33,
-    62,
-    63,
-    64,
-    65,
-    0x7f01,
-    0x7ffe,
-    0x7fff,
-    0x8000,
-    0x8001,
-    0x8101,
-    0xfffe,
-    0xffff,
-    0x10000,
-    0x10001,
-    0x3ffffffe,
-    0x3fffffff,
-    0x40000000,
-    0x40000001,
-    0x524b2245,
-    0x7ffffffe,
-    0x7fffffff,
-    0x80000000,
-    0x80000001,
-    0xc717a08d,
-    0xfffffffe,
-    0xffffffff,
-    0x100000000,
-    0x100000001,
-    0x3ffffffffffffffe,
-    0x3fffffffffffffff,
-    0x4000000000000000,
-    0x4000000000000001,
-    0xfffffffffffffffe,
-    0xffffffffffffffff,
-    0x10000000000000000,
-    0x10000000000000001,
-    0xffffffffffffffffffffffff,
-    0x1000000000000000000000000,
-    0x1000000000000000000000001,
-    0xffffffffffffffffffffffffffffffffffffffffffffffff,
-    0x1000000000000000000000000000000000000000000000000,
-    0x1000000000000000000000000000000000000000000000001
-  ]
-
-  #VS.map! {|v| 0x4000000000000000.coerce(v)[0] }
-
   BDSIZE = 0x4000000000000000.coerce(0)[0].size
   def self.bdsize(x)
     ((x + 1) / 8 + BDSIZE) / BDSIZE * BDSIZE
@@ -115,47 +9,7 @@
     self.class.bdsize(x)
   end
 
-  min = -1
-  min *= 2 while min.class == Fixnum
-  FIXNUM_MIN = min/2
-  max = 1
-  max *= 2 while (max-1).class == Fixnum
-  FIXNUM_MAX = max/2-1
-
-  def test_fixnum_range
-    assert_instance_of(Bignum, FIXNUM_MIN-1)
-    assert_instance_of(Fixnum, FIXNUM_MIN)
-    assert_instance_of(Fixnum, FIXNUM_MAX)
-    assert_instance_of(Bignum, FIXNUM_MAX+1)
-  end
-
-  def check_class(n)
-    if FIXNUM_MIN <= n && n <= FIXNUM_MAX
-      assert_instance_of(Fixnum, n)
-    else
-      assert_instance_of(Bignum, n)
-    end
-  end
-
   def test_aref
-    VS.each {|a|
-      100.times {|i|
-        assert_equal((a >> i).odd? ? 1 : 0, a[i], "(#{a})[#{i}]")
-      }
-    }
-    VS.each {|a|
-      VS.each {|b|
-        c = nil
-        assert_nothing_raised("(#{a})[#{b}]") { c = a[b] }
-        check_class(c)
-        if b < 0
-          assert_equal(0, c, "(#{a})[#{b}]")
-        else
-          assert_equal((a >> b).odd? ? 1 : 0, c, "(#{a})[#{b}]")
-        end
-      }
-    }
-
     # assert_equal(1, (1 << 0x40000000)[0x40000000], "[ruby-dev:31271]")
     # assert_equal(0, (-1 << 0x40000001)[0x40000000], "[ruby-dev:31271]")
     big_zero = 0x40000000.coerce(0)[0]
@@ -163,155 +17,15 @@
     assert_equal(1, 0x400000001[big_zero], "[ruby-dev:31271]")
   end
 
-  def test_plus
-    VS.each {|a|
-      VS.each {|b|
-        c = a + b
-        check_class(c)
-        assert_equal(b + a, c, "#{a} + #{b}")
-        assert_equal(a, c - b, "(#{a} + #{b}) - #{b}")
-        assert_equal(a-~b-1, c, "#{a} + #{b}") # Hacker's Delight
-        assert_equal((a^b)+2*(a&b), c, "#{a} + #{b}") # Hacker's Delight
-        assert_equal((a|b)+(a&b), c, "#{a} + #{b}") # Hacker's Delight
-        assert_equal(2*(a|b)-(a^b), c, "#{a} + #{b}") # Hacker's Delight
-      }
-    }
-  end
-
-  def test_minus
-    VS.each {|a|
-      VS.each {|b|
-        c = a - b
-        check_class(c)
-        assert_equal(a, c + b, "(#{a} - #{b}) + #{b}")
-        assert_equal(-b, c - a, "(#{a} - #{b}) - #{a}")
-        assert_equal(a+~b+1, c, "#{a} - #{b}") # Hacker's Delight
-        assert_equal((a^b)-2*(b&~a), c, "#{a} - #{b}") # Hacker's Delight
-        assert_equal((a&~b)-(b&~a), c, "#{a} - #{b}") # Hacker's Delight
-        assert_equal(2*(a&~b)-(a^b), c, "#{a} - #{b}") # Hacker's Delight
-      }
-    }
-  end
-
-  def test_mult
-    VS.each {|a|
-      VS.each {|b|
-        c = a * b
-        check_class(c)
-        assert_equal(b * a, c, "#{a} * #{b}")
-        assert_equal(b, c / a, "(#{a} * #{b}) / #{a}") if a != 0
-        assert_equal(a.abs * b.abs, (a * b).abs, "(#{a} * #{b}).abs")
-        assert_equal((a-100)*(b-100)+(a-100)*100+(b-100)*100+10000, c, "#{a} * #{b}")
-        assert_equal((a+100)*(b+100)-(a+100)*100-(b+100)*100+10000, c, "#{a} * #{b}")
-      }
-    }
-  end
-
-  def test_divmod
-    VS.each {|a|
-      VS.each {|b|
-        if b == 0
-          assert_raise(ZeroDivisionError) { a.divmod(b) }
-        else
-          q, r = a.divmod(b)
-          check_class(q)
-          check_class(r)
-          assert_equal(a, b*q+r)
-          assert(r.abs < b.abs)
-          assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0))
-          assert_equal(q, a/b)
-          assert_equal(q, a.div(b))
-          assert_equal(r, a%b)
-          assert_equal(r, a.modulo(b))
-        end
-      }
-    }
-  end
-
   def test_pow
-    small_values = VS.find_all {|v| 0 <= v && v < 1000 }
-    VS.each {|a|
-      small_values.each {|b|
-        c = a ** b
-        check_class(c)
-        d = 1
-        b.times { d *= a }
-        assert_equal(d, c, "(#{a}) ** #{b}")
-        if a != 0
-          d = c
-          b.times { d /= a }
-          assert_equal(1, d, "((#{a}) ** #{b}) / #{a} / ...(#{b} times)...")
-        end
-      }
-    }
-
-    assert_equal(0**-1 == 0, false)
+    assert_not_equal(0, begin
+                          0**-1
+                        rescue
+                          nil
+                        end, "[ruby-dev:32084] [ruby-dev:34547]")
   end
 
-  def test_not
-    VS.each {|a|
-      b = ~a
-      check_class(b)
-      assert_equal(-1 ^ a, b, "~#{a}")
-      assert_equal(-a-1, b, "~#{a}") # Hacker's Delight
-      assert_equal(0, a & b, "#{a} & ~#{a}")
-      assert_equal(-1, a | b, "#{a} | ~#{a}")
-    }
-  end
-
-  def test_or
-    VS.each {|a|
-      VS.each {|b|
-        c = a | b
-        check_class(c)
-        assert_equal(b | a, c, "#{a} | #{b}")
-        assert_equal(a + b - (a&b), c, "#{a} | #{b}")
-        assert_equal((a & ~b) + b, c, "#{a} | #{b}") # Hacker's Delight
-        assert_equal(-1, c | ~a, "(#{a} | #{b}) | ~#{a})")
-      }
-    }
-  end
-
-  def test_and
-    VS.each {|a|
-      VS.each {|b|
-        c = a & b
-        check_class(c)
-        assert_equal(b & a, c, "#{a} & #{b}")
-        assert_equal(a + b - (a|b), c, "#{a} & #{b}")
-        assert_equal((~a | b) - ~a, c, "#{a} & #{b}") # Hacker's Delight
-        assert_equal(0, c & ~a, "(#{a} & #{b}) & ~#{a}")
-      }
-    }
-  end
-
-  def test_xor
-    VS.each {|a|
-      VS.each {|b|
-        c = a ^ b
-        check_class(c)
-        assert_equal(b ^ a, c, "#{a} ^ #{b}")
-        assert_equal((a|b)-(a&b), c, "#{a} ^ #{b}") # Hacker's Delight
-        assert_equal(b, c ^ a, "(#{a} ^ #{b}) ^ #{a}")
-      }
-    }
-  end
-
   def test_lshift
-    small_values = VS.find_all {|v| v < 8000 }
-    VS.each {|a|
-      small_values.each {|b|
-        c = a << b
-        check_class(c)
-        if 0 <= b
-          assert_equal(a, c >> b, "(#{a} << #{b}) >> #{b}")
-          assert_equal(a * 2**b, c, "#{a} << #{b}")
-        end
-        0.upto(c.size*8+10) {|nth|
-          assert_equal(a[nth-b], c[nth], "(#{a} << #{b})[#{nth}]")
-        }
-      }
-    }
     assert_equal(0, 1 << -0x40000000)
     assert_equal(0, 1 << -0x40000001)
     assert_equal(0, 1 << -0x80000000)
@@ -320,20 +34,6 @@
   end
 
   def test_rshift
-    small_values = VS.find_all {|v| -8000 < v }
-    VS.each {|a|
-      small_values.each {|b|
-        c = a >> b
-        check_class(c)
-        if b <= 0
-          assert_equal(a, c << b, "(#{a} >> #{b}) << #{b}")
-          assert_equal(a * 2**(-b), c, "#{a} >> #{b}")
-        end
-        0.upto(c.size*8+10) {|nth|
-          assert_equal(a[nth+b], c[nth], "(#{a} >> #{b})[#{nth}]")
-        }
-      }
-    }
     # assert_equal(bdsize(0x40000001), (1 >> -0x40000001).size)
     assert((1 >> 0x80000000).zero?)
     assert((1 >> 0xffffffff).zero?)
@@ -342,309 +42,6 @@
     # assert_equal((1 << 0x40000001), (1 >> -0x40000001))
   end
 
-  def test_succ
-    VS.each {|a|
-      b = a.succ
-      check_class(b)
-      assert_equal(a+1, b, "(#{a}).succ")
-      assert_equal(a, b.pred, "(#{a}).succ.pred")
-      assert_equal(a, b-1, "(#{a}).succ - 1")
-    }
-  end
-
-  def test_pred
-    VS.each {|a|
-      b = a.pred
-      check_class(b)
-      assert_equal(a-1, b, "(#{a}).pred")
-      assert_equal(a, b.succ, "(#{a}).pred.succ")
-      assert_equal(a, b + 1, "(#{a}).pred + 1")
-    }
-  end
-
-  def test_unary_plus
-    VS.each {|a|
-      b = +a
-      check_class(b)
-      assert_equal(a, b, "+(#{a})")
-    }
-  end
-
-  def test_unary_minus
-    VS.each {|a|
-      b = -a
-      check_class(b)
-      assert_equal(0-a, b, "-(#{a})")
-      assert_equal(~a+1, b, "-(#{a})")
-      assert_equal(0, a+b, "#{a}+(-(#{a}))")
-    }
-  end
-
-  def test_cmp
-    VS.each_with_index {|a, i|
-      VS.each_with_index {|b, j|
-        assert_equal(i <=> j, a <=> b, "#{a} <=> #{b}")
-        assert_equal(i < j, a < b, "#{a} < #{b}")
-        assert_equal(i <= j, a <= b, "#{a} <= #{b}")
-        assert_equal(i > j, a > b, "#{a} > #{b}")
-        assert_equal(i >= j, a >= b, "#{a} >= #{b}")
-      }
-    }
-  end
-
-  def test_eq
-    VS.each_with_index {|a, i|
-      VS.each_with_index {|b, j|
-        c = a == b
-        assert_equal(b == a, c, "#{a} == #{b}")
-        assert_equal(i == j, c, "#{a} == #{b}")
-      }
-    }
-  end
-
-  def test_abs
-    VS.each {|a|
-      b = a.abs
-      check_class(b)
-      if a < 0
-        assert_equal(-a, b, "(#{a}).abs")
-      else
-        assert_equal(a, b, "(#{a}).abs")
-      end
-    }
-  end
-
-  def test_ceil
-    VS.each {|a|
-      b = a.ceil
-      check_class(b)
-      assert_equal(a, b, "(#{a}).ceil")
-    }
-  end
-
-  def test_floor
-    VS.each {|a|
-      b = a.floor
-      check_class(b)
-      assert_equal(a, b, "(#{a}).floor")
-    }
-  end
-
-  def test_round
-    VS.each {|a|
-      b = a.round
-      check_class(b)
-      assert_equal(a, b, "(#{a}).round")
-    }
-  end
-
-  def test_truncate
-    VS.each {|a|
-      b = a.truncate
-      check_class(b)
-      assert_equal(a, b, "(#{a}).truncate")
-    }
-  end
-
-  def test_remainder
-    VS.each {|a|
-      VS.each {|b|
-        if b == 0
-          assert_raise(ZeroDivisionError) { a.divmod(b) }
-        else
-          r = a.remainder(b)
-          check_class(r)
-          if a < 0
-            assert_operator(-b.abs, :<, r, "#{a}.remainder(#{b})")
-            assert_operator(0, :>=, r, "#{a}.remainder(#{b})")
-          elsif 0 < a
-            assert_operator(0, :<=, r, "#{a}.remainder(#{b})")
-            assert_operator(b.abs, :>, r, "#{a}.remainder(#{b})")
-          else
-            assert_equal(0, r, "#{a}.remainder(#{b})")
-          end
-        end
-      }
-    }
-  end
-
-  def test_zero_nonzero
-    VS.each {|a|
-      z = a.zero?
-      n = a.nonzero?
-      if a == 0
-        assert_equal(true, z, "(#{a}).zero?")
-        assert_equal(nil, n, "(#{a}).nonzero?")
-      else
-        assert_equal(false, z, "(#{a}).zero?")
-        assert_equal(a, n, "(#{a}).nonzero?")
-        check_class(n)
-      end
-      assert(z ^ n, "(#{a}).zero? ^ (#{a}).nonzero?")
-    }
-  end
-
-  def test_even_odd
-    VS.each {|a|
-      e = a.even?
-      o = a.odd?
-      assert_equal((a % 2) == 0, e, "(#{a}).even?")
-      assert_equal((a % 2) == 1, o, "(#{a}).odd")
-      assert_equal((a & 1) == 0, e, "(#{a}).even?")
-      assert_equal((a & 1) == 1, o, "(#{a}).odd")
-      assert(e ^ o, "(#{a}).even? ^ (#{a}).odd?")
-    }
-  end
-
-  def test_to_s
-    2.upto(36) {|radix|
-      VS.each {|a|
-        s = a.to_s(radix)
-        b = s.to_i(radix)
-        assert_equal(a, b, "(#{a}).to_s(#{radix}).to_i(#{radix})")
-      }
-    }
-  end
-
-  def test_printf_x
-    VS.reverse_each {|a|
-      s = sprintf("%x", a)
-      if /\A\.\./ =~ s
-        b = -($'.tr('0123456789abcdef', 'fedcba9876543210').to_i(16) + 1)
-      else
-        b = s.to_i(16)
-      end
-      assert_equal(a, b, "sprintf('%x', #{a}) = #{s.inspect}")
-    }
-  end
-
-  def test_printf_x_sign
-    VS.reverse_each {|a|
-      s = sprintf("%+x", a)
-      b = s.to_i(16)
-      assert_equal(a, b, "sprintf('%+x', #{a}) = #{s.inspect}")
-      s = sprintf("% x", a)
-      b = s.to_i(16)
-      assert_equal(a, b, "sprintf('% x', #{a}) = #{s.inspect}")
-    }
-  end
-
-  def test_printf_o
-    VS.reverse_each {|a|
-      s = sprintf("%o", a)
-      if /\A\.\./ =~ s
-        b = -($'.tr('01234567', '76543210').to_i(8) + 1)
-      else
-        b = s.to_i(8)
-      end
-      assert_equal(a, b, "sprintf('%o', #{a}) = #{s.inspect}")
-    }
-  end
-
-  def test_printf_o_sign
-    VS.reverse_each {|a|
-      s = sprintf("%+o", a)
-      b = s.to_i(8)
-      assert_equal(a, b, "sprintf('%+o', #{a}) = #{s.inspect}")
-      s = sprintf("% o", a)
-      b = s.to_i(8)
-      assert_equal(a, b, "sprintf('% o', #{a}) = #{s.inspect}")
-    }
-  end
-
-  def test_printf_b
-    VS.reverse_each {|a|
-      s = sprintf("%b", a)
-      if /\A\.\./ =~ s
-        b = -($'.tr('01', '10').to_i(2) + 1)
-      else
-        b = s.to_i(2)
-      end
-      assert_equal(a, b, "sprintf('%b', #{a}) = #{s.inspect}")
-    }
-  end
-
-  def test_printf_b_sign
-    VS.reverse_each {|a|
-      s = sprintf("%+b", a)
-      b = s.to_i(2)
-      assert_equal(a, b, "sprintf('%+b', #{a}) = #{s.inspect}")
-      s = sprintf("% b", a)
-      b = s.to_i(2)
-      assert_equal(a, b, "sprintf('% b', #{a}) = #{s.inspect}")
-    }
-  end
-
-  def test_printf_diu
-    VS.reverse_each {|a|
-      s = sprintf("%d", a)
-      b = s.to_i
-      assert_equal(a, b, "sprintf('%d', #{a}) = #{s.inspect}")
-      s = sprintf("%i", a)
-      b = s.to_i
-      assert_equal(a, b, "sprintf('%i', #{a}) = #{s.inspect}")
-      s = sprintf("%u", a)
-      b = s.to_i
-      assert_equal(a, b, "sprintf('%u', #{a}) = #{s.inspect}")
-    }
-  end
-
-  def test_marshal
-    VS.reverse_each {|a|
-      s = Marshal.dump(a)
-      b = Marshal.load(s)
-      assert_equal(a, b, "Marshal.load(Marshal.dump(#{a}))")
-    }
-  end
-
-  def test_pack
-    %w[c C s S s! S! i I i! I! l L l! L! q Q n N v V].each {|template|
-      size = [0].pack(template).size
-      mask = (1 << (size * 8)) - 1
-      if /[A-Znv]/ =~ template
-        min = 0
-        max = (1 << (size * 8))-1
-      else
-        min = -(1 << (size * 8 - 1))
-        max = (1 << (size * 8 - 1)) - 1
-      end
-      VS.reverse_each {|a|
-        s = [a].pack(template)
-        b = s.unpack(template)[0]
-        assert_equal(a & mask, b & mask, "[#{a}].pack(#{template.dump}).unpack(#{template.dump}) & #{mask}")
-        if min <= a && a <= max
-          assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
-        end
-      }
-    }
-  end
-
-  def test_pack_ber
-    template = "w"
-    VS.reverse_each {|a|
-      if a < 0
-        assert_raise(ArgumentError) { [a].pack(template) }
-      else
-        s = [a].pack(template)
-        b = s.unpack(template)[0]
-        assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
-      end
-    }
-  end
-
-  def test_pack_utf8
-    template = "U"
-    VS.reverse_each {|a|
-      if a < 0 || 0x7fffffff < a
-        assert_raise(RangeError) { [a].pack(template) }
-      else
-        s = [a].pack(template)
-        b = s.unpack(template)[0]
-        assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
-      end
-    }
-  end
-
   def test_Integer
     assert_raise(ArgumentError) {Integer("0x-1")}
     assert_raise(ArgumentError) {Integer("-0x-1")}
@@ -788,4 +185,9 @@
     assert_equal(-1111_1111_1111_1111_1111_1111_1111_1110, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1))
     assert_equal(Bignum, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1).class)
   end
+
+  def test_Integer2
+    assert_equal(2 ** 50, Integer(2.0 ** 50))
+    assert_raise(TypeError) { Integer(nil) }
+  end
 end

Added: MacRuby/trunk/test/ruby/test_integer_comb.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_integer_comb.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_integer_comb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,620 @@
+require 'test/unit'
+
+class TestIntegerComb < Test::Unit::TestCase
+  VS = [
+    -0x1000000000000000000000000000000000000000000000002,
+    -0x1000000000000000000000000000000000000000000000001,
+    -0x1000000000000000000000000000000000000000000000000,
+    -0xffffffffffffffffffffffffffffffffffffffffffffffff,
+    -0x1000000000000000000000002,
+    -0x1000000000000000000000001,
+    -0x1000000000000000000000000,
+    -0xffffffffffffffffffffffff,
+    -0x10000000000000002,
+    -0x10000000000000001,
+    -0x10000000000000000,
+    -0xffffffffffffffff,
+    -0x4000000000000002,
+    -0x4000000000000001,
+    -0x4000000000000000,
+    -0x3fffffffffffffff,
+    -0x100000002,
+    -0x100000001,
+    -0x100000000,
+    -0xffffffff,
+    -0xc717a08d, # 0xc717a08d * 0x524b2245 = 0x4000000000000001
+    -0x80000002,
+    -0x80000001,
+    -0x80000000,
+    -0x7fffffff,
+    -0x524b2245,
+    -0x40000002,
+    -0x40000001,
+    -0x40000000,
+    -0x3fffffff,
+    -0x10002,
+    -0x10001,
+    -0x10000,
+    -0xffff,
+    -0x8101, # 0x8101 * 0x7f01 = 0x40000001
+    -0x8002,
+    -0x8001,
+    -0x8000,
+    -0x7fff,
+    -0x7f01,
+    -65,
+    -64,
+    -63,
+    -62,
+    -33,
+    -32,
+    -31,
+    -30,
+    -3,
+    -2,
+    -1,
+    0,
+    1,
+    2,
+    3,
+    30,
+    31,
+    32,
+    33,
+    62,
+    63,
+    64,
+    65,
+    0x7f01,
+    0x7ffe,
+    0x7fff,
+    0x8000,
+    0x8001,
+    0x8101,
+    0xfffe,
+    0xffff,
+    0x10000,
+    0x10001,
+    0x3ffffffe,
+    0x3fffffff,
+    0x40000000,
+    0x40000001,
+    0x524b2245,
+    0x7ffffffe,
+    0x7fffffff,
+    0x80000000,
+    0x80000001,
+    0xc717a08d,
+    0xfffffffe,
+    0xffffffff,
+    0x100000000,
+    0x100000001,
+    0x3ffffffffffffffe,
+    0x3fffffffffffffff,
+    0x4000000000000000,
+    0x4000000000000001,
+    0xfffffffffffffffe,
+    0xffffffffffffffff,
+    0x10000000000000000,
+    0x10000000000000001,
+    0xffffffffffffffffffffffff,
+    0x1000000000000000000000000,
+    0x1000000000000000000000001,
+    0xffffffffffffffffffffffffffffffffffffffffffffffff,
+    0x1000000000000000000000000000000000000000000000000,
+    0x1000000000000000000000000000000000000000000000001
+  ]
+
+  #VS.map! {|v| 0x4000000000000000.coerce(v)[0] }
+
+  min = -1
+  min *= 2 while min.class == Fixnum
+  FIXNUM_MIN = min/2
+  max = 1
+  max *= 2 while (max-1).class == Fixnum
+  FIXNUM_MAX = max/2-1
+
+  def test_fixnum_range
+    assert_instance_of(Bignum, FIXNUM_MIN-1)
+    assert_instance_of(Fixnum, FIXNUM_MIN)
+    assert_instance_of(Fixnum, FIXNUM_MAX)
+    assert_instance_of(Bignum, FIXNUM_MAX+1)
+  end
+
+  def check_class(n)
+    if FIXNUM_MIN <= n && n <= FIXNUM_MAX
+      assert_instance_of(Fixnum, n)
+    else
+      assert_instance_of(Bignum, n)
+    end
+  end
+
+  def test_aref
+    VS.each {|a|
+      100.times {|i|
+        assert_equal((a >> i).odd? ? 1 : 0, a[i], "(#{a})[#{i}]")
+      }
+    }
+    VS.each {|a|
+      VS.each {|b|
+        c = nil
+        assert_nothing_raised("(#{a})[#{b}]") { c = a[b] }
+        check_class(c)
+        if b < 0
+          assert_equal(0, c, "(#{a})[#{b}]")
+        else
+          assert_equal((a >> b).odd? ? 1 : 0, c, "(#{a})[#{b}]")
+        end
+      }
+    }
+  end
+
+  def test_plus
+    VS.each {|a|
+      VS.each {|b|
+        c = a + b
+        check_class(c)
+        assert_equal(b + a, c, "#{a} + #{b}")
+        assert_equal(a, c - b, "(#{a} + #{b}) - #{b}")
+        assert_equal(a-~b-1, c, "#{a} + #{b}") # Hacker's Delight
+        assert_equal((a^b)+2*(a&b), c, "#{a} + #{b}") # Hacker's Delight
+        assert_equal((a|b)+(a&b), c, "#{a} + #{b}") # Hacker's Delight
+        assert_equal(2*(a|b)-(a^b), c, "#{a} + #{b}") # Hacker's Delight
+      }
+    }
+  end
+
+  def test_minus
+    VS.each {|a|
+      VS.each {|b|
+        c = a - b
+        check_class(c)
+        assert_equal(a, c + b, "(#{a} - #{b}) + #{b}")
+        assert_equal(-b, c - a, "(#{a} - #{b}) - #{a}")
+        assert_equal(a+~b+1, c, "#{a} - #{b}") # Hacker's Delight
+        assert_equal((a^b)-2*(b&~a), c, "#{a} - #{b}") # Hacker's Delight
+        assert_equal((a&~b)-(b&~a), c, "#{a} - #{b}") # Hacker's Delight
+        assert_equal(2*(a&~b)-(a^b), c, "#{a} - #{b}") # Hacker's Delight
+      }
+    }
+  end
+
+  def test_mult
+    VS.each {|a|
+      VS.each {|b|
+        c = a * b
+        check_class(c)
+        assert_equal(b * a, c, "#{a} * #{b}")
+        assert_equal(b, c / a, "(#{a} * #{b}) / #{a}") if a != 0
+        assert_equal(a.abs * b.abs, (a * b).abs, "(#{a} * #{b}).abs")
+        assert_equal((a-100)*(b-100)+(a-100)*100+(b-100)*100+10000, c, "#{a} * #{b}")
+        assert_equal((a+100)*(b+100)-(a+100)*100-(b+100)*100+10000, c, "#{a} * #{b}")
+      }
+    }
+  end
+
+  def test_divmod
+    VS.each {|a|
+      VS.each {|b|
+        if b == 0
+          assert_raise(ZeroDivisionError) { a.divmod(b) }
+        else
+          q, r = a.divmod(b)
+          check_class(q)
+          check_class(r)
+          assert_equal(a, b*q+r)
+          assert(r.abs < b.abs)
+          assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0))
+          assert_equal(q, a/b)
+          assert_equal(q, a.div(b))
+          assert_equal(r, a%b)
+          assert_equal(r, a.modulo(b))
+        end
+      }
+    }
+  end
+
+  def test_pow
+    small_values = VS.find_all {|v| 0 <= v && v < 1000 }
+    VS.each {|a|
+      small_values.each {|b|
+        c = a ** b
+        check_class(c)
+        d = 1
+        b.times { d *= a }
+        assert_equal(d, c, "(#{a}) ** #{b}")
+        if a != 0
+          d = c
+          b.times { d /= a }
+          assert_equal(1, d, "((#{a}) ** #{b}) / #{a} / ...(#{b} times)...")
+        end
+      }
+    }
+  end
+
+  def test_not
+    VS.each {|a|
+      b = ~a
+      check_class(b)
+      assert_equal(-1 ^ a, b, "~#{a}")
+      assert_equal(-a-1, b, "~#{a}") # Hacker's Delight
+      assert_equal(0, a & b, "#{a} & ~#{a}")
+      assert_equal(-1, a | b, "#{a} | ~#{a}")
+    }
+  end
+
+  def test_or
+    VS.each {|a|
+      VS.each {|b|
+        c = a | b
+        check_class(c)
+        assert_equal(b | a, c, "#{a} | #{b}")
+        assert_equal(a + b - (a&b), c, "#{a} | #{b}")
+        assert_equal((a & ~b) + b, c, "#{a} | #{b}") # Hacker's Delight
+        assert_equal(-1, c | ~a, "(#{a} | #{b}) | ~#{a})")
+      }
+    }
+  end
+
+  def test_and
+    VS.each {|a|
+      VS.each {|b|
+        c = a & b
+        check_class(c)
+        assert_equal(b & a, c, "#{a} & #{b}")
+        assert_equal(a + b - (a|b), c, "#{a} & #{b}")
+        assert_equal((~a | b) - ~a, c, "#{a} & #{b}") # Hacker's Delight
+        assert_equal(0, c & ~a, "(#{a} & #{b}) & ~#{a}")
+      }
+    }
+  end
+
+  def test_xor
+    VS.each {|a|
+      VS.each {|b|
+        c = a ^ b
+        check_class(c)
+        assert_equal(b ^ a, c, "#{a} ^ #{b}")
+        assert_equal((a|b)-(a&b), c, "#{a} ^ #{b}") # Hacker's Delight
+        assert_equal(b, c ^ a, "(#{a} ^ #{b}) ^ #{a}")
+      }
+    }
+  end
+
+  def test_lshift
+    small_values = VS.find_all {|v| v < 8000 }
+    VS.each {|a|
+      small_values.each {|b|
+        c = a << b
+        check_class(c)
+        if 0 <= b
+          assert_equal(a, c >> b, "(#{a} << #{b}) >> #{b}")
+          assert_equal(a * 2**b, c, "#{a} << #{b}")
+        end
+        0.upto(c.size*8+10) {|nth|
+          assert_equal(a[nth-b], c[nth], "(#{a} << #{b})[#{nth}]")
+        }
+      }
+    }
+  end
+
+  def test_rshift
+    small_values = VS.find_all {|v| -8000 < v }
+    VS.each {|a|
+      small_values.each {|b|
+        c = a >> b
+        check_class(c)
+        if b <= 0
+          assert_equal(a, c << b, "(#{a} >> #{b}) << #{b}")
+          assert_equal(a * 2**(-b), c, "#{a} >> #{b}")
+        end
+        0.upto(c.size*8+10) {|nth|
+          assert_equal(a[nth+b], c[nth], "(#{a} >> #{b})[#{nth}]")
+        }
+      }
+    }
+  end
+
+  def test_succ
+    VS.each {|a|
+      b = a.succ
+      check_class(b)
+      assert_equal(a+1, b, "(#{a}).succ")
+      assert_equal(a, b.pred, "(#{a}).succ.pred")
+      assert_equal(a, b-1, "(#{a}).succ - 1")
+    }
+  end
+
+  def test_pred
+    VS.each {|a|
+      b = a.pred
+      check_class(b)
+      assert_equal(a-1, b, "(#{a}).pred")
+      assert_equal(a, b.succ, "(#{a}).pred.succ")
+      assert_equal(a, b + 1, "(#{a}).pred + 1")
+    }
+  end
+
+  def test_unary_plus
+    VS.each {|a|
+      b = +a
+      check_class(b)
+      assert_equal(a, b, "+(#{a})")
+    }
+  end
+
+  def test_unary_minus
+    VS.each {|a|
+      b = -a
+      check_class(b)
+      assert_equal(0-a, b, "-(#{a})")
+      assert_equal(~a+1, b, "-(#{a})")
+      assert_equal(0, a+b, "#{a}+(-(#{a}))")
+    }
+  end
+
+  def test_cmp
+    VS.each_with_index {|a, i|
+      VS.each_with_index {|b, j|
+        assert_equal(i <=> j, a <=> b, "#{a} <=> #{b}")
+        assert_equal(i < j, a < b, "#{a} < #{b}")
+        assert_equal(i <= j, a <= b, "#{a} <= #{b}")
+        assert_equal(i > j, a > b, "#{a} > #{b}")
+        assert_equal(i >= j, a >= b, "#{a} >= #{b}")
+      }
+    }
+  end
+
+  def test_eq
+    VS.each_with_index {|a, i|
+      VS.each_with_index {|b, j|
+        c = a == b
+        assert_equal(b == a, c, "#{a} == #{b}")
+        assert_equal(i == j, c, "#{a} == #{b}")
+      }
+    }
+  end
+
+  def test_abs
+    VS.each {|a|
+      b = a.abs
+      check_class(b)
+      if a < 0
+        assert_equal(-a, b, "(#{a}).abs")
+      else
+        assert_equal(a, b, "(#{a}).abs")
+      end
+    }
+  end
+
+  def test_ceil
+    VS.each {|a|
+      b = a.ceil
+      check_class(b)
+      assert_equal(a, b, "(#{a}).ceil")
+    }
+  end
+
+  def test_floor
+    VS.each {|a|
+      b = a.floor
+      check_class(b)
+      assert_equal(a, b, "(#{a}).floor")
+    }
+  end
+
+  def test_round
+    VS.each {|a|
+      b = a.round
+      check_class(b)
+      assert_equal(a, b, "(#{a}).round")
+    }
+  end
+
+  def test_truncate
+    VS.each {|a|
+      b = a.truncate
+      check_class(b)
+      assert_equal(a, b, "(#{a}).truncate")
+    }
+  end
+
+  def test_remainder
+    VS.each {|a|
+      VS.each {|b|
+        if b == 0
+          assert_raise(ZeroDivisionError) { a.divmod(b) }
+        else
+          r = a.remainder(b)
+          check_class(r)
+          if a < 0
+            assert_operator(-b.abs, :<, r, "#{a}.remainder(#{b})")
+            assert_operator(0, :>=, r, "#{a}.remainder(#{b})")
+          elsif 0 < a
+            assert_operator(0, :<=, r, "#{a}.remainder(#{b})")
+            assert_operator(b.abs, :>, r, "#{a}.remainder(#{b})")
+          else
+            assert_equal(0, r, "#{a}.remainder(#{b})")
+          end
+        end
+      }
+    }
+  end
+
+  def test_zero_nonzero
+    VS.each {|a|
+      z = a.zero?
+      n = a.nonzero?
+      if a == 0
+        assert_equal(true, z, "(#{a}).zero?")
+        assert_equal(nil, n, "(#{a}).nonzero?")
+      else
+        assert_equal(false, z, "(#{a}).zero?")
+        assert_equal(a, n, "(#{a}).nonzero?")
+        check_class(n)
+      end
+      assert(z ^ n, "(#{a}).zero? ^ (#{a}).nonzero?")
+    }
+  end
+
+  def test_even_odd
+    VS.each {|a|
+      e = a.even?
+      o = a.odd?
+      assert_equal((a % 2) == 0, e, "(#{a}).even?")
+      assert_equal((a % 2) == 1, o, "(#{a}).odd")
+      assert_equal((a & 1) == 0, e, "(#{a}).even?")
+      assert_equal((a & 1) == 1, o, "(#{a}).odd")
+      assert(e ^ o, "(#{a}).even? ^ (#{a}).odd?")
+    }
+  end
+
+  def test_to_s
+    2.upto(36) {|radix|
+      VS.each {|a|
+        s = a.to_s(radix)
+        b = s.to_i(radix)
+        assert_equal(a, b, "(#{a}).to_s(#{radix}).to_i(#{radix})")
+      }
+    }
+  end
+
+  def test_printf_x
+    VS.reverse_each {|a|
+      s = sprintf("%x", a)
+      if /\A\.\./ =~ s
+        b = -($'.tr('0123456789abcdef', 'fedcba9876543210').to_i(16) + 1)
+      else
+        b = s.to_i(16)
+      end
+      assert_equal(a, b, "sprintf('%x', #{a}) = #{s.inspect}")
+    }
+  end
+
+  def test_printf_x_sign
+    VS.reverse_each {|a|
+      s = sprintf("%+x", a)
+      b = s.to_i(16)
+      assert_equal(a, b, "sprintf('%+x', #{a}) = #{s.inspect}")
+      s = sprintf("% x", a)
+      b = s.to_i(16)
+      assert_equal(a, b, "sprintf('% x', #{a}) = #{s.inspect}")
+    }
+  end
+
+  def test_printf_o
+    VS.reverse_each {|a|
+      s = sprintf("%o", a)
+      if /\A\.\./ =~ s
+        b = -($'.tr('01234567', '76543210').to_i(8) + 1)
+      else
+        b = s.to_i(8)
+      end
+      assert_equal(a, b, "sprintf('%o', #{a}) = #{s.inspect}")
+    }
+  end
+
+  def test_printf_o_sign
+    VS.reverse_each {|a|
+      s = sprintf("%+o", a)
+      b = s.to_i(8)
+      assert_equal(a, b, "sprintf('%+o', #{a}) = #{s.inspect}")
+      s = sprintf("% o", a)
+      b = s.to_i(8)
+      assert_equal(a, b, "sprintf('% o', #{a}) = #{s.inspect}")
+    }
+  end
+
+  def test_printf_b
+    VS.reverse_each {|a|
+      s = sprintf("%b", a)
+      if /\A\.\./ =~ s
+        b = -($'.tr('01', '10').to_i(2) + 1)
+      else
+        b = s.to_i(2)
+      end
+      assert_equal(a, b, "sprintf('%b', #{a}) = #{s.inspect}")
+    }
+  end
+
+  def test_printf_b_sign
+    VS.reverse_each {|a|
+      s = sprintf("%+b", a)
+      b = s.to_i(2)
+      assert_equal(a, b, "sprintf('%+b', #{a}) = #{s.inspect}")
+      s = sprintf("% b", a)
+      b = s.to_i(2)
+      assert_equal(a, b, "sprintf('% b', #{a}) = #{s.inspect}")
+    }
+  end
+
+  def test_printf_diu
+    VS.reverse_each {|a|
+      s = sprintf("%d", a)
+      b = s.to_i
+      assert_equal(a, b, "sprintf('%d', #{a}) = #{s.inspect}")
+      s = sprintf("%i", a)
+      b = s.to_i
+      assert_equal(a, b, "sprintf('%i', #{a}) = #{s.inspect}")
+      s = sprintf("%u", a)
+      b = s.to_i
+      assert_equal(a, b, "sprintf('%u', #{a}) = #{s.inspect}")
+    }
+  end
+
+  def test_marshal
+    VS.reverse_each {|a|
+      s = Marshal.dump(a)
+      b = Marshal.load(s)
+      assert_equal(a, b, "Marshal.load(Marshal.dump(#{a}))")
+    }
+  end
+
+  def test_pack
+    %w[c C s S s! S! i I i! I! l L l! L! q Q n N v V].each {|template|
+      size = [0].pack(template).size
+      mask = (1 << (size * 8)) - 1
+      if /[A-Znv]/ =~ template
+        min = 0
+        max = (1 << (size * 8))-1
+      else
+        min = -(1 << (size * 8 - 1))
+        max = (1 << (size * 8 - 1)) - 1
+      end
+      VS.reverse_each {|a|
+        s = [a].pack(template)
+        b = s.unpack(template)[0]
+        assert_equal(a & mask, b & mask, "[#{a}].pack(#{template.dump}).unpack(#{template.dump}) & #{mask}")
+        if min <= a && a <= max
+          assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
+        end
+      }
+    }
+  end
+
+  def test_pack_ber
+    template = "w"
+    VS.reverse_each {|a|
+      if a < 0
+        assert_raise(ArgumentError) { [a].pack(template) }
+      else
+        s = [a].pack(template)
+        b = s.unpack(template)[0]
+        assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
+      end
+    }
+  end
+
+  def test_pack_utf8
+    template = "U"
+    VS.reverse_each {|a|
+      if a < 0 || 0x7fffffff < a
+        assert_raise(RangeError) { [a].pack(template) }
+      else
+        s = [a].pack(template)
+        b = s.unpack(template)[0]
+        assert_equal(a, b, "[#{a}].pack(#{template.dump}).unpack(#{template.dump})")
+      end
+    }
+  end
+end

Modified: MacRuby/trunk/test/ruby/test_io.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_io.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_io.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,4 +1,8 @@
 require 'test/unit'
+require 'tmpdir'
+require 'io/nonblock'
+require 'socket'
+require 'stringio'
 
 class TestIO < Test::Unit::TestCase
   def test_gets_rs
@@ -55,4 +59,490 @@
   ensure
     r.close
   end
+
+  def test_rubydev33072
+    assert_raise(Errno::ENOENT, "[ruby-dev:33072]") do
+      File.read("empty", nil, nil, {})
+    end
+  end
+
+  def with_pipe
+    r, w = IO.pipe
+    begin
+      yield r, w
+    ensure
+      r.close unless r.closed?
+      w.close unless w.closed?
+    end
+  end
+
+  def with_read_pipe(content)
+    r, w = IO.pipe
+    w << content
+    w.close
+    begin
+      yield r
+    ensure
+      r.close
+    end
+  end
+
+  def mkcdtmpdir
+    Dir.mktmpdir {|d|
+      Dir.chdir(d) {
+        yield
+      }
+    }
+  end
+
+  def test_copy_stream
+    mkcdtmpdir {|d|
+
+      content = "foobar"
+      File.open("src", "w") {|f| f << content }
+      ret = IO.copy_stream("src", "dst")
+      assert_equal(content.bytesize, ret)
+      assert_equal(content, File.read("dst"))
+
+      # overwrite by smaller file.
+      content = "baz"
+      File.open("src", "w") {|f| f << content }
+      ret = IO.copy_stream("src", "dst")
+      assert_equal(content.bytesize, ret)
+      assert_equal(content, File.read("dst"))
+
+      ret = IO.copy_stream("src", "dst", 2)
+      assert_equal(2, ret)
+      assert_equal(content[0,2], File.read("dst"))
+
+      ret = IO.copy_stream("src", "dst", 0)
+      assert_equal(0, ret)
+      assert_equal("", File.read("dst"))
+
+      ret = IO.copy_stream("src", "dst", nil, 1)
+      assert_equal(content.bytesize-1, ret)
+      assert_equal(content[1..-1], File.read("dst"))
+
+      assert_raise(Errno::ENOENT) {
+        IO.copy_stream("nodir/foo", "dst")
+      }
+
+      assert_raise(Errno::ENOENT) {
+        IO.copy_stream("src", "nodir/bar")
+      }
+
+      with_pipe {|r, w|
+        ret = IO.copy_stream("src", w)
+        assert_equal(content.bytesize, ret)
+        w.close
+        assert_equal(content, r.read)
+      }
+
+      with_pipe {|r, w|
+        w.close
+        assert_raise(IOError) { IO.copy_stream("src", w) }
+      }
+
+      pipe_content = "abc"
+      with_read_pipe(pipe_content) {|r|
+        ret = IO.copy_stream(r, "dst")
+        assert_equal(pipe_content.bytesize, ret)
+        assert_equal(pipe_content, File.read("dst"))
+      }
+
+      with_read_pipe("abc") {|r1|
+        assert_equal("a", r1.getc)
+        with_pipe {|r2, w2|
+          w2.sync = false
+          w2 << "def"
+          ret = IO.copy_stream(r1, w2)
+          assert_equal(2, ret)
+          w2.close
+          assert_equal("defbc", r2.read)
+        }
+      }
+
+      with_read_pipe("abc") {|r1|
+        assert_equal("a", r1.getc)
+        with_pipe {|r2, w2|
+          w2.sync = false
+          w2 << "def"
+          ret = IO.copy_stream(r1, w2, 1)
+          assert_equal(1, ret)
+          w2.close
+          assert_equal("defb", r2.read)
+        }
+      }
+
+      with_read_pipe("abc") {|r1|
+        assert_equal("a", r1.getc)
+        with_pipe {|r2, w2|
+          ret = IO.copy_stream(r1, w2)
+          assert_equal(2, ret)
+          w2.close
+          assert_equal("bc", r2.read)
+        }
+      }
+
+      with_read_pipe("abc") {|r1|
+        assert_equal("a", r1.getc)
+        with_pipe {|r2, w2|
+          ret = IO.copy_stream(r1, w2, 1)
+          assert_equal(1, ret)
+          w2.close
+          assert_equal("b", r2.read)
+        }
+      }
+
+      with_read_pipe("abc") {|r1|
+        assert_equal("a", r1.getc)
+        with_pipe {|r2, w2|
+          ret = IO.copy_stream(r1, w2, 0)
+          assert_equal(0, ret)
+          w2.close
+          assert_equal("", r2.read)
+        }
+      }
+
+      with_pipe {|r1, w1|
+        w1 << "abc"
+        assert_equal("a", r1.getc)
+        with_pipe {|r2, w2|
+          w1 << "def"
+          w1.close
+          ret = IO.copy_stream(r1, w2)
+          assert_equal(5, ret)
+          w2.close
+          assert_equal("bcdef", r2.read)
+        }
+      }
+
+      with_pipe {|r, w|
+        ret = IO.copy_stream("src", w, 1, 1)
+        assert_equal(1, ret)
+        w.close
+        assert_equal(content[1,1], r.read)
+      }
+
+      with_read_pipe("abc") {|r1|
+        assert_equal("a", r1.getc)
+        with_pipe {|r2, w2|
+          w2.nonblock = true
+          s = w2.syswrite("a" * 100000)
+          t = Thread.new { sleep 0.1; r2.read }
+          ret = IO.copy_stream(r1, w2)
+          w2.close
+          assert_equal(2, ret)
+          assert_equal("a" * s + "bc", t.value)
+        }
+      }
+
+      bigcontent = "abc" * 123456
+      File.open("bigsrc", "w") {|f| f << bigcontent }
+      ret = IO.copy_stream("bigsrc", "bigdst")
+      assert_equal(bigcontent.bytesize, ret)
+      assert_equal(bigcontent, File.read("bigdst"))
+
+      File.unlink("bigdst")
+      ret = IO.copy_stream("bigsrc", "bigdst", nil, 100)
+      assert_equal(bigcontent.bytesize-100, ret)
+      assert_equal(bigcontent[100..-1], File.read("bigdst"))
+
+      File.unlink("bigdst")
+      ret = IO.copy_stream("bigsrc", "bigdst", 30000, 100)
+      assert_equal(30000, ret)
+      assert_equal(bigcontent[100, 30000], File.read("bigdst"))
+
+      File.open("bigsrc") {|f|
+        assert_equal(0, f.pos)
+        ret = IO.copy_stream(f, "bigdst", nil, 10)
+        assert_equal(bigcontent.bytesize-10, ret)
+        assert_equal(bigcontent[10..-1], File.read("bigdst"))
+        assert_equal(0, f.pos)
+        ret = IO.copy_stream(f, "bigdst", 40, 30)
+        assert_equal(40, ret)
+        assert_equal(bigcontent[30, 40], File.read("bigdst"))
+        assert_equal(0, f.pos)
+      }
+
+      with_pipe {|r, w|
+        w.close
+        assert_raise(IOError) { IO.copy_stream("src", w) }
+      }
+
+      megacontent = "abc" * 1234567
+      File.open("megasrc", "w") {|f| f << megacontent }
+
+      with_pipe {|r1, w1|
+        with_pipe {|r2, w2|
+          t1 = Thread.new { w1 << megacontent; w1.close }
+          t2 = Thread.new { r2.read }
+          r1.nonblock = true
+          w2.nonblock = true
+          ret = IO.copy_stream(r1, w2)
+          assert_equal(megacontent.bytesize, ret)
+          w2.close
+          t1.join
+          assert_equal(megacontent, t2.value)
+        }
+      }
+
+      with_pipe {|r1, w1|
+        with_pipe {|r2, w2|
+          t1 = Thread.new { w1 << megacontent; w1.close }
+          t2 = Thread.new { r2.read }
+          ret = IO.copy_stream(r1, w2)
+          assert_equal(megacontent.bytesize, ret)
+          w2.close
+          t1.join
+          assert_equal(megacontent, t2.value)
+        }
+      }
+
+      with_pipe {|r, w|
+        t = Thread.new { r.read }
+        ret = IO.copy_stream("megasrc", w)
+        assert_equal(megacontent.bytesize, ret)
+        w.close
+        assert_equal(megacontent, t.value)
+      }
+    }
+  end
+
+  def test_copy_stream_rbuf
+    mkcdtmpdir {|d|
+      with_pipe {|r, w|
+        File.open("foo", "w") {|f| f << "abcd" }
+        File.open("foo") {|f|
+          f.read(1)
+          assert_equal(3, IO.copy_stream(f, w, 10, 1))
+        }
+        w.close
+        assert_equal("bcd", r.read)
+      }
+    }
+  end
+
+  def with_socketpair
+    s1, s2 = UNIXSocket.pair
+    begin
+      yield s1, s2
+    ensure
+      s1.close unless s1.closed?
+      s2.close unless s2.closed?
+    end
+  end
+
+  def test_copy_stream_socket
+    return unless defined? UNIXSocket
+    mkcdtmpdir {|d|
+
+      content = "foobar"
+      File.open("src", "w") {|f| f << content }
+
+      with_socketpair {|s1, s2|
+        ret = IO.copy_stream("src", s1)
+        assert_equal(content.bytesize, ret)
+        s1.close
+        assert_equal(content, s2.read)
+      }
+
+      bigcontent = "abc" * 123456
+      File.open("bigsrc", "w") {|f| f << bigcontent }
+
+      with_socketpair {|s1, s2|
+        t = Thread.new { s2.read }
+        ret = IO.copy_stream("bigsrc", s1)
+        assert_equal(bigcontent.bytesize, ret)
+        s1.close
+        result = t.value
+        assert_equal(bigcontent, result)
+      }
+
+      with_socketpair {|s1, s2|
+        t = Thread.new { s2.read }
+        ret = IO.copy_stream("bigsrc", s1, 10000)
+        assert_equal(10000, ret)
+        s1.close
+        result = t.value
+        assert_equal(bigcontent[0,10000], result)
+      }
+
+      File.open("bigsrc") {|f|
+        assert_equal(0, f.pos)
+        with_socketpair {|s1, s2|
+          t = Thread.new { s2.read }
+          ret = IO.copy_stream(f, s1, nil, 100)
+          assert_equal(bigcontent.bytesize-100, ret)
+          assert_equal(0, f.pos)
+          s1.close
+          result = t.value
+          assert_equal(bigcontent[100..-1], result)
+        }
+      }
+
+      File.open("bigsrc") {|f|
+        assert_equal(bigcontent[0,100], f.read(100))
+        assert_equal(100, f.pos)
+        with_socketpair {|s1, s2|
+          t = Thread.new { s2.read }
+          ret = IO.copy_stream(f, s1)
+          assert_equal(bigcontent.bytesize-100, ret)
+          assert_equal(bigcontent.length, f.pos)
+          s1.close
+          result = t.value
+          assert_equal(bigcontent[100..-1], result)
+        }
+      }
+
+      megacontent = "abc" * 1234567
+      File.open("megasrc", "w") {|f| f << megacontent }
+
+      with_socketpair {|s1, s2|
+        t = Thread.new { s2.read }
+        s1.nonblock = true
+        ret = IO.copy_stream("megasrc", s1)
+        assert_equal(megacontent.bytesize, ret)
+        s1.close
+        result = t.value
+        assert_equal(megacontent, result)
+      }
+    }
+  end
+
+  def test_copy_stream_strio
+    src = StringIO.new("abcd")
+    dst = StringIO.new
+    ret = IO.copy_stream(src, dst)
+    assert_equal(4, ret)
+    assert_equal("abcd", dst.string)
+    assert_equal(4, src.pos)
+  end
+
+  def test_copy_stream_strio_len
+    src = StringIO.new("abcd")
+    dst = StringIO.new
+    ret = IO.copy_stream(src, dst, 3)
+    assert_equal(3, ret)
+    assert_equal("abc", dst.string)
+    assert_equal(3, src.pos)
+  end
+
+  def test_copy_stream_strio_off
+    src = StringIO.new("abcd")
+    with_pipe {|r, w|
+      assert_raise(ArgumentError) {
+        IO.copy_stream(src, w, 3, 1)
+      }
+    }
+  end
+
+  def test_copy_stream_fname_to_strio
+    mkcdtmpdir {|d|
+      File.open("foo", "w") {|f| f << "abcd" }
+      src = "foo"
+      dst = StringIO.new
+      ret = IO.copy_stream(src, dst, 3)
+      assert_equal(3, ret)
+      assert_equal("abc", dst.string)
+    }
+  end
+
+  def test_copy_stream_strio_to_fname
+    mkcdtmpdir {|d|
+      # StringIO to filename
+      src = StringIO.new("abcd")
+      ret = IO.copy_stream(src, "fooo", 3)
+      assert_equal(3, ret)
+      assert_equal("abc", File.read("fooo"))
+      assert_equal(3, src.pos)
+    }
+  end
+
+  def test_copy_stream_io_to_strio
+    mkcdtmpdir {|d|
+      # IO to StringIO
+      File.open("bar", "w") {|f| f << "abcd" }
+      File.open("bar") {|src|
+        dst = StringIO.new
+        ret = IO.copy_stream(src, dst, 3)
+        assert_equal(3, ret)
+        assert_equal("abc", dst.string)
+        assert_equal(3, src.pos)
+      }
+    }
+  end
+
+  def test_copy_stream_strio_to_io
+    mkcdtmpdir {|d|
+      # StringIO to IO
+      src = StringIO.new("abcd")
+      ret = File.open("baz", "w") {|dst|
+        IO.copy_stream(src, dst, 3)
+      }
+      assert_equal(3, ret)
+      assert_equal("abc", File.read("baz"))
+      assert_equal(3, src.pos)
+    }
+  end
+
+  def test_copy_stream_strio_flush
+    with_pipe {|r, w|
+      w.sync = false
+      w.write "zz"
+      src = StringIO.new("abcd")
+      IO.copy_stream(src, w)
+      t = Thread.new {
+        w.close
+      }
+      assert_equal("zzabcd", r.read)
+      t.join
+    }
+  end
+
+  def test_copy_stream_strio_rbuf
+    with_pipe {|r, w|
+      w << "abcd"
+      w.close
+      assert_equal("a", r.read(1))
+      sio = StringIO.new
+      IO.copy_stream(r, sio)
+      assert_equal("bcd", sio.string)
+    }
+  end
+
+  def test_copy_stream_src_wbuf
+    mkcdtmpdir {|d|
+      with_pipe {|r, w|
+        File.open("foe", "w+") {|f|
+          f.write "abcd\n"
+          f.rewind
+          f.write "xy"
+          IO.copy_stream(f, w)
+        }
+        assert_equal("xycd\n", File.read("foe"))
+        w.close
+        assert_equal("cd\n", r.read)
+        r.close
+      }
+    }
+  end
+
+  def test_copy_stream_dst_rbuf
+    mkcdtmpdir {|d|
+      with_pipe {|r, w|
+        w << "xyz"
+        w.close
+        File.open("fom", "w+") {|f|
+          f.write "abcd\n"
+          f.rewind
+          assert_equal("abc", f.read(3))
+          f.ungetc "c"
+          IO.copy_stream(r, f)
+        }
+        assert_equal("abxyz", File.read("fom"))
+      }
+    }
+  end
+
 end

Modified: MacRuby/trunk/test/ruby/test_io_m17n.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_io_m17n.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_io_m17n.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -120,15 +120,6 @@
     }
   end
 
-  def test_open_w_enc
-    with_tmpdir {
-      open("tmp", "w:euc-jp") {|f|
-        assert_equal(Encoding::EUC_JP, f.external_encoding)
-        assert_equal(nil, f.internal_encoding)
-      }
-    }
-  end
-
   def test_stdin
     assert_equal(Encoding.default_external, STDIN.external_encoding)
     assert_equal(nil, STDIN.internal_encoding)
@@ -426,5 +417,14 @@
       assert_equal("\u{3042}".encode("euc-jp"), result)
     }
   end
+
+  def test_file_foreach
+    with_tmpdir {
+      generate_file('tst', 'a' * 8191 + "\xa1\xa1")
+      assert_nothing_raised {
+        File.foreach('tst', :encoding=>"euc-jp") {|line| line.inspect }
+      }
+    }
+  end
 end
 

Modified: MacRuby/trunk/test/ruby/test_iterator.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_iterator.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_iterator.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -491,7 +491,7 @@
     loop{a.push e.next}
     assert_equal([1,2,3], a)
 
-    assert_equal([[1, 8, 10], [2, 6, 11], [3, 4, 12]],
-                 (1..10).zip([8,6,4],(10..100)).to_a)
+    assert_equal([[8, 1, 10], [6, 2, 11], [4, 3, 12]],
+                 [8,6,4].zip((1..10),(10..100)).to_a)
   end
 end

Modified: MacRuby/trunk/test/ruby/test_literal.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_literal.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_literal.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -17,10 +17,13 @@
     assert_instance_of Fixnum, 1_2_3_4
     assert_equal '18', 0x12.inspect
     assert_instance_of Fixnum, 0x12
+    assert_raise(SyntaxError) { eval("0x") }
     assert_equal '15', 0o17.inspect
     assert_instance_of Fixnum, 0o17
+    assert_raise(SyntaxError) { eval("0o") }
     assert_equal '5', 0b101.inspect
     assert_instance_of Fixnum, 0b101
+    assert_raise(SyntaxError) { eval("0b") }
     assert_equal '123456789012345678901234567890', 123456789012345678901234567890.inspect
     assert_instance_of Bignum, 123456789012345678901234567890
     assert_instance_of Float, 1.3
@@ -181,4 +184,58 @@
     assert_equal __LINE__, __LINE__
   end
 
+  def test_integer
+    head = ['', '0x', '0o', '0b', '0d', '-', '+']
+    chars = ['0', '1', '_', '9', 'f']
+    head.each {|h|
+      4.times {|len|
+        a = [h]
+        len.times { a = a.product(chars).map {|x| x.join('') } }
+        a.each {|s|
+          next if s.empty?
+          begin
+            r1 = Integer(s)
+          rescue ArgumentError
+            r1 = :err
+          end
+          begin
+            r2 = eval(s)
+          rescue NameError, SyntaxError
+            r2 = :err
+          end
+          assert_equal(r1, r2, "Integer(#{s.inspect}) != eval(#{s.inspect})")
+        }
+      }
+    }
+  end
+
+  def test_float
+    head = ['', '-', '+']
+    chars = ['0', '1', '_', '9', 'f', '.']
+    head.each {|h|
+      6.times {|len|
+        a = [h]
+        len.times { a = a.product(chars).map {|x| x.join('') } }
+        a.each {|s|
+          next if s.empty?
+          next if /\.\z/ =~ s
+          next if /\A[-+]?\./ =~ s
+          next if /\A[-+]?0/ =~ s
+          begin
+            r1 = Float(s)
+          rescue ArgumentError
+            r1 = :err
+          end
+          begin
+            r2 = eval(s)
+          rescue NameError, SyntaxError
+            r2 = :err
+          end
+          r2 = :err if Range === r2
+          assert_equal(r1, r2, "Float(#{s.inspect}) != eval(#{s.inspect})")
+        }
+      }
+    }
+  end
+
 end

Modified: MacRuby/trunk/test/ruby/test_m17n.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_m17n.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_m17n.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -785,6 +785,13 @@
     assert(s("a") < a("\xa1"))
   end
 
+  def test_str_multiply
+    str = "\u3042"
+    assert_equal(true,  (str * 0).ascii_only?, "[ruby-dev:33895]")
+    assert_equal(false, (str * 1).ascii_only?)
+    assert_equal(false, (str * 2).ascii_only?)
+  end
+
   def test_str_aref
     assert_equal(a("\xc2"), a("\xc2\xa1")[0])
     assert_equal(a("\xa1"), a("\xc2\xa1")[1])
@@ -796,8 +803,26 @@
     assert_equal(nil,       s("\xc2\xa1")[2])
     assert_equal(u("\xc2\xa1"), u("\xc2\xa1")[0])
     assert_equal(nil,           u("\xc2\xa1")[1])
+
+    str = "\u3042"
+    assert_equal(true,  str[0, 0].ascii_only?, "[ruby-dev:33895]")
+    assert_equal(false, str[0, 1].ascii_only?)
+    assert_equal(false, str[0..-1].ascii_only?)
   end
 
+  def test_utf8str_aref
+    s = "abcdefghijklmnopqrstuvwxyz\u{3042 3044 3046 3048 304A}"
+    assert_equal("a", s[0])
+    assert_equal("h", s[7])
+    assert_equal("i", s[8])
+    assert_equal("j", s[9])
+    assert_equal("\u{3044}", s[27])
+    assert_equal("\u{3046}", s[28])
+    assert_equal("\u{3048}", s[29])
+    s = "abcdefghijklmnopqrstuvw\u{3042 3044 3046 3048 304A}"
+    assert_equal("\u{3044}", s[24])
+  end
+
   def test_str_aref_len
     assert_equal(a("\xa1"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 1])
     assert_equal(a("\xa1\xc2"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[1, 2])
@@ -852,6 +877,9 @@
     }
 
     assert_equal(e("\xA1\xA1"), a("a").tr(a("a"), e("\xA1\xA1")))
+
+    assert_equal("X\u3042\u3044X", "A\u3042\u3044\u3046".tr("^\u3042\u3044", "X"))
+    assert_equal("\u3042\u3046" * 100, ("\u3042\u3044" * 100).tr("\u3044", "\u3046"))
   end
 
   def test_tr_s
@@ -869,6 +897,10 @@
     assert_equal(1, e("\xa1\xa2").delete("z").length)
     s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4")
     assert_raise(ArgumentError){s.delete(a("\xa3\xb2"))}
+
+    a = "\u3042\u3044\u3046\u3042\u3044\u3046"
+    a.delete!("\u3042\u3044", "^\u3044")
+    assert_equal("\u3044\u3046\u3044\u3046", a)
   end
 
   def test_include?
@@ -939,6 +971,12 @@
     assert_equal(u("\xf0jihgfedcba"), u("abcdefghij\xf0").reverse)
   end
 
+  def test_reverse_bang
+    s = u("abcdefghij\xf0")
+    s.reverse!
+    assert_equal(u("\xf0jihgfedcba"), s)
+  end
+
   def test_plus
     assert_raise(ArgumentError){u("\xe3\x81\x82") + a("\xa1")}
   end
@@ -1016,8 +1054,8 @@
      mu = method(u("\xc2\xa1"))
      assert_not_equal(me.name, mu.name)
      assert_not_equal(me.inspect, mu.inspect)
-     assert_equal(e("\xc2\xa1"), me.name)
-     assert_equal(u("\xc2\xa1"), mu.name)
+     assert_equal(e("\xc2\xa1"), me.name.to_s)
+     assert_equal(u("\xc2\xa1"), mu.name.to_s)
   end
 
   def test_symbol
@@ -1101,6 +1139,13 @@
     assert_equal(Encoding::US_ASCII, {1=>nil,"foo"=>""}.to_s.encoding)
   end
 
+  def test_encoding_find
+    assert_raise(TypeError) {Encoding.find(nil)}
+    assert_raise(TypeError) {Encoding.find(0)}
+    assert_raise(TypeError) {Encoding.find([])}
+    assert_raise(TypeError) {Encoding.find({})}
+  end
+
   def test_encoding_to_s
     assert_equal(Encoding::US_ASCII, Encoding::US_ASCII.to_s.encoding)
     assert_equal(Encoding::US_ASCII, Encoding::US_ASCII.inspect.encoding)
@@ -1165,8 +1210,27 @@
     assert_equal(true, (s.dup << s).valid_encoding?)
     assert_equal(true, "".center(2, s).valid_encoding?)
 
-     s = "\xa1\xa1\x8f".force_encoding("euc-jp")
-     assert_equal(false, s.valid_encoding?)
-     assert_equal(true, s.reverse.valid_encoding?)
+    s = "\xa1\xa1\x8f".force_encoding("euc-jp")
+    assert_equal(false, s.valid_encoding?)
+    assert_equal(true, s.reverse.valid_encoding?)
   end
+
+  def test_getbyte
+    assert_equal(0x82, u("\xE3\x81\x82\xE3\x81\x84").getbyte(2))
+    assert_equal(0x82, u("\xE3\x81\x82\xE3\x81\x84").getbyte(-4))
+    assert_nil(u("\xE3\x81\x82\xE3\x81\x84").getbyte(100))
+  end
+
+  def test_setbyte
+    s = u("\xE3\x81\x82\xE3\x81\x84")
+    s.setbyte(2, 0x84)
+    assert_equal(u("\xE3\x81\x84\xE3\x81\x84"), s)
+
+    s = u("\xE3\x81\x82\xE3\x81\x84")
+    assert_raise(IndexError) { s.setbyte(100, 0) }
+
+    s = u("\xE3\x81\x82\xE3\x81\x84")
+    s.setbyte(-4, 0x84)
+    assert_equal(u("\xE3\x81\x84\xE3\x81\x84"), s)
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_m17n_comb.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_m17n_comb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_m17n_comb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,6 @@
 require 'test/unit'
 require 'stringio'
+require_relative 'allpairs'
 
 class TestM17NComb < Test::Unit::TestCase
   def assert_encoding(encname, actual, message=nil)
@@ -113,20 +114,8 @@
     #"aaa".force_encoding("utf-32be"),
   ]
 
-  def combination(*args)
-    args = args.map {|a| a.to_a }
-    i = 0
-    while true
-      n = i
-      as = []
-      args.reverse_each {|a|
-        n, m = n.divmod(a.length)
-        as.unshift a[m]
-      }
-      break if 0 < n
-      yield as
-      i += 1
-    end
+  def combination(*args, &b)
+    AllPairs.each(*args, &b)
   end
 
   def encdump(str)
@@ -720,8 +709,10 @@
 
   def test_str_chomp
     combination(STRINGS, STRINGS) {|s1, s2|
-      if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding
-        assert_raise(ArgumentError) { s1.chomp(s2) }
+      if !s1.ascii_only? && !s2.ascii_only? && !Encoding.compatible?(s1,s2)
+        if s1.bytesize > s2.bytesize 
+          assert_raise(ArgumentError) { s1.chomp(s2) }
+        end
         next
       end
       t = enccall(s1, :chomp, s2)
@@ -813,6 +804,10 @@
 
   def test_str_delete
     combination(STRINGS, STRINGS) {|s1, s2|
+      if s1.empty?
+        assert_equal(s1, s1.delete(s2))
+        next
+      end
       if !s1.valid_encoding? || !s2.valid_encoding?
         assert_raise(ArgumentError) { s1.delete(s2) }
         next
@@ -1563,6 +1558,8 @@
         assert_raise(ArgumentError, desc) { s1.start_with?(s2) }
         next
       end
+      s1 = s1.dup.force_encoding("ASCII-8BIT")
+      s2 = s2.dup.force_encoding("ASCII-8BIT")
       if s1.length < s2.length
         assert_equal(false, enccall(s1, :start_with?, s2), desc)
         next

Modified: MacRuby/trunk/test/ruby/test_marshal.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_marshal.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_marshal.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,4 @@
 require 'test/unit'
-require 'require_relative'
 require_relative 'marshaltestlib'
 
 class TestMarshal < Test::Unit::TestCase

Modified: MacRuby/trunk/test/ruby/test_math.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_math.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_math.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,8 @@
 
 class TestMath < Test::Unit::TestCase
   def check(a, b)
-    assert_in_delta(a, b, Float::EPSILON * 4)
+    err = [Float::EPSILON * 4, [a.abs, b.abs].max * Float::EPSILON * 256].max
+    assert_in_delta(a, b, err)
   end
 
   def test_atan2

Modified: MacRuby/trunk/test/ruby/test_method.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_method.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_method.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,4 +1,5 @@
 require 'test/unit'
+require_relative 'envutil'
 
 class TestMethod < Test::Unit::TestCase
   def setup
@@ -10,6 +11,10 @@
     $VERBOSE = @verbose
   end
 
+  def ruby(*r, &b)
+    EnvUtil.rubyexec(*r, &b)
+  end
+
   def m0() end
   def m1(a) end
   def m2(a, b) end
@@ -107,8 +112,10 @@
     def o.foo; end
     m = o.method(:foo)
     assert_equal(o, m.receiver)
-    assert_equal("foo", m.name)
+    assert_equal(:foo, m.name)
     assert_equal(class << o; self; end, m.owner)
+    assert_equal(:foo, m.unbind.name)
+    assert_equal(class << o; self; end, m.unbind.owner)
   end
 
   def test_instance_method
@@ -200,4 +207,17 @@
     m2 = c2.new.method(:foo)
     assert_equal("#<Method: #{ c2.inspect }(#{ c.inspect })#foo>", m2.inspect)
   end
+
+  def test_callee_top_level
+    ruby do |w, r, e|
+      w.puts "p __callee__"
+      w.close
+      assert_equal("nil", r.read.chomp)
+      assert_match("", e.read.chomp)
+    end
+  end
+
+  def test_caller_negative_level
+    assert_raise(ArgumentError) { caller(-1) }
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_module.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_module.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_module.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,10 +1,39 @@
 require 'test/unit'
 require 'pp'
+require_relative 'envutil'
 
 $m0 = Module.nesting
 
 class TestModule < Test::Unit::TestCase
+  def assert_method_defined?(klass, mid, message="")
+    message = build_message(message, "#{klass}\##{mid} expected to be defined.")
+    _wrap_assertion do
+      klass.method_defined?(mid) or
+        raise Test::Unit::AssertionFailedError, message, caller(3)
+    end
+  end
 
+  def assert_method_not_defined?(klass, mid, message="")
+    message = build_message(message, "#{klass}\##{mid} expected to not be defined.")
+    _wrap_assertion do
+      klass.method_defined?(mid) and
+        raise Test::Unit::AssertionFailedError, message, caller(3)
+    end
+  end
+
+  def setup
+    @verbose = $VERBOSE
+    $VERBOSE = nil
+  end
+
+  def teardown
+    $VERBOSE = @verbose
+  end
+
+  def ruby(*r, &b)
+    EnvUtil.rubyexec(*r, &b)
+  end
+
   def test_LT_0
     assert_equal true, String < Object
     assert_equal false, Object < String
@@ -232,14 +261,44 @@
   end
 
   def test_method_defined?
-    assert(!User.method_defined?(:wombat))
-    assert(User.method_defined?(:user))
-    assert(User.method_defined?(:mixin))
-    assert(!User.method_defined?(:wombat))
-    assert(User.method_defined?(:user))
-    assert(User.method_defined?(:mixin))
+    assert_method_not_defined?(User, :wombat)
+    assert_method_defined?(User, :user)
+    assert_method_defined?(User, :mixin)
+    assert_method_not_defined?(User, :wombat)
+    assert_method_defined?(User, :user)
+    assert_method_defined?(User, :mixin)
   end
 
+  def module_exec_aux
+    Proc.new do
+      def dynamically_added_method_3; end
+    end
+  end
+  def module_exec_aux_2(&block)
+    User.module_exec(&block)
+  end
+
+  def test_module_exec
+    User.module_exec do
+      def dynamically_added_method_1; end
+    end
+    assert_method_defined?(User, :dynamically_added_method_1)
+
+    block = Proc.new do
+      def dynamically_added_method_2; end
+    end
+    User.module_exec(&block)
+    assert_method_defined?(User, :dynamically_added_method_2)
+
+    User.module_exec(&module_exec_aux)
+    assert_method_defined?(User, :dynamically_added_method_3)
+
+    module_exec_aux_2 do
+      def dynamically_added_method_4; end
+    end
+    assert_method_defined?(User, :dynamically_added_method_4)
+  end
+
   def test_module_eval
     User.module_eval("MODULE_EVAL = 1")
     assert_equal(1, User::MODULE_EVAL)
@@ -313,4 +372,322 @@
     assert_instance_of(Module, m)
   end
 
+  def test_freeze
+    m = Module.new
+    m.freeze
+    assert_raise(RuntimeError) do
+      m.module_eval do
+        def foo; end
+      end
+    end
+  end
+
+  def test_attr_obsoleted_flag
+    c = Class.new
+    c.class_eval do
+      def initialize
+        @foo = :foo
+        @bar = :bar
+      end
+      attr :foo, true
+      attr :bar, false
+    end
+    o = c.new
+    assert_equal(true, o.respond_to?(:foo))
+    assert_equal(true, o.respond_to?(:foo=))
+    assert_equal(true, o.respond_to?(:bar))
+    assert_equal(false, o.respond_to?(:bar=))
+  end
+
+  def test_const_get2
+    c1 = Class.new
+    c2 = Class.new(c1)
+
+    eval("c1::Foo = :foo")
+    assert_equal(:foo, c1::Foo)
+    assert_equal(:foo, c2::Foo)
+    assert_equal(:foo, c2.const_get(:Foo))
+    assert_raise(NameError) { c2.const_get(:Foo, false) }
+
+    eval("c1::Foo = :foo")
+    assert_raise(NameError) { c1::Bar }
+    assert_raise(NameError) { c2::Bar }
+    assert_raise(NameError) { c2.const_get(:Bar) }
+    assert_raise(NameError) { c2.const_get(:Bar, false) }
+
+    c1.instance_eval do
+      def const_missing(x)
+        x
+      end
+    end
+
+    assert_equal(:Bar, c1::Bar)
+    assert_equal(:Bar, c2::Bar)
+    assert_equal(:Bar, c2.const_get(:Bar))
+    assert_equal(:Bar, c2.const_get(:Bar, false))
+
+    assert_raise(NameError) { c1.const_get(:foo) }
+  end
+
+  def test_const_set2
+    c1 = Class.new
+    assert_raise(NameError) { c1.const_set(:foo, :foo) }
+  end
+
+  def test_const_get3
+    c1 = Class.new
+    assert_raise(NameError) { c1.const_defined?(:foo) }
+  end
+
+  def test_class_variable_get2
+    c = Class.new
+    c.class_eval { @@foo = :foo }
+    assert_equal(:foo, c.class_variable_get(:@@foo))
+    assert_raise(NameError) { c.class_variable_get(:@@bar) } # c.f. instance_variable_get
+    assert_raise(NameError) { c.class_variable_get(:foo) }
+  end
+
+  def test_class_variable_set2
+    c = Class.new
+    c.class_variable_set(:@@foo, :foo)
+    assert_equal(:foo, c.class_eval { @@foo })
+    assert_raise(NameError) { c.class_variable_set(:foo, 1) }
+  end
+
+  def test_class_variable_defined
+    c = Class.new
+    c.class_eval { @@foo = :foo }
+    assert_equal(true, c.class_variable_defined?(:@@foo))
+    assert_equal(false, c.class_variable_defined?(:@@bar))
+    assert_raise(NameError) { c.class_variable_defined?(:foo) }
+  end
+
+  def test_export_method
+    m = Module.new
+    assert_raise(NameError) do
+      m.instance_eval { public(:foo) }
+    end
+  end
+
+  def test_attr
+    ruby do |w, r, e|
+      w.puts "$VERBOSE = true"
+      w.puts "c = Class.new"
+      w.puts "c.instance_eval do"
+      w.puts "  private"
+      w.puts "  attr_reader :foo"
+      w.puts "end"
+      w.puts "o = c.new"
+      w.puts "o.foo rescue p(:ok)"
+      w.puts "p(o.instance_eval { foo })"
+      w.close
+      assert_equal(":ok\nnil", r.read.chomp)
+      assert_match(/warning: private attribute\?$/, e.read.chomp)
+    end
+
+    c = Class.new
+    assert_raise(NameError) do
+      c.instance_eval { attr_reader :"$" }
+    end
+  end
+
+  def test_undef
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+        Class.instance_eval { undef_method(:foo) }
+      end.join
+    end
+
+    c = Class.new
+    assert_raise(NameError) do
+      c.instance_eval { undef_method(:foo) }
+    end
+
+    m = Module.new
+    assert_raise(NameError) do
+      m.instance_eval { undef_method(:foo) }
+    end
+
+    o = Object.new
+    assert_raise(NameError) do
+      class << o; self; end.instance_eval { undef_method(:foo) }
+    end
+
+    %w(object_id __send__ initialize).each do |m|
+      ruby do |w, r, e|
+        w.puts "$VERBOSE = false"
+        w.puts "Class.new.instance_eval { undef_method(:#{m}) }"
+        w.close
+        assert_equal("", r.read.chomp)
+        assert_match(/warning: undefining `#{m}' may cause serious problem$/, e.read.chomp)
+      end
+    end
+  end
+
+  def test_alias
+    m = Module.new
+    assert_raise(NameError) do
+      m.class_eval { alias foo bar }
+    end
+
+    ruby do |w, r, e|
+      w.puts "$VERBOSE = true"
+      w.puts "c = Class.new"
+      w.puts "c.class_eval do"
+      w.puts "  def foo; 1; end"
+      w.puts "  def bar; 2; end"
+      w.puts "end"
+      w.puts "c.class_eval { alias foo bar }"
+      w.puts "p c.new.foo"
+      w.close
+      assert_equal("2", r.read.chomp)
+      assert_match(/warning: discarding old foo$/, e.read.chomp)
+    end
+  end
+
+  def test_mod_constants
+    Module.const_set(:Foo, :foo)
+    assert_equal([:Foo], Module.constants(true))
+    assert_equal([:Foo], Module.constants(false))
+    Module.instance_eval { remove_const(:Foo) }
+  end
+
+  def test_frozen_class
+    m = Module.new
+    m.freeze
+    assert_raise(RuntimeError) do
+      m.instance_eval { undef_method(:foo) }
+    end
+
+    c = Class.new
+    c.freeze
+    assert_raise(RuntimeError) do
+      c.instance_eval { undef_method(:foo) }
+    end
+
+    o = Object.new
+    c = class << o; self; end
+    c.freeze
+    assert_raise(RuntimeError) do
+      c.instance_eval { undef_method(:foo) }
+    end
+  end
+
+  def test_method_defined
+    c = Class.new
+    c.class_eval do
+      def foo; end
+      def bar; end
+      def baz; end
+      public :foo
+      protected :bar
+      private :baz
+    end
+
+    assert_equal(true, c.public_method_defined?(:foo))
+    assert_equal(false, c.public_method_defined?(:bar))
+    assert_equal(false, c.public_method_defined?(:baz))
+
+    assert_equal(false, c.protected_method_defined?(:foo))
+    assert_equal(true, c.protected_method_defined?(:bar))
+    assert_equal(false, c.protected_method_defined?(:baz))
+
+    assert_equal(false, c.private_method_defined?(:foo))
+    assert_equal(false, c.private_method_defined?(:bar))
+    assert_equal(true, c.private_method_defined?(:baz))
+  end
+
+  def test_change_visibility_under_safe4
+    c = Class.new
+    c.class_eval do
+      def foo; end
+    end
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+        c.class_eval { private :foo }
+      end.join
+    end
+  end
+
+  def test_top_public_private
+    ruby do |w, r, e|
+      w.puts "private"
+      w.puts "def foo; :foo; end"
+      w.puts "public"
+      w.puts "def bar; :bar; end"
+      w.puts "p self.private_methods.grep(/^foo$|^bar$/)"
+      w.puts "p self.methods.grep(/^foo$|^bar$/)"
+      w.close
+      assert_equal("[:foo]\n[:bar]", r.read.chomp)
+      assert_equal("", e.read.chomp)
+    end
+  end
+
+  def test_append_features
+    t = nil
+    m = Module.new
+    m.module_eval do
+      def foo; :foo; end
+    end
+    class << m; self; end.class_eval do
+      define_method(:append_features) do |mod|
+        t = mod
+        super(mod)
+      end
+    end
+
+    m2 = Module.new
+    m2.module_eval { include(m) }
+    assert_equal(m2, t)
+
+    o = Object.new
+    o.extend(m2)
+    assert_equal(true, o.respond_to?(:foo))
+  end
+
+  def test_append_features_raise
+    m = Module.new
+    m.module_eval do
+      def foo; :foo; end
+    end
+    class << m; self; end.class_eval do
+      define_method(:append_features) {|mod| raise }
+    end
+
+    m2 = Module.new
+    assert_raise(RuntimeError) do
+      m2.module_eval { include(m) }
+    end
+
+    o = Object.new
+    o.extend(m2)
+    assert_equal(false, o.respond_to?(:foo))
+  end
+
+  def test_append_features_type_error
+    assert_raise(TypeError) do
+      Module.new.instance_eval { append_features(1) }
+    end
+  end
+
+  def test_included
+    m = Module.new
+    m.module_eval do
+      def foo; :foo; end
+    end
+    class << m; self; end.class_eval do
+      define_method(:included) {|mod| raise }
+    end
+
+    m2 = Module.new
+    assert_raise(RuntimeError) do
+      m2.module_eval { include(m) }
+    end
+
+    o = Object.new
+    o.extend(m2)
+    assert_equal(true, o.respond_to?(:foo))
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_numeric.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_numeric.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_numeric.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -51,16 +51,7 @@
   end
 
   def test_quo
-    DummyNumeric.class_eval do
-      def /(x); :div; end
-    end
-
-    assert_equal(:div, DummyNumeric.new.quo(0))
-
-  ensure
-    DummyNumeric.class_eval do
-      remove_method :/
-    end
+    assert_raise(ArgumentError) {DummyNumeric.new.quo(1)}
   end
 
   def test_divmod
@@ -73,231 +64,10 @@
     assert_equal(:mod, DummyNumeric.new.modulo(0))
     assert_equal([42, :mod], DummyNumeric.new.divmod(0))
 
-  ensure
-    DummyNumeric.class_eval do
-      remove_method :/, :%
-    end
-  end
+    assert_kind_of(Integer, 11.divmod(3.5).first, '[ruby-dev:34006]')
 
-  def test_scalar_p
-    assert(Numeric.new.scalar?)
-  end
-
-  def test_integer_p
-    assert(!Numeric.new.integer?)
-  end
-
-  def test_abs
-    a = DummyNumeric.new
-    DummyNumeric.class_eval do
-      def -@; :ok; end
-      def <(x); true; end
-    end
-
-    assert_equal(:ok, a.abs)
-
-    DummyNumeric.class_eval do
-      def <(x); false; end
-    end
-
-    assert_equal(a, a.abs)
-
   ensure
     DummyNumeric.class_eval do
-      remove_method :-@, :<
-    end
-  end
-
-  def test_zero_p
-    DummyNumeric.class_eval do
-      def ==(x); true; end
-    end
-
-    assert(DummyNumeric.new.zero?)
-
-  ensure
-    DummyNumeric.class_eval do
-      remove_method :==
-    end
-  end
-
-  def test_to_int
-    DummyNumeric.class_eval do
-      def to_i; :ok; end
-    end
-
-    assert_equal(:ok, DummyNumeric.new.to_int)
-
-  ensure
-    DummyNumeric.class_eval do
-      remove_method :to_i
-    end
-  end
-
-  def test_cmp
-    a = Numeric.new
-    assert_equal(0, a <=> a)
-    assert_nil(a <=> :foo)
-  end
-
-  def test_floor_ceil_round_truncate
-    DummyNumeric.class_eval do
-      def to_f; 1.5; end
-    end
-
-    a = DummyNumeric.new
-    assert_equal(1, a.floor)
-    assert_equal(2, a.ceil)
-    assert_equal(2, a.round)
-    assert_equal(1, a.truncate)
-
-    DummyNumeric.class_eval do
-      def to_f; 1.4; end
-    end
-
-    a = DummyNumeric.new
-    assert_equal(1, a.floor)
-    assert_equal(2, a.ceil)
-    assert_equal(1, a.round)
-    assert_equal(1, a.truncate)
-
-    DummyNumeric.class_eval do
-      def to_f; -1.5; end
-    end
-
-    a = DummyNumeric.new
-    assert_equal(-2, a.floor)
-    assert_equal(-1, a.ceil)
-    assert_equal(-2, a.round)
-    assert_equal(-1, a.truncate)
-
-  ensure
-    DummyNumeric.class_eval do
-      remove_method :to_f
-    end
-  end
-
-  def test_step
-    a = []
-    1.step(10) {|x| a << x }
-    assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
-
-    a = []
-    1.step(10, 2) {|x| a << x }
-    assert_equal([1, 3, 5, 7, 9], a)
-
-    assert_raise(ArgumentError) { 1.step(10, 1, 0) { } }
-    assert_raise(ArgumentError) { 1.step(10, 0) { } }
-
-    a = []
-    10.step(1, -2) {|x| a << x }
-    assert_equal([10, 8, 6, 4, 2], a)
-
-    a = []
-    1.0.step(10.0, 2.0) {|x| a << x }
-    assert_equal([1.0, 3.0, 5.0, 7.0, 9.0], a)
-
-    a = []
-    1.step(10, 2**32) {|x| a << x }
-    assert_equal([1], a)
-
-    a = []
-    10.step(1, -(2**32)) {|x| a << x }
-    assert_equal([10], a)
-  end
-
-  def test_num2long
-    assert_raise(TypeError) { 1 & nil }
-    assert_equal(1, 1 & 1.0)
-    assert_raise(RangeError) { 1 & 2147483648.0 }
-    o = Object.new
-    def o.to_int; 1; end
-    assert_equal(1, 1 & o)
-  end
-
-  def test_eql
-    assert(1 == 1.0)
-    assert(!(1.eql?(1.0)))
-    assert(!(1.eql?(2)))
-  end
-end
-require 'test/unit'
-
-class TestNumeric < Test::Unit::TestCase
-  class DummyNumeric < Numeric
-  end
-
-  def test_coerce
-    a, b = 1.coerce(2)
-    assert_equal(Fixnum, a.class)
-    assert_equal(Fixnum, b.class)
-
-    a, b = 1.coerce(2.0)
-    assert_equal(Float, a.class)
-    assert_equal(Float, b.class)
-
-    assert_raise(TypeError) { -Numeric.new }
-  end
-
-  def test_dummynumeric
-    a = DummyNumeric.new
-
-    DummyNumeric.class_eval do
-      def coerce(x); nil; end
-    end
-    assert_raise(TypeError) { -a }
-    assert_nil(1 <=> a)
-    assert_raise(ArgumentError) { 1 <= a }
-
-    DummyNumeric.class_eval do
-      def coerce(x); 1.coerce(x); end
-    end
-    assert_equal(2, 1 + a)
-    assert_equal(0, 1 <=> a)
-    assert(1 <= a)
-
-    DummyNumeric.class_eval do
-      def coerce(x); [x, 1]; end
-    end
-    assert_equal(-1, -a)
-
-  ensure
-    DummyNumeric.class_eval do
-      remove_method :coerce
-    end
-  end
-
-  def test_numeric
-    a = Numeric.new
-    assert_raise(TypeError) { def a.foo; end }
-    assert_raise(TypeError) { a.dup }
-  end
-
-  def test_quo
-    DummyNumeric.class_eval do
-      def /(x); :div; end
-    end
-
-    assert_equal(:div, DummyNumeric.new.quo(0))
-
-  ensure
-    DummyNumeric.class_eval do
-      remove_method :/
-    end
-  end
-
-  def test_divmod
-    DummyNumeric.class_eval do
-      def /(x); 42.0; end
-      def %(x); :mod; end
-    end
-
-    assert_equal(42, DummyNumeric.new.div(0))
-    assert_equal(:mod, DummyNumeric.new.modulo(0))
-    assert_equal([42, :mod], DummyNumeric.new.divmod(0))
-
-  ensure
-    DummyNumeric.class_eval do
       remove_method :/, :%
     end
   end
@@ -431,11 +201,9 @@
 
   def test_num2long
     assert_raise(TypeError) { 1 & nil }
-    assert_equal(1, 1 & 1.0)
-    assert_raise(RangeError) do
-      1 & 2147483648.0
-      1 & 9223372036854777856.0
-    end
+    assert_raise(TypeError) { 1 & 1.0 }
+    assert_raise(TypeError) { 1 & 2147483648.0 }
+    assert_raise(TypeError) { 1 & 9223372036854777856.0 }
     o = Object.new
     def o.to_int; 1; end
     assert_equal(1, 1 & o)

Added: MacRuby/trunk/test/ruby/test_object.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_object.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_object.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,339 @@
+require 'test/unit'
+require_relative 'envutil'
+
+class TestObject < Test::Unit::TestCase
+  def setup
+    @verbose = $VERBOSE
+    $VERBOSE = nil
+  end
+
+  def teardown
+    $VERBOSE = @verbose
+  end
+
+  def ruby(*r, &b)
+    EnvUtil.rubyexec(*r, &b)
+  end
+
+  def test_dup
+    assert_raise(TypeError) { 1.dup }
+    assert_raise(TypeError) { true.dup }
+    assert_raise(TypeError) { nil.dup }
+
+    assert_raise(TypeError) do
+      Object.new.instance_eval { initialize_copy(1) }
+    end
+  end
+
+  def test_instance_of
+    assert_raise(TypeError) { 1.instance_of?(1) }
+  end
+
+  def test_kind_of
+    assert_raise(TypeError) { 1.kind_of?(1) }
+  end
+
+  def test_taint_frozen_obj
+    o = Object.new
+    o.freeze
+    assert_raise(RuntimeError) { o.taint }
+
+    o = Object.new
+    o.taint
+    o.freeze
+    assert_raise(RuntimeError) { o.untaint }
+  end
+
+  def test_freeze_under_safe_4
+    o = Object.new
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+        o.freeze
+      end.join
+    end
+  end
+
+  def test_freeze_immediate
+    assert_equal(false, 1.frozen?)
+    1.freeze
+    assert_equal(true, 1.frozen?)
+    assert_equal(false, 2.frozen?)
+  end
+
+  def test_nil_to_f
+    assert_equal(0.0, nil.to_f)
+  end
+
+  def test_not
+    assert_equal(false, Object.new.send(:!))
+    assert_equal(true, nil.send(:!))
+  end
+
+  def test_true_and
+    assert_equal(true, true & true)
+    assert_equal(true, true & 1)
+    assert_equal(false, true & false)
+    assert_equal(false, true & nil)
+  end
+
+  def test_true_or
+    assert_equal(true, true | true)
+    assert_equal(true, true | 1)
+    assert_equal(true, true | false)
+    assert_equal(true, true | nil)
+  end
+
+  def test_true_xor
+    assert_equal(false, true ^ true)
+    assert_equal(false, true ^ 1)
+    assert_equal(true, true ^ false)
+    assert_equal(true, true ^ nil)
+  end
+
+  def test_false_and
+    assert_equal(false, false & true)
+    assert_equal(false, false & 1)
+    assert_equal(false, false & false)
+    assert_equal(false, false & nil)
+  end
+
+  def test_false_or
+    assert_equal(true, false | true)
+    assert_equal(true, false | 1)
+    assert_equal(false, false | false)
+    assert_equal(false, false | nil)
+  end
+
+  def test_false_xor
+    assert_equal(true, false ^ true)
+    assert_equal(true, false ^ 1)
+    assert_equal(false, false ^ false)
+    assert_equal(false, false ^ nil)
+  end
+
+  def test_methods
+    o = Object.new
+    a1 = o.methods
+    a2 = o.methods(false)
+
+    def o.foo; end
+
+    assert_equal([:foo], o.methods(true) - a1)
+    assert_equal([:foo], o.methods(false) - a2)
+  end
+
+  def test_methods2
+    c0 = Class.new
+    c1 = Class.new(c0)
+    c1.module_eval do
+      public   ; def foo; end
+      protected; def bar; end
+      private  ; def baz; end
+    end
+    c2 = Class.new(c1)
+    c2.module_eval do
+      public   ; def foo2; end
+      protected; def bar2; end
+      private  ; def baz2; end
+    end
+
+    o0 = c0.new
+    o2 = c2.new
+
+    assert_equal([:baz, :baz2], (o2.private_methods - o0.private_methods).sort)
+    assert_equal([:baz2], (o2.private_methods(false) - o0.private_methods(false)).sort)
+
+    assert_equal([:bar, :bar2], (o2.protected_methods - o0.protected_methods).sort)
+    assert_equal([:bar2], (o2.protected_methods(false) - o0.protected_methods(false)).sort)
+
+    assert_equal([:foo, :foo2], (o2.public_methods - o0.public_methods).sort)
+    assert_equal([:foo2], (o2.public_methods(false) - o0.public_methods(false)).sort)
+  end
+
+  def test_instance_variable_get
+    o = Object.new
+    o.instance_eval { @foo = :foo }
+    assert_equal(:foo, o.instance_variable_get(:@foo))
+    assert_equal(nil, o.instance_variable_get(:@bar))
+    assert_raise(NameError) { o.instance_variable_get(:foo) }
+  end
+
+  def test_instance_variable_set
+    o = Object.new
+    o.instance_variable_set(:@foo, :foo)
+    assert_equal(:foo, o.instance_eval { @foo })
+    assert_raise(NameError) { o.instance_variable_set(:foo, 1) }
+  end
+
+  def test_instance_variable_defined
+    o = Object.new
+    o.instance_eval { @foo = :foo }
+    assert_equal(true, o.instance_variable_defined?(:@foo))
+    assert_equal(false, o.instance_variable_defined?(:@bar))
+    assert_raise(NameError) { o.instance_variable_defined?(:foo) }
+  end
+
+  def test_convert_type
+    o = Object.new
+    def o.to_s; 1; end
+    assert_raise(TypeError) { String(o) }
+  end
+
+  def test_check_convert_type
+    o = Object.new
+    def o.to_a; 1; end
+    assert_raise(TypeError) { Array(o) }
+  end
+
+  def test_to_integer
+    o = Object.new
+    def o.to_i; nil; end
+    assert_raise(TypeError) { Integer(o) }
+  end
+
+  class MyInteger
+    def initialize(n); @num = n; end
+    def to_int; @num; end
+    def <=>(n); @num <=> n.to_int; end
+    def <=(n); @num <= n.to_int; end
+    def +(n); MyInteger.new(@num + n.to_int); end
+  end
+
+  def test_check_to_integer
+    o1 = MyInteger.new(1)
+    o9 = MyInteger.new(9)
+    n = 0
+    Range.new(o1, o9).step(2) {|x| n += x.to_int }
+    assert_equal(1+3+5+7+9, n)
+  end
+
+  def test_add_method_under_safe4
+    o = Object.new
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+        def o.foo
+        end
+      end.join
+    end
+  end
+
+  def test_redefine_method_under_verbose
+    ruby do |w, r, e|
+      w.puts "$VERBOSE = true"
+      w.puts "o = Object.new"
+      w.puts "def o.foo; 1; end"
+      w.puts "def o.foo; 2; end"
+      w.puts "p o.foo"
+      w.close
+      assert_equal("2", r.read.chomp)
+      assert_match(/warning: method redefined; discarding old foo$/, e.read.chomp)
+    end
+  end
+
+  def test_redefine_method_which_may_case_serious_problem
+    ruby do |w, r, e|
+      w.puts "$VERBOSE = false"
+      w.puts "def (Object.new).object_id; end"
+      w.close
+      assert_equal("", r.read.chomp)
+      assert_match(/warning: redefining `object_id' may cause serious problem$/, e.read.chomp)
+    end
+
+    ruby do |w, r, e|
+      w.puts "$VERBOSE = false"
+      w.puts "def (Object.new).__send__; end"
+      w.close
+      assert_equal("", r.read.chomp)
+      assert_match(/warning: redefining `__send__' may cause serious problem$/, e.read.chomp)
+    end
+  end
+
+  def test_remove_method
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+        Object.instance_eval { remove_method(:foo) }
+      end.join
+    end
+
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+        Class.instance_eval { remove_method(:foo) }
+      end.join
+    end
+
+    c = Class.new
+    c.freeze
+    assert_raise(RuntimeError) do
+      c.instance_eval { remove_method(:foo) }
+    end
+
+    %w(object_id __send__ initialize).each do |m|
+      ruby do |w, r, e|
+        w.puts "$VERBOSE = false"
+        w.puts "begin"
+        w.puts "  Class.new.instance_eval { remove_method(:#{m}) }"
+        w.puts "rescue NameError"
+        w.puts "  p :ok"
+        w.puts "end"
+        w.close
+        assert_equal(":ok", r.read.chomp)
+        assert_match(/warning: removing `#{m}' may cause serious problem$/, e.read.chomp)
+      end
+    end
+  end
+
+  def test_method_missing
+    assert_raise(ArgumentError) do
+      1.instance_eval { method_missing }
+    end
+
+    c = Class.new
+    c.class_eval do
+      protected
+      def foo; end
+    end
+    assert_raise(NoMethodError) do
+      c.new.foo
+    end
+
+    assert_raise(NoMethodError) do
+      1.instance_eval { method_missing(:method_missing) }
+    end
+  end
+
+  def test_send_with_no_arguments
+    assert_raise(ArgumentError) { 1.send }
+  end
+
+  def test_specific_eval_with_wrong_arguments
+    assert_raise(ArgumentError) do
+      1.instance_eval("foo") { foo }
+    end
+
+    assert_raise(ArgumentError) do
+      1.instance_eval
+    end
+
+    assert_raise(ArgumentError) do
+      1.instance_eval("", 1, 1, 1)
+    end
+  end
+
+  def test_instance_exec
+    x = 1.instance_exec(42) {|a| self + a }
+    assert_equal(43, x)
+
+    x = "foo".instance_exec("bar") {|a| self + a }
+    assert_equal("foobar", x)
+  end
+
+  def test_extend
+    assert_raise(ArgumentError) do
+      1.extend
+    end
+  end
+end

Modified: MacRuby/trunk/test/ruby/test_objectspace.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_objectspace.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_objectspace.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -33,4 +33,19 @@
   deftest_id2ref(true)
   deftest_id2ref(false)
   deftest_id2ref(nil)
+
+  def test_count_objects
+    h = {}
+    ObjectSpace.count_objects(h)
+    assert_kind_of(Hash, h)
+    assert(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
+    assert(h.values.all? {|x| x.is_a?(Integer) })
+
+    h = ObjectSpace.count_objects
+    assert_kind_of(Hash, h)
+    assert(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
+    assert(h.values.all? {|x| x.is_a?(Integer) })
+
+    assert_raise(TypeError) { ObjectSpace.count_objects(1) }
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_pack.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_pack.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_pack.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -63,6 +63,7 @@
     assert_equal a, a.pack("P").unpack("P*")
     assert_equal "a", a.pack("P").unpack("P")[0]
     assert_equal a, a.pack("P").freeze.unpack("P*")
+    assert_raise(ArgumentError) { (a.pack("P") + "").unpack("P*") }
   end
 
   def test_pack_p
@@ -70,6 +71,7 @@
     assert_equal a, a.pack("p").unpack("p*")
     assert_equal a[0], a.pack("p").unpack("p")[0]
     assert_equal a, a.pack("p").freeze.unpack("p*")
+    assert_raise(ArgumentError) { (a.pack("p") + "").unpack("p*") }
   end
 
   def test_format_string_modified
@@ -429,4 +431,14 @@
     assert_equal([0xffffffff], "\217\377\377\377\177".unpack("w"), [0xffffffff])
     assert_equal([0x100000000], "\220\200\200\200\000".unpack("w"), [0x100000000])
   end
+
+  def test_modify_under_safe4
+    s = "foo"
+    assert_raise(SecurityError) do
+      Thread.new do
+        $SAFE = 4
+        s.clear
+      end.join
+    end
+  end
 end

Added: MacRuby/trunk/test/ruby/test_parse.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_parse.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_parse.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,874 @@
+require 'test/unit'
+require 'stringio'
+
+class TestParse < Test::Unit::TestCase
+  def setup
+    @verbose = $VERBOSE
+    $VERBOSE = nil
+  end
+
+  def teardown
+    $VERBOSE = @verbose
+  end
+
+  def test_else_without_rescue
+    x = eval <<-END
+      begin
+      else
+        42
+      end
+    END
+    assert_equal(42, x)
+  end
+  
+  def test_alias_backref
+    assert_raise(SyntaxError) do
+      eval <<-END
+        alias $foo $1
+      END
+    end
+  end
+
+  def test_command_call
+    t = Object.new
+    def t.foo(x); x; end
+
+    a = false
+    b = c = d = true
+    assert_nothing_raised do
+      eval <<-END
+        a &&= t.foo 42
+        b &&= t.foo 42
+        c &&= t.foo nil
+        d &&= t.foo false
+      END
+    end
+    assert_equal([false, 42, nil, false], [a, b, c, d])
+
+    a = 3
+    assert_nothing_raised { eval("a &= t.foo 5") }
+    assert_equal(1, a)
+
+    a = [nil, nil, true, true]
+    assert_nothing_raised do
+      eval <<-END
+        a[0] ||= t.foo 42
+        a[1] &&= t.foo 42
+        a[2] ||= t.foo 42
+        a[3] &&= t.foo 42
+      END
+    end
+    assert_equal([42, nil, true, 42], a)
+
+    o = Object.new
+    class << o
+      attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
+    end
+    o.foo = o.Foo = o::baz = nil
+    o.bar = o.Bar = o::qux = 1
+    assert_nothing_raised do
+      eval <<-END
+        o.foo ||= t.foo 42
+        o.bar &&= t.foo 42
+        o.Foo ||= t.foo 42
+        o.Bar &&= t.foo 42
+        o::baz ||= t.foo 42
+        o::qux &&= t.foo 42
+      END
+    end
+    assert_equal([42, 42], [o.foo, o.bar])
+    assert_equal([42, 42], [o.Foo, o.Bar])
+    assert_equal([42, 42], [o::baz, o::qux])
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        $1 ||= t.foo 42
+      END
+    end
+
+    def t.bar(x); x + yield; end
+
+    a = b = nil
+    assert_nothing_raised do
+      eval <<-END
+        a = t.bar "foo" do
+          "bar"
+        end.gsub "ob", "OB"
+        b = t.bar "foo" do
+          "bar"
+        end::gsub "ob", "OB"
+      END
+    end
+    assert_equal("foOBar", a)
+    assert_equal("foOBar", b)
+
+    a = nil
+    assert_nothing_raised do
+      t.instance_eval <<-END
+        a = bar "foo" { "bar" }
+      END
+    end
+    assert_equal("foobar", a)
+
+    a = nil
+    assert_nothing_raised do
+      eval <<-END
+        a = t::bar "foo" { "bar" }
+      END
+    end
+    assert_equal("foobar", a)
+
+    def t.baz(*r)
+      @baz = r + (block_given? ? [yield] : [])
+    end
+
+    assert_nothing_raised do
+      t.instance_eval "baz ()"
+    end
+    assert_equal([], t.instance_eval { @baz })
+
+    assert_nothing_raised do
+      t.instance_eval "baz (1), 2"
+    end
+    assert_equal([1, 2], t.instance_eval { @baz })
+
+    assert_nothing_raised do
+      t.instance_eval "baz (3, 4)"
+    end
+    assert_equal([3, 4], t.instance_eval { @baz })
+
+    assert_nothing_raised do
+      t.instance_eval "baz (5, &proc{6})"
+    end
+    assert_equal([5, 6], t.instance_eval { @baz })
+
+    assert_nothing_raised do
+      t.instance_eval "baz (7 => 8)"
+    end
+    assert_equal([{ 7 => 8 }], t.instance_eval { @baz })
+
+    assert_nothing_raised do
+      t.instance_eval "baz (9, 10 => 11)"
+    end
+    assert_equal([9, { 10 => 11 }], t.instance_eval { @baz })
+
+    assert_nothing_raised do
+      t.instance_eval "baz (12, 13, 14 => 15)"
+    end
+    assert_equal([12, 13, { 14 => 15 }], t.instance_eval { @baz })
+
+    assert_nothing_raised do
+      t.instance_eval "baz (&proc {16})"
+    end
+    assert_equal([16], t.instance_eval { @baz })
+  end
+
+  def test_mlhs_node
+    c = Class.new
+    class << c
+      attr_accessor :foo, :bar, :Foo, :Bar
+      FOO = BAR = nil
+    end
+
+    assert_nothing_raised do
+      eval <<-END
+        c::foo, c::bar = 1, 2
+        c.Foo, c.Bar = 1, 2
+        c::FOO, c::BAR = 1, 2
+      END
+    end
+    assert_equal([1, 2], [c::foo, c::bar])
+    assert_equal([1, 2], [c.Foo, c.Bar])
+    assert_equal([1, 2], [c::FOO, c::BAR])
+  end
+
+  def test_dynamic_constant_assignment
+    assert_raise(SyntaxError) do
+      Object.new.instance_eval <<-END
+        def foo
+          self::FOO, self::BAR = 1, 2
+          ::FOO, ::BAR = 1, 2
+        end
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        $1, $2 = 1, 2
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      Object.new.instance_eval <<-END
+        def foo
+          ::FOO = 1
+        end
+      END
+    end
+
+    c = Class.new
+    assert_raise(SyntaxError) do
+      eval <<-END
+        c::FOO &= 1
+        ::FOO &= 1
+      END
+    end
+
+    c = Class.new
+    assert_raise(SyntaxError) do
+      eval <<-END
+        $1 &= 1
+      END
+    end
+  end
+
+  def test_class_module
+    assert_raise(SyntaxError) do
+      eval <<-END
+        class foo; end
+      END
+    end
+    
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def foo
+          class Foo; end
+          module Bar; end
+        end
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        class Foo Bar; end
+      END
+    end
+  end
+
+  def test_op_name
+    o = Object.new
+    def o.>(x); x; end
+    def o./(x); x; end
+
+    a = nil
+    assert_nothing_raised do
+      o.instance_eval <<-END
+        undef >, /
+      END
+    end
+  end
+
+  def test_arg
+    o = Object.new
+    class << o
+      attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
+    end
+    o.foo = o.Foo = o::baz = nil
+    o.bar = o.Bar = o::qux = 1
+    assert_nothing_raised do
+      eval <<-END
+        o.foo ||= 42
+        o.bar &&= 42
+        o.Foo ||= 42
+        o.Bar &&= 42
+        o::baz ||= 42
+        o::qux &&= 42
+      END
+    end
+    assert_equal([42, 42], [o.foo, o.bar])
+    assert_equal([42, 42], [o.Foo, o.Bar])
+    assert_equal([42, 42], [o::baz, o::qux])
+
+    a = nil
+    assert_nothing_raised do
+      eval <<-END
+        a = -2.0 ** 2
+      END
+    end
+    assert_equal(-4.0, a)
+  end
+
+  def test_open_args
+    o = Object.new
+    def o.foo(*r); r.inject(42, :+); end
+
+    a = nil
+    assert_nothing_raised do
+      o.instance_eval <<-END
+        a = foo ()
+      END
+    end
+    assert_equal(42, a)
+  end
+
+  def test_block_variable
+    o = Object.new
+    def o.foo(*r); yield(*r); end
+
+    a = nil
+    assert_nothing_raised do
+      eval <<-END
+        o.foo 1 {|; a| a = 42 }
+      END
+    end
+    assert_nil(a)
+  end
+
+  def test_bad_arg
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def foo(FOO); end
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def foo(@foo); end
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def foo($foo); end
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def foo(@@foo); end
+      END
+    end
+
+    o = Object.new
+    def o.foo(*r); yield(*r); end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        o.foo 1 {|; @a| @a = 42 }
+      END
+    end
+  end
+
+  def test_do_lambda
+    a = b = nil
+    assert_nothing_raised do
+      eval <<-END
+        a = -> do
+          b = 42
+        end
+      END
+    end
+    a.call
+    assert_equal(42, b)
+  end
+
+  def test_block_call_colon2
+    o = Object.new
+    def o.foo(x); x + yield; end
+
+    a = b = nil
+    assert_nothing_raised do
+      o.instance_eval <<-END
+        a = foo 1 do 42 end.to_s
+        b = foo 1 do 42 end::to_s
+      END
+    end
+    assert_equal("43", a)
+    assert_equal("43", b)
+  end
+
+  def test_call_method
+    a = b = nil
+    assert_nothing_raised do
+      eval <<-END
+        a = proc {|x| x + "bar" }.("foo")
+        b = proc {|x| x + "bar" }::("foo")
+      END
+    end
+    assert_equal("foobar", a)
+    assert_equal("foobar", b)
+  end
+
+  def test_xstring
+    assert_raise(Errno::ENOENT) do
+      eval("``")
+    end
+  end
+
+  def test_words
+    assert_equal([], %W( ))
+  end
+  
+  def test_dstr
+    @@foo = 1
+    assert_equal("foo 1 bar", "foo #@@foo bar")
+    "1" =~ /(.)/
+    assert_equal("foo 1 bar", "foo #$1 bar")
+  end
+
+  def test_dsym
+    assert_nothing_raised { eval(':""') }
+  end
+
+  def test_arg2
+    o = Object.new
+
+    assert_nothing_raised do
+      eval <<-END
+        def o.foo(a=42,*r,z,&b); b.call(r.inject(a*1000+z*100, :+)); end
+      END
+    end
+    assert_equal(-1405, o.foo(1,2,3,4) {|x| -x })
+    assert_equal(-1302, o.foo(1,2,3) {|x| -x })
+    assert_equal(-1200, o.foo(1,2) {|x| -x })
+    assert_equal(-42100, o.foo(1) {|x| -x })
+    assert_raise(ArgumentError) { o.foo() }
+
+    assert_nothing_raised do
+      eval <<-END
+        def o.foo(a=42,z,&b); b.call(a*1000+z*100); end
+      END
+    end
+    assert_equal(-1200, o.foo(1,2) {|x| -x } )
+    assert_equal(-42100, o.foo(1) {|x| -x } )
+    assert_raise(ArgumentError) { o.foo() }
+
+    assert_nothing_raised do
+      eval <<-END
+        def o.foo(*r,z,&b); b.call(r.inject(z*100, :+)); end
+      END
+    end
+    assert_equal(-303, o.foo(1,2,3) {|x| -x } )
+    assert_equal(-201, o.foo(1,2) {|x| -x } )
+    assert_equal(-100, o.foo(1) {|x| -x } )
+    assert_raise(ArgumentError) { o.foo() }
+  end
+
+  def test_duplicate_argument
+    assert_raise(SyntaxError) do
+      eval <<-END
+        1.times {|&b?| }
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        1.times {|a, a|}
+      END
+    end
+
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def foo(a, a); end
+      END
+    end
+  end
+
+  def test_define_singleton_error
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def ("foo").foo; end
+      END
+    end
+  end
+
+  def test_backquote
+    t = Object.new
+
+    assert_nothing_raised do
+      eval <<-END
+        def t.`(x); "foo" + x + "bar"; end
+      END
+    end
+    a = b = nil
+    assert_nothing_raised do
+      eval <<-END
+        a = t.` "zzz"
+        1.times {|;z| t.` ("zzz") }
+      END
+      t.instance_eval <<-END
+        b = `zzz`
+      END
+    end
+    assert_equal("foozzzbar", a)
+    assert_equal("foozzzbar", b)
+  end
+
+  def test_carrige_return
+    assert_equal(2, eval("1 +\r\n1"))
+  end
+
+  def test_string
+    assert_raise(SyntaxError) do
+      eval '"\xg1"'
+    end
+
+    assert_raise(SyntaxError) do
+      eval '"\u{1234"'
+    end
+
+    assert_raise(SyntaxError) do
+      eval '"\M1"'
+    end
+
+    assert_raise(SyntaxError) do
+      eval '"\C1"'
+    end
+
+    assert_equal("\x81", eval('"\C-\M-a"'))
+    assert_equal("\177", eval('"\c?"'))
+  end
+
+  def test_question
+    assert_raise(SyntaxError) { eval('?') }
+    assert_raise(SyntaxError) { eval('? ') }
+    assert_raise(SyntaxError) { eval("?\n") }
+    assert_raise(SyntaxError) { eval("?\t") }
+    assert_raise(SyntaxError) { eval("?\v") }
+    assert_raise(SyntaxError) { eval("?\r") }
+    assert_raise(SyntaxError) { eval("?\f") }
+    assert_equal("\u{1234}", eval("?\u{1234}"))
+    assert_equal("\u{1234}", eval('?\u{1234}'))
+  end
+
+  def test_percent
+    assert_equal(:foo, eval('%s(foo)'))
+    assert_raise(SyntaxError) { eval('%s') }
+    assert_raise(SyntaxError) { eval('%ss') }
+    assert_raise(SyntaxError) { eval('%z()') }
+  end
+
+  def test_symbol
+    assert_raise(SyntaxError) do
+      eval ":'foo\0bar'"
+    end
+    assert_raise(SyntaxError) do
+      eval ':"foo\u0000bar"'
+    end
+    assert_raise(SyntaxError) do
+      eval ':"foo\u{0}bar"'
+    end
+    assert_raise(SyntaxError) do
+      eval ':"foo\u{}bar"'
+    end
+  end
+
+  def test_parse_string
+    assert_raise(SyntaxError) do
+      eval <<-END
+/
+      END
+    end
+  end
+
+  def test_here_document
+    x = nil
+
+    assert_raise(SyntaxError) do
+      eval %q(
+<<FOO
+      )
+    end
+
+    assert_raise(SyntaxError) do
+      eval %q(
+<<FOO
+#$
+FOO
+      )
+    end
+
+    assert_raise(SyntaxError) do
+      eval %q(
+<<"
+      )
+    end
+
+    assert_raise(SyntaxError) do
+      eval %q(
+<<``
+      )
+    end
+
+    assert_raise(SyntaxError) do
+      eval %q(
+<<--
+      )
+    end
+
+    assert_raise(SyntaxError) do
+      eval %q(
+<<FOO
+#$
+foo
+FOO
+      )
+    end
+
+    assert_nothing_raised do
+      eval "x = <<FOO\r\n1\r\nFOO"
+    end
+    assert_equal("1\n", x)
+  end
+
+  def test_magic_comment
+    x = nil
+    assert_nothing_raised do
+      eval <<-END
+# coding = utf-8
+x = __ENCODING__
+      END
+    end
+    assert_equal(Encoding.find("UTF-8"), x)
+
+    assert_raise(ArgumentError) do
+      eval <<-END
+# coding = foobarbazquxquux_dummy_enconding
+x = __ENCODING__
+      END
+    end
+  end
+
+  def test_utf8_bom
+    x = nil
+    assert_nothing_raised do
+      eval "\xef\xbb\xbf x = __ENCODING__"
+    end
+    assert_equal(Encoding.find("UTF-8"), x)
+    assert_raise(NameError) { eval "\xef" }
+  end
+
+  def test_dot_in_next_line
+    x = nil
+    assert_nothing_raised do
+      eval <<-END
+        x = 1
+        .to_s
+      END
+    end
+    assert_equal("1", x)
+  end
+
+  def test_pow_asgn
+    x = 3
+    assert_nothing_raised { eval("x **= 2") }
+    assert_equal(9, x)
+  end
+
+  def test_embedded_rd
+    assert_raise(SyntaxError) do
+      eval <<-END
+=begin
+      END
+    end
+  end
+
+  def test_float
+    assert_equal(1.0/0, eval("1e10000"))
+    assert_raise(SyntaxError) { eval('1_E') }
+    assert_raise(SyntaxError) { eval('1E1E1') }
+  end
+
+  def test_global_variable
+    assert_equal(nil, eval('$-x'))
+    assert_equal(nil, eval('alias $preserve_last_match $&'))
+    assert_equal(nil, eval('alias $& $test_parse_foobarbazqux'))
+    $test_parse_foobarbazqux = nil
+    assert_equal(nil, $&)
+    assert_equal(nil, eval('alias $& $preserve_last_match'))
+    assert_raise(SyntaxError) { eval('$#') }
+  end
+
+  def test_invalid_instance_variable
+    assert_raise(SyntaxError) { eval('@#') }
+  end
+
+  def test_invalid_class_variable
+    assert_raise(SyntaxError) { eval('@@1') }
+  end
+
+  def test_invalid_char
+    x = 1
+    assert_equal(1, eval("\x01x"))
+    assert_equal(nil, eval("\x04x"))
+  end
+
+  def test_literal_concat
+    x = "baz"
+    assert_equal("foobarbaz", eval('"foo" "bar#{x}"'))
+  end
+
+  def test_unassignable
+    assert_raise(SyntaxError) do
+      eval %q(self = 1)
+    end
+    assert_raise(SyntaxError) do
+      eval %q(nil = 1)
+    end
+    assert_raise(SyntaxError) do
+      eval %q(true = 1)
+    end
+    assert_raise(SyntaxError) do
+      eval %q(false = 1)
+    end
+    assert_raise(SyntaxError) do
+      eval %q(__FILE__ = 1)
+    end
+    assert_raise(SyntaxError) do
+      eval %q(__LINE__ = 1)
+    end
+    assert_raise(SyntaxError) do
+      eval %q(__ENCODING__ = 1)
+    end
+    assert_raise(SyntaxError) do
+      eval <<-END
+        def foo
+          FOO = 1
+        end
+      END
+    end
+  end
+
+  def test_block_dup
+    assert_raise(SyntaxError) do
+      eval <<-END
+        foo(&proc{}) {}
+      END
+    end
+  end
+
+  def test_set_backref
+    assert_raise(SyntaxError) do
+      eval <<-END
+        $& = 1
+      END
+    end
+  end
+
+  def test_arg_concat
+    o = Object.new
+    class << o; self; end.instance_eval do
+      define_method(:[]=) {|*r, &b| b.call(r) }
+    end
+    r = nil
+    assert_nothing_raised do
+      eval <<-END
+        o[&proc{|x| r = x }] = 1
+      END
+    end
+    assert_equal([1], r)
+  end
+
+  def test_void_expr_stmts_value
+    # This test checks if void contexts are warned correctly.
+    # Thus, warnings MUST NOT be suppressed.
+    $VERBOSE = true
+    stderr = $stderr
+    $stderr = StringIO.new("")
+    x = 1
+    assert_nil eval("x; nil")
+    assert_nil eval("1+1; nil")
+    assert_nil eval("TestParse; nil")
+    assert_nil eval("::TestParse; nil")
+    assert_nil eval("x..x; nil")
+    assert_nil eval("x...x; nil")
+    assert_nil eval("self; nil")
+    assert_nil eval("nil; nil")
+    assert_nil eval("true; nil")
+    assert_nil eval("false; nil")
+    assert_nil eval("defined?(1); nil")
+
+    assert_raise(SyntaxError) do
+      eval %q(1; next; 2)
+    end
+
+    o = Object.new
+    assert_nothing_raised do
+      eval <<-END
+        x = def o.foo; end
+      END
+    end
+    assert_equal($stderr.string.lines.to_a.size, 14)
+    $stderr = stderr
+  end
+
+  def test_assign_in_conditional
+    assert_raise(SyntaxError) do
+      eval <<-END
+        (x, y = 1, 2) ? 1 : 2
+      END
+    end
+
+    assert_nothing_raised do
+      eval <<-END
+        if @x = true
+          1
+        else
+          2
+        end
+      END
+    end
+  end
+
+  def test_literal_in_conditional
+    assert_nothing_raised do
+      eval <<-END
+        "foo" ? 1 : 2
+      END
+    end
+
+    assert_nothing_raised do
+      x = "bar"
+      eval <<-END
+        /foo#{x}baz/ ? 1 : 2
+      END
+    end
+
+    assert_nothing_raised do
+      eval <<-END
+        (true..false) ? 1 : 2
+      END
+    end
+
+    assert_nothing_raised do
+      eval <<-END
+        ("foo".."bar") ? 1 : 2
+      END
+    end
+
+    assert_nothing_raised do
+      x = "bar"
+      eval <<-END
+        :"foo#{"x"}baz" ? 1 : 2
+      END
+    end
+  end
+
+  def test_no_blockarg
+    assert_raise(SyntaxError) do
+      eval <<-END
+        yield(&:+)
+      END
+    end
+  end
+
+  def test_intern
+    assert_equal(':""', ''.intern.inspect)
+    assert_equal(':$foo', '$foo'.intern.inspect)
+    assert_equal(':"!foo"', '!foo'.intern.inspect)
+    assert_equal(':"foo=="', "foo==".intern.inspect)
+  end
+
+  def test_all_symbols
+    x = Symbol.all_symbols
+    assert_kind_of(Array, x)
+    assert(x.all? {|s| s.is_a?(Symbol) })
+  end
+
+  def test_is_class_id
+    c = Class.new
+    assert_raise(NameError) do
+      c.instance_eval { remove_class_variable(:@var) }
+    end
+  end
+end

Modified: MacRuby/trunk/test/ruby/test_pipe.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_pipe.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_pipe.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,5 +1,4 @@
 require 'test/unit'
-require 'require_relative'
 require_relative 'ut_eof'
 
 class TestPipe < Test::Unit::TestCase

Modified: MacRuby/trunk/test/ruby/test_process.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_process.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_process.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,30 @@
 require 'test/unit'
+require 'tmpdir'
+require_relative 'envutil'
 
 class TestProcess < Test::Unit::TestCase
+  RUBY = EnvUtil.rubybin
+
+  def write_file(filename, content)
+    File.open(filename, "w") {|f|
+      f << content
+    }
+  end
+
+  def with_tmpchdir
+    Dir.mktmpdir {|d|
+      Dir.chdir(d) {
+        yield d
+      }
+    }
+  end
+
+  def run_in_child(str) # should be called in a temporary directory
+    write_file("test-script", str)
+    Process.wait spawn(RUBY, "test-script")
+    $?
+  end
+
   def test_rlimit_availability
     begin
       Process.getrlimit(nil)
@@ -21,21 +45,799 @@
 
   def test_rlimit_nofile
     return unless rlimit_exist?
-    pid = fork {
-      cur_nofile, max_nofile = Process.getrlimit(Process::RLIMIT_NOFILE)
-      begin
-        Process.setrlimit(Process::RLIMIT_NOFILE, 0, max_nofile)
-      rescue Errno::EINVAL
-        exit 0
+    with_tmpchdir {
+      write_file 's', <<-"End"
+	cur_nofile, max_nofile = Process.getrlimit(Process::RLIMIT_NOFILE)
+	result = 1
+	begin
+	  Process.setrlimit(Process::RLIMIT_NOFILE, 0, max_nofile)
+	rescue Errno::EINVAL
+	  result = 0
+	end
+	if result == 1
+	  begin
+	    IO.pipe
+	  rescue Errno::EMFILE
+	   result = 0
+	  end
+	end
+	Process.setrlimit(Process::RLIMIT_NOFILE, cur_nofile, max_nofile)
+	exit result
+      End
+      pid = spawn RUBY, "s"
+      Process.wait pid
+      assert_equal(0, $?.to_i, "#{$?}")
+    }
+  end
+
+  def test_rlimit_name
+    return unless rlimit_exist?
+    [
+      :AS, "AS",
+      :CORE, "CORE",
+      :CPU, "CPU",
+      :DATA, "DATA",
+      :FSIZE, "FSIZE",
+      :MEMLOCK, "MEMLOCK",
+      :NOFILE, "NOFILE",
+      :NPROC, "NPROC",
+      :RSS, "RSS",
+      :STACK, "STACK",
+      :SBSIZE, "SBSIZE",
+    ].each {|name|
+      if Process.const_defined? "RLIMIT_#{name}"
+        assert_nothing_raised { Process.getrlimit(name) }
+      else
+        assert_raise(ArgumentError) { Process.getrlimit(name) }
       end
+    }
+    assert_raise(ArgumentError) { Process.getrlimit(:FOO) }
+    assert_raise(ArgumentError) { Process.getrlimit("FOO") }
+  end
+
+  def test_rlimit_value
+    return unless rlimit_exist?
+    assert_raise(ArgumentError) { Process.setrlimit(:CORE, :FOO) }
+    assert_raise(Errno::EPERM) { Process.setrlimit(:NOFILE, :INFINITY) }
+    assert_raise(Errno::EPERM) { Process.setrlimit(:NOFILE, "INFINITY") }
+  end
+
+  TRUECOMMAND = [RUBY, '-e', '']
+
+  def test_execopts_opts
+    assert_nothing_raised {
+      Process.wait Process.spawn(*TRUECOMMAND, {})
+    }
+    assert_raise(ArgumentError) {
+      Process.wait Process.spawn(*TRUECOMMAND, :foo => 100)
+    }
+    assert_raise(ArgumentError) {
+      Process.wait Process.spawn(*TRUECOMMAND, Process => 100)
+    }
+  end
+
+  def test_execopts_pgroup
+    assert_nothing_raised { system(*TRUECOMMAND, :pgroup=>false) }
+
+    io = IO.popen([RUBY, "-e", "print Process.getpgrp"])
+    assert_equal(Process.getpgrp.to_s, io.read)
+    io.close
+
+    io = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true])
+    assert_equal(io.pid.to_s, io.read)
+    io.close
+
+    assert_raise(ArgumentError) { system(*TRUECOMMAND, :pgroup=>-1) }
+    assert_raise(Errno::EPERM) { Process.wait spawn(*TRUECOMMAND, :pgroup=>2) }
+
+    io1 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>true])
+    io2 = IO.popen([RUBY, "-e", "print Process.getpgrp", :pgroup=>io1.pid])
+    assert_equal(io1.pid.to_s, io1.read)
+    assert_equal(io1.pid.to_s, io2.read)
+    Process.wait io1.pid
+    Process.wait io2.pid
+    io1.close
+    io2.close
+  end
+
+  def test_execopts_rlimit
+    return unless rlimit_exist?
+    assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_foo=>0) }
+    assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_NOFILE=>0) }
+    assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[]) }
+    assert_raise(ArgumentError) { system(*TRUECOMMAND, :rlimit_nofile=>[1,2,3]) }
+
+    max = Process.getrlimit(:CORE).last
+
+    n = max
+    IO.popen([RUBY, "-e",
+             "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io|
+      assert_equal("[#{n}, #{n}]\n", io.read)
+    }
+
+    n = 0
+    IO.popen([RUBY, "-e",
+             "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io|
+      assert_equal("[#{n}, #{n}]\n", io.read)
+    }
+
+    n = max
+    IO.popen([RUBY, "-e",
+             "p Process.getrlimit(:CORE)", :rlimit_core=>[n]]) {|io|
+      assert_equal("[#{n}, #{n}]", io.read.chomp)
+    }
+
+    m, n = 0, max
+    IO.popen([RUBY, "-e",
+             "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io|
+      assert_equal("[#{m}, #{n}]", io.read.chomp)
+    }
+
+    m, n = 0, 0
+    IO.popen([RUBY, "-e",
+             "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io|
+      assert_equal("[#{m}, #{n}]", io.read.chomp)
+    }
+
+    n = max
+    IO.popen([RUBY, "-e",
+      "p Process.getrlimit(:CORE), Process.getrlimit(:CPU)",
+      :rlimit_core=>n, :rlimit_cpu=>3600]) {|io|
+      assert_equal("[#{n}, #{n}]\n[3600, 3600]", io.read.chomp)
+    }
+  end
+
+  ENVCOMMAND = [RUBY, '-e', 'ENV.each {|k,v| puts "#{k}=#{v}" }']
+
+  def test_execopts_env
+    assert_raise(ArgumentError) {
+      system({"F=O"=>"BAR"}, *TRUECOMMAND)
+    }
+
+    h = {}
+    ENV.each {|k,v| h[k] = nil unless k.upcase == "PATH" }
+    IO.popen([h, RUBY, '-e', 'puts ENV.keys.map{|e|e.upcase}']) {|io|
+      assert_equal("PATH\n", io.read)
+    }
+
+    IO.popen([{"FOO"=>"BAR"}, *ENVCOMMAND]) {|io|
+      assert_match(/^FOO=BAR$/, io.read)
+    }
+
+    with_tmpchdir {|d|
+      system({"fofo"=>"haha"}, *ENVCOMMAND, STDOUT=>"out")
+      assert_match(/^fofo=haha$/, File.read("out").chomp)
+    }
+  end
+
+  def test_execopts_unsetenv_others
+    IO.popen([*ENVCOMMAND, :unsetenv_others=>true]) {|io|
+      assert_equal("", io.read)
+    }
+    IO.popen([{"A"=>"B"}, *ENVCOMMAND, :unsetenv_others=>true]) {|io|
+      assert_equal("A=B\n", io.read)
+    }
+  end
+
+  PWD = [RUBY, '-e', 'puts Dir.pwd']
+
+  def test_execopts_chdir
+    with_tmpchdir {|d|
+      IO.popen([*PWD, :chdir => d]) {|io|
+        assert_equal(d, io.read.chomp)
+      }
+      assert_raise(Errno::ENOENT) {
+        Process.wait Process.spawn(*PWD, :chdir => "d/notexist")
+      }
+    }
+  end
+
+  UMASK = [RUBY, '-e', 'printf "%04o\n", File.umask']
+
+  def test_execopts_umask
+    IO.popen([*UMASK, :umask => 0]) {|io|
+      assert_equal("0000", io.read.chomp)
+    }
+    IO.popen([*UMASK, :umask => 0777]) {|io|
+      assert_equal("0777", io.read.chomp)
+    }
+  end
+
+  def with_pipe
+    begin
+      r, w = IO.pipe
+      yield r, w
+    ensure
+      r.close unless r.closed?
+      w.close unless w.closed?
+    end
+  end
+
+  def with_pipes(n)
+    ary = []
+    begin
+      n.times {
+        ary << IO.pipe
+      }
+      yield ary
+    ensure
+      ary.each {|r, w|
+        r.close unless r.closed?
+        w.close unless w.closed?
+      }
+    end
+  end
+
+  ECHO = lambda {|arg| [RUBY, '-e', "puts #{arg.dump}; STDOUT.flush"] }
+  SORT = [RUBY, '-e', "puts ARGF.readlines.sort"]
+  CAT = [RUBY, '-e', "IO.copy_stream STDIN, STDOUT"]
+
+  def test_execopts_redirect
+    with_tmpchdir {|d|
+      Process.wait Process.spawn(*ECHO["a"], STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+      assert_equal("a", File.read("out").chomp)
+      Process.wait Process.spawn(*ECHO["0"], STDOUT=>["out", File::WRONLY|File::CREAT|File::APPEND, 0644])
+      assert_equal("a\n0\n", File.read("out"))
+      Process.wait Process.spawn(*SORT, STDIN=>["out", File::RDONLY, 0644],
+                                         STDOUT=>["out2", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+      assert_equal("0\na\n", File.read("out2"))
+      Process.wait Process.spawn(*ECHO["b"], [STDOUT, STDERR]=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+      assert_equal("b", File.read("out").chomp)
+      # problem occur with valgrind
+      #Process.wait Process.spawn(*ECHO["a"], STDOUT=>:close, STDERR=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+      #p File.read("out")
+      #assert(!File.read("out").empty?) # error message such as "-e:1:in `flush': Bad file descriptor (Errno::EBADF)"
+      Process.wait Process.spawn(*ECHO["c"], STDERR=>STDOUT, STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644])
+      assert_equal("c", File.read("out").chomp)
+      File.open("out", "w") {|f|
+        Process.wait Process.spawn(*ECHO["d"], f=>STDOUT, STDOUT=>f)
+        assert_equal("d", File.read("out").chomp)
+      }
+      Process.wait Process.spawn(*ECHO["e"], STDOUT=>["out", File::WRONLY|File::CREAT|File::TRUNC, 0644],
+                                 3=>STDOUT, 4=>STDOUT, 5=>STDOUT, 6=>STDOUT, 7=>STDOUT)
+      assert_equal("e", File.read("out").chomp)
+      File.open("out", "w") {|f|
+        h = {STDOUT=>f, f=>STDOUT}
+        3.upto(30) {|i| h[i] = STDOUT if f.fileno != i }
+        Process.wait Process.spawn(*ECHO["f"], h)
+        assert_equal("f", File.read("out").chomp)
+      }
+      assert_raise(ArgumentError) {
+        Process.wait Process.spawn(*ECHO["f"], 1=>Process)
+      }
+      assert_raise(ArgumentError) {
+        Process.wait Process.spawn(*ECHO["f"], [Process]=>1)
+      }
+      assert_raise(ArgumentError) {
+        Process.wait Process.spawn(*ECHO["f"], [1, STDOUT]=>2)
+      }
+      assert_raise(ArgumentError) {
+        Process.wait Process.spawn(*ECHO["f"], -1=>2)
+      }
+      Process.wait Process.spawn(*ECHO["hhh\nggg\n"], STDOUT=>"out")
+      assert_equal("hhh\nggg\n", File.read("out"))
+      Process.wait Process.spawn(*SORT, STDIN=>"out", STDOUT=>"out2")
+      assert_equal("ggg\nhhh\n", File.read("out2"))
+
+      assert_raise(Errno::ENOENT) {
+        Process.wait Process.spawn("non-existing-command", (3..60).to_a=>["err", File::WRONLY|File::CREAT])
+      }
+      assert_equal("", File.read("err"))
+
+      system(*ECHO["bb\naa\n"], STDOUT=>["out", "w"])
+      assert_equal("bb\naa\n", File.read("out"))
+      system(*SORT, STDIN=>["out"], STDOUT=>"out2")
+      assert_equal("aa\nbb\n", File.read("out2"))
+
+      with_pipe {|r1, w1|
+        with_pipe {|r2, w2|
+          pid = spawn(*SORT, STDIN=>r1, STDOUT=>w2, w1=>:close, r2=>:close)
+          r1.close
+          w2.close
+          w1.puts "c"
+          w1.puts "a"
+          w1.puts "b"
+          w1.close
+          assert_equal("a\nb\nc\n", r2.read)
+        }
+      }
+
+      with_pipes(5) {|pipes|
+        ios = pipes.flatten
+        h = {}
+        ios.length.times {|i| h[ios[i]] = ios[(i-1)%ios.length] }
+        h2 = h.invert
+        rios = pipes.map {|r, w| r }
+        wios = pipes.map {|r, w| w }
+        child_wfds = wios.map {|w| h2[w].fileno }
+        pid = spawn(RUBY, "-e",
+                "[#{child_wfds.join(',')}].each {|fd| IO.new(fd).puts fd }", h)
+        pipes.each {|r, w|
+          assert_equal("#{h2[w].fileno}\n", r.gets)
+        }
+        Process.wait pid;
+      }
+
+      with_pipes(5) {|pipes|
+        ios = pipes.flatten
+        h = {}
+        ios.length.times {|i| h[ios[i]] = ios[(i+1)%ios.length] }
+        h2 = h.invert
+        rios = pipes.map {|r, w| r }
+        wios = pipes.map {|r, w| w }
+        child_wfds = wios.map {|w| h2[w].fileno }
+        pid = spawn(RUBY, "-e",
+                "[#{child_wfds.join(',')}].each {|fd| IO.new(fd).puts fd }", h)
+        pipes.each {|r, w|
+          assert_equal("#{h2[w].fileno}\n", r.gets)
+        }
+        Process.wait pid;
+      }
+
+      closed_fd = nil
+      with_pipes(5) {|pipes|
+        io = pipes.last.last
+        closed_fd = io.fileno
+      }
+      assert_raise(Errno::EBADF) { Process.wait spawn(*TRUECOMMAND, closed_fd=>closed_fd) }
+
+      with_pipe {|r, w|
+        w.close_on_exec = true
+        pid = spawn(RUBY, "-e", "IO.new(#{w.fileno}).print 'a'", w=>w)
+        w.close
+        assert_equal("a", r.read)
+        Process.wait pid
+      }
+
+      system(*ECHO["funya"], :out=>"out")
+      assert_equal("funya\n", File.read("out"))
+      system(RUBY, '-e', 'STDOUT.reopen(STDERR); puts "henya"', :err=>"out")
+      assert_equal("henya\n", File.read("out"))
+      IO.popen([*CAT, :in=>"out"]) {|io|
+        assert_equal("henya\n", io.read)
+      }
+    }
+  end
+
+  def test_execopts_exec
+    with_tmpchdir {|d|
+      write_file("s", 'exec "echo aaa", STDOUT=>"foo"')
+      pid = spawn RUBY, 's'
+      Process.wait pid
+      assert_equal("aaa\n", File.read("foo"))
+    }
+  end
+
+  def test_execopts_popen
+    with_tmpchdir {|d|
+      IO.popen("#{RUBY} -e 'puts :foo'") {|io| assert_equal("foo\n", io.read) }
+      assert_raise(Errno::ENOENT) { IO.popen(["echo bar"]) {} } # assuming "echo bar" command not exist.
+      IO.popen(ECHO["baz"]) {|io| assert_equal("baz\n", io.read) }
+      assert_raise(ArgumentError) {
+        IO.popen([*ECHO["qux"], STDOUT=>STDOUT]) {|io| }
+      }
+      IO.popen([*ECHO["hoge"], STDERR=>STDOUT]) {|io|
+        assert_equal("hoge\n", io.read)
+      }
+      assert_raise(ArgumentError) {
+        IO.popen([*ECHO["fuga"], STDOUT=>"out"]) {|io| }
+      }
+      with_pipe {|r, w|
+        IO.popen([RUBY, '-e', 'IO.new(3).puts("a"); puts "b"', 3=>w]) {|io|
+          assert_equal("b\n", io.read)
+        }
+        w.close
+        assert_equal("a\n", r.read)
+      }
+      IO.popen([RUBY, '-e', "IO.new(9).puts(:b)",
+               9=>["out2", File::WRONLY|File::CREAT|File::TRUNC]]) {|io|
+        assert_equal("", io.read)
+      }
+      assert_equal("b\n", File.read("out2"))
+    }
+  end
+
+  def test_popen_fork
+    IO.popen("-") {|io|
+      if !io
+        puts "fooo"
+      else
+        assert_equal("fooo\n", io.read)
+      end
+    }
+  end
+
+  def test_fd_inheritance
+    with_pipe {|r, w|
+      system(RUBY, '-e', 'IO.new(ARGV[0].to_i).puts(:ba)', w.fileno.to_s)
+      w.close
+      assert_equal("ba\n", r.read)
+    }
+    with_pipe {|r, w|
+      Process.wait spawn(RUBY, '-e',
+                         'IO.new(ARGV[0].to_i).puts("bi") rescue nil',
+                         w.fileno.to_s)
+      w.close
+      assert_equal("", r.read)
+    }
+    with_pipe {|r, w|
+      with_tmpchdir {|d|
+	write_file("s", <<-"End")
+	  exec(#{RUBY.dump}, '-e',
+	       'IO.new(ARGV[0].to_i).puts("bu") rescue nil',
+	       #{w.fileno.to_s.dump})
+	End
+	Process.wait spawn(RUBY, "s", :close_others=>false)
+	w.close
+	assert_equal("bu\n", r.read)
+      }
+    }
+    with_pipe {|r, w|
+      io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}).puts('me')"])
+      w.close
+      errmsg = io.read
+      assert_equal("", r.read)
+      assert_not_equal("", errmsg)
+    }
+    with_pipe {|r, w|
+      errmsg = `#{RUBY} -e "STDERR.reopen(STDOUT); IO.new(#{w.fileno}).puts(123)"`
+      w.close
+      assert_equal("", r.read)
+      assert_not_equal("", errmsg)
+    }
+  end
+
+  def test_execopts_close_others
+    with_tmpchdir {|d|
+      with_pipe {|r, w|
+        system(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i).puts("ma")', w.fileno.to_s, :close_others=>true)
+        w.close
+        assert_equal("", r.read)
+        assert_not_equal("", File.read("err"))
+        File.unlink("err")
+      }
+      with_pipe {|r, w|
+        Process.wait spawn(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i).puts("mi")', w.fileno.to_s, :close_others=>true)
+        w.close
+        assert_equal("", r.read)
+        assert_not_equal("", File.read("err"))
+        File.unlink("err")
+      }
+      with_pipe {|r, w|
+        Process.wait spawn(RUBY, '-e', 'IO.new(ARGV[0].to_i).puts("bi")', w.fileno.to_s, :close_others=>false)
+        w.close
+        assert_equal("bi\n", r.read)
+      }
+      with_pipe {|r, w|
+	write_file("s", <<-"End")
+	  exec(#{RUBY.dump}, '-e',
+	       'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i).puts("mu")',
+	       #{w.fileno.to_s.dump},
+	       :close_others=>true)
+	End
+        Process.wait spawn(RUBY, "s", :close_others=>false)
+        w.close
+        assert_equal("", r.read)
+        assert_not_equal("", File.read("err"))
+        File.unlink("err")
+      }
+      with_pipe {|r, w|
+        io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}).puts('me')", :close_others=>true])
+        w.close
+        errmsg = io.read
+        assert_equal("", r.read)
+        assert_not_equal("", errmsg)
+      }
+      with_pipe {|r, w|
+        io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}).puts('mo')", :close_others=>false])
+        w.close
+        errmsg = io.read
+        assert_equal("mo\n", r.read)
+        assert_equal("", errmsg)
+      }
+      with_pipe {|r, w|
+        io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}).puts('mo')", :close_others=>nil])
+        w.close
+        errmsg = io.read
+        assert_equal("mo\n", r.read)
+        assert_equal("", errmsg)
+      }
+
+    }
+  end
+
+  def test_execopts_redirect_self
+    with_pipe {|r, w|
+      w << "haha\n"
+      w.close
+      r.close_on_exec = true
+      IO.popen([RUBY, "-e", "print IO.new(#{r.fileno}).read", r.fileno=>r.fileno, :close_others=>false]) {|io|
+        assert_equal("haha\n", io.read)
+      }
+    }
+  end
+
+  def test_execopts_duplex_io
+    IO.popen("#{RUBY} -e ''", "r+") {|duplex|
+      assert_raise(ArgumentError) { system("#{RUBY} -e ''", duplex=>STDOUT) }
+      assert_raise(ArgumentError) { system("#{RUBY} -e ''", STDOUT=>duplex) }
+    }
+  end
+
+  def test_execopts_modification
+    h = {}
+    Process.wait spawn(*TRUECOMMAND, h)
+    assert_equal({}, h)
+
+    h = {}
+    system(*TRUECOMMAND, h)
+    assert_equal({}, h)
+
+    h = {}
+    io = IO.popen([*TRUECOMMAND, h])
+    io.close
+    assert_equal({}, h)
+  end
+
+  def test_system_noshell
+    str = "echo non existing command name which contains spaces"
+    assert_nil(system([str, str]))
+  end
+
+  def test_spawn_noshell
+    str = "echo non existing command name which contains spaces"
+    assert_raise(Errno::ENOENT) { spawn([str, str]) }
+  end
+
+  def test_popen_noshell
+    str = "echo non existing command name which contains spaces"
+    assert_raise(Errno::ENOENT) { IO.popen([str, str]) }
+  end
+
+  def test_exec_noshell
+    with_tmpchdir {|d|
+      with_pipe {|r, w|
+	write_file("s", <<-"End")
+	  str = "echo non existing command name which contains spaces"
+	  w = IO.new(#{w.fileno})
+	  STDOUT.reopen(w)
+	  STDERR.reopen(w)
+	  begin
+	    exec [str, str]
+	  rescue Errno::ENOENT
+	    w.write "Errno::ENOENT success"
+	  end
+	End
+	system(RUBY, "s", :close_others=>false)
+	w.close
+	assert_equal("Errno::ENOENT success", r.read)
+      }
+    }
+  end
+
+  def test_system_wordsplit
+    with_tmpchdir {|d|
+      write_file("script", <<-'End')
+        File.open("result", "w") {|t| t << "haha pid=#{$$} ppid=#{Process.ppid}" }
+        exit 5
+      End
+      str = "#{RUBY} script"
+      ret = system(str)
+      status = $?
+      assert_equal(false, ret)
+      assert(status.exited?)
+      assert_equal(5, status.exitstatus)
+      assert_equal("haha pid=#{status.pid} ppid=#{$$}", File.read("result"))
+    }
+  end
+
+  def test_spawn_wordsplit
+    with_tmpchdir {|d|
+      write_file("script", <<-'End')
+        File.open("result", "w") {|t| t << "hihi pid=#{$$} ppid=#{Process.ppid}" }
+        exit 6
+      End
+      str = "#{RUBY} script"
+      pid = spawn(str)
+      Process.wait pid
+      status = $?
+      assert_equal(pid, status.pid)
+      assert(status.exited?)
+      assert_equal(6, status.exitstatus)
+      assert_equal("hihi pid=#{status.pid} ppid=#{$$}", File.read("result"))
+    }
+  end
+
+  def test_popen_wordsplit
+    with_tmpchdir {|d|
+      write_file("script", <<-'End')
+        print "fufu pid=#{$$} ppid=#{Process.ppid}"
+        exit 7
+      End
+      str = "#{RUBY} script"
+      io = IO.popen(str)
+      pid = io.pid
+      result = io.read
+      io.close
+      status = $?
+      assert_equal(pid, status.pid)
+      assert(status.exited?)
+      assert_equal(7, status.exitstatus)
+      assert_equal("fufu pid=#{status.pid} ppid=#{$$}", result)
+    }
+  end
+
+  def test_exec_wordsplit
+    with_tmpchdir {|d|
+      write_file("script", <<-'End')
+        File.open("result", "w") {|t| t << "hehe pid=#{$$} ppid=#{Process.ppid}" }
+        exit 6
+      End
+      write_file("s", <<-"End")
+	ruby = #{RUBY.dump}
+	exec "\#{ruby} script"
+      End
+      pid = spawn(RUBY, "s")
+      Process.wait pid
+      status = $?
+      assert_equal(pid, status.pid)
+      assert(status.exited?)
+      assert_equal(6, status.exitstatus)
+      assert_equal("hehe pid=#{status.pid} ppid=#{$$}", File.read("result"))
+    }
+  end
+
+  def test_system_shell
+    with_tmpchdir {|d|
+      write_file("script1", <<-'End')
+        File.open("result1", "w") {|t| t << "taka pid=#{$$} ppid=#{Process.ppid}" }
+        exit 7
+      End
+      write_file("script2", <<-'End')
+        File.open("result2", "w") {|t| t << "taki pid=#{$$} ppid=#{Process.ppid}" }
+        exit 8
+      End
+      ret = system("#{RUBY} script1; #{RUBY} script2")
+      status = $?
+      assert_equal(false, ret)
+      assert(status.exited?)
+      result1 = File.read("result1")
+      result2 = File.read("result2")
+      assert_match(/\Ataka pid=\d+ ppid=\d+\z/, result1)
+      assert_match(/\Ataki pid=\d+ ppid=\d+\z/, result2)
+      assert_not_equal(result1[/\d+/].to_i, status.pid)
+    }
+  end
+
+  def test_spawn_shell
+    with_tmpchdir {|d|
+      write_file("script1", <<-'End')
+        File.open("result1", "w") {|t| t << "taku pid=#{$$} ppid=#{Process.ppid}" }
+        exit 7
+      End
+      write_file("script2", <<-'End')
+        File.open("result2", "w") {|t| t << "take pid=#{$$} ppid=#{Process.ppid}" }
+        exit 8
+      End
+      pid = spawn("#{RUBY} script1; #{RUBY} script2")
+      Process.wait pid
+      status = $?
+      assert(status.exited?)
+      assert(!status.success?)
+      result1 = File.read("result1")
+      result2 = File.read("result2")
+      assert_match(/\Ataku pid=\d+ ppid=\d+\z/, result1)
+      assert_match(/\Atake pid=\d+ ppid=\d+\z/, result2)
+      assert_not_equal(result1[/\d+/].to_i, status.pid)
+    }
+  end
+
+  def test_popen_shell
+    with_tmpchdir {|d|
+      write_file("script1", <<-'End')
+        puts "tako pid=#{$$} ppid=#{Process.ppid}"
+        exit 7
+      End
+      write_file("script2", <<-'End')
+        puts "tika pid=#{$$} ppid=#{Process.ppid}"
+        exit 8
+      End
+      io = IO.popen("#{RUBY} script1; #{RUBY} script2")
+      result = io.read
+      io.close
+      status = $?
+      assert(status.exited?)
+      assert(!status.success?)
+      assert_match(/\Atako pid=\d+ ppid=\d+\ntika pid=\d+ ppid=\d+\n\z/, result)
+      assert_not_equal(result[/\d+/].to_i, status.pid)
+    }
+  end
+
+  def test_exec_shell
+    with_tmpchdir {|d|
+      write_file("script1", <<-'End')
+        File.open("result1", "w") {|t| t << "tiki pid=#{$$} ppid=#{Process.ppid}" }
+        exit 7
+      End
+      write_file("script2", <<-'End')
+        File.open("result2", "w") {|t| t << "tiku pid=#{$$} ppid=#{Process.ppid}" }
+        exit 8
+      End
+      write_file("s", <<-"End")
+	ruby = #{RUBY.dump}
+	exec("\#{ruby} script1; \#{ruby} script2")
+      End
+      pid = spawn RUBY, "s"
+      Process.wait pid
+      status = $?
+      assert(status.exited?)
+      assert(!status.success?)
+      result1 = File.read("result1")
+      result2 = File.read("result2")
+      assert_match(/\Atiki pid=\d+ ppid=\d+\z/, result1)
+      assert_match(/\Atiku pid=\d+ ppid=\d+\z/, result2)
+      assert_not_equal(result1[/\d+/].to_i, status.pid)
+    }
+  end
+
+  def test_argv0
+    with_tmpchdir {|d|
+      assert_equal(false, system([RUBY, "asdfg"], "-e", "exit false"))
+      assert_equal(true, system([RUBY, "zxcvb"], "-e", "exit true"))
+
+      Process.wait spawn([RUBY, "poiu"], "-e", "exit 4")
+      assert_equal(4, $?.exitstatus)
+
+      assert_equal("1", IO.popen([[RUBY, "qwerty"], "-e", "print 1"]).read)
+
+      write_file("s", <<-"End")
+        exec([#{RUBY.dump}, "lkjh"], "-e", "exit 5")
+      End
+      pid = spawn RUBY, "s"
+      Process.wait pid
+      assert_equal(5, $?.exitstatus)
+    }
+  end
+
+  def with_stdin(filename)
+    open(filename) {|f|
       begin
-        IO.pipe
-      rescue Errno::EMFILE
-        exit 0
+        old = STDIN.dup
+        begin
+          STDIN.reopen(filename)
+          yield
+        ensure
+          STDIN.reopen(old)
+        end
+      ensure
+        old.close
       end
-      exit 1
     }
-    Process.wait pid
-    assert_equal(0, $?.to_i, "#{$?}")
   end
+
+  def test_argv0_noarg
+    with_tmpchdir {|d|
+      open("t", "w") {|f| f.print "exit true" }
+      open("f", "w") {|f| f.print "exit false" }
+
+      with_stdin("t") { assert_equal(true, system([RUBY, "qaz"])) }
+      with_stdin("f") { assert_equal(false, system([RUBY, "wsx"])) }
+
+      with_stdin("t") { Process.wait spawn([RUBY, "edc"]) }
+      assert($?.success?)
+      with_stdin("f") { Process.wait spawn([RUBY, "rfv"]) }
+      assert(!$?.success?)
+
+      with_stdin("t") { IO.popen([[RUBY, "tgb"]]) {|io| assert_equal("", io.read) } }
+      assert($?.success?)
+      with_stdin("f") { IO.popen([[RUBY, "yhn"]]) {|io| assert_equal("", io.read) } }
+      assert(!$?.success?)
+
+      status = run_in_child "STDIN.reopen('t'); exec([#{RUBY.dump}, 'ujm'])"
+      assert(status.success?)
+      status = run_in_child "STDIN.reopen('f'); exec([#{RUBY.dump}, 'ik,'])"
+      assert(!status.success?)
+    }
+  end
+
 end

Modified: MacRuby/trunk/test/ruby/test_rand.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_rand.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_rand.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -128,4 +128,40 @@
     ws.each {|w| assert_equal(w.to_i, rand(-0x10000)) }
   end
 
+  def test_types
+    srand(0)
+    assert_equal(44, rand(100.0))
+    assert_equal(1245085576965981900420779258691, rand((2**100).to_f))
+    assert_equal(914679880601515615685077935113, rand(-(2**100).to_f))
+
+    srand(0)
+    assert_equal(997707939797331598305742933184, rand(2**100))
+    assert_in_delta(0.602763376071644, rand((2**100).coerce(0).first),
+                    0.000000000000001)
+
+    srand(0)
+    assert_in_delta(0.548813503927325, rand(nil),
+                    0.000000000000001)
+    srand(0)
+    o = Object.new
+    def o.to_i; 100; end
+    assert_equal(44, rand(o))
+    assert_equal(47, rand(o))
+    assert_equal(64, rand(o))
+  end
+
+  def test_srand
+    srand
+    assert_kind_of(Integer, rand(2))
+
+    srand(2**100)
+    %w(3258412053).each {|w|
+      assert_equal(w.to_i, rand(0x100000000))
+    }
+  end
+
+  def test_shuffle
+    srand(0)
+    assert_equal([1,4,2,5,3], [1,2,3,4,5].shuffle)
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_range.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_range.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_range.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -114,12 +114,6 @@
     (0..10).step(2) {|x| a << x }
     assert_equal([0, 2, 4, 6, 8, 10], a)
 
-    o = Object.new
-    def o.to_int; 2; end
-    a = []
-    (0..10).step(o) {|x| a << x }
-    assert_equal([0, 2, 4, 6, 8, 10], a)
-
     assert_raise(ArgumentError) { (0..10).step(-1) { } }
     assert_raise(ArgumentError) { (0..10).step(0) { } }
 
@@ -153,6 +147,20 @@
     a = []
     (o1...o2).step(1) {|x| a << x }
     assert_equal([o1], a)
+
+    assert_nothing_raised("[ruby-dev:34557]") { (0..2).step(0.5) {|x| } }
+
+    a = []
+    (0..2).step(0.5) {|x| a << x }
+    assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)
+
+    a = []
+    (0x40000000..0x40000002).step(0.5) {|x| a << x }
+    assert_equal([1073741824, 1073741824.5, 1073741825.0, 1073741825.5, 1073741826], a)
+
+    o = Object.new
+    def o.to_int() 1 end
+    assert_nothing_raised("[ruby-dev:34558]") { (0..2).step(o) {|x| } }
   end
 
   def test_each

Added: MacRuby/trunk/test/ruby/test_rational.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_rational.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_rational.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,1059 @@
+require 'test/unit'
+
+class RationalSub < Rational; end
+
+class Rational_Test < Test::Unit::TestCase
+
+  def test_ratsub
+    c = RationalSub.__send__(:new, 1)
+    cc = RationalSub.__send__(:convert, 1)
+    if defined?(RationalSub::Unify)
+      assert_instance_of(Fixnum, c)
+      assert_instance_of(Fixnum, cc)
+    else
+      assert_instance_of(RationalSub, c)
+      assert_instance_of(RationalSub, cc)
+
+      c2 = c + 1
+      assert_instance_of(RationalSub, c2)
+      c2 = c - 1
+      assert_instance_of(RationalSub, c2)
+
+      c3 = c - c2
+      assert_instance_of(RationalSub, c3)
+
+      s = Marshal.dump(c)
+      c5 = Marshal.load(s)
+      assert_equal(c, c5)
+      assert_instance_of(RationalSub, c5)
+    end
+  end
+
+  def test_hash
+    assert_instance_of(Fixnum, Rational(1,2).hash)
+
+    h = {}
+    h[Rational(0)] = 0
+    h[Rational(1,1)] = 1
+    h[Rational(2,1)] = 2
+    h[Rational(3,1)] = 3
+
+    assert_equal(4, h.size)
+    assert_equal(2, h[Rational(2,1)])
+
+    h[Rational(0,1)] = 9
+    assert_equal(4, h.size)
+  end
+
+  def test_freeze
+    c = Rational(1)
+    c.freeze
+    unless defined?(Rational::Unify)
+      assert_equal(true, c.frozen?)
+    end
+    assert_instance_of(String, c.to_s)
+  end
+
+  def test_new_bang # no unify & no reduce
+    assert_instance_of(Rational, Rational.__send__(:new!, 2,1))
+    assert_equal([2,1], Rational.__send__(:new!, 2,1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,4],  Rational.__send__(:new!, 2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-2,4], Rational.__send__(:new!, -2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-2,4], Rational.__send__(:new!, 2,-4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,4], Rational.__send__(:new!, -2,-4).
+		 instance_eval{[numerator, denominator]})
+
+    # to_i
+    assert_equal([2,1], Rational.__send__(:new!, Rational(2)).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,3], Rational.__send__(:new!, Rational(2), Rational(3)).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([2,3], Rational.__send__(:new!, 2, Rational(3)).
+		 instance_eval{[numerator, denominator]})
+
+    assert_equal([1,1], Rational.__send__(:new!, 1.1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,1], Rational.__send__(:new!, -1.1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,1], Rational.__send__(:new!, '1').
+		 instance_eval{[numerator, denominator]})
+    assert_equal([0,1], Rational.__send__(:new!, nil).
+		 instance_eval{[numerator, denominator]})
+  end
+
+=begin
+  def test_reduce
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational.__send__(:reduce, 2,1))
+    else
+      assert_instance_of(Rational, Rational.__send__(:reduce, 2,1))
+      assert_instance_of(Rational, Rational.__send__(:reduce, 2,1))
+    end
+    assert_equal([2,1], Rational.__send__(:reduce, 2,1).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,2], Rational.__send__(:reduce, 2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:reduce, -2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:reduce, 2,-4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,2], Rational.__send__(:reduce, -2,-4).
+		 instance_eval{[numerator, denominator]})
+
+    assert_raise(ArgumentError){Rational.__send__(:reduce, Rational(1,2),2)}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, 2,Rational(1,2))}
+    assert_raise(ArgumentError){Rational.
+      __send__(:reduce, Rational(1,2),Rational(1,2))}
+
+    assert_raise(ArgumentError){Rational.__send__(:reduce, 1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, -1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, '1')}
+    assert_raise(ArgumentError){Rational.__send__(:reduce, nil)}
+  end
+=end
+
+  def test_new
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational.__send__(:new, 2,1))
+    else
+      assert_instance_of(Rational, Rational.__send__(:new, 2,1))
+      assert_equal([2,1], Rational.__send__(:new, 2,1).
+		   instance_eval{[numerator, denominator]})
+    end
+    assert_equal([1,2], Rational.__send__(:new, 2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:new, -2,4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([-1,2], Rational.__send__(:new, 2,-4).
+		 instance_eval{[numerator, denominator]})
+    assert_equal([1,2], Rational.__send__(:new, -2,-4).
+		 instance_eval{[numerator, denominator]})
+
+    assert_raise(ArgumentError){Rational.__send__(:new, Rational(1,2),2)}
+    assert_raise(ArgumentError){Rational.__send__(:new, 2,Rational(1,2))}
+    assert_raise(ArgumentError){Rational.__send__(:new, Rational(1,2),Rational(1,2))}
+
+    assert_raise(ArgumentError){Rational.__send__(:new, 1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:new, -1.1)}
+    assert_raise(ArgumentError){Rational.__send__(:new, '1')}
+    assert_raise(ArgumentError){Rational.__send__(:new, nil)}
+=begin
+    assert_raise(ArgumentError){Rational.__send__(:new, Rational(1))}
+    if defined?(Complex)
+      assert_raise(ArgumentError){Rational.__send__(:new, Complex(1))}
+    end
+=end
+  end
+
+  def test_conv
+    c = Rational(0,1)
+    assert_equal(Rational.__send__(:new, 0,1), c)
+
+    c = Rational(2**32, 2**32)
+    assert_equal(Rational.__send__(:new, 2**32,2**32), c)
+    assert_equal([1,1], [c.numerator,c.denominator])
+
+    c = Rational(-2**32, 2**32)
+    assert_equal(Rational.__send__(:new, -2**32,2**32), c)
+    assert_equal([-1,1], [c.numerator,c.denominator])
+
+    c = Rational(2**32, -2**32)
+    assert_equal(Rational.__send__(:new, 2**32,-2**32), c)
+    assert_equal([-1,1], [c.numerator,c.denominator])
+
+    c = Rational(-2**32, -2**32)
+    assert_equal(Rational.__send__(:new, -2**32,-2**32), c)
+    assert_equal([1,1], [c.numerator,c.denominator])
+
+    c = Rational(Rational(1,2),2)
+    assert_equal(Rational.__send__(:new, 1,4), c)
+
+    c = Rational(2,Rational(1,2))
+    assert_equal(Rational.__send__(:new, 4), c)
+
+    c = Rational(Rational(1,2),Rational(1,2))
+    assert_equal(Rational.__send__(:new, 1), c)
+
+    assert_equal(Rational.__send__(:new, 1),Rational(1))
+    assert_equal(1.1.to_r,Rational(1.1))
+    assert_equal(Rational.__send__(:new, 1),Rational('1'))
+    assert_raise(ArgumentError){Rational(nil)}
+  end
+
+  def test_attr
+    c = Rational(4)
+
+    assert_equal(4, c.numerator)
+    assert_equal(1, c.denominator)
+
+    c = Rational(4,5)
+
+    assert_equal(4, c.numerator)
+    assert_equal(5, c.denominator)
+
+    c = Rational.__send__(:new, 4)
+
+    assert_equal(4, c.numerator)
+    assert_equal(1, c.denominator)
+
+    c = Rational.__send__(:new, 4,5)
+
+    assert_equal(4, c.numerator)
+    assert_equal(5, c.denominator)
+
+    c = Rational.__send__(:new!, 4)
+
+    assert_equal(4, c.numerator)
+    assert_equal(1, c.denominator)
+
+    c = Rational.__send__(:new!, 4,5)
+
+    assert_equal(4, c.numerator)
+    assert_equal(5, c.denominator)
+  end
+
+  def test_attr2
+    c = Rational(1)
+
+    if defined?(Rational::Unify)
+      assert_equal(true, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(true, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(true, c.rational?)
+      assert_equal(true, c.real?)
+      assert_equal(false, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    else
+      assert_equal(true, c.scalar?)
+=begin
+      assert_equal(true, c.finite?)
+      assert_equal(false, c.infinite?)
+      assert_equal(false, c.nan?)
+      assert_equal(false, c.integer?)
+      assert_equal(false, c.float?)
+      assert_equal(true, c.rational?)
+      assert_equal(true, c.real?)
+      assert_equal(false, c.complex?)
+      assert_equal(true, c.exact?)
+      assert_equal(false, c.inexact?)
+=end
+    end
+
+=begin
+    assert_equal(true, Rational(0).positive?)
+    assert_equal(true, Rational(1).positive?)
+    assert_equal(false, Rational(-1).positive?)
+    assert_equal(false, Rational(0).negative?)
+    assert_equal(false, Rational(1).negative?)
+    assert_equal(true, Rational(-1).negative?)
+
+    assert_equal(0, Rational(0).sign)
+    assert_equal(1, Rational(2).sign)
+    assert_equal(-1, Rational(-2).sign)
+=end
+
+    assert_equal(true, Rational(0).zero?)
+    assert_equal(true, Rational(0,1).zero?)
+    assert_equal(false, Rational(1,1).zero?)
+
+    assert_equal(nil, Rational(0).nonzero?)
+    assert_equal(nil, Rational(0,1).nonzero?)
+    assert_equal(Rational(1,1), Rational(1,1).nonzero?)
+  end
+
+  def test_uplus
+    assert_equal(Rational(1), +Rational(1))
+    assert_equal(Rational(-1), +Rational(-1))
+    assert_equal(Rational(1,1), +Rational(1,1))
+    assert_equal(Rational(-1,1), +Rational(-1,1))
+    assert_equal(Rational(-1,1), +Rational(1,-1))
+    assert_equal(Rational(1,1), +Rational(-1,-1))
+  end
+
+  def test_negate
+    assert_equal(Rational(-1), -Rational(1))
+    assert_equal(Rational(1), -Rational(-1))
+    assert_equal(Rational(-1,1), -Rational(1,1))
+    assert_equal(Rational(1,1), -Rational(-1,1))
+    assert_equal(Rational(1,1), -Rational(1,-1))
+    assert_equal(Rational(-1,1), -Rational(-1,-1))
+
+=begin
+    assert_equal(0, Rational(0).negate)
+    assert_equal(-2, Rational(2).negate)
+    assert_equal(2, Rational(-2).negate)
+=end
+  end
+
+  def test_add
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(7,6), c + c2)
+
+    assert_equal(Rational(5,2), c + 2)
+    assert_equal(2.5, c + 2.0)
+  end
+
+  def test_sub
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(-1,6), c - c2)
+
+    assert_equal(Rational(-3,2), c - 2)
+    assert_equal(-1.5, c - 2.0)
+  end
+
+  def test_mul
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(1,3), c * c2)
+
+    assert_equal(Rational(1,1), c * 2)
+    assert_equal(1.0, c * 2.0)
+  end
+
+  def test_div
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(3,4), c / c2)
+
+    assert_equal(Rational(1,4), c / 2)
+    assert_equal(0.25, c / 2.0)
+  end
+
+  def assert_eql(exp, act, *args)
+    unless Array === exp
+      exp = [exp]
+    end
+    unless Array === act
+      act = [act]
+    end
+    exp.zip(act).each do |e, a|
+      na = [e, a] + args
+      assert_equal(*na)
+      na = [e.class, a] + args
+      assert_instance_of(*na)
+    end
+  end
+
+  def test_idiv
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql(0, c.div(c2))
+    assert_eql(0, c.div(2))
+    assert_eql(0, c.div(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal(2, c.div(c2))
+    assert_equal(-3, c.div(-c2))
+    assert_equal(-3, (-c).div(c2))
+    assert_equal(2, (-c).div(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal(1, c.div(c2))
+    assert_equal(-2, c.div(-c2))
+    assert_equal(-2, (-c).div(c2))
+    assert_equal(1, (-c).div(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal(3, c.div(c2))
+      assert_equal(-4, c.div(-c2))
+      assert_equal(-4, (-c).div(c2))
+      assert_equal(3, (-c).div(-c2))
+    end
+  end
+
+  def test_divmod
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql([0, Rational(1,2)], c.divmod(c2))
+    assert_eql([0, Rational(1,2)], c.divmod(2))
+    assert_eql([0, 0.5], c.divmod(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal([2, Rational(21,100)], c.divmod(c2))
+    assert_equal([-3, Rational(-119,100)], c.divmod(-c2))
+    assert_equal([-3, Rational(119,100)], (-c).divmod(c2))
+    assert_equal([2, Rational(-21,100)], (-c).divmod(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal([1, Rational(101,100)], c.divmod(c2))
+    assert_equal([-2, Rational(-99,100)], c.divmod(-c2))
+    assert_equal([-2, Rational(99,100)], (-c).divmod(c2))
+    assert_equal([1, Rational(-101,100)], (-c).divmod(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal([3,2], c.divmod(c2))
+      assert_equal([-4,-1], c.divmod(-c2))
+      assert_equal([-4,1], (-c).divmod(c2))
+      assert_equal([3,-2], (-c).divmod(-c2))
+    end
+  end
+
+=begin
+  def test_quot
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql(0, c.quot(c2))
+    assert_eql(0, c.quot(2))
+    assert_eql(0, c.quot(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal(2, c.quot(c2))
+    assert_equal(-2, c.quot(-c2))
+    assert_equal(-2, (-c).quot(c2))
+    assert_equal(2, (-c).quot(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal(1, c.quot(c2))
+    assert_equal(-1, c.quot(-c2))
+    assert_equal(-1, (-c).quot(c2))
+    assert_equal(1, (-c).quot(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal(3, c.quot(c2))
+      assert_equal(-3, c.quot(-c2))
+      assert_equal(-3, (-c).quot(c2))
+      assert_equal(3, (-c).quot(-c2))
+    end
+  end
+
+  def test_quotrem
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_eql([0, Rational(1,2)], c.quotrem(c2))
+    assert_eql([0, Rational(1,2)], c.quotrem(2))
+    assert_eql([0, 0.5], c.quotrem(2.0))
+
+    c = Rational(301,100)
+    c2 = Rational(7,5)
+
+    assert_equal([2, Rational(21,100)], c.quotrem(c2))
+    assert_equal([-2, Rational(21,100)], c.quotrem(-c2))
+    assert_equal([-2, Rational(-21,100)], (-c).quotrem(c2))
+    assert_equal([2, Rational(-21,100)], (-c).quotrem(-c2))
+
+    c = Rational(301,100)
+    c2 = Rational(2)
+
+    assert_equal([1, Rational(101,100)], c.quotrem(c2))
+    assert_equal([-1, Rational(101,100)], c.quotrem(-c2))
+    assert_equal([-1, Rational(-101,100)], (-c).quotrem(c2))
+    assert_equal([1, Rational(-101,100)], (-c).quotrem(-c2))
+
+    unless defined?(Rational::Unify)
+      c = Rational(11)
+      c2 = Rational(3)
+
+      assert_equal([3,2], c.quotrem(c2))
+      assert_equal([-3,2], c.quotrem(-c2))
+      assert_equal([-3,-2], (-c).quotrem(c2))
+      assert_equal([3,-2], (-c).quotrem(-c2))
+    end
+  end
+=end
+
+  def test_quo
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(Rational(3,4), c.quo(c2))
+
+    assert_equal(Rational(1,4), c.quo(2))
+    assert_equal(Rational(0.25), c.quo(2.0))
+  end
+
+  def test_fdiv
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    assert_equal(0.75, c.fdiv(c2))
+
+    assert_equal(0.25, c.fdiv(2))
+    assert_equal(0.25, c.fdiv(2.0))
+  end
+
+  def test_expt
+    c = Rational(1,2)
+    c2 = Rational(2,3)
+
+    r = c ** c2
+    assert_in_delta(0.6299, r, 0.001)
+
+    assert_equal(Rational(1,4), c ** 2)
+    assert_equal(Rational(4), c ** -2)
+    assert_equal(Rational(1,4), (-c) ** 2)
+    assert_equal(Rational(4), (-c) ** -2)
+
+    assert_equal(0.25, c ** 2.0)
+    assert_equal(4.0, c ** -2.0)
+
+    assert_equal(Rational(1,4), c ** Rational(2))
+    assert_equal(Rational(4), c ** Rational(-2))
+
+    assert_equal(Rational(1), 0 ** Rational(0))
+    assert_equal(Rational(1), Rational(0) ** 0)
+    assert_equal(Rational(1), Rational(0) ** Rational(0))
+
+    # p ** p
+    x = 2 ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(2) ** 2
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(2) ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    # -p ** p
+    x = (-2) ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(-2) ** 2
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    x = Rational(-2) ** Rational(2)
+    assert_equal(Rational(4), x)
+    unless defined?(Rational::Unify)
+      assert_instance_of(Rational, x)
+    end
+    assert_equal(4, x.numerator)
+    assert_equal(1, x.denominator)
+
+    # p ** -p
+    x = 2 ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(2) ** -2
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(2) ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    # -p ** -p
+    x = (-2) ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(-2) ** -2
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+
+    x = Rational(-2) ** Rational(-2)
+    assert_equal(Rational(1,4), x)
+    assert_instance_of(Rational, x)
+    assert_equal(1, x.numerator)
+    assert_equal(4, x.denominator)
+  end
+
+  def test_cmp
+    assert_equal(-1, Rational(-1) <=> Rational(0))
+    assert_equal(0, Rational(0) <=> Rational(0))
+    assert_equal(+1, Rational(+1) <=> Rational(0))
+
+    assert_equal(-1, Rational(-1) <=> 0)
+    assert_equal(0, Rational(0) <=> 0)
+    assert_equal(+1, Rational(+1) <=> 0)
+
+    assert_equal(-1, Rational(-1) <=> 0.0)
+    assert_equal(0, Rational(0) <=> 0.0)
+    assert_equal(+1, Rational(+1) <=> 0.0)
+
+    assert_equal(-1, Rational(1,2) <=> Rational(2,3))
+    assert_equal(0, Rational(2,3) <=> Rational(2,3))
+    assert_equal(+1, Rational(2,3) <=> Rational(1,2))
+
+    f = 2**30-1
+    b = 2**30
+
+    assert_equal(0, Rational(f) <=> Rational(f))
+    assert_equal(-1, Rational(f) <=> Rational(b))
+    assert_equal(+1, Rational(b) <=> Rational(f))
+    assert_equal(0, Rational(b) <=> Rational(b))
+
+    assert_equal(-1, Rational(f-1) <=> Rational(f))
+    assert_equal(+1, Rational(f) <=> Rational(f-1))
+    assert_equal(-1, Rational(b-1) <=> Rational(b))
+    assert_equal(+1, Rational(b) <=> Rational(b-1))
+
+    assert_equal(false, Rational(0) < Rational(0))
+    assert_equal(true, Rational(0) <= Rational(0))
+    assert_equal(true, Rational(0) >= Rational(0))
+    assert_equal(false, Rational(0) > Rational(0))
+  end
+
+  def test_equal
+    assert(Rational(1,1) == Rational(1))
+    assert(Rational(1,1) == Rational.__send__(:new, 1))
+    assert(Rational(1,1) == Rational.__send__(:new, 1,1))
+    assert(Rational(1,1) == Rational.__send__(:new!, 1))
+    assert(Rational(1,1) == Rational.__send__(:new!, 1,1))
+
+    assert(Rational(-1,1) == Rational(-1))
+    assert(Rational(-1,1) == Rational.__send__(:new, -1))
+    assert(Rational(-1,1) == Rational.__send__(:new, -1,1))
+    assert(Rational(-1,1) == Rational.__send__(:new!, -1))
+    assert(Rational(-1,1) == Rational.__send__(:new!, -1,1))
+
+    assert_equal(false, Rational(2,1) == Rational(1))
+    assert_equal(true, Rational(2,1) != Rational(1))
+    assert_equal(false, Rational(1) == nil)
+    assert_equal(false, Rational(1) == '')
+
+    assert_equal(false, Rational(1,2**100) == 1)
+  end
+
+  def test_unify
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational(1,2) + Rational(1,2))
+      assert_instance_of(Fixnum, Rational(1,2) - Rational(1,2))
+      assert_instance_of(Fixnum, Rational(1,2) * 2)
+      assert_instance_of(Fixnum, Rational(1,2) / Rational(1,2))
+      assert_instance_of(Fixnum, Rational(1,2).div(Rational(1,2)))
+      assert_instance_of(Fixnum, Rational(1,2).quo(Rational(1,2)))
+      assert_instance_of(Fixnum, Rational(1,2) ** -2)
+    end
+  end
+
+  def test_to_s
+    c = Rational(1,2)
+
+    assert_instance_of(String, c.to_s)
+    assert_equal('1/2', c.to_s)
+
+    assert_equal('0', Rational(0,2).to_s)
+    assert_equal('0', Rational(0,-2).to_s)
+    assert_equal('1/2', Rational(1,2).to_s)
+    assert_equal('-1/2', Rational(-1,2).to_s)
+    assert_equal('1/2', Rational(-1,-2).to_s)
+    assert_equal('-1/2', Rational(1,-2).to_s)
+    assert_equal('1/2', Rational(-1,-2).to_s)
+  end
+
+  def test_inspect
+    c = Rational(1,2)
+
+    assert_instance_of(String, c.inspect)
+    assert_equal('Rational(1, 2)', c.inspect)
+  end
+
+  def test_marshal
+    c = Rational(1,2)
+
+    s = Marshal.dump(c)
+    c2 = Marshal.load(s)
+    assert_equal(c, c2)
+    assert_instance_of(Rational, c2)
+  end
+
+  def test_parse
+    assert_equal(Rational(0), ''.to_r)
+    assert_equal(Rational(0), ' '.to_r)
+    assert_equal(Rational(5), '5'.to_r)
+    assert_equal(Rational(-5), '-5'.to_r)
+    assert_equal(Rational(5,3), '5/3'.to_r)
+    assert_equal(Rational(-5,3), '-5/3'.to_r)
+    assert_equal(Rational(5,-3), '5/-3'.to_r)
+    assert_equal(Rational(-5,-3), '-5/-3'.to_r)
+
+    assert_equal(Rational(5), '5.0'.to_r)
+    assert_equal(Rational(-5), '-5.0'.to_r)
+    assert_equal(Rational(5,3), '5.0/3'.to_r)
+    assert_equal(Rational(-5,3), '-5.0/3'.to_r)
+    assert_equal(Rational(5,-3), '5.0/-3'.to_r)
+    assert_equal(Rational(-5,-3), '-5.0/-3'.to_r)
+
+    assert_equal(Rational(5), '5e0'.to_r)
+    assert_equal(Rational(-5), '-5e0'.to_r)
+    assert_equal(Rational(5,3), '5e0/3'.to_r)
+    assert_equal(Rational(-5,3), '-5e0/3'.to_r)
+    assert_equal(Rational(5,-3), '5e0/-3'.to_r)
+    assert_equal(Rational(-5,-3), '-5e0/-3'.to_r)
+
+    assert_equal(Rational(33,100), '0.33'.to_r)
+    assert_equal(Rational(-33,100), '-0.33'.to_r)
+    assert_equal(Rational(-33,100), '-0.3_3'.to_r)
+
+    assert_equal(Rational(1,2), '5e-1'.to_r)
+    assert_equal(Rational(50), '5e+1'.to_r)
+    assert_equal(Rational(1,2), '5.0e-1'.to_r)
+    assert_equal(Rational(50), '5.0e+1'.to_r)
+    assert_equal(Rational(50), '5e1'.to_r)
+    assert_equal(Rational(50), '5E1'.to_r)
+    assert_equal(Rational(500), '5e2'.to_r)
+    assert_equal(Rational(5000), '5e3'.to_r)
+    assert_equal(Rational(500000000000), '5e1_1'.to_r)
+
+    assert_equal(Rational(5), Rational('5'))
+    assert_equal(Rational(-5), Rational('-5'))
+    assert_equal(Rational(5,3), Rational('5/3'))
+    assert_equal(Rational(-5,3), Rational('-5/3'))
+    assert_equal(Rational(5,-3), Rational('5/-3'))
+    assert_equal(Rational(-5,-3), Rational('-5/-3'))
+
+    assert_equal(Rational(33,100), Rational('0.33'))
+    assert_equal(Rational(-33,100), Rational('-0.33'))
+    assert_equal(Rational(-33,100), Rational('-0.3_3'))
+
+    assert_equal(Rational(1,2), Rational('5e-1'))
+    assert_equal(Rational(50), Rational('5e1'))
+    assert_equal(Rational(50), Rational('5E1'))
+    assert_equal(Rational(500), Rational('5e2'))
+    assert_equal(Rational(5000), Rational('5e3'))
+    assert_equal(Rational(500000000000), Rational('5e1_1'))
+
+    assert_equal(Rational(5.0), Rational('5.0'))
+    assert_equal(Rational(-5.0), Rational('-5.0'))
+    assert_equal(Rational(5.0,3), Rational('5.0/3'))
+    assert_equal(Rational(-5.0,3), Rational('-5.0/3'))
+    assert_equal(Rational(5.0,-3), Rational('5.0/-3'))
+    assert_equal(Rational(-5.0,-3), Rational('-5.0/-3'))
+
+    assert_equal(Rational(0), '_'.to_r)
+    assert_equal(Rational(0), '_5'.to_r)
+    assert_equal(Rational(5), '5_'.to_r)
+    assert_equal(Rational(5), '5x'.to_r)
+    assert_equal(Rational(5), '5/_3'.to_r)
+    assert_equal(Rational(5,3), '5/3_'.to_r)
+    assert_equal(Rational(5,3), '5/3.3'.to_r)
+    assert_equal(Rational(5,3), '5/3x'.to_r)
+    assert_raise(ArgumentError){ Rational('')}
+    assert_raise(ArgumentError){ Rational('_')}
+    assert_raise(ArgumentError){ Rational('_5')}
+    assert_raise(ArgumentError){ Rational('5_')}
+    assert_raise(ArgumentError){ Rational('5x')}
+    assert_raise(ArgumentError){ Rational('5/_3')}
+    assert_raise(ArgumentError){ Rational('5/3_')}
+    assert_raise(ArgumentError){ Rational('5/3.3')}
+    assert_raise(ArgumentError){ Rational('5/3x')}
+  end
+
+=begin
+  def test_reciprocal
+    assert_equal(Rational(1,9), Rational(9,1).reciprocal)
+    assert_equal(Rational(9,1), Rational(1,9).reciprocal)
+    assert_equal(Rational(-1,9), Rational(-9,1).reciprocal)
+    assert_equal(Rational(-9,1), Rational(-1,9).reciprocal)
+  end
+=end
+
+  def test_to_i
+    assert_equal(1, Rational(3,2).to_i)
+    assert_equal(1, Integer(Rational(3,2)))
+  end
+
+  def test_to_f
+    assert_equal(1.5, Rational(3,2).to_f)
+    assert_equal(1.5, Float(Rational(3,2)))
+  end
+
+  def test_to_c
+    if defined?(Complex) && !Complex.instance_variable_get('@RCS_ID')
+      if defined?(Rational::Unify)
+	assert_equal(Rational(3,2), Rational(3,2).to_c)
+	assert_equal(Rational(3,2), Complex(Rational(3,2)))
+      else
+	assert_equal(Complex(Rational(3,2)), Rational(3,2).to_c)
+	assert_equal(Complex(Rational(3,2)), Complex(Rational(3,2)))
+      end
+    end
+  end
+
+  def test_to_r
+    c = nil.to_r
+    assert_equal([0,1] , [c.numerator, c.denominator])
+
+    c = 0.to_r
+    assert_equal([0,1] , [c.numerator, c.denominator])
+
+    c = 1.to_r
+    assert_equal([1,1] , [c.numerator, c.denominator])
+
+    c = 1.1.to_r
+    assert_equal([2476979795053773, 2251799813685248],
+		 [c.numerator, c.denominator])
+
+    c = Rational(1,2).to_r
+    assert_equal([1,2] , [c.numerator, c.denominator])
+
+    if defined?(Complex)
+      if Complex.instance_variable_get('@RCS_ID')
+	assert_raise(NoMethodError){Complex(1,2).to_r}
+      else
+	assert_raise(RangeError){Complex(1,2).to_r}
+      end
+    end
+  end
+
+  def test_prec
+    assert_equal(true, Rational < Precision)
+
+    c = Rational(3,2)
+
+    assert_eql(1, c.prec(Integer))
+    assert_eql(1.5, c.prec(Float))
+    assert_eql(c, c.prec(Rational))
+  end
+
+  def test_supp
+    assert_equal(true, 1.scalar?)
+    assert_equal(true, 1.1.scalar?)
+
+    if defined?(Complex)
+      assert_equal(1, 1.real)
+      assert_equal(0, 1.image)
+      assert_equal(0, 1.imag)
+
+      assert_equal(1.1, 1.1.real)
+      assert_equal(0, 1.1.image)
+      assert_equal(0, 1.1.imag)
+
+      assert_equal(0, 1.arg)
+      assert_equal(0, 1.angle)
+
+      assert_equal(0, 1.0.arg)
+      assert_equal(0, 1.0.angle)
+
+      assert_equal(Math::PI, -1.arg)
+      assert_equal(Math::PI, -1.angle)
+
+      assert_equal(Math::PI, -1.0.arg)
+      assert_equal(Math::PI, -1.0.angle)
+
+      assert_equal([1,0], 1.polar)
+      assert_equal([1, Math::PI], -1.polar)
+
+      assert_equal([1.0,0], 1.0.polar)
+      assert_equal([1.0, Math::PI], -1.0.polar)
+
+      assert_equal(1, 1.conjugate)
+      assert_equal(-1, -1.conjugate)
+      assert_equal(1, 1.conj)
+      assert_equal(-1, -1.conj)
+
+      assert_equal(1.1, 1.1.conjugate)
+      assert_equal(-1.1, -1.1.conjugate)
+      assert_equal(1.1, 1.1.conj)
+      assert_equal(-1.1, -1.1.conj)
+    end
+
+    assert_equal(1, 1.numerator)
+    assert_equal(9, 9.numerator)
+    assert_equal(1, 1.denominator)
+    assert_equal(1, 9.denominator)
+
+    assert_equal(1.0, 1.0.numerator)
+    assert_equal(9.0, 9.0.numerator)
+    assert_equal(1.0, 1.0.denominator)
+    assert_equal(1.0, 9.0.denominator)
+
+=begin
+    assert_equal(Rational(1,9), 9.reciprocal)
+    assert_equal(Rational(1,9), 9.0.reciprocal)
+    assert_equal(Rational(1,9), 9.inverse)
+    assert_equal(Rational(1,9), 9.0.inverse)
+=end
+
+    assert_equal(Rational(1,2), 1.quo(2))
+    assert_equal(Rational(5000000000), 10000000000.quo(2))
+    assert_equal(Rational(1,2), 1.0.quo(2))
+    assert_equal(Rational(1,4), Rational(1,2).quo(2))
+
+    assert_equal(0.5, 1.fdiv(2))
+    assert_equal(5000000000.0, 10000000000.fdiv(2))
+    assert_equal(0.5, 1.0.fdiv(2))
+    assert_equal(0.25, Rational(1,2).fdiv(2))
+  end
+
+  def test_zero_div
+    assert_raise(ZeroDivisionError) { Rational(1, 0) }
+    assert_raise(ZeroDivisionError) { Rational(1, 1) / 0 }
+  end
+
+  def test_gcd
+    assert_equal(0, Rational(0, 2**100))
+  end
+
+  def test_unify2
+    f = defined?(Rational::Unify)
+    Rational.const_set(:Unify, true) unless f
+
+    assert_same(42, Rational(84, 2))
+    assert_same(1, Rational(1, 2) + Rational(1, 2))
+
+    Rational.instance_eval { remove_const(:Unify) } unless f
+  end
+
+  def test_coerce
+    r = Rational(7, 3)
+    assert_equal(Rational(42, 1), r.coerce(42).first)
+    assert_raise(TypeError) { r.coerce(Object.new) }
+
+    o = Object.new
+    def o.coerce(x); [x.numerator, x.denominator]; end
+    assert_equal(10, r + o)
+    assert_equal(4, r - o)
+    assert_equal(21, r * o)
+    assert_equal(2, r / o)
+    assert_equal(343, r ** o)
+    assert_equal(1, r <=> o)
+
+    b = 2**100
+    def b.<=>(x); 0; end rescue nil
+    assert_equal(1, r ** b)
+    b = 2**100
+    def b.**(x); -1; end rescue nil
+    assert_equal(-1, Rational(1, b)**3)
+  end
+
+  def test_modulo_remainder
+    assert_equal(Rational(1, 2), Rational(5, 2).modulo(1))
+    assert_equal(Rational(1, 2), Rational(5, 2).modulo(2))
+    assert_equal(Rational(5, 2), Rational(5, 2).modulo(3))
+    assert_equal(Rational(5, 6), Rational(5, 2).modulo(Rational(5, 3)))
+    assert_equal(Rational(1, 2), Rational(-5, 2).modulo(1))
+    assert_equal(Rational(-1, 2), Rational(5, 2).modulo(-1))
+    assert_equal(Rational(-1, 2), Rational(-5, 2).modulo(-1))
+
+    assert_equal(Rational(1, 2), Rational(5, 2).remainder(1))
+    assert_equal(Rational(1, 2), Rational(5, 2).remainder(2))
+    assert_equal(Rational(5, 2), Rational(5, 2).remainder(3))
+    assert_equal(Rational(5, 6), Rational(5, 2).remainder(Rational(5, 3)))
+    assert_equal(Rational(-1, 2), Rational(-5, 2).remainder(1))
+    assert_equal(Rational(1, 2), Rational(5, 2).remainder(-1))
+    assert_equal(Rational(-1, 2), Rational(-5, 2).remainder(-1))
+  end
+
+  def test_abs
+    assert_equal(Rational(1, 2), Rational(1, 2).abs)
+    assert_equal(Rational(1, 2), Rational(-1, 2).abs)
+  end
+
+  def test_floor_ceil_truncate_round
+    assert_equal( 2, Rational( 5, 2).floor)
+    assert_equal(-3, Rational(-5, 2).floor)
+    assert_equal( 3, Rational( 5, 2).ceil)
+    assert_equal(-2, Rational(-5, 2).ceil)
+    assert_equal( 2, Rational( 5, 2).truncate)
+    assert_equal(-2, Rational(-5, 2).truncate)
+    assert_equal( 3, Rational( 5, 2).round)
+    assert_equal(-3, Rational(-5, 2).round)
+    assert_equal( 1, Rational( 4, 3).round)
+    assert_equal(-1, Rational(-4, 3).round)
+    assert_equal( 2, Rational( 5, 3).round)
+    assert_equal(-2, Rational(-5, 3).round)
+  end
+
+  def test_convert
+    assert_equal(Rational(1, 2), Rational(Complex(1, 0), 2))
+    assert_raise(RangeError) { Rational(Complex(1, 1), 1) }
+    assert_equal(Rational(1, 2), Rational(1, Complex(2, 0)))
+    assert_raise(RangeError) { Rational(1, Complex(2, 1)) }
+    assert_equal(Rational(1, 2), Rational(0.25, 0.5))
+    assert_equal(Rational(1, 2), Rational('1', '2'))
+  end
+
+  def test_add2
+    assert_equal(Rational(2**100, 3), Rational(0, 1) + Rational(2**100, 3))
+    assert_equal(Rational(2, 3**100), Rational(0, 1) + Rational(2, 3**100))
+  end
+
+  def test_div2
+    assert_raise(ZeroDivisionError) { Rational(1, 1) / Rational(0, 1) }
+  end
+
+  def test_to_f2
+    assert_equal(1, Rational(2**5000,3).to_f.infinite?)
+    assert_equal(0, Rational(1, 2**5000).to_f)
+  end
+
+  def test_fixed_bug
+    if defined?(Rational::Unify)
+      assert_instance_of(Fixnum, Rational(1,2) ** 0) # mathn's bug
+    end
+
+    n = Float::MAX.to_i * 2
+    assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]')
+  end
+
+  def test_known_bug
+  end
+
+end

Added: MacRuby/trunk/test/ruby/test_rational2.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_rational2.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_rational2.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,1360 @@
+require 'test/unit'
+
+class Rational_Test2 < Test::Unit::TestCase
+
+  def test_kumi
+    assert_equal(Rational(2, 1),
+                 Rational(1, 1) + Rational(1, 1))
+    assert_equal(Rational(0, 1),
+                 Rational(1, 1) - Rational(1, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(1, 1) * Rational(1, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(1, 1) / Rational(1, 1))
+    assert_equal(Rational(3, 1),
+                 Rational(1, 1) + Rational(2, 1))
+    assert_equal(Rational(-1, 1),
+                 Rational(1, 1) - Rational(2, 1))
+    assert_equal(Rational(2, 1),
+                 Rational(1, 1) * Rational(2, 1))
+    assert_equal(Rational(1, 2),
+                 Rational(1, 1) / Rational(2, 1))
+    assert_equal(Rational(4, 1),
+                 Rational(1, 1) + Rational(3, 1))
+    assert_equal(Rational(-2, 1),
+                 Rational(1, 1) - Rational(3, 1))
+    assert_equal(Rational(3, 1),
+                 Rational(1, 1) * Rational(3, 1))
+    assert_equal(Rational(1, 3),
+                 Rational(1, 1) / Rational(3, 1))
+    assert_equal(Rational(1073741790, 1),
+                 Rational(1, 1) + Rational(1073741789, 1))
+    assert_equal(Rational(-1073741788, 1),
+                 Rational(1, 1) - Rational(1073741789, 1))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(1, 1) * Rational(1073741789, 1))
+    assert_equal(Rational(1, 1073741789),
+                 Rational(1, 1) / Rational(1073741789, 1))
+    assert_equal(Rational(1073741828, 1),
+                 Rational(1, 1) + Rational(1073741827, 1))
+    assert_equal(Rational(-1073741826, 1),
+                 Rational(1, 1) - Rational(1073741827, 1))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(1, 1) * Rational(1073741827, 1))
+    assert_equal(Rational(1, 1073741827),
+                 Rational(1, 1) / Rational(1073741827, 1))
+    assert_equal(Rational(5, 3),
+                 Rational(1, 1) + Rational(2, 3))
+    assert_equal(Rational(1, 3),
+                 Rational(1, 1) - Rational(2, 3))
+    assert_equal(Rational(2, 3),
+                 Rational(1, 1) * Rational(2, 3))
+    assert_equal(Rational(3, 2),
+                 Rational(1, 1) / Rational(2, 3))
+    assert_equal(Rational(5, 2),
+                 Rational(1, 1) + Rational(3, 2))
+    assert_equal(Rational(-1, 2),
+                 Rational(1, 1) - Rational(3, 2))
+    assert_equal(Rational(3, 2),
+                 Rational(1, 1) * Rational(3, 2))
+    assert_equal(Rational(2, 3),
+                 Rational(1, 1) / Rational(3, 2))
+    assert_equal(Rational(1073741792, 1073741789),
+                 Rational(1, 1) + Rational(3, 1073741789))
+    assert_equal(Rational(1073741786, 1073741789),
+                 Rational(1, 1) - Rational(3, 1073741789))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(1, 1) * Rational(3, 1073741789))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1, 1) / Rational(3, 1073741789))
+    assert_equal(Rational(1073741792, 3),
+                 Rational(1, 1) + Rational(1073741789, 3))
+    assert_equal(Rational(-1073741786, 3),
+                 Rational(1, 1) - Rational(1073741789, 3))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1, 1) * Rational(1073741789, 3))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(1, 1) / Rational(1073741789, 3))
+    assert_equal(Rational(1073741830, 1073741827),
+                 Rational(1, 1) + Rational(3, 1073741827))
+    assert_equal(Rational(1073741824, 1073741827),
+                 Rational(1, 1) - Rational(3, 1073741827))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(1, 1) * Rational(3, 1073741827))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1, 1) / Rational(3, 1073741827))
+    assert_equal(Rational(1073741830, 3),
+                 Rational(1, 1) + Rational(1073741827, 3))
+    assert_equal(Rational(-1073741824, 3),
+                 Rational(1, 1) - Rational(1073741827, 3))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1, 1) * Rational(1073741827, 3))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(1, 1) / Rational(1073741827, 3))
+    assert_equal(Rational(2147483616, 1073741827),
+                 Rational(1, 1) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(38, 1073741827),
+                 Rational(1, 1) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(1, 1) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(1, 1) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(2147483616, 1073741789),
+                 Rational(1, 1) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(-38, 1073741789),
+                 Rational(1, 1) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(1, 1) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(1, 1) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(3, 1),
+                 Rational(2, 1) + Rational(1, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(2, 1) - Rational(1, 1))
+    assert_equal(Rational(2, 1),
+                 Rational(2, 1) * Rational(1, 1))
+    assert_equal(Rational(2, 1),
+                 Rational(2, 1) / Rational(1, 1))
+    assert_equal(Rational(4, 1),
+                 Rational(2, 1) + Rational(2, 1))
+    assert_equal(Rational(0, 1),
+                 Rational(2, 1) - Rational(2, 1))
+    assert_equal(Rational(4, 1),
+                 Rational(2, 1) * Rational(2, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(2, 1) / Rational(2, 1))
+    assert_equal(Rational(5, 1),
+                 Rational(2, 1) + Rational(3, 1))
+    assert_equal(Rational(-1, 1),
+                 Rational(2, 1) - Rational(3, 1))
+    assert_equal(Rational(6, 1),
+                 Rational(2, 1) * Rational(3, 1))
+    assert_equal(Rational(2, 3),
+                 Rational(2, 1) / Rational(3, 1))
+    assert_equal(Rational(1073741791, 1),
+                 Rational(2, 1) + Rational(1073741789, 1))
+    assert_equal(Rational(-1073741787, 1),
+                 Rational(2, 1) - Rational(1073741789, 1))
+    assert_equal(Rational(2147483578, 1),
+                 Rational(2, 1) * Rational(1073741789, 1))
+    assert_equal(Rational(2, 1073741789),
+                 Rational(2, 1) / Rational(1073741789, 1))
+    assert_equal(Rational(1073741829, 1),
+                 Rational(2, 1) + Rational(1073741827, 1))
+    assert_equal(Rational(-1073741825, 1),
+                 Rational(2, 1) - Rational(1073741827, 1))
+    assert_equal(Rational(2147483654, 1),
+                 Rational(2, 1) * Rational(1073741827, 1))
+    assert_equal(Rational(2, 1073741827),
+                 Rational(2, 1) / Rational(1073741827, 1))
+    assert_equal(Rational(8, 3),
+                 Rational(2, 1) + Rational(2, 3))
+    assert_equal(Rational(4, 3),
+                 Rational(2, 1) - Rational(2, 3))
+    assert_equal(Rational(4, 3),
+                 Rational(2, 1) * Rational(2, 3))
+    assert_equal(Rational(3, 1),
+                 Rational(2, 1) / Rational(2, 3))
+    assert_equal(Rational(7, 2),
+                 Rational(2, 1) + Rational(3, 2))
+    assert_equal(Rational(1, 2),
+                 Rational(2, 1) - Rational(3, 2))
+    assert_equal(Rational(3, 1),
+                 Rational(2, 1) * Rational(3, 2))
+    assert_equal(Rational(4, 3),
+                 Rational(2, 1) / Rational(3, 2))
+    assert_equal(Rational(2147483581, 1073741789),
+                 Rational(2, 1) + Rational(3, 1073741789))
+    assert_equal(Rational(2147483575, 1073741789),
+                 Rational(2, 1) - Rational(3, 1073741789))
+    assert_equal(Rational(6, 1073741789),
+                 Rational(2, 1) * Rational(3, 1073741789))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(2, 1) / Rational(3, 1073741789))
+    assert_equal(Rational(1073741795, 3),
+                 Rational(2, 1) + Rational(1073741789, 3))
+    assert_equal(Rational(-1073741783, 3),
+                 Rational(2, 1) - Rational(1073741789, 3))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(2, 1) * Rational(1073741789, 3))
+    assert_equal(Rational(6, 1073741789),
+                 Rational(2, 1) / Rational(1073741789, 3))
+    assert_equal(Rational(2147483657, 1073741827),
+                 Rational(2, 1) + Rational(3, 1073741827))
+    assert_equal(Rational(2147483651, 1073741827),
+                 Rational(2, 1) - Rational(3, 1073741827))
+    assert_equal(Rational(6, 1073741827),
+                 Rational(2, 1) * Rational(3, 1073741827))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(2, 1) / Rational(3, 1073741827))
+    assert_equal(Rational(1073741833, 3),
+                 Rational(2, 1) + Rational(1073741827, 3))
+    assert_equal(Rational(-1073741821, 3),
+                 Rational(2, 1) - Rational(1073741827, 3))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(2, 1) * Rational(1073741827, 3))
+    assert_equal(Rational(6, 1073741827),
+                 Rational(2, 1) / Rational(1073741827, 3))
+    assert_equal(Rational(3221225443, 1073741827),
+                 Rational(2, 1) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741865, 1073741827),
+                 Rational(2, 1) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(2147483578, 1073741827),
+                 Rational(2, 1) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(2147483654, 1073741789),
+                 Rational(2, 1) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(3221225405, 1073741789),
+                 Rational(2, 1) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741751, 1073741789),
+                 Rational(2, 1) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(2147483654, 1073741789),
+                 Rational(2, 1) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(2147483578, 1073741827),
+                 Rational(2, 1) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(4, 1),
+                 Rational(3, 1) + Rational(1, 1))
+    assert_equal(Rational(2, 1),
+                 Rational(3, 1) - Rational(1, 1))
+    assert_equal(Rational(3, 1),
+                 Rational(3, 1) * Rational(1, 1))
+    assert_equal(Rational(3, 1),
+                 Rational(3, 1) / Rational(1, 1))
+    assert_equal(Rational(5, 1),
+                 Rational(3, 1) + Rational(2, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 1) - Rational(2, 1))
+    assert_equal(Rational(6, 1),
+                 Rational(3, 1) * Rational(2, 1))
+    assert_equal(Rational(3, 2),
+                 Rational(3, 1) / Rational(2, 1))
+    assert_equal(Rational(6, 1),
+                 Rational(3, 1) + Rational(3, 1))
+    assert_equal(Rational(0, 1),
+                 Rational(3, 1) - Rational(3, 1))
+    assert_equal(Rational(9, 1),
+                 Rational(3, 1) * Rational(3, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 1) / Rational(3, 1))
+    assert_equal(Rational(1073741792, 1),
+                 Rational(3, 1) + Rational(1073741789, 1))
+    assert_equal(Rational(-1073741786, 1),
+                 Rational(3, 1) - Rational(1073741789, 1))
+    assert_equal(Rational(3221225367, 1),
+                 Rational(3, 1) * Rational(1073741789, 1))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(3, 1) / Rational(1073741789, 1))
+    assert_equal(Rational(1073741830, 1),
+                 Rational(3, 1) + Rational(1073741827, 1))
+    assert_equal(Rational(-1073741824, 1),
+                 Rational(3, 1) - Rational(1073741827, 1))
+    assert_equal(Rational(3221225481, 1),
+                 Rational(3, 1) * Rational(1073741827, 1))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(3, 1) / Rational(1073741827, 1))
+    assert_equal(Rational(11, 3),
+                 Rational(3, 1) + Rational(2, 3))
+    assert_equal(Rational(7, 3),
+                 Rational(3, 1) - Rational(2, 3))
+    assert_equal(Rational(2, 1),
+                 Rational(3, 1) * Rational(2, 3))
+    assert_equal(Rational(9, 2),
+                 Rational(3, 1) / Rational(2, 3))
+    assert_equal(Rational(9, 2),
+                 Rational(3, 1) + Rational(3, 2))
+    assert_equal(Rational(3, 2),
+                 Rational(3, 1) - Rational(3, 2))
+    assert_equal(Rational(9, 2),
+                 Rational(3, 1) * Rational(3, 2))
+    assert_equal(Rational(2, 1),
+                 Rational(3, 1) / Rational(3, 2))
+    assert_equal(Rational(3221225370, 1073741789),
+                 Rational(3, 1) + Rational(3, 1073741789))
+    assert_equal(Rational(3221225364, 1073741789),
+                 Rational(3, 1) - Rational(3, 1073741789))
+    assert_equal(Rational(9, 1073741789),
+                 Rational(3, 1) * Rational(3, 1073741789))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(3, 1) / Rational(3, 1073741789))
+    assert_equal(Rational(1073741798, 3),
+                 Rational(3, 1) + Rational(1073741789, 3))
+    assert_equal(Rational(-1073741780, 3),
+                 Rational(3, 1) - Rational(1073741789, 3))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(3, 1) * Rational(1073741789, 3))
+    assert_equal(Rational(9, 1073741789),
+                 Rational(3, 1) / Rational(1073741789, 3))
+    assert_equal(Rational(3221225484, 1073741827),
+                 Rational(3, 1) + Rational(3, 1073741827))
+    assert_equal(Rational(3221225478, 1073741827),
+                 Rational(3, 1) - Rational(3, 1073741827))
+    assert_equal(Rational(9, 1073741827),
+                 Rational(3, 1) * Rational(3, 1073741827))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(3, 1) / Rational(3, 1073741827))
+    assert_equal(Rational(1073741836, 3),
+                 Rational(3, 1) + Rational(1073741827, 3))
+    assert_equal(Rational(-1073741818, 3),
+                 Rational(3, 1) - Rational(1073741827, 3))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(3, 1) * Rational(1073741827, 3))
+    assert_equal(Rational(9, 1073741827),
+                 Rational(3, 1) / Rational(1073741827, 3))
+    assert_equal(Rational(4294967270, 1073741827),
+                 Rational(3, 1) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(2147483692, 1073741827),
+                 Rational(3, 1) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(3221225367, 1073741827),
+                 Rational(3, 1) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(3221225481, 1073741789),
+                 Rational(3, 1) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(4294967194, 1073741789),
+                 Rational(3, 1) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(2147483540, 1073741789),
+                 Rational(3, 1) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(3221225481, 1073741789),
+                 Rational(3, 1) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(3221225367, 1073741827),
+                 Rational(3, 1) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741790, 1),
+                 Rational(1073741789, 1) + Rational(1, 1))
+    assert_equal(Rational(1073741788, 1),
+                 Rational(1073741789, 1) - Rational(1, 1))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(1073741789, 1) * Rational(1, 1))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(1073741789, 1) / Rational(1, 1))
+    assert_equal(Rational(1073741791, 1),
+                 Rational(1073741789, 1) + Rational(2, 1))
+    assert_equal(Rational(1073741787, 1),
+                 Rational(1073741789, 1) - Rational(2, 1))
+    assert_equal(Rational(2147483578, 1),
+                 Rational(1073741789, 1) * Rational(2, 1))
+    assert_equal(Rational(1073741789, 2),
+                 Rational(1073741789, 1) / Rational(2, 1))
+    assert_equal(Rational(1073741792, 1),
+                 Rational(1073741789, 1) + Rational(3, 1))
+    assert_equal(Rational(1073741786, 1),
+                 Rational(1073741789, 1) - Rational(3, 1))
+    assert_equal(Rational(3221225367, 1),
+                 Rational(1073741789, 1) * Rational(3, 1))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1073741789, 1) / Rational(3, 1))
+    assert_equal(Rational(2147483578, 1),
+                 Rational(1073741789, 1) + Rational(1073741789, 1))
+    assert_equal(Rational(0, 1),
+                 Rational(1073741789, 1) - Rational(1073741789, 1))
+    assert_equal(Rational(1152921429444920521, 1),
+                 Rational(1073741789, 1) * Rational(1073741789, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741789, 1) / Rational(1073741789, 1))
+    assert_equal(Rational(2147483616, 1),
+                 Rational(1073741789, 1) + Rational(1073741827, 1))
+    assert_equal(Rational(-38, 1),
+                 Rational(1073741789, 1) - Rational(1073741827, 1))
+    assert_equal(Rational(1152921470247108503, 1),
+                 Rational(1073741789, 1) * Rational(1073741827, 1))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(1073741789, 1) / Rational(1073741827, 1))
+    assert_equal(Rational(3221225369, 3),
+                 Rational(1073741789, 1) + Rational(2, 3))
+    assert_equal(Rational(3221225365, 3),
+                 Rational(1073741789, 1) - Rational(2, 3))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(1073741789, 1) * Rational(2, 3))
+    assert_equal(Rational(3221225367, 2),
+                 Rational(1073741789, 1) / Rational(2, 3))
+    assert_equal(Rational(2147483581, 2),
+                 Rational(1073741789, 1) + Rational(3, 2))
+    assert_equal(Rational(2147483575, 2),
+                 Rational(1073741789, 1) - Rational(3, 2))
+    assert_equal(Rational(3221225367, 2),
+                 Rational(1073741789, 1) * Rational(3, 2))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(1073741789, 1) / Rational(3, 2))
+    assert_equal(Rational(1152921429444920524, 1073741789),
+                 Rational(1073741789, 1) + Rational(3, 1073741789))
+    assert_equal(Rational(1152921429444920518, 1073741789),
+                 Rational(1073741789, 1) - Rational(3, 1073741789))
+    assert_equal(Rational(3, 1),
+                 Rational(1073741789, 1) * Rational(3, 1073741789))
+    assert_equal(Rational(1152921429444920521, 3),
+                 Rational(1073741789, 1) / Rational(3, 1073741789))
+    assert_equal(Rational(4294967156, 3),
+                 Rational(1073741789, 1) + Rational(1073741789, 3))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(1073741789, 1) - Rational(1073741789, 3))
+    assert_equal(Rational(1152921429444920521, 3),
+                 Rational(1073741789, 1) * Rational(1073741789, 3))
+    assert_equal(Rational(3, 1),
+                 Rational(1073741789, 1) / Rational(1073741789, 3))
+    assert_equal(Rational(1152921470247108506, 1073741827),
+                 Rational(1073741789, 1) + Rational(3, 1073741827))
+    assert_equal(Rational(1152921470247108500, 1073741827),
+                 Rational(1073741789, 1) - Rational(3, 1073741827))
+    assert_equal(Rational(3221225367, 1073741827),
+                 Rational(1073741789, 1) * Rational(3, 1073741827))
+    assert_equal(Rational(1152921470247108503, 3),
+                 Rational(1073741789, 1) / Rational(3, 1073741827))
+    assert_equal(Rational(4294967194, 3),
+                 Rational(1073741789, 1) + Rational(1073741827, 3))
+    assert_equal(Rational(2147483540, 3),
+                 Rational(1073741789, 1) - Rational(1073741827, 3))
+    assert_equal(Rational(1152921470247108503, 3),
+                 Rational(1073741789, 1) * Rational(1073741827, 3))
+    assert_equal(Rational(3221225367, 1073741827),
+                 Rational(1073741789, 1) / Rational(1073741827, 3))
+    assert_equal(Rational(1152921471320850292, 1073741827),
+                 Rational(1073741789, 1) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921469173366714, 1073741827),
+                 Rational(1073741789, 1) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921429444920521, 1073741827),
+                 Rational(1073741789, 1) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(1073741789, 1) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921430518662348, 1073741789),
+                 Rational(1073741789, 1) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921428371178694, 1073741789),
+                 Rational(1073741789, 1) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(1073741789, 1) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921429444920521, 1073741827),
+                 Rational(1073741789, 1) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741828, 1),
+                 Rational(1073741827, 1) + Rational(1, 1))
+    assert_equal(Rational(1073741826, 1),
+                 Rational(1073741827, 1) - Rational(1, 1))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(1073741827, 1) * Rational(1, 1))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(1073741827, 1) / Rational(1, 1))
+    assert_equal(Rational(1073741829, 1),
+                 Rational(1073741827, 1) + Rational(2, 1))
+    assert_equal(Rational(1073741825, 1),
+                 Rational(1073741827, 1) - Rational(2, 1))
+    assert_equal(Rational(2147483654, 1),
+                 Rational(1073741827, 1) * Rational(2, 1))
+    assert_equal(Rational(1073741827, 2),
+                 Rational(1073741827, 1) / Rational(2, 1))
+    assert_equal(Rational(1073741830, 1),
+                 Rational(1073741827, 1) + Rational(3, 1))
+    assert_equal(Rational(1073741824, 1),
+                 Rational(1073741827, 1) - Rational(3, 1))
+    assert_equal(Rational(3221225481, 1),
+                 Rational(1073741827, 1) * Rational(3, 1))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1073741827, 1) / Rational(3, 1))
+    assert_equal(Rational(2147483616, 1),
+                 Rational(1073741827, 1) + Rational(1073741789, 1))
+    assert_equal(Rational(38, 1),
+                 Rational(1073741827, 1) - Rational(1073741789, 1))
+    assert_equal(Rational(1152921470247108503, 1),
+                 Rational(1073741827, 1) * Rational(1073741789, 1))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(1073741827, 1) / Rational(1073741789, 1))
+    assert_equal(Rational(2147483654, 1),
+                 Rational(1073741827, 1) + Rational(1073741827, 1))
+    assert_equal(Rational(0, 1),
+                 Rational(1073741827, 1) - Rational(1073741827, 1))
+    assert_equal(Rational(1152921511049297929, 1),
+                 Rational(1073741827, 1) * Rational(1073741827, 1))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741827, 1) / Rational(1073741827, 1))
+    assert_equal(Rational(3221225483, 3),
+                 Rational(1073741827, 1) + Rational(2, 3))
+    assert_equal(Rational(3221225479, 3),
+                 Rational(1073741827, 1) - Rational(2, 3))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(1073741827, 1) * Rational(2, 3))
+    assert_equal(Rational(3221225481, 2),
+                 Rational(1073741827, 1) / Rational(2, 3))
+    assert_equal(Rational(2147483657, 2),
+                 Rational(1073741827, 1) + Rational(3, 2))
+    assert_equal(Rational(2147483651, 2),
+                 Rational(1073741827, 1) - Rational(3, 2))
+    assert_equal(Rational(3221225481, 2),
+                 Rational(1073741827, 1) * Rational(3, 2))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(1073741827, 1) / Rational(3, 2))
+    assert_equal(Rational(1152921470247108506, 1073741789),
+                 Rational(1073741827, 1) + Rational(3, 1073741789))
+    assert_equal(Rational(1152921470247108500, 1073741789),
+                 Rational(1073741827, 1) - Rational(3, 1073741789))
+    assert_equal(Rational(3221225481, 1073741789),
+                 Rational(1073741827, 1) * Rational(3, 1073741789))
+    assert_equal(Rational(1152921470247108503, 3),
+                 Rational(1073741827, 1) / Rational(3, 1073741789))
+    assert_equal(Rational(4294967270, 3),
+                 Rational(1073741827, 1) + Rational(1073741789, 3))
+    assert_equal(Rational(2147483692, 3),
+                 Rational(1073741827, 1) - Rational(1073741789, 3))
+    assert_equal(Rational(1152921470247108503, 3),
+                 Rational(1073741827, 1) * Rational(1073741789, 3))
+    assert_equal(Rational(3221225481, 1073741789),
+                 Rational(1073741827, 1) / Rational(1073741789, 3))
+    assert_equal(Rational(1152921511049297932, 1073741827),
+                 Rational(1073741827, 1) + Rational(3, 1073741827))
+    assert_equal(Rational(1152921511049297926, 1073741827),
+                 Rational(1073741827, 1) - Rational(3, 1073741827))
+    assert_equal(Rational(3, 1),
+                 Rational(1073741827, 1) * Rational(3, 1073741827))
+    assert_equal(Rational(1152921511049297929, 3),
+                 Rational(1073741827, 1) / Rational(3, 1073741827))
+    assert_equal(Rational(4294967308, 3),
+                 Rational(1073741827, 1) + Rational(1073741827, 3))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(1073741827, 1) - Rational(1073741827, 3))
+    assert_equal(Rational(1152921511049297929, 3),
+                 Rational(1073741827, 1) * Rational(1073741827, 3))
+    assert_equal(Rational(3, 1),
+                 Rational(1073741827, 1) / Rational(1073741827, 3))
+    assert_equal(Rational(1152921512123039718, 1073741827),
+                 Rational(1073741827, 1) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921509975556140, 1073741827),
+                 Rational(1073741827, 1) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(1073741827, 1) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921511049297929, 1073741789),
+                 Rational(1073741827, 1) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921471320850330, 1073741789),
+                 Rational(1073741827, 1) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921469173366676, 1073741789),
+                 Rational(1073741827, 1) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921511049297929, 1073741789),
+                 Rational(1073741827, 1) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(1073741827, 1) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(5, 3),
+                 Rational(2, 3) + Rational(1, 1))
+    assert_equal(Rational(-1, 3),
+                 Rational(2, 3) - Rational(1, 1))
+    assert_equal(Rational(2, 3),
+                 Rational(2, 3) * Rational(1, 1))
+    assert_equal(Rational(2, 3),
+                 Rational(2, 3) / Rational(1, 1))
+    assert_equal(Rational(8, 3),
+                 Rational(2, 3) + Rational(2, 1))
+    assert_equal(Rational(-4, 3),
+                 Rational(2, 3) - Rational(2, 1))
+    assert_equal(Rational(4, 3),
+                 Rational(2, 3) * Rational(2, 1))
+    assert_equal(Rational(1, 3),
+                 Rational(2, 3) / Rational(2, 1))
+    assert_equal(Rational(11, 3),
+                 Rational(2, 3) + Rational(3, 1))
+    assert_equal(Rational(-7, 3),
+                 Rational(2, 3) - Rational(3, 1))
+    assert_equal(Rational(2, 1),
+                 Rational(2, 3) * Rational(3, 1))
+    assert_equal(Rational(2, 9),
+                 Rational(2, 3) / Rational(3, 1))
+    assert_equal(Rational(3221225369, 3),
+                 Rational(2, 3) + Rational(1073741789, 1))
+    assert_equal(Rational(-3221225365, 3),
+                 Rational(2, 3) - Rational(1073741789, 1))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(2, 3) * Rational(1073741789, 1))
+    assert_equal(Rational(2, 3221225367),
+                 Rational(2, 3) / Rational(1073741789, 1))
+    assert_equal(Rational(3221225483, 3),
+                 Rational(2, 3) + Rational(1073741827, 1))
+    assert_equal(Rational(-3221225479, 3),
+                 Rational(2, 3) - Rational(1073741827, 1))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(2, 3) * Rational(1073741827, 1))
+    assert_equal(Rational(2, 3221225481),
+                 Rational(2, 3) / Rational(1073741827, 1))
+    assert_equal(Rational(4, 3),
+                 Rational(2, 3) + Rational(2, 3))
+    assert_equal(Rational(0, 1),
+                 Rational(2, 3) - Rational(2, 3))
+    assert_equal(Rational(4, 9),
+                 Rational(2, 3) * Rational(2, 3))
+    assert_equal(Rational(1, 1),
+                 Rational(2, 3) / Rational(2, 3))
+    assert_equal(Rational(13, 6),
+                 Rational(2, 3) + Rational(3, 2))
+    assert_equal(Rational(-5, 6),
+                 Rational(2, 3) - Rational(3, 2))
+    assert_equal(Rational(1, 1),
+                 Rational(2, 3) * Rational(3, 2))
+    assert_equal(Rational(4, 9),
+                 Rational(2, 3) / Rational(3, 2))
+    assert_equal(Rational(2147483587, 3221225367),
+                 Rational(2, 3) + Rational(3, 1073741789))
+    assert_equal(Rational(2147483569, 3221225367),
+                 Rational(2, 3) - Rational(3, 1073741789))
+    assert_equal(Rational(2, 1073741789),
+                 Rational(2, 3) * Rational(3, 1073741789))
+    assert_equal(Rational(2147483578, 9),
+                 Rational(2, 3) / Rational(3, 1073741789))
+    assert_equal(Rational(1073741791, 3),
+                 Rational(2, 3) + Rational(1073741789, 3))
+    assert_equal(Rational(-357913929, 1),
+                 Rational(2, 3) - Rational(1073741789, 3))
+    assert_equal(Rational(2147483578, 9),
+                 Rational(2, 3) * Rational(1073741789, 3))
+    assert_equal(Rational(2, 1073741789),
+                 Rational(2, 3) / Rational(1073741789, 3))
+    assert_equal(Rational(2147483663, 3221225481),
+                 Rational(2, 3) + Rational(3, 1073741827))
+    assert_equal(Rational(2147483645, 3221225481),
+                 Rational(2, 3) - Rational(3, 1073741827))
+    assert_equal(Rational(2, 1073741827),
+                 Rational(2, 3) * Rational(3, 1073741827))
+    assert_equal(Rational(2147483654, 9),
+                 Rational(2, 3) / Rational(3, 1073741827))
+    assert_equal(Rational(357913943, 1),
+                 Rational(2, 3) + Rational(1073741827, 3))
+    assert_equal(Rational(-1073741825, 3),
+                 Rational(2, 3) - Rational(1073741827, 3))
+    assert_equal(Rational(2147483654, 9),
+                 Rational(2, 3) * Rational(1073741827, 3))
+    assert_equal(Rational(2, 1073741827),
+                 Rational(2, 3) / Rational(1073741827, 3))
+    assert_equal(Rational(5368709021, 3221225481),
+                 Rational(2, 3) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(-1073741713, 3221225481),
+                 Rational(2, 3) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(2147483578, 3221225481),
+                 Rational(2, 3) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(2147483654, 3221225367),
+                 Rational(2, 3) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(5368709059, 3221225367),
+                 Rational(2, 3) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(-1073741903, 3221225367),
+                 Rational(2, 3) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(2147483654, 3221225367),
+                 Rational(2, 3) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(2147483578, 3221225481),
+                 Rational(2, 3) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(5, 2),
+                 Rational(3, 2) + Rational(1, 1))
+    assert_equal(Rational(1, 2),
+                 Rational(3, 2) - Rational(1, 1))
+    assert_equal(Rational(3, 2),
+                 Rational(3, 2) * Rational(1, 1))
+    assert_equal(Rational(3, 2),
+                 Rational(3, 2) / Rational(1, 1))
+    assert_equal(Rational(7, 2),
+                 Rational(3, 2) + Rational(2, 1))
+    assert_equal(Rational(-1, 2),
+                 Rational(3, 2) - Rational(2, 1))
+    assert_equal(Rational(3, 1),
+                 Rational(3, 2) * Rational(2, 1))
+    assert_equal(Rational(3, 4),
+                 Rational(3, 2) / Rational(2, 1))
+    assert_equal(Rational(9, 2),
+                 Rational(3, 2) + Rational(3, 1))
+    assert_equal(Rational(-3, 2),
+                 Rational(3, 2) - Rational(3, 1))
+    assert_equal(Rational(9, 2),
+                 Rational(3, 2) * Rational(3, 1))
+    assert_equal(Rational(1, 2),
+                 Rational(3, 2) / Rational(3, 1))
+    assert_equal(Rational(2147483581, 2),
+                 Rational(3, 2) + Rational(1073741789, 1))
+    assert_equal(Rational(-2147483575, 2),
+                 Rational(3, 2) - Rational(1073741789, 1))
+    assert_equal(Rational(3221225367, 2),
+                 Rational(3, 2) * Rational(1073741789, 1))
+    assert_equal(Rational(3, 2147483578),
+                 Rational(3, 2) / Rational(1073741789, 1))
+    assert_equal(Rational(2147483657, 2),
+                 Rational(3, 2) + Rational(1073741827, 1))
+    assert_equal(Rational(-2147483651, 2),
+                 Rational(3, 2) - Rational(1073741827, 1))
+    assert_equal(Rational(3221225481, 2),
+                 Rational(3, 2) * Rational(1073741827, 1))
+    assert_equal(Rational(3, 2147483654),
+                 Rational(3, 2) / Rational(1073741827, 1))
+    assert_equal(Rational(13, 6),
+                 Rational(3, 2) + Rational(2, 3))
+    assert_equal(Rational(5, 6),
+                 Rational(3, 2) - Rational(2, 3))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 2) * Rational(2, 3))
+    assert_equal(Rational(9, 4),
+                 Rational(3, 2) / Rational(2, 3))
+    assert_equal(Rational(3, 1),
+                 Rational(3, 2) + Rational(3, 2))
+    assert_equal(Rational(0, 1),
+                 Rational(3, 2) - Rational(3, 2))
+    assert_equal(Rational(9, 4),
+                 Rational(3, 2) * Rational(3, 2))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 2) / Rational(3, 2))
+    assert_equal(Rational(3221225373, 2147483578),
+                 Rational(3, 2) + Rational(3, 1073741789))
+    assert_equal(Rational(3221225361, 2147483578),
+                 Rational(3, 2) - Rational(3, 1073741789))
+    assert_equal(Rational(9, 2147483578),
+                 Rational(3, 2) * Rational(3, 1073741789))
+    assert_equal(Rational(1073741789, 2),
+                 Rational(3, 2) / Rational(3, 1073741789))
+    assert_equal(Rational(2147483587, 6),
+                 Rational(3, 2) + Rational(1073741789, 3))
+    assert_equal(Rational(-2147483569, 6),
+                 Rational(3, 2) - Rational(1073741789, 3))
+    assert_equal(Rational(1073741789, 2),
+                 Rational(3, 2) * Rational(1073741789, 3))
+    assert_equal(Rational(9, 2147483578),
+                 Rational(3, 2) / Rational(1073741789, 3))
+    assert_equal(Rational(3221225487, 2147483654),
+                 Rational(3, 2) + Rational(3, 1073741827))
+    assert_equal(Rational(3221225475, 2147483654),
+                 Rational(3, 2) - Rational(3, 1073741827))
+    assert_equal(Rational(9, 2147483654),
+                 Rational(3, 2) * Rational(3, 1073741827))
+    assert_equal(Rational(1073741827, 2),
+                 Rational(3, 2) / Rational(3, 1073741827))
+    assert_equal(Rational(2147483663, 6),
+                 Rational(3, 2) + Rational(1073741827, 3))
+    assert_equal(Rational(-2147483645, 6),
+                 Rational(3, 2) - Rational(1073741827, 3))
+    assert_equal(Rational(1073741827, 2),
+                 Rational(3, 2) * Rational(1073741827, 3))
+    assert_equal(Rational(9, 2147483654),
+                 Rational(3, 2) / Rational(1073741827, 3))
+    assert_equal(Rational(5368709059, 2147483654),
+                 Rational(3, 2) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741903, 2147483654),
+                 Rational(3, 2) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(3221225367, 2147483654),
+                 Rational(3, 2) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(3221225481, 2147483578),
+                 Rational(3, 2) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(5368709021, 2147483578),
+                 Rational(3, 2) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741713, 2147483578),
+                 Rational(3, 2) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(3221225481, 2147483578),
+                 Rational(3, 2) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(3221225367, 2147483654),
+                 Rational(3, 2) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741792, 1073741789),
+                 Rational(3, 1073741789) + Rational(1, 1))
+    assert_equal(Rational(-1073741786, 1073741789),
+                 Rational(3, 1073741789) - Rational(1, 1))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(3, 1073741789) * Rational(1, 1))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(3, 1073741789) / Rational(1, 1))
+    assert_equal(Rational(2147483581, 1073741789),
+                 Rational(3, 1073741789) + Rational(2, 1))
+    assert_equal(Rational(-2147483575, 1073741789),
+                 Rational(3, 1073741789) - Rational(2, 1))
+    assert_equal(Rational(6, 1073741789),
+                 Rational(3, 1073741789) * Rational(2, 1))
+    assert_equal(Rational(3, 2147483578),
+                 Rational(3, 1073741789) / Rational(2, 1))
+    assert_equal(Rational(3221225370, 1073741789),
+                 Rational(3, 1073741789) + Rational(3, 1))
+    assert_equal(Rational(-3221225364, 1073741789),
+                 Rational(3, 1073741789) - Rational(3, 1))
+    assert_equal(Rational(9, 1073741789),
+                 Rational(3, 1073741789) * Rational(3, 1))
+    assert_equal(Rational(1, 1073741789),
+                 Rational(3, 1073741789) / Rational(3, 1))
+    assert_equal(Rational(1152921429444920524, 1073741789),
+                 Rational(3, 1073741789) + Rational(1073741789, 1))
+    assert_equal(Rational(-1152921429444920518, 1073741789),
+                 Rational(3, 1073741789) - Rational(1073741789, 1))
+    assert_equal(Rational(3, 1),
+                 Rational(3, 1073741789) * Rational(1073741789, 1))
+    assert_equal(Rational(3, 1152921429444920521),
+                 Rational(3, 1073741789) / Rational(1073741789, 1))
+    assert_equal(Rational(1152921470247108506, 1073741789),
+                 Rational(3, 1073741789) + Rational(1073741827, 1))
+    assert_equal(Rational(-1152921470247108500, 1073741789),
+                 Rational(3, 1073741789) - Rational(1073741827, 1))
+    assert_equal(Rational(3221225481, 1073741789),
+                 Rational(3, 1073741789) * Rational(1073741827, 1))
+    assert_equal(Rational(3, 1152921470247108503),
+                 Rational(3, 1073741789) / Rational(1073741827, 1))
+    assert_equal(Rational(2147483587, 3221225367),
+                 Rational(3, 1073741789) + Rational(2, 3))
+    assert_equal(Rational(-2147483569, 3221225367),
+                 Rational(3, 1073741789) - Rational(2, 3))
+    assert_equal(Rational(2, 1073741789),
+                 Rational(3, 1073741789) * Rational(2, 3))
+    assert_equal(Rational(9, 2147483578),
+                 Rational(3, 1073741789) / Rational(2, 3))
+    assert_equal(Rational(3221225373, 2147483578),
+                 Rational(3, 1073741789) + Rational(3, 2))
+    assert_equal(Rational(-3221225361, 2147483578),
+                 Rational(3, 1073741789) - Rational(3, 2))
+    assert_equal(Rational(9, 2147483578),
+                 Rational(3, 1073741789) * Rational(3, 2))
+    assert_equal(Rational(2, 1073741789),
+                 Rational(3, 1073741789) / Rational(3, 2))
+    assert_equal(Rational(6, 1073741789),
+                 Rational(3, 1073741789) + Rational(3, 1073741789))
+    assert_equal(Rational(0, 1),
+                 Rational(3, 1073741789) - Rational(3, 1073741789))
+    assert_equal(Rational(9, 1152921429444920521),
+                 Rational(3, 1073741789) * Rational(3, 1073741789))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 1073741789) / Rational(3, 1073741789))
+    assert_equal(Rational(1152921429444920530, 3221225367),
+                 Rational(3, 1073741789) + Rational(1073741789, 3))
+    assert_equal(Rational(-1152921429444920512, 3221225367),
+                 Rational(3, 1073741789) - Rational(1073741789, 3))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 1073741789) * Rational(1073741789, 3))
+    assert_equal(Rational(9, 1152921429444920521),
+                 Rational(3, 1073741789) / Rational(1073741789, 3))
+    assert_equal(Rational(6442450848, 1152921470247108503),
+                 Rational(3, 1073741789) + Rational(3, 1073741827))
+    assert_equal(Rational(114, 1152921470247108503),
+                 Rational(3, 1073741789) - Rational(3, 1073741827))
+    assert_equal(Rational(9, 1152921470247108503),
+                 Rational(3, 1073741789) * Rational(3, 1073741827))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(3, 1073741789) / Rational(3, 1073741827))
+    assert_equal(Rational(1152921470247108512, 3221225367),
+                 Rational(3, 1073741789) + Rational(1073741827, 3))
+    assert_equal(Rational(-1152921470247108494, 3221225367),
+                 Rational(3, 1073741789) - Rational(1073741827, 3))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(3, 1073741789) * Rational(1073741827, 3))
+    assert_equal(Rational(9, 1152921470247108503),
+                 Rational(3, 1073741789) / Rational(1073741827, 3))
+    assert_equal(Rational(1152921432666146002, 1152921470247108503),
+                 Rational(3, 1073741789) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(-1152921426223695040, 1152921470247108503),
+                 Rational(3, 1073741789) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(3, 1073741789) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(3221225481, 1152921429444920521),
+                 Rational(3, 1073741789) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741830, 1073741789),
+                 Rational(3, 1073741789) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(-1073741824, 1073741789),
+                 Rational(3, 1073741789) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(3221225481, 1152921429444920521),
+                 Rational(3, 1073741789) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(3, 1073741789) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741792, 3),
+                 Rational(1073741789, 3) + Rational(1, 1))
+    assert_equal(Rational(1073741786, 3),
+                 Rational(1073741789, 3) - Rational(1, 1))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1073741789, 3) * Rational(1, 1))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1073741789, 3) / Rational(1, 1))
+    assert_equal(Rational(1073741795, 3),
+                 Rational(1073741789, 3) + Rational(2, 1))
+    assert_equal(Rational(1073741783, 3),
+                 Rational(1073741789, 3) - Rational(2, 1))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(1073741789, 3) * Rational(2, 1))
+    assert_equal(Rational(1073741789, 6),
+                 Rational(1073741789, 3) / Rational(2, 1))
+    assert_equal(Rational(1073741798, 3),
+                 Rational(1073741789, 3) + Rational(3, 1))
+    assert_equal(Rational(1073741780, 3),
+                 Rational(1073741789, 3) - Rational(3, 1))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(1073741789, 3) * Rational(3, 1))
+    assert_equal(Rational(1073741789, 9),
+                 Rational(1073741789, 3) / Rational(3, 1))
+    assert_equal(Rational(4294967156, 3),
+                 Rational(1073741789, 3) + Rational(1073741789, 1))
+    assert_equal(Rational(-2147483578, 3),
+                 Rational(1073741789, 3) - Rational(1073741789, 1))
+    assert_equal(Rational(1152921429444920521, 3),
+                 Rational(1073741789, 3) * Rational(1073741789, 1))
+    assert_equal(Rational(1, 3),
+                 Rational(1073741789, 3) / Rational(1073741789, 1))
+    assert_equal(Rational(4294967270, 3),
+                 Rational(1073741789, 3) + Rational(1073741827, 1))
+    assert_equal(Rational(-2147483692, 3),
+                 Rational(1073741789, 3) - Rational(1073741827, 1))
+    assert_equal(Rational(1152921470247108503, 3),
+                 Rational(1073741789, 3) * Rational(1073741827, 1))
+    assert_equal(Rational(1073741789, 3221225481),
+                 Rational(1073741789, 3) / Rational(1073741827, 1))
+    assert_equal(Rational(1073741791, 3),
+                 Rational(1073741789, 3) + Rational(2, 3))
+    assert_equal(Rational(357913929, 1),
+                 Rational(1073741789, 3) - Rational(2, 3))
+    assert_equal(Rational(2147483578, 9),
+                 Rational(1073741789, 3) * Rational(2, 3))
+    assert_equal(Rational(1073741789, 2),
+                 Rational(1073741789, 3) / Rational(2, 3))
+    assert_equal(Rational(2147483587, 6),
+                 Rational(1073741789, 3) + Rational(3, 2))
+    assert_equal(Rational(2147483569, 6),
+                 Rational(1073741789, 3) - Rational(3, 2))
+    assert_equal(Rational(1073741789, 2),
+                 Rational(1073741789, 3) * Rational(3, 2))
+    assert_equal(Rational(2147483578, 9),
+                 Rational(1073741789, 3) / Rational(3, 2))
+    assert_equal(Rational(1152921429444920530, 3221225367),
+                 Rational(1073741789, 3) + Rational(3, 1073741789))
+    assert_equal(Rational(1152921429444920512, 3221225367),
+                 Rational(1073741789, 3) - Rational(3, 1073741789))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741789, 3) * Rational(3, 1073741789))
+    assert_equal(Rational(1152921429444920521, 9),
+                 Rational(1073741789, 3) / Rational(3, 1073741789))
+    assert_equal(Rational(2147483578, 3),
+                 Rational(1073741789, 3) + Rational(1073741789, 3))
+    assert_equal(Rational(0, 1),
+                 Rational(1073741789, 3) - Rational(1073741789, 3))
+    assert_equal(Rational(1152921429444920521, 9),
+                 Rational(1073741789, 3) * Rational(1073741789, 3))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741789, 3) / Rational(1073741789, 3))
+    assert_equal(Rational(1152921470247108512, 3221225481),
+                 Rational(1073741789, 3) + Rational(3, 1073741827))
+    assert_equal(Rational(1152921470247108494, 3221225481),
+                 Rational(1073741789, 3) - Rational(3, 1073741827))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(1073741789, 3) * Rational(3, 1073741827))
+    assert_equal(Rational(1152921470247108503, 9),
+                 Rational(1073741789, 3) / Rational(3, 1073741827))
+    assert_equal(Rational(715827872, 1),
+                 Rational(1073741789, 3) + Rational(1073741827, 3))
+    assert_equal(Rational(-38, 3),
+                 Rational(1073741789, 3) - Rational(1073741827, 3))
+    assert_equal(Rational(1152921470247108503, 9),
+                 Rational(1073741789, 3) * Rational(1073741827, 3))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(1073741789, 3) / Rational(1073741827, 3))
+    assert_equal(Rational(1152921473468333870, 3221225481),
+                 Rational(1073741789, 3) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921467025883136, 3221225481),
+                 Rational(1073741789, 3) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921429444920521, 3221225481),
+                 Rational(1073741789, 3) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1073741789, 3) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921432666146002, 3221225367),
+                 Rational(1073741789, 3) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921426223695040, 3221225367),
+                 Rational(1073741789, 3) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1073741789, 3) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921429444920521, 3221225481),
+                 Rational(1073741789, 3) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741830, 1073741827),
+                 Rational(3, 1073741827) + Rational(1, 1))
+    assert_equal(Rational(-1073741824, 1073741827),
+                 Rational(3, 1073741827) - Rational(1, 1))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(3, 1073741827) * Rational(1, 1))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(3, 1073741827) / Rational(1, 1))
+    assert_equal(Rational(2147483657, 1073741827),
+                 Rational(3, 1073741827) + Rational(2, 1))
+    assert_equal(Rational(-2147483651, 1073741827),
+                 Rational(3, 1073741827) - Rational(2, 1))
+    assert_equal(Rational(6, 1073741827),
+                 Rational(3, 1073741827) * Rational(2, 1))
+    assert_equal(Rational(3, 2147483654),
+                 Rational(3, 1073741827) / Rational(2, 1))
+    assert_equal(Rational(3221225484, 1073741827),
+                 Rational(3, 1073741827) + Rational(3, 1))
+    assert_equal(Rational(-3221225478, 1073741827),
+                 Rational(3, 1073741827) - Rational(3, 1))
+    assert_equal(Rational(9, 1073741827),
+                 Rational(3, 1073741827) * Rational(3, 1))
+    assert_equal(Rational(1, 1073741827),
+                 Rational(3, 1073741827) / Rational(3, 1))
+    assert_equal(Rational(1152921470247108506, 1073741827),
+                 Rational(3, 1073741827) + Rational(1073741789, 1))
+    assert_equal(Rational(-1152921470247108500, 1073741827),
+                 Rational(3, 1073741827) - Rational(1073741789, 1))
+    assert_equal(Rational(3221225367, 1073741827),
+                 Rational(3, 1073741827) * Rational(1073741789, 1))
+    assert_equal(Rational(3, 1152921470247108503),
+                 Rational(3, 1073741827) / Rational(1073741789, 1))
+    assert_equal(Rational(1152921511049297932, 1073741827),
+                 Rational(3, 1073741827) + Rational(1073741827, 1))
+    assert_equal(Rational(-1152921511049297926, 1073741827),
+                 Rational(3, 1073741827) - Rational(1073741827, 1))
+    assert_equal(Rational(3, 1),
+                 Rational(3, 1073741827) * Rational(1073741827, 1))
+    assert_equal(Rational(3, 1152921511049297929),
+                 Rational(3, 1073741827) / Rational(1073741827, 1))
+    assert_equal(Rational(2147483663, 3221225481),
+                 Rational(3, 1073741827) + Rational(2, 3))
+    assert_equal(Rational(-2147483645, 3221225481),
+                 Rational(3, 1073741827) - Rational(2, 3))
+    assert_equal(Rational(2, 1073741827),
+                 Rational(3, 1073741827) * Rational(2, 3))
+    assert_equal(Rational(9, 2147483654),
+                 Rational(3, 1073741827) / Rational(2, 3))
+    assert_equal(Rational(3221225487, 2147483654),
+                 Rational(3, 1073741827) + Rational(3, 2))
+    assert_equal(Rational(-3221225475, 2147483654),
+                 Rational(3, 1073741827) - Rational(3, 2))
+    assert_equal(Rational(9, 2147483654),
+                 Rational(3, 1073741827) * Rational(3, 2))
+    assert_equal(Rational(2, 1073741827),
+                 Rational(3, 1073741827) / Rational(3, 2))
+    assert_equal(Rational(6442450848, 1152921470247108503),
+                 Rational(3, 1073741827) + Rational(3, 1073741789))
+    assert_equal(Rational(-114, 1152921470247108503),
+                 Rational(3, 1073741827) - Rational(3, 1073741789))
+    assert_equal(Rational(9, 1152921470247108503),
+                 Rational(3, 1073741827) * Rational(3, 1073741789))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(3, 1073741827) / Rational(3, 1073741789))
+    assert_equal(Rational(1152921470247108512, 3221225481),
+                 Rational(3, 1073741827) + Rational(1073741789, 3))
+    assert_equal(Rational(-1152921470247108494, 3221225481),
+                 Rational(3, 1073741827) - Rational(1073741789, 3))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(3, 1073741827) * Rational(1073741789, 3))
+    assert_equal(Rational(9, 1152921470247108503),
+                 Rational(3, 1073741827) / Rational(1073741789, 3))
+    assert_equal(Rational(6, 1073741827),
+                 Rational(3, 1073741827) + Rational(3, 1073741827))
+    assert_equal(Rational(0, 1),
+                 Rational(3, 1073741827) - Rational(3, 1073741827))
+    assert_equal(Rational(9, 1152921511049297929),
+                 Rational(3, 1073741827) * Rational(3, 1073741827))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 1073741827) / Rational(3, 1073741827))
+    assert_equal(Rational(1152921511049297938, 3221225481),
+                 Rational(3, 1073741827) + Rational(1073741827, 3))
+    assert_equal(Rational(-1152921511049297920, 3221225481),
+                 Rational(3, 1073741827) - Rational(1073741827, 3))
+    assert_equal(Rational(1, 1),
+                 Rational(3, 1073741827) * Rational(1073741827, 3))
+    assert_equal(Rational(9, 1152921511049297929),
+                 Rational(3, 1073741827) / Rational(1073741827, 3))
+    assert_equal(Rational(1073741792, 1073741827),
+                 Rational(3, 1073741827) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(-1073741786, 1073741827),
+                 Rational(3, 1073741827) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(3221225367, 1152921511049297929),
+                 Rational(3, 1073741827) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(3, 1073741827) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921514270523296, 1152921470247108503),
+                 Rational(3, 1073741827) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(-1152921507828072562, 1152921470247108503),
+                 Rational(3, 1073741827) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(3, 1073741827) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(3221225367, 1152921511049297929),
+                 Rational(3, 1073741827) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741830, 3),
+                 Rational(1073741827, 3) + Rational(1, 1))
+    assert_equal(Rational(1073741824, 3),
+                 Rational(1073741827, 3) - Rational(1, 1))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1073741827, 3) * Rational(1, 1))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1073741827, 3) / Rational(1, 1))
+    assert_equal(Rational(1073741833, 3),
+                 Rational(1073741827, 3) + Rational(2, 1))
+    assert_equal(Rational(1073741821, 3),
+                 Rational(1073741827, 3) - Rational(2, 1))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(1073741827, 3) * Rational(2, 1))
+    assert_equal(Rational(1073741827, 6),
+                 Rational(1073741827, 3) / Rational(2, 1))
+    assert_equal(Rational(1073741836, 3),
+                 Rational(1073741827, 3) + Rational(3, 1))
+    assert_equal(Rational(1073741818, 3),
+                 Rational(1073741827, 3) - Rational(3, 1))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(1073741827, 3) * Rational(3, 1))
+    assert_equal(Rational(1073741827, 9),
+                 Rational(1073741827, 3) / Rational(3, 1))
+    assert_equal(Rational(4294967194, 3),
+                 Rational(1073741827, 3) + Rational(1073741789, 1))
+    assert_equal(Rational(-2147483540, 3),
+                 Rational(1073741827, 3) - Rational(1073741789, 1))
+    assert_equal(Rational(1152921470247108503, 3),
+                 Rational(1073741827, 3) * Rational(1073741789, 1))
+    assert_equal(Rational(1073741827, 3221225367),
+                 Rational(1073741827, 3) / Rational(1073741789, 1))
+    assert_equal(Rational(4294967308, 3),
+                 Rational(1073741827, 3) + Rational(1073741827, 1))
+    assert_equal(Rational(-2147483654, 3),
+                 Rational(1073741827, 3) - Rational(1073741827, 1))
+    assert_equal(Rational(1152921511049297929, 3),
+                 Rational(1073741827, 3) * Rational(1073741827, 1))
+    assert_equal(Rational(1, 3),
+                 Rational(1073741827, 3) / Rational(1073741827, 1))
+    assert_equal(Rational(357913943, 1),
+                 Rational(1073741827, 3) + Rational(2, 3))
+    assert_equal(Rational(1073741825, 3),
+                 Rational(1073741827, 3) - Rational(2, 3))
+    assert_equal(Rational(2147483654, 9),
+                 Rational(1073741827, 3) * Rational(2, 3))
+    assert_equal(Rational(1073741827, 2),
+                 Rational(1073741827, 3) / Rational(2, 3))
+    assert_equal(Rational(2147483663, 6),
+                 Rational(1073741827, 3) + Rational(3, 2))
+    assert_equal(Rational(2147483645, 6),
+                 Rational(1073741827, 3) - Rational(3, 2))
+    assert_equal(Rational(1073741827, 2),
+                 Rational(1073741827, 3) * Rational(3, 2))
+    assert_equal(Rational(2147483654, 9),
+                 Rational(1073741827, 3) / Rational(3, 2))
+    assert_equal(Rational(1152921470247108512, 3221225367),
+                 Rational(1073741827, 3) + Rational(3, 1073741789))
+    assert_equal(Rational(1152921470247108494, 3221225367),
+                 Rational(1073741827, 3) - Rational(3, 1073741789))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(1073741827, 3) * Rational(3, 1073741789))
+    assert_equal(Rational(1152921470247108503, 9),
+                 Rational(1073741827, 3) / Rational(3, 1073741789))
+    assert_equal(Rational(715827872, 1),
+                 Rational(1073741827, 3) + Rational(1073741789, 3))
+    assert_equal(Rational(38, 3),
+                 Rational(1073741827, 3) - Rational(1073741789, 3))
+    assert_equal(Rational(1152921470247108503, 9),
+                 Rational(1073741827, 3) * Rational(1073741789, 3))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(1073741827, 3) / Rational(1073741789, 3))
+    assert_equal(Rational(1152921511049297938, 3221225481),
+                 Rational(1073741827, 3) + Rational(3, 1073741827))
+    assert_equal(Rational(1152921511049297920, 3221225481),
+                 Rational(1073741827, 3) - Rational(3, 1073741827))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741827, 3) * Rational(3, 1073741827))
+    assert_equal(Rational(1152921511049297929, 9),
+                 Rational(1073741827, 3) / Rational(3, 1073741827))
+    assert_equal(Rational(2147483654, 3),
+                 Rational(1073741827, 3) + Rational(1073741827, 3))
+    assert_equal(Rational(0, 1),
+                 Rational(1073741827, 3) - Rational(1073741827, 3))
+    assert_equal(Rational(1152921511049297929, 9),
+                 Rational(1073741827, 3) * Rational(1073741827, 3))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741827, 3) / Rational(1073741827, 3))
+    assert_equal(Rational(1152921514270523296, 3221225481),
+                 Rational(1073741827, 3) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921507828072562, 3221225481),
+                 Rational(1073741827, 3) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1073741827, 3) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921511049297929, 3221225367),
+                 Rational(1073741827, 3) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921473468333984, 3221225367),
+                 Rational(1073741827, 3) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921467025883022, 3221225367),
+                 Rational(1073741827, 3) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921511049297929, 3221225367),
+                 Rational(1073741827, 3) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1073741827, 3) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(2147483616, 1073741827),
+                 Rational(1073741789, 1073741827) + Rational(1, 1))
+    assert_equal(Rational(-38, 1073741827),
+                 Rational(1073741789, 1073741827) - Rational(1, 1))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(1073741789, 1073741827) * Rational(1, 1))
+    assert_equal(Rational(1073741789, 1073741827),
+                 Rational(1073741789, 1073741827) / Rational(1, 1))
+    assert_equal(Rational(3221225443, 1073741827),
+                 Rational(1073741789, 1073741827) + Rational(2, 1))
+    assert_equal(Rational(-1073741865, 1073741827),
+                 Rational(1073741789, 1073741827) - Rational(2, 1))
+    assert_equal(Rational(2147483578, 1073741827),
+                 Rational(1073741789, 1073741827) * Rational(2, 1))
+    assert_equal(Rational(1073741789, 2147483654),
+                 Rational(1073741789, 1073741827) / Rational(2, 1))
+    assert_equal(Rational(4294967270, 1073741827),
+                 Rational(1073741789, 1073741827) + Rational(3, 1))
+    assert_equal(Rational(-2147483692, 1073741827),
+                 Rational(1073741789, 1073741827) - Rational(3, 1))
+    assert_equal(Rational(3221225367, 1073741827),
+                 Rational(1073741789, 1073741827) * Rational(3, 1))
+    assert_equal(Rational(1073741789, 3221225481),
+                 Rational(1073741789, 1073741827) / Rational(3, 1))
+    assert_equal(Rational(1152921471320850292, 1073741827),
+                 Rational(1073741789, 1073741827) + Rational(1073741789, 1))
+    assert_equal(Rational(-1152921469173366714, 1073741827),
+                 Rational(1073741789, 1073741827) - Rational(1073741789, 1))
+    assert_equal(Rational(1152921429444920521, 1073741827),
+                 Rational(1073741789, 1073741827) * Rational(1073741789, 1))
+    assert_equal(Rational(1, 1073741827),
+                 Rational(1073741789, 1073741827) / Rational(1073741789, 1))
+    assert_equal(Rational(1152921512123039718, 1073741827),
+                 Rational(1073741789, 1073741827) + Rational(1073741827, 1))
+    assert_equal(Rational(-1152921509975556140, 1073741827),
+                 Rational(1073741789, 1073741827) - Rational(1073741827, 1))
+    assert_equal(Rational(1073741789, 1),
+                 Rational(1073741789, 1073741827) * Rational(1073741827, 1))
+    assert_equal(Rational(1073741789, 1152921511049297929),
+                 Rational(1073741789, 1073741827) / Rational(1073741827, 1))
+    assert_equal(Rational(5368709021, 3221225481),
+                 Rational(1073741789, 1073741827) + Rational(2, 3))
+    assert_equal(Rational(1073741713, 3221225481),
+                 Rational(1073741789, 1073741827) - Rational(2, 3))
+    assert_equal(Rational(2147483578, 3221225481),
+                 Rational(1073741789, 1073741827) * Rational(2, 3))
+    assert_equal(Rational(3221225367, 2147483654),
+                 Rational(1073741789, 1073741827) / Rational(2, 3))
+    assert_equal(Rational(5368709059, 2147483654),
+                 Rational(1073741789, 1073741827) + Rational(3, 2))
+    assert_equal(Rational(-1073741903, 2147483654),
+                 Rational(1073741789, 1073741827) - Rational(3, 2))
+    assert_equal(Rational(3221225367, 2147483654),
+                 Rational(1073741789, 1073741827) * Rational(3, 2))
+    assert_equal(Rational(2147483578, 3221225481),
+                 Rational(1073741789, 1073741827) / Rational(3, 2))
+    assert_equal(Rational(1152921432666146002, 1152921470247108503),
+                 Rational(1073741789, 1073741827) + Rational(3, 1073741789))
+    assert_equal(Rational(1152921426223695040, 1152921470247108503),
+                 Rational(1073741789, 1073741827) - Rational(3, 1073741789))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(1073741789, 1073741827) * Rational(3, 1073741789))
+    assert_equal(Rational(1152921429444920521, 3221225481),
+                 Rational(1073741789, 1073741827) / Rational(3, 1073741789))
+    assert_equal(Rational(1152921473468333870, 3221225481),
+                 Rational(1073741789, 1073741827) + Rational(1073741789, 3))
+    assert_equal(Rational(-1152921467025883136, 3221225481),
+                 Rational(1073741789, 1073741827) - Rational(1073741789, 3))
+    assert_equal(Rational(1152921429444920521, 3221225481),
+                 Rational(1073741789, 1073741827) * Rational(1073741789, 3))
+    assert_equal(Rational(3, 1073741827),
+                 Rational(1073741789, 1073741827) / Rational(1073741789, 3))
+    assert_equal(Rational(1073741792, 1073741827),
+                 Rational(1073741789, 1073741827) + Rational(3, 1073741827))
+    assert_equal(Rational(1073741786, 1073741827),
+                 Rational(1073741789, 1073741827) - Rational(3, 1073741827))
+    assert_equal(Rational(3221225367, 1152921511049297929),
+                 Rational(1073741789, 1073741827) * Rational(3, 1073741827))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1073741789, 1073741827) / Rational(3, 1073741827))
+    assert_equal(Rational(1152921514270523296, 3221225481),
+                 Rational(1073741789, 1073741827) + Rational(1073741827, 3))
+    assert_equal(Rational(-1152921507828072562, 3221225481),
+                 Rational(1073741789, 1073741827) - Rational(1073741827, 3))
+    assert_equal(Rational(1073741789, 3),
+                 Rational(1073741789, 1073741827) * Rational(1073741827, 3))
+    assert_equal(Rational(3221225367, 1152921511049297929),
+                 Rational(1073741789, 1073741827) / Rational(1073741827, 3))
+    assert_equal(Rational(2147483578, 1073741827),
+                 Rational(1073741789, 1073741827) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(0, 1),
+                 Rational(1073741789, 1073741827) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921429444920521, 1152921511049297929),
+                 Rational(1073741789, 1073741827) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741789, 1073741827) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(2305842940494218450, 1152921470247108503),
+                 Rational(1073741789, 1073741827) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(-81604377408, 1152921470247108503),
+                 Rational(1073741789, 1073741827) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741789, 1073741827) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921429444920521, 1152921511049297929),
+                 Rational(1073741789, 1073741827) / Rational(1073741827, 1073741789))
+    assert_equal(Rational(2147483616, 1073741789),
+                 Rational(1073741827, 1073741789) + Rational(1, 1))
+    assert_equal(Rational(38, 1073741789),
+                 Rational(1073741827, 1073741789) - Rational(1, 1))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(1073741827, 1073741789) * Rational(1, 1))
+    assert_equal(Rational(1073741827, 1073741789),
+                 Rational(1073741827, 1073741789) / Rational(1, 1))
+    assert_equal(Rational(3221225405, 1073741789),
+                 Rational(1073741827, 1073741789) + Rational(2, 1))
+    assert_equal(Rational(-1073741751, 1073741789),
+                 Rational(1073741827, 1073741789) - Rational(2, 1))
+    assert_equal(Rational(2147483654, 1073741789),
+                 Rational(1073741827, 1073741789) * Rational(2, 1))
+    assert_equal(Rational(1073741827, 2147483578),
+                 Rational(1073741827, 1073741789) / Rational(2, 1))
+    assert_equal(Rational(4294967194, 1073741789),
+                 Rational(1073741827, 1073741789) + Rational(3, 1))
+    assert_equal(Rational(-2147483540, 1073741789),
+                 Rational(1073741827, 1073741789) - Rational(3, 1))
+    assert_equal(Rational(3221225481, 1073741789),
+                 Rational(1073741827, 1073741789) * Rational(3, 1))
+    assert_equal(Rational(1073741827, 3221225367),
+                 Rational(1073741827, 1073741789) / Rational(3, 1))
+    assert_equal(Rational(1152921430518662348, 1073741789),
+                 Rational(1073741827, 1073741789) + Rational(1073741789, 1))
+    assert_equal(Rational(-1152921428371178694, 1073741789),
+                 Rational(1073741827, 1073741789) - Rational(1073741789, 1))
+    assert_equal(Rational(1073741827, 1),
+                 Rational(1073741827, 1073741789) * Rational(1073741789, 1))
+    assert_equal(Rational(1073741827, 1152921429444920521),
+                 Rational(1073741827, 1073741789) / Rational(1073741789, 1))
+    assert_equal(Rational(1152921471320850330, 1073741789),
+                 Rational(1073741827, 1073741789) + Rational(1073741827, 1))
+    assert_equal(Rational(-1152921469173366676, 1073741789),
+                 Rational(1073741827, 1073741789) - Rational(1073741827, 1))
+    assert_equal(Rational(1152921511049297929, 1073741789),
+                 Rational(1073741827, 1073741789) * Rational(1073741827, 1))
+    assert_equal(Rational(1, 1073741789),
+                 Rational(1073741827, 1073741789) / Rational(1073741827, 1))
+    assert_equal(Rational(5368709059, 3221225367),
+                 Rational(1073741827, 1073741789) + Rational(2, 3))
+    assert_equal(Rational(1073741903, 3221225367),
+                 Rational(1073741827, 1073741789) - Rational(2, 3))
+    assert_equal(Rational(2147483654, 3221225367),
+                 Rational(1073741827, 1073741789) * Rational(2, 3))
+    assert_equal(Rational(3221225481, 2147483578),
+                 Rational(1073741827, 1073741789) / Rational(2, 3))
+    assert_equal(Rational(5368709021, 2147483578),
+                 Rational(1073741827, 1073741789) + Rational(3, 2))
+    assert_equal(Rational(-1073741713, 2147483578),
+                 Rational(1073741827, 1073741789) - Rational(3, 2))
+    assert_equal(Rational(3221225481, 2147483578),
+                 Rational(1073741827, 1073741789) * Rational(3, 2))
+    assert_equal(Rational(2147483654, 3221225367),
+                 Rational(1073741827, 1073741789) / Rational(3, 2))
+    assert_equal(Rational(1073741830, 1073741789),
+                 Rational(1073741827, 1073741789) + Rational(3, 1073741789))
+    assert_equal(Rational(1073741824, 1073741789),
+                 Rational(1073741827, 1073741789) - Rational(3, 1073741789))
+    assert_equal(Rational(3221225481, 1152921429444920521),
+                 Rational(1073741827, 1073741789) * Rational(3, 1073741789))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1073741827, 1073741789) / Rational(3, 1073741789))
+    assert_equal(Rational(1152921432666146002, 3221225367),
+                 Rational(1073741827, 1073741789) + Rational(1073741789, 3))
+    assert_equal(Rational(-1152921426223695040, 3221225367),
+                 Rational(1073741827, 1073741789) - Rational(1073741789, 3))
+    assert_equal(Rational(1073741827, 3),
+                 Rational(1073741827, 1073741789) * Rational(1073741789, 3))
+    assert_equal(Rational(3221225481, 1152921429444920521),
+                 Rational(1073741827, 1073741789) / Rational(1073741789, 3))
+    assert_equal(Rational(1152921514270523296, 1152921470247108503),
+                 Rational(1073741827, 1073741789) + Rational(3, 1073741827))
+    assert_equal(Rational(1152921507828072562, 1152921470247108503),
+                 Rational(1073741827, 1073741789) - Rational(3, 1073741827))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(1073741827, 1073741789) * Rational(3, 1073741827))
+    assert_equal(Rational(1152921511049297929, 3221225367),
+                 Rational(1073741827, 1073741789) / Rational(3, 1073741827))
+    assert_equal(Rational(1152921473468333984, 3221225367),
+                 Rational(1073741827, 1073741789) + Rational(1073741827, 3))
+    assert_equal(Rational(-1152921467025883022, 3221225367),
+                 Rational(1073741827, 1073741789) - Rational(1073741827, 3))
+    assert_equal(Rational(1152921511049297929, 3221225367),
+                 Rational(1073741827, 1073741789) * Rational(1073741827, 3))
+    assert_equal(Rational(3, 1073741789),
+                 Rational(1073741827, 1073741789) / Rational(1073741827, 3))
+    assert_equal(Rational(2305842940494218450, 1152921470247108503),
+                 Rational(1073741827, 1073741789) + Rational(1073741789, 1073741827))
+    assert_equal(Rational(81604377408, 1152921470247108503),
+                 Rational(1073741827, 1073741789) - Rational(1073741789, 1073741827))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741827, 1073741789) * Rational(1073741789, 1073741827))
+    assert_equal(Rational(1152921511049297929, 1152921429444920521),
+                 Rational(1073741827, 1073741789) / Rational(1073741789, 1073741827))
+    assert_equal(Rational(2147483654, 1073741789),
+                 Rational(1073741827, 1073741789) + Rational(1073741827, 1073741789))
+    assert_equal(Rational(0, 1),
+                 Rational(1073741827, 1073741789) - Rational(1073741827, 1073741789))
+    assert_equal(Rational(1152921511049297929, 1152921429444920521),
+                 Rational(1073741827, 1073741789) * Rational(1073741827, 1073741789))
+    assert_equal(Rational(1, 1),
+                 Rational(1073741827, 1073741789) / Rational(1073741827, 1073741789))
+  end
+
+end

Modified: MacRuby/trunk/test/ruby/test_regexp.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_regexp.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_regexp.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -123,6 +123,8 @@
     r = /./
     m = r.match("a")
     assert_equal(r, m.regexp)
+    re = /foo/
+    assert_equal(re, re.match("foo").regexp)
   end
 
   def test_source
@@ -188,11 +190,6 @@
     assert_equal(/foo/, m.dup.regexp)
   end
 
-  def test_match_regexp
-    re = /foo/
-    assert_equal(re, re.match("foo").regexp)
-  end
-
   def test_match_size
     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
     assert_equal(5, m.size)

Added: MacRuby/trunk/test/ruby/test_rubyoptions.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_rubyoptions.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_rubyoptions.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,455 @@
+require 'test/unit'
+
+require 'tmpdir'
+require 'tempfile'
+require_relative 'envutil'
+
+class TestRubyOptions < Test::Unit::TestCase
+  def ruby(*r, &b)
+    EnvUtil.rubyexec(*r, &b)
+  end
+
+  def test_source_file
+    ruby('') do |w, r, e|
+      w.close
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+  end
+
+  def test_usage
+    ruby('-h') do |w, r, e|
+      w.close
+      assert(r.readlines.size <= 24)
+    end
+
+    ruby('--help') do |w, r, e|
+      w.close
+      assert(r.readlines.size <= 24)
+    end
+  end
+
+  def test_option_variables
+    ruby('-e', 'p [$-p, $-l, $-a]') do |w, r, e|
+      assert_equal('[false, false, false]', r.read.chomp)
+    end
+
+    ruby('-p', '-l', '-a', '-e', 'p [$-p, $-l, $-a]') do |w, r, e|
+      w.puts 'foo'
+      w.puts 'bar'
+      w.puts 'baz'
+      w.close_write
+      r = r.readlines.map {|l| l.chomp }
+      assert_equal(
+        [ '[true, true, true]', 'foo',
+          '[true, true, true]', 'bar',
+          '[true, true, true]', 'baz' ], r)
+    end
+  end
+
+  def test_warning
+    ruby('-W0', '-e', 'p $-W') do |w, r, e|
+      assert_equal('0', r.read.chomp)
+    end
+    ruby('-W1', '-e', 'p $-W') do |w, r, e|
+      assert_equal('1', r.read.chomp)
+    end
+    ruby('-Wx', '-e', 'p $-W') do |w, r, e|
+      assert_equal('1', r.read.chomp)
+    end
+    ruby('-W', '-e', 'p $-W') do |w, r, e|
+      assert_equal('2', r.read.chomp)
+    end
+  end
+
+  def test_safe_level
+    ruby('-T', '-e', '') do |w, r, e|
+      assert_match(/no -e allowed in tainted mode \(SecurityError\)/, e.read)
+    end
+
+    ruby('-T4', '-S', 'foo.rb') do |w, r, e|
+      assert_match(/no -S allowed in tainted mode \(SecurityError\)/, e.read)
+    end
+  end
+
+  def test_debug
+    ruby('-de', 'p $DEBUG') do |w, r, e|
+      assert_equal('true', r.read.chomp)
+    end
+
+    ruby('--debug', '-e', 'p $DEBUG') do |w, r, e|
+      assert_equal('true', r.read.chomp)
+    end
+  end
+
+  def test_verbose
+    ruby('-vve', '') do |w, r, e|
+      assert_match(/^ruby #{RUBY_VERSION} .*? \[#{RUBY_PLATFORM}\]$/, r.read)
+    end
+
+    ruby('--verbose', '-e', 'p $VERBOSE') do |w, r, e|
+      assert_equal('true', r.read.chomp)
+    end
+
+    ruby('--verbose') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+  end
+
+  def test_copyright
+    ruby('--copyright') do |w, r, e|
+      assert_match(/^ruby - Copyright \(C\) 1993-\d+ Yukihiro Matsumoto$/, r.read)
+    end
+
+    ruby('--verbose', '-e', 'p $VERBOSE') do |w, r, e|
+      assert_equal('true', r.read.chomp)
+    end
+  end
+
+  def test_enable
+    ruby('--enable', 'all', '-e', '') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ruby('--enable-all', '-e', '') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ruby('--enable=all', '-e', '') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ruby('--enable', 'foobarbazqux', '-e', '') do |w, r, e|
+      assert_match(/unknown argument for --enable: `foobarbazqux'/, e.read)
+    end
+
+    ruby('--enable') do |w, r, e|
+      assert_match(/missing argument for --enable/, e.read)
+    end
+  end
+
+  def test_disable
+    ruby('--disable', 'all', '-e', '') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ruby('--disable-all', '-e', '') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ruby('--disable=all', '-e', '') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ruby('--disable', 'foobarbazqux', '-e', '') do |w, r, e|
+      assert_match(/unknown argument for --disable: `foobarbazqux'/, e.read)
+    end
+
+    ruby('--disable') do |w, r, e|
+      assert_match(/missing argument for --disable/, e.read)
+    end
+  end
+
+  def test_kanji
+    ruby('-KU') do |w, r, e|
+      w.puts "p '\u3042'"
+      w.close
+      assert_equal("\"\u3042\"", r.read.chomp.force_encoding(Encoding.find('utf-8')))
+    end
+
+    ruby('-KE', '-e', '') do |w, r, e|
+      assert_equal("", r.read)
+      assert_equal("", e.read)
+    end
+
+    ruby('-KS', '-e', '') do |w, r, e|
+      assert_equal("", r.read)
+      assert_equal("", e.read)
+    end
+
+    ruby('-KN', '-e', '') do |w, r, e|
+      assert_equal("", r.read)
+      assert_equal("", e.read)
+    end
+  end
+
+  def test_version
+    ruby('--version') do |w, r, e|
+      assert_match(/^ruby #{RUBY_VERSION} .*? \[#{RUBY_PLATFORM}\]$/, r.read)
+    end
+  end
+
+  def test_eval
+    ruby('-e') do |w, r, e|
+      assert_match(/no code specified for -e \(RuntimeError\)/, e.read)
+    end
+  end
+
+  def test_require
+    ruby('-r', 'pp', '-e', 'pp 1') do |w, r, e|
+      assert_equal('1', r.read.chomp)
+    end
+    ruby('-rpp', '-e', 'pp 1') do |w, r, e|
+      w.close
+      assert_equal('1', r.read.chomp)
+    end
+  end
+
+  def test_include
+    d = Dir.tmpdir
+    ruby('-I' + d, '-e', '') do |w, r, e|
+      assert_equal('', e.read.chomp)
+      assert_equal('', r.read.chomp)
+    end
+
+    d = Dir.tmpdir
+    ruby('-I', d, '-e', '') do |w, r, e|
+      assert_equal('', e.read.chomp)
+      assert_equal('', r.read.chomp)
+    end
+  end
+
+  def test_separator
+    ruby('-000', '-e', 'print gets') do |w, r, e|
+      w.write "foo\nbar\0baz"
+      w.close
+      assert_equal('', e.read)
+      assert_equal("foo\nbar\0baz", r.read)
+    end
+
+    ruby('-0141', '-e', 'print gets') do |w, r, e|
+      w.write "foo\nbar\0baz"
+      w.close
+      assert_equal('', e.read)
+      assert_equal("foo\nba", r.read)
+    end
+
+    ruby('-0e', 'print gets') do |w, r, e|
+      w.write "foo\nbar\0baz"
+      w.close
+      assert_equal('', e.read)
+      assert_equal("foo\nbar\0", r.read)
+    end
+  end
+
+  def test_autosplit
+    ruby('-an', '-F:', '-e', 'p $F') do |w, r, e|
+      w.puts "foo:bar:baz"
+      w.puts "qux:quux:quuux"
+      w.close
+      r = r.readlines.map {|l| l.chomp }
+      assert_equal(['["foo", "bar", "baz\n"]', '["qux", "quux", "quuux\n"]'], r)
+    end
+  end
+
+  def test_chdir
+    ruby('-C') do |w, r, e|
+      assert_match(/Can't chdir/, e.read)
+    end
+
+    ruby('-C', 'test_ruby_test_rubyoptions_foobarbazqux') do |w, r, e|
+      assert_match(/Can't chdir/, e.read)
+    end
+
+    d = Dir.tmpdir
+    ruby('-C', d, '-e', 'puts Dir.pwd') do |w, r, e|
+      assert_equal('', e.read)
+      assert(File.identical?(r.read.chomp, d))
+    end
+  end
+
+  def test_yydebug
+    ruby('-ye', '') do |w, r, e|
+      assert_equal("", r.read)
+      assert_nothing_raised { e.read }
+    end
+
+    ruby('--yydebug', '-e', '') do |w, r, e|
+      assert_equal("", r.read)
+      assert_nothing_raised { e.read }
+    end
+  end
+
+  def test_encoding
+    ruby('-Eutf-8') do |w, r, e|
+      w.puts "p '\u3042'"
+      w.close
+      assert_match(/invalid multibyte char/, e.read)
+    end
+
+    ruby('--encoding') do |w, r, e|
+      assert_match(/missing argument for --encoding/, e.read)
+    end
+
+    ruby('--encoding', 'test_ruby_test_rubyoptions_foobarbazqux') do |w, r, e|
+      assert_match(/unknown encoding name - test_ruby_test_rubyoptions_foobarbazqux \(RuntimeError\)/, e.read)
+    end
+
+    ruby('--encoding', 'utf-8') do |w, r, e|
+      w.puts "p '\u3042'"
+      w.close
+      assert_match(/invalid multibyte char/, e.read)
+    end
+  end
+
+  def test_syntax_check
+    ruby('-c', '-e', '1+1') do |w, r, e|
+      assert_equal('Syntax OK', r.read.chomp)
+    end
+  end
+
+  def test_invalid_option
+    ruby('--foobarbazqux') do |w, r, e|
+      assert_match(/invalid option --foobarbazqux/, e.read)
+    end
+
+    ruby("-\r", '-e', '') do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ruby("-\rx") do |w, r, e|
+      assert_match(/invalid option -\\x0D  \(-h will show valid options\) \(RuntimeError\)/, e.read)
+    end
+
+    ruby("-\x01") do |w, r, e|
+      assert_match(/invalid option -\\x01  \(-h will show valid options\) \(RuntimeError\)/, e.read)
+    end
+
+    ruby('-Z') do |w, r, e|
+      assert_match(/invalid option -Z  \(-h will show valid options\) \(RuntimeError\)/, e.read)
+    end
+  end
+
+  def test_rubyopt
+    rubyopt_orig = ENV['RUBYOPT']
+
+    ENV['RUBYOPT'] = ' - -'
+    ruby do |w, r, e|
+      w.close
+      assert_equal('', e.read)
+      assert_equal('', r.read)
+    end
+
+    ENV['RUBYOPT'] = '-e "p 1"'
+    ruby do |w, r, e|
+      assert_match(/invalid switch in RUBYOPT: -e \(RuntimeError\)/, e.read)
+    end
+
+    ENV['RUBYOPT'] = '-T1'
+    ruby do |w, r, e|
+      assert_match(/no program input from stdin allowed in tainted mode \(SecurityError\)/, e.read)
+    end
+
+    ENV['RUBYOPT'] = '-T4'
+    ruby do |w, r, e|
+    end
+
+    ENV['RUBYOPT'] = '-KN -Eus-ascii'
+    ruby('-KU', '-Eutf-8') do |w, r, e|
+      w.puts "p '\u3042'"
+      w.close
+      assert_equal("\"\u3042\"", r.read.chomp.force_encoding(Encoding.find('utf-8')))
+    end
+
+  ensure
+    if rubyopt_orig
+      ENV['RUBYOPT'] = rubyopt_orig
+    else
+      ENV.delete('RUBYOPT')
+    end
+  end
+
+  def test_search
+    rubypath_orig = ENV['RUBYPATH']
+    path_orig = ENV['PATH']
+
+    t = Tempfile.new(["test_ruby_test_rubyoption", ".rb"])
+    t.puts "p 1"
+    t.close
+
+    @verbose = $VERBOSE
+    $VERBOSE = nil
+
+    ENV['PATH'] = File.dirname(t.path)
+
+    ruby('-S', File.basename(t.path)) do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('1', r.read.chomp)
+    end
+
+    ENV['RUBYPATH'] = File.dirname(t.path)
+
+    ruby('-S', File.basename(t.path)) do |w, r, e|
+      assert_equal('', e.read)
+      assert_equal('1', r.read.chomp)
+    end
+
+  ensure
+    if rubypath_orig
+      ENV['RUBYPATH'] = rubypath_orig
+    else
+      ENV.delete('RUBYPATH')
+    end
+    if path_orig
+      ENV['PATH'] = path_orig
+    else
+      ENV.delete('PATH')
+    end
+    t.close(true) if t
+    $VERBOSE = @verbose
+  end
+
+  def test_shebang
+    ruby do |w, r, e|
+      w.print "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux\r\np 1\r\n"
+      w.close
+      assert_match(/Can't exec \/test_r_u_b_y_test_r_u_b_y_options_foobarbazqux \(fatal\)/, e.read)
+      assert_equal('', r.read.chomp)
+    end
+
+    ruby do |w, r, e|
+      w.print "#! /test_r_u_b_y_test_r_u_b_y_options_foobarbazqux -foo -bar\r\np 1\r\n"
+      w.close
+      assert_match(/Can't exec \/test_r_u_b_y_test_r_u_b_y_options_foobarbazqux \(fatal\)/, e.read)
+      assert_equal('', r.read.chomp)
+    end
+
+    ruby do |w, r, e|
+      w.print "#!ruby -KU -Eutf-8\r\np \"\u3042\"\r\n"
+      w.close
+      assert_equal('', e.read.chomp)
+      assert_equal("\"\u3042\"", r.read.chomp.force_encoding(Encoding.find('utf-8')))
+    end
+  end
+
+  def test_sflag
+    ruby('-', '-abc', '-def=foo', '-ghi-jkl', '--', '-xyz') do |w, r, e|
+      w.print "#!ruby -s\np [$abc, $def, $ghi_jkl, $xyz]\n"
+      w.close
+      assert_equal('', e.read)
+      assert_equal('[true, "foo", true, nil]', r.read.chomp)
+    end
+
+    ruby('-', '-#') do |w, r, e|
+      w.print "#!ruby -s\n"
+      w.close
+      assert_match(/invalid name for global variable - -# \(NameError\)/, e.read)
+      assert_equal('', r.read.chomp)
+    end
+
+    ruby('-', '-#=foo') do |w, r, e|
+      w.print "#!ruby -s\n"
+      w.close
+      assert_match(/invalid name for global variable - -# \(NameError\)/, e.read)
+      assert_equal('', r.read.chomp)
+    end
+  end
+end

Modified: MacRuby/trunk/test/ruby/test_settracefunc.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_settracefunc.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_settracefunc.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -159,7 +159,7 @@
                  events.shift)
     assert_equal(["c-return", 4, :set_backtrace, Exception],
                  events.shift)
-    assert_equal(["raise", 4, :raise, Kernel],
+    assert_equal(["raise", 4, :test_raise, TestSetTraceFunc],
                  events.shift)
     assert_equal(["c-call", 4, :===, Module],
                  events.shift)
@@ -171,4 +171,8 @@
                  events.shift)
     assert_equal([], events)
   end
+
+  def test_invalid_proc
+    assert_raise(TypeError) { set_trace_func(1) }
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_sprintf.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_sprintf.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_sprintf.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -31,22 +31,22 @@
     assert_equal("  0010", sprintf("%6.4b", 2))
     assert_equal("  ..11", sprintf("%6.4b", -1))
 
-    assert_equal(" 0b0", sprintf("%#4b", 0))
+    assert_equal("   0", sprintf("%#4b", 0))
     assert_equal(" 0b1", sprintf("%#4b", 1))
     assert_equal("0b10", sprintf("%#4b", 2))
     assert_equal("0b..1", sprintf("%#4b", -1))
 
-    assert_equal("0b00", sprintf("%#04b", 0))
+    assert_equal("0000", sprintf("%#04b", 0))
     assert_equal("0b01", sprintf("%#04b", 1))
     assert_equal("0b10", sprintf("%#04b", 2))
     assert_equal("0b..1", sprintf("%#04b", -1))
 
-    assert_equal("0b0000", sprintf("%#.4b", 0))
+    assert_equal("0000", sprintf("%#.4b", 0))
     assert_equal("0b0001", sprintf("%#.4b", 1))
     assert_equal("0b0010", sprintf("%#.4b", 2))
     assert_equal("0b..11", sprintf("%#.4b", -1))
 
-    assert_equal("0b0000", sprintf("%#6.4b", 0))
+    assert_equal("  0000", sprintf("%#6.4b", 0))
     assert_equal("0b0001", sprintf("%#6.4b", 1))
     assert_equal("0b0010", sprintf("%#6.4b", 2))
     assert_equal("0b..11", sprintf("%#6.4b", -1))
@@ -87,17 +87,17 @@
     assert_equal("NaN     ", sprintf("%-8f", nan))
     assert_equal("    +NaN", sprintf("%+8f", nan))
 
-    assert_equal("00000NaN", sprintf("%08f", nan))
+    assert_equal("     NaN", sprintf("%08f", nan))
     assert_equal("NaN     ", sprintf("%-08f", nan))
-    assert_equal("+0000NaN", sprintf("%+08f", nan))
+    assert_equal("    +NaN", sprintf("%+08f", nan))
 
     assert_equal("     NaN", sprintf("% 8f", nan))
     assert_equal(" NaN    ", sprintf("%- 8f", nan))
     assert_equal("    +NaN", sprintf("%+ 8f", nan))
 
-    assert_equal(" 0000NaN", sprintf("% 08f", nan))
+    assert_equal("     NaN", sprintf("% 08f", nan))
     assert_equal(" NaN    ", sprintf("%- 08f", nan))
-    assert_equal("+0000NaN", sprintf("%+ 08f", nan))
+    assert_equal("    +NaN", sprintf("%+ 08f", nan))
   end
 
   def test_inf
@@ -110,17 +110,17 @@
     assert_equal("Inf     ", sprintf("%-8f", inf))
     assert_equal("    +Inf", sprintf("%+8f", inf))
 
-    assert_equal("00000Inf", sprintf("%08f", inf))
+    assert_equal("     Inf", sprintf("%08f", inf))
     assert_equal("Inf     ", sprintf("%-08f", inf))
-    assert_equal("+0000Inf", sprintf("%+08f", inf))
+    assert_equal("    +Inf", sprintf("%+08f", inf))
 
     assert_equal("     Inf", sprintf("% 8f", inf))
     assert_equal(" Inf    ", sprintf("%- 8f", inf))
     assert_equal("    +Inf", sprintf("%+ 8f", inf))
 
-    assert_equal(" 0000Inf", sprintf("% 08f", inf))
+    assert_equal("     Inf", sprintf("% 08f", inf))
     assert_equal(" Inf    ", sprintf("%- 08f", inf))
-    assert_equal("+0000Inf", sprintf("%+ 08f", inf))
+    assert_equal("    +Inf", sprintf("%+ 08f", inf))
 
     assert_equal("-Inf", sprintf("%f", -inf))
     assert_equal("-Inf", sprintf("%-f", -inf))
@@ -130,21 +130,22 @@
     assert_equal("-Inf    ", sprintf("%-8f", -inf))
     assert_equal("    -Inf", sprintf("%+8f", -inf))
 
-    assert_equal("-0000Inf", sprintf("%08f", -inf))
+    assert_equal("    -Inf", sprintf("%08f", -inf))
     assert_equal("-Inf    ", sprintf("%-08f", -inf))
-    assert_equal("-0000Inf", sprintf("%+08f", -inf))
+    assert_equal("    -Inf", sprintf("%+08f", -inf))
 
     assert_equal("    -Inf", sprintf("% 8f", -inf))
     assert_equal("-Inf    ", sprintf("%- 8f", -inf))
     assert_equal("    -Inf", sprintf("%+ 8f", -inf))
 
-    assert_equal("-0000Inf", sprintf("% 08f", -inf))
+    assert_equal("    -Inf", sprintf("% 08f", -inf))
     assert_equal("-Inf    ", sprintf("%- 08f", -inf))
-    assert_equal("-0000Inf", sprintf("%+ 08f", -inf))
+    assert_equal("    -Inf", sprintf("%+ 08f", -inf))
     assert_equal('..f00000000',
       sprintf("%x", -2**32), '[ruby-dev:32351]')
     assert_equal("..101111111111111111111111111111111",
       sprintf("%b", -2147483649), '[ruby-dev:32365]')
+    assert_equal(" Inf", sprintf("% e", inf), '[ruby-dev:34002]')
   end
 
   def test_invalid
@@ -219,6 +220,9 @@
     assert_equal("0B1", sprintf("%#B", 1))
     assert_equal("1", sprintf("%d", 1.0))
     assert_equal("4294967296", sprintf("%d", (2**32).to_f))
+    assert_equal("-2147483648", sprintf("%d", -(2**31).to_f))
+    assert_equal("18446744073709551616", sprintf("%d", (2**64).to_f))
+    assert_equal("-9223372036854775808", sprintf("%d", -(2**63).to_f))
     assert_equal("1", sprintf("%d", "1"))
     o = Object.new; def o.to_int; 1; end
     assert_equal("1", sprintf("%d", o))

Modified: MacRuby/trunk/test/ruby/test_sprintf_comb.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_sprintf_comb.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_sprintf_comb.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,4 +1,5 @@
 require 'test/unit'
+require_relative 'allpairs'
 
 class TestSprintfComb < Test::Unit::TestCase
   VS = [
@@ -106,24 +107,13 @@
   ]
   VS.reverse!
 
-  def combination(*args)
-    args = args.map {|a| a.to_a }
-    i = 0
-    while true
-      n = i
-      as = []
-      args.reverse_each {|a|
-        n, m = n.divmod(a.length)
-        as.unshift a[m]
-      }
-      break if 0 < n
-      yield as
-      i += 1
-    end
+  def combination(*args, &b)
+    #AllPairs.exhaustive_each(*args, &b)
+    AllPairs.each(*args, &b)
   end
 
-  def emu(format, v)
-    /\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d+))?(.)\z/ =~ format
+  def emu_int(format, v)
+    /\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format
     sp = $1
     hs = $2
     pl = $3
@@ -145,7 +135,7 @@
       radix = 2
       digitmap = {0 => '0', 1 => '1'}
       complement = !pl && !sp
-      prefix = '0b' if hs
+      prefix = '0b' if hs && v != 0
     when 'd'
       radix = 10
       digitmap = {}
@@ -161,13 +151,13 @@
       digitmap = {}
       16.times {|i| digitmap[i] = i.to_s(16).upcase }
       complement = !pl && !sp
-      prefix = '0X' if hs
+      prefix = '0X' if hs && v != 0
     when 'x'
       radix = 16
       digitmap = {}
       16.times {|i| digitmap[i] = i.to_s(16) }
       complement = !pl && !sp
-      prefix = '0x' if hs
+      prefix = '0x' if hs && v != 0
     else
       raise "unexpected type: #{type.inspect}"
     end
@@ -273,23 +263,20 @@
     str
   end
 
-  def test_format
+  def test_format_integer
     combination(
         %w[b d o X x],
         [nil, 0, 5, 20],
-        [nil, 0, 8, 20],
+        ["", ".", ".0", ".8", ".20"],
         ['', ' '],
         ['', '#'],
         ['', '+'],
         ['', '-'],
         ['', '0']) {|type, width, precision, sp, hs, pl, mi, zr|
-      if precision
-        precision = ".#{precision}"
-      end
       format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}"
       VS.each {|v|
         r = sprintf format, v
-        e = emu format, v
+        e = emu_int format, v
         if true
           assert_equal(e, r, "sprintf(#{format.dump}, #{v})")
         else
@@ -300,4 +287,262 @@
       }
     }
   end
+
+  FLOAT_VALUES = [
+    -1e100,
+    -123456789.0,
+    -1.0,
+    -0.0,
+    0.0,
+    0.01,
+    1/3.0,
+    2/3.0,
+    1.0,
+    2.0,
+    9.99999999,
+    123456789.0,
+    1e100,
+    Float::MAX,
+    Float::MIN,
+    Float::EPSILON,
+    1+Float::EPSILON,
+    #1-Float::EPSILON/2,
+    10 + Float::EPSILON*10,
+    10 - Float::EPSILON*5,
+    1.0/0.0,
+    -1.0/0.0,
+    0.0/0.0,
+  ]
+
+  def split_float10(v)
+    if v == 0
+      if 1/v < 0
+        sign = -1
+        v = -v
+      else
+        sign = 1
+      end
+    else
+      if v < 0
+        sign = -1
+        v = -v
+      else
+        sign = 1
+      end
+    end
+    exp = 0
+    int = v.floor
+    v -= int
+    while v != 0
+      v *= 2
+      int *= 2
+      i = v.floor
+      v -= i
+      int += i
+      exp -= 1
+    end
+    int *= 5 ** (-exp)
+    [sign, int, exp]
+  end
+
+  def emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp)
+    precision = 6 unless precision
+    if int == 0
+      if precision == 0 && !hs
+        result = "0#{type}+00"
+      else
+        result = "0." + "0" * precision + "#{type}+00"
+      end
+    else
+      if int < 10**precision
+        int *= 10**precision
+        exp -= precision
+      end
+      digits = int.to_s.length
+      discard = digits - (precision+1)
+      if discard != 0
+        q, r = int.divmod(10**discard)
+        if r < 10**discard / 2
+          int = q
+          exp += discard
+        elsif (q+1).to_s.length == q.to_s.length
+          int = q+1
+          exp += discard
+        else
+          discard += 1
+          q, r = int.divmod(10**discard)
+          int = q+1
+          exp += discard
+        end
+      end
+      ints = int.to_s
+      frac = ints[1..-1]
+      result = ints[0,1]
+      e = exp + frac.length
+      if precision != 0 || hs
+        result << "."
+        if precision != 0
+          result << frac
+        end
+      end
+      result << type
+      if e == 0
+        if v.abs < 1
+          result << '-00' # glibc 2.7 causes '+00'
+        else
+          result << '+00'
+        end
+      else
+        result << sprintf("%+03d", e)
+      end
+      result
+    end
+    result
+  end
+
+  def emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp)
+    precision = 6 unless precision
+    if int == 0
+      if precision == 0 && !hs
+        result = '0'
+      else
+        result = '0.' + '0' * precision
+      end
+    else
+      if -precision < exp
+        int *= 10 ** (precision+exp)
+        exp = -precision
+      end
+      if exp < -precision
+        discard = -exp - precision
+        q, r = int.divmod(10**discard)
+        if 10**discard / 2 <= r
+          q += 1
+        end
+        int = q
+        exp += discard
+      end
+      result = int.to_s
+      if result.length <= precision
+        result = '0' * (precision+1 - result.length) + result
+      end
+      if precision != 0 || hs
+        if precision == 0
+          result << '.'
+        else
+          result[-precision,0] = '.'
+        end
+      end
+    end
+    result
+  end
+
+  def emu_float(format, v)
+    /\A%( )?(\#)?(\+)?(-)?(0)?(\d+)?(?:\.(\d*))?(.)\z/ =~ format
+    sp = $1
+    hs = $2
+    pl = $3
+    mi = $4
+    zr = $5
+    width = $6
+    precision = $7
+    type = $8
+    width = width.to_i if width
+    precision = precision.to_i if precision
+
+    zr = nil if mi && zr
+
+    if v.infinite?
+      sign = v < 0 ? -1 : 1
+      int = :inf
+      hs = zr = nil
+    elsif v.nan?
+      sign = 1
+      int = :nan
+      hs = zr = nil
+    else
+      sign, int, exp = split_float10(v)
+    end
+
+    if sign < 0
+      sign = '-'
+    elsif sign == 0
+      sign = ''
+    elsif pl
+      sign = '+'
+    elsif sp
+      sign = ' '
+    else
+      sign = ''
+    end
+
+    if v.nan?
+      result = 'NaN'
+    elsif v.infinite?
+      result = 'Inf'
+    else
+      case type
+      when /[eE]/
+        result = emu_e(sp, hs, pl, mi, zr, width, precision, type, v, sign, int, exp)
+      when /f/
+        result = emu_f(sp, hs, pl, mi, zr, width, precision, type, sign, int, exp)
+      when /[gG]/
+        precision = 6 unless precision
+        precision = 1 if precision == 0
+        r = emu_e(sp, hs, pl, mi, zr, width, precision-1, type.tr('gG', 'eE'), v, sign, int, exp)
+        /[eE]([+-]\d+)/ =~ r
+        e = $1.to_i
+        if e < -4 || precision <= e
+          result = r
+        else
+          result = emu_f(sp, hs, pl, mi, zr, width, precision-1-e, type, sign, int, exp)
+        end
+        result.sub!(/\.[0-9]*/) { $&.sub(/\.?0*\z/, '') } if !hs
+      else
+        raise "unexpected type: #{type}"
+      end
+    end
+
+    pad = ''
+    if width && sign.length + result.length < width
+      if zr
+        pad = '0' * (width - sign.length - result.length)
+      else
+        pad = ' ' * (width - sign.length - result.length)
+      end
+    end
+    if mi
+      sign + result + pad
+    elsif zr
+      sign + pad + result
+    else
+      pad + sign + result
+    end
+
+  end
+
+  def test_format_float
+    combination(
+        %w[e E f g G],
+        [nil, 0, 5, 20],
+        ["", ".", ".0", ".8", ".20", ".200"],
+        ['', ' '],
+        ['', '#'],
+        ['', '+'],
+        ['', '-'],
+        ['', '0']) {|type, width, precision, sp, hs, pl, mi, zr|
+      format = "%#{sp}#{hs}#{pl}#{mi}#{zr}#{width}#{precision}#{type}"
+      FLOAT_VALUES.each {|v|
+        r = sprintf format, v
+        e = emu_float format, v
+        if true
+          assert_equal(e, r, "sprintf(#{format.dump}, #{'%.20g' % v})")
+        else
+          if e != r
+            puts "#{e.dump}\t#{r.dump}\tsprintf(#{format.dump}, #{'%.20g' % v})"
+          end
+        end
+      }
+    }
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_string.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_string.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_string.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -57,6 +57,12 @@
       assert_equal(S("Foo"), S("FooBar")[/([A-Z]..)([A-Z]..)/, -2])
       assert_equal(nil,      S("FooBar")[/([A-Z]..)([A-Z]..)/, -3])
     end
+
+    o = Object.new
+    def o.to_int; 2; end
+    assert_equal("o", "foo"[o])
+
+    assert_raise(ArgumentError) { "foo"[] }
   end
 
   def test_ASET # '[]='
@@ -136,6 +142,14 @@
     s = S("a string")
     s[0..s.size] = S("another string")
     assert_equal(S("another string"), s)
+
+    o = Object.new
+    def o.to_int; 2; end
+    s = "foo"
+    s[o] = "bar"
+    assert_equal("fobar", s)
+
+    assert_raise(ArgumentError) { "foo"[1, 2, 3] = "" }
   end
 
   def test_CMP # '<=>'
@@ -150,6 +164,21 @@
       assert_equal(0, S("ABCDEF") <=> S("abcdef"))
       $= = false
     end
+
+    assert_nil("foo" <=> Object.new)
+
+    o = Object.new
+    def o.to_str; "bar"; end
+    assert_nil("foo" <=> o)
+
+    def o.<=>(x); nil; end
+    assert_nil("foo" <=> o)
+
+    def o.<=>(x); 1; end
+    assert_equal(-1, "foo" <=> o)
+
+    def o.<=>(x); 2**100; end
+    assert_equal(-(2**100), "foo" <=> o)
   end
 
   def test_EQUAL # '=='
@@ -165,6 +194,13 @@
 
     assert(S("CAT") != S('cat'))
     assert(S("CaT") != S('cAt'))
+
+    o = Object.new
+    def o.to_str; end
+    def o.==(x); false; end
+    assert_equal(false, "foo" == o)
+    def o.==(x); true; end
+    assert_equal(true, "foo" == o)
   end
 
   def test_LSHIFT # '<<'
@@ -176,6 +212,11 @@
       s << s
       assert_equal("a" * (2 << i), s)
     }
+
+    s = ["foo"].pack("p")
+    l = s.size
+    s << "bar"
+    assert_equal(l + 3, s.size)
   end
 
   def test_MATCH # '=~'
@@ -187,6 +228,12 @@
       assert_equal(10,  S("FeeFieFoo-Fum") =~ /FUM$/)
       $= = false
     end
+
+    o = Object.new
+    def o.=~(x); x + "bar"; end
+    assert_equal("foobar", S("foo") =~ o)
+
+    assert_raise(TypeError) { S("foo") =~ "foo" }
   end
 
   def test_MOD # '%'
@@ -207,7 +254,7 @@
       171,
       171]
 
-    assert_equal(S(' hi 123 %foo   456 0x0A3.1 1011 ab AB 0b1011 0xab 0XAB'), x)
+    assert_equal(S(' hi 123 %foo   456 0A3.1 1011 ab AB 0b1011 0xab 0XAB'), x)
   end
 
   def test_MUL # '*'
@@ -280,6 +327,7 @@
   def test_chomp
     assert_equal(S("hello"), S("hello").chomp("\n"))
     assert_equal(S("hello"), S("hello\n").chomp("\n"))
+    save = $/
 
     $/ = "\n"
 
@@ -289,7 +337,7 @@
     $/ = "!"
     assert_equal(S("hello"), S("hello").chomp)
     assert_equal(S("hello"), S("hello!").chomp)
-    $/ = "\n"
+    $/ = save
   end
 
   def test_chomp!
@@ -302,6 +350,7 @@
     a = S("hello\n")
     a.chomp!(S("\n"))
     assert_equal(S("hello"), a)
+    save = $/
 
     $/ = "\n"
     a = S("hello")
@@ -321,13 +370,28 @@
     a.chomp!
     assert_equal(S("hello"), a)
 
-    $/ = "\n"
+    $/ = save
 
     a = S("hello\n")
     b = a.dup
     assert_equal(S("hello"), a.chomp!)
     assert_equal(S("hello\n"), b)
    
+    s = "foo\r\n"
+    s.chomp!
+    assert_equal("foo", s)
+
+    s = "foo\r"
+    s.chomp!
+    assert_equal("foo", s)
+
+    s = "foo\r\n"
+    s.chomp!("")
+    assert_equal("foo", s)
+
+    s = "foo\r"
+    s.chomp!("")
+    assert_equal("foo\r", s)
   end
 
   def test_chop
@@ -391,6 +455,8 @@
     assert_equal(4, a.count(S("hello"), S("^l")))
     assert_equal(4, a.count(S("ej-m")))
     assert_equal(0, S("y").count(S("a\\-z")))
+
+    assert_raise(ArgumentError) { "foo".count }
   end
 
   def test_crypt
@@ -430,6 +496,12 @@
     a.delete!(S("lo"))
     assert_equal(S("he"), a)
     assert_equal(S("hello"), b)
+
+    a = S("hello")
+    a.delete!(S("^el"))
+    assert_equal(S("ell"), a)
+
+    assert_raise(ArgumentError) { S("foo").delete! }
   end
 
 
@@ -474,6 +546,7 @@
   end
 
   def test_each
+    save = $/
     $/ = "\n"
     res=[]
     S("hello\nworld").lines.each {|x| res << x}
@@ -490,7 +563,7 @@
     S("hello!world").lines.each {|x| res << x}
     assert_equal(S("hello!"), res[0])
     assert_equal(S("world"),  res[1])
-    $/ = "\n"
+    $/ = save
   end
 
   def test_each_byte
@@ -502,6 +575,7 @@
   end
 
   def test_each_line
+    save = $/
     $/ = "\n"
     res=[]
     S("hello\nworld").lines.each {|x| res << x}
@@ -520,7 +594,11 @@
     assert_equal(S("hello!"), res[0])
     assert_equal(S("world"),  res[1])
     
-    $/ = "\n"
+    $/ = save
+
+    s = nil
+    "foo\nbar".each_line(nil) {|s2| s = s2 }
+    assert_equal("foo\nbar", s)
   end
 
   def test_empty?
@@ -545,6 +623,8 @@
     a = S("hello")
     a.taint
     assert(a.gsub(/./, S('X')).tainted?)
+
+    assert_raise(ArgumentError) { "foo".gsub }
   end
 
   def test_gsub!
@@ -633,6 +713,14 @@
     assert_nil(S("hello").index(?z))
     assert_nil(S("hello").index(S("z")))
     assert_nil(S("hello").index(/z./))
+
+    o = Object.new
+    def o.to_str; "bar"; end
+    assert_equal(3, "foobarbarbaz".index(o))
+    assert_raise(TypeError) { "foo".index(Object.new) }
+
+    assert_nil("foo".index(//, -100))
+    assert_nil($~)
   end
 
   def test_intern
@@ -723,6 +811,15 @@
     b = a.replace(S("xyz"))
     assert_equal(S("xyz"), b)
     assert(b.tainted?)
+
+    s = "foo" * 100
+    s2 = ("bar" * 100).dup
+    s.replace(s2)
+    assert_equal(s2, s)
+
+    s2 = ["foo"].pack("p")
+    s.replace(s2)
+    assert_equal(s2, s)
   end
 
   def test_reverse
@@ -765,6 +862,14 @@
     assert_nil(S("hello").rindex(S("z")))
     assert_nil(S("hello").rindex(/z./))
 
+    o = Object.new
+    def o.to_str; "bar"; end
+    assert_equal(6, "foobarbarbaz".rindex(o))
+    assert_raise(TypeError) { "foo".rindex(Object.new) }
+
+    assert_nil("foo".rindex(//, -100))
+    assert_nil($~)
+
     assert_equal(0, S("hello").rindex(S("hello"), 0))
     assert_equal(0, S("").rindex(S(""), 0))
   end
@@ -934,6 +1039,8 @@
       assert_nil(a.slice!(S("plugh")))
       assert_equal(S("FooBar"), a)
     end
+
+    assert_raise(ArgumentError) { "foo".slice! }
   end
 
   def test_split
@@ -958,7 +1065,7 @@
     assert_equal([S("a"), S(""), S("b"), S("c")], S("a||b|c|").split(S('|')))
     assert_equal([S("a"), S(""), S("b"), S("c"), S("")], S("a||b|c|").split(S('|'), -1))
 
-    assert_equal([], S("").split(//))
+    assert_equal([], "".split(//, 1))
   end
 
   def test_squeeze
@@ -1049,6 +1156,20 @@
     a = S("hello")
     a.taint
     assert(a.sub(/./, S('X')).tainted?)
+
+    o = Object.new
+    def o.to_str; "bar"; end
+    assert_equal("fooBARbaz", "foobarbaz".sub(o, "BAR"))
+
+    assert_raise(TypeError) { "foo".sub(Object.new, "") }
+
+    assert_raise(ArgumentError) { "foo".sub }
+
+    assert_raise(IndexError) { "foo"[/(?:(o$)|(x))/, 2] = 'bar' }
+
+    o = Object.new
+    def o.to_s; self; end
+    assert_match(/^foo#<Object:0x.*>baz$/, "foobarbaz".sub("bar") { o })
   end
 
   def test_sub!
@@ -1214,7 +1335,7 @@
     assert_equal(12, "1_2".to_i(10))
     assert_equal(0x40000000, "1073741824".to_i(10))
     assert_equal(0x4000000000000000, "4611686018427387904".to_i(10))
-    assert_equal(12, "1__2".to_i(10))
+    assert_equal(1, "1__2".to_i(10))
     assert_equal(1, "1_z".to_i(10))
   end
 
@@ -1234,7 +1355,6 @@
     assert_equal(S("hippo"), S("hello").tr(S("el"), S("ip")))
     assert_equal(S("*e**o"), S("hello").tr(S("^aeiou"), S("*")))
     assert_equal(S("hal"),   S("ibm").tr(S("b-z"), S("a-z")))
-    assert_equal(S("-p"),    S("-p").tr(S("^-pv"), "x"))
   end
 
   def test_tr!
@@ -1404,5 +1524,83 @@
       assert_equal(s1, s2)
       s1 << 'a'
     }
+
+    assert_raise(ArgumentError) { "foo" * (-1) }
   end
+
+  def test_respond_to
+    o = Object.new 
+    def o.respond_to?(arg) [:to_str].include?(arg) ? nil : super end
+    def o.to_str() "" end
+    def o.==(other) "" == other end
+    assert_equal(false, "" == o)
+  end
+
+  def test_match_method
+    assert_equal("bar", "foobarbaz".match(/bar/).to_s)
+
+    o = /foo/
+    def o.match(x, y, z); x + y + z; end
+    assert_equal("foobarbaz", "foo".match(o, "bar", "baz"))
+    x = nil
+    "foo".match(o, "bar", "baz") {|y| x = y }
+    assert_equal("foobarbaz", x)
+
+    assert_raise(ArgumentError) { "foo".match }
+  end
+
+  def test_clear
+    s = "foo" * 100
+    s.clear
+    assert_equal("", s)
+  end
+
+  def test_to_s_2
+    c = Class.new(String)
+    s = c.new
+    s.replace("foo")
+    assert_equal("foo", s.to_s)
+    assert_instance_of(String, s.to_s)
+  end
+
+  def test_partition
+    assert_equal(%w(he l lo), "hello".partition(/l/))
+    assert_equal(%w(he l lo), "hello".partition("l"))
+    assert_raise(TypeError) { "hello".partition(1) }
+  end
+
+  def test_rpartition
+    assert_equal(%w(hel l o), "hello".rpartition(/l/))
+    assert_equal(%w(hel l o), "hello".rpartition("l"))
+    assert_raise(TypeError) { "hello".rpartition(1) }
+  end
+
+  def test_setter
+    assert_raise(TypeError) { $/ = 1 }
+  end
+
+  def test_to_id
+    c = Class.new
+    c.class_eval do
+      def initialize
+        @foo = :foo
+      end
+    end
+
+    assert_raise(TypeError) do
+      c.class_eval { attr 1 }
+    end
+
+    o = Object.new
+    def o.to_str; :foo; end
+    assert_raise(TypeError) do
+      c.class_eval { attr 1 }
+    end
+
+    def o.to_str; "foo"; end
+    assert_nothing_raised do
+      c.class_eval { attr o }
+    end
+    assert_equal(:foo, c.new.foo)
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_struct.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_struct.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_struct.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -91,7 +91,6 @@
   end
 
   def test_struct_new
-    Struct.instance_eval { const_set(:Foo, nil) }
     assert_raise(NameError) { Struct.new("foo") }
     assert_nothing_raised { Struct.new("Foo") }
     Struct.instance_eval { remove_const(:Foo) }

Modified: MacRuby/trunk/test/ruby/test_symbol.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_symbol.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_symbol.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -77,5 +77,59 @@
 
   def test_to_proc
     assert_equal %w(1 2 3), (1..3).map(&:to_s)
+    [
+      [],
+      [1],
+      [1, 2],
+      [1, [2, 3]],
+    ].each do |ary|
+      ary_id = ary.object_id
+      assert_equal ary_id, :object_id.to_proc.call(ary)
+      ary_ids = ary.collect{|x| x.object_id }
+      assert_equal ary_ids, ary.collect(&:object_id)
+    end
   end
+
+  def test_call
+    o = Object.new
+    def o.foo(x, y); x + y; end
+
+    assert_equal(3, :foo.to_proc.call(o, 1, 2))
+    assert_raise(ArgumentError) { :foo.to_proc.call }
+  end
+
+  def test_succ
+    assert_equal(:fop, :foo.succ)
+  end
+
+  def test_cmp
+    assert_equal(0, :FoO <=> :FoO)
+    assert_equal(-1, :FoO <=> :fOO)
+    assert_equal(1, :fOO <=> :FoO)
+    assert_nil(:foo <=> "foo")
+  end
+
+  def test_casecmp
+    assert_equal(0, :FoO.casecmp(:fOO))
+    assert_equal(1, :FoO.casecmp(:BaR))
+    assert_equal(-1, :baR.casecmp(:FoO))
+    assert_nil(:foo.casecmp("foo"))
+  end
+
+  def test_length
+    assert_equal(3, :FoO.length)
+    assert_equal(3, :FoO.size)
+  end
+
+  def test_empty
+    assert_equal(false, :FoO.empty?)
+    assert_equal(true, :"".empty?)
+  end
+
+  def test_case
+    assert_equal(:FOO, :FoO.upcase)
+    assert_equal(:foo, :FoO.downcase)
+    assert_equal(:Foo, :foo.capitalize)
+    assert_equal(:fOo, :FoO.swapcase)
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_system.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_system.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_system.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,5 @@
 require 'test/unit'
 require 'tmpdir'
-require 'require_relative'
 require_relative 'envutil'
 
 class TestSystem < Test::Unit::TestCase

Modified: MacRuby/trunk/test/ruby/test_thread.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_thread.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_thread.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,36 @@
 require 'test/unit'
+require 'thread'
+require_relative 'envutil'
 
 class TestThread < Test::Unit::TestCase
+  def ruby(*r, &b)
+    EnvUtil.rubyexec(*r, &b)
+  end
+
+  class Thread < ::Thread
+    Threads = []
+    def self.new(*)
+      th = super
+      th.abort_on_exception = true
+      Threads << th
+      th
+    end
+  end
+
+  def setup
+    Thread::Threads.clear
+  end
+
+  def teardown
+    Thread::Threads.each do |t|
+      t.kill if t.alive?
+      begin
+        t.join
+      rescue Exception
+      end
+    end
+  end
+
   def test_mutex_synchronize
     m = Mutex.new
     r = 0
@@ -20,6 +50,403 @@
     }
     assert_equal(max * max * max, r)
   end
+
+  def test_condvar
+    mutex = Mutex.new
+    condvar = ConditionVariable.new
+    result = []
+    mutex.synchronize do
+      t = Thread.new do
+        mutex.synchronize do
+          result << 1
+          condvar.signal
+        end
+      end
+
+      result << 0
+      condvar.wait(mutex)
+      result << 2
+      t.join
+    end
+    assert_equal([0, 1, 2], result)
+  end
+
+  def test_condvar_wait_not_owner
+    mutex = Mutex.new
+    condvar = ConditionVariable.new
+
+    assert_raises(ThreadError) { condvar.wait(mutex) }
+  end
+
+  def test_condvar_wait_exception_handling
+    # Calling wait in the only thread running should raise a ThreadError of
+    # 'stopping only thread'
+    mutex = Mutex.new
+    condvar = ConditionVariable.new
+
+    locked = false
+    thread = Thread.new do
+      Thread.current.abort_on_exception = false
+      mutex.synchronize do
+        begin
+          condvar.wait(mutex)
+        rescue Exception
+          locked = mutex.locked?
+          raise
+        end
+      end
+    end
+
+    until thread.stop?
+      sleep(0.1)
+    end
+
+    thread.raise Interrupt, "interrupt a dead condition variable"
+    assert_raises(Interrupt) { thread.value }
+    assert(locked)
+  end
+
+  def test_local_barrier
+    dir = File.dirname(__FILE__)
+    lbtest = File.join(dir, "lbtest.rb")
+    $:.unshift File.join(File.dirname(dir), 'ruby')
+    require 'envutil'
+    $:.shift
+    10.times {
+      result = `#{EnvUtil.rubybin} #{lbtest}`
+      assert(!$?.coredump?, '[ruby-dev:30653]')
+      assert_equal("exit.", result[/.*\Z/], '[ruby-dev:30653]')
+    }
+  end
+
+  def test_priority
+    c1 = c2 = 0
+    t1 = Thread.new { loop { c1 += 1 } }
+    t1.priority = -1
+    t2 = Thread.new { loop { c2 += 1 } }
+    t2.priority = -3
+    assert_equal(-1, t1.priority)
+    assert_equal(-3, t2.priority)
+    sleep 0.5
+    t1.kill
+    t2.kill
+    assert(c1 > c2 * 2, "[ruby-dev:33124]")
+  end
+
+  def test_new
+    assert_raise(ThreadError) do
+      Thread.new
+    end
+
+    t1 = Thread.new { sleep }
+    assert_raise(ThreadError) do
+      t1.instance_eval { initialize { } }
+    end
+
+    t2 = Thread.new(&method(:sleep).to_proc)
+    assert_raise(ThreadError) do
+      t2.instance_eval { initialize { } }
+    end
+
+  ensure
+    t1.kill if t1
+    t2.kill if t2
+  end
+
+  def test_join
+    t = Thread.new { sleep }
+    assert_nil(t.join(0.5))
+
+  ensure
+    t.kill if t
+  end
+
+  def test_join2
+    t1 = Thread.new { sleep(1.5) }
+    t2 = Thread.new do
+      t1.join(1)
+    end
+    t3 = Thread.new do
+      sleep 0.5
+      t1.join
+    end
+    assert_nil(t2.value)
+    assert_equal(t1, t3.value)
+
+  ensure
+    t1.kill if t1
+    t2.kill if t2
+    t3.kill if t3
+  end
+
+  def test_kill_main_thread
+    ruby do |w, r, e|
+      w.puts "p 1"
+      w.puts "Thread.kill Thread.current"
+      w.puts "p 2"
+      w.close
+      assert_equal("1", r.read.chomp)
+    end
+  end
+
+  def test_exit
+    s = 0
+    Thread.new do
+      s += 1
+      Thread.exit
+      s += 2
+    end.join
+    assert_equal(1, s)
+  end
+
+  def test_wakeup
+    s = 0
+    t = Thread.new do
+      s += 1
+      Thread.stop
+      s += 1
+    end
+    sleep 0.5
+    assert_equal(1, s)
+    t.wakeup
+    sleep 0.5
+    assert_equal(2, s)
+    assert_raise(ThreadError) { t.wakeup }
+
+  ensure
+    t.kill if t
+  end
+
+  def test_stop
+    ruby do |w, r, e|
+      w.puts "begin"
+      w.puts "  Thread.stop"
+      w.puts "  p 1"
+      w.puts "rescue ThreadError"
+      w.puts "  p 2"
+      w.puts "end"
+      w.close
+      assert_equal("2", r.read.chomp)
+    end
+  end
+
+  def test_list
+    ruby do |w, r, e|
+      w.puts "t1 = Thread.new { sleep }"
+      w.puts "t2 = Thread.new { loop { } }"
+      w.puts "t3 = Thread.new { }.join"
+      w.puts "p [Thread.current, t1, t2].sort_by {|t| t.object_id }"
+      w.puts "p Thread.list.sort_by {|t| t.object_id }"
+      w.close
+      assert_equal(r.gets, r.gets)
+    end
+  end
+
+  def test_main
+    ruby do |w, r, e|
+      w.puts "p Thread.main == Thread.current"
+      w.puts "Thread.new { p Thread.main == Thread.current }.join"
+      w.close
+      assert_equal("true", r.gets.chomp)
+      assert_equal("false", r.gets.chomp)
+    end
+  end
+
+  def test_abort_on_exception
+    ruby do |w, r, e|
+      w.puts "p Thread.abort_on_exception"
+      w.puts "begin"
+      w.puts "  Thread.new { raise }"
+      w.puts "  sleep 0.5"
+      w.puts "  p 1"
+      w.puts "rescue"
+      w.puts "  p 2"
+      w.puts "end"
+      w.close_write
+      assert_equal("false", r.gets.chomp)
+      assert_equal("1", r.gets.chomp)
+      assert_equal("", e.read)
+    end
+
+    ruby do |w, r, e|
+      w.puts "Thread.abort_on_exception = true"
+      w.puts "p Thread.abort_on_exception"
+      w.puts "begin"
+      w.puts "  Thread.new { raise }"
+      w.puts "  sleep 0.5"
+      w.puts "  p 1"
+      w.puts "rescue"
+      w.puts "  p 2"
+      w.puts "end"
+      w.close_write
+      assert_equal("true", r.gets.chomp)
+      assert_equal("2", r.gets.chomp)
+      assert_equal("", e.read)
+    end
+
+    ruby('-d') do |w, r, e|
+      w.puts "p Thread.abort_on_exception"
+      w.puts "begin"
+      w.puts "  Thread.new { raise }"
+      w.puts "  sleep 0.5"
+      w.puts "  p 1"
+      w.puts "rescue"
+      w.puts "  p 2"
+      w.puts "end"
+      w.close_write
+      assert_equal("false", r.gets.chomp)
+      assert_equal("2", r.gets.chomp)
+      assert_not_equal("", e.read)
+    end
+
+    ruby do |w, r, e|
+      w.puts "p Thread.abort_on_exception"
+      w.puts "begin"
+      w.puts "  t = Thread.new { sleep 0.5; raise }"
+      w.puts "  t.abort_on_exception = true"
+      w.puts "  p t.abort_on_exception"
+      w.puts "  sleep 1"
+      w.puts "  p 1"
+      w.puts "rescue"
+      w.puts "  p 2"
+      w.puts "end"
+      w.close_write
+      assert_equal("false", r.gets.chomp)
+      assert_equal("true", r.gets.chomp)
+      assert_equal("2", r.gets.chomp)
+      assert_equal("", e.read)
+    end
+  end
+
+  def test_status_and_stop_p
+    a = ::Thread.new { raise("die now") }
+    b = Thread.new { Thread.stop }
+    c = Thread.new { Thread.exit }
+    d = Thread.new { sleep }
+    e = Thread.current
+    sleep 0.5
+    d.kill
+
+    assert_equal(nil, a.status)
+    assert_equal("sleep", b.status)
+    assert_equal(false, c.status)
+    assert_match(/^#<TestThread::Thread:.* dead>$/, c.inspect)
+    assert_equal("aborting", d.status)
+    assert_equal("run", e.status)
+
+    assert(a.stop?)
+    assert(b.stop?)
+    assert(c.stop?)
+    assert(!d.stop?)
+    assert(!e.stop?)
+
+  ensure
+    a.kill if a
+    b.kill if b
+    c.kill if c
+    d.kill if d
+  end
+
+  def test_safe_level
+    t = Thread.new { $SAFE = 3; sleep }
+    sleep 0.5
+    assert_equal(0, Thread.current.safe_level)
+    assert_equal(3, t.safe_level)
+
+  ensure
+    t.kill if t
+  end
+
+  def test_thread_local
+    t = Thread.new { sleep }
+
+    assert_equal(false, t.key?(:foo))
+
+    t["foo"] = "foo"
+    t["bar"] = "bar"
+    t["baz"] = "baz"
+
+    assert_equal(true, t.key?(:foo))
+    assert_equal(true, t.key?("foo"))
+    assert_equal(false, t.key?(:qux))
+    assert_equal(false, t.key?("qux"))
+
+    assert_equal([:foo, :bar, :baz], t.keys)
+
+  ensure
+    t.kill if t
+  end
+
+  def test_thread_local_security
+    t = Thread.new { sleep }
+
+    assert_raise(SecurityError) do
+      Thread.new { $SAFE = 4; t[:foo] }.join
+    end
+
+    assert_raise(SecurityError) do
+      Thread.new { $SAFE = 4; t[:foo] = :baz }.join
+    end
+
+    assert_raise(RuntimeError) do
+      Thread.new do
+        Thread.current[:foo] = :bar
+        Thread.current.freeze
+        Thread.current[:foo] = :baz
+      end.join
+    end
+  end
+
+  def test_select_wait
+    assert_nil(IO.select(nil, nil, nil, 1))
+    t = Thread.new do
+      IO.select(nil, nil, nil, nil)
+    end
+    sleep 0.5
+    t.kill
+  end
+
+  def test_mutex_deadlock
+    m = Mutex.new
+    m.synchronize do
+      assert_raise(ThreadError) do
+        m.synchronize do
+          assert(false)
+        end
+      end
+    end
+  end
+
+  def test_mutex_interrupt
+    m = Mutex.new
+    m.lock
+    t = Thread.new do
+      m.lock
+      :foo
+    end
+    sleep 0.5
+    t.kill
+    assert_nil(t.value)
+  end
+
+  def test_mutex_illegal_unlock
+    m = Mutex.new
+    m.lock
+    assert_raise(ThreadError) do
+      Thread.new do
+        m.unlock
+      end.join
+    end
+  end
+
+  def test_recursive_error
+    o = Object.new
+    def o.inspect
+      Thread.current[:__recursive_key__][:inspect] = nil
+      super
+    end
+    assert_raise(TypeError) { [o].inspect }
+  end
 end
 
 class TestThreadGroup < Test::Unit::TestCase
@@ -33,25 +460,43 @@
 
   def test_frozen_thgroup
     thgrp = ThreadGroup.new
+
+    t = Thread.new{1}
     Thread.new{
       thgrp.add(Thread.current)
       thgrp.freeze
       assert_raise(ThreadError) do
         Thread.new{1}.join
       end
+      assert_raise(ThreadError) do
+        thgrp.add(t)
+      end
+      assert_raise(ThreadError) do
+        ThreadGroup.new.add Thread.current
+      end
     }.join
+    t.join
   end
 
   def test_enclosed_thgroup
     thgrp = ThreadGroup.new
-    thgrp.enclose
+    assert_equal(false, thgrp.enclosed?)
+
+    t = Thread.new{1}
     Thread.new{
-      assert_raise(ThreadError) do
-        thgrp.add(Thread.current)
-      end
+      thgrp.add(Thread.current)
+      thgrp.enclose
+      assert_equal(true, thgrp.enclosed?)
       assert_nothing_raised do
         Thread.new{1}.join
       end
+      assert_raise(ThreadError) do
+        thgrp.add t
+      end
+      assert_raise(ThreadError) do
+        ThreadGroup.new.add Thread.current
+      end
     }.join
+    t.join
   end
 end

Modified: MacRuby/trunk/test/ruby/test_time.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_time.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_time.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -64,6 +64,12 @@
     end
   end
 
+  def test_strtime
+    t = nil
+    assert_nothing_raised { t = Time.utc("2000", "1", "2" , "3", "4", "5") }
+    assert_equal(Time.utc(2000,1,2,3,4,5), t)
+  end
+
   def test_huge_difference
     if negative_time_t?
       assert_equal(Time.at(-0x80000000), Time.at(0x7fffffff) - 0xffffffff, "[ruby-dev:22619]")
@@ -327,6 +333,7 @@
   end
 
   def test_strftime
+    t = Time.at(946684800).getlocal
     assert_equal("Sat", T2000.strftime("%a"))
     assert_equal("Saturday", T2000.strftime("%A"))
     assert_equal("Jan", T2000.strftime("%b"))
@@ -347,7 +354,7 @@
     assert_equal("00:00:00", T2000.strftime("%X"))
     assert_equal("00", T2000.strftime("%y"))
     assert_equal("2000", T2000.strftime("%Y"))
-    assert_equal("GMT", T2000.strftime("%Z"))
+    assert(["GMT", "UTC"].include?(T2000.strftime("%Z")))
     assert_equal("%", T2000.strftime("%%"))
 
     assert_equal("", T2000.strftime(""))

Modified: MacRuby/trunk/test/ruby/test_trace.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_trace.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_trace.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -18,4 +18,32 @@
     
     untrace_var :$x
   end
+
+  def test_trace_tainted_proc
+    $x = 1234
+    s = proc { $y = :foo }
+    trace_var :$x, s
+    s.taint
+    $x = 42
+    assert_equal(:foo, $y)
+  ensure
+    untrace_var :$x
+  end
+
+  def test_trace_proc_that_raises_exception
+    $x = 1234
+    trace_var :$x, proc { raise }
+    assert_raise(RuntimeError) { $x = 42 }
+  ensure
+    untrace_var :$x
+  end
+
+  def test_trace_string
+    $x = 1234
+    trace_var :$x, "$y = :bar"
+    $x = 42
+    assert_equal(:bar, $y)
+  ensure
+    untrace_var :$x
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_transcode.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_transcode.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_transcode.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,7 +3,7 @@
 
 require 'test/unit'
 class TestTranscode < Test::Unit::TestCase
-  def setup # trick to create all the necessary encodings
+  def setup_really_needed? # trick to create all the necessary encodings
     all_encodings = [ 'ISO-8859-1', 'ISO-8859-2',
                       'ISO-8859-3', 'ISO-8859-4',
                       'ISO-8859-5', 'ISO-8859-6',
@@ -19,8 +19,6 @@
   end
 
   def test_errors
-    # we don't have semantics for conversion without attribute yet
-    # maybe 'convert to UTF-8' would be nice :-)
     assert_raise(ArgumentError) { 'abc'.encode }
     assert_raise(ArgumentError) { 'abc'.encode! }
     assert_raise(ArgumentError) { 'abc'.encode('foo', 'bar') }
@@ -241,4 +239,18 @@
     check_utf_32_both_ways("\u{8FF00}", "\x00\x08\xFF\x00")
     check_utf_32_both_ways("\u{F00FF}", "\x00\x0F\x00\xFF")
   end
+  
+  def test_invalid_ignore
+    # arguments only
+    assert_nothing_raised { 'abc'.encode('utf-8', invalid: :ignore) }
+    # check handling of UTF-8 ill-formed subsequences
+    assert_equal("\x00\x41\x00\x3E\x00\x42".force_encoding('UTF-16BE'),
+      "\x41\xC2\x3E\x42".encode('UTF-16BE', 'UTF-8', invalid: :ignore))
+    assert_equal("\x00\x41\x00\xF1\x00\x42".force_encoding('UTF-16BE'),
+      "\x41\xC2\xC3\xB1\x42".encode('UTF-16BE', 'UTF-8', invalid: :ignore))
+    assert_equal("\x00\x42".force_encoding('UTF-16BE'),
+      "\xF0\x80\x80\x42".encode('UTF-16BE', 'UTF-8', invalid: :ignore))
+    assert_equal(''.force_encoding('UTF-16BE'),
+      "\x82\xAB".encode('UTF-16BE', 'UTF-8', invalid: :ignore))
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_utf16.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_utf16.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_utf16.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -113,6 +113,11 @@
     assert_equal(s.encoding, s.intern.to_s.encoding, "#{encdump s}.intern.to_s.encoding")
   end
 
+  def test_sym_eq
+    s = "aa".force_encoding("utf-16le")
+    assert(s.intern != :aa, "#{encdump s}.intern != :aa")
+  end
+
   def test_compatible
     s1 = "aa".force_encoding("utf-16be")
     s2 = "z".force_encoding("us-ascii")
@@ -132,13 +137,21 @@
   end
 
   def test_hex
-    s1 = "f\0f\0".force_encoding("utf-16le")
-    assert_equal(255, s1.hex, "#{encdump s1}.hex")
+    assert_raise(ArgumentError) {
+      "ff".encode("utf-16le").hex
+    }
+    assert_raise(ArgumentError) {
+      "ff".encode("utf-16be").hex
+    }
   end
 
   def test_oct
-    assert_equal(077, "77".encode("utf-16le").oct)
-    assert_equal(077, "77".encode("utf-16be").oct)
+    assert_raise(ArgumentError) {
+      "77".encode("utf-16le").oct
+    }
+    assert_raise(ArgumentError) {
+      "77".encode("utf-16be").oct
+    }
   end
 
   def test_count
@@ -224,7 +237,11 @@
 
   def test_chomp
     s = "\1\n".force_encoding("utf-16be")
-    assert_str_equal(s, s.chomp, "#{encdump s}.chomp")
+    assert_equal(s, s.chomp, "#{encdump s}.chomp")
+    s = "\0\n".force_encoding("utf-16be")
+    assert_equal("", s.chomp, "#{encdump s}.chomp")
+    s = "\0\r\0\n".force_encoding("utf-16be")
+    assert_equal("", s.chomp, "#{encdump s}.chomp")
   end
 
   def test_succ
@@ -245,8 +262,16 @@
                 "Regexp.new(#{encdump s}).encoding")
   end
 
+  def test_regexp_match
+    assert_raise(ArgumentError) { Regexp.new("aa".force_encoding("utf-16be")) =~ "aa" }
+  end
+
   def test_gsub
     s = "abcd".force_encoding("utf-16be")
+    assert_nothing_raised {
+      s.gsub(Regexp.new(".".encode("utf-16be")), "xy")
+    }
+    s = "ab\0\ncd".force_encoding("utf-16be")
     assert_raise(ArgumentError) {
       s.gsub(Regexp.new(".".encode("utf-16be")), "xy")
     }
@@ -260,7 +285,7 @@
     assert_str_equal("cd".encode("utf-16be"), r[1])
   end
 
-  def test_count
+  def test_count2
     e = "abc".count("^b")
     assert_equal(e, "abc".encode("utf-16be").count("^b".encode("utf-16be")))
     assert_equal(e, "abc".encode("utf-16le").count("^b".encode("utf-16le")))

Added: MacRuby/trunk/test/ruby/test_utf32.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_utf32.rb	                        (rev 0)
+++ MacRuby/trunk/test/ruby/test_utf32.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,27 @@
+require 'test/unit'
+
+class TestUTF32 < Test::Unit::TestCase
+  def encdump(str)
+    d = str.dump
+    if /\.force_encoding\("[A-Za-z0-9.:_+-]*"\)\z/ =~ d
+      d
+    else
+      "#{d}.force_encoding(#{str.encoding.name.dump})"
+    end
+  end
+
+  def assert_str_equal(expected, actual, message=nil)
+    full_message = build_message(message, <<EOT)
+#{encdump expected} expected but not equal to
+#{encdump actual}.
+EOT
+    assert_block(full_message) { expected == actual }
+  end
+
+  def test_substr
+    assert_str_equal(
+      "abcdefgh".force_encoding("utf-32be"),
+      "abcdefgh".force_encoding("utf-32be")[0,3])
+  end
+end
+

Modified: MacRuby/trunk/test/ruby/test_variable.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_variable.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_variable.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -54,4 +54,25 @@
     assert_equal("Zeus", atlas.ruler3)
     assert_equal("Cronus", atlas.ruler4)
   end
+
+  def test_local_variables
+    lvar = 1
+    assert_instance_of(Symbol, local_variables[0], "[ruby-dev:34008]")
+  end
+
+  def test_local_variables2
+    x = 1
+    proc do |y|
+      assert_equal([:x, :y], local_variables.sort)
+    end.call
+  end
+
+  def test_local_variables3
+    x = 1
+    proc do |y|
+      1.times do |z|
+        assert_equal([:x, :y, :z], local_variables.sort)
+      end
+    end.call
+  end
 end

Modified: MacRuby/trunk/test/ruby/test_yield.rb
===================================================================
--- MacRuby/trunk/test/ruby/test_yield.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/ruby/test_yield.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -74,7 +74,6 @@
   end
 end
 
-require 'require_relative'
 require_relative 'sentence'
 class TestRubyYieldGen < Test::Unit::TestCase
   Syntax = {

Added: MacRuby/trunk/test/rubygems/gem_installer_test_case.rb
===================================================================
--- MacRuby/trunk/test/rubygems/gem_installer_test_case.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/gem_installer_test_case.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,86 @@
+require 'test/unit'
+require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
+require 'rubygems/installer'
+
+class Gem::Installer
+  attr_accessor :gem_dir
+
+  attr_writer :format
+  attr_writer :gem_home
+  attr_writer :env_shebang
+  attr_writer :ignore_dependencies
+  attr_writer :format_executable
+  attr_writer :security_policy
+  attr_writer :spec
+  attr_writer :wrappers
+end
+
+class GemInstallerTestCase < RubyGemTestCase
+
+  def setup
+    super
+
+    @spec = quick_gem "a"
+    @gem = File.join @tempdir, "#{@spec.full_name}.gem"
+
+    util_build_gem @spec
+    FileUtils.mv File.join(@gemhome, 'cache', "#{@spec.full_name}.gem"),
+                 @tempdir
+
+    @installer = Gem::Installer.new @gem
+    @installer.gem_dir = util_gem_dir
+    @installer.gem_home = @gemhome
+    @installer.spec = @spec
+  end
+
+  def util_gem_bindir(version = '2')
+    File.join util_gem_dir(version), "bin"
+  end
+
+  def util_gem_dir(version = '2')
+    File.join @gemhome, "gems", "a-#{version}" # HACK
+  end
+
+  def util_inst_bindir
+    File.join @gemhome, "bin"
+  end
+
+  def util_make_exec(version = '2', shebang = "#!/usr/bin/ruby")
+    @spec.executables = ["my_exec"]
+
+    FileUtils.mkdir_p util_gem_bindir(version)
+    exec_file = @installer.formatted_program_filename "my_exec"
+    exec_path = File.join util_gem_bindir(version), exec_file
+    File.open exec_path, 'w' do |f|
+      f.puts shebang
+    end
+  end
+
+  def util_setup_gem(ui = @ui) # HACK fix use_ui to make this automatic
+    @spec.files = File.join('lib', 'code.rb')
+    @spec.executables << 'executable'
+    @spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb')
+
+    Dir.chdir @tempdir do
+      FileUtils.mkdir_p 'bin'
+      FileUtils.mkdir_p 'lib'
+      FileUtils.mkdir_p File.join('ext', 'a')
+      File.open File.join('bin', 'executable'), 'w' do |f| f.puts '1' end
+      File.open File.join('lib', 'code.rb'), 'w' do |f| f.puts '1' end
+      File.open File.join('ext', 'a', 'mkrf_conf.rb'), 'w' do |f|
+        f << <<-EOF
+          File.open 'Rakefile', 'w' do |rf| rf.puts "task :default" end
+        EOF
+      end
+
+      use_ui ui do
+        FileUtils.rm @gem
+        Gem::Builder.new(@spec).build
+      end
+    end
+
+    @installer = Gem::Installer.new @gem
+  end
+
+end
+

Added: MacRuby/trunk/test/rubygems/gem_package_tar_test_case.rb
===================================================================
--- MacRuby/trunk/test/rubygems/gem_package_tar_test_case.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/gem_package_tar_test_case.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,146 @@
+require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
+require 'rubygems/package'
+
+class File
+
+  # straight from setup.rb
+  def self.dir?(path)
+    # for corrupted windows stat()
+    File.directory?((path[-1,1] == '/') ? path : path + '/')
+  end
+
+  def self.read_b(name)
+    File.open(name, "rb") { |f| f.read }
+  end
+
+end
+
+class TarTestCase < RubyGemTestCase
+
+  def ASCIIZ(str, length)
+    str + "\0" * (length - str.length)
+  end
+
+  def SP(s)
+    s + " "
+  end
+
+  def SP_Z(s)
+    s + " \0"
+  end
+
+  def Z(s)
+    s + "\0"
+  end
+
+  def assert_headers_equal(expected, actual)
+    expected = expected.to_s unless String === expected
+    actual = actual.to_s unless String === actual
+
+    fields = %w[
+      name 100
+      mode 8
+      uid 8
+      gid 8
+      size 12
+      mtime 12
+      checksum 8
+      typeflag 1
+      linkname 100
+      magic 6
+      version 2
+      uname 32 
+      gname 32
+      devmajor 8
+      devminor 8
+      prefix 155
+    ]
+
+    offset = 0
+
+    until fields.empty? do
+      name = fields.shift
+      length = fields.shift.to_i
+
+      if name == "checksum" then
+        chksum_off = offset
+        offset += length
+        next
+      end
+
+      assert_equal expected[offset, length], actual[offset, length], 
+                   "Field #{name} of the tar header differs."
+
+      offset += length
+    end
+
+    assert_equal expected[chksum_off, 8], actual[chksum_off, 8]
+  end
+
+  def calc_checksum(header)
+    sum = header.unpack("C*").inject{|s,a| s + a}
+    SP(Z(to_oct(sum, 6)))
+  end
+
+  def header(type, fname, dname, length, mode, checksum = nil)
+    checksum ||= " " * 8
+
+    arr = [                  # struct tarfile_entry_posix
+      ASCIIZ(fname, 100),    # char name[100];     ASCII + (Z unless filled)
+      Z(to_oct(mode, 7)),    # char mode[8];       0 padded, octal null
+      Z(to_oct(0, 7)),       # char uid[8];        ditto
+      Z(to_oct(0, 7)),       # char gid[8];        ditto
+      Z(to_oct(length, 11)), # char size[12];      0 padded, octal, null
+      Z(to_oct(0, 11)),      # char mtime[12];     0 padded, octal, null
+      checksum,              # char checksum[8];   0 padded, octal, null, space
+      type,                  # char typeflag[1];   file: "0"  dir: "5"
+      "\0" * 100,            # char linkname[100]; ASCII + (Z unless filled)
+      "ustar\0",             # char magic[6];      "ustar\0"
+      "00",                  # char version[2];    "00"
+      ASCIIZ("wheel", 32),   # char uname[32];     ASCIIZ
+      ASCIIZ("wheel", 32),   # char gname[32];     ASCIIZ
+      Z(to_oct(0, 7)),       # char devmajor[8];   0 padded, octal, null
+      Z(to_oct(0, 7)),       # char devminor[8];   0 padded, octal, null
+      ASCIIZ(dname, 155)     # char prefix[155];   ASCII + (Z unless filled)
+    ]
+
+    format = "C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155"
+    h = if RUBY_VERSION >= "1.9" then
+          arr.join
+        else
+          arr = arr.join("").split(//).map{|x| x[0]}
+          arr.pack format
+        end
+    ret = h + "\0" * (512 - h.size)
+    assert_equal(512, ret.size)
+    ret
+  end
+
+  def tar_dir_header(name, prefix, mode)
+    h = header("5", name, prefix, 0, mode)
+    checksum = calc_checksum(h)
+    header("5", name, prefix, 0, mode, checksum)
+  end
+
+  def tar_file_header(fname, dname, mode, length)
+    h = header("0", fname, dname, length, mode)
+    checksum = calc_checksum(h)
+    header("0", fname, dname, length, mode, checksum)
+  end
+
+  def to_oct(n, pad_size)
+    "%0#{pad_size}o" % n
+  end
+
+  def util_entry(tar)
+    io = TempIO.new tar
+    header = Gem::Package::TarHeader.from io
+    entry = Gem::Package::TarReader::Entry.new header, io
+  end
+
+  def util_dir_entry
+    util_entry tar_dir_header("foo", "bar", 0)
+  end
+
+end
+

Modified: MacRuby/trunk/test/rubygems/gemutilities.rb
===================================================================
--- MacRuby/trunk/test/rubygems/gemutilities.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/gemutilities.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -10,9 +10,10 @@
 require 'fileutils'
 require 'test/unit'
 require 'tmpdir'
+require 'tempfile'
 require 'uri'
-require 'rubygems/gem_open_uri'
 require 'rubygems/source_info_cache'
+require 'rubygems/package'
 
 require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui')
 
@@ -56,6 +57,22 @@
     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
 
 class RubyGemTestCase < Test::Unit::TestCase
@@ -76,6 +93,7 @@
     @gemhome = File.join @tempdir, "gemhome"
     @gemcache = File.join(@gemhome, "source_cache")
     @usrcache = File.join(@gemhome, ".gem", "user_cache")
+    @latest_usrcache = File.join(@gemhome, ".gem", "latest_user_cache")
 
     FileUtils.mkdir_p @gemhome
 
@@ -101,6 +119,11 @@
     end
 
     @marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
+
+    @private_key = File.expand_path File.join(File.dirname(__FILE__),
+                                              'private_key.pem')
+    @public_cert = File.expand_path File.join(File.dirname(__FILE__),
+                                              'public_cert.pem')
   end
 
   def teardown
@@ -135,25 +158,52 @@
   end
 
   def prep_cache_files(lc)
-    [ [lc.system_cache_file, 'sys'],
-      [lc.user_cache_file, 'usr'],
-    ].each do |fn, data|
-      FileUtils.mkdir_p File.dirname(fn).untaint
-      open(fn.dup.untaint, "wb") { |f| f.write(Marshal.dump({'key' => data})) }
+    @usr_si ||= Gem::SourceIndex.new
+    @usr_sice ||= Gem::SourceInfoCacheEntry.new @usr_si, 0
+
+    @sys_si ||= Gem::SourceIndex.new
+    @sys_sice ||= Gem::SourceInfoCacheEntry.new @sys_si, 0
+
+    latest_si = Gem::SourceIndex.new
+    latest_si.add_specs(*@sys_si.latest_specs)
+    latest_sys_sice = Gem::SourceInfoCacheEntry.new latest_si, 0
+
+    latest_si = Gem::SourceIndex.new
+    latest_si.add_specs(*@usr_si.latest_specs)
+    latest_usr_sice = Gem::SourceInfoCacheEntry.new latest_si, 0
+
+    [ [lc.system_cache_file, @sys_sice],
+      [lc.latest_system_cache_file, latest_sys_sice],
+      [lc.user_cache_file, @usr_sice],
+      [lc.latest_user_cache_file, latest_usr_sice],
+    ].each do |filename, data|
+      FileUtils.mkdir_p File.dirname(filename).untaint
+
+      open filename.dup.untaint, 'wb' do |f|
+        f.write Marshal.dump({ @gem_repo => data })
+      end
     end
   end
 
-  def read_cache(fn)
-    open(fn.dup.untaint) { |f| Marshal.load f.read }
+  def read_cache(path)
+    open path.dup.untaint, 'rb' do |io|
+      Marshal.load io.read
+    end
   end
 
+  def read_binary(path)
+    Gem.read_binary path
+  end
+
   def write_file(path)
     path = File.join(@gemhome, path)
     dir = File.dirname path
     FileUtils.mkdir_p dir
-    File.open(path, "w") { |io|
-      yield(io)
-    }
+
+    open path, 'wb' do |io|
+      yield io
+    end
+
     path
   end
 
@@ -204,6 +254,23 @@
     end
   end
 
+  def util_gem(name, version, &block)
+    spec = quick_gem(name, version, &block)
+
+    util_build_gem spec
+
+    cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem"
+    FileUtils.mv File.join(@gemhome, 'cache', "#{spec.original_name}.gem"),
+                 cache_file
+    FileUtils.rm File.join(@gemhome, 'specifications',
+                           "#{spec.full_name}.gemspec")
+
+    spec.loaded_from = nil
+    spec.loaded = false
+
+    [spec, cache_file]
+  end
+
   def util_make_gems
     init = proc do |s|
       s.files = %w[lib/code.rb]
@@ -212,6 +279,7 @@
 
     @a1 = quick_gem('a', '1', &init)
     @a2 = quick_gem('a', '2', &init)
+    @a_evil9 = quick_gem('a_evil', '9', &init)
     @b2 = quick_gem('b', '2', &init)
     @c1_2   = quick_gem('c', '1.2',   &init)
     @pl1     = quick_gem 'pl', '1' do |s| # l for legacy
@@ -227,7 +295,7 @@
     write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb]) do end
     write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb]) do end
 
-    [@a1, @a2, @b2, @c1_2, @pl1].each { |spec| util_build_gem spec }
+    [@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].each { |spec| util_build_gem spec }
 
     FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name)
 
@@ -256,32 +324,19 @@
     @fetcher = FakeFetcher.new
     @fetcher.uri = @uri
 
-    @gem1 = quick_gem 'gem_one' do |gem|
-      gem.files = %w[Rakefile lib/gem_one.rb]
-    end
+    util_make_gems
 
-    @gem2 = quick_gem 'gem_two' do |gem|
-      gem.files = %w[Rakefile lib/gem_two.rb]
-    end
-
-    @gem3 = quick_gem 'gem_three' do |gem| # missing gem
-      gem.files = %w[Rakefile lib/gem_three.rb]
-    end
-
-    # this gem has a higher version and longer name than the gem we want
-    @gem4 = quick_gem 'gem_one_evil', '666' do |gem|
-      gem.files = %w[Rakefile lib/gem_one.rb]
-    end
-
-    @all_gems = [@gem1, @gem2, @gem3, @gem4].sort
+    @all_gems = [@a1, @a2, @a_evil9, @b2, @c1_2].sort
     @all_gem_names = @all_gems.map { |gem| gem.full_name }
 
-    gem_names = [@gem1.full_name, @gem2.full_name, @gem4.full_name]
+    gem_names = [@a1.full_name, @a2.full_name, @b2.full_name]
     @gem_names = gem_names.sort.join("\n")
 
-    @source_index = Gem::SourceIndex.new @gem1.full_name => @gem1,
-                                         @gem2.full_name => @gem2,
-                                         @gem4.full_name => @gem4
+    @source_index = Gem::SourceIndex.new
+    @source_index.add_spec @a1
+    @source_index.add_spec @a2
+    @source_index.add_spec @a_evil9
+    @source_index.add_spec @c1_2
 
     Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
   end
@@ -294,7 +349,12 @@
 
     sice = Gem::SourceInfoCacheEntry.new si, 0
     sic = Gem::SourceInfoCache.new
+
     sic.set_cache_data( { @gem_repo => sice } )
+    sic.update
+    sic.write_cache
+    sic.reset_cache_data
+
     Gem::SourceInfoCache.instance_variable_set :@cache, sic
     si
   end
@@ -311,5 +371,43 @@
     Gem.win_platform?
   end
 
+  # NOTE Allow tests to use a random (but controlled) port number instead of
+  # a hardcoded one. This helps CI tools when running parallels builds on
+  # the same builder slave.
+  def self.process_based_port
+    @@process_based_port ||= 8000 + $$ % 1000
+  end
+
+  def process_based_port
+    self.class.process_based_port
+  end
+
 end
 
+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/trunk/test/rubygems/mockgemui.rb
===================================================================
--- MacRuby/trunk/test/rubygems/mockgemui.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/mockgemui.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -15,9 +15,8 @@
   def initialize(input="")
     super(StringIO.new(input), StringIO.new, StringIO.new)
     @terminated = false
-    @banged = false
   end
-  
+
   def input
     @ins.string
   end
@@ -30,22 +29,15 @@
     @errs.string
   end
 
-  def banged?
-    @banged
-  end
-
   def terminated?
     @terminated
   end
 
-  def terminate_interaction!(status=1)
-    @terminated = true 
-    @banged = true
-    fail TermError
-  end
-
   def terminate_interaction(status=0)
     @terminated = true
-    fail TermError
+
+    raise TermError
   end
+
 end
+

Added: MacRuby/trunk/test/rubygems/private_key.pem
===================================================================
--- MacRuby/trunk/test/rubygems/private_key.pem	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/private_key.pem	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAm24C6xixiAxO+i1f3L8XRMwrmLkt6BvT60mZ7g8HsklH3af7
+KNHA6vo/G6sujs2UsNO4HY8BTEneiVOXXWQlcsJ+Z5wEPlIu4zFueAmLefx+n9lE
+ulNIUDoyUenKX4spoMRnX8k4lXL05ho/6JFq0JdDY2DmAaQ4vvTz5mh9kZiybtHQ
+fzcpbA51uY+sjdQRCPDHyUUfh0SmWJlLYMwcBdVeCiGUPBLi+iP5x1btO4uiJK6Q
+IMaV1H3SUCYtKGQKl7qwFd8k8ZBcHYOtmK61tupg3vqWQc0em6SxPj5lws8+1MVK
+twBNIDx24jF4ntxBRNKMZ7FN5SHbobAgDYkPAQIDAQABAoIBAGQilgK8X/PUajVH
+clEXU3hhSV0VQHwfIYKeYms6h6zXBVPKW0dLC0zXeDztJgueasMZQ67XaPCrTpGO
+px/l2zJ6F1HM8/bqn4aDXDY9f/xRLYryQRMBgL8fHzgitNylHWaT4j2Vt7yg2SI9
+mxrMRNKqASJPVR+Nm3l6+n9gpjVb99wEucWplPPHI6KhXLYPZOqSwt+zaH5roz3k
+UQmMs0Bs4hF1SzVl0n+KNoXHOwswVrmBWXgWvm2OhnwY2e26jfejc8toJc/ShAJ7
+C9exnrdimcgEKbd22Sum4G00CDYhcrG5LHHqkgwifcAEVctrvBZBZHGgpxlO8a8U
+eF2Vr7kCgYEAykdrBlzp7Fn9xzUInBQ3NXTTYAq51lpuJdmHQmPuTSY0buoHkd9f
+xbUCZ2qR9QAesrx4hI0qGLetc8IOKDoWx2rPepCCvO3Kx61o1SB5fAvBue03qVoq
+HqACX3Uk24Em8zAz9xuP13ETH/wU7sUbUxRHMCre6ZDmlxn4g5l+Nl8CgYEAxLVl
+22yBx0dfRr3UsHY9rxll2gIlnfnYfiJzq8wetzt/TfztRV5ILz7FyWqL5d7IoqkA
+fT2V4HAasRJASnKohwJe7z5M/H2ExwkGNFvY+jefb2CoUl5WouK9AlhbqBk3zmHi
+sY5GqQkAp/kHMntEin+sErJw6mkgAGdser3a9p8CgYEAqi31w++tunRnxw4+RRnY
+7Pdx0k6T1NxV6TAe1ONAHNY0rM/mOHqml65W7GzDiU1lhlh8SIB/VzZJDqfHw15D
+xdh94A7uf0bMILwrA4wDyTIW9Xa3Kpq57vQNqwPiU25QN69pOM+Ob+IpBfLOJafc
++kOINOUMj5Kh/aQS6Zzci58CgYEAk24dlFKEBjbRCvU2FrfYTYcsljPru7ZJc2gg
+588J6m0WYf5CWy5pzbcviGFpzvSlzXv7GOLylQ+QgcxbETFUbDPzsT4xd0AgJwj1
+dIKuYgMUZOa94VZBer2TydEtiRS1heJJhKhM/1329u4nXceTvHYqIq1JAfeee48I
+eAoZtaMCgYBz1FjWFQnMTD5nmyPEEZneoBPAR5+9jwOps+IYOoHtazoMFszzd0qo
+JZW3Ihn9KRrVSxfFApKS/ZwjiZ+tJUk7DE/v/0l0sszefY7s8b0pL1lpeZSoL71e
+QoG1WLXUiDV3BRlmyOAF1h3p12KRTLgwubN51ajECwcs3QwE+ZT8Gg==
+-----END RSA PRIVATE KEY-----

Added: MacRuby/trunk/test/rubygems/public_cert.pem
===================================================================
--- MacRuby/trunk/test/rubygems/public_cert.pem	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/public_cert.pem	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
+YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
+ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
+cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
+FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
+LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
+U5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm
+Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
+mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
+g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
+sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
+BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
+kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
+bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
+DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
+UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
+14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
+x52qPcexcYZR7w==
+-----END CERTIFICATE-----

Modified: MacRuby/trunk/test/rubygems/test_gem.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -19,6 +19,7 @@
     expected = [
       File.join(@gemhome, *%W[gems #{@a1.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@a2.full_name} lib]),
+      File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
@@ -213,6 +214,7 @@
 
     expected = [
       File.join(@gemhome, *%W[gems #{@a2.full_name} lib]),
+      File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
@@ -226,7 +228,7 @@
     install_gem foo
     Gem.source_index = nil
 
-    Gem.activate 'foo', false
+    Gem.activate 'foo'
 
     assert_equal true, Gem.loaded_specs.keys.include?('foo')
   end
@@ -235,9 +237,31 @@
     assert_equal [Gem.dir], Gem.path
   end
 
+  unless win_platform?
+    def test_self_path_APPLE_GEM_HOME
+      Gem.clear_paths
+      Gem.const_set :APPLE_GEM_HOME, '/tmp/apple_gem_home'
+  
+      assert Gem.path.include?('/tmp/apple_gem_home')
+    ensure
+      Gem.send :remove_const, :APPLE_GEM_HOME
+    end
+  
+    def test_self_path_APPLE_GEM_HOME_GEM_PATH
+      Gem.clear_paths
+      ENV['GEM_PATH'] = @gemhome
+      Gem.const_set :APPLE_GEM_HOME, '/tmp/apple_gem_home'
+  
+      assert !Gem.path.include?('/tmp/apple_gem_home')
+    ensure
+      Gem.send :remove_const, :APPLE_GEM_HOME
+    end
+  end
+
   def test_self_path_ENV_PATH
     Gem.clear_paths
     path_count = Gem.path.size
+    path_count -= 1 if defined? APPLE_GEM_HOME
     Gem.clear_paths
     util_ensure_gem_dirs
 
@@ -257,8 +281,8 @@
     ENV['GEM_PATH'] = dirs.join File::PATH_SEPARATOR
 
     assert_equal @gemhome, Gem.dir
+
     paths = [Gem.dir]
-    paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
     assert_equal @additional + paths, Gem.path
   end
 
@@ -270,8 +294,8 @@
     ENV['GEM_PATH'] = @additional.join(File::PATH_SEPARATOR)
 
     assert_equal @gemhome, Gem.dir
+
     paths = [Gem.dir]
-    paths.insert(0, APPLE_GEM_HOME) if defined? APPLE_GEM_HOME
     assert_equal @additional + paths, Gem.path
   end
 
@@ -281,9 +305,56 @@
 
   def test_self_prefix
     file_name = File.expand_path __FILE__
-    assert_equal File.dirname(File.dirname(file_name)), Gem.prefix
+
+    prefix = File.dirname File.dirname(file_name)
+    prefix = File.dirname prefix if File.basename(prefix) == 'test'
+
+    assert_equal prefix, Gem.prefix
   end
 
+  def test_self_prefix_libdir
+    orig_libdir = Gem::ConfigMap[:libdir]
+
+    file_name = File.expand_path __FILE__
+    prefix = File.dirname File.dirname(file_name)
+
+    Gem::ConfigMap[:libdir] = prefix
+
+    assert_nil Gem.prefix
+  ensure
+    Gem::ConfigMap[:libdir] = orig_libdir
+  end
+
+  def test_self_prefix_sitelibdir
+    orig_sitelibdir = Gem::ConfigMap[:sitelibdir]
+
+    file_name = File.expand_path __FILE__
+    prefix = File.dirname File.dirname(file_name)
+
+    Gem::ConfigMap[:sitelibdir] = prefix
+
+    assert_nil Gem.prefix
+  ensure
+    Gem::ConfigMap[:sitelibdir] = orig_sitelibdir
+  end
+
+  def test_self_refresh
+    util_make_gems
+
+    a1_spec = File.join @gemhome, "specifications", "#{@a1.full_name}.gemspec" 
+
+    FileUtils.mv a1_spec, @tempdir
+
+    assert !Gem.source_index.gems.include?(@a1.full_name)
+
+    FileUtils.mv File.join(@tempdir, "#{@a1.full_name}.gemspec"), a1_spec
+
+    Gem.refresh
+
+    assert Gem.source_index.gems.include?(@a1.full_name)
+    assert_equal nil, Gem.instance_variable_get(:@searcher)
+  end
+
   def test_self_required_location
     util_make_gems
 
@@ -295,6 +366,13 @@
                  Gem.required_location("a", "code.rb", "= 2")
   end
 
+  def test_self_ruby_version
+    version = RUBY_VERSION.dup
+    version << ".#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+
+    assert_equal Gem::Version.new(version), Gem.ruby_version
+  end
+
   def test_self_searcher
     assert_kind_of Gem::GemPathSearcher, Gem.searcher
   end

Modified: MacRuby/trunk/test/rubygems/test_gem_command_manager.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_command_manager.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_command_manager.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -67,11 +67,12 @@
       assert_equal true, check_options[:wrappers]
       assert_equal Gem::Requirement.default, check_options[:version]
       assert_equal Gem.dir, check_options[:install_dir]
+      assert_equal nil, check_options[:bin_dir]
 
       #check settings
       check_options = nil
       @command_manager.process_args(
-        "install --force --test --local --rdoc --install-dir . --version 3.0 --no-wrapper")
+        "install --force --test --local --rdoc --install-dir . --version 3.0 --no-wrapper --bindir . ")
       assert_equal true, check_options[:test]
       assert_equal true, check_options[:generate_rdoc]
       assert_equal true, check_options[:force]
@@ -79,6 +80,7 @@
       assert_equal false, check_options[:wrappers]
       assert_equal Gem::Requirement.new('3.0'), check_options[:version]
       assert_equal Dir.pwd, check_options[:install_dir]
+      assert_equal Dir.pwd, check_options[:bin_dir]
 
       #check remote domain
       check_options = nil
@@ -164,7 +166,7 @@
 
     #check defaults
     @command_manager.process_args("query")
-    assert_equal(/.*/, check_options[:name])
+    assert_equal(//, check_options[:name])
     assert_equal :local, check_options[:domain]
     assert_equal false, check_options[:details]
 

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_environment_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_environment_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_environment_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -20,7 +20,7 @@
       @cmd.execute
     end
 
-    assert_match %r|RUBYGEMS VERSION: (\d\.)+\d \((\d\.)+\d\)|, @ui.output
+    assert_match %r|RUBYGEMS VERSION: (\d\.)+\d|, @ui.output
     assert_match %r|RUBY VERSION: \d\.\d\.\d \(.*\) \[.*\]|, @ui.output
     assert_match %r|INSTALLATION DIRECTORY: #{Regexp.escape @gemhome}|,
                  @ui.output
@@ -62,6 +62,21 @@
     assert_equal '', @ui.error
   end
 
+  def test_execute_gempath_multiple
+    Gem.clear_paths
+    path = [@gemhome, "#{@gemhome}2"].join File::PATH_SEPARATOR
+    ENV['GEM_PATH'] = path
+
+    @cmd.send :handle_options, %w[gempath]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    assert_equal "#{Gem.path.join File::PATH_SEPARATOR}\n", @ui.output
+    assert_equal '', @ui.error
+  end
+
   def test_execute_packageversion
     @cmd.send :handle_options, %w[packageversion]
 

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_fetch_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_fetch_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_fetch_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -15,13 +15,12 @@
   def test_execute
     util_setup_fake_fetcher
 
-    util_build_gem @gem1
     @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
       @source_index.dump
-    @fetcher.data["#{@gem_repo}/gems/#{@gem1.full_name}.gem"] =
-      File.read(File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"))
+    @fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] =
+      File.read(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
 
-      @cmd.options[:args] = [@gem1.name]
+    @cmd.options[:args] = [@a2.name]
 
     use_ui @ui do
       Dir.chdir @tempdir do
@@ -29,7 +28,7 @@
       end
     end
 
-    assert File.exist?(File.join(@tempdir, "#{@gem1.full_name}.gem"))
+    assert File.exist?(File.join(@tempdir, "#{@a2.full_name}.gem"))
   end
 
 end

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_install_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_install_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_install_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -34,25 +34,26 @@
     util_setup_fake_fetcher
     @cmd.options[:domain] = :local
 
-    gem1 = quick_gem 'gem_one'
-    util_build_gem gem1
-    FileUtils.mv File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"),
+    FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
                  File.join(@tempdir)
 
-    @cmd.options[:args] = [gem1.name]
+    @cmd.options[:args] = [@a2.name]
 
     use_ui @ui do
       orig_dir = Dir.pwd
       begin
         Dir.chdir @tempdir
-        @cmd.execute
+        e = assert_raises Gem::SystemExitException do
+          @cmd.execute
+        end
+        assert_equal 0, e.exit_code
       ensure
         Dir.chdir orig_dir
       end
     end
 
     out = @ui.output.split "\n"
-    assert_equal "Successfully installed #{@gem1.full_name}", out.shift
+    assert_equal "Successfully installed #{@a2.full_name}", out.shift
     assert_equal "1 gem installed", out.shift
     assert out.empty?, out.inspect
   end
@@ -61,14 +62,17 @@
     util_setup_fake_fetcher
     @cmd.options[:domain] = :local
 
-    @cmd.options[:args] = %w[gem_one]
+    @cmd.options[:args] = %w[no_such_gem]
 
     use_ui @ui do
-      @cmd.execute
+      e = assert_raises Gem::SystemExitException do
+        @cmd.execute
+      end
+      assert_equal 2, e.exit_code
     end
 
     # HACK no repository was checked
-    assert_equal "ERROR:  could not find gem_one locally or in a repository\n",
+    assert_equal "ERROR:  could not find no_such_gem locally or in a repository\n",
                  @ui.error
   end
 
@@ -88,7 +92,10 @@
     @cmd.options[:args] = %w[nonexistent]
 
     use_ui @ui do
-      @cmd.execute
+      e = assert_raises Gem::SystemExitException do
+        @cmd.execute
+      end
+      assert_equal 2, e.exit_code
     end
 
     assert_equal "ERROR:  could not find nonexistent locally or in a repository\n",
@@ -100,25 +107,27 @@
     @cmd.options[:generate_ri] = true
     util_setup_fake_fetcher
 
-    util_build_gem @gem1
     @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
       @source_index.dump
-    @fetcher.data["#{@gem_repo}/gems/gem_one-0.0.2.gem"] =
-      File.read(File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"))
+    @fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] =
+      read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
 
-    @cmd.options[:args] = [@gem1.name]
+    @cmd.options[:args] = [@a2.name]
 
     use_ui @ui do
-      @cmd.execute
+      e = assert_raises Gem::SystemExitException do
+        @cmd.execute
+      end
+      assert_equal 0, e.exit_code
     end
 
     out = @ui.output.split "\n"
     assert_match %r|Bulk updating|, out.shift
-    assert_equal "Successfully installed #{@gem1.full_name}", out.shift
+    assert_equal "Successfully installed #{@a2.full_name}", out.shift
     assert_equal "1 gem installed", out.shift
-    assert_equal "Installing ri documentation for #{@gem1.full_name}...",
+    assert_equal "Installing ri documentation for #{@a2.full_name}...",
                  out.shift
-    assert_equal "Installing RDoc documentation for #{@gem1.full_name}...",
+    assert_equal "Installing RDoc documentation for #{@a2.full_name}...",
                  out.shift
     assert out.empty?, out.inspect
   end
@@ -127,31 +136,30 @@
     util_setup_fake_fetcher
     @cmd.options[:domain] = :local
 
-    gem1 = quick_gem 'gem_one'
-    util_build_gem gem1
-    FileUtils.mv File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"),
+    FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
                  File.join(@tempdir)
 
-    gem2 = quick_gem 'gem_two'
-    util_build_gem gem2
-    FileUtils.mv File.join(@gemhome, 'cache', "#{@gem2.full_name}.gem"),
+    FileUtils.mv File.join(@gemhome, 'cache', "#{@b2.full_name}.gem"),
                  File.join(@tempdir)
 
-    @cmd.options[:args] = [gem1.name, gem2.name]
+    @cmd.options[:args] = [@a2.name, @b2.name]
 
     use_ui @ui do
       orig_dir = Dir.pwd
       begin
         Dir.chdir @tempdir
-        @cmd.execute
+        e = assert_raises Gem::SystemExitException do
+          @cmd.execute
+        end
+        assert_equal 0, e.exit_code
       ensure
         Dir.chdir orig_dir
       end
     end
 
     out = @ui.output.split "\n"
-    assert_equal "Successfully installed #{@gem1.full_name}", out.shift
-    assert_equal "Successfully installed #{@gem2.full_name}", out.shift
+    assert_equal "Successfully installed #{@a2.full_name}", out.shift
+    assert_equal "Successfully installed #{@b2.full_name}", out.shift
     assert_equal "2 gems installed", out.shift
     assert out.empty?, out.inspect
   end

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_query_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_query_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_query_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -7,21 +7,33 @@
   def setup
     super
 
-    @foo_gem = quick_gem 'foo' do |spec|
-      spec.summary = 'This is a lot of text.  ' * 5
-    end
-    @foo_gem_p = quick_gem 'foo' do |spec|
-      spec.summary = 'This is a lot of text.  ' * 5
-      spec.platform = Gem::Platform::CURRENT
-    end
-    @bar_gem = quick_gem 'bar'
+    util_make_gems
 
+    @a2.summary = 'This is a lot of text. ' * 4
+
     @cmd = Gem::Commands::QueryCommand.new
+
+    @si = util_setup_source_info_cache @a1, @a2, @pl1
+    util_setup_fake_fetcher
+
+    @fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] = proc do
+      raise Gem::RemoteFetcher::FetchError
+    end
   end
 
   def test_execute
-    util_setup_source_info_cache @foo_gem, @foo_gem_p
+    cache = Gem::SourceInfoCache.cache
+    cache.update
+    cache.write_cache
+    cache.reset_cache_data
+    Gem::SourceInfoCache.reset
 
+    a2_name = @a2.full_name
+    @fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = util_zip a2_name
+    @fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a2_name}.gemspec.rz"] = util_zip Marshal.dump(@a2)
+    @fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] =
+      Marshal.dump @si
+
     @cmd.handle_options %w[-r]
 
     use_ui @ui do
@@ -32,16 +44,54 @@
 
 *** REMOTE GEMS ***
 
-foo (2)
+Updating metadata for 1 gems from http://gems.example.com/
+.
+complete
+a (2)
     EOF
 
     assert_equal expected, @ui.output
     assert_equal '', @ui.error
   end
 
+  def test_execute_all
+    cache = Gem::SourceInfoCache.cache
+    cache.update
+    cache.write_cache
+    cache.reset_cache_data
+    Gem::SourceInfoCache.reset
+
+    a1_name = @a1.full_name
+    a2_name = @a2.full_name
+    @fetcher.data["#{@gem_repo}/quick/index.rz"] =
+        util_zip [a1_name, a2_name].join("\n")
+    @fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = util_zip a2_name
+    @fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a1_name}.gemspec.rz"] = util_zip Marshal.dump(@a1)
+    @fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a2_name}.gemspec.rz"] = util_zip Marshal.dump(@a2)
+    @fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] =
+      Marshal.dump @si
+
+    @cmd.handle_options %w[-r --all]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    expected = <<-EOF
+
+*** REMOTE GEMS ***
+
+Updating metadata for 2 gems from http://gems.example.com/
+..
+complete
+a (2, 1)
+    EOF
+
+    assert_equal expected, @ui.output
+    assert_equal '', @ui.error
+  end
+
   def test_execute_details
-    util_setup_source_info_cache @foo_gem
-
     @cmd.handle_options %w[-r -d]
 
     use_ui @ui do
@@ -52,18 +102,94 @@
 
 *** REMOTE GEMS ***
 
-foo (2)
-    This is a lot of text.  This is a lot of text.  This is a lot of
-    text.  This is a lot of text.  This is a lot of text.
+a (2)
+    This is a lot of text. This is a lot of text. This is a lot of text.
+    This is a lot of text.
+
+pl (1)
+    this is a summary
     EOF
 
     assert_equal expected, @ui.output
     assert_equal '', @ui.error
   end
 
+  def test_execute_installed
+    @cmd.handle_options %w[-n c --installed]
+
+    e = assert_raise Gem::SystemExitException do
+      use_ui @ui do
+        @cmd.execute
+      end
+    end
+
+    assert_equal 0, e.exit_code
+
+    assert_equal "true\n", @ui.output
+    assert_equal '', @ui.error
+  end
+
+  def test_execute_installed_no_name
+    @cmd.handle_options %w[--installed]
+
+    e = assert_raise Gem::SystemExitException do
+      use_ui @ui do
+        @cmd.execute
+      end
+    end
+
+    assert_equal '', @ui.output
+    assert_equal "ERROR:  You must specify a gem name\n", @ui.error
+
+    assert_equal 4, e.exit_code
+  end
+
+  def test_execute_installed_not_installed
+    @cmd.handle_options %w[-n not_installed --installed]
+
+    e = assert_raise Gem::SystemExitException do
+      use_ui @ui do
+        @cmd.execute
+      end
+    end
+
+    assert_equal "false\n", @ui.output
+    assert_equal '', @ui.error
+
+    assert_equal 1, e.exit_code
+  end
+
+  def test_execute_installed_version
+    @cmd.handle_options %w[-n c --installed --version 1.2]
+
+    e = assert_raise Gem::SystemExitException do
+      use_ui @ui do
+        @cmd.execute
+      end
+    end
+
+    assert_equal "true\n", @ui.output
+    assert_equal '', @ui.error
+
+    assert_equal 0, e.exit_code
+  end
+
+  def test_execute_installed_version_not_installed
+    @cmd.handle_options %w[-n c --installed --version 2]
+
+    e = assert_raise Gem::SystemExitException do
+      use_ui @ui do
+        @cmd.execute
+      end
+    end
+
+    assert_equal "false\n", @ui.output
+    assert_equal '', @ui.error
+
+    assert_equal 1, e.exit_code
+  end
+
   def test_execute_no_versions
-    util_setup_source_info_cache @foo_gem, @bar_gem
-
     @cmd.handle_options %w[-r --no-versions]
 
     use_ui @ui do
@@ -74,8 +200,8 @@
 
 *** REMOTE GEMS ***
 
-bar
-foo
+a
+pl
     EOF
 
     assert_equal expected, @ui.output

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_server_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_server_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_server_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -20,7 +20,7 @@
     @cmd.send :handle_options, %w[-p 9999 -d /nonexistent --daemon]
 
     assert_equal true, @cmd.options[:daemon]
-    assert_equal '/nonexistent', @cmd.options[:gemdir]
+    assert_equal File.expand_path('/nonexistent'), @cmd.options[:gemdir]
     assert_equal 9999, @cmd.options[:port]
   end
 end

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_sources_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_sources_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_sources_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -31,10 +31,11 @@
   def test_execute_add
     util_setup_fake_fetcher
 
-    @si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
 
     @fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
-      @si.dump
+      si.dump
 
     @cmd.handle_options %w[--add http://beta-gems.example.com]
 
@@ -45,7 +46,7 @@
     end
 
     expected = <<-EOF
-Bulk updating Gem source index for: http://beta-gems.example.com
+Bulk updating Gem source index for: http://beta-gems.example.com/
 http://beta-gems.example.com added to sources
     EOF
 
@@ -60,14 +61,11 @@
   def test_execute_add_nonexistent_source
     util_setup_fake_fetcher
 
-    @si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
-
     @fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
       proc do
         raise Gem::RemoteFetcher::FetchError, 'it died'
       end
 
-
     Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
 
     @cmd.handle_options %w[--add http://beta-gems.example.com]
@@ -104,6 +102,41 @@
     assert_equal '', @ui.error
   end
 
+  def test_execute_clear_all
+    @cmd.handle_options %w[--clear-all]
+
+    util_setup_source_info_cache
+
+    cache = Gem::SourceInfoCache.cache
+    cache.update
+    cache.write_cache
+
+    assert File.exist?(cache.system_cache_file),
+           'system cache file'
+    assert File.exist?(cache.latest_system_cache_file),
+           'latest system cache file'
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    expected = <<-EOF
+*** Removed user source cache ***
+*** Removed latest user source cache ***
+*** Removed system source cache ***
+*** Removed latest system source cache ***
+    EOF
+
+    assert_equal expected, @ui.output
+    assert_equal '', @ui.error
+
+    assert !File.exist?(cache.system_cache_file),
+           'system cache file'
+    assert !File.exist?(cache.latest_system_cache_file),
+           'latest system cache file'
+
+  end
+
   def test_execute_remove
     @cmd.handle_options %W[--remove #{@gem_repo}]
 
@@ -122,20 +155,45 @@
     assert_equal [], Gem::SourceInfoCache.cache_data.keys
   end
 
+  def test_execute_remove_no_network
+    @cmd.handle_options %W[--remove #{@gem_repo}]
+
+    util_setup_fake_fetcher
+
+    @fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] = proc do
+      raise Gem::RemoteFetcher::FetchError
+    end
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    expected = "#{@gem_repo} removed from sources\n"
+
+    assert_equal expected, @ui.output
+    assert_equal '', @ui.error
+
+    Gem::SourceInfoCache.cache.flush
+    assert_equal [], Gem::SourceInfoCache.cache_data.keys
+  end
+
   def test_execute_update
     @cmd.handle_options %w[--update]
 
     util_setup_source_info_cache
+    Gem::SourceInfoCache.reset
+
     util_setup_fake_fetcher
-    @si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
-    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
+    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
 
     use_ui @ui do
       @cmd.execute
     end
 
     expected = <<-EOF
-Bulk updating Gem source index for: #{@gem_repo}
+Bulk updating Gem source index for: #{@gem_repo}/
 source cache successfully updated
     EOF
 

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_specification_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_specification_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_specification_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -12,6 +12,7 @@
 
   def test_execute
     foo = quick_gem 'foo'
+    Gem.source_index.add_spec foo
 
     @cmd.options[:args] = %w[foo]
 
@@ -87,7 +88,6 @@
 
     assert_match %r|\A--- !ruby/object:Gem::Specification|, @ui.output
     assert_match %r|name: foo|, @ui.output
-    assert_equal "WARNING:  Remote information is not complete\n\n", @ui.error
   end
 
 end

Modified: MacRuby/trunk/test/rubygems/test_gem_commands_unpack_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_unpack_command.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_unpack_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -17,15 +17,57 @@
 
     @cmd.options[:args] = %w[a]
 
-      use_ui @ui do
-        Dir.chdir @tempdir do
-          @cmd.execute
-        end
+    use_ui @ui do
+      Dir.chdir @tempdir do
+        @cmd.execute
       end
+    end
 
     assert File.exist?(File.join(@tempdir, 'a-2'))
   end
 
+  def test_execute_gem_path
+    util_make_gems
+
+    Gem.clear_paths
+
+    gemhome2 = File.join @tempdir, 'gemhome2'
+
+    Gem.send :set_paths, [gemhome2, @gemhome].join(File::PATH_SEPARATOR)
+    Gem.send :set_home, gemhome2
+
+    @cmd.options[:args] = %w[a]
+
+    use_ui @ui do
+      Dir.chdir @tempdir do
+        @cmd.execute
+      end
+    end
+
+    assert File.exist?(File.join(@tempdir, 'a-2'))
+  end
+
+  def test_execute_gem_path_missing
+    util_make_gems
+
+    Gem.clear_paths
+
+    gemhome2 = File.join @tempdir, 'gemhome2'
+
+    Gem.send :set_paths, [gemhome2, @gemhome].join(File::PATH_SEPARATOR)
+    Gem.send :set_home, gemhome2
+
+    @cmd.options[:args] = %w[z]
+
+    use_ui @ui do
+      Dir.chdir @tempdir do
+        @cmd.execute
+      end
+    end
+
+    assert_equal '', @ui.output
+  end
+
   def test_execute_with_target_option
     util_make_gems
 

Added: MacRuby/trunk/test/rubygems/test_gem_commands_update_command.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_commands_update_command.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_commands_update_command.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,175 @@
+require 'test/unit'
+require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
+require 'rubygems/commands/update_command'
+
+class TestGemCommandsUpdateCommand < RubyGemTestCase
+
+  def setup
+    super
+
+    @cmd = Gem::Commands::UpdateCommand.new
+
+    util_setup_fake_fetcher
+
+    @a1_path = File.join @gemhome, 'cache', "#{@a1.full_name}.gem"
+    @a2_path = File.join @gemhome, 'cache', "#{@a2.full_name}.gem"
+
+    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
+      @source_index.dump
+    @fetcher.data["#{@gem_repo}/gems/#{@a1.full_name}.gem"] = read_binary @a1_path
+    @fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] = read_binary @a2_path
+  end
+
+  def test_execute
+    util_remove_gems
+
+    Gem::Installer.new(@a1_path).install
+
+    @cmd.options[:args] = []
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    out = @ui.output.split "\n"
+    assert_equal "Updating installed gems", out.shift
+    assert_match %r|Bulk updating|, out.shift
+    assert_equal "Updating #{@a2.name}", out.shift
+    assert_equal "Successfully installed #{@a2.full_name}", out.shift
+    assert_equal "Gems updated: #{@a2.name}", out.shift
+
+    assert out.empty?, out.inspect
+  end
+
+  # before:
+  #   a1 -> c1.2
+  # after:
+  #   a2 -> b2 # new dependency
+  #   a2 -> c2
+
+  def test_execute_dependencies
+    @a1.add_dependency 'c', '1.2'
+
+    @c2 = quick_gem 'c', '2' do |s|
+      s.files = %w[lib/code.rb]
+      s.require_paths = %w[lib]
+    end
+
+    @a2.add_dependency 'c', '2'
+    @a2.add_dependency 'b', '2'
+
+    @b2_path = File.join @gemhome, 'cache', "#{@b2.full_name}.gem"
+    @c1_2_path = File.join @gemhome, 'cache', "#{@c1_2.full_name}.gem"
+    @c2_path = File.join @gemhome, 'cache', "#{@c2.full_name}.gem"
+
+    @source_index = Gem::SourceIndex.new
+    @source_index.add_spec @a1
+    @source_index.add_spec @a2
+    @source_index.add_spec @b2
+    @source_index.add_spec @c1_2
+    @source_index.add_spec @c2
+
+    util_build_gem @a1
+    util_build_gem @a2
+    util_build_gem @c2
+
+    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
+      @source_index.dump
+    @fetcher.data["#{@gem_repo}/gems/#{@a1.full_name}.gem"] = read_binary @a1_path
+    @fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] = read_binary @a2_path
+    @fetcher.data["#{@gem_repo}/gems/#{@b2.full_name}.gem"] = read_binary @b2_path
+    @fetcher.data["#{@gem_repo}/gems/#{@c1_2.full_name}.gem"] =
+      read_binary @c1_2_path
+    @fetcher.data["#{@gem_repo}/gems/#{@c2.full_name}.gem"] = read_binary @c2_path
+
+    util_remove_gems
+
+    Gem::Installer.new(@c1_2_path).install
+    Gem::Installer.new(@a1_path).install
+
+    @cmd.options[:args] = []
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    out = @ui.output.split "\n"
+    assert_equal "Updating installed gems", out.shift
+    assert_match %r|Bulk updating|, out.shift
+    assert_equal "Updating #{@a2.name}", out.shift
+    assert_match %r|Bulk updating|, out.shift
+    assert_equal "Successfully installed #{@c2.full_name}", out.shift
+    assert_equal "Successfully installed #{@b2.full_name}", out.shift
+    assert_equal "Successfully installed #{@a2.full_name}", out.shift
+    assert_equal "Gems updated: #{@c2.name}, #{@b2.name}, #{@a2.name}",
+                 out.shift
+
+    assert out.empty?, out.inspect
+  end
+
+  def test_execute_named
+    util_remove_gems
+
+    Gem::Installer.new(@a1_path).install
+
+    @cmd.options[:args] = [@a1.name]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    out = @ui.output.split "\n"
+    assert_equal "Updating installed gems", out.shift
+    assert_match %r|Bulk updating|, out.shift
+    assert_equal "Updating #{@a2.name}", out.shift
+    assert_equal "Successfully installed #{@a2.full_name}", out.shift
+    assert_equal "Gems updated: #{@a2.name}", out.shift
+
+    assert out.empty?, out.inspect
+  end
+
+  def test_execute_named_up_to_date
+    util_remove_gems
+
+    Gem::Installer.new(@a2_path).install
+
+    @cmd.options[:args] = [@a2.name]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    out = @ui.output.split "\n"
+    assert_equal "Updating installed gems", out.shift
+    assert_match %r|Bulk updating|, out.shift
+    assert_equal "Nothing to update", out.shift
+
+    assert out.empty?, out.inspect
+  end
+
+  def test_execute_up_to_date
+    util_remove_gems
+
+    Gem::Installer.new(@a2_path).install
+
+    @cmd.options[:args] = []
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    out = @ui.output.split "\n"
+    assert_equal "Updating installed gems", out.shift
+    assert_match %r|Bulk updating|, out.shift
+    assert_equal "Nothing to update", out.shift
+
+    assert out.empty?, out.inspect
+  end
+
+  def util_remove_gems
+    FileUtils.rm_r File.join(@gemhome, 'gems')
+    FileUtils.rm_r File.join(@gemhome, 'specifications')
+  end
+
+end
+

Modified: MacRuby/trunk/test/rubygems/test_gem_dependency_installer.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_dependency_installer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_dependency_installer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -54,8 +54,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'a'
-      inst.install
+      inst = Gem::DependencyInstaller.new
+      inst.install 'a'
     end
 
     assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
@@ -70,8 +70,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'b'
-      inst.install
+      inst = Gem::DependencyInstaller.new
+      inst.install 'b'
     end
 
     assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
@@ -84,8 +84,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'b'
-      inst.install
+      inst = Gem::DependencyInstaller.new
+      inst.install 'b'
     end
 
     assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
@@ -102,8 +102,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'f'
-      inst.install
+      inst = Gem::DependencyInstaller.new
+      inst.install 'f'
     end
 
     assert_equal %w[f-2], inst.installed_gems.map { |s| s.full_name }
@@ -114,19 +114,49 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'a-1.gem'
-      inst.install
+      inst = Gem::DependencyInstaller.new :domain => :local
+      inst.install 'a-1.gem'
     end
 
     assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
   end
 
+  def test_install_local_dependency
+    FileUtils.mv @a1_gem, @tempdir
+    FileUtils.mv @b1_gem, @tempdir
+
+    inst = nil
+
+    Dir.chdir @tempdir do
+      inst = Gem::DependencyInstaller.new :domain => :local
+      inst.install 'b-1.gem'
+    end
+
+    assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
+  end
+
+  def test_install_local_dependency_installed
+    FileUtils.mv @a1_gem, @tempdir
+    FileUtils.mv @b1_gem, @tempdir
+
+    inst = nil
+
+    Dir.chdir @tempdir do
+      Gem::Installer.new('a-1.gem').install
+
+      inst = Gem::DependencyInstaller.new :domain => :local
+      inst.install 'b-1.gem'
+    end
+
+    assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
+  end
+
   def test_install_local_subdir
     inst = nil
-    
+
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'gems/a-1.gem'
-      inst.install
+      inst = Gem::DependencyInstaller.new :domain => :local
+      inst.install 'gems/a-1.gem'
     end
 
     assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
@@ -137,12 +167,11 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'a', nil, :env_shebang => true,
-                                          :wrappers => true
-      inst.install
+      inst = Gem::DependencyInstaller.new :env_shebang => true, :wrappers => true
+      inst.install 'a'
     end
 
-    assert_match %r|\A#!/usr/bin/env ruby\n|,
+    assert_match %r|\A#!/usr/bin/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}\n|,
                  File.read(File.join(@gemhome, 'bin', 'a_bin'))
   end
 
@@ -153,8 +182,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'b', nil, :force => true
-      inst.install
+      inst = Gem::DependencyInstaller.new :force => true
+      inst.install 'b'
     end
 
     assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
@@ -165,8 +194,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'b', nil, :ignore_dependencies => true
-      inst.install
+      inst = Gem::DependencyInstaller.new :ignore_dependencies => true
+      inst.install 'b'
     end
 
     assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
@@ -179,14 +208,16 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'a', nil, :install_dir => gemhome2
-      inst.install
+      inst = Gem::DependencyInstaller.new :install_dir => gemhome2
+      inst.install 'a'
     end
 
     assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
 
     assert File.exist?(File.join(gemhome2, 'specifications',
                                  "#{@a1.full_name}.gemspec"))
+    assert File.exist?(File.join(gemhome2, 'cache',
+                                 "#{@a1.full_name}.gem"))
   end
 
   def test_install_domain_both
@@ -201,8 +232,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'b', nil, :domain => :both
-      inst.install
+      inst = Gem::DependencyInstaller.new :domain => :both
+      inst.install 'b'
     end
 
     assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
@@ -217,14 +248,34 @@
     assert_equal b1_expected, b1.loaded_from
   end
 
+  def test_install_domain_both_no_network
+    Gem::SourceInfoCache.instance_variable_set :@cache, nil
+
+    @fetcher.data["http://gems.example.com/gems/Marshal.#{@marshal_version}"] =
+      proc do
+        raise Gem::RemoteFetcher::FetchError
+      end
+
+    FileUtils.mv @a1_gem, @tempdir
+    FileUtils.mv @b1_gem, @tempdir
+    inst = nil
+
+    Dir.chdir @tempdir do
+      inst = Gem::DependencyInstaller.new :domain => :both
+      inst.install 'b'
+    end
+
+    assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
+  end
+
   def test_install_domain_local
     FileUtils.mv @b1_gem, @tempdir
     inst = nil
 
     Dir.chdir @tempdir do
       e = assert_raise Gem::InstallError do
-        inst = Gem::DependencyInstaller.new 'b', nil, :domain => :local
-        inst.install
+        inst = Gem::DependencyInstaller.new :domain => :local
+        inst.install 'b'
       end
       assert_equal 'b requires a (>= 0)', e.message
     end
@@ -240,12 +291,47 @@
 
     @fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
 
-    inst = Gem::DependencyInstaller.new 'a', nil, :domain => :remote
-    inst.install
+    inst = Gem::DependencyInstaller.new :domain => :remote
+    inst.install 'a'
 
     assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
   end
 
+  def test_install_remote
+    a1_data = nil
+    File.open @a1_gem, 'rb' do |fp|
+      a1_data = fp.read
+    end
+
+    @fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
+
+    inst = Gem::DependencyInstaller.new
+
+    Dir.chdir @tempdir do
+      inst.install 'a'
+    end
+
+    assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
+  end
+
+  def test_install_remote_dep
+    a1_data = nil
+    File.open @a1_gem, 'rb' do |fp|
+      a1_data = fp.read
+    end
+
+    @fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
+
+    inst = Gem::DependencyInstaller.new
+
+    Dir.chdir @tempdir do
+      dep = Gem::Dependency.new @a1.name, @a1.version
+      inst.install dep
+    end
+
+    assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
+  end
+
   def test_install_domain_remote_platform_newer
     a2_o, a2_o_gem = util_gem 'a', '2' do |s|
       s.platform = Gem::Platform.new %w[cpu other_platform 1]
@@ -266,8 +352,8 @@
     @fetcher.data["http://gems.example.com/gems/#{a2_o.full_name}.gem"] =
       a2_o_data
 
-    inst = Gem::DependencyInstaller.new 'a', nil, :domain => :remote
-    inst.install
+    inst = Gem::DependencyInstaller.new :domain => :remote
+    inst.install 'a'
 
     assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
   end
@@ -278,8 +364,8 @@
     inst = nil
 
     Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'a'
-      inst.install
+      inst = Gem::DependencyInstaller.new
+      inst.install 'a'
     end
 
     assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
@@ -290,13 +376,17 @@
 
   if defined? OpenSSL then
     def test_install_security_policy
-      FileUtils.mv @a1_gem, @cache_dir
-      FileUtils.mv @b1_gem, @cache_dir
+      data = File.open(@a1_gem, 'rb') { |f| f.read }
+      @fetcher.data['http://gems.example.com/gems/a-1.gem'] = data
+
+      data = File.open(@b1_gem, 'rb') { |f| f.read }
+      @fetcher.data['http://gems.example.com/gems/b-1.gem'] = data
+
       policy = Gem::Security::HighSecurity
-      inst = Gem::DependencyInstaller.new 'b', nil, :security_policy => policy
+      inst = Gem::DependencyInstaller.new :security_policy => policy
 
       e = assert_raise Gem::Exception do
-        inst.install
+        inst.install 'b'
       end
 
       assert_equal 'Unsigned gem', e.message
@@ -305,145 +395,48 @@
     end
   end
 
-  def test_install_wrappers
-    FileUtils.mv @a1_gem, @cache_dir
-    inst = Gem::DependencyInstaller.new 'a', :wrappers => true
+  # Wrappers don't work on mswin
+  unless win_platform? then
+    def test_install_no_wrappers
+      @fetcher.data['http://gems.example.com/gems/a-1.gem'] = read_binary(@a1_gem)
 
-    inst.install
+      inst = Gem::DependencyInstaller.new :wrappers => false
+      inst.install 'a'
 
-    assert_match %r|This file was generated by RubyGems.|,
-                 File.read(File.join(@gemhome, 'bin', 'a_bin'))
+      assert_no_match(%r|This file was generated by RubyGems.|,
+                      File.read(File.join(@gemhome, 'bin', 'a_bin')))
+    end
   end
 
   def test_install_version
-    FileUtils.mv @d1_gem, @cache_dir
-    FileUtils.mv @d2_gem, @cache_dir
-    inst = Gem::DependencyInstaller.new 'd', '= 1'
+    data = File.open(@d2_gem, 'rb') { |f| f.read }
+    @fetcher.data['http://gems.example.com/gems/d-2.gem'] = data
 
-    inst.install
+    data = File.open(@d1_gem, 'rb') { |f| f.read }
+    @fetcher.data['http://gems.example.com/gems/d-1.gem'] = data
 
+    inst = Gem::DependencyInstaller.new
+
+    inst.install 'd', '= 1'
+
     assert_equal %w[d-1], inst.installed_gems.map { |s| s.full_name }
   end
 
   def test_install_version_default
-    FileUtils.mv @d1_gem, @cache_dir
-    FileUtils.mv @d2_gem, @cache_dir
-    inst = Gem::DependencyInstaller.new 'd'
+    data = File.open(@d2_gem, 'rb') { |f| f.read }
+    @fetcher.data['http://gems.example.com/gems/d-2.gem'] = data
 
-    inst.install
+    data = File.open(@d1_gem, 'rb') { |f| f.read }
+    @fetcher.data['http://gems.example.com/gems/d-1.gem'] = data
 
+    inst = Gem::DependencyInstaller.new
+    inst.install 'd'
+
     assert_equal %w[d-2], inst.installed_gems.map { |s| s.full_name }
   end
 
-  def test_download
-    a1_data = nil
-    File.open @a1_gem, 'rb' do |fp|
-      a1_data = fp.read
-    end
-
-    @fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
-
-    inst = Gem::DependencyInstaller.new 'a'
-
-    a1_cache_gem = File.join(@gemhome, 'cache', "#{@a1.full_name}.gem")
-    assert_equal a1_cache_gem, inst.download(@a1, 'http://gems.example.com')
-
-    assert File.exist?(a1_cache_gem)
-  end
-
-  def test_download_cached
-    FileUtils.mv @a1_gem, @cache_dir
-
-    inst = Gem::DependencyInstaller.new 'a'
-
-    assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
-                 inst.download(@a1, 'http://gems.example.com')
-  end
-
-  def test_download_local
-    FileUtils.mv @a1_gem, @tempdir
-    local_path = File.join @tempdir, "#{@a1.full_name}.gem"
-    inst = nil
-
-    Dir.chdir @tempdir do
-      inst = Gem::DependencyInstaller.new 'a'
-    end
-
-    assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
-                 inst.download(@a1, local_path)
-  end
-
-  def test_download_install_dir
-    a1_data = nil
-    File.open @a1_gem, 'rb' do |fp|
-      a1_data = fp.read
-    end
-
-    @fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
-
-    install_dir = File.join @tempdir, 'more_gems'
-
-    inst = Gem::DependencyInstaller.new 'a', nil, :install_dir => install_dir
-
-    a1_cache_gem = File.join install_dir, 'cache', "#{@a1.full_name}.gem"
-    assert_equal a1_cache_gem, inst.download(@a1, 'http://gems.example.com')
-
-    assert File.exist?(a1_cache_gem)
-  end
-
-  unless win_platform? then # File.chmod doesn't work
-    def test_download_local_read_only
-      FileUtils.mv @a1_gem, @tempdir
-      local_path = File.join @tempdir, "#{@a1.full_name}.gem"
-      inst = nil
-      File.chmod 0555, File.join(@gemhome, 'cache')
-
-      Dir.chdir @tempdir do
-        inst = Gem::DependencyInstaller.new 'a'
-      end
-
-      assert_equal File.join(@tempdir, "#{@a1.full_name}.gem"),
-        inst.download(@a1, local_path)
-    ensure
-      File.chmod 0755, File.join(@gemhome, 'cache')
-    end
-  end
-
-  def test_download_platform_legacy
-    original_platform = 'old-platform'
-
-    e1, e1_gem = util_gem 'e', '1' do |s|
-      s.platform = Gem::Platform::CURRENT
-      s.instance_variable_set :@original_platform, original_platform
-    end
-
-    e1_data = nil
-    File.open e1_gem, 'rb' do |fp|
-      e1_data = fp.read
-    end
-
-    @fetcher.data["http://gems.example.com/gems/e-1-#{original_platform}.gem"] = e1_data
-
-    inst = Gem::DependencyInstaller.new 'a'
-
-    e1_cache_gem = File.join(@gemhome, 'cache', "#{e1.full_name}.gem")
-    assert_equal e1_cache_gem, inst.download(e1, 'http://gems.example.com')
-
-    assert File.exist?(e1_cache_gem)
-  end
-
-  def test_download_unsupported
-    inst = Gem::DependencyInstaller.new 'a'
-
-    e = assert_raise Gem::InstallError do
-      inst.download @a1, 'ftp://gems.rubyforge.org'
-    end
-
-    assert_equal 'unsupported URI scheme ftp', e.message
-  end
-
   def test_find_gems_gems_with_sources
-    inst = Gem::DependencyInstaller.new 'a'
+    inst = Gem::DependencyInstaller.new
     dep = Gem::Dependency.new 'b', '>= 0'
 
     assert_equal [[@b1, 'http://gems.example.com']],
@@ -452,7 +445,7 @@
 
   def test_find_gems_with_sources_local
     FileUtils.mv @a1_gem, @tempdir
-    inst = Gem::DependencyInstaller.new 'b'
+    inst = Gem::DependencyInstaller.new
     dep = Gem::Dependency.new 'a', '>= 0'
     gems = nil
 
@@ -462,7 +455,7 @@
 
     assert_equal 2, gems.length
     remote = gems.first
-    assert_equal @a1, remote.first, 'remote spec'
+    assert_equal 'a-1', remote.first.full_name, 'remote spec'
     assert_equal 'http://gems.example.com', remote.last, 'remote path'
 
     local = gems.last
@@ -472,7 +465,9 @@
   end
 
   def test_gather_dependencies
-    inst = Gem::DependencyInstaller.new 'b'
+    inst = Gem::DependencyInstaller.new
+    inst.find_spec_by_name_and_version 'b'
+    inst.gather_dependencies
 
     assert_equal %w[a-1 b-1], inst.gems_to_install.map { |s| s.full_name }
   end
@@ -488,7 +483,9 @@
     @fetcher.uri = URI.parse 'http://gems.example.com'
     @fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
 
-    inst = Gem::DependencyInstaller.new 'c'
+    inst = Gem::DependencyInstaller.new
+    inst.find_spec_by_name_and_version 'c'
+    inst.gather_dependencies
 
     assert_equal %w[b-2 c-1], inst.gems_to_install.map { |s| s.full_name }
   end
@@ -496,14 +493,18 @@
   def test_gather_dependencies_platform_alternate
     util_set_arch 'cpu-my_platform1'
 
-    inst = Gem::DependencyInstaller.new 'w'
+    inst = Gem::DependencyInstaller.new
+    inst.find_spec_by_name_and_version 'w'
+    inst.gather_dependencies
 
     assert_equal %w[x-1-cpu-my_platform-1 w-1],
                  inst.gems_to_install.map { |s| s.full_name }
   end
 
   def test_gather_dependencies_platform_bump
-    inst = Gem::DependencyInstaller.new 'z'
+    inst = Gem::DependencyInstaller.new
+    inst.find_spec_by_name_and_version 'z'
+    inst.gather_dependencies
 
     assert_equal %w[y-1 z-1], inst.gems_to_install.map { |s| s.full_name }
   end
@@ -518,27 +519,11 @@
     @fetcher.uri = URI.parse 'http://gems.example.com'
     @fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
 
-    inst = Gem::DependencyInstaller.new 'e'
+    inst = Gem::DependencyInstaller.new
+    inst.find_spec_by_name_and_version 'e'
+    inst.gather_dependencies
 
     assert_equal %w[d-1 e-1], inst.gems_to_install.map { |s| s.full_name }
   end
-
-  def util_gem(name, version, &block)
-    spec = quick_gem(name, version, &block)
-
-    util_build_gem spec
-
-    cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem"
-    FileUtils.mv File.join(@gemhome, 'cache', "#{spec.original_name}.gem"),
-                 cache_file
-    FileUtils.rm File.join(@gemhome, 'specifications',
-                           "#{spec.full_name}.gemspec")
-
-    spec.loaded_from = nil
-    spec.loaded = false
-
-    [spec, cache_file]
-  end
-
 end
 

Modified: MacRuby/trunk/test/rubygems/test_gem_ext_configure_builder.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_ext_configure_builder.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_ext_configure_builder.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -47,16 +47,19 @@
       end
     end
 
-    expected = %r|configure failed:
+    shell_error_msg = %r{(\./configure: No such file or directory)|(Can't open \./configure)}
+    sh_prefix_configure = "sh ./configure --prefix="
+    
+    expected = %r(configure failed:
 
-sh \./configure --prefix=#{Regexp.escape @dest_path}
-.*?: \./configure: No such file or directory
-|
+#{Regexp.escape sh_prefix_configure}#{Regexp.escape @dest_path}
+.*?: #{shell_error_msg}
+)
 
     assert_match expected, error.message
 
-    assert_equal "sh ./configure --prefix=#{@dest_path}", output.shift
-    assert_match %r|\./configure: No such file or directory\n|, output.shift
+    assert_equal "#{sh_prefix_configure}#{@dest_path}", output.shift
+    assert_match %r(#{shell_error_msg}\n), output.shift
     assert_equal true, output.empty?
   end
 

Modified: MacRuby/trunk/test/rubygems/test_gem_format.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_format.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_format.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -22,7 +22,7 @@
 
     gems = Dir[File.join(@gemhome, 'cache', '*.gem')]
 
-    names = [@a1, @a2, @b2, @c1_2, @pl1].map do |spec|
+    names = [@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].map do |spec|
       spec.original_name
     end
 

Modified: MacRuby/trunk/test/rubygems/test_gem_indexer.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_indexer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_indexer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -53,6 +53,11 @@
     assert_indexed quickdir, "index"
     assert_indexed quickdir, "index.rz"
 
+    assert_indexed quickdir, "latest_index"
+    assert_indexed quickdir, "latest_index.rz"
+
+    assert_no_match %r|a-1|, File.read(File.join(quickdir, 'latest_index'))
+
     assert_indexed quickdir, "#{@a1.full_name}.gemspec.rz"
     assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
     assert_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
@@ -74,8 +79,8 @@
     end
 
     expected = <<-EOF
-Generating index for 5 gems in #{@tempdir}
-.....
+Generating index for 6 gems in #{@tempdir}
+......
 Loaded all gems
 Generating master indexes (this may take a while)
     EOF

Modified: MacRuby/trunk/test/rubygems/test_gem_installer.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_installer.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_installer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -4,64 +4,11 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'test/unit'
-require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
-require 'rubygems/installer'
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_installer_test_case')
 
-class Gem::Installer
-  attr_accessor :gem_dir
+class TestGemInstaller < GemInstallerTestCase
 
-  attr_writer :format
-  attr_writer :gem_home
-  attr_writer :env_shebang
-  attr_writer :ignore_dependencies
-  attr_writer :format_executable
-  attr_writer :security_policy
-  attr_writer :spec
-  attr_writer :wrappers
-end
-
-class TestGemInstaller < RubyGemTestCase
-
-  def setup
-    super
-
-    @spec = quick_gem "a"
-    @gem = File.join @tempdir, "#{@spec.full_name}.gem"
-
-    util_build_gem @spec
-    FileUtils.mv File.join(@gemhome, 'cache', "#{@spec.full_name}.gem"),
-                 @tempdir
-
-    @installer = Gem::Installer.new @gem
-    @installer.gem_dir = util_gem_dir
-    @installer.gem_home = @gemhome
-    @installer.spec = @spec
-  end
-
-  def util_gem_dir(version = '2')
-    File.join @gemhome, "gems", "a-#{version}" # HACK
-  end
-
-  def util_gem_bindir(version = '2')
-    File.join util_gem_dir(version), "bin"
-  end
-
-  def util_inst_bindir
-    File.join @gemhome, "bin"
-  end
-
-  def util_make_exec(version = '2', shebang = "#!/usr/bin/ruby")
-    @spec.executables = ["my_exec"]
-
-    FileUtils.mkdir_p util_gem_bindir(version)
-    exec_file = @installer.formatted_program_filename "my_exec"
-    exec_path = File.join util_gem_bindir(version), exec_file
-    File.open exec_path, 'w' do |f|
-      f.puts shebang
-    end
-  end
-
   def test_app_script_text
     util_make_exec '2', ''
 
@@ -162,7 +109,7 @@
     @installer.gem_dir = '/nonexistent'
     expanded_gem_dir = @installer.send(:expand_and_validate_gem_dir)
     if win_platform?
-      expected = File.join(Config::CONFIG['bindir'][0..2], 'nonexistent').downcase
+      expected = File.expand_path('/nonexistent').downcase
       expanded_gem_dir = expanded_gem_dir.downcase
     else
       expected = '/nonexistent'
@@ -768,7 +715,7 @@
     @installer.env_shebang = true
 
     shebang = @installer.shebang 'my_exec'
-    assert_equal "#!/usr/bin/env ruby", shebang
+    assert_equal "#!/usr/bin/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}", shebang
   end
 
   def test_shebang_nested
@@ -855,31 +802,5 @@
     File.join @gemhome, 'cache', "#{spec.full_name}.gem"
   end
 
-  def util_setup_gem
-    @spec.files = File.join('lib', 'code.rb')
-    @spec.executables << 'executable'
-    @spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb')
-
-    Dir.chdir @tempdir do
-      FileUtils.mkdir_p 'bin'
-      FileUtils.mkdir_p 'lib'
-      FileUtils.mkdir_p File.join('ext', 'a')
-      File.open File.join('bin', 'executable'), 'w' do |f| f.puts '1' end
-      File.open File.join('lib', 'code.rb'), 'w' do |f| f.puts '1' end
-      File.open File.join('ext', 'a', 'mkrf_conf.rb'), 'w' do |f|
-        f << <<-EOF
-          File.open 'Rakefile', 'w' do |rf| rf.puts "task :default" end
-        EOF
-      end
-
-      use_ui @ui do
-        FileUtils.rm @gem
-        Gem::Builder.new(@spec).build
-      end
-    end
-
-    @installer = Gem::Installer.new @gem
-  end
-
 end
 

Added: MacRuby/trunk/test/rubygems/test_gem_package_tar_header.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_package_tar_header.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_package_tar_header.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,137 @@
+#--
+# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
+# All rights reserved.
+# See LICENSE.txt for permissions.
+#++
+
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_package_tar_test_case')
+require 'rubygems/package'
+
+class TestGemPackageTarHeader < TarTestCase
+
+  def setup
+    super
+
+    header = {
+      :name     => 'x',
+      :mode     => 0644,
+      :uid      => 1000,
+      :gid      => 10000,
+      :size     => 100,
+      :mtime    => 12345,
+      :typeflag => '0',
+      :linkname => 'link',
+      :uname    => 'user',
+      :gname    => 'group',
+      :devmajor => 1,
+      :devminor => 2,
+      :prefix   => 'y',
+    }
+
+    @tar_header = Gem::Package::TarHeader.new header
+  end
+
+  def test_self_from
+    io = TempIO.new @tar_header.to_s
+
+    new_header = Gem::Package::TarHeader.from io
+
+    assert_headers_equal @tar_header, new_header
+  end
+
+  def test_initialize
+    assert_equal '',      @tar_header.checksum, 'checksum'
+    assert_equal 1,       @tar_header.devmajor, 'devmajor'
+    assert_equal 2,       @tar_header.devminor, 'devminor'
+    assert_equal 10000,   @tar_header.gid,      'gid'
+    assert_equal 'group', @tar_header.gname,    'gname'
+    assert_equal 'link',  @tar_header.linkname, 'linkname'
+    assert_equal 'ustar', @tar_header.magic,    'magic'
+    assert_equal 0644,    @tar_header.mode,     'mode'
+    assert_equal 12345,   @tar_header.mtime,    'mtime'
+    assert_equal 'x',     @tar_header.name,     'name'
+    assert_equal 'y',     @tar_header.prefix,   'prefix'
+    assert_equal 100,     @tar_header.size,     'size'
+    assert_equal '0',     @tar_header.typeflag, 'typeflag'
+    assert_equal 1000,    @tar_header.uid,      'uid'
+    assert_equal 'user',  @tar_header.uname,    'uname'
+    assert_equal '00',    @tar_header.version,  'version'
+
+    assert !@tar_header.empty?, 'empty'
+  end
+
+  def test_initialize_bad
+    assert_raises ArgumentError do
+      Gem::Package::TarHeader.new :name => '', :size => '', :mode => ''
+    end
+
+    assert_raises ArgumentError do
+      Gem::Package::TarHeader.new :name => '', :size => '', :prefix => ''
+    end
+
+    assert_raises ArgumentError do
+      Gem::Package::TarHeader.new :name => '', :prefix => '', :mode => ''
+    end
+
+    assert_raises ArgumentError do
+      Gem::Package::TarHeader.new :prefix => '', :size => '', :mode => ''
+    end
+  end
+
+  def test_empty_eh
+    assert !@tar_header.empty?
+
+    @tar_header = Gem::Package::TarHeader.new :name => 'x', :prefix => '',
+                                              :mode => 0, :size => 0,
+                                              :empty => true
+
+    assert @tar_header.empty?
+  end
+
+  def test_equals2
+    assert_equal @tar_header, @tar_header
+    assert_equal @tar_header, @tar_header.dup
+  end
+
+  def test_to_s
+    expected = <<-EOF.split("\n").join
+x\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\0000000644\0000001750\0000023420\00000000000144\00000000030071
+\000012467\000 0link\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000ustar\00000user\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+group\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\0000000001\0000000002\000y\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
+\000\000\000\000\000\000\000\000\000\000
+    EOF
+
+    assert_headers_equal expected, @tar_header
+  end
+
+  def test_update_checksum
+    assert_equal '', @tar_header.checksum
+
+    @tar_header.update_checksum
+
+    assert_equal '012467', @tar_header.checksum
+  end
+
+end
+

Added: MacRuby/trunk/test/rubygems/test_gem_package_tar_input.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_package_tar_input.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_package_tar_input.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,119 @@
+#--
+# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
+# All rights reserved.
+# See LICENSE.txt for permissions.
+#++
+
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_package_tar_test_case')
+require 'rubygems/package/tar_input'
+
+class TestGemPackageTarInput < TarTestCase
+
+  # Sometimes the setgid bit doesn't take.  Don't know if this is a problem on
+  # all systems, or just some.  But for now, we will ignore it in the tests.
+  SETGID_BIT = 02000
+
+  def setup
+    super
+
+    inner_tar = tar_file_header("bla", "", 0612, 10)
+    inner_tar += "0123456789" + "\0" * 502
+    inner_tar += tar_file_header("foo", "", 0636, 5)
+    inner_tar += "01234" + "\0" * 507
+    inner_tar += tar_dir_header("__dir__", "", 0600)
+    inner_tar += "\0" * 1024
+    str = TempIO.new
+
+    begin
+      os = Zlib::GzipWriter.new str
+      os.write inner_tar
+    ensure
+      os.finish
+    end
+
+    str.rewind
+
+    @file = File.join @tempdir, 'bla.tar'
+
+    File.open @file, 'wb' do |f|
+      f.write tar_file_header("data.tar.gz", "", 0644, str.string.size)
+      f.write str.string
+      f.write "\0" * ((512 - (str.string.size % 512)) % 512 )
+
+      @spec = Gem::Specification.new do |spec|
+        spec.author = "Mauricio :)"
+      end
+
+      meta = @spec.to_yaml
+
+      f.write tar_file_header("metadata", "", 0644, meta.size)
+      f.write meta + "\0" * (1024 - meta.size) 
+      f.write "\0" * 1024
+    end
+
+    @entry_names = %w{bla foo __dir__}
+    @entry_sizes = [10, 5, 0]
+    #FIXME: are these modes system dependent?
+    @entry_modes = [0100612, 0100636, 040600]
+    @entry_files = %W[#{@tempdir}/bla #{@tempdir}/foo]
+    @entry_contents = %w[0123456789 01234]
+  end
+
+  def test_each_works
+    open @file, 'rb' do |io|
+      Gem::Package::TarInput.open io do |tar_input|
+        count = 0
+
+        tar_input.each_with_index do |entry, i|
+          count = i
+
+          assert_kind_of Gem::Package::TarReader::Entry, entry
+          assert_equal @entry_names[i], entry.header.name
+          assert_equal @entry_sizes[i], entry.header.size
+        end
+
+        assert_equal 2, count
+
+        assert_equal @spec, tar_input.metadata
+      end
+    end
+  end
+
+  def test_extract_entry_works
+    open @file, 'rb' do |io|
+      Gem::Package::TarInput.open io do |tar_input|
+        assert_equal @spec, tar_input.metadata
+
+        count = 0
+
+        tar_input.each_with_index do |entry, i|
+          count = i
+          tar_input.extract_entry @tempdir, entry
+          name = File.join @tempdir, entry.header.name
+
+          if entry.directory?
+            assert File.dir?(name)
+          else
+            assert File.file?(name)
+            assert_equal @entry_sizes[i], File.stat(name).size
+            #FIXME: win32? !!
+          end
+
+          unless Gem.win_platform? then
+            assert_equal @entry_modes[i], File.stat(name).mode & (~SETGID_BIT)
+          end
+        end
+
+        assert_equal 2, count
+      end
+    end
+
+    @entry_files.each_with_index do |x, i|
+      assert File.file?(x)
+      assert_equal @entry_contents[i], File.read_b(x)
+    end
+  end
+
+end
+

Added: MacRuby/trunk/test/rubygems/test_gem_package_tar_output.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_package_tar_output.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_package_tar_output.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,104 @@
+#--
+# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
+# All rights reserved.
+# See LICENSE.txt for permissions.
+#++
+
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_package_tar_test_case')
+require 'rubygems/package/tar_output'
+
+class TestGemPackageTarOutput < TarTestCase
+
+  def setup
+    super
+
+    @file = File.join @tempdir, 'bla2.tar'
+  end
+
+  def test_self_open
+    open @file, 'wb' do |tar_io|
+      Gem::Package::TarOutput.open tar_io do |tar_writer|
+        tar_writer.add_file_simple 'README', 0, 17 do |io|
+          io.write "This is a README\n"
+        end
+
+        tar_writer.metadata = "This is some metadata\n"
+      end
+    end
+
+    files = util_extract
+
+    name, data = files.shift
+    assert_equal 'data.tar.gz', name
+
+    gz = Zlib::GzipReader.new StringIO.new(data)
+
+    Gem::Package::TarReader.new gz do |tar_reader|
+      tar_reader.each do |entry|
+        assert_equal 'README', entry.full_name
+        assert_equal "This is a README\n", entry.read
+      end
+    end
+
+    gz.close
+
+    name, data = files.shift
+    assert_equal 'metadata.gz', name
+
+    gz = Zlib::GzipReader.new StringIO.new(data)
+    assert_equal "This is some metadata\n", gz.read
+
+    assert files.empty?
+  ensure
+    gz.close if gz
+  end
+
+  if defined? OpenSSL then
+    def test_self_open_signed
+      signer = Gem::Security::Signer.new @private_key, [@public_cert]
+
+      open @file, 'wb' do |tar_io|
+        Gem::Package::TarOutput.open tar_io, signer do |tar_writer|
+          tar_writer.add_file_simple 'README', 0, 17 do |io|
+            io.write "This is a README\n"
+          end
+
+          tar_writer.metadata = "This is some metadata\n"
+        end
+      end
+
+      files = util_extract
+
+      name, data = files.shift
+      assert_equal 'data.tar.gz', name
+
+      name, data = files.shift
+      assert_equal 'metadata.gz', name
+
+      name, data = files.shift
+      assert_equal 'data.tar.gz.sig', name
+
+      name, data = files.shift
+      assert_equal 'metadata.gz.sig', name
+
+      assert files.empty?
+    end
+  end
+
+  def util_extract
+    files = []
+
+    open @file, 'rb' do |io|
+      Gem::Package::TarReader.new io do |tar_reader|
+        tar_reader.each do |entry|
+          files << [entry.full_name, entry.read]
+        end
+      end
+    end
+
+    files
+  end
+
+end
+

Added: MacRuby/trunk/test/rubygems/test_gem_package_tar_reader.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_package_tar_reader.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_package_tar_reader.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,53 @@
+#--
+# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
+# All rights reserved.
+# See LICENSE.txt for permissions.
+#++
+
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_package_tar_test_case')
+require 'rubygems/package'
+
+class TestGemPackageTarReader < TarTestCase
+
+  def test_each_entry
+    tar = tar_dir_header "foo", "bar", 0
+    tar << tar_file_header("bar", "baz", 0, 0)
+
+    io = TempIO.new tar
+
+    entries = 0
+
+    Gem::Package::TarReader.new io do |tar_reader|
+      tar_reader.each_entry do |entry|
+        assert_kind_of Gem::Package::TarReader::Entry, entry
+
+        entries += 1
+      end
+    end
+
+    assert_equal 2, entries
+  end
+
+  def test_rewind
+    content = ('a'..'z').to_a.join(" ")
+
+    str = tar_file_header("lib/foo", "", 010644, content.size) + content +
+            "\0" * (512 - content.size)
+    str << "\0" * 1024
+
+    Gem::Package::TarReader.new(TempIO.new(str)) do |tar_reader|
+      3.times do
+        tar_reader.rewind
+        i = 0
+        tar_reader.each_entry do |entry|
+          assert_equal(content, entry.read)
+          i += 1
+        end
+        assert_equal(1, i)
+      end
+    end
+  end
+
+end
+

Added: MacRuby/trunk/test/rubygems/test_gem_package_tar_reader_entry.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_package_tar_reader_entry.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_package_tar_reader_entry.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,116 @@
+#--
+# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
+# All rights reserved.
+# See LICENSE.txt for permissions.
+#++
+
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_package_tar_test_case')
+require 'rubygems/package'
+
+class TestGemPackageTarReaderEntry < TarTestCase
+
+  def setup
+    super
+
+    @contents = ('a'..'z').to_a.join * 100
+
+    @tar = ''
+    @tar << tar_file_header("lib/foo", "", 0, @contents.size)
+    @tar << @contents
+    @tar << "\0" * (512 - (@tar.size % 512))
+
+    @entry = util_entry @tar
+  end
+
+  def test_bytes_read
+    assert_equal 0, @entry.bytes_read
+
+    @entry.getc
+
+    assert_equal 1, @entry.bytes_read
+  end
+
+  def test_close
+    @entry.close
+
+    assert @entry.bytes_read
+
+    e = assert_raise IOError do @entry.eof? end
+    assert_equal 'closed Gem::Package::TarReader::Entry', e.message
+
+    e = assert_raise IOError do @entry.getc end
+    assert_equal 'closed Gem::Package::TarReader::Entry', e.message
+
+    e = assert_raise IOError do @entry.pos end
+    assert_equal 'closed Gem::Package::TarReader::Entry', e.message
+
+    e = assert_raise IOError do @entry.read end
+    assert_equal 'closed Gem::Package::TarReader::Entry', e.message
+
+    e = assert_raise IOError do @entry.rewind end
+    assert_equal 'closed Gem::Package::TarReader::Entry', e.message
+  end
+
+  def test_closed_eh
+    @entry.close
+
+    assert @entry.closed?
+  end
+
+  def test_eof_eh
+    @entry.read
+
+    assert @entry.eof?
+  end
+
+  def test_full_name
+    assert_equal 'lib/foo', @entry.full_name
+  end
+
+  def test_getc
+    assert_equal ?a, @entry.getc
+  end
+
+  def test_directory_eh
+    assert_equal false, @entry.directory?
+    assert_equal true, util_dir_entry.directory?
+  end
+
+  def test_file_eh
+    assert_equal true, @entry.file?
+    assert_equal false, util_dir_entry.file?
+  end
+
+  def test_pos
+    assert_equal 0, @entry.pos
+
+    @entry.getc
+
+    assert_equal 1, @entry.pos
+  end
+
+  def test_read
+    assert_equal @contents, @entry.read
+  end
+
+  def test_read_big
+    assert_equal @contents, @entry.read(@contents.size * 2)
+  end
+
+  def test_read_small
+    assert_equal @contents[0...100], @entry.read(100)
+  end
+
+  def test_rewind
+    char = @entry.getc
+
+    @entry.rewind
+
+    assert_equal 0, @entry.pos
+
+    assert_equal char, @entry.getc
+  end
+
+end
+

Added: MacRuby/trunk/test/rubygems/test_gem_package_tar_writer.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_package_tar_writer.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_package_tar_writer.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,151 @@
+#--
+# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
+# All rights reserved.
+# See LICENSE.txt for permissions.
+#++
+
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_package_tar_test_case')
+require 'rubygems/package/tar_writer'
+
+class TestTarWriter < TarTestCase
+
+  def setup
+    super
+
+    @data = 'abcde12345'
+    @io = TempIO.new
+    @tar_writer = Gem::Package::TarWriter.new @io
+  end
+
+  def teardown
+    @tar_writer.close unless @tar_writer.closed?
+
+    super
+  end
+
+  def test_add_file
+    @tar_writer.add_file 'x', 0644 do |f| f.write 'a' * 10 end
+
+    assert_headers_equal(tar_file_header('x', '', 0644, 10),
+                         @io.string[0, 512])
+    assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
+    assert_equal 1024, @io.pos
+  end
+
+  def test_add_file_simple
+    @tar_writer.add_file_simple 'x', 0644, 10 do |io| io.write "a" * 10 end
+
+    assert_headers_equal(tar_file_header('x', '', 0644, 10),
+                         @io.string[0, 512])
+
+    assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
+    assert_equal 1024, @io.pos
+  end
+
+  def test_add_file_simple_padding
+    @tar_writer.add_file_simple 'x', 0, 100
+
+    assert_headers_equal tar_file_header('x', '', 0, 100), 
+                         @io.string[0, 512]
+
+    assert_equal "\0" * 512, @io.string[512, 512]
+  end
+
+  def test_add_file_simple_data
+    @tar_writer.add_file_simple("lib/foo/bar", 0, 10) { |f| f.write @data }
+    @tar_writer.flush
+
+    assert_equal @data + ("\0" * (512- at data.size)),
+                 @io.string[512, 512]
+  end
+
+  def test_add_file_simple_size
+    assert_raise Gem::Package::TarWriter::FileOverflow do 
+      @tar_writer.add_file_simple("lib/foo/bar", 0, 10) do |io|
+        io.write "1" * 11
+      end
+    end
+  end
+
+  def test_add_file_unseekable
+    assert_raise Gem::Package::NonSeekableIO do 
+      Gem::Package::TarWriter.new(Object.new).add_file 'x', 0
+    end
+  end
+
+  def test_close
+    @tar_writer.close
+
+    assert_equal "\0" * 1024, @io.string
+
+    e = assert_raise IOError do
+      @tar_writer.close
+    end
+    assert_equal 'closed Gem::Package::TarWriter', e.message
+
+    e = assert_raise IOError do
+      @tar_writer.flush
+    end
+    assert_equal 'closed Gem::Package::TarWriter', e.message
+
+    e = assert_raise IOError do
+      @tar_writer.add_file 'x', 0
+    end
+    assert_equal 'closed Gem::Package::TarWriter', e.message
+
+    e = assert_raise IOError do
+      @tar_writer.add_file_simple 'x', 0, 0
+    end
+    assert_equal 'closed Gem::Package::TarWriter', e.message
+
+    e = assert_raise IOError do
+      @tar_writer.mkdir 'x', 0
+    end
+    assert_equal 'closed Gem::Package::TarWriter', e.message
+  end
+
+  def test_mkdir
+    @tar_writer.mkdir 'foo', 0644
+
+    assert_headers_equal tar_dir_header('foo', '', 0644),
+                         @io.string[0, 512]
+    assert_equal 512, @io.pos
+  end
+
+  def test_split_name
+    assert_equal ['b' * 100, 'a' * 155],
+                 @tar_writer.split_name("#{'a' * 155}/#{'b' * 100}")
+
+    assert_equal ["#{'qwer/' * 19}bla", 'a' * 151],
+                 @tar_writer.split_name("#{'a' * 151}/#{'qwer/' * 19}bla")
+  end
+
+  def test_split_name_too_long_name
+    name = File.join 'a', 'b' * 100
+    assert_equal ['b' * 100, 'a'], @tar_writer.split_name(name)
+
+    assert_raise Gem::Package::TooLongFileName do
+      name = File.join 'a', 'b' * 101
+      @tar_writer.split_name name
+    end
+  end
+
+  def test_split_name_too_long_prefix
+    name = File.join 'a' * 155, 'b'
+    assert_equal ['b', 'a' * 155], @tar_writer.split_name(name)
+
+    assert_raise Gem::Package::TooLongFileName do
+      name = File.join 'a' * 156, 'b'
+      @tar_writer.split_name name
+    end
+  end
+
+  def test_split_name_too_long_total
+    assert_raise Gem::Package::TooLongFileName do
+      @tar_writer.split_name 'a' * 257
+    end
+  end
+
+end
+

Modified: MacRuby/trunk/test/rubygems/test_gem_remote_fetcher.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_remote_fetcher.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_remote_fetcher.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -76,8 +76,9 @@
 
   # don't let 1.8 and 1.9 autotest collide
   RUBY_VERSION =~ /(\d+)\.(\d+)\.(\d+)/
-  PROXY_PORT = 12345 + $1.to_i * 100 + $2.to_i * 10 + $3.to_i
-  SERVER_PORT = 23456 + $1.to_i * 100 + $2.to_i * 10 + $3.to_i
+  # don't let parallel runners collide
+  PROXY_PORT = process_based_port + 100 + $1.to_i * 100 + $2.to_i * 10 + $3.to_i
+  SERVER_PORT = process_based_port + 200 + $1.to_i * 100 + $2.to_i * 10 + $3.to_i
 
   def setup
     super
@@ -97,6 +98,13 @@
     @server_uri = base_server_uri + "/yaml"
     @server_z_uri = base_server_uri + "/yaml.Z"
 
+    # REFACTOR: copied from test_gem_dependency_installer.rb
+    @gems_dir = File.join @tempdir, 'gems'
+    @cache_dir = File.join @gemhome, 'cache'
+    FileUtils.mkdir @gems_dir
+
+    @a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end
+
     Gem::RemoteFetcher.instance_variable_set :@fetcher, nil
   end
 
@@ -156,6 +164,140 @@
     end
   end
 
+  def util_fuck_with_fetcher data, blow = false
+    fetcher = Gem::RemoteFetcher.fetcher
+    fetcher.instance_variable_set :@test_data, data
+
+    unless blow then
+      def fetcher.fetch_path arg
+        @test_arg = arg
+        @test_data
+      end
+    else
+      def fetcher.fetch_path arg
+        # OMG I'm such an ass
+        class << self; remove_method :fetch_path; end
+        def self.fetch_path arg
+          @test_arg = arg
+          @test_data
+        end
+
+        raise Gem::RemoteFetcher::FetchError, "haha!"
+      end
+    end
+
+    fetcher
+  end
+
+  def test_download
+    a1_data = nil
+    File.open @a1_gem, 'rb' do |fp|
+      a1_data = fp.read
+    end
+
+    fetcher = util_fuck_with_fetcher a1_data
+
+    a1_cache_gem = File.join(@gemhome, 'cache', "#{@a1.full_name}.gem")
+    assert_equal a1_cache_gem, fetcher.download(@a1, 'http://gems.example.com')
+    assert_equal("http://gems.example.com/gems/a-1.gem",
+                 fetcher.instance_variable_get(:@test_arg).to_s)
+    assert File.exist?(a1_cache_gem)
+  end
+
+  def test_download_cached
+    FileUtils.mv @a1_gem, @cache_dir
+
+    inst = Gem::RemoteFetcher.fetcher
+
+    assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
+                 inst.download(@a1, 'http://gems.example.com')
+  end
+
+  def test_download_local
+    FileUtils.mv @a1_gem, @tempdir
+    local_path = File.join @tempdir, "#{@a1.full_name}.gem"
+    inst = nil
+
+    Dir.chdir @tempdir do
+      inst = Gem::RemoteFetcher.fetcher
+    end
+
+    assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
+                 inst.download(@a1, local_path)
+  end
+
+  def test_download_install_dir
+    a1_data = nil
+    File.open @a1_gem, 'rb' do |fp|
+      a1_data = fp.read
+    end
+
+    fetcher = util_fuck_with_fetcher a1_data
+
+    install_dir = File.join @tempdir, 'more_gems'
+
+    a1_cache_gem = File.join install_dir, 'cache', "#{@a1.full_name}.gem"
+    actual = fetcher.download(@a1, 'http://gems.example.com', install_dir)
+
+    assert_equal a1_cache_gem, actual
+    assert_equal("http://gems.example.com/gems/a-1.gem",
+                 fetcher.instance_variable_get(:@test_arg).to_s)
+
+    assert File.exist?(a1_cache_gem)
+  end
+
+  unless win_platform? then # File.chmod doesn't work
+    def test_download_local_read_only
+      FileUtils.mv @a1_gem, @tempdir
+      local_path = File.join @tempdir, "#{@a1.full_name}.gem"
+      inst = nil
+      File.chmod 0555, File.join(@gemhome, 'cache')
+
+      Dir.chdir @tempdir do
+        inst = Gem::RemoteFetcher.fetcher
+      end
+
+      assert_equal File.join(@tempdir, "#{@a1.full_name}.gem"),
+        inst.download(@a1, local_path)
+    ensure
+      File.chmod 0755, File.join(@gemhome, 'cache')
+    end
+  end
+
+  def test_download_platform_legacy
+    original_platform = 'old-platform'
+
+    e1, e1_gem = util_gem 'e', '1' do |s|
+      s.platform = Gem::Platform::CURRENT
+      s.instance_variable_set :@original_platform, original_platform
+    end
+
+    e1_data = nil
+    File.open e1_gem, 'rb' do |fp|
+      e1_data = fp.read
+    end
+
+    fetcher = util_fuck_with_fetcher e1_data, :blow_chunks
+
+    e1_cache_gem = File.join(@gemhome, 'cache', "#{e1.full_name}.gem")
+
+    assert_equal e1_cache_gem, fetcher.download(e1, 'http://gems.example.com')
+
+    assert_equal("http://gems.example.com/gems/#{e1.original_name}.gem",
+                 fetcher.instance_variable_get(:@test_arg).to_s)
+    assert File.exist?(e1_cache_gem)
+  end
+
+  def test_download_unsupported
+    inst = Gem::RemoteFetcher.fetcher
+
+    e = assert_raise Gem::InstallError do
+      inst.download @a1, 'ftp://gems.rubyforge.org'
+    end
+
+    assert_equal 'unsupported URI scheme ftp', e.message
+  end
+
   def test_explicit_proxy
     use_ui @ui do
       fetcher = Gem::RemoteFetcher.new @proxy_uri
@@ -232,22 +374,6 @@
     assert_equal 'EOFError: EOFError reading uri', e.message
   end
 
-  def test_fetch_path_open_uri_http_error
-    fetcher = Gem::RemoteFetcher.new nil
-
-    def fetcher.open_uri_or_path(uri)
-      io = StringIO.new 'went boom'
-      err = OpenURI::HTTPError.new 'error', io
-      raise err
-    end
-
-    e = assert_raise Gem::RemoteFetcher::FetchError do
-      fetcher.fetch_path 'uri'
-    end
-
-    assert_equal "OpenURI::HTTPError: error reading uri\n\twent boom", e.message
-  end
-
   def test_fetch_path_socket_error
     fetcher = Gem::RemoteFetcher.new nil
 
@@ -324,6 +450,53 @@
     end
   end
 
+  def test_open_uri_or_path
+    fetcher = Gem::RemoteFetcher.new nil
+
+    conn = Object.new
+    def conn.started?() true end
+    def conn.request(req)
+      unless defined? @requested then
+        @requested = true
+        res = Net::HTTPRedirection.new nil, 301, nil
+        res.add_field 'Location', 'http://gems.example.com/real_path'
+        res
+      else
+        res = Net::HTTPOK.new nil, 200, nil
+        def res.body() 'real_path' end
+        res
+      end
+    end
+
+    conn = { 'gems.example.com:80' => conn }
+    fetcher.instance_variable_set :@connections, conn
+
+    fetcher.send :open_uri_or_path, 'http://gems.example.com/redirect' do |io|
+      assert_equal 'real_path', io.read
+    end
+  end
+
+  def test_open_uri_or_path_limited_redirects
+    fetcher = Gem::RemoteFetcher.new nil
+
+    conn = Object.new
+    def conn.started?() true end
+    def conn.request(req)
+      res = Net::HTTPRedirection.new nil, 301, nil
+      res.add_field 'Location', 'http://gems.example.com/redirect'
+      res
+    end
+
+    conn = { 'gems.example.com:80' => conn }
+    fetcher.instance_variable_set :@connections, conn
+
+    e = assert_raise Gem::RemoteFetcher::FetchError do
+      fetcher.send :open_uri_or_path, 'http://gems.example.com/redirect'
+    end
+
+    assert_equal 'too many redirects', e.message
+  end
+
   def test_zip
     use_ui @ui do
       self.class.enable_zip = true

Modified: MacRuby/trunk/test/rubygems/test_gem_server.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_server.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_server.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -15,7 +15,7 @@
 
     @a1 = quick_gem 'a', '1'
 
-    @server = Gem::Server.new Gem.dir, 8809, false
+    @server = Gem::Server.new Gem.dir, process_based_port, false
     @req = WEBrick::HTTPRequest.new :Logger => nil
     @res = WEBrick::HTTPResponse.new :HTTPVersion => '1.0'
   end

Modified: MacRuby/trunk/test/rubygems/test_gem_source_index.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_source_index.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_source_index.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -36,7 +36,8 @@
 
     use_ui @ui do
       fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
+      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
+                    @c1_2.full_name].sort,
                    fetched_index.gems.map { |n,s| n }.sort
     end
 
@@ -82,7 +83,8 @@
 
     use_ui @ui do
       fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
+      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
+                    @c1_2.full_name].sort,
                    fetched_index.gems.map { |n,s| n }.sort
     end
 
@@ -105,7 +107,8 @@
 
     use_ui @ui do
       fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
+      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
+                    @c1_2.full_name].sort,
                    fetched_index.gems.map { |n,s| n }.sort
     end
 
@@ -123,7 +126,8 @@
     util_setup_bulk_fetch false
     use_ui @ui do
       fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
+      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
+                    @c1_2.full_name].sort,
                    fetched_index.gems.map { |n,s| n }.sort
     end
 
@@ -136,15 +140,36 @@
   end
 
   def test_fetch_quick_index
-    quick_index = util_zip @gem_names
-    @fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
+    index = util_zip @gem_names
+    latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
 
-    quick_index = @source_index.fetch_quick_index @uri
-    assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
+    @fetcher.data["#{@gem_repo}/quick/index.rz"] = index
+    @fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = latest_index
+
+    quick_index = @source_index.fetch_quick_index @uri, false
+    assert_equal [@a2.full_name, @b2.full_name].sort,
                  quick_index.sort
 
     paths = @fetcher.paths
 
+    assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
+  def test_fetch_quick_index_all
+    index = util_zip @gem_names
+    latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
+
+    @fetcher.data["#{@gem_repo}/quick/index.rz"] = index
+    @fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = latest_index
+
+    quick_index = @source_index.fetch_quick_index @uri, true
+    assert_equal [@a1.full_name, @a2.full_name, @b2.full_name].sort,
+                 quick_index.sort
+
+    paths = @fetcher.paths
+
     assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
 
     assert paths.empty?, paths.join(', ')
@@ -155,7 +180,7 @@
       proc { raise Exception }
 
     e = assert_raise Gem::OperationNotSupportedError do
-      @source_index.fetch_quick_index @uri
+      @source_index.fetch_quick_index @uri, true
     end
 
     assert_equal 'No quick index found: Exception', e.message
@@ -167,41 +192,201 @@
     assert paths.empty?, paths.join(', ')
   end
 
+  def test_fetch_quick_index_fallback
+    index = util_zip @gem_names
+
+    @fetcher.data["#{@gem_repo}/quick/index.rz"] = index
+
+    quick_index = @source_index.fetch_quick_index @uri, false
+    assert_equal @gem_names.split, quick_index.sort
+
+    paths = @fetcher.paths
+
+    assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
+    assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
+  def test_fetch_quick_index_subdir
+    latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
+    repo = URI.parse "#{@gem_repo}/~nobody/mirror/"
+
+    @fetcher.data["#{repo}quick/latest_index.rz"] = latest_index
+
+    quick_index = @source_index.fetch_quick_index repo, false
+    assert_equal [@a2.full_name, @b2.full_name].sort,
+                 quick_index.sort
+
+    paths = @fetcher.paths
+
+    assert_equal "#{repo}quick/latest_index.rz", paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
+  def test_fetch_single_spec
+    a1_spec_url = "#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz"
+    @fetcher.data[a1_spec_url] = util_zip Marshal.dump(@a1)
+
+    spec = @source_index.send :fetch_single_spec, URI.parse(@gem_repo),
+                              @a1.full_name
+
+    assert_equal @a1.full_name, spec.full_name
+
+    paths = @fetcher.paths
+
+    assert_equal a1_spec_url, paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
+  def test_fetch_single_spec_subdir
+    repo = URI.parse "#{@gem_repo}/~nobody/mirror/"
+
+    a1_spec_url = "#{repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz"
+    @fetcher.data[a1_spec_url] = util_zip Marshal.dump(@a1)
+
+    spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
+
+    assert_equal @a1.full_name, spec.full_name
+
+    paths = @fetcher.paths
+
+    assert_equal a1_spec_url, paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
+  def test_fetch_single_spec_yaml
+    a1_spec_url = "#{@gem_repo}/quick/#{@a1.full_name}.gemspec.rz"
+    @fetcher.data[a1_spec_url] = util_zip @a1.to_yaml
+
+    repo = URI.parse @gem_repo
+
+    spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
+
+    assert_equal @a1.full_name, spec.full_name
+
+    paths = @fetcher.paths
+
+    assert_equal "#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz", paths.shift
+    assert_equal a1_spec_url, paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
+  def test_fetch_single_spec_yaml_subdir
+    repo = URI.parse "#{@gem_repo}/~nobody/mirror/"
+
+    a1_spec_url = "#{repo}quick/#{@a1.full_name}.gemspec.rz"
+    @fetcher.data[a1_spec_url] = util_zip @a1.to_yaml
+
+    spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
+
+    assert_equal @a1.full_name, spec.full_name
+
+    paths = @fetcher.paths
+
+    assert_equal "#{repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz", paths.shift
+    assert_equal a1_spec_url, paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
   def test_find_missing
-    missing = @source_index.find_missing [@gem3.full_name]
-    assert_equal [@gem3.full_name], missing
+    missing = @source_index.find_missing [@b2.full_name]
+    assert_equal [@b2.full_name], missing
   end
 
   def test_find_missing_none_missing
-    missing = @source_index.find_missing @gem_names.split
+    missing = @source_index.find_missing [
+      @a1.full_name, @a2.full_name, @c1_2.full_name
+    ]
+
     assert_equal [], missing
   end
 
   def test_latest_specs
-    spec = quick_gem @gem1.name, '1'
-    @source_index.add_spec spec
+    p1_ruby = quick_gem 'p', '1'
+    p1_platform = quick_gem 'p', '1' do |spec|
+      spec.platform = Gem::Platform::CURRENT
+    end
 
+    a1_platform = quick_gem @a1.name, (@a1.version) do |s|
+      s.platform = Gem::Platform.new 'x86-my_platform1'
+    end
+
+    a2_platform = quick_gem @a2.name, (@a2.version) do |s|
+      s.platform = Gem::Platform.new 'x86-my_platform1'
+    end
+
+    a2_platform_other = quick_gem @a2.name, (@a2.version) do |s|
+      s.platform = Gem::Platform.new 'x86-other_platform1'
+    end
+
+    a3_platform_other = quick_gem @a2.name, (@a2.version.bump) do |s|
+      s.platform = Gem::Platform.new 'x86-other_platform1'
+    end
+
+    @source_index.add_spec p1_ruby
+    @source_index.add_spec p1_platform
+    @source_index.add_spec a1_platform
+    @source_index.add_spec a2_platform
+    @source_index.add_spec a2_platform_other
+    @source_index.add_spec a3_platform_other
+
     expected = [
-      @gem1.full_name,
-      @gem2.full_name,
-      @gem4.full_name,
+      @a2.full_name,
+      a2_platform.full_name,
+      a3_platform_other.full_name,
+      @c1_2.full_name,
+      @a_evil9.full_name,
+      p1_ruby.full_name,
+      p1_platform.full_name,
     ].sort
 
-    assert_equal expected, @source_index.latest_specs.map { |s| s.full_name }.sort
+    latest_specs = @source_index.latest_specs.map { |s| s.full_name }.sort
+
+    assert_equal expected, latest_specs
   end
 
+  def test_load_gems_in
+    spec_dir1 = File.join @gemhome, 'specifications'
+    spec_dir2 = File.join @tempdir, 'gemhome2', 'specifications'
+
+    FileUtils.rm_r spec_dir1
+
+    FileUtils.mkdir_p spec_dir1
+    FileUtils.mkdir_p spec_dir2
+
+    a1 = quick_gem 'a', '1' do |spec| spec.author = 'author 1' end
+    a2 = quick_gem 'a', '1' do |spec| spec.author = 'author 2' end
+
+    File.open File.join(spec_dir1, "#{a1.full_name}.gemspec"), 'w' do |fp|
+      fp.write a1.to_ruby
+    end
+
+    File.open File.join(spec_dir2, "#{a2.full_name}.gemspec"), 'w' do |fp|
+      fp.write a2.to_ruby
+    end
+
+    @source_index.load_gems_in spec_dir1, spec_dir2
+
+    assert_equal a1.author, @source_index.specification(a1.full_name).author
+  end
+
   def test_outdated
-    sic = Gem::SourceInfoCache.new
-    Gem::SourceInfoCache.instance_variable_set :@cache, sic
+    util_setup_source_info_cache
 
     assert_equal [], @source_index.outdated
 
-    updated = quick_gem @gem1.name, (@gem1.version.bump)
+    updated = quick_gem @a2.name, (@a2.version.bump)
     util_setup_source_info_cache updated
 
     assert_equal [updated.name], @source_index.outdated
 
-    updated_platform = quick_gem @gem1.name, (updated.version.bump) do |s|
+    updated_platform = quick_gem @a2.name, (updated.version.bump) do |s|
       s.platform = Gem::Platform.new 'x86-other_platform1'
     end
 
@@ -210,30 +395,54 @@
     assert_equal [updated_platform.name], @source_index.outdated
   end
 
+  def test_refresh_bang
+    a1_spec = File.join @gemhome, "specifications", "#{@a1.full_name}.gemspec" 
+
+    FileUtils.mv a1_spec, @tempdir
+
+    source_index = Gem::SourceIndex.from_installed_gems
+
+    assert !source_index.gems.include?(@a1.full_name)
+
+    FileUtils.mv File.join(@tempdir, "#{@a1.full_name}.gemspec"), a1_spec
+
+    source_index.refresh!
+
+    assert source_index.gems.include?(@a1.full_name)
+  end
+
   def test_remove_extra
-    @source_index.remove_extra [@gem1.full_name]
-    assert_equal [@gem1.full_name], @source_index.gems.map { |n,s| n }
+    @source_index.add_spec @a1
+    @source_index.add_spec @a2
+    @source_index.add_spec @pl1
+
+    @source_index.remove_extra [@a1.full_name, @pl1.full_name]
+
+    assert_equal [@a1.full_name],
+                 @source_index.gems.map { |n,s| n }.sort
   end
 
   def test_remove_extra_no_changes
-    gems = @gem_names.split.sort
+    gems = [@a1.full_name, @a2.full_name]
+    @source_index.add_spec @a1
+    @source_index.add_spec @a2
+
     @source_index.remove_extra gems
+
     assert_equal gems, @source_index.gems.map { |n,s| n }.sort
   end
 
   def test_search
-    assert_equal [@gem1, @gem4], @source_index.search("gem_one")
-    assert_equal [@gem1], @source_index.search("gem_one", "= 2")
+    assert_equal [@a1, @a2, @a_evil9], @source_index.search('a')
+    assert_equal [@a2], @source_index.search('a', '= 2')
 
-    assert_equal [], @source_index.search("bogusstring")
-    assert_equal [], @source_index.search("gem_one", "= 3.2.1")
+    assert_equal [], @source_index.search('bogusstring')
+    assert_equal [], @source_index.search('a', '= 3')
 
-    @a1 = quick_gem 'a', '1'
-    @a2 = quick_gem 'a', '2'
+    source_index = Gem::SourceIndex.new
+    source_index.add_spec @a1
+    source_index.add_spec @a2
 
-    source_index = Gem::SourceIndex.new @a1.full_name => @a1,
-                                        @a2.full_name => @a2
-
     assert_equal [@a1], source_index.search(@a1.name, '= 1')
 
     r1 = Gem::Requirement.create '= 1'
@@ -276,7 +485,7 @@
   end
 
   def test_specification
-    assert_equal @gem1, @source_index.specification(@gem1.full_name)
+    assert_equal @a1, @source_index.specification(@a1.full_name)
 
     assert_nil @source_index.specification("foo-1.2.4")
   end
@@ -298,9 +507,11 @@
     assert_equal [], @source_index.gems.keys.sort
 
     use_ui @ui do
-      @source_index.update @uri
+      @source_index.update @uri, true
 
-      assert_equal @gem_names.split, @source_index.gems.keys.sort
+      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
+                    @c1_2.full_name],
+                   @source_index.gems.keys.sort
     end
 
     paths = @fetcher.paths
@@ -315,15 +526,42 @@
     old_gem_conf = Gem.configuration
     Gem.configuration = Gem::ConfigFile.new([])
 
+    latest_names = [@a2, @a_evil9, @b2, @c1_2].map { |s| s.full_name }
+    latest_index = util_zip latest_names.join("\n")
+    @fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = latest_index
+
+    marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
+                            "#{@b2.full_name}.gemspec.rz"
+    @fetcher.data[marshal_uri] = util_zip Marshal.dump(@b2)
+
+    use_ui @ui do
+      @source_index.update @uri, false
+
+      assert_equal latest_names, @source_index.gems.keys.sort
+    end
+
+    paths = @fetcher.paths
+    assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
+    assert_equal marshal_uri, paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  ensure
+    Gem.configuration = old_gem_conf
+  end
+
+  def test_update_incremental_all
+    old_gem_conf = Gem.configuration
+    Gem.configuration = Gem::ConfigFile.new([])
+
     quick_index = util_zip @all_gem_names.join("\n")
     @fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
 
     marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@gem3.full_name}.gemspec.rz"
-    @fetcher.data[marshal_uri] = util_zip Marshal.dump(@gem3)
+                            "#{@b2.full_name}.gemspec.rz"
+    @fetcher.data[marshal_uri] = util_zip Marshal.dump(@b2)
 
     use_ui @ui do
-      @source_index.update @uri
+      @source_index.update @uri, true
 
       assert_equal @all_gem_names, @source_index.gems.keys.sort
     end
@@ -345,13 +583,13 @@
     @fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
 
     marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@gem3.full_name}.gemspec.rz"
+                            "#{@b2.full_name}.gemspec.rz"
 
-    yaml_uri = "#{@gem_repo}/quick/#{@gem3.full_name}.gemspec.rz"
-    @fetcher.data[yaml_uri] = util_zip @gem3.to_yaml
+    yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
+    @fetcher.data[yaml_uri] = util_zip @b2.to_yaml
 
     use_ui @ui do
-      @source_index.update @uri
+      @source_index.update @uri, true
 
       assert_equal @all_gem_names, @source_index.gems.keys.sort
     end
@@ -374,16 +612,16 @@
     @fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
 
     marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@gem3.full_name}.gemspec.rz"
-    marshal_data = Marshal.dump(@gem3)
+                            "#{@b2.full_name}.gemspec.rz"
+    marshal_data = Marshal.dump(@b2)
     marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
     @fetcher.data[marshal_uri] = util_zip marshal_data
 
-    yaml_uri = "#{@gem_repo}/quick/#{@gem3.full_name}.gemspec.rz"
-    @fetcher.data[yaml_uri] = util_zip @gem3.to_yaml
+    yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
+    @fetcher.data[yaml_uri] = util_zip @b2.to_yaml
 
     use_ui @ui do
-      @source_index.update @uri
+      @source_index.update @uri, true
 
       assert_equal @all_gem_names, @source_index.gems.keys.sort
     end
@@ -398,22 +636,48 @@
     Gem.configuration = old_gem_conf
   end
 
+  def test_update_subdir
+    @gem_repo = @gem_repo + "/subdir"
+
+    util_setup_bulk_fetch true
+
+    @source_index.gems.replace({})
+    assert_equal [], @source_index.gems.keys.sort
+
+    uri = @uri.to_s + "/subdir"
+
+    use_ui @ui do
+      @source_index.update uri, true
+
+      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
+                    @c1_2.full_name],
+                   @source_index.gems.keys.sort
+    end
+
+    paths = @fetcher.paths
+
+    assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
+    assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
+
+    assert paths.empty?, paths.join(', ')
+  end
+
   def test_update_with_missing
     marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@gem3.full_name}.gemspec.rz"
-    dumped = Marshal.dump @gem3
+                            "#{@c1_2.full_name}.gemspec.rz"
+    dumped = Marshal.dump @c1_2
     @fetcher.data[marshal_uri] = util_zip(dumped)
 
     use_ui @ui do
-      @source_index.update_with_missing @uri, [@gem3.full_name]
+      @source_index.update_with_missing @uri, [@c1_2.full_name]
     end
 
-    spec = @source_index.specification(@gem3.full_name)
+    spec = @source_index.specification(@c1_2.full_name)
     # We don't care about the equality of undumped attributes
-    @gem3.files = spec.files
-    @gem3.loaded_from = spec.loaded_from
+    @c1_2.files = spec.files
+    @c1_2.loaded_from = spec.loaded_from
 
-    assert_equal @gem3, spec
+    assert_equal @c1_2, spec
   end
 
   def util_setup_bulk_fetch(compressed)
@@ -427,3 +691,4 @@
   end
 
 end
+

Modified: MacRuby/trunk/test/rubygems/test_gem_source_info_cache.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_source_info_cache.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_source_info_cache.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -25,7 +25,12 @@
     @sic = Gem::SourceInfoCache.new
     @sic.instance_variable_set :@fetcher, @fetcher
 
+    @si_new = Gem::SourceIndex.new
+    @sice_new = Gem::SourceInfoCacheEntry.new @si_new, 0
+
     prep_cache_files @sic
+
+    @sic.reset_cache_data
   end
 
   def teardown
@@ -35,9 +40,11 @@
 
   def test_self_cache_refreshes
     Gem.configuration.update_sources = true #true by default
-    source_index = Gem::SourceIndex.new 'key' => 'sys'
-    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
 
+    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
+
     Gem.sources.replace %W[#{@gem_repo}]
 
     use_ui @ui do
@@ -51,9 +58,11 @@
 
   def test_self_cache_skips_refresh_based_on_configuration
     Gem.configuration.update_sources = false
-    source_index = Gem::SourceIndex.new 'key' => 'sys'
-    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
 
+    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
+
     Gem.sources.replace %w[#{@gem_repo}]
 
     use_ui @ui do
@@ -66,20 +75,24 @@
   end
 
   def test_self_cache_data
-    source_index = Gem::SourceIndex.new 'key' => 'sys'
-    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
 
+    @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
+
     Gem::SourceInfoCache.instance_variable_set :@cache, nil
-    sice = Gem::SourceInfoCacheEntry.new source_index, 0
+    sice = Gem::SourceInfoCacheEntry.new si, 0
 
     use_ui @ui do
-      assert_equal source_index.gems,
-                   Gem::SourceInfoCache.cache_data[@gem_repo].source_index.gems
+      gems = Gem::SourceInfoCache.cache_data[@gem_repo].source_index.gems
+      gem_names = gems.map { |_, spec| spec.full_name }
+
+      assert_equal si.gems.map { |_,spec| spec.full_name }, gem_names
     end
   end
 
   def test_cache_data
-    assert_equal [['key','sys']], @sic.cache_data.to_a.sort
+    assert_equal [[@gem_repo, @usr_sice]], @sic.cache_data.to_a.sort
   end
 
   def test_cache_data_dirty
@@ -97,7 +110,14 @@
 
     data = { @gem_repo => { 'totally' => 'borked' } }
 
-    [@sic.system_cache_file, @sic.user_cache_file].each do |fn|
+    cache_files = [
+      @sic.system_cache_file,
+      @sic.latest_system_cache_file,
+      @sic.user_cache_file,
+      @sic.latest_user_cache_file
+    ]
+
+    cache_files.each do |fn|
       FileUtils.mkdir_p File.dirname(fn)
       open(fn, "wb") { |f| f.write Marshal.dump(data) }
     end
@@ -113,7 +133,9 @@
 
   def test_cache_data_none_readable
     FileUtils.chmod 0222, @sic.system_cache_file
+    FileUtils.chmod 0222, @sic.latest_system_cache_file
     FileUtils.chmod 0222, @sic.user_cache_file
+    FileUtils.chmod 0222, @sic.latest_user_cache_file
     return if (File.stat(@sic.system_cache_file).mode & 0222) != 0222
     return if (File.stat(@sic.user_cache_file).mode & 0222) != 0222
     # HACK for systems that don't support chmod
@@ -129,6 +151,16 @@
     assert_equal 'unable to locate a writable cache file', e.message
   end
 
+  def test_cache_data_nonexistent
+    FileUtils.rm @sic.system_cache_file
+    FileUtils.rm @sic.latest_system_cache_file
+    FileUtils.rm @sic.user_cache_file
+    FileUtils.rm @sic.latest_user_cache_file
+
+    # TODO test verbose output
+    assert_equal [], @sic.cache_data.to_a.sort
+  end
+
   def test_cache_data_repair
     data = {
         @gem_repo => {
@@ -152,7 +184,8 @@
 
   def test_cache_data_user_fallback
     FileUtils.chmod 0444, @sic.system_cache_file
-    assert_equal [['key','usr']], @sic.cache_data.to_a.sort
+
+    assert_equal [[@gem_repo, @usr_sice]], @sic.cache_data.to_a.sort
   end
 
   def test_cache_file
@@ -174,60 +207,119 @@
   end
 
   def test_flush
-    @sic.cache_data['key'] = 'new'
+    @sic.cache_data[@gem_repo] = @sice_new
     @sic.update
     @sic.flush
 
-    assert_equal [['key','new']], read_cache(@sic.system_cache_file).to_a.sort
+    assert_equal [[@gem_repo, @sice_new]],
+                 read_cache(@sic.system_cache_file).to_a.sort
   end
 
+  def test_latest_cache_data
+    util_make_gems
+
+    sice = Gem::SourceInfoCacheEntry.new @source_index, 0
+
+    @sic.set_cache_data @gem_repo => sice
+    latest = @sic.latest_cache_data
+    gems = latest[@gem_repo].source_index.search('a').map { |s| s.full_name }
+
+    assert_equal %w[a-2 a_evil-9], gems
+  end
+
+  def test_latest_cache_file
+    latest_cache_file = File.join File.dirname(@gemcache),
+                                  "latest_#{File.basename @gemcache}"
+    assert_equal latest_cache_file, @sic.latest_cache_file
+  end
+
+  def test_latest_system_cache_file
+    assert_equal File.join(Gem.dir, "latest_source_cache"),
+                 @sic.latest_system_cache_file
+  end
+
+  def test_latest_user_cache_file
+    assert_equal @latest_usrcache, @sic.latest_user_cache_file
+  end
+
   def test_read_system_cache
-    assert_equal [['key','sys']], @sic.cache_data.to_a.sort
+    assert_equal [[@gem_repo, @sys_sice]], @sic.cache_data.to_a.sort
   end
 
   def test_read_user_cache
-    FileUtils.chmod 0444, @sic.system_cache_file
+    FileUtils.chmod 0444, @sic.user_cache_file
+    FileUtils.chmod 0444, @sic.latest_user_cache_file
 
-    assert_equal [['key','usr']], @sic.cache_data.to_a.sort
+    @si = Gem::SourceIndex.new
+    @si.add_specs @a1, @a2
+
+    @sice = Gem::SourceInfoCacheEntry.new @si, 0
+
+    @sic.set_cache_data({ @gem_repo => @sice })
+    @sic.update
+    @sic.write_cache
+    @sic.reset_cache_data
+
+    user_cache_data = @sic.cache_data.to_a.sort
+
+    assert_equal 1, user_cache_data.length
+    user_cache_data = user_cache_data.first
+
+    assert_equal @gem_repo, user_cache_data.first
+
+    gems = user_cache_data.last.source_index.map { |_,spec| spec.full_name }
+    assert_equal [@a2.full_name], gems
   end
 
   def test_search
-    si = Gem::SourceIndex.new @gem1.full_name => @gem1
-    cache_data = {
-      @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
-    }
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
+    cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
     @sic.instance_variable_set :@cache_data, cache_data
 
-    assert_equal [@gem1], @sic.search(//)
+    assert_equal [@a1], @sic.search(//)
   end
 
+  def test_search_all
+    util_make_gems
+
+    sice = Gem::SourceInfoCacheEntry.new @source_index, 0
+
+    @sic.set_cache_data @gem_repo => sice
+    @sic.update
+    @sic.instance_variable_set :@only_latest, false
+    @sic.write_cache
+    @sic.reset_cache_data
+
+    gem_names = @sic.search(//, false, true).map { |spec| spec.full_name }
+
+    assert_equal %w[a-1 a-2 a_evil-9 c-1.2], gem_names
+  end
+
   def test_search_dependency
-    si = Gem::SourceIndex.new @gem1.full_name => @gem1
-    cache_data = {
-      @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
-    }
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
+    cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
     @sic.instance_variable_set :@cache_data, cache_data
 
-    dep = Gem::Dependency.new @gem1.name, @gem1.version
+    dep = Gem::Dependency.new @a1.name, @a1.version
 
-    assert_equal [@gem1], @sic.search(dep)
+    assert_equal [@a1], @sic.search(dep)
   end
 
   def test_search_no_matches
-    si = Gem::SourceIndex.new @gem1.full_name => @gem1
-    cache_data = {
-      @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
-    }
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
+    cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
     @sic.instance_variable_set :@cache_data, cache_data
 
     assert_equal [], @sic.search(/nonexistent/)
   end
 
   def test_search_no_matches_in_source
-    si = Gem::SourceIndex.new @gem1.full_name => @gem1
-    cache_data = {
-      @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
-    }
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
+    cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
     @sic.instance_variable_set :@cache_data, cache_data
     Gem.sources.replace %w[more-gems.example.com]
 
@@ -235,13 +327,12 @@
   end
 
   def test_search_with_source
-    si = Gem::SourceIndex.new @gem1.full_name => @gem1
-    cache_data = {
-      @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
-    }
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
+    cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
     @sic.instance_variable_set :@cache_data, cache_data
 
-    assert_equal [[@gem1, @gem_repo]],
+    assert_equal [[@a1, @gem_repo]],
                  @sic.search_with_source(//)
   end
 
@@ -254,46 +345,102 @@
   end
 
   def test_write_cache
-    @sic.cache_data['key'] = 'new'
+    @sic.cache_data[@gem_repo] = @sice_new
     @sic.write_cache
 
-    assert_equal [['key', 'new']],
+    assert_equal [[@gem_repo, @sice_new]],
                  read_cache(@sic.system_cache_file).to_a.sort
-    assert_equal [['key', 'usr']],
+    assert_equal [[@gem_repo, @usr_sice]],
                  read_cache(@sic.user_cache_file).to_a.sort
   end
 
   def test_write_cache_user
     FileUtils.chmod 0444, @sic.system_cache_file
-    @sic.set_cache_data({'key' => 'new'})
+    @sic.set_cache_data({@gem_repo => @sice_new})
     @sic.update
     @sic.write_cache
+    @sic.instance_variable_set :@only_latest, false
 
-    assert_equal [['key', 'sys']], read_cache(@sic.system_cache_file).to_a.sort
-    assert_equal [['key', 'new']], read_cache(@sic.user_cache_file).to_a.sort
+    assert File.exist?(@sic.user_cache_file), 'user_cache_file'
+    assert File.exist?(@sic.latest_user_cache_file),
+           'latest_user_cache_file exists'
+
+    assert_equal [[@gem_repo, @sys_sice]],
+                 read_cache(@sic.system_cache_file).to_a.sort
+    assert_equal [[@gem_repo, @sice_new]],
+                 read_cache(@sic.user_cache_file).to_a.sort
   end
 
   def test_write_cache_user_from_scratch
     FileUtils.rm_rf @sic.user_cache_file
+    FileUtils.rm_rf @sic.latest_user_cache_file
+
     FileUtils.chmod 0444, @sic.system_cache_file
-    @sic.set_cache_data({'key' => 'new'})
+    FileUtils.chmod 0444, @sic.latest_system_cache_file
+
+    @si = Gem::SourceIndex.new
+    @si.add_specs @a1, @a2
+
+    @sice = Gem::SourceInfoCacheEntry.new @si, 0
+
+    @sic.set_cache_data({ @gem_repo => @sice })
     @sic.update
+
     @sic.write_cache
 
-    assert_equal [['key', 'sys']], read_cache(@sic.system_cache_file).to_a.sort
-    assert_equal [['key', 'new']], read_cache(@sic.user_cache_file).to_a.sort
+    assert File.exist?(@sic.user_cache_file), 'system_cache_file'
+    assert File.exist?(@sic.latest_user_cache_file),
+           'latest_system_cache_file'
+
+    user_cache_data = read_cache(@sic.user_cache_file).to_a.sort
+    assert_equal 1, user_cache_data.length, 'user_cache_data length'
+    user_cache_data = user_cache_data.first
+
+    assert_equal @gem_repo, user_cache_data.first
+
+    gems = user_cache_data.last.source_index.map { |_,spec| spec.full_name }
+    assert_equal [@a1.full_name, @a2.full_name], gems
+
+    user_cache_data = read_cache(@sic.latest_user_cache_file).to_a.sort
+    assert_equal 1, user_cache_data.length
+    user_cache_data = user_cache_data.first
+
+    assert_equal @gem_repo, user_cache_data.first
+
+    gems = user_cache_data.last.source_index.map { |_,spec| spec.full_name }
+    assert_equal [@a2.full_name], gems
   end
 
   def test_write_cache_user_no_directory
     FileUtils.rm_rf File.dirname(@sic.user_cache_file)
     FileUtils.chmod 0444, @sic.system_cache_file
-    @sic.set_cache_data({'key' => 'new'})
+    @sic.set_cache_data({ @gem_repo => @sice_new })
     @sic.update
     @sic.write_cache
 
-    assert_equal [['key','sys']], read_cache(@sic.system_cache_file).to_a.sort
-    assert_equal [['key','new']], read_cache(@sic.user_cache_file).to_a.sort
+    assert_equal [[@gem_repo, @sys_sice]],
+                 read_cache(@sic.system_cache_file).to_a.sort
+    assert_equal [[@gem_repo, @sys_sice]],
+                 read_cache(@sic.user_cache_file).to_a.sort
+    assert_equal [[@gem_repo, @sice_new]],
+                 read_cache(@sic.latest_user_cache_file).to_a.sort
   end
 
+  def test_write_cache_user_only_latest
+    FileUtils.chmod 0444, @sic.system_cache_file
+    @sic.set_cache_data({@gem_repo => @sice_new})
+    @sic.update
+    @sic.write_cache
+
+    assert File.exist?(@sic.user_cache_file), 'user_cache_file'
+    assert File.exist?(@sic.latest_user_cache_file),
+           'latest_user_cache_file exists'
+
+    assert_equal [[@gem_repo, @sys_sice]],
+                 read_cache(@sic.system_cache_file).to_a.sort
+    assert_equal [[@gem_repo, @sice_new]],
+                 read_cache(@sic.user_cache_file).to_a.sort
+  end
+
 end
 

Modified: MacRuby/trunk/test/rubygems/test_gem_source_info_cache_entry.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_source_info_cache_entry.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_gem_source_info_cache_entry.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -9,37 +9,68 @@
 
     util_setup_fake_fetcher
 
-    @si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
+    @si = Gem::SourceIndex.new
+    @si.add_spec @a1
     @sic_e = Gem::SourceInfoCacheEntry.new @si, @si.dump.size
   end
 
   def test_refresh
     @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] =
-      proc { raise Exception }
+      proc { raise }
     @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
 
-    assert_nothing_raised do
-      @sic_e.refresh @gem_repo
+    use_ui @ui do
+      @sic_e.refresh @gem_repo, true
     end
   end
 
+  def test_refresh_all
+    @si.add_spec @a2
+
+    a1_name = @a1.full_name
+    a2_name = @a2.full_name
+
+    @fetcher.data["#{@gem_repo}/quick/index.rz"] =
+        util_zip [a1_name, a2_name].join("\n")
+    @fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = util_zip a2_name
+    @fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a1_name}.gemspec.rz"] = util_zip Marshal.dump(@a1)
+    @fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a2_name}.gemspec.rz"] = util_zip Marshal.dump(@a2)
+    @fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] =
+      Marshal.dump @si
+
+    sic_e = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
+
+    use_ui @ui do
+      sic_e.refresh @gem_repo, false
+    end
+
+    assert_equal [a2_name], sic_e.source_index.map { |n,| n }.sort
+
+    use_ui @ui do
+      sic_e.refresh @gem_repo, true
+    end
+
+    assert_equal [a1_name, a2_name], sic_e.source_index.map { |n,| n }.sort
+  end
+
   def test_refresh_bad_uri
     assert_raise URI::BadURIError do
-      @sic_e.refresh 'gems.example.com'
+      @sic_e.refresh 'gems.example.com', true
     end
   end
 
   def test_refresh_update
-    si = Gem::SourceIndex.new @gem1.full_name => @gem1,
-                              @gem2.full_name => @gem2
+    si = Gem::SourceIndex.new
+    si.add_spec @a1
+    si.add_spec @b2
     @fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
 
     use_ui @ui do
-      @sic_e.refresh @gem_repo
+      @sic_e.refresh @gem_repo, true
     end
 
-    new_gem = @sic_e.source_index.specification(@gem2.full_name)
-    assert_equal @gem2.full_name, new_gem.full_name
+    new_gem = @sic_e.source_index.specification(@b2.full_name)
+    assert_equal @b2.full_name, new_gem.full_name
   end
 
 end

Added: MacRuby/trunk/test/rubygems/test_gem_uninstaller.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_gem_uninstaller.rb	                        (rev 0)
+++ MacRuby/trunk/test/rubygems/test_gem_uninstaller.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,43 @@
+require File.join(File.expand_path(File.dirname(__FILE__)),
+                  'gem_installer_test_case')
+require 'rubygems/uninstaller'
+
+class TestGemUninstaller < GemInstallerTestCase
+
+  def setup
+    super
+
+    ui = MockGemUi.new
+    util_setup_gem ui
+
+    use_ui ui do
+      @installer.install
+    end
+  end
+
+  def test_remove_executables_force_keep
+    uninstaller = Gem::Uninstaller.new nil, :executables => false
+
+    use_ui @ui do
+      uninstaller.remove_executables @spec
+    end
+
+    assert_equal true, File.exist?(File.join(@gemhome, 'bin', 'executable'))
+
+    assert_equal "Executables and scripts will remain installed.\n", @ui.output
+  end
+
+  def test_remove_executables_force_remove
+    uninstaller = Gem::Uninstaller.new nil, :executables => true
+
+    use_ui @ui do
+      uninstaller.remove_executables @spec
+    end
+
+    assert_equal "Removing executable\n", @ui.output
+
+    assert_equal false, File.exist?(File.join(@gemhome, 'bin', 'executable'))
+  end
+
+end
+

Deleted: MacRuby/trunk/test/rubygems/test_open_uri.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_open_uri.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_open_uri.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,13 +0,0 @@
-require 'test/unit'
-require 'rubygems/gem_open_uri'
-
-class TestOpenURI < Test::Unit::TestCase
-
-  def test_open_uri_not_broken
-    assert_nothing_raised do
-      open __FILE__ do end
-    end
-  end
-
-end
-

Deleted: MacRuby/trunk/test/rubygems/test_package.rb
===================================================================
--- MacRuby/trunk/test/rubygems/test_package.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/rubygems/test_package.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,610 +0,0 @@
-#--
-# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
-# All rights reserved.
-# See LICENSE.txt for permissions.
-#++
-
-require 'test/unit'
-require 'stringio'
-require 'fileutils'
-
-require 'rubygems'
-require 'rubygems/package'
-
-class File
-
-  # straight from setup.rb
-  def self.dir?(path)
-    # for corrupted windows stat()
-    File.directory?((path[-1,1] == '/') ? path : path + '/')
-  end
-
-  def self.read_b(name)
-    File.open(name, "rb"){|f| f.read}
-  end
-
-end
-
-class TarTestCase < Test::Unit::TestCase
-
-  undef_method :default_test if instance_methods.include? 'default_test' or
-                                instance_methods.include? :default_test
-
-  def assert_headers_equal(h1, h2)
-    fields = %w[name 100 mode 8 uid 8 gid 8 size 12 mtime 12 checksum 8
-                    typeflag 1 linkname 100 magic 6 version 2 uname 32 
-                    gname 32 devmajor 8 devminor 8 prefix 155]
-    offset = 0
-    until fields.empty?
-      name = fields.shift
-      length = fields.shift.to_i
-      if name == "checksum"
-        chksum_off = offset
-        offset += length
-        next
-      end
-      assert_equal(h1[offset, length], h2[offset, length], 
-                         "Field #{name} of the tar header differs.")
-      offset += length
-    end
-    assert_equal(h1[chksum_off, 8], h2[chksum_off, 8])
-  end
-
-  def tar_file_header(fname, dname, mode, length)
-    h = header("0", fname, dname, length, mode)
-    checksum = calc_checksum(h)
-    header("0", fname, dname, length, mode, checksum)
-  end
-
-  def tar_dir_header(name, prefix, mode)
-    h = header("5", name, prefix, 0, mode)
-    checksum = calc_checksum(h)
-    header("5", name, prefix, 0, mode, checksum)
-  end
-
-  def header(type, fname, dname, length, mode, checksum = nil)
-    checksum ||= " " * 8
-
-    arr = [                  # struct tarfile_entry_posix
-      ASCIIZ(fname, 100),    # char name[100];     ASCII + (Z unless filled)
-      Z(to_oct(mode, 7)),    # char mode[8];       0 padded, octal null
-      Z(to_oct(0, 7)),       # char uid[8];        ditto
-      Z(to_oct(0, 7)),       # char gid[8];        ditto
-      Z(to_oct(length, 11)), # char size[12];      0 padded, octal, null
-      Z(to_oct(0, 11)),      # char mtime[12];     0 padded, octal, null
-      checksum,              # char checksum[8];   0 padded, octal, null, space
-      type,                  # char typeflag[1];   file: "0"  dir: "5"
-      "\0" * 100,            # char linkname[100]; ASCII + (Z unless filled)
-      "ustar\0",             # char magic[6];      "ustar\0"
-      "00",                  # char version[2];    "00"
-      ASCIIZ("wheel", 32),   # char uname[32];     ASCIIZ
-      ASCIIZ("wheel", 32),   # char gname[32];     ASCIIZ
-      Z(to_oct(0, 7)),       # char devmajor[8];   0 padded, octal, null
-      Z(to_oct(0, 7)),       # char devminor[8];   0 padded, octal, null
-      ASCIIZ(dname, 155)     # char prefix[155];   ASCII + (Z unless filled)
-    ]
-
-    format = "C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155"
-    h = if RUBY_VERSION >= "1.9" then
-          arr.join
-        else
-          arr = arr.join("").split(//).map{|x| x[0]}
-          arr.pack format
-        end
-    ret = h + "\0" * (512 - h.size)
-    assert_equal(512, ret.size)
-    ret
-  end
-
-  def calc_checksum(header)
-    sum = header.unpack("C*").inject{|s,a| s + a}
-    SP(Z(to_oct(sum, 6)))
-  end
-
-  def to_oct(n, pad_size)
-        "%0#{pad_size}o" % n
-  end
-
-  def ASCIIZ(str, length)
-    str + "\0" * (length - str.length)
-  end
-
-  def SP(s)
-    s + " "
-  end
-
-  def Z(s)
-    s + "\0"
-  end
-
-  def SP_Z(s)
-    s + " \0"
-  end
-
-end
-
-class TestTarHeader < TarTestCase
-
-  def test_arguments_are_checked
-    e = ArgumentError
-    gpth = Gem::Package::TarHeader
-    assert_raises(e) { gpth.new :name=>"", :size=>"", :mode=>"" }
-    assert_raises(e) { gpth.new :name=>"", :size=>"", :prefix=>"" }
-    assert_raises(e) { gpth.new :name=>"", :prefix=>"", :mode=>"" }
-    assert_raises(e) { gpth.new :prefix=>"", :size=>"", :mode=>"" }
-  end
-
-  def test_basic_headers
-    header = Gem::Package::TarHeader.new(:name => "bla", :mode => 012345,
-                                         :size => 10, :prefix => "").to_s
-    assert_headers_equal(tar_file_header("bla", "", 012345, 10), header.to_s)
-    header = Gem::Package::TarHeader.new(:name => "bla", :mode => 012345,
-                                         :size => 0, :prefix => "",
-                                         :typeflag => "5" ).to_s
-    assert_headers_equal(tar_dir_header("bla", "", 012345), header)
-  end
-
-  def test_long_name_works
-    header = Gem::Package::TarHeader.new(:name => "a" * 100, :mode => 012345, 
-                                         :size => 10, :prefix => "").to_s
-    assert_headers_equal(tar_file_header("a" * 100, "", 012345, 10), header)
-
-    header = Gem::Package::TarHeader.new(:name => "a" * 100, :mode => 012345,
-                                         :size => 10, :prefix => "bb" * 60).to_s
-    assert_headers_equal(tar_file_header("a" * 100, "bb" * 60, 012345, 10),
-                         header)
-  end
-
-  def test_new_from_stream
-    header = tar_file_header("a" * 100, "", 012345, 10)
-    h = nil
-    header = StringIO.new header
-    assert_nothing_raised{ h = Gem::Package::TarHeader.new_from_stream header }
-    assert_equal("a" * 100, h.name)
-    assert_equal(012345, h.mode)
-    assert_equal(10, h.size)
-    assert_equal("", h.prefix)
-    assert_equal("ustar", h.magic)
-  end
-
-end
-
-class TestTarInput < TarTestCase
-
-  # Sometimes the setgid bit doesn't take.  Don't know if this
-  # is a problem on all systems, or just some.  But for now, we
-  # will ignore it in the tests.
-  SETGID_BIT = 02000
-
-  def setup
-    FileUtils.mkdir_p "data__"
-    inner_tar = tar_file_header("bla", "", 0612, 10)
-    inner_tar += "0123456789" + "\0" * 502
-    inner_tar += tar_file_header("foo", "", 0636, 5)
-    inner_tar += "01234" + "\0" * 507
-    inner_tar += tar_dir_header("__dir__", "", 0600)
-    inner_tar += "\0" * 1024
-    str = StringIO.new ""
-    begin
-      os = Zlib::GzipWriter.new str
-      os.write inner_tar
-    ensure
-      os.finish
-    end
-    str.rewind
-    File.open("data__/bla.tar", "wb") do |f|
-      f.write tar_file_header("data.tar.gz", "", 0644, str.string.size)
-      f.write str.string
-      f.write "\0" * ((512 - (str.string.size % 512)) % 512 )
-      @spec = Gem::Specification.new do |spec|
-        spec.author = "Mauricio :)"
-      end
-      meta = @spec.to_yaml
-      f.write tar_file_header("metadata", "", 0644, meta.size)
-      f.write meta + "\0" * (1024 - meta.size) 
-      f.write "\0" * 1024
-    end
-    @file = "data__/bla.tar"
-    @entry_names = %w{bla foo __dir__}
-    @entry_sizes = [10, 5, 0]
-    #FIXME: are these modes system dependent?
-    @entry_modes = [0100612, 0100636, 040600]
-    @entry_files = %w{data__/bla data__/foo}
-    @entry_contents = %w[0123456789 01234]
-  end
-
-  def teardown
-    #            FileUtils.rm_rf "data__"
-  end
-
-  def test_each_works
-    Gem::Package::TarInput.open(@file) do |is|
-      count = 0
-
-      is.each_with_index do |entry, i|
-        count = i
-
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        assert_equal(@entry_names[i], entry.name)
-        assert_equal(@entry_sizes[i], entry.size)
-      end
-
-      assert_equal 2, count
-
-      assert_equal @spec, is.metadata
-    end
-  end
-
-  def test_extract_entry_works
-    Gem::Package::TarInput.open(@file) do |is|
-      assert_equal @spec, is.metadata
-      count = 0
-
-      is.each_with_index do |entry, i|
-        count = i
-        is.extract_entry "data__", entry
-        name = File.join("data__", entry.name)
-
-        if entry.is_directory?
-          assert File.dir?(name)
-        else
-          assert File.file?(name) 
-          assert_equal(@entry_sizes[i], File.stat(name).size)
-          #FIXME: win32? !!
-        end
-
-        unless ::Config::CONFIG["arch"] =~ /msdos|win32/i
-          assert_equal(@entry_modes[i],
-                       File.stat(name).mode & (~SETGID_BIT))
-        end
-      end
-
-      assert_equal 2, count
-    end
-
-    @entry_files.each_with_index do |x, i|
-      assert(File.file?(x))
-      assert_equal(@entry_contents[i], File.read_b(x))
-    end
-  end
-
-end
-
-class TestTarOutput < TarTestCase
-
-  def setup
-    FileUtils.mkdir_p "data__", :verbose=>false
-    @file = "data__/bla2.tar"
-  end
-
-  def teardown
-    FileUtils.rm_rf "data__"
-  end
-
-  def test_file_looks_good
-    Gem::Package::TarOutput.open(@file) do |os|
-      os.metadata = "bla".to_yaml
-    end
-    f = File.open(@file, "rb")
-    Gem::Package::TarReader.new(f) do |is|
-      i = 0
-      is.each do |entry|
-        case i
-        when 0
-          assert_equal("data.tar.gz", entry.name)
-        when 1
-          assert_equal("metadata.gz", entry.name)
-          gzis = Zlib::GzipReader.new entry
-          assert_equal("bla".to_yaml, gzis.read)
-          gzis.close
-        end
-        i += 1
-      end
-      assert_equal(2, i)
-    end
-  ensure
-    f.close
-  end
-
-end
-
-class TestTarReader < TarTestCase
-
-  def test_eof_works
-    str = tar_file_header("bar", "baz", 0644, 0)
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      is.each_entry do |entry|
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        data = entry.read
-        assert_equal(nil, data)
-        assert_equal(nil, entry.read(10))
-        assert_equal(nil, entry.read)
-        assert_equal(nil, entry.getc)
-        assert_equal(true, entry.eof?)
-      end
-    end
-    str = tar_dir_header("foo", "bar", 012345)
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      is.each_entry do |entry|
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        data = entry.read
-        assert_equal(nil, data)
-        assert_equal(nil, entry.read(10))
-        assert_equal(nil, entry.read)
-        assert_equal(nil, entry.getc)
-        assert_equal(true, entry.eof?)
-      end
-    end
-    str = tar_dir_header("foo", "bar", 012345)
-    str += tar_file_header("bar", "baz", 0644, 0)
-    str += tar_file_header("bar", "baz", 0644, 0)
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      is.each_entry do |entry|
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        data = entry.read
-        assert_equal(nil, data)
-        assert_equal(nil, entry.read(10))
-        assert_equal(nil, entry.read)
-        assert_equal(nil, entry.getc)
-        assert_equal(true, entry.eof?)
-      end
-    end
-  end
-
-  def test_multiple_entries
-    str = tar_file_header("lib/foo", "", 010644, 10) + "\0" * 512
-    str += tar_file_header("bar", "baz", 0644, 0)
-    str += tar_dir_header("foo", "bar", 012345)
-    str += "\0" * 1024
-    names = %w[lib/foo bar foo]
-    prefixes = ["", "baz", "bar"]
-    modes = [010644, 0644, 012345]
-    sizes = [10, 0, 0]
-    isdir = [false, false, true]
-    isfile = [true, true, false]
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      i = 0
-      is.each_entry do |entry|
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        assert_equal(names[i], entry.name)
-        assert_equal(prefixes[i], entry.prefix)
-        assert_equal(sizes[i], entry.size)
-        assert_equal(modes[i], entry.mode)
-        assert_equal(isdir[i], entry.is_directory?)
-        assert_equal(isfile[i], entry.is_file?)
-        if prefixes[i] != ""
-          assert_equal(File.join(prefixes[i], names[i]),
-                       entry.full_name)
-        else
-          assert_equal(names[i], entry.name)
-        end
-        i += 1
-      end
-      assert_equal(names.size, i) 
-    end
-  end
-
-  def test_read_works
-    contents = ('a'..'z').inject(""){|s,x| s << x * 100}
-    str = tar_file_header("lib/foo", "", 010644, contents.size) + contents 
-    str += "\0" * (512 - (str.size % 512))
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      is.each_entry do |entry|
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        data = entry.read(3000) # bigger than contents.size
-        assert_equal(contents, data)
-        assert_equal(true, entry.eof?)
-      end
-    end
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      is.each_entry do |entry|
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        data = entry.read(100)
-        (entry.size - data.size).times {|i| data << entry.getc.chr }
-        assert_equal(contents, data)
-        assert_equal(nil, entry.read(10))
-        assert_equal(true, entry.eof?)
-      end
-    end
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      is.each_entry do |entry|
-        assert_kind_of(Gem::Package::TarReader::Entry, entry)
-        data = entry.read
-        assert_equal(contents, data)
-        assert_equal(nil, entry.read(10))
-        assert_equal(nil, entry.read)
-        assert_equal(nil, entry.getc)
-        assert_equal(true, entry.eof?)
-      end
-    end
-  end
-
-  def test_rewind_entry_works
-    content = ('a'..'z').to_a.join(" ")
-    str = tar_file_header("lib/foo", "", 010644, content.size) + content + 
-            "\0" * (512 - content.size)
-    str << "\0" * 1024
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      is.each_entry do |entry|
-        3.times do 
-          entry.rewind
-          assert_equal(content, entry.read)
-          assert_equal(content.size, entry.pos)
-        end
-      end
-    end
-  end
-
-  def test_rewind_works
-    content = ('a'..'z').to_a.join(" ")
-    str = tar_file_header("lib/foo", "", 010644, content.size) + content + 
-            "\0" * (512 - content.size)
-    str << "\0" * 1024
-    Gem::Package::TarReader.new(StringIO.new(str)) do |is|
-      3.times do
-        is.rewind
-        i = 0
-        is.each_entry do |entry|
-          assert_equal(content, entry.read)
-          i += 1
-        end
-        assert_equal(1, i)
-      end
-    end
-  end
-
-end
-
-class TestTarWriter < TarTestCase
-
-  class DummyIO
-    attr_reader :data
-    def initialize
-      @data = ""
-    end
-    def write(dat)
-      data << dat
-      dat.size
-    end
-    def reset
-      @data = ""
-    end
-  end
-
-  def setup
-    @data = "a" * 10
-    @dummyos = DummyIO.new
-    @os = Gem::Package::TarWriter.new(@dummyos)
-  end
-
-  def teardown
-    @os.close
-  end
-
-  def test_add_file
-    dummyos = StringIO.new
-    class << dummyos
-      def method_missing(meth, *a)
-        self.string.send(meth, *a)
-      end
-    end
-
-    content1 = ('a'..'z').to_a.join("")  # 26
-    content2 = ('aa'..'zz').to_a.join("") # 1352
-
-    Gem::Package::TarWriter.new(dummyos) do |os|
-      os.add_file("lib/foo/bar", 0644) {|f| f.write "a" * 10 }
-      os.add_file("lib/bar/baz", 0644) {|f| f.write content1 }
-      os.add_file("lib/bar/baz", 0644) {|f| f.write content2 }
-      os.add_file("lib/bar/baz", 0644) {|f| }
-    end
-
-    assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 10),
-                         dummyos[0,512])
-    assert_equal("a" * 10 + "\0" * 502, dummyos[512,512])
-    offset = 512 * 2
-    [content1, content2, ""].each do |data|
-      assert_headers_equal(tar_file_header("lib/bar/baz", "", 0644,
-                                           data.size),
-                                           dummyos[offset,512])
-      offset += 512
-      until !data || data == ""
-        chunk = data[0,512]
-        data[0,512] = ""
-        assert_equal(chunk + "\0" * (512-chunk.size), 
-                     dummyos[offset,512])
-                     offset += 512
-      end
-    end
-    assert_equal("\0" * 1024, dummyos[offset,1024])
-  end
-
-  def test_add_file_simple
-    @dummyos.reset
-    Gem::Package::TarWriter.new(@dummyos) do |os|
-      os.add_file_simple("lib/foo/bar", 0644, 10) {|f| f.write "a" * 10 }
-      os.add_file_simple("lib/bar/baz", 0644, 100) {|f| f.write "fillme"}
-    end
-    assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 10),
-                         @dummyos.data[0,512])
-    assert_equal("a" * 10 + "\0" * 502, @dummyos.data[512,512])
-    assert_headers_equal(tar_file_header("lib/bar/baz", "", 0644, 100), 
-                         @dummyos.data[512*2,512])
-    assert_equal("fillme" + "\0" * 506, @dummyos.data[512*3,512])
-    assert_equal("\0" * 512, @dummyos.data[512*4, 512])
-    assert_equal("\0" * 512, @dummyos.data[512*5, 512])
-  end
-
-  def test_add_file_tests_seekability
-    assert_raises(Gem::Package::NonSeekableIO) do 
-      @os.add_file("libdfdsfd", 0644) {|f| }
-    end
-  end
-
-  def test_file_name_is_split_correctly
-    # test insane file lengths, and
-    #  a{100}/b{155}, etc
-    @dummyos.reset
-    names = ["a" * 155 + '/' + "b" * 100, "a" * 151 + "/" + ("qwer/" * 19) + "bla" ]
-    o_names = ["b" * 100, "qwer/" * 19 + "bla"]
-    o_prefixes = ["a" * 155, "a" * 151]
-    names.each {|name| @os.add_file_simple(name, 0644, 10) { } }
-    o_names.each_with_index do |nam, i|
-      assert_headers_equal(tar_file_header(nam, o_prefixes[i], 0644, 10),
-                           @dummyos.data[2*i*512,512])
-    end
-    assert_raises(Gem::Package::TooLongFileName) do
-      @os.add_file_simple(File.join("a" * 152, "b" * 10, "a" * 92), 0644,10) {}
-    end
-    assert_raises(Gem::Package::TooLongFileName) do
-      @os.add_file_simple(File.join("a" * 162, "b" * 10), 0644,10) {}
-    end
-    assert_raises(Gem::Package::TooLongFileName) do
-      @os.add_file_simple(File.join("a" * 10, "b" * 110), 0644,10) {}
-    end
-  end
-
-  def test_file_size_is_checked
-    @dummyos.reset
-    assert_raises(Gem::Package::TarWriter::FileOverflow) do 
-      @os.add_file_simple("lib/foo/bar", 0644, 10) {|f| f.write "1" * 100}
-    end
-    assert_nothing_raised do
-      @os.add_file_simple("lib/foo/bar", 0644, 10) {|f| }
-    end
-  end
-
-  def test_write_data
-    @dummyos.reset
-    @os.add_file_simple("lib/foo/bar", 0644, 10) { |f| f.write @data }
-    @os.flush
-    assert_equal(@data + ("\0" * (512- at data.size)),
-                 @dummyos.data[512,512])
-  end
-
-  def test_write_header
-    @dummyos.reset
-    @os.add_file_simple("lib/foo/bar", 0644, 0) { |f|  }
-    @os.flush
-    assert_headers_equal(tar_file_header("lib/foo/bar", "", 0644, 0),
-                         @dummyos.data[0,512])
-    @dummyos.reset
-    @os.mkdir("lib/foo", 0644)
-    assert_headers_equal(tar_dir_header("lib/foo", "", 0644),
-                         @dummyos.data[0,512])
-    @os.mkdir("lib/bar", 0644)
-    assert_headers_equal(tar_dir_header("lib/bar", "", 0644),
-                         @dummyos.data[512*1,512])
-  end
-
-  def test_write_operations_fail_after_closed
-    @dummyos.reset
-    @os.add_file_simple("sadd", 0644, 20) { |f| }
-    @os.close
-    assert_raises(Gem::Package::ClosedIO) { @os.flush }
-    assert_raises(Gem::Package::ClosedIO) { @os.add_file("dfdsf", 0644){} }
-    assert_raises(Gem::Package::ClosedIO) { @os.mkdir "sdfdsf", 0644 }
-  end
-
-end
-

Modified: MacRuby/trunk/test/stringio/test_stringio.rb
===================================================================
--- MacRuby/trunk/test/stringio/test_stringio.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/stringio/test_stringio.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -40,4 +40,29 @@
     end
     assert_equal("hacker\nother ruby\n", stringio.string, "[ruby-core:3836]")
   end
+
+  def test_gets
+    assert_equal(nil, StringIO.new("").gets)
+    assert_equal("\n", StringIO.new("\n").gets)
+    assert_equal("a\n", StringIO.new("a\n").gets)
+    assert_equal("a\n", StringIO.new("a\nb\n").gets)
+    assert_equal("a", StringIO.new("a").gets)
+    assert_equal("a\n", StringIO.new("a\nb").gets)
+    assert_equal("abc\n", StringIO.new("abc\n\ndef\n").gets)
+    assert_equal("abc\n\ndef\n", StringIO.new("abc\n\ndef\n").gets(nil))
+    assert_equal("abc\n\n", StringIO.new("abc\n\ndef\n").gets(""))
+  end
+
+  def test_readlines
+    assert_equal([], StringIO.new("").readlines)
+    assert_equal(["\n"], StringIO.new("\n").readlines)
+    assert_equal(["a\n"], StringIO.new("a\n").readlines)
+    assert_equal(["a\n", "b\n"], StringIO.new("a\nb\n").readlines)
+    assert_equal(["a"], StringIO.new("a").readlines)
+    assert_equal(["a\n", "b"], StringIO.new("a\nb").readlines)
+    assert_equal(["abc\n", "\n", "def\n"], StringIO.new("abc\n\ndef\n").readlines)
+    assert_equal(["abc\n\ndef\n"], StringIO.new("abc\n\ndef\n").readlines(nil), "[ruby-dev:34591]")
+    assert_equal(["abc\n\n", "def\n"], StringIO.new("abc\n\ndef\n").readlines(""))
+  end
+
 end

Modified: MacRuby/trunk/test/strscan/test_stringscanner.rb
===================================================================
--- MacRuby/trunk/test/strscan/test_stringscanner.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/strscan/test_stringscanner.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -545,7 +545,7 @@
   def test_generic_regexp
     ss = StringScanner.new("\xA1\xA2".force_encoding("euc-jp"))
     t = ss.scan(/./)
-    assert_equal("\xa1\xa1".force_encoding("euc-jp"), t)
+    assert_equal("\xa1\xa2".force_encoding("euc-jp"), t)
   end
 
 end

Deleted: MacRuby/trunk/test/test_generator.rb
===================================================================
--- MacRuby/trunk/test/test_generator.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/test_generator.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,4 +0,0 @@
-require 'pathname'
-require Pathname.new(__FILE__).dirname.join('inlinetest.rb')
-target = __FILE__[/test_(.*\.rb)$/, 1]
-InlineTest.loadtest__END__part(target)

Added: MacRuby/trunk/test/test_pstore.rb
===================================================================
--- MacRuby/trunk/test/test_pstore.rb	                        (rev 0)
+++ MacRuby/trunk/test/test_pstore.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,74 @@
+require 'test/unit'
+require 'pstore'
+
+class PStoreTest < Test::Unit::TestCase
+  def setup
+    @pstore_file = "pstore.tmp.#{Process.pid}"
+    @pstore = PStore.new(@pstore_file)
+  end
+
+  def teardown
+    File.unlink(@pstore_file) rescue nil
+  end
+
+  def test_opening_new_file_in_readonly_mode_should_result_in_empty_values
+    @pstore.transaction(true) do
+      assert_nil @pstore[:foo]
+      assert_nil @pstore[:bar]
+    end
+  end
+  
+  def test_opening_new_file_in_readwrite_mode_should_result_in_empty_values
+    @pstore.transaction do
+      assert_nil @pstore[:foo]
+      assert_nil @pstore[:bar]
+    end
+  end
+  
+  def test_data_should_be_loaded_correctly_when_in_readonly_mode
+    @pstore.transaction do
+      @pstore[:foo] = "bar"
+    end
+    @pstore.transaction(true) do
+      assert_equal "bar", @pstore[:foo]
+    end
+  end
+  
+  def test_data_should_be_loaded_correctly_when_in_readwrite_mode
+    @pstore.transaction do
+      @pstore[:foo] = "bar"
+    end
+    @pstore.transaction do
+      assert_equal "bar", @pstore[:foo]
+    end
+  end
+  
+  def test_changes_after_commit_are_discarded
+    @pstore.transaction do
+      @pstore[:foo] = "bar"
+      @pstore.commit
+      @pstore[:foo] = "baz"
+    end
+    @pstore.transaction(true) do
+      assert_equal "bar", @pstore[:foo]
+    end
+  end
+  
+  def test_changes_are_not_written_on_abort
+    @pstore.transaction do
+      @pstore[:foo] = "bar"
+      @pstore.abort
+    end
+    @pstore.transaction(true) do
+      assert_nil @pstore[:foo]
+    end
+  end
+  
+  def test_writing_inside_readonly_transaction_raises_error
+    assert_raise(PStore::Error) do
+      @pstore.transaction(true) do
+        @pstore[:foo] = "bar"
+      end
+    end
+  end
+end

Modified: MacRuby/trunk/test/webrick/test_filehandler.rb
===================================================================
--- MacRuby/trunk/test/webrick/test_filehandler.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/test/webrick/test_filehandler.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,6 +1,7 @@
 require "test/unit"
 require "webrick"
 require "stringio"
+require File.join(File.dirname(__FILE__), "utils.rb")
 
 class WEBrick::TestFileHandler < Test::Unit::TestCase
   def default_file_handler(filename)
@@ -66,4 +67,62 @@
     res = make_range_response(filename, "bytes=0-0, -2")
     assert_match(%r{^multipart/byteranges}, res["content-type"])
   end
+
+  def test_filehandler
+    config = { :DocumentRoot => File.dirname(__FILE__), }
+    this_file = File.basename(__FILE__)
+    TestWEBrick.start_httpserver(config) do |server, addr, port|
+      http = Net::HTTP.new(addr, port)
+      req = Net::HTTP::Get.new("/")
+      http.request(req){|res|
+        assert_equal("200", res.code)
+        assert_equal("text/html", res.content_type)
+        assert_match(/HREF="#{this_file}"/, res.body)
+      }
+      req = Net::HTTP::Get.new("/#{this_file}")
+      http.request(req){|res|
+        assert_equal("200", res.code)
+        assert_equal("text/plain", res.content_type)
+        assert_equal(File.read(__FILE__), res.body)
+      }
+    end
+  end
+
+  def test_non_disclosure_name
+    config = { :DocumentRoot => File.dirname(__FILE__), }
+    this_file = File.basename(__FILE__)
+    TestWEBrick.start_httpserver(config) do |server, addr, port|
+      http = Net::HTTP.new(addr, port)
+      doc_root_opts = server[:DocumentRootOptions]
+      doc_root_opts[:NondisclosureName] = %w(.ht* *~ test_*)
+      req = Net::HTTP::Get.new("/")
+      http.request(req){|res|
+        assert_equal("200", res.code)
+        assert_equal("text/html", res.content_type)
+        assert_no_match(/HREF="#{File.basename(__FILE__)}"/, res.body)
+      }
+      req = Net::HTTP::Get.new("/#{this_file}")
+      http.request(req){|res|
+        assert_equal("404", res.code)
+      }
+      doc_root_opts[:NondisclosureName] = %w(.ht* *~ TEST_*)
+      http.request(req){|res|
+        assert_equal("404", res.code)
+      }
+    end
+  end
+
+  def test_directory_traversal
+    config = { :DocumentRoot => File.dirname(__FILE__), }
+    this_file = File.basename(__FILE__)
+    TestWEBrick.start_httpserver(config) do |server, addr, port|
+      http = Net::HTTP.new(addr, port)
+      req = Net::HTTP::Get.new("/../../")
+      http.request(req){|res| assert_equal("400", res.code) }
+      req = Net::HTTP::Get.new(
+        "/..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5cboot.ini"
+      )
+      http.request(req){|res| assert_equal("404", res.code) }
+    end
+  end
 end

Added: MacRuby/trunk/test/xmlrpc/test_cookie.rb
===================================================================
--- MacRuby/trunk/test/xmlrpc/test_cookie.rb	                        (rev 0)
+++ MacRuby/trunk/test/xmlrpc/test_cookie.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,96 @@
+require 'test/unit'
+require 'time'
+require 'webrick'
+require File.join(File.dirname(__FILE__), 'webrick_testing')
+require "xmlrpc/server"
+require 'xmlrpc/client'
+
+class TestCookie < Test::Unit::TestCase
+  include WEBrick_Testing
+
+  def create_servlet
+    s = XMLRPC::WEBrickServlet.new
+
+    def s.logged_in_users
+      @logged_in_users ||= {}
+    end
+    def s.request
+      @request
+    end
+    def s.response
+      @response
+    end
+    def s.service(request, response)
+      @request = request
+      @response = response
+      super
+    ensure
+      @request = nil
+      @response = nil
+    end
+
+    key = Time.now.to_i.to_s
+    valid_user = "valid-user"
+    s.add_handler("test.login") do |user, password|
+      ok = (user == valid_user and password == "secret")
+      if ok
+        s.logged_in_users[key] = user
+        expires = (Time.now + 60 * 60).httpdate
+        cookies = s.response.cookies
+        cookies << "key=\"#{key}\"; path=\"/RPC2\"; expires=#{expires}"
+        cookies << "user=\"#{user}\"; path=\"/RPC2\""
+      end
+      ok
+    end
+
+    s.add_handler("test.require_authenticate_echo") do |string|
+      cookies = {}
+      s.request.cookies.each do |cookie|
+        cookies[cookie.name] = cookie.value
+      end
+      if cookies == {"key" => key, "user" => valid_user}
+        string
+      else
+        raise XMLRPC::FaultException.new(29, "Authentication required")
+      end
+    end
+
+    s.set_default_handler do |name, *args|
+      raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
+            " or wrong number of parameters!")
+    end
+
+    s.add_introspection
+
+    s
+  end
+
+  def setup_http_server(port)
+    option = {:Port => port}
+
+    start_server(option) {|w| w.mount('/RPC2', create_servlet) }
+
+    @s = XMLRPC::Client.new3(:port => port)
+  end
+
+  PORT = 8070
+  def test_cookie
+    begin
+      setup_http_server(PORT)
+      do_test
+    ensure
+      stop_server
+    end
+  end
+
+  def do_test
+    assert(!@s.call("test.login", "invalid-user", "invalid-password"))
+    exception = assert_raise(XMLRPC::FaultException) do
+      @s.call("test.require_authenticate_echo", "Hello")
+    end
+    assert_equal(29, exception.faultCode)
+
+    assert(@s.call("test.login", "valid-user", "secret"))
+    assert_equal("Hello", @s.call("test.require_authenticate_echo", "Hello"))
+  end
+end

Added: MacRuby/trunk/test/yaml/test_yamlstore.rb
===================================================================
--- MacRuby/trunk/test/yaml/test_yamlstore.rb	                        (rev 0)
+++ MacRuby/trunk/test/yaml/test_yamlstore.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -0,0 +1,74 @@
+require 'test/unit'
+require 'yaml/store'
+
+class YAMLStoreTest < Test::Unit::TestCase
+  def setup
+    @yamlstore_file = "yamlstore.tmp.#{Process.pid}"
+    @yamlstore = YAML::Store.new(@yamlstore_file)
+  end
+
+  def teardown
+    File.unlink(@yamlstore_file) rescue nil
+  end
+
+  def test_opening_new_file_in_readonly_mode_should_result_in_empty_values
+    @yamlstore.transaction(true) do
+      assert_nil @yamlstore[:foo]
+      assert_nil @yamlstore[:bar]
+    end
+  end
+  
+  def test_opening_new_file_in_readwrite_mode_should_result_in_empty_values
+    @yamlstore.transaction do
+      assert_nil @yamlstore[:foo]
+      assert_nil @yamlstore[:bar]
+    end
+  end
+  
+  def test_data_should_be_loaded_correctly_when_in_readonly_mode
+    @yamlstore.transaction do
+      @yamlstore[:foo] = "bar"
+    end
+    @yamlstore.transaction(true) do
+      assert_equal "bar", @yamlstore[:foo]
+    end
+  end
+  
+  def test_data_should_be_loaded_correctly_when_in_readwrite_mode
+    @yamlstore.transaction do
+      @yamlstore[:foo] = "bar"
+    end
+    @yamlstore.transaction do
+      assert_equal "bar", @yamlstore[:foo]
+    end
+  end
+  
+  def test_changes_after_commit_are_discarded
+    @yamlstore.transaction do
+      @yamlstore[:foo] = "bar"
+      @yamlstore.commit
+      @yamlstore[:foo] = "baz"
+    end
+    @yamlstore.transaction(true) do
+      assert_equal "bar", @yamlstore[:foo]
+    end
+  end
+  
+  def test_changes_are_not_written_on_abort
+    @yamlstore.transaction do
+      @yamlstore[:foo] = "bar"
+      @yamlstore.abort
+    end
+    @yamlstore.transaction(true) do
+      assert_nil @yamlstore[:foo]
+    end
+  end
+  
+  def test_writing_inside_readonly_transaction_raises_error
+    assert_raise(PStore::Error) do
+      @yamlstore.transaction(true) do
+        @yamlstore[:foo] = "bar"
+      end
+    end
+  end
+end

Modified: MacRuby/trunk/thread.c
===================================================================
--- MacRuby/trunk/thread.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/thread.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   thread.c -
 
-  $Author: matz $
+  $Author: akr $
 
   Copyright (C) 2004-2007 Koichi Sasada
 
@@ -70,9 +70,9 @@
 static volatile int system_working = 1;
 
 inline static void
-st_delete_wrap(st_table * table, VALUE key)
+st_delete_wrap(st_table *table, st_data_t key)
 {
-    st_delete(table, (st_data_t *) & key, 0);
+    st_delete(table, &key, 0);
 }
 
 /********************************************************************************/
@@ -273,7 +273,7 @@
 }
 
 static void
-thread_cleanup_func(void *th_ptr)
+thread_cleanup_func_before_exec(void *th_ptr)
 {
     rb_thread_t *th = th_ptr;
     th->status = THREAD_KILLED;
@@ -281,6 +281,13 @@
 #ifdef __ia64
     th->machine_register_stack_start = th->machine_register_stack_end = 0;
 #endif
+}
+
+static void
+thread_cleanup_func(void *th_ptr)
+{
+    rb_thread_t *th = th_ptr;
+    thread_cleanup_func_before_exec(th_ptr);
     native_thread_destroy(th);
 }
 
@@ -298,10 +305,12 @@
     rb_thread_t *main_th;
     VALUE errinfo = Qnil;
 
+#if !WITH_OBJC
     th->machine_stack_start = stack_start;
 #ifdef __ia64
     th->machine_register_stack_start = register_stack_start;
 #endif
+#endif
     thread_debug("thread start: %p\n", th);
 
     native_mutex_lock(&th->vm->global_interpreter_lock);
@@ -461,20 +470,42 @@
 /* +infty, for this purpose */
 #define DELAY_INFTY 1E30
 
+struct join_arg {
+    rb_thread_t *target, *waiting;
+    double limit;
+    int forever;
+};
+
 static VALUE
-thread_join(rb_thread_t *target_th, double delay)
+remove_from_join_list(VALUE arg)
 {
-    rb_thread_t *th = GET_THREAD();
-    double now, limit = timeofday() + delay;
+    struct join_arg *p = (struct join_arg *)arg;
+    rb_thread_t *target_th = p->target, *th = p->waiting;
 
-    thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
+    if (target_th->status != THREAD_KILLED) {
+	rb_thread_t **pth = &target_th->join_list_head;
 
-    if (target_th->status != THREAD_KILLED) {
-	th->join_list_next = target_th->join_list_head;
-	target_th->join_list_head = th;
+	while (*pth) {
+	    if (*pth == th) {
+		*pth = th->join_list_next;
+		break;
+	    }
+	    pth = &(*pth)->join_list_next;
+	}
     }
+
+    return Qnil;
+}
+
+static VALUE
+thread_join_sleep(VALUE arg)
+{
+    struct join_arg *p = (struct join_arg *)arg;
+    rb_thread_t *target_th = p->target, *th = p->waiting;
+    double now, limit = p->limit;
+
     while (target_th->status != THREAD_KILLED) {
-	if (delay == DELAY_INFTY) {
+	if (p->forever) {
 	    sleep_forever(th);
 	}
 	else {
@@ -482,14 +513,38 @@
 	    if (now > limit) {
 		thread_debug("thread_join: timeout (thid: %p)\n",
 			     (void *)target_th->thread_id);
-		return Qnil;
+		return Qfalse;
 	    }
 	    sleep_wait_for_interrupt(th, limit - now);
 	}
 	thread_debug("thread_join: interrupted (thid: %p)\n",
 		     (void *)target_th->thread_id);
     }
+    return Qtrue;
+}
 
+static VALUE
+thread_join(rb_thread_t *target_th, double delay)
+{
+    rb_thread_t *th = GET_THREAD();
+    struct join_arg arg;
+
+    arg.target = target_th;
+    arg.waiting = th;
+    arg.limit = timeofday() + delay;
+    arg.forever = delay == DELAY_INFTY;
+
+    thread_debug("thread_join (thid: %p)\n", (void *)target_th->thread_id);
+
+    if (target_th->status != THREAD_KILLED) {
+	th->join_list_next = target_th->join_list_head;
+	target_th->join_list_head = th;
+	if (!rb_ensure(thread_join_sleep, (VALUE)&arg,
+		       remove_from_join_list, (VALUE)&arg)) {
+	    return Qnil;
+	}
+    }
+
     thread_debug("thread_join: success (thid: %p)\n",
 		 (void *)target_th->thread_id);
 
@@ -628,9 +683,18 @@
 static double
 timeofday(void)
 {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+    struct timespec tp;
+
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
+        return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
+    } else
+#endif
+    {
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
+    }
 }
 
 static void
@@ -1476,7 +1540,7 @@
 	GC_WB(&th->local_storage, st_init_numtable());
     }
     if (NIL_P(val)) {
-	st_delete(th->local_storage, (st_data_t *) & id, 0);
+	st_delete_wrap(th->local_storage, id);
 	return Qnil;
     }
     st_insert(th->local_storage, id, val);
@@ -1511,15 +1575,17 @@
  */
 
 static VALUE
-rb_thread_key_p(VALUE self, ID id)
+rb_thread_key_p(VALUE self, VALUE key)
 {
     rb_thread_t *th;
+    ID id = rb_to_id(key);
+
     GetThreadPtr(self, th);
 
     if (!th->local_storage) {
 	return Qfalse;
     }
-    if (st_lookup(th->local_storage, rb_to_id(id), 0)) {
+    if (st_lookup(th->local_storage, id, 0)) {
 	return Qtrue;
     }
     return Qfalse;
@@ -1702,6 +1768,25 @@
     memcpy(dst->fdset, src, size);
 }
 
+int
+rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
+{
+    fd_set *r = NULL, *w = NULL, *e = NULL;
+    if (readfds) {
+        rb_fd_resize(n - 1, readfds);
+        r = rb_fd_ptr(readfds);
+    }
+    if (writefds) {
+        rb_fd_resize(n - 1, writefds);
+        w = rb_fd_ptr(writefds);
+    }
+    if (exceptfds) {
+        rb_fd_resize(n - 1, exceptfds);
+        e = rb_fd_ptr(exceptfds);
+    }
+    return select(n, r, w, e, timeout);
+}
+
 #undef FD_ZERO
 #undef FD_SET
 #undef FD_CLR
@@ -1746,7 +1831,7 @@
     fd_set orig_read, orig_write, orig_except;
 
 #ifndef linux
-    double limit;
+    double limit = 0;
     struct timeval wait_rest;
 
     if (timeout) {
@@ -1797,11 +1882,11 @@
     errno = lerrno;
 
     if (result < 0) {
-	if (errno == EINTR
+	switch (errno) {
+	  case EINTR:
 #ifdef ERESTART
-	    || errno == ERESTART
+	  case ERESTART:
 #endif
-	    ) {
 	    if (read) *read = orig_read;
 	    if (write) *write = orig_write;
 	    if (except) *except = orig_except;
@@ -1816,6 +1901,8 @@
 	    }
 #endif
 	    goto retry;
+	  default:
+	    break;
 	}
     }
     return result;
@@ -1896,10 +1983,13 @@
 void
 rb_gc_save_machine_context(rb_thread_t *th)
 {
+#if !WITH_OBJC
     SET_MACHINE_STACK_END(&th->machine_stack_end);
+    FLUSH_REGISTER_WINDOWS;
 #ifdef __ia64
     th->machine_register_stack_end = rb_ia64_bsp();
 #endif
+#endif
     setjmp(th->machine_regs);
 }
 
@@ -1920,8 +2010,8 @@
     /* check signal */
     if (vm->buffered_signal_size && vm->main_thread->exec_signal == 0) {
 	vm->main_thread->exec_signal = rb_get_next_signal(vm);
-	thread_debug("buffered_signal_size: %d, sig: %d\n",
-		     vm->buffered_signal_size, vm->main_thread->exec_signal);
+	thread_debug("buffered_signal_size: %ld, sig: %d\n",
+		     (long)vm->buffered_signal_size, vm->main_thread->exec_signal);
 	rb_thread_interrupt(vm->main_thread);
     }
 
@@ -1943,6 +2033,7 @@
     if (timer_thread_id) {
 	system_working = 0;
 	native_thread_join(timer_thread_id);
+	timer_thread_id = 0;
     }
 }
 
@@ -1984,6 +2075,32 @@
     st_insert(vm->living_threads, thval, (st_data_t) th->thread_id);
 }
 
+static int
+terminate_atfork_before_exec_i(st_data_t key, st_data_t val, rb_thread_t *current_th)
+{
+    VALUE thval = key;
+    rb_thread_t *th;
+    GetThreadPtr(thval, th);
+
+    if (th != current_th) {
+	thread_cleanup_func_before_exec(th);
+    }
+    return ST_CONTINUE;
+}
+
+void
+rb_thread_atfork_before_exec(void)
+{
+    rb_thread_t *th = GET_THREAD();
+    rb_vm_t *vm = th->vm;
+    VALUE thval = th->self;
+    vm->main_thread = th;
+
+    st_foreach(vm->living_threads, terminate_atfork_before_exec_i, (st_data_t)th);
+    st_clear(vm->living_threads);
+    st_insert(vm->living_threads, thval, (st_data_t) th->thread_id);
+}
+
 struct thgroup {
     int enclosed;
     VALUE group;
@@ -2298,34 +2415,23 @@
     return locked;
 }
 
-static VALUE
+static int
 lock_func(rb_thread_t *th, mutex_t *mutex)
 {
-    int locked = 0;
+    int interrupted = Qfalse;
 
-    while (locked == 0) {
-	native_mutex_lock(&mutex->lock);
-	{
-	    if (mutex->th == 0) {
-		mutex->th = th;
-		locked = 1;
-	    }
-	    else {
-		mutex->cond_waiting++;
-		native_cond_wait(&mutex->cond, &mutex->lock);
+    native_mutex_lock(&mutex->lock);
+    while (mutex->th || (mutex->th = th, 0)) {
+	mutex->cond_waiting++;
+	native_cond_wait(&mutex->cond, &mutex->lock);
 
-		if (th->interrupt_flag) {
-		    locked = 1;
-		}
-		else if (mutex->th == 0) {
-		    mutex->th = th;
-		    locked = 1;
-		}
-	    }
+	if (th->interrupt_flag) {
+	    interrupted = Qtrue;
+	    break;
 	}
-	native_mutex_unlock(&mutex->lock);
     }
-    return Qnil;
+    native_mutex_unlock(&mutex->lock);
+    return interrupted;
 }
 
 static void
@@ -2356,11 +2462,15 @@
 	GetMutexPtr(self, mutex);
 
 	while (mutex->th != th) {
+	    int interrupted;
+
 	    BLOCKING_REGION({
-		lock_func(th, mutex);
+		interrupted = lock_func(th, mutex);
 	    }, lock_interrupt, mutex);
 
-	    RUBY_VM_CHECK_INTS();
+	    if (interrupted) {
+		RUBY_VM_CHECK_INTS();
+	    }
 	}
     }
     return self;
@@ -2404,6 +2514,21 @@
     return self;
 }
 
+static VALUE
+rb_mutex_sleep_forever(VALUE time)
+{
+    rb_thread_sleep_forever();
+    return Qnil;
+}
+
+static VALUE
+rb_mutex_wait_for(VALUE time)
+{
+    const struct timeval *t = (struct timeval *)time;
+    rb_thread_wait_for(*t);
+    return Qnil;
+}
+
 VALUE
 rb_mutex_sleep(VALUE self, VALUE timeout)
 {
@@ -2416,19 +2541,18 @@
     rb_mutex_unlock(self);
     beg = time(0);
     if (NIL_P(timeout)) {
-	rb_thread_sleep_forever();
+	rb_ensure(rb_mutex_sleep_forever, Qnil, rb_mutex_lock, self);
     }
     else {
-	rb_thread_wait_for(t);
+	rb_ensure(rb_mutex_wait_for, (VALUE)&t, rb_mutex_lock, self);
     }
-    rb_mutex_lock(self);
     end = time(0) - beg;
     return INT2FIX(end);
 }
 
 /*
  * call-seq:
- *    mutex.sleep(timeout = nil)    => self
+ *    mutex.sleep(timeout = nil)    => number
  *
  * Releases the lock and sleeps +timeout+ seconds if it is given and
  * non-nil or forever.  Raises +ThreadError+ if +mutex+ wasn't locked by
@@ -2771,7 +2895,7 @@
 	    xfree(hook);
 	}
 	else {
-	prev = hook;
+	    prev = hook;
 	}
 	hook = next;
     }

Modified: MacRuby/trunk/thread_pthread.c
===================================================================
--- MacRuby/trunk/thread_pthread.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/thread_pthread.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -115,7 +115,9 @@
 #define native_cleanup_pop  pthread_cleanup_pop
 #define native_thread_yield() sched_yield()
 
+#ifndef __CYGWIN__
 static void add_signal_thread_list(rb_thread_t *th);
+#endif
 static void remove_signal_thread_list(rb_thread_t *th);
 
 static rb_thread_lock_t signal_thread_list_lock;
@@ -422,7 +424,6 @@
     }
 
     th->status = THREAD_STOPPED;
-    pthread_cond_init(&th->native_thread_data.sleep_cond, 0);
 
     thread_debug("native_sleep %ld\n", tv ? tv->tv_sec : -1);
     GVL_UNLOCK_BEGIN();
@@ -469,9 +470,11 @@
     struct signal_thread_list *next;
 };
 
+#ifndef __CYGWIN__
 static struct signal_thread_list signal_thread_list_anchor = {
     0, 0, 0,
 };
+#endif
 
 #define FGLOCK(lock, body) do { \
     native_mutex_lock(lock); \
@@ -496,6 +499,7 @@
 }
 #endif
 
+#ifndef __CYGWIN__
 static void
 add_signal_thread_list(rb_thread_t *th)
 {
@@ -521,6 +525,7 @@
 	});
     }
 }
+#endif
 
 static void
 remove_signal_thread_list(rb_thread_t *th)

Modified: MacRuby/trunk/thread_win32.c
===================================================================
--- MacRuby/trunk/thread_win32.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/thread_win32.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,7 +3,7 @@
 
   thread_win32.c -
 
-  $Author: usa $
+  $Author: nobu $
 
   Copyright (C) 2004-2007 Koichi Sasada
 
@@ -73,7 +73,7 @@
 		  GetLastError(),
 		  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 		  (LPTSTR) & lpMsgBuf, 0, NULL);
-    rb_bug("%s", lpMsgBuf);
+    rb_bug("%s", (char*)lpMsgBuf);
 }
 
 static void
@@ -116,7 +116,7 @@
 
     thread_debug("  WaitForMultipleObjects start (count: %d)\n", count);
     ret = WaitForMultipleObjects(count, targets, FALSE, timeout);
-    thread_debug("  WaitForMultipleObjects end (ret: %d)\n", ret);
+    thread_debug("  WaitForMultipleObjects end (ret: %lu)\n", ret);
 
     if (ret == WAIT_OBJECT_0 + count - 1 && th) {
 	errno = EINTR;
@@ -227,9 +227,9 @@
 	    /* interrupted.  return immediate */
 	}
 	else {
-	    thread_debug("native_sleep start (%d)\n", (int)msec);
+	    thread_debug("native_sleep start (%lu)\n", msec);
 	    ret = w32_wait_events(0, 0, msec, th);
-	    thread_debug("native_sleep done (%d)\n", ret);
+	    thread_debug("native_sleep done (%lu)\n", ret);
 	}
 
 	th->unblock_function = 0;
@@ -393,7 +393,7 @@
     {
 	r = WaitForSingleObject(entry.event, INFINITE);
 	if (r != WAIT_OBJECT_0) {
-	    rb_bug("native_cond_wait: WaitForSingleObject returns %d", r);
+	    rb_bug("native_cond_wait: WaitForSingleObject returns %lu", r);
 	}
     }
     native_mutex_lock(mutex);

Modified: MacRuby/trunk/time.c
===================================================================
--- MacRuby/trunk/time.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/time.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   time.c -
 
-  $Author: matz $
+  $Author: akr $
   created at: Tue Dec 28 14:31:59 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -12,6 +12,7 @@
 #include "ruby/ruby.h"
 #include <sys/types.h>
 #include <time.h>
+#include <errno.h>
 #include "ruby/encoding.h"
 
 #ifdef HAVE_UNISTD_H
@@ -216,18 +217,24 @@
 	break;
 
       default:
-        ary = rb_check_array_type(rb_funcall(num, id_divmod, 1, INT2FIX(1)));
-        if (NIL_P(ary)) {
+        if (rb_respond_to(num, id_divmod)) {
+            ary = rb_check_array_type(rb_funcall(num, id_divmod, 1, INT2FIX(1)));
+            if (NIL_P(ary)) {
+                goto typeerror;
+            }
+            i = rb_ary_entry(ary, 0);
+            f = rb_ary_entry(ary, 1);
+            t.tv_sec = NUM2LONG(i);
+            if (interval && t.tv_sec < 0)
+                rb_raise(rb_eArgError, "%s must be positive", tstr);
+            f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
+            t.tv_nsec = NUM2LONG(f);
+        }
+        else {
+typeerror:
             rb_raise(rb_eTypeError, "can't convert %s into %s",
                      rb_obj_classname(num), tstr);
         }
-        i = rb_ary_entry(ary, 0);
-        f = rb_ary_entry(ary, 1);
-        t.tv_sec = NUM2LONG(i);
-	if (interval && t.tv_sec < 0)
-	    rb_raise(rb_eArgError, "%s must be positive", tstr);
-        f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
-        t.tv_nsec = NUM2LONG(f);
 	break;
     }
     return t;
@@ -326,7 +333,7 @@
     return t;
 }
 
-static const char *months[] = {
+static const char *const months[] = {
     "jan", "feb", "mar", "apr", "may", "jun",
     "jul", "aug", "sep", "oct", "nov", "dec",
 };
@@ -349,7 +356,7 @@
     if (TYPE(obj) == T_STRING) {
 	obj = rb_str_to_inum(obj, 10, Qfalse);
         *nsec = 0;
-        return NUM2LONG(obj) * 1000;
+        return NUM2LONG(obj);
     }
 
     ts = time_timespec(obj, 1);
@@ -1830,7 +1837,7 @@
  *  Returns <code>true</code> if <i>time</i> occurs during Daylight
  *  Saving Time in its time zone.
  *     
- *   CST6CDT:
+ *   # CST6CDT:
  *     Time.local(2000, 1, 1).zone    #=> "CST"
  *     Time.local(2000, 1, 1).isdst   #=> false
  *     Time.local(2000, 1, 1).dst?    #=> false
@@ -1838,7 +1845,7 @@
  *     Time.local(2000, 7, 1).isdst   #=> true
  *     Time.local(2000, 7, 1).dst?    #=> true
  *
- *   Asia/Tokyo:
+ *   # Asia/Tokyo:
  *     Time.local(2000, 1, 1).zone    #=> "JST"
  *     Time.local(2000, 1, 1).isdst   #=> false
  *     Time.local(2000, 1, 1).dst?    #=> false
@@ -2003,8 +2010,9 @@
     if (flen == 0) {
 	return 0;
     }
+    errno = 0;
     len = strftime(*buf, SMALLBUF, format, time);
-    if (len != 0 || **buf == '\0') return len;
+    if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
     for (size=1024; ; size*=2) {
 	*buf = xmalloc(size);
 	(*buf)[0] = '\0';

Modified: MacRuby/trunk/tool/compile_prelude.rb
===================================================================
--- MacRuby/trunk/tool/compile_prelude.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/tool/compile_prelude.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -8,7 +8,7 @@
 
 preludes = ARGV.dup
 outfile = preludes.pop
-init_name = outfile[/\w+(?=_prelude.c\z)/] || 'prelude'
+init_name = outfile[/\w+(?=_prelude.c\b)/] || 'prelude'
 
 C_ESC = {
   "\\" => "\\\\",

Modified: MacRuby/trunk/tool/instruction.rb
===================================================================
--- MacRuby/trunk/tool/instruction.rb	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/tool/instruction.rb	2008-05-18 08:10:19 UTC (rev 199)
@@ -1139,7 +1139,7 @@
 
           uni_insn, uni_insns = *unif
           uni_insns = uni_insns[1..-1]
-          unif_insns_each << "static int UNIFIED_#{insn.name}_#{i}[] = {" +
+          unif_insns_each << "static const int UNIFIED_#{insn.name}_#{i}[] = {" +
                              "  BIN(#{uni_insn.name}), #{uni_insns.size + 2}, \n  " +
                              uni_insns.map{|e| "BIN(#{e.name})"}.join(", ") + "};\n"
           }
@@ -1147,14 +1147,14 @@
           
         end
         if size > 0
-          unif_insns << "static int *UNIFIED_#{insn.name}[] = {(int *)#{size+1}, \n"
+          unif_insns << "static const int *const UNIFIED_#{insn.name}[] = {(int *)#{size+1}, \n"
           unif_insns << (0...size).map{|e| "  UNIFIED_#{insn.name}_#{e}"}.join(",\n") + "};\n"
           unif_insns_data << "  UNIFIED_#{insn.name}"
         else
           unif_insns_data << "  0"
         end
       }
-      unif_insns_data = "static int **unified_insns_data[] = {\n" +
+      unif_insns_data = "static const int *const *const unified_insns_data[] = {\n" +
                         unif_insns_data.join(",\n") + "};\n"
       ERB.new(vpath.read('template/optunifs.inc.tmpl')).result(binding)
     end

Modified: MacRuby/trunk/transcode.c
===================================================================
--- MacRuby/trunk/transcode.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/transcode.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   transcode.c -
 
-  $Author: duerst $
+  $Author: nobu $
   created at: Tue Oct 30 16:10:22 JST 2007
 
   Copyright (C) 2007 Martin Duerst
@@ -88,14 +88,6 @@
     declare_transcoder(enc2, enc1, lib);
 }
 
-static void
-init_transcoder_table(void)
-{
-#ifndef NO_TRANSDB_H
-#include "transdb.h"
-#endif
-}
-
 #define encoding_equal(enc1, enc2) (STRCASECMP(enc1, enc2) == 0)
 
 static const rb_transcoder *
@@ -180,8 +172,10 @@
 	    if (from_utf8) {
 		if ((next_byte&0xC0) == 0x80)
 		    next_byte -= 0x80;
-		else
+		else {
+		    in_p--; /* may need to add more code later to revert other things */
 		    goto invalid;
+		}
 	    }
 	    next_table = (const BYTE_LOOKUP *)next_info;
 	    goto follow_byte;
@@ -393,13 +387,15 @@
 
 /*
  *  call-seq:
- *     str.encode!(encoding)   => str
- *     str.encode!(to_encoding, from_encoding)   => str
+ *     str.encode!(encoding [, options] )   => str
+ *     str.encode!(to_encoding, from_encoding [, options] )   => str
  *
- *  With one argument, transcodes the contents of <i>str</i> from
+ *  The first form transcodes the contents of <i>str</i> from
  *  str.encoding to +encoding+.
- *  With two arguments, transcodes the contents of <i>str</i> from
+ *  The second form transcodes the contents of <i>str</i> from
  *  from_encoding to to_encoding.
+ *  The options Hash gives details for conversion. See String#encode
+ *  for details.
  *  Returns the string even if no changes were made.
  */
 
@@ -408,40 +404,41 @@
 {
     VALUE newstr = str;
     int encidx = str_transcode(argc, argv, &newstr);
+    int cr = 0;
 
     if (encidx < 0) return str;
     rb_str_shared_replace(str, newstr);
     rb_enc_associate_index(str, encidx);
+
+    /* transcoded string never be broken. */
+    if (rb_enc_asciicompat(rb_enc_from_index(encidx))) {
+	rb_str_coderange_scan_restartable(RSTRING_PTR(str), RSTRING_END(str), 0, &cr);
+    }
+    else {
+	cr = ENC_CODERANGE_VALID;
+    }
+    ENC_CODERANGE_SET(str, cr);
     return str;
 }
 
 /*
  *  call-seq:
- *     str.encode(encoding)   => str
- *     str.encode(to_encoding, from_encoding)   => str
+ *     str.encode(encoding [, options] )   => str
+ *     str.encode(to_encoding, from_encoding [, options] )   => str
  *
- *  With one argument, returns a copy of <i>str</i> transcoded
+ *  The first form returns a copy of <i>str</i> transcoded
  *  to encoding +encoding+.
- *  With two arguments, returns a copy of <i>str</i> transcoded
+ *  The second form returns a copy of <i>str</i> transcoded
  *  from from_encoding to to_encoding.
+ *  The options Hash gives details for conversion. Details
+ *  to be added.
  */
 
 static VALUE
 rb_str_transcode(int argc, VALUE *argv, VALUE str)
 {
-    VALUE newstr = str;
-    int encidx = str_transcode(argc, argv, &newstr);
-
-    if (newstr == str) {
-	newstr = rb_str_new3(str);
-	if (encidx >= 0) rb_enc_associate_index(newstr, encidx);
-    }
-    else {
-	RBASIC(newstr)->klass = rb_obj_class(str);
-	OBJ_INFECT(newstr, str);
-	rb_enc_associate_index(newstr, encidx);
-    }
-    return newstr;
+    str = rb_str_dup(str);
+    return rb_str_transcode_bang(argc, argv, str);
 }
 
 #else // WITH_OBJC
@@ -468,7 +465,6 @@
 #if !WITH_OBJC
     transcoder_table = st_init_strcasetable();
     transcoder_lib_table = st_init_strcasetable();
-    init_transcoder_table();
 
     sym_invalid = ID2SYM(rb_intern("invalid"));
     sym_ignore = ID2SYM(rb_intern("ignore"));

Modified: MacRuby/trunk/variable.c
===================================================================
--- MacRuby/trunk/variable.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/variable.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -469,8 +469,13 @@
     void  (*setter)(ANYARGS))
 {
     struct global_variable *gvar;
-    ID id = global_id(name);
+    ID id;
+    VALUE tmp;
+    
+    if (var)
+        tmp = *var;
 
+    id = global_id(name);
     gvar = rb_global_entry(id)->var;
     gvar->data = (void*)var;
     gvar->getter = getter?getter:var_getter;
@@ -723,7 +728,7 @@
  *  
  *  Returns an array of the names of global variables.
  *     
- *     global_variables.grep /std/   #=> ["$stderr", "$stdout", "$stdin"]
+ *     global_variables.grep /std/   #=> [:$stdin, :$stdout, :$stderr]
  */
 
 VALUE
@@ -752,7 +757,7 @@
 
     entry2 = rb_global_entry(name2);
     if (!st_lookup(rb_global_tbl, name1, &data1)) {
-	entry1 = ALLOC(struct global_entry);
+ 	entry1 = ALLOC(struct global_entry);
 	entry1->id = name1;
 	st_add_direct(rb_global_tbl, name1, (st_data_t)entry1);
     }
@@ -1155,22 +1160,23 @@
     switch (TYPE(obj)) {
       case T_OBJECT:
         obj_ivar_each(obj, func, arg);
-	return;
+	break;
       case T_CLASS:
       case T_MODULE:
 	if (RCLASS_IV_TBL(obj)) {
 	    st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
 	}
-	return;
-    }
-    if (!generic_iv_tbl)
-	return; 
-    if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
-	st_data_t tbl;
+	break;
+      default:
+	if (!generic_iv_tbl) break;
+	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
+	    st_data_t tbl;
 
-	if (st_lookup(generic_iv_tbl, obj, &tbl)) {
-	    st_foreach_safe((st_table *)tbl, func, arg);
+	    if (st_lookup(generic_iv_tbl, obj, &tbl)) {
+		st_foreach_safe((st_table *)tbl, func, arg);
+	    }
 	}
+	break;
     }
 }
 
@@ -1197,7 +1203,7 @@
  *         @iv = 3
  *       end
  *     end
- *     Fred.new.instance_variables   #=> ["@iv"]
+ *     Fred.new.instance_variables   #=> [:@iv]
  */
 
 VALUE
@@ -1415,7 +1421,7 @@
     VALUE file;
     NODE *load = autoload_delete(klass, id);
 
-    if (!load || !(file = load->nd_lit) || rb_provided(RSTRING_CPTR(file))) {
+    if (!load || !(file = load->nd_lit)) {
 	return Qfalse;
     }
     return rb_require_safe(file, load->nd_nth);
@@ -1474,7 +1480,7 @@
 
     tmp = klass;
   retry:
-    while (tmp && !NIL_P(tmp)) {
+    while (RTEST(tmp)) {
 	while (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp),id,&value)) {
 	    if (value == Qundef) {
 		if (!RTEST(rb_autoload_load(tmp, id))) break;
@@ -1642,8 +1648,8 @@
  *  modules (example at start of section), unless the <i>all</i>
  *  parameter is set to <code>false</code>.
  *
- *    IO.constants.include?("SYNC")         => true
- *    IO.constants(false).include?("SYNC")  => false
+ *    IO.constants.include?(:SYNC)         => true
+ *    IO.constants(false).include?(:SYNC)  => false
  *
  *  Also see <code>Module::const_defined?</code>.
  */
@@ -1928,8 +1934,8 @@
  *     class Two < One
  *       @@var2 = 2
  *     end
- *     One.class_variables   #=> ["@@var1"]
- *     Two.class_variables   #=> ["@@var2"]
+ *     One.class_variables   #=> [:@@var1]
+ *     Two.class_variables   #=> [:@@var2]
  */
 
 VALUE

Modified: MacRuby/trunk/version.c
===================================================================
--- MacRuby/trunk/version.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/version.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   version.c -
 
-  $Author: akr $
+  $Author: nobu $
   created at: Thu Sep 30 20:08:01 JST 1993
 
   Copyright (C) 1993-2007 Yukihiro Matsumoto
@@ -14,7 +14,7 @@
 #include <stdio.h>
 
 #define PRINT(type) puts(ruby_##type)
-#define MKSTR(type) rb_obj_freeze(rb_str_new(ruby_##type, sizeof(ruby_##type)-1))
+#define MKSTR(type) rb_obj_freeze(rb_usascii_str_new(ruby_##type, sizeof(ruby_##type)-1))
 
 const int ruby_version_code = RUBY_VERSION_CODE;
 const char ruby_version[] = RUBY_VERSION;

Modified: MacRuby/trunk/version.h
===================================================================
--- MacRuby/trunk/version.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/version.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -1,15 +1,15 @@
 #define RUBY_VERSION "1.9.0"
-#define RUBY_RELEASE_DATE "2008-03-01"
+#define RUBY_RELEASE_DATE "2008-05-17"
 #define RUBY_VERSION_CODE 190
-#define RUBY_RELEASE_CODE 20080301
+#define RUBY_RELEASE_CODE 20080517
 #define RUBY_PATCHLEVEL 0
 
 #define RUBY_VERSION_MAJOR 1
 #define RUBY_VERSION_MINOR 9
 #define RUBY_VERSION_TEENY 0
 #define RUBY_RELEASE_YEAR 2008
-#define RUBY_RELEASE_MONTH 3
-#define RUBY_RELEASE_DAY 1
+#define RUBY_RELEASE_MONTH 5
+#define RUBY_RELEASE_DAY 17
 
 #ifdef RUBY_EXTERN
 RUBY_EXTERN const int ruby_version_code;

Modified: MacRuby/trunk/vm.c
===================================================================
--- MacRuby/trunk/vm.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/vm.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -122,6 +122,7 @@
 
 	RUBY_GC_INFO("env->prev_envval\n");
 	RUBY_MARK_UNLESS_NULL(env->prev_envval);
+	RUBY_MARK_UNLESS_NULL(env->block.self);
 	RUBY_MARK_UNLESS_NULL(env->block.proc);
 
 	if (env->block.iseq) {
@@ -279,13 +280,10 @@
 collect_local_variables_in_env(rb_env_t *env, VALUE ary)
 {
     int i;
-    if (env->block.lfp == env->block.dfp) {
-	return 0;
-    }
     for (i = 0; i < env->block.iseq->local_table_size; i++) {
 	ID lid = env->block.iseq->local_table[i];
 	if (lid) {
-	    rb_ary_push(ary, rb_str_dup(rb_id2str(lid)));
+	    rb_ary_push(ary, ID2SYM(lid));
 	}
     }
     if (env->prev_envval) {
@@ -501,7 +499,6 @@
     VALUE klass;
     ID id;
     NODE *body;
-    int nosuper = 0;
     rb_control_frame_t *cfp = th->cfp;
 
     if (!cfp->iseq) {
@@ -530,7 +527,7 @@
 	rb_bug("vm_call_super: not found");
     }
 
-    return vm_call0(th, klass, recv, id, id, argc, argv, body, nosuper);
+    return vm_call0(th, klass, recv, id, id, argc, argv, body, CALL_SUPER);
 }
 
 VALUE
@@ -721,7 +718,7 @@
 vm_backtrace_each(rb_thread_t *th,
 		  rb_control_frame_t *limit_cfp,
 		  rb_control_frame_t *cfp,
-		  const char *file, int line_no, VALUE ary)
+		  char *file, int line_no, VALUE ary)
 {
     VALUE str;
 
@@ -732,7 +729,7 @@
 		rb_iseq_t *iseq = cfp->iseq;
 
 		line_no = vm_get_sourceline(cfp);
-		file = RSTRING_CPTR(iseq->filename);
+		file = (char *)RSTRING_CPTR(iseq->filename);
 		str = rb_sprintf("%s:%d:in `%s'",
 				 file, line_no, RSTRING_CPTR(iseq->name));
 		rb_ary_push(ary, str);
@@ -912,8 +909,9 @@
 {
     VALUE result = Qnil;
 
-    if (val == Qundef)
+    if (val == Qundef) {
 	val = GET_THREAD()->tag->retval;
+    }
     switch (state) {
       case 0:
 	break;
@@ -1146,8 +1144,10 @@
     int state;
     VALUE result, err;
     VALUE initial = 0;
+    VALUE *escape_dfp = NULL;
 
     TH_PUSH_TAG(th);
+    _tag.retval = Qnil;
     if ((state = EXEC_TAG()) == 0) {
       vm_loop_start:
 	result = vm_eval(th, initial);
@@ -1163,7 +1163,6 @@
 	unsigned long epc, cont_pc, cont_sp;
 	VALUE catch_iseqval;
 	rb_control_frame_t *cfp;
-	VALUE *escape_dfp = NULL;
 	VALUE type;
 
 	err = th->errinfo;
@@ -1496,6 +1495,7 @@
 	RUBY_MARK_UNLESS_NULL(vm->thgroup_default);
 	RUBY_MARK_UNLESS_NULL(vm->mark_object_ary);
 	RUBY_MARK_UNLESS_NULL(vm->last_status);
+	RUBY_MARK_UNLESS_NULL(vm->load_path);
 	RUBY_MARK_UNLESS_NULL(vm->loaded_features);
 	RUBY_MARK_UNLESS_NULL(vm->top_self);
 
@@ -1588,7 +1588,6 @@
 	    VALUE *ptr = th->value_cache_ptr;
 	    while (*ptr) {
 		VALUE v = *ptr;
-		RBASIC(v)->isa = NULL;
 		RBASIC(v)->flags = 0;
 		RBASIC(v)->klass = 0;
 		ptr++;
@@ -1646,6 +1645,7 @@
 	RUBY_MARK_UNLESS_NULL(th->top_wrapper);
 	RUBY_MARK_UNLESS_NULL(th->fiber);
 	RUBY_MARK_UNLESS_NULL(th->root_fiber);
+	RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
 
 	rb_mark_tbl(th->local_storage);
 
@@ -1659,7 +1659,6 @@
 	mark_event_hooks(th->event_hooks);
     }
 
-    RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
     RUBY_MARK_LEAVE("thread");
 }
 #else
@@ -1861,12 +1860,19 @@
     vm_init_redefined_flag();
 }
 
+struct rb_objspace *rb_objspace_alloc(void);
+
 void
 Init_BareVM(void)
 {
     /* VM bootstrap: phase 1 */
-    rb_vm_t *vm = ALLOC(rb_vm_t);
-    rb_thread_t *th = ALLOC(rb_thread_t);
+#if WITH_OBJC
+    rb_vm_t *vm = xmalloc(sizeof(*vm));
+    rb_thread_t *th = xmalloc(sizeof(*th));
+#else
+    rb_vm_t *vm = malloc(sizeof(*vm));
+    rb_thread_t *th = malloc(sizeof(*th));
+#endif
     MEMZERO(th, rb_thread_t, 1);
 
     rb_thread_set_current_raw(th);
@@ -1880,6 +1886,9 @@
 #endif
 
     vm_init2(vm);
+#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
+    vm->objspace = rb_objspace_alloc();
+#endif
     ruby_current_vm = vm;
     GC_ROOT(&ruby_current_vm);
 

Modified: MacRuby/trunk/vm_core.h
===================================================================
--- MacRuby/trunk/vm_core.h	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/vm_core.h	2008-05-18 08:10:19 UTC (rev 199)
@@ -139,6 +139,7 @@
     int instructions_unification;
     int stack_caching;
     int trace_instruction;
+    int debug_level;
 } rb_compile_option_t;
 
 struct iseq_compile_data {
@@ -161,6 +162,8 @@
     struct iseq_compile_data_storage *storage_current;
     int last_line;
     int flip_cnt;
+    int label_no;
+    int node_level;
     const rb_compile_option_t *option;
 };
 
@@ -300,6 +303,7 @@
 
     /* load */
     VALUE top_self;
+    VALUE load_path;
     VALUE loaded_features;
     struct st_table *loading_table;
     
@@ -309,6 +313,10 @@
 
     /* hook */
     rb_event_hook_t *event_hooks;
+
+#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
+    struct rb_objspace *objspace;
+#endif
 } rb_vm_t;
 
 typedef struct {
@@ -346,7 +354,7 @@
     THREAD_KILLED,
 };
 
-typedef jmp_buf rb_jmpbuf_t;
+typedef RUBY_JMP_BUF rb_jmpbuf_t;
 
 struct rb_vm_tag {
     rb_jmpbuf_t buf;
@@ -439,6 +447,7 @@
     VALUE *machine_register_stack_end;
     size_t machine_register_stack_maxsize;
 #endif
+
     jmp_buf machine_regs;
     int mark_stack_len;
 
@@ -650,7 +659,7 @@
   RUBY_VM_CHECK_INTS_TH(GET_THREAD())
 
 /* tracer */
-static void inline
+static inline void
 exec_event_hooks(rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
 {
     while (hook) {

Modified: MacRuby/trunk/vm_evalbody.c
===================================================================
--- MacRuby/trunk/vm_evalbody.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/vm_evalbody.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -3,7 +3,7 @@
 
   vm_evalbody.c -
 
-  $Author: akr $
+  $Author: shyouhei $
 
   Copyright (C) 2004-2007 Koichi Sasada
 
@@ -14,11 +14,11 @@
 #if VMDEBUG > 0
 #define DECL_SC_REG(type, r, reg) register type reg_##r
 
-#elif __GNUC__ && __x86_64
-#define DECL_SC_REG(type, r, reg) register type reg_##r asm("r" reg)
+#elif __GNUC__ && __x86_64__
+#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg)
 
 #elif __GNUC__ && __i386__
-#define DECL_SC_REG(type, r, reg) register type reg_##r asm("e" reg)
+#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("e" reg)
 
 #else
 #define DECL_SC_REG(type, r, reg) register type reg_##r

Modified: MacRuby/trunk/vm_insnhelper.c
===================================================================
--- MacRuby/trunk/vm_insnhelper.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/vm_insnhelper.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -2,7 +2,7 @@
 
   insnhelper.c - instruction helper functions.
 
-  $Author: nobu $
+  $Author: matz $
 
   Copyright (C) 2007 Koichi Sasada
 
@@ -909,15 +909,12 @@
 
     switch (key) {
       case 0:
-	//svar->v1 = val;
 	GC_WB(&svar->v1, val);
 	return;
       case 1:
-	//svar->v2 = val;
 	GC_WB(&svar->v2, val);
 	return;
       case 2:
-	//svar->basic.klass = val;
 	GC_WB(&svar->basic.klass, val);
 	return;
       default: {
@@ -985,6 +982,19 @@
     return val;
 }
 
+static inline void
+vm_check_if_namespace(VALUE klass)
+{
+    switch (TYPE(klass)) {
+      case T_CLASS:
+      case T_MODULE:
+	break;
+      default:
+	rb_raise(rb_eTypeError, "%s is not a class/module",
+		 RSTRING_CPTR(rb_inspect(klass)));
+    }
+}
+
 static inline VALUE
 vm_get_ev_const(rb_thread_t *th, rb_iseq_t *iseq,
 		VALUE klass, ID id, int is_defined)
@@ -1039,19 +1049,12 @@
 	}
     }
     else {
-	switch (TYPE(klass)) {
-	  case T_CLASS:
-	  case T_MODULE:
-	    break;
-	  default:
-	    rb_raise(rb_eTypeError, "%s is not a class/module",
-		     RSTRING_CPTR(rb_obj_as_string(klass)));
-	}
+	vm_check_if_namespace(klass);
 	if (is_defined) {
-	    return rb_const_defined(klass, id);
+	    return rb_const_defined_from(klass, id);
 	}
 	else {
-	    return rb_const_get(klass, id);
+	    return rb_const_get_from(klass, id);
 	}
     }
 }
@@ -1089,7 +1092,7 @@
 		     rb_id2name(id), rb_obj_classname(obj));
 	}
 
-	if (rb_obj_frozen_p(obj)) {
+	if (OBJ_FROZEN(obj)) {
 	    rb_error_frozen("object");
 	}
 

Modified: MacRuby/trunk/win32/Makefile.sub
===================================================================
--- MacRuby/trunk/win32/Makefile.sub	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/win32/Makefile.sub	2008-05-18 08:10:19 UTC (rev 199)
@@ -208,7 +208,7 @@
 RUNRUBY = $(MINIRUBY)
 !else
 MINIRUBY = .\miniruby$(EXEEXT) -I$(srcdir)/lib
-RUNRUBY = .\ruby$(EXEEXT) -I"$(EXTOUT)/$(arch)"
+RUNRUBY = .\$(PROGRAM) -I"$(EXTOUT)/$(arch)"
 !endif
 MINIRUBY = $(MINIRUBY) $(MINIRUBYOPT)
 RUNRUBY = $(RUNRUBY) "$(srcdir)/runruby.rb" --extout="$(EXTOUT)" --
@@ -250,7 +250,7 @@
 !if !defined(WINMAINOBJ)
 WINMAINOBJ    = winmain.$(OBJEXT)
 !endif
-MINIOBJS      = dmydln.$(OBJEXT) dmyencoding.$(OBJEXT) dmytranscode.$(OBJEXT) miniprelude.$(OBJEXT)
+ARCHMINIOBJS  = dmydln.$(OBJEXT)
 LIBOBJS       = $(MISSING) $(LIBOBJS)
 
 !ifndef COMMON_LIBS
@@ -367,6 +367,29 @@
 #define rb_uid_t int
 #define HAVE_STRUCT_STAT_ST_RDEV 1
 #define HAVE_ST_RDEV 1
+#define int8_t signed char
+#define HAVE_UINT8_T 1
+#define uint8_t unsigned char
+#define HAVE_INT16_T 1
+#define int16_t short
+#define HAVE_UINT16_T 1
+#define uint16_t unsigned short
+#define HAVE_INT32_T 1
+#define int32_t int
+#define HAVE_UINT32_T 1
+#define uint32_t unsigned int
+#define HAVE_INT64_T HAVE_LONG_LONG
+#define int64_t __int64
+#define HAVE_UINT64_T HAVE_LONG_LONG
+#define uint64_t unsigned __int64
+#define HAVE_INTPTR_T 1
+#define HAVE_UINTPTR_T 1
+#define HAVE_SSIZE_T 1
+!if "$(ARCH)" == "x64" || "$(ARCH)" == "ia64"
+#define ssize_t __int64
+!else
+#define ssize_t int
+!endif
 #define GETGROUPS_T int
 #define RETSIGTYPE void
 !if !defined(WIN32_WCE)
@@ -419,6 +442,9 @@
 #define RSHIFT(x,y) ((x)>>(int)y)
 #define FILE_COUNT _cnt
 #define FILE_READPTR _ptr
+#define RUBY_SETJMP(env) _setjmp(env)
+#define RUBY_LONGJMP(env,val) longjmp(env,val)
+#define RUBY_JMP_BUF jmp_buf
 #define inline __inline
 #define NEED_IO_SEEK_BETWEEN_RW 1
 !if "$(PROCESSOR_ARCHITECTURE)" == "x86" || "$(ARCH)" == "x64" || "$(ARCH)" == "ia64"
@@ -657,7 +683,7 @@
 		$(AR) $(ARFLAGS)$@ -def:$<
 
 clean-local::
-		@$(RM) ext\extinit.c ext\extinit.$(OBJEXT) ext\vc*.pdb miniruby.lib
+		@$(RM) $(WINMAINOBJ) ext\extinit.c ext\extinit.$(OBJEXT) ext\vc*.pdb miniruby.lib
 		@$(RM) $(RUBY_INSTALL_NAME).res $(RUBYW_INSTALL_NAME).res $(RUBY_SO_NAME).res
 		@$(RM) *.map *.pdb *.ilk *.exp $(RUBYDEF) ext\ripper\y.output
 

Modified: MacRuby/trunk/win32/win32.c
===================================================================
--- MacRuby/trunk/win32/win32.c	2008-05-17 01:51:04 UTC (rev 198)
+++ MacRuby/trunk/win32/win32.c	2008-05-18 08:10:19 UTC (rev 199)
@@ -376,11 +376,10 @@
     }
 
     if (!GetEnvironmentVariable("USER", env, sizeof env)) {
-	if (GetEnvironmentVariable("USERNAME", env, sizeof env) ||
-	    GetUserName(env, (len = sizeof env, &len))) {
+	if (GetEnvironmentVariable("USERNAME", env, sizeof env)) {
 	    SetEnvironmentVariable("USER", env);
 	}
-	else {
+	else if (!GetUserName(env, (len = sizeof env, &len))) {
 	    NTLoginName = "<Unknown>";
 	    return;
 	}

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20080518/dd2d0565/attachment-0001.htm 


More information about the macruby-changes mailing list