[macruby-changes] [233] MacRuby/branches/testing
source_changes at macosforge.org
source_changes at macosforge.org
Wed May 28 13:03:11 PDT 2008
Revision: 233
http://trac.macosforge.org/projects/ruby/changeset/233
Author: lsansonetti at apple.com
Date: 2008-05-28 13:03:03 -0700 (Wed, 28 May 2008)
Log Message:
-----------
merge from trunk
Modified Paths:
--------------
MacRuby/branches/testing/ChangeLog
MacRuby/branches/testing/Makefile.in
MacRuby/branches/testing/array.c
MacRuby/branches/testing/benchmark/bm_so_sieve.rb
MacRuby/branches/testing/benchmark/bm_vm2_eval.rb
MacRuby/branches/testing/bignum.c
MacRuby/branches/testing/blockinlining.c
MacRuby/branches/testing/bootstraptest/runner.rb
MacRuby/branches/testing/bootstraptest/test_class.rb
MacRuby/branches/testing/bootstraptest/test_knownbug.rb
MacRuby/branches/testing/bootstraptest/test_literal.rb
MacRuby/branches/testing/bootstraptest/test_objectspace.rb
MacRuby/branches/testing/bootstraptest/test_thread.rb
MacRuby/branches/testing/bs.c
MacRuby/branches/testing/class.c
MacRuby/branches/testing/common.mk
MacRuby/branches/testing/compar.c
MacRuby/branches/testing/compile.c
MacRuby/branches/testing/compile.h
MacRuby/branches/testing/configure.in
MacRuby/branches/testing/cont.c
MacRuby/branches/testing/debug.c
MacRuby/branches/testing/debug.h
MacRuby/branches/testing/dir.c
MacRuby/branches/testing/dln.c
MacRuby/branches/testing/dln.h
MacRuby/branches/testing/dmyencoding.c
MacRuby/branches/testing/dmytranscode.c
MacRuby/branches/testing/doc/NEWS
MacRuby/branches/testing/enc/depend
MacRuby/branches/testing/enc/make_encdb.rb
MacRuby/branches/testing/enc/make_encmake.rb
MacRuby/branches/testing/enc/trans/make_transdb.rb
MacRuby/branches/testing/enc/trans/utf_16_32.c
MacRuby/branches/testing/encoding.c
MacRuby/branches/testing/enum.c
MacRuby/branches/testing/enumerator.c
MacRuby/branches/testing/error.c
MacRuby/branches/testing/eval.c
MacRuby/branches/testing/eval_error.c
MacRuby/branches/testing/eval_intern.h
MacRuby/branches/testing/eval_jump.c
MacRuby/branches/testing/eval_method.c
MacRuby/branches/testing/ext/dbm/dbm.c
MacRuby/branches/testing/ext/digest/defs.h
MacRuby/branches/testing/ext/dl/cfunc.c
MacRuby/branches/testing/ext/dl/win32/lib/win32/registry.rb
MacRuby/branches/testing/ext/dl/win32/lib/win32/resolv.rb
MacRuby/branches/testing/ext/extmk.rb
MacRuby/branches/testing/ext/gdbm/gdbm.c
MacRuby/branches/testing/ext/iconv/iconv.c
MacRuby/branches/testing/ext/json/ext/generator/generator.c
MacRuby/branches/testing/ext/nkf/nkf-utf8/nkf.c
MacRuby/branches/testing/ext/nkf/nkf.c
MacRuby/branches/testing/ext/openssl/lib/openssl/digest.rb
MacRuby/branches/testing/ext/openssl/openssl_missing.c
MacRuby/branches/testing/ext/openssl/openssl_missing.h
MacRuby/branches/testing/ext/openssl/ossl_asn1.c
MacRuby/branches/testing/ext/openssl/ossl_config.c
MacRuby/branches/testing/ext/openssl/ossl_digest.c
MacRuby/branches/testing/ext/openssl/ossl_hmac.c
MacRuby/branches/testing/ext/openssl/ossl_ocsp.c
MacRuby/branches/testing/ext/openssl/ossl_pkey_dh.c
MacRuby/branches/testing/ext/openssl/ossl_pkey_dsa.c
MacRuby/branches/testing/ext/openssl/ossl_pkey_ec.c
MacRuby/branches/testing/ext/openssl/ossl_pkey_rsa.c
MacRuby/branches/testing/ext/openssl/ossl_ssl.c
MacRuby/branches/testing/ext/openssl/ossl_ssl_session.c
MacRuby/branches/testing/ext/openssl/ossl_version.h
MacRuby/branches/testing/ext/openssl/ossl_x509cert.c
MacRuby/branches/testing/ext/openssl/ossl_x509crl.c
MacRuby/branches/testing/ext/openssl/ossl_x509ext.c
MacRuby/branches/testing/ext/openssl/ossl_x509name.c
MacRuby/branches/testing/ext/openssl/ossl_x509req.c
MacRuby/branches/testing/ext/openssl/ossl_x509revoked.c
MacRuby/branches/testing/ext/purelib.rb
MacRuby/branches/testing/ext/racc/cparse/cparse.c
MacRuby/branches/testing/ext/readline/extconf.rb
MacRuby/branches/testing/ext/readline/readline.c
MacRuby/branches/testing/ext/sdbm/init.c
MacRuby/branches/testing/ext/socket/socket.c
MacRuby/branches/testing/ext/stringio/stringio.c
MacRuby/branches/testing/ext/strscan/strscan.c
MacRuby/branches/testing/ext/syck/emitter.c
MacRuby/branches/testing/ext/syck/implicit.c
MacRuby/branches/testing/ext/syck/rubyext.c
MacRuby/branches/testing/ext/syck/syck.c
MacRuby/branches/testing/ext/syck/syck.h
MacRuby/branches/testing/ext/syslog/syslog.txt
MacRuby/branches/testing/ext/tk/extconf.rb
MacRuby/branches/testing/ext/tk/lib/multi-tk.rb
MacRuby/branches/testing/ext/tk/lib/tk/autoload.rb
MacRuby/branches/testing/ext/tk/stubs.c
MacRuby/branches/testing/ext/tk/tcltklib.c
MacRuby/branches/testing/ext/tk/tkutil/tkutil.c
MacRuby/branches/testing/ext/win32ole/win32ole.c
MacRuby/branches/testing/ext/zlib/zlib.c
MacRuby/branches/testing/file.c
MacRuby/branches/testing/gc.c
MacRuby/branches/testing/gem_prelude.rb
MacRuby/branches/testing/golf_prelude.rb
MacRuby/branches/testing/hash.c
MacRuby/branches/testing/include/ruby/defines.h
MacRuby/branches/testing/include/ruby/encoding.h
MacRuby/branches/testing/include/ruby/intern.h
MacRuby/branches/testing/include/ruby/missing.h
MacRuby/branches/testing/include/ruby/node.h
MacRuby/branches/testing/include/ruby/ruby.h
MacRuby/branches/testing/include/ruby/win32.h
MacRuby/branches/testing/inits.c
MacRuby/branches/testing/insns.def
MacRuby/branches/testing/instruby.rb
MacRuby/branches/testing/io.c
MacRuby/branches/testing/iseq.c
MacRuby/branches/testing/lib/cgi.rb
MacRuby/branches/testing/lib/complex.rb
MacRuby/branches/testing/lib/csv.rb
MacRuby/branches/testing/lib/date.rb
MacRuby/branches/testing/lib/debug.rb
MacRuby/branches/testing/lib/drb/drb.rb
MacRuby/branches/testing/lib/erb.rb
MacRuby/branches/testing/lib/getoptlong.rb
MacRuby/branches/testing/lib/ipaddr.rb
MacRuby/branches/testing/lib/irb/cmd/help.rb
MacRuby/branches/testing/lib/irb/init.rb
MacRuby/branches/testing/lib/irb/workspace.rb
MacRuby/branches/testing/lib/irb.rb
MacRuby/branches/testing/lib/mathn.rb
MacRuby/branches/testing/lib/mkmf.rb
MacRuby/branches/testing/lib/net/http.rb
MacRuby/branches/testing/lib/net/pop.rb
MacRuby/branches/testing/lib/net/smtp.rb
MacRuby/branches/testing/lib/net/telnet.rb
MacRuby/branches/testing/lib/open3.rb
MacRuby/branches/testing/lib/pstore.rb
MacRuby/branches/testing/lib/rational.rb
MacRuby/branches/testing/lib/rdoc/code_objects.rb
MacRuby/branches/testing/lib/rdoc/generator/html.rb
MacRuby/branches/testing/lib/rdoc/generator.rb
MacRuby/branches/testing/lib/rdoc/markup/inline.rb
MacRuby/branches/testing/lib/rdoc/markup/to_html.rb
MacRuby/branches/testing/lib/rdoc/markup.rb
MacRuby/branches/testing/lib/rdoc/options.rb
MacRuby/branches/testing/lib/rdoc/parsers/parse_rb.rb
MacRuby/branches/testing/lib/rdoc/rdoc.rb
MacRuby/branches/testing/lib/rdoc/ri/descriptions.rb
MacRuby/branches/testing/lib/rdoc/ri/display.rb
MacRuby/branches/testing/lib/rdoc/ri/driver.rb
MacRuby/branches/testing/lib/rdoc/ri/formatter.rb
MacRuby/branches/testing/lib/rdoc/ri/util.rb
MacRuby/branches/testing/lib/rdoc/ri/writer.rb
MacRuby/branches/testing/lib/rdoc/template.rb
MacRuby/branches/testing/lib/rdoc.rb
MacRuby/branches/testing/lib/resolv.rb
MacRuby/branches/testing/lib/rexml/document.rb
MacRuby/branches/testing/lib/rubygems/builder.rb
MacRuby/branches/testing/lib/rubygems/command_manager.rb
MacRuby/branches/testing/lib/rubygems/commands/cleanup_command.rb
MacRuby/branches/testing/lib/rubygems/commands/environment_command.rb
MacRuby/branches/testing/lib/rubygems/commands/fetch_command.rb
MacRuby/branches/testing/lib/rubygems/commands/install_command.rb
MacRuby/branches/testing/lib/rubygems/commands/list_command.rb
MacRuby/branches/testing/lib/rubygems/commands/mirror_command.rb
MacRuby/branches/testing/lib/rubygems/commands/pristine_command.rb
MacRuby/branches/testing/lib/rubygems/commands/query_command.rb
MacRuby/branches/testing/lib/rubygems/commands/sources_command.rb
MacRuby/branches/testing/lib/rubygems/commands/specification_command.rb
MacRuby/branches/testing/lib/rubygems/commands/uninstall_command.rb
MacRuby/branches/testing/lib/rubygems/commands/unpack_command.rb
MacRuby/branches/testing/lib/rubygems/commands/update_command.rb
MacRuby/branches/testing/lib/rubygems/custom_require.rb
MacRuby/branches/testing/lib/rubygems/defaults.rb
MacRuby/branches/testing/lib/rubygems/dependency_installer.rb
MacRuby/branches/testing/lib/rubygems/doc_manager.rb
MacRuby/branches/testing/lib/rubygems/exceptions.rb
MacRuby/branches/testing/lib/rubygems/format.rb
MacRuby/branches/testing/lib/rubygems/indexer/abstract_index_builder.rb
MacRuby/branches/testing/lib/rubygems/indexer/master_index_builder.rb
MacRuby/branches/testing/lib/rubygems/indexer/quick_index_builder.rb
MacRuby/branches/testing/lib/rubygems/indexer.rb
MacRuby/branches/testing/lib/rubygems/install_update_options.rb
MacRuby/branches/testing/lib/rubygems/installer.rb
MacRuby/branches/testing/lib/rubygems/package.rb
MacRuby/branches/testing/lib/rubygems/remote_fetcher.rb
MacRuby/branches/testing/lib/rubygems/requirement.rb
MacRuby/branches/testing/lib/rubygems/rubygems_version.rb
MacRuby/branches/testing/lib/rubygems/security.rb
MacRuby/branches/testing/lib/rubygems/server.rb
MacRuby/branches/testing/lib/rubygems/source_index.rb
MacRuby/branches/testing/lib/rubygems/source_info_cache.rb
MacRuby/branches/testing/lib/rubygems/source_info_cache_entry.rb
MacRuby/branches/testing/lib/rubygems/specification.rb
MacRuby/branches/testing/lib/rubygems/uninstaller.rb
MacRuby/branches/testing/lib/rubygems/user_interaction.rb
MacRuby/branches/testing/lib/rubygems/version_option.rb
MacRuby/branches/testing/lib/rubygems.rb
MacRuby/branches/testing/lib/set.rb
MacRuby/branches/testing/lib/shellwords.rb
MacRuby/branches/testing/lib/test/unit/testcase.rb
MacRuby/branches/testing/lib/webrick/httprequest.rb
MacRuby/branches/testing/lib/webrick/httpservlet/filehandler.rb
MacRuby/branches/testing/lib/xmlrpc/client.rb
MacRuby/branches/testing/lib/yaml/store.rb
MacRuby/branches/testing/load.c
MacRuby/branches/testing/marshal.c
MacRuby/branches/testing/math.c
MacRuby/branches/testing/misc/README
MacRuby/branches/testing/misc/ruby-mode.el
MacRuby/branches/testing/misc/ruby-style.el
MacRuby/branches/testing/missing/lgamma_r.c
MacRuby/branches/testing/missing/tgamma.c
MacRuby/branches/testing/missing/vsnprintf.c
MacRuby/branches/testing/numeric.c
MacRuby/branches/testing/objc.m
MacRuby/branches/testing/object.c
MacRuby/branches/testing/pack.c
MacRuby/branches/testing/parse.y
MacRuby/branches/testing/prelude.rb
MacRuby/branches/testing/proc.c
MacRuby/branches/testing/process.c
MacRuby/branches/testing/random.c
MacRuby/branches/testing/range.c
MacRuby/branches/testing/re.c
MacRuby/branches/testing/regexec.c
MacRuby/branches/testing/regint.h
MacRuby/branches/testing/regparse.c
MacRuby/branches/testing/ruby.1
MacRuby/branches/testing/ruby.c
MacRuby/branches/testing/sample/test.rb
MacRuby/branches/testing/sample-macruby/Scripts/hello_world.rb
MacRuby/branches/testing/sample-macruby/Scripts/transparent_hello.rb
MacRuby/branches/testing/signal.c
MacRuby/branches/testing/sprintf.c
MacRuby/branches/testing/st.c
MacRuby/branches/testing/string.c
MacRuby/branches/testing/struct.c
MacRuby/branches/testing/template/insns.inc.tmpl
MacRuby/branches/testing/template/insns_info.inc.tmpl
MacRuby/branches/testing/template/opt_sc.inc.tmpl
MacRuby/branches/testing/template/optunifs.inc.tmpl
MacRuby/branches/testing/test/erb/test_erb.rb
MacRuby/branches/testing/test/gdbm/test_gdbm.rb
MacRuby/branches/testing/test/io/nonblock/test_flush.rb
MacRuby/branches/testing/test/net/imap/test_imap.rb
MacRuby/branches/testing/test/openssl/test_ssl.rb
MacRuby/branches/testing/test/openssl/utils.rb
MacRuby/branches/testing/test/rdoc/test_rdoc_c_parser.rb
MacRuby/branches/testing/test/rdoc/test_rdoc_markup_attribute_manager.rb
MacRuby/branches/testing/test/rdoc/test_rdoc_ri_formatter.rb
MacRuby/branches/testing/test/ruby/envutil.rb
MacRuby/branches/testing/test/ruby/marshaltestlib.rb
MacRuby/branches/testing/test/ruby/test_array.rb
MacRuby/branches/testing/test/ruby/test_assignment.rb
MacRuby/branches/testing/test/ruby/test_beginendblock.rb
MacRuby/branches/testing/test/ruby/test_bignum.rb
MacRuby/branches/testing/test/ruby/test_class.rb
MacRuby/branches/testing/test/ruby/test_continuation.rb
MacRuby/branches/testing/test/ruby/test_enum.rb
MacRuby/branches/testing/test/ruby/test_enumerator.rb
MacRuby/branches/testing/test/ruby/test_env.rb
MacRuby/branches/testing/test/ruby/test_eval.rb
MacRuby/branches/testing/test/ruby/test_exception.rb
MacRuby/branches/testing/test/ruby/test_file.rb
MacRuby/branches/testing/test/ruby/test_file_exhaustive.rb
MacRuby/branches/testing/test/ruby/test_fixnum.rb
MacRuby/branches/testing/test/ruby/test_float.rb
MacRuby/branches/testing/test/ruby/test_hash.rb
MacRuby/branches/testing/test/ruby/test_integer.rb
MacRuby/branches/testing/test/ruby/test_io.rb
MacRuby/branches/testing/test/ruby/test_io_m17n.rb
MacRuby/branches/testing/test/ruby/test_iterator.rb
MacRuby/branches/testing/test/ruby/test_literal.rb
MacRuby/branches/testing/test/ruby/test_m17n.rb
MacRuby/branches/testing/test/ruby/test_m17n_comb.rb
MacRuby/branches/testing/test/ruby/test_marshal.rb
MacRuby/branches/testing/test/ruby/test_math.rb
MacRuby/branches/testing/test/ruby/test_method.rb
MacRuby/branches/testing/test/ruby/test_module.rb
MacRuby/branches/testing/test/ruby/test_numeric.rb
MacRuby/branches/testing/test/ruby/test_objectspace.rb
MacRuby/branches/testing/test/ruby/test_pack.rb
MacRuby/branches/testing/test/ruby/test_pipe.rb
MacRuby/branches/testing/test/ruby/test_process.rb
MacRuby/branches/testing/test/ruby/test_rand.rb
MacRuby/branches/testing/test/ruby/test_range.rb
MacRuby/branches/testing/test/ruby/test_regexp.rb
MacRuby/branches/testing/test/ruby/test_settracefunc.rb
MacRuby/branches/testing/test/ruby/test_sprintf.rb
MacRuby/branches/testing/test/ruby/test_sprintf_comb.rb
MacRuby/branches/testing/test/ruby/test_string.rb
MacRuby/branches/testing/test/ruby/test_stringchar.rb
MacRuby/branches/testing/test/ruby/test_struct.rb
MacRuby/branches/testing/test/ruby/test_symbol.rb
MacRuby/branches/testing/test/ruby/test_system.rb
MacRuby/branches/testing/test/ruby/test_thread.rb
MacRuby/branches/testing/test/ruby/test_time.rb
MacRuby/branches/testing/test/ruby/test_trace.rb
MacRuby/branches/testing/test/ruby/test_transcode.rb
MacRuby/branches/testing/test/ruby/test_utf16.rb
MacRuby/branches/testing/test/ruby/test_variable.rb
MacRuby/branches/testing/test/ruby/test_yield.rb
MacRuby/branches/testing/test/rubygems/gemutilities.rb
MacRuby/branches/testing/test/rubygems/mockgemui.rb
MacRuby/branches/testing/test/rubygems/test_gem.rb
MacRuby/branches/testing/test/rubygems/test_gem_command_manager.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_environment_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_fetch_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_install_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_query_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_server_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_sources_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_specification_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_commands_unpack_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_dependency_installer.rb
MacRuby/branches/testing/test/rubygems/test_gem_ext_configure_builder.rb
MacRuby/branches/testing/test/rubygems/test_gem_format.rb
MacRuby/branches/testing/test/rubygems/test_gem_indexer.rb
MacRuby/branches/testing/test/rubygems/test_gem_installer.rb
MacRuby/branches/testing/test/rubygems/test_gem_remote_fetcher.rb
MacRuby/branches/testing/test/rubygems/test_gem_server.rb
MacRuby/branches/testing/test/rubygems/test_gem_source_index.rb
MacRuby/branches/testing/test/rubygems/test_gem_source_info_cache.rb
MacRuby/branches/testing/test/rubygems/test_gem_source_info_cache_entry.rb
MacRuby/branches/testing/test/stringio/test_stringio.rb
MacRuby/branches/testing/test/strscan/test_stringscanner.rb
MacRuby/branches/testing/test/webrick/test_filehandler.rb
MacRuby/branches/testing/test-macruby/test_boxed.rb
MacRuby/branches/testing/thread.c
MacRuby/branches/testing/thread_pthread.c
MacRuby/branches/testing/thread_win32.c
MacRuby/branches/testing/time.c
MacRuby/branches/testing/tool/compile_prelude.rb
MacRuby/branches/testing/tool/instruction.rb
MacRuby/branches/testing/transcode.c
MacRuby/branches/testing/util.c
MacRuby/branches/testing/variable.c
MacRuby/branches/testing/version.c
MacRuby/branches/testing/version.h
MacRuby/branches/testing/vm.c
MacRuby/branches/testing/vm_core.h
MacRuby/branches/testing/vm_dump.c
MacRuby/branches/testing/vm_evalbody.c
MacRuby/branches/testing/vm_insnhelper.c
MacRuby/branches/testing/win32/Makefile.sub
MacRuby/branches/testing/win32/win32.c
Added Paths:
-----------
MacRuby/branches/testing/.cvsignore
MacRuby/branches/testing/.document
MacRuby/branches/testing/benchmark/bm_app_mergesort.rb
MacRuby/branches/testing/complex.c
MacRuby/branches/testing/enc/prelude.rb
MacRuby/branches/testing/lib/rdoc/markup/attribute_manager.rb
MacRuby/branches/testing/lib/rubygems/indexer/latest_index_builder.rb
MacRuby/branches/testing/lib/rubygems/package/
MacRuby/branches/testing/lib/rubygems/package/f_sync_dir.rb
MacRuby/branches/testing/lib/rubygems/package/tar_header.rb
MacRuby/branches/testing/lib/rubygems/package/tar_input.rb
MacRuby/branches/testing/lib/rubygems/package/tar_output.rb
MacRuby/branches/testing/lib/rubygems/package/tar_reader/
MacRuby/branches/testing/lib/rubygems/package/tar_reader/entry.rb
MacRuby/branches/testing/lib/rubygems/package/tar_reader.rb
MacRuby/branches/testing/lib/rubygems/package/tar_writer.rb
MacRuby/branches/testing/rational.c
MacRuby/branches/testing/test/erb/hello.erb
MacRuby/branches/testing/test/rdoc/test_rdoc_ri_default_display.rb
MacRuby/branches/testing/test/ruby/allpairs.rb
MacRuby/branches/testing/test/ruby/lbtest.rb
MacRuby/branches/testing/test/ruby/test_comparable.rb
MacRuby/branches/testing/test/ruby/test_complex.rb
MacRuby/branches/testing/test/ruby/test_integer_comb.rb
MacRuby/branches/testing/test/ruby/test_objc.rb
MacRuby/branches/testing/test/ruby/test_object.rb
MacRuby/branches/testing/test/ruby/test_parse.rb
MacRuby/branches/testing/test/ruby/test_rational.rb
MacRuby/branches/testing/test/ruby/test_rational2.rb
MacRuby/branches/testing/test/ruby/test_rubyoptions.rb
MacRuby/branches/testing/test/ruby/test_utf32.rb
MacRuby/branches/testing/test/rubygems/gem_installer_test_case.rb
MacRuby/branches/testing/test/rubygems/gem_package_tar_test_case.rb
MacRuby/branches/testing/test/rubygems/private_key.pem
MacRuby/branches/testing/test/rubygems/public_cert.pem
MacRuby/branches/testing/test/rubygems/test_gem_commands_update_command.rb
MacRuby/branches/testing/test/rubygems/test_gem_package_tar_header.rb
MacRuby/branches/testing/test/rubygems/test_gem_package_tar_input.rb
MacRuby/branches/testing/test/rubygems/test_gem_package_tar_output.rb
MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader.rb
MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader_entry.rb
MacRuby/branches/testing/test/rubygems/test_gem_package_tar_writer.rb
MacRuby/branches/testing/test/rubygems/test_gem_uninstaller.rb
MacRuby/branches/testing/test/test_pstore.rb
MacRuby/branches/testing/test/xmlrpc/test_cookie.rb
MacRuby/branches/testing/test/yaml/test_yamlstore.rb
MacRuby/branches/testing/test-macruby/test_hash.rb
Removed Paths:
-------------
MacRuby/branches/testing/.cvsignore
MacRuby/branches/testing/.document
MacRuby/branches/testing/lib/rubygems/package/f_sync_dir.rb
MacRuby/branches/testing/lib/rubygems/package/tar_header.rb
MacRuby/branches/testing/lib/rubygems/package/tar_input.rb
MacRuby/branches/testing/lib/rubygems/package/tar_output.rb
MacRuby/branches/testing/lib/rubygems/package/tar_reader/
MacRuby/branches/testing/lib/rubygems/package/tar_reader/entry.rb
MacRuby/branches/testing/lib/rubygems/package/tar_reader.rb
MacRuby/branches/testing/lib/rubygems/package/tar_writer.rb
MacRuby/branches/testing/test/rubygems/test_open_uri.rb
MacRuby/branches/testing/test/rubygems/test_package.rb
MacRuby/branches/testing/test/test_generator.rb
Deleted: MacRuby/branches/testing/.cvsignore
===================================================================
--- MacRuby/branches/testing/.cvsignore 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/.cvsignore 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,52 +0,0 @@
-*.bak
-*.orig
-*.rej
-*.sav
-*~
-.*.list
-.*.time
-.ccmalloc
-.ppack
-.ext
-.git
-.svn
-.pc
-COPYING.LIB
-ChangeLog.pre-alpha
-ChangeLog.pre1_1
-ChangeLog-1.8.0
-Makefile
-README.fat-patch
-README.v6
-README.atheos
-archive
-autom4te*.cache
-automake
-beos
-config.cache
-config.h
-config.h.in
-config.log
-config.status
-configure
-libruby.so.*
-miniruby
-newdate.rb
-newver.rb
-parse.c
-patches
-patches-master
-pitest.rb
-ppack
-preview
-rbconfig.rb
-rename2.h
-repack
-riscos
-rubicon
-ruby
-ruby-man.rd.gz
-tmp
-web
-y.output
-y.tab.c
Copied: MacRuby/branches/testing/.cvsignore (from rev 232, MacRuby/trunk/.cvsignore)
===================================================================
--- MacRuby/branches/testing/.cvsignore (rev 0)
+++ MacRuby/branches/testing/.cvsignore 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,52 @@
+*.bak
+*.orig
+*.rej
+*.sav
+*~
+.*.list
+.*.time
+.ccmalloc
+.ppack
+.ext
+.git
+.svn
+.pc
+COPYING.LIB
+ChangeLog.pre-alpha
+ChangeLog.pre1_1
+ChangeLog-1.8.0
+Makefile
+README.fat-patch
+README.v6
+README.atheos
+archive
+autom4te*.cache
+automake
+beos
+config.cache
+config.h
+config.h.in
+config.log
+config.status
+configure
+libruby.so.*
+miniruby
+newdate.rb
+newver.rb
+parse.c
+patches
+patches-master
+pitest.rb
+ppack
+preview
+rbconfig.rb
+rename2.h
+repack
+riscos
+rubicon
+ruby
+ruby-man.rd.gz
+tmp
+web
+y.output
+y.tab.c
Deleted: MacRuby/branches/testing/.document
===================================================================
--- MacRuby/branches/testing/.document 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/.document 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,16 +0,0 @@
-# This file determines which files in the
-# Ruby hierarchy will be processed by the RDoc
-# tool when it is given the top-level directory
-# as an argument
-
-# Process all the C source files
-*.c
-
-# the lib/ directory (which has its own .document file)
-
-lib
-
-
-# and some of the ext/ directory (which has its own .document file)
-
-ext
Copied: MacRuby/branches/testing/.document (from rev 232, MacRuby/trunk/.document)
===================================================================
--- MacRuby/branches/testing/.document (rev 0)
+++ MacRuby/branches/testing/.document 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,16 @@
+# This file determines which files in the
+# Ruby hierarchy will be processed by the RDoc
+# tool when it is given the top-level directory
+# as an argument
+
+# Process all the C source files
+*.c
+
+# the lib/ directory (which has its own .document file)
+
+lib
+
+
+# and some of the ext/ directory (which has its own .document file)
+
+ext
Modified: MacRuby/branches/testing/ChangeLog
===================================================================
--- MacRuby/branches/testing/ChangeLog 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ChangeLog 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/Makefile.in
===================================================================
--- MacRuby/branches/testing/Makefile.in 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/Makefile.in 2008-05-28 20:03:03 UTC (rev 233)
@@ -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@
@@ -198,6 +201,7 @@
clean-local::
@$(RM) ext/extinit.c ext/extinit.$(OBJEXT) ext/ripper/y.output
+ @$(RM) gc-stub.$(OBJEXT)
distclean-local::
@$(RM) ext/config.cache $(RBCONFIG)
Modified: MacRuby/branches/testing/array.c
===================================================================
--- MacRuby/branches/testing/array.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/array.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -16,6 +16,10 @@
#include "ruby/st.h"
VALUE rb_cArray;
+#if WITH_OBJC
+VALUE rb_cCFArray;
+VALUE rb_cArrayRuby;
+#endif
static ID id_cmp;
@@ -37,6 +41,37 @@
}
}
+#if WITH_OBJC
+/* TODO optimize this */
+struct rb_objc_ary_struct {
+ bool named_args;
+ void *cptr;
+};
+
+/* This variable will always stay NULL, we only use its address. */
+static void *rb_objc_ary_assoc_key = NULL;
+
+static struct rb_objc_ary_struct *
+rb_objc_ary_get_struct(VALUE ary)
+{
+ return rb_objc_get_associative_ref((void *)ary, &rb_objc_ary_assoc_key);
+}
+
+static struct rb_objc_ary_struct *
+rb_objc_ary_get_struct2(VALUE ary)
+{
+ struct rb_objc_ary_struct *s;
+
+ s = rb_objc_ary_get_struct(ary);
+ if (s == NULL) {
+ s = xmalloc(sizeof(struct rb_objc_ary_struct));
+ rb_objc_set_associative_ref((void *)ary, &rb_objc_ary_assoc_key, s);
+ s->named_args = false;
+ s->cptr = NULL;
+ }
+ return s;
+}
+#else
#define ARY_SHARED_P(a) FL_TEST(a, ELTS_SHARED)
#define ARY_SET_LEN(ary, n) do { \
@@ -48,10 +83,34 @@
REALLOC_N(RARRAY(ary)->ptr, VALUE, (capacity));\
RARRAY(ary)->aux.capa = (capacity);\
} while (0)
+#endif
+VALUE rb_ary_frozen_p(VALUE ary);
+
+#if WITH_OBJC
+
static inline void
rb_ary_modify_check(VALUE ary)
{
+ long mask;
+ mask = rb_objc_flag_get_mask(ary);
+ if (mask == 0) {
+ bool _CFArrayIsMutable(void *);
+ if (!_CFArrayIsMutable((void *)ary))
+ mask |= FL_FREEZE;
+ }
+ if ((mask & FL_FREEZE) == FL_FREEZE)
+ rb_raise(rb_eRuntimeError, "can't modify frozen/immutable array");
+ if ((mask & FL_TAINT) == FL_TAINT && rb_safe_level() >= 4)
+ rb_raise(rb_eSecurityError, "Insecure: can't modify array");
+}
+#define rb_ary_modify rb_ary_modify_check
+
+#else
+
+static inline void
+rb_ary_modify_check(VALUE ary)
+{
if (OBJ_FROZEN(ary)) rb_error_frozen("array");
if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify array");
@@ -71,6 +130,7 @@
RARRAY(ary)->ptr = ptr;
}
}
+#endif
VALUE
rb_ary_freeze(VALUE ary)
@@ -86,16 +146,60 @@
* while being sorted).
*/
-static VALUE
+VALUE
rb_ary_frozen_p(VALUE ary)
{
if (OBJ_FROZEN(ary)) return Qtrue;
return Qfalse;
}
+#if WITH_OBJC
+int rb_any_cmp(VALUE a, VALUE b);
+
+static Boolean
+rb_cfarray_equal_cb(const void *v1, const void *v2)
+{
+ return !rb_any_cmp((VALUE)v1, (VALUE)v2);
+}
+
+static const void *
+rb_cfarray_retain_cb(CFAllocatorRef allocator, const void *v)
+{
+ rb_objc_retain(v);
+ return v;
+}
+
+static void
+rb_cfarray_release_cb(CFAllocatorRef allocator, const void *v)
+{
+ rb_objc_release(v);
+}
+
+static void
+rb_ary_insert(VALUE ary, long idx, VALUE val);
+#endif
+
static VALUE
ary_alloc(VALUE klass)
{
+#if WITH_OBJC
+ VALUE ary;
+ CFArrayCallBacks cb;
+
+ memset(&cb, 0, sizeof(CFArrayCallBacks));
+ cb.retain = rb_cfarray_retain_cb;
+ cb.release = rb_cfarray_release_cb;
+ cb.equal = rb_cfarray_equal_cb;
+
+ ary = (VALUE)CFArrayCreateMutable(NULL, 0, &cb);
+ if (klass != 0 && klass != rb_cArray && klass != rb_cArrayRuby)
+ *(Class *)ary = RCLASS_OCID(klass);
+
+ CFMakeCollectable((CFTypeRef)ary);
+ rb_gc_malloc_increase(sizeof(void *));
+
+ return ary;
+#else
NEWOBJ(ary, struct RArray);
OBJSETUP(ary, klass, T_ARRAY);
@@ -104,6 +208,7 @@
ary->aux.capa = 0;
return (VALUE)ary;
+#endif
}
static VALUE
@@ -114,13 +219,15 @@
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);
+#if !WITH_OBJC
if (len == 0) len++;
GC_WB(&RARRAY(ary)->ptr, ALLOC_N(VALUE, len));
RARRAY(ary)->aux.capa = len;
+#endif
return ary;
}
@@ -128,7 +235,11 @@
VALUE
rb_ary_new2(long len)
{
+#if WITH_OBJC
+ return ary_new(0, len);
+#else
return ary_new(rb_cArray, len);
+#endif
}
@@ -151,11 +262,13 @@
va_start(ar, n);
for (i=0; i<n; i++) {
- RARRAY_PTR(ary)[i] = va_arg(ar, VALUE);
+ rb_ary_insert(ary, i, va_arg(ar, VALUE));
}
va_end(ar);
+#if !WITH_OBJC
RARRAY(ary)->len = n;
+#endif
return ary;
}
@@ -166,8 +279,12 @@
ary = rb_ary_new2(n);
if (n > 0 && elts) {
+#if WITH_OBJC
+ CFArrayReplaceValues((CFMutableArrayRef)ary, CFRangeMake(0, 0), (const void **)elts, n);
+#else
MEMCPY(RARRAY_PTR(ary), elts, VALUE, n);
RARRAY(ary)->len = n;
+#endif
}
return ary;
@@ -176,11 +293,16 @@
void
rb_ary_free(VALUE ary)
{
+#if WITH_OBJC
+ rb_notimplement();
+#else
if (!ARY_SHARED_P(ary)) {
xfree(RARRAY(ary)->ptr);
}
+#endif
}
+#if !WITH_OBJC
static VALUE
ary_make_shared(VALUE ary)
{
@@ -200,6 +322,7 @@
return (VALUE)shared;
}
}
+#endif
VALUE
rb_assoc_new(VALUE car, VALUE cdr)
@@ -291,10 +414,12 @@
rb_ary_modify(ary);
if (rb_scan_args(argc, argv, "02", &size, &val) == 0) {
+#if !WITH_OBJC
if (RARRAY_PTR(ary) && !ARY_SHARED_P(ary)) {
free(RARRAY(ary)->ptr);
}
RARRAY(ary)->len = 0;
+#endif
if (rb_block_given_p()) {
rb_warning("given block not used");
}
@@ -313,11 +438,13 @@
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);
- RESIZE_CAPA(ary, len);
+#if !WITH_OBJC
+ RESIZE_CAPA(ary, len);
+#endif
if (rb_block_given_p()) {
long i;
@@ -325,13 +452,21 @@
rb_warn("block supersedes default value argument");
}
for (i=0; i<len; i++) {
- rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
+ rb_ary_insert(ary, i, rb_yield(LONG2NUM(i)));
+#if !WITH_OBJC
RARRAY(ary)->len = i + 1;
+#endif
}
}
else {
+#if WITH_OBJC
+ long i;
+ for (i=0; i<len; i++)
+ rb_ary_insert(ary, i, val);
+#else
memfill(RARRAY_PTR(ary), len, val);
RARRAY(ary)->len = len;
+#endif
}
return ary;
}
@@ -353,16 +488,22 @@
if (argc < 0) {
rb_raise(rb_eArgError, "negative array size");
}
+#if WITH_OBJC
+ CFArrayReplaceValues((CFMutableArrayRef)ary, CFRangeMake(0, 0),
+ (const void **)argv, argc);
+#else
RARRAY(ary)->ptr = ALLOC_N(VALUE, argc);
RARRAY(ary)->aux.capa = argc;
MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
RARRAY(ary)->len = argc;
-
+#endif
+
return ary;
}
-void
-rb_ary_store(VALUE ary, long idx, VALUE val)
+#if WITH_OBJC
+static void
+rb_ary_insert(VALUE ary, long idx, VALUE val)
{
if (idx < 0) {
idx += RARRAY_LEN(ary);
@@ -373,6 +514,48 @@
}
rb_ary_modify(ary);
+
+ CFArrayInsertValueAtIndex((CFMutableArrayRef)ary, idx,
+ (const void *)val);
+}
+#endif
+
+void
+rb_ary_store(VALUE ary, long idx, VALUE val)
+{
+ long len = RARRAY_LEN(ary);
+ if (idx < 0) {
+ idx += len;
+ if (idx < 0) {
+ rb_raise(rb_eIndexError, "index %ld out of array",
+ idx - len);
+ }
+ }
+
+ rb_ary_modify(ary);
+
+#if WITH_OBJC
+ if (idx > len) {
+ const void **objs;
+ long i;
+ if (idx > sizeof(CFIndex))
+ if ((idx - len) * (long)sizeof(VALUE) <= idx - len)
+ rb_raise(rb_eArgError, "index too big");
+ objs = (const void **)alloca(sizeof(void *) * (idx - len));
+ if (objs == NULL)
+ rb_raise(rb_eArgError, "index too big");
+ for (i = 0; i < (idx - len); i++)
+ objs[i] = (const void *)Qnil;
+ CFArrayReplaceValues((CFMutableArrayRef)ary,
+ CFRangeMake(len, 0),
+ objs,
+ idx - len);
+ CFArrayAppendValue((CFMutableArrayRef)ary, (const void *)val);
+ }
+ else {
+ CFArraySetValueAtIndex((CFMutableArrayRef)ary, idx, (const void *)val);
+ }
+#else
if (idx >= ARY_CAPA(ary)) {
long new_capa = ARY_CAPA(ary) / 2;
@@ -397,8 +580,10 @@
RARRAY(ary)->len = idx + 1;
}
GC_WB(&RARRAY_PTR(ary)[idx], val);
+#endif
}
+#if !WITH_OBJC
static VALUE
ary_shared_array(VALUE klass, VALUE ary)
{
@@ -411,28 +596,38 @@
FL_SET(val, ELTS_SHARED);
return val;
}
+#endif
static VALUE
-ary_shared_first(int argc, VALUE *argv, VALUE ary, int last)
+ary_shared_first(int argc, VALUE *argv, VALUE ary, int last, bool remove)
{
VALUE nv, result;
long n;
long offset = 0;
+ long ary_len;
rb_scan_args(argc, argv, "1", &nv);
n = NUM2LONG(nv);
- if (n > RARRAY_LEN(ary)) {
- n = RARRAY_LEN(ary);
+ ary_len = RARRAY_LEN(ary);
+ if (n > ary_len) {
+ n = ary_len;
}
else if (n < 0) {
rb_raise(rb_eArgError, "negative array size");
}
if (last) {
- offset = RARRAY_LEN(ary) - n;
+ offset = ary_len - n;
}
+#if WITH_OBJC
+ result = rb_ary_new();
+ CFArrayAppendArray((CFMutableArrayRef)result, (CFArrayRef)ary, CFRangeMake(offset, n));
+ if (remove)
+ CFArrayReplaceValues((CFMutableArrayRef)ary, CFRangeMake(offset, n), NULL, 0);
+#else
result = ary_shared_array(rb_cArray, ary);
RARRAY(result)->ptr += offset;
RARRAY(result)->len = n;
+#endif
return result;
}
@@ -453,7 +648,12 @@
VALUE
rb_ary_push(VALUE ary, VALUE item)
{
+#if WITH_OBJC
+ rb_ary_modify(ary);
+ CFArrayAppendValue((CFMutableArrayRef)ary, (const void *)item);
+#else
rb_ary_store(ary, RARRAY_LEN(ary), item);
+#endif
return ary;
}
@@ -484,6 +684,17 @@
{
long n;
rb_ary_modify_check(ary);
+#if WITH_OBJC
+ n = RARRAY_LEN(ary);
+ if (n == 0) {
+ return Qnil;
+ }
+ else {
+ VALUE val = RARRAY_AT(ary, n - 1);
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, n - 1);
+ return val;
+ }
+#else
if (RARRAY_LEN(ary) == 0) return Qnil;
if (!ARY_SHARED_P(ary) &&
RARRAY_LEN(ary) * 3 < ARY_CAPA(ary) &&
@@ -494,15 +705,20 @@
n = RARRAY_LEN(ary)-1;
RARRAY(ary)->len = n;
return RARRAY_PTR(ary)[n];
+#endif
}
/*
* 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"]
@@ -519,8 +735,10 @@
}
rb_ary_modify_check(ary);
- result = ary_shared_first(argc, argv, ary, Qtrue);
+ result = ary_shared_first(argc, argv, ary, Qtrue, true);
+#if !WITH_OBJC
RARRAY(ary)->len -= RARRAY_LEN(result);
+#endif
return result;
}
@@ -531,6 +749,10 @@
rb_ary_modify_check(ary);
if (RARRAY_LEN(ary) == 0) return Qnil;
+#if WITH_OBJC
+ top = RARRAY_AT(ary, 0);
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, 0);
+#else
top = RARRAY_PTR(ary)[0];
if (!ARY_SHARED_P(ary)) {
if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
@@ -544,17 +766,22 @@
RARRAY(ary)->ptr++; /* shift ptr */
RARRAY(ary)->len--;
+#endif
return top;
}
/*
* 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"]
@@ -575,7 +802,8 @@
}
rb_ary_modify_check(ary);
- result = ary_shared_first(argc, argv, ary, Qfalse);
+ result = ary_shared_first(argc, argv, ary, Qfalse, true);
+#if !WITH_OBJC
n = RARRAY_LEN(result);
if (ARY_SHARED_P(ary)) {
RARRAY(ary)->ptr += n;
@@ -585,6 +813,7 @@
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n);
RARRAY(ary)->len -= n;
}
+#endif
return result;
}
@@ -608,6 +837,14 @@
if (argc == 0) return ary;
rb_ary_modify(ary);
+#if WITH_OBJC
+ {
+ long i;
+ for (i = argc - 1; i >= 0; i--)
+ CFArrayInsertValueAtIndex((CFMutableArrayRef)ary,
+ 0, (const void *)argv[i]);
+ }
+#else
if (RARRAY(ary)->aux.capa <= (len = RARRAY(ary)->len) + argc) {
RESIZE_CAPA(ary, len + argc + ARY_DEFAULT_SIZE);
}
@@ -616,7 +853,8 @@
MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len);
MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
RARRAY(ary)->len += argc;
-
+#endif
+
return ary;
}
@@ -627,6 +865,18 @@
}
/* faster version - use this if you don't need to treat negative offset */
+#if WITH_OBJC
+VALUE
+rb_ary_elt(VALUE ary, long offset)
+{
+ long n = RARRAY_LEN(ary);
+ if (n == 0)
+ return Qnil;
+ if (offset < 0 || n <= offset)
+ return Qnil;
+ return (VALUE)CFArrayGetValueAtIndex((CFArrayRef)ary, offset);
+}
+#else
static inline VALUE
rb_ary_elt(VALUE ary, long offset)
{
@@ -636,7 +886,32 @@
}
return RARRAY_PTR(ary)[offset];
}
+#endif
+const VALUE *
+rb_ary_ptr(VALUE ary)
+{
+#if WITH_OBJC
+ /* FIXME we could inline __CFArrayGetBucketsPtr for non-store arrays,
+ * for performance reasons.
+ */
+ const VALUE *values;
+ long len;
+
+ len = RARRAY_LEN(ary);
+ if (len == 0)
+ return NULL;
+ values = (const VALUE *)xmalloc(sizeof(VALUE) * len);
+ CFArrayGetValues((CFArrayRef)ary, CFRangeMake(0, len),
+ (const void **)values);
+ GC_WB(&rb_objc_ary_get_struct2(ary)->cptr, values);
+
+ return values;
+#else
+ return RARRAY_PTR(ary);
+#endif
+}
+
VALUE
rb_ary_entry(VALUE ary, long offset)
{
@@ -649,6 +924,32 @@
VALUE
rb_ary_subseq(VALUE ary, long beg, long len)
{
+#if WITH_OBJC
+ long n;
+ VALUE newary;
+ VALUE klass;
+
+ if (beg < 0 || len < 0)
+ return Qnil;
+
+ n = RARRAY_LEN(ary);
+ if (beg > n)
+ return Qnil;
+
+ if (n < len || n < beg + len)
+ len = n - beg;
+
+ klass = rb_obj_class(ary);
+ newary = ary_alloc(klass);
+ if (len > 0) {
+ const void **values;
+ values = alloca(sizeof(void *) * len);
+ CFArrayGetValues((CFArrayRef)ary, CFRangeMake(beg, len), values);
+ CFArrayReplaceValues((CFMutableArrayRef)newary, CFRangeMake(0, 0),
+ values, len);
+ }
+ return newary;
+#else
VALUE klass, ary2, shared;
VALUE *ptr;
@@ -670,6 +971,7 @@
FL_SET(ary2, ELTS_SHARED);
return ary2;
+#endif
}
/*
@@ -776,10 +1078,10 @@
{
if (argc == 0) {
if (RARRAY_LEN(ary) == 0) return Qnil;
- return RARRAY_PTR(ary)[0];
+ return RARRAY_AT(ary, 0);
}
else {
- return ary_shared_first(argc, argv, ary, Qfalse);
+ return ary_shared_first(argc, argv, ary, Qfalse, false);
}
}
@@ -800,11 +1102,12 @@
rb_ary_last(int argc, VALUE *argv, VALUE ary)
{
if (argc == 0) {
- if (RARRAY_LEN(ary) == 0) return Qnil;
- return RARRAY_PTR(ary)[RARRAY_LEN(ary)-1];
+ long n = RARRAY_LEN(ary);
+ if (n == 0) return Qnil;
+ return RARRAY_AT(ary, n - 1);
}
else {
- return ary_shared_first(argc, argv, ary, Qtrue);
+ return ary_shared_first(argc, argv, ary, Qtrue, false);
}
}
@@ -852,7 +1155,7 @@
}
return ifnone;
}
- return RARRAY_PTR(ary)[idx];
+ return RARRAY_AT(ary, idx);
}
/*
@@ -869,27 +1172,38 @@
* 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
rb_ary_index(int argc, VALUE *argv, VALUE ary)
{
VALUE val;
- long i;
+ long n, i;
+ n = RARRAY_LEN(ary);
if (rb_scan_args(argc, argv, "01", &val) == 0) {
RETURN_ENUMERATOR(ary, 0, 0);
- for (i=0; i<RARRAY_LEN(ary); i++) {
- if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
+ for (i=0; i<n; i++) {
+ if (RTEST(rb_yield(RARRAY_AT(ary, i)))) {
return LONG2NUM(i);
}
}
}
else {
- for (i=0; i<RARRAY_LEN(ary); i++) {
- if (rb_equal(RARRAY_PTR(ary)[i], val))
+#if WITH_OBJC
+ CFIndex idx;
+ idx = CFArrayGetFirstIndexOfValue((CFArrayRef)ary, CFRangeMake(0, n),
+ (const void *)val);
+ if (idx != -1)
+ return LONG2NUM(idx);
+#else
+ for (i=0; i<n; i++) {
+ if (rb_equal(RARRAY_AT(ary, i), val))
return LONG2NUM(i);
}
+#endif
}
return Qnil;
}
@@ -913,26 +1227,35 @@
rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
{
VALUE val;
- long i = RARRAY_LEN(ary);
+ long i, n;
+
+ i = n = RARRAY_LEN(ary);
if (rb_scan_args(argc, argv, "01", &val) == 0) {
RETURN_ENUMERATOR(ary, 0, 0);
while (i--) {
- if (RTEST(rb_yield(RARRAY_PTR(ary)[i])))
+ if (RTEST(rb_yield(RARRAY_AT(ary, i))))
return LONG2NUM(i);
- if (i > RARRAY_LEN(ary)) {
- i = RARRAY_LEN(ary);
+ if (i > n) {
+ i = n;
}
}
}
else {
+#if WITH_OBJC
+ i = CFArrayGetLastIndexOfValue((CFArrayRef)ary, CFRangeMake(0, n),
+ (const void *)val);
+ if (i != -1)
+ return LONG2NUM(i);
+#else
while (i--) {
- if (rb_equal(RARRAY_PTR(ary)[i], val))
+ if (rb_equal(RARRAY_AT(ary, i), val))
return LONG2NUM(i);
- if (i > RARRAY_LEN(ary)) {
- i = RARRAY_LEN(ary);
+ if (i > n) {
+ i = n;
}
}
+#endif
}
return Qnil;
}
@@ -952,18 +1275,19 @@
static void
rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
{
- long rlen;
+ long n, rlen;
+ n = RARRAY_LEN(ary);
if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
if (beg < 0) {
- beg += RARRAY_LEN(ary);
+ beg += n;
if (beg < 0) {
- beg -= RARRAY_LEN(ary);
+ beg -= n;
rb_raise(rb_eIndexError, "index %ld out of array", beg);
}
}
- if (RARRAY_LEN(ary) < len || RARRAY_LEN(ary) < beg + len) {
- len = RARRAY_LEN(ary) - beg;
+ if (n < len || n < beg + len) {
+ len = n - beg;
}
if (rpl == Qundef) {
@@ -974,6 +1298,31 @@
rlen = RARRAY_LEN(rpl);
}
rb_ary_modify(ary);
+#if WITH_OBJC
+ if (beg >= n) {
+ long i;
+ for (i = n; i < beg - n; i++) {
+ CFArrayAppendValue((CFMutableArrayRef)ary, (const void *)Qnil);
+ }
+ if (rlen > 0)
+ CFArrayAppendArray((CFMutableArrayRef)ary, (CFArrayRef)rpl,
+ CFRangeMake(0, rlen));
+ }
+ else {
+ const void **values;
+ if (rlen > 0) {
+ values = (void *)alloca(sizeof(void *) * rlen);
+ CFArrayGetValues((CFArrayRef)rpl, CFRangeMake(0, rlen), values);
+ }
+ else {
+ values = NULL;
+ }
+ CFArrayReplaceValues((CFMutableArrayRef)ary,
+ CFRangeMake(beg, len),
+ values,
+ rlen);
+ }
+#else
if (beg >= RARRAY_LEN(ary)) {
len = beg + rlen;
if (len >= ARY_CAPA(ary)) {
@@ -1006,6 +1355,7 @@
MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen);
}
}
+#endif
}
/*
@@ -1033,7 +1383,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
@@ -1077,7 +1427,7 @@
*/
static VALUE
-rb_ary_insert(int argc, VALUE *argv, VALUE ary)
+rb_ary_insert_m(int argc, VALUE *argv, VALUE ary)
{
long pos;
@@ -1117,9 +1467,8 @@
long i;
RETURN_ENUMERATOR(ary, 0, 0);
- for (i=0; i<RARRAY_LEN(ary); i++) {
- rb_yield(RARRAY_PTR(ary)[i]);
- }
+ for (i = 0; i < RARRAY_LEN(ary); i++)
+ rb_yield(RARRAY_AT(ary, i));
return ary;
}
@@ -1141,10 +1490,10 @@
static VALUE
rb_ary_each_index(VALUE ary)
{
- long i;
+ long i, n;
RETURN_ENUMERATOR(ary, 0, 0);
- for (i=0; i<RARRAY_LEN(ary); i++) {
+ for (i = 0, n = RARRAY_LEN(ary); i < n; i++) {
rb_yield(LONG2NUM(i));
}
return ary;
@@ -1168,14 +1517,15 @@
static VALUE
rb_ary_reverse_each(VALUE ary)
{
- long len;
+ long n, len;
RETURN_ENUMERATOR(ary, 0, 0);
len = RARRAY_LEN(ary);
while (len--) {
- rb_yield(RARRAY_PTR(ary)[len]);
- if (RARRAY_LEN(ary) < len) {
- len = RARRAY_LEN(ary);
+ rb_yield(RARRAY_AT(ary, len));
+ n = RARRAY_LEN(ary);
+ if (n < len) {
+ len = n;
}
}
return ary;
@@ -1214,21 +1564,38 @@
return Qfalse;
}
+#if WITH_OBJC
+static inline VALUE
+rb_ary_dup2(VALUE ary)
+{
+ VALUE klass, dup;
+ long n;
+
+ klass = rb_obj_class(ary);
+ dup = ary_new(klass, 0);
+ n = RARRAY_LEN(ary);
+ if (n > 0)
+ CFArrayAppendArray((CFMutableArrayRef)dup, (CFArrayRef)ary,
+ CFRangeMake(0, n));
+ return dup;
+}
+#endif
+
VALUE
rb_ary_dup(VALUE ary)
{
+#if WITH_OBJC
+ VALUE dup = rb_ary_dup2(ary);
+ /* copy the named_args flag, but not other flags */
+ if (rb_ary_is_named_args(ary))
+ rb_ary_set_named_args(dup, true);
+#else
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);
-#if WITH_OBJC
- if (FL_TEST(ary, RARRAY_NAMED_ARGS))
- FL_SET(dup, RARRAY_NAMED_ARGS);
#endif
-
return dup;
}
@@ -1247,15 +1614,17 @@
VALUE
rb_ary_join(VALUE ary, VALUE sep)
{
- long len = 1, i;
+ long len = 1, i, count;
int taint = Qfalse;
VALUE result, tmp;
if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0);
if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue;
-
+#if WITH_OBJC
+ result = rb_str_buf_new(0);
+#else
for (i=0; i<RARRAY_LEN(ary); i++) {
- tmp = rb_check_string_type(RARRAY_PTR(ary)[i]);
+ tmp = rb_check_string_type(RARRAY_AT(ary, i));
len += NIL_P(tmp) ? 10 : RSTRING_LEN(tmp);
}
if (!NIL_P(sep)) {
@@ -1263,8 +1632,10 @@
len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
}
result = rb_str_buf_new(len);
- for (i=0; i<RARRAY_LEN(ary); i++) {
- tmp = RARRAY_PTR(ary)[i];
+#endif
+
+ for (i=0, count=RARRAY_LEN(ary); i<count; i++) {
+ tmp = RARRAY_AT(ary, i);
switch (TYPE(tmp)) {
case T_STRING:
break;
@@ -1322,7 +1693,7 @@
if (recur) return rb_tainted_str_new2("[...]");
str = rb_str_buf_new2("[");
for (i=0; i<RARRAY_LEN(ary); i++) {
- s = rb_inspect(RARRAY_PTR(ary)[i]);
+ s = rb_inspect(RARRAY_AT(ary, i));
if (OBJ_TAINTED(s)) tainted = Qtrue;
if (i > 0) rb_str_buf_cat2(str, ", ");
rb_str_buf_append(str, s);
@@ -1364,7 +1735,11 @@
static VALUE
rb_ary_to_a(VALUE ary)
{
+#if WITH_OBJC
+ if (!rb_objc_ary_is_pure(ary)) {
+#else
if (rb_obj_class(ary) != rb_cArray) {
+#endif
VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
rb_ary_replace(dup, ary);
return dup;
@@ -1388,6 +1763,18 @@
VALUE
rb_ary_reverse(VALUE ary)
{
+#if WITH_OBJC
+ long n;
+
+ rb_ary_modify(ary);
+ n = RARRAY_LEN(ary);
+ if (n > 0) {
+ long i;
+ for (i = 0; i < (n / 2); i++)
+ CFArrayExchangeValuesAtIndices((CFMutableArrayRef)ary,
+ i, n - i - 1);
+ }
+#else
VALUE *p1, *p2;
VALUE tmp;
@@ -1402,6 +1789,7 @@
*p2-- = tmp;
}
}
+#endif
return ary;
}
@@ -1441,7 +1829,11 @@
static int
sort_1(const void *ap, const void *bp, void *dummy)
{
+#if WITH_OBJC
+ VALUE a = (VALUE)ap, b = (VALUE)bp;
+#else
VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
+#endif
VALUE retval = rb_yield_values(2, a, b);
int n;
@@ -1453,7 +1845,11 @@
sort_2(const void *ap, const void *bp, void *dummy)
{
VALUE retval;
+#if WITH_OBJC
+ VALUE a = (VALUE)ap, b = (VALUE)bp;
+#else
VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
+#endif
int n;
if (FIXNUM_P(a) && FIXNUM_P(b)) {
@@ -1490,18 +1886,32 @@
VALUE
rb_ary_sort_bang(VALUE ary)
{
+ long n = RARRAY_LEN(ary);
rb_ary_modify(ary);
- if (RARRAY_LEN(ary) > 1) {
+ if (n > 1) {
+#if WITH_OBJC
+ CFArraySortValues((CFMutableArrayRef)ary,
+ CFRangeMake(0, n),
+ (CFComparatorFunction)(rb_block_given_p() ? sort_1 : sort_2),
+ NULL);
+#else
VALUE tmp = ary_make_shared(ary);
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;
}
@@ -1554,7 +1964,7 @@
RETURN_ENUMERATOR(ary, 0, 0);
collect = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
- rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
+ rb_ary_push(collect, rb_yield(RARRAY_AT(ary, i)));
}
return collect;
}
@@ -1582,7 +1992,7 @@
RETURN_ENUMERATOR(ary, 0, 0);
rb_ary_modify(ary);
for (i = 0; i < RARRAY_LEN(ary); i++) {
- rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i]));
+ rb_ary_store(ary, i, rb_yield(RARRAY_AT(ary, i)));
}
return ary;
}
@@ -1654,13 +2064,15 @@
rb_ary_select(VALUE ary)
{
VALUE result;
- long i;
+ long n, i;
RETURN_ENUMERATOR(ary, 0, 0);
- result = rb_ary_new2(RARRAY_LEN(ary));
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
- rb_ary_push(result, rb_ary_elt(ary, i));
+ n = RARRAY_LEN(ary);
+ result = rb_ary_new2(n);
+ for (i = 0; i < n; i++) {
+ VALUE v = RARRAY_AT(ary, i);
+ if (RTEST(rb_yield(v))) {
+ rb_ary_push(result, v);
}
}
return result;
@@ -1686,6 +2098,27 @@
VALUE
rb_ary_delete(VALUE ary, VALUE item)
{
+#if WITH_OBJC
+ long n, i;
+ CFRange r;
+
+ rb_ary_modify(ary);
+
+ r = CFRangeMake(0, RARRAY_LEN(ary));
+ n = 0;
+ while ((i = CFArrayGetFirstIndexOfValue((CFArrayRef)ary, r,
+ (const void *)item)) != -1) {
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, i);
+ n++;
+ }
+ if (n == 0) {
+ if (rb_block_given_p()) {
+ return rb_yield(item);
+ }
+ return Qnil;
+ }
+ return item;
+#else
long i1, i2;
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
@@ -1714,6 +2147,7 @@
}
return item;
+#endif
}
VALUE
@@ -1729,10 +2163,14 @@
}
rb_ary_modify(ary);
- del = RARRAY_PTR(ary)[pos];
+ del = RARRAY_AT(ary, pos);
+#if WITH_OBJC
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, pos);
+#else
MEMMOVE(RARRAY_PTR(ary)+pos, RARRAY_PTR(ary)+pos+1, VALUE,
RARRAY_LEN(ary)-pos-1);
RARRAY(ary)->len--;
+#endif
return del;
}
@@ -1765,14 +2203,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"]
@@ -1787,16 +2219,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;
}
@@ -1831,22 +2273,37 @@
static VALUE
rb_ary_reject_bang(VALUE ary)
{
- long i1, i2;
+ long orign, n, i1, i2;
RETURN_ENUMERATOR(ary, 0, 0);
rb_ary_modify(ary);
- for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
- VALUE v = RARRAY_PTR(ary)[i1];
+ orign = n = RARRAY_LEN(ary);
+ for (i1 = i2 = 0; i1 < n; i1++) {
+ VALUE v = RARRAY_AT(ary, i1);
+#if WITH_OBJC
+ if (!RTEST(rb_yield(v))) {
+ continue;
+ }
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, i1);
+ n--;
+ i1--;
+#else
if (RTEST(rb_yield(v))) continue;
if (i1 != i2) {
rb_ary_store(ary, i2, v);
}
i2++;
+#endif
}
- if (RARRAY_LEN(ary) == i2) return Qnil;
+#if WITH_OBJC
+ if (n == orign)
+ return Qnil;
+#else
+ if (n == i2) return Qnil;
if (i2 < RARRAY_LEN(ary))
RARRAY(ary)->len = i2;
+#endif
return ary;
}
@@ -1922,7 +2379,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]]
@@ -2023,6 +2479,12 @@
orig = to_ary(orig);
rb_ary_modify_check(copy);
if (copy == orig) return copy;
+#if WITH_OBJC
+ CFArrayRemoveAllValues((CFMutableArrayRef)copy);
+ CFArrayAppendArray((CFMutableArrayRef)copy,
+ (CFArrayRef)orig,
+ CFRangeMake(0, RARRAY_LEN(orig)));
+#else
shared = ary_make_shared(orig);
if (!ARY_SHARED_P(copy)) {
ptr = RARRAY(copy)->ptr;
@@ -2032,6 +2494,7 @@
RARRAY(copy)->len = RARRAY(orig)->len;
RARRAY(copy)->aux.shared = shared;
FL_SET(copy, ELTS_SHARED);
+#endif
return copy;
}
@@ -2050,10 +2513,14 @@
rb_ary_clear(VALUE ary)
{
rb_ary_modify(ary);
+#if WITH_OBJC
+ CFArrayRemoveAllValues((CFMutableArrayRef)ary);
+#else
RARRAY(ary)->len = 0;
if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
RESIZE_CAPA(ary, ARY_DEFAULT_SIZE * 2);
}
+#endif
return ary;
}
@@ -2085,10 +2552,12 @@
rb_ary_fill(int argc, VALUE *argv, VALUE ary)
{
VALUE item, arg1, arg2;
- long beg = 0, end = 0, len = 0;
+ long beg = 0, end = 0, len = 0, n;
VALUE *p, *pend;
int block_p = Qfalse;
+ n = RARRAY_LEN(ary);
+
if (rb_block_given_p()) {
block_p = Qtrue;
rb_scan_args(argc, argv, "02", &arg1, &arg2);
@@ -2100,20 +2569,20 @@
switch (argc) {
case 1:
beg = 0;
- len = RARRAY_LEN(ary);
+ len = n;
break;
case 2:
- if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) {
+ if (rb_range_beg_len(arg1, &beg, &len, n, 1)) {
break;
}
/* fall through */
case 3:
beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
if (beg < 0) {
- beg = RARRAY_LEN(ary) + beg;
+ beg = n + beg;
if (beg < 0) beg = 0;
}
- len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2);
+ len = NIL_P(arg2) ? n - beg : NUM2LONG(arg2);
if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
break;
}
@@ -2122,13 +2591,15 @@
if (end < 0) {
rb_raise(rb_eArgError, "argument too big");
}
- if (RARRAY_LEN(ary) < end) {
+#if !WITH_OBJC
+ if (n < end) {
if (end >= ARY_CAPA(ary)) {
RESIZE_CAPA(ary, end);
}
rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), end - RARRAY_LEN(ary));
RARRAY(ary)->len = end;
}
+#endif
if (block_p) {
VALUE v;
@@ -2136,16 +2607,25 @@
for (i=beg; i<end; i++) {
v = rb_yield(LONG2NUM(i));
+#if !WITH_OBJC
if (i>=RARRAY_LEN(ary)) break;
- RARRAY_PTR(ary)[i] = v;
+#endif
+ rb_ary_store(ary, i, v);
}
}
else {
+#if WITH_OBJC
+ long i;
+ for (i=beg; i<end; i++) {
+ rb_ary_store(ary, i, item);
+ }
+#else
p = RARRAY_PTR(ary) + beg;
pend = p + len;
while (p < pend) {
*p++ = item;
}
+#endif
}
return ary;
}
@@ -2166,12 +2646,21 @@
VALUE z;
long len;
+#if WITH_OBJC
y = to_ary(y);
+ z = rb_ary_new2(0);
+ CFArrayAppendArray((CFMutableArrayRef)z,
+ (CFArrayRef)x, CFRangeMake(0, RARRAY_LEN(x)));
+ CFArrayAppendArray((CFMutableArrayRef)z,
+ (CFArrayRef)y, CFRangeMake(0, RARRAY_LEN(y)));
+#else
+ y = to_ary(y);
len = RARRAY_LEN(x) + RARRAY_LEN(y);
z = rb_ary_new2(len);
MEMCPY(RARRAY_PTR(z), RARRAY_PTR(x), VALUE, RARRAY_LEN(x));
MEMCPY(RARRAY_PTR(z) + RARRAY_LEN(x), RARRAY_PTR(y), VALUE, RARRAY_LEN(y));
RARRAY(z)->len = len;
+#endif
return z;
}
@@ -2215,7 +2704,7 @@
rb_ary_times(VALUE ary, VALUE times)
{
VALUE ary2, tmp;
- long i, len;
+ long n, i, len;
tmp = rb_check_string_type(times);
if (!NIL_P(tmp)) {
@@ -2227,9 +2716,18 @@
if (len < 0) {
rb_raise(rb_eArgError, "negative argument");
}
- if (LONG_MAX/len < RARRAY_LEN(ary)) {
+ n = RARRAY_LEN(ary);
+ if (LONG_MAX/len < n) {
rb_raise(rb_eArgError, "argument too big");
}
+#if WITH_OBJC
+ ary2 = ary_new(rb_obj_class(ary), 0);
+ for (i = 0; i < len; i++) {
+ CFArrayAppendArray((CFMutableArrayRef)ary2,
+ (CFArrayRef)ary,
+ CFRangeMake(0, n));
+ }
+#else
len *= RARRAY_LEN(ary);
ary2 = ary_new(rb_obj_class(ary), len);
@@ -2239,6 +2737,7 @@
MEMCPY(RARRAY_PTR(ary2)+i, RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
}
OBJ_INFECT(ary2, ary);
+#endif
return ary2;
}
@@ -2270,9 +2769,9 @@
VALUE v;
for (i = 0; i < RARRAY_LEN(ary); ++i) {
- v = rb_check_array_type(RARRAY_PTR(ary)[i]);
+ v = rb_check_array_type(RARRAY_AT(ary, i));
if (!NIL_P(v) && RARRAY_LEN(v) > 0 &&
- rb_equal(RARRAY_PTR(v)[0], key))
+ rb_equal(RARRAY_AT(v, 0), key))
return v;
}
return Qnil;
@@ -2299,10 +2798,10 @@
VALUE v;
for (i = 0; i < RARRAY_LEN(ary); ++i) {
- v = RARRAY_PTR(ary)[i];
+ v = RARRAY_AT(ary, i);
if (TYPE(v) == T_ARRAY &&
RARRAY_LEN(v) > 1 &&
- rb_equal(RARRAY_PTR(v)[1], value))
+ rb_equal(RARRAY_AT(v, 1), value))
return v;
}
return Qnil;
@@ -2373,16 +2872,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
@@ -2397,7 +2890,7 @@
h = RARRAY_LEN(ary);
for (i=0; i<RARRAY_LEN(ary); i++) {
h = (h << 1) | (h<0 ? 1 : 0);
- n = rb_hash(RARRAY_PTR(ary)[i]);
+ n = rb_hash(RARRAY_AT(ary, i));
h ^= NUM2LONG(n);
}
return LONG2FIX(h);
@@ -2433,14 +2926,19 @@
VALUE
rb_ary_includes(VALUE ary, VALUE item)
{
+#if WITH_OBJC
+ return CFArrayContainsValue((CFArrayRef)ary,
+ 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;
}
}
return Qfalse;
+#endif
}
@@ -2463,7 +2961,6 @@
return Qundef;
}
-
/*
* call-seq:
* array <=> other_array -> -1, 0, +1
@@ -2507,11 +3004,11 @@
long i;
for (i=0; i<RARRAY_LEN(ary1); i++) {
- rb_hash_aset(hash, RARRAY_PTR(ary1)[i], Qtrue);
+ rb_hash_aset(hash, RARRAY_AT(ary1, i), Qtrue);
}
if (ary2) {
for (i=0; i<RARRAY_LEN(ary2); i++) {
- rb_hash_aset(hash, RARRAY_PTR(ary2)[i], Qtrue);
+ rb_hash_aset(hash, RARRAY_AT(ary2, i), Qtrue);
}
}
return hash;
@@ -2540,7 +3037,12 @@
ary3 = rb_ary_new();
for (i=0; i<RARRAY_LEN(ary1); i++) {
+#if WITH_OBJC
+ if (CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
+ (const void *)RARRAY_AT(ary1, i), NULL)) continue;
+#else
if (st_lookup(RHASH_TBL(hash), RARRAY_PTR(ary1)[i], 0)) continue;
+#endif
rb_ary_push(ary3, rb_ary_elt(ary1, i));
}
return ary3;
@@ -2573,7 +3075,13 @@
for (i=0; i<RARRAY_LEN(ary1); i++) {
v = vv = rb_ary_elt(ary1, i);
+#if WITH_OBJC
+ if (CFDictionaryContainsKey((CFDictionaryRef)hash, (const void *)vv)) {
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)hash,
+ (const void *)vv);
+#else
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
+#endif
rb_ary_push(ary3, v);
}
}
@@ -2605,13 +3113,25 @@
for (i=0; i<RARRAY_LEN(ary1); i++) {
v = vv = rb_ary_elt(ary1, i);
+#if WITH_OBJC
+ if (CFDictionaryContainsKey((CFDictionaryRef)hash, (const void *)vv)) {
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)hash,
+ (const void *)vv);
+#else
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
+#endif
rb_ary_push(ary3, v);
}
}
for (i=0; i<RARRAY_LEN(ary2); i++) {
v = vv = rb_ary_elt(ary2, i);
+#if WITH_OBJC
+ if (CFDictionaryContainsKey((CFDictionaryRef)hash, (const void *)vv)) {
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)hash,
+ (const void *)vv);
+#else
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
+#endif
rb_ary_push(ary3, v);
}
}
@@ -2635,6 +3155,30 @@
static VALUE
rb_ary_uniq_bang(VALUE ary)
{
+#if WITH_OBJC
+ long i, n;
+ bool changed;
+
+ rb_ary_modify(ary);
+ n = RARRAY_LEN(ary);
+ for (i = 0, changed = false; i < n; i++) {
+ VALUE e;
+ long idx;
+ CFRange r;
+
+ e = RARRAY_AT(ary, i);
+ r = CFRangeMake(i + 1, n - i - 1);
+ while ((idx = CFArrayGetFirstIndexOfValue((CFArrayRef)ary,
+ r, (const void *)e)) != -1) {
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, idx);
+ r.location = idx;
+ r.length = --n - idx;
+ changed = true;
+ }
+ }
+ if (!changed)
+ return Qnil;
+#else
VALUE hash, v, vv;
long i, j;
@@ -2645,11 +3189,18 @@
}
for (i=j=0; i<RARRAY_LEN(ary); i++) {
v = vv = rb_ary_elt(ary, i);
+#if WITH_OBJC
+ if (CFDictionaryContainsKey((CFDictionaryRef)hash, (const void *)vv)) {
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)hash,
+ (const void *)vv);
+#else
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
+#endif
rb_ary_store(ary, j++, v);
}
}
RARRAY(ary)->len = j;
+#endif
return ary;
}
@@ -2686,6 +3237,26 @@
static VALUE
rb_ary_compact_bang(VALUE ary)
{
+#if WITH_OBJC
+ long i, n, k;
+ CFRange r;
+
+ rb_ary_modify(ary);
+ n = RARRAY_LEN(ary);
+ if (n == 0)
+ return Qnil;
+ k = 0;
+ r = CFRangeMake(0, n);
+ while ((i = CFArrayGetFirstIndexOfValue((CFArrayRef)ary,
+ r, (const void *)Qnil)) != -1) {
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, i);
+ r.location = i;
+ r.length = n - i;
+ k++;
+ }
+ if (k == 0)
+ return Qnil;
+#else
VALUE *p, *t, *end;
long n;
@@ -2703,6 +3274,7 @@
n = p - RARRAY_PTR(ary);
RESIZE_CAPA(ary, n);
RARRAY(ary)->len = n;
+#endif
return ary;
}
@@ -2749,11 +3321,16 @@
long i;
for (i=0; i<RARRAY_LEN(ary); i++) {
- VALUE v = RARRAY_PTR(ary)[i];
+ VALUE v = RARRAY_AT(ary, i);
if (RTEST(rb_yield(v))) n++;
}
}
else {
+#if WITH_OBJC
+ long total = RARRAY_LEN(ary);
+ n = total - CFArrayGetCountOfValue((CFArrayRef)ary,
+ CFRangeMake(0, total), (const void *)Qnil);
+#else
VALUE *p = RARRAY_PTR(ary);
VALUE *pend = p + RARRAY_LEN(ary);
@@ -2761,7 +3338,9 @@
if (!NIL_P(*p)) n++;
p++;
}
+#endif
}
+
return LONG2NUM(n);
}
@@ -2774,14 +3353,14 @@
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;
while (1) {
while (i < RARRAY_LEN(ary)) {
- elt = RARRAY_PTR(ary)[i++];
+ elt = RARRAY_AT(ary, i++);
tmp = rb_check_array_type(elt);
if (NIL_P(tmp) || (level >= 0 && RARRAY_LEN(stack) / 2 >= level)) {
rb_ary_push(result, elt);
@@ -2860,7 +3439,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]]
*/
@@ -2897,9 +3476,13 @@
rb_ary_modify(ary);
while (i) {
long j = rb_genrand_real()*i;
- VALUE tmp = RARRAY_PTR(ary)[--i];
+#if WITH_OBJC
+ CFArrayExchangeValuesAtIndices((CFMutableArrayRef)ary, --i, j);
+#else
+ VALUE tmp = RARRAY_AT(ary, --i);
RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j];
RARRAY_PTR(ary)[j] = tmp;
+#endif
}
return ary;
}
@@ -2940,32 +3523,48 @@
i = RARRAY_LEN(ary);
if (i == 0) return Qnil;
j = rb_genrand_real()*i;
- return RARRAY_PTR(ary)[j];
+ return RARRAY_AT(ary, j);
}
/*
* 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_PTR(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_AT(ary, i));
+ }
+ }
return Qnil;
}
@@ -3001,11 +3600,16 @@
/* Build a ruby array of the corresponding values */
/* And yield it to the associated block */
VALUE result = rb_ary_new2(r);
+#if WITH_OBJC
+ for (j = 0; j < r; j++)
+ rb_ary_store(result, j, RARRAY_AT(values, p[j]));
+#else
VALUE *result_array = RARRAY_PTR(result);
const VALUE *values_array = RARRAY_PTR(values);
for (j = 0; j < r; j++) result_array[j] = values_array[p[j]];
RARRAY(result)->len = r;
+#endif
rb_yield(result);
}
}
@@ -3028,13 +3632,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
@@ -3055,8 +3660,8 @@
rb_yield(rb_ary_new2(0));
}
else if (r == 1) { /* this is a special, easy case */
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
+ for (i = 0; i < n; i++) {
+ rb_yield(rb_ary_new3(1, RARRAY_AT(ary, i)));
}
}
else { /* this is the general case */
@@ -3064,13 +3669,19 @@
long *p = (long*)RSTRING_PTR(t0);
volatile VALUE t1 = tmpbuf(n,sizeof(int));
int *used = (int*)RSTRING_PTR(t1);
+#if WITH_OBJC
+ VALUE ary0 = rb_ary_dup(ary);
+#else
VALUE ary0 = ary_make_shared(ary); /* private defensive copy of ary */
+#endif
for (i = 0; i < n; i++) used[i] = 0; /* initialize array */
permute0(n, r, p, 0, used, ary0); /* compute and yield permutations */
+#if !WITH_OBJC
RB_GC_GUARD(t0);
RB_GC_GUARD(t1);
+#endif
}
return ary;
}
@@ -3108,13 +3719,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
*
*/
@@ -3125,6 +3737,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 */
@@ -3134,7 +3747,7 @@
}
else if (n == 1) {
for (i = 0; i < len; i++) {
- rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
+ rb_yield(rb_ary_new3(1, RARRAY_AT(ary, i)));
}
}
else {
@@ -3142,18 +3755,24 @@
long *stack = (long*)RSTRING_PTR(t0);
long nlen = combi_len(len, n);
volatile VALUE cc = rb_ary_new2(n);
- VALUE *chosen = RARRAY_PTR(cc);
long lev = 0;
+#if !WITH_OBJC
RBASIC(cc)->klass = 0;
+#endif
MEMZERO(stack, long, n);
stack[0] = -1;
for (i = 0; i < nlen; i++) {
- chosen[lev] = RARRAY_PTR(ary)[stack[lev+1]];
+ rb_ary_store(cc, lev, RARRAY_AT(ary, stack[lev+1]));
for (lev++; lev < n; lev++) {
- chosen[lev] = RARRAY_PTR(ary)[stack[lev+1] = stack[lev]+1];
+ stack[lev+1] = stack[lev]+1;
+ rb_ary_store(cc, lev, RARRAY_AT(ary, stack[lev+1]));
}
- rb_yield(rb_ary_new4(n, chosen));
+#if WITH_OBJC
+ rb_yield(rb_ary_dup(cc));
+#else
+ rb_yield(cc);
+#endif
do {
stack[lev--]++;
} while (lev && (stack[lev+1]+n == len+lev+1));
@@ -3239,8 +3858,233 @@
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
+
+#define NSCFARRAY() RCLASS_OCID(rb_cCFArray)
+
+#define PREPARE_RCV(x) \
+ Class old = *(Class *)x; \
+ *(Class *)x = NSCFARRAY();
+
+#define RESTORE_RCV(x) \
+ *(Class *)x = old;
+
+bool
+rb_objc_ary_is_pure(VALUE ary)
+{
+ return *(Class *)ary == NSCFARRAY();
+}
+
+static CFIndex
+imp_rb_array_count(void *rcv, SEL sel)
+{
+ CFIndex count;
+ PREPARE_RCV(rcv);
+ count = CFArrayGetCount((CFArrayRef)rcv);
+ RESTORE_RCV(rcv);
+ return count;
+}
+
+static const void *
+imp_rb_array_objectAtIndex(void *rcv, SEL sel, CFIndex idx)
+{
+ const void *obj;
+ PREPARE_RCV(rcv);
+ obj = CFArrayGetValueAtIndex((CFArrayRef)rcv, idx);
+ RESTORE_RCV(rcv);
+ return obj;
+}
+
+static void
+imp_rb_array_insertObjectAtIndex(void *rcv, SEL sel, void *obj, CFIndex idx)
+{
+ PREPARE_RCV(rcv);
+ CFArrayInsertValueAtIndex((CFMutableArrayRef)rcv, idx, obj);
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_array_removeObjectAtIndex(void *rcv, SEL sel, CFIndex idx)
+{
+ PREPARE_RCV(rcv);
+ CFArrayRemoveValueAtIndex((CFMutableArrayRef)rcv, idx);
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_array_replaceObjectAtIndexWithObject(void *rcv, SEL sel, CFIndex idx,
+ void *obj)
+{
+ PREPARE_RCV(rcv);
+ CFArraySetValueAtIndex((CFMutableArrayRef)rcv, idx, obj);
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_array_addObject(void *rcv, SEL sel, void *obj)
+{
+ PREPARE_RCV(rcv);
+ CFArrayAppendValue((CFMutableArrayRef)rcv, obj);
+ RESTORE_RCV(rcv);
+}
+
+static CFIndex
+imp_rb_array_cfindexOfObjectInRange(void *rcv, SEL sel, void *obj,
+ CFRange range)
+{
+ CFIndex i;
+ PREPARE_RCV(rcv);
+ i = CFArrayGetFirstIndexOfValue((CFArrayRef)rcv, range, obj);
+ RESTORE_RCV(rcv);
+ return i;
+}
+
+void
+rb_objc_install_array_primitives(Class klass)
+{
+#define INSTALL_METHOD(selname, imp) \
+ do { \
+ SEL sel = sel_registerName(selname); \
+ Method method = class_getInstanceMethod(klass, sel); \
+ assert(method != NULL); \
+ assert(class_addMethod(klass, sel, (IMP)imp, \
+ method_getTypeEncoding(method))); \
+ } \
+ while(0)
+
+ INSTALL_METHOD("count", imp_rb_array_count);
+ INSTALL_METHOD("objectAtIndex:", imp_rb_array_objectAtIndex);
+ INSTALL_METHOD("insertObject:atIndex:", imp_rb_array_insertObjectAtIndex);
+ INSTALL_METHOD("removeObjectAtIndex:", imp_rb_array_removeObjectAtIndex);
+ INSTALL_METHOD("replaceObjectAtIndex:withObject:",
+ imp_rb_array_replaceObjectAtIndexWithObject);
+ INSTALL_METHOD("addObject:", imp_rb_array_addObject);
+
+ /* This is to work around a bug where CF will try to call an non-existing
+ * method.
+ */
+ if (true) {
+ INSTALL_METHOD("_cfindexOfObject:range:",
+ imp_rb_array_cfindexOfObjectInRange);
+ Method m = class_getInstanceMethod(klass,
+ sel_registerName("_cfindexOfObject:range:"));
+ class_addMethod(klass, sel_registerName("_cfindexOfObject:inRange:"),
+ method_getImplementation(m), method_getTypeEncoding(m));
+ }
+
+#undef INSTALL_METHOD
+}
+
+void
+rb_ary_set_named_args(VALUE ary, bool flag)
+{
+ rb_objc_ary_get_struct2(ary)->named_args = flag;
+}
+
+bool
+rb_ary_is_named_args(VALUE ary)
+{
+ struct rb_objc_ary_struct *s = rb_objc_ary_get_struct(ary);
+ return s != NULL && s->named_args;
+}
+#endif
+
/* Arrays are ordered, integer-indexed collections of any object.
* Array indexing starts at 0, as in C or Java. A negative index is
* assumed to be relative to the end of the array---that is, an index of -1
@@ -3252,8 +4096,12 @@
Init_Array(void)
{
#if WITH_OBJC
- rb_cArray = rb_define_class("Array",
- rb_objc_import_class((Class)objc_getClass("NSMutableArray")));
+ rb_cCFArray = rb_objc_import_class((Class)objc_getClass("NSCFArray"));;
+ rb_cArray = rb_objc_import_class((Class)objc_getClass("NSArray"));
+ rb_cArrayRuby =
+ rb_objc_import_class((Class)objc_getClass("NSMutableArray"));
+ FL_UNSET(rb_cArrayRuby, RCLASS_OBJC_IMPORTED);
+ rb_const_set(rb_cObject, rb_intern("Array"), rb_cArrayRuby);
#else
rb_cArray = rb_define_class("Array", rb_cObject);
#endif
@@ -3287,13 +4135,14 @@
rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1);
rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1);
rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1);
- rb_define_method(rb_cArray, "insert", rb_ary_insert, -1);
+ rb_define_method(rb_cArray, "insert", rb_ary_insert_m, -1);
rb_define_method(rb_cArray, "each", rb_ary_each, 0);
rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0);
rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0);
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);
@@ -3343,10 +4192,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("<=>");
}
Copied: MacRuby/branches/testing/benchmark/bm_app_mergesort.rb (from rev 232, MacRuby/trunk/benchmark/bm_app_mergesort.rb)
===================================================================
--- MacRuby/branches/testing/benchmark/bm_app_mergesort.rb (rev 0)
+++ MacRuby/branches/testing/benchmark/bm_app_mergesort.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,51 @@
+# http://npzrk8rz.wordpress.com/2008/01/17/ruby-vs-php-performance/
+
+def merge(a, b)
+ c = []
+ while !a.empty? && !b.empty?
+ if a[0] > b[0]
+ c << b[0]
+ b.shift
+ else
+ c << a[0]
+ a.shift
+ end
+ end
+ while !a.empty?
+ c << a[0]
+ a.shift
+ end
+ while !b.empty?
+ c << b[0]
+ b.shift
+ end
+ return c
+end
+
+def mergesort(a)
+ n = a.size
+ if n <= 1
+ return a
+ end
+
+ l1 = []
+ l2 = []
+ i = 0
+ while i < n / 2
+ l1 << a[i]
+ i += 1
+ end
+ while i < n
+ l2 << a[i]
+ i += 1
+ end
+
+ l1 = mergesort(l1)
+ l2 = mergesort(l2)
+ return merge(l1, l2)
+end
+
+numbers = [47448054, 1106251565, 1208921855, 170086026, 840395770, 444281018, 1297307905, 1613614128, 357068250, 1829657695, 654555439, 1261773796, 1821640729, 449683981, 1062536538, 96076061, 1387478498, 1835855315, 364455615, 4830124, 864633601, 289493189, 471351435, 435996916, 1366312031, 888420407, 1923379522, 735726044, 1094401518, 245520239, 109946712, 1107893495, 592868510, 700148765, 273016388, 343881444, 420725947, 1259049694, 1692920986, 71271532, 1154617350, 593508009, 1106700528, 430204045, 1045928775, 1330476642, 49983990, 1451164767, 1175404600, 644832496, 365016297, 1048732794, 503615317, 217186301, 1176160338, 1183622513, 81711049, 1720671278, 1393072097, 1315236388, 1451774341, 92848458, 271000544, 1667871288, 380233084, 1053079658, 1249341507, 1276652307, 1722015039, 1243698025, 178813868, 1449271074, 1994327579, 270972819, 1043379189, 1592595484, 462468972, 1464773315, 1994172406, 997300623, 46405283, 1614271949, 447907123, 317292284, 378291676, 1253835093
, 523476912, 1606023999, 59263848, 1234358080, 140981643, 1828471854, 1197394207, 1317927546, 878287915, 334576359, 982149842, 642878238, 1024064999, 1834342299];
+3000.times do
+ mergesort(numbers)
+end
Modified: MacRuby/branches/testing/benchmark/bm_so_sieve.rb
===================================================================
--- MacRuby/branches/testing/benchmark/bm_so_sieve.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/benchmark/bm_so_sieve.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/benchmark/bm_vm2_eval.rb
===================================================================
--- MacRuby/branches/testing/benchmark/bm_vm2_eval.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/benchmark/bm_vm2_eval.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/bignum.c
===================================================================
--- MacRuby/branches/testing/bignum.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bignum.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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) {
@@ -574,7 +592,7 @@
VALUE
rb_str_to_inum(VALUE str, int base, int badcheck)
{
- char *s;
+ const char *s;
long len;
StringValue(str);
@@ -582,10 +600,10 @@
s = StringValueCStr(str);
}
else {
- s = RSTRING_PTR(str);
+ s = RSTRING_CPTR(str);
}
if (s) {
- len = RSTRING_LEN(str);
+ len = RSTRING_CLEN(str);
if (s[len]) { /* no sentinel somehow */
char *p = ALLOCA_N(char, len+1);
@@ -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,42 +861,42 @@
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;
if (FIXNUM_P(x)) {
VALUE str = rb_fix2str(x, base);
- char* str_ptr = RSTRING_PTR(str);
- long str_len = RSTRING_LEN(str);
+ const char* str_ptr = RSTRING_CPTR(str);
+ long str_len = RSTRING_CLEN(str);
if (trim) {
if (FIX2INT(x) == 0) return 0;
MEMCPY(ptr, str_ptr, char, str_len);
@@ -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,19 +939,19 @@
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;
ss = rb_usascii_str_new(0, n2 + 1); /* plus one for sign */
- ptr = RSTRING_PTR(ss);
+ ptr = RSTRING_PTR(ss); /* ok */
ptr[0] = RBIGNUM_SIGN(x) ? '+' : '-';
hbase = base*base;
@@ -951,15 +962,16 @@
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';
rb_str_resize(ss, len);
+ RSTRING_SYNC(ss);
return ss;
}
@@ -987,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);
}
@@ -1136,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;
@@ -1156,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;
@@ -1737,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;
@@ -1759,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);
@@ -1771,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
*
@@ -1892,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;
@@ -1932,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;
@@ -1951,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);
}
@@ -1976,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);
@@ -1997,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);
@@ -2005,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
@@ -2029,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;
@@ -2054,7 +2144,7 @@
}
return bignorm(z);
}
- d = (double)yy;
+ /* NOTREACHED */
break;
default:
@@ -2063,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
@@ -2079,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));
}
@@ -2134,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));
}
@@ -2192,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));
}
@@ -2589,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/branches/testing/blockinlining.c
===================================================================
--- MacRuby/branches/testing/blockinlining.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/blockinlining.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -43,7 +43,7 @@
parent, iseq->type,
GC_GUARDED_PTR(builder));
if (0) {
- printf("%s\n", RSTRING_PTR(ruby_iseq_disasm(iseqval)));
+ printf("%s\n", RSTRING_CPTR(ruby_iseq_disasm(iseqval)));
}
iseq->cached_special_block = iseqval;
iseq->cached_special_block_builder = builder;
Modified: MacRuby/branches/testing/bootstraptest/runner.rb
===================================================================
--- MacRuby/branches/testing/bootstraptest/runner.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bootstraptest/runner.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/bootstraptest/test_class.rb
===================================================================
--- MacRuby/branches/testing/bootstraptest/test_class.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bootstraptest/test_class.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -106,7 +106,7 @@
assert_equal 'C', %q( class A; class ::C; end end; C )
assert_equal 'Class', %q( class A; class ::C; end end; C.class )
assert_equal 'OK', %q( class A; ::C = "OK"; end; C )
-assert_equal 'String', %q( class A; ::C = "OK"; end; C.class )
+assert_equal 'NSCFString', %q( class A; ::C = "OK"; end; C.class )
# class/module dup
assert_equal 'Class', %q( class C; end; C.dup.class )
Modified: MacRuby/branches/testing/bootstraptest/test_knownbug.rb
===================================================================
--- MacRuby/branches/testing/bootstraptest/test_knownbug.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bootstraptest/test_knownbug.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/bootstraptest/test_literal.rb
===================================================================
--- MacRuby/branches/testing/bootstraptest/test_literal.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bootstraptest/test_literal.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -35,13 +35,13 @@
# string literal
assert_equal 'a', '?a'
-assert_equal 'String', '?a.class'
+assert_equal 'NSCFString', '?a.class'
assert_equal 'A', '?A'
-assert_equal 'String', '?A.class'
+assert_equal 'NSCFString', '?A.class'
assert_equal "\n", '?\n'
-assert_equal 'String', '?\n.class'
+assert_equal 'NSCFString', '?\n.class'
assert_equal ' ', '?\ '
-assert_equal 'String', '?\ .class'
+assert_equal 'NSCFString', '?\ .class'
assert_equal 'string', "'string'"
assert_equal 'string', '"string"'
assert_equal 'string', '%(string)'
@@ -87,28 +87,28 @@
assert_equal 'Regexp', %q(/re#{'ge'}xp/.class)
# array
-assert_equal 'Array', '[].class'
+assert_equal 'NSCFArray', '[].class'
assert_equal '0', '[].size'
assert_equal '0', '[].length'
assert_equal '[]', '[].inspect'
-assert_equal 'Array', '[0].class'
+assert_equal 'NSCFArray', '[0].class'
assert_equal '1', '[3].size'
assert_equal '[3]', '[3].inspect'
assert_equal '3', 'a = [3]; a[0]'
-assert_equal 'Array', '[1,2].class'
+assert_equal 'NSCFArray', '[1,2].class'
assert_equal '2', '[1,2].size'
-assert_equal '[1, 2]', '[1,2].inspect'
-assert_equal 'Array', '[1,2,3,4,5].class'
+assert_equal '[1, 2]', '[1,2].inspect'
+assert_equal 'NSCFArray', '[1,2,3,4,5].class'
assert_equal '5', '[1,2,3,4,5].size'
assert_equal '[1, 2, 3, 4, 5]', '[1,2,3,4,5].inspect'
assert_equal '1', 'a = [1,2]; a[0]'
assert_equal '2', 'a = [1,2]; a[1]'
-assert_equal 'Array', 'a = [1 + 2, 3 + 4, 5 + 6]; a.class'
+assert_equal 'NSCFArray', 'a = [1 + 2, 3 + 4, 5 + 6]; a.class'
assert_equal '[3, 7, 11]', 'a = [1 + 2, 3 + 4, 5 + 6]; a.inspect'
assert_equal '7', 'a = [1 + 2, 3 + 4, 5 + 6]; a[1]'
assert_equal '1', '([0][0] += 1)'
assert_equal '1', '([2][0] -= 1)'
-assert_equal 'Array', 'a = [obj = Object.new]; a.class'
+assert_equal 'NSCFArray', 'a = [obj = Object.new]; a.class'
assert_equal '1', 'a = [obj = Object.new]; a.size'
assert_equal 'true', 'a = [obj = Object.new]; a[0] == obj'
assert_equal '5', 'a = [1,2,3]; a[1] = 5; a[1]'
@@ -119,9 +119,9 @@
# hash
-assert_equal 'Hash', '{}.class'
+assert_equal 'NSCFDictionary', '{}.class'
assert_equal '{}', '{}.inspect'
-assert_equal 'Hash', '{1=>2}.class'
+assert_equal 'NSCFDictionary', '{1=>2}.class'
assert_equal '{1=>2}', '{1=>2}.inspect'
assert_equal '2', 'h = {1 => 2}; h[1]'
assert_equal '0', 'h = {1 => 2}; h.delete(1); h.size'
@@ -166,7 +166,7 @@
assert_equal 'a', 'r = ("a".."c"); r.begin'
assert_equal 'c', 'r = ("a".."c"); r.end'
-assert_equal 'String', '__FILE__.class'
+assert_equal 'NSCFString', '__FILE__.class'
assert_equal 'Fixnum', '__LINE__.class'
###
Modified: MacRuby/branches/testing/bootstraptest/test_objectspace.rb
===================================================================
--- MacRuby/branches/testing/bootstraptest/test_objectspace.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bootstraptest/test_objectspace.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -8,6 +8,9 @@
rescue RangeError
next
end
+ # Some CF containers cannot be inspected because they contain pointers
+ # to C raw data.
+ next if o.is_a?(Hash) or o.is_a?(Array)
o.inspect if defined?(o.inspect)
}
}, '[ruby-dev:31911]'
@@ -31,3 +34,11 @@
end
}
}, '[ruby-dev:31985]'
+
+assert_equal "[Class]", %q{
+ ObjectSpace.each_object(Class).map { |x| x.class }.uniq
+}, 'macruby #61'
+
+assert_equal "[Class, Module]", %q{
+ ObjectSpace.each_object(Module).map { |x| x.class }.uniq
+}, 'macruby #61'
Modified: MacRuby/branches/testing/bootstraptest/test_thread.rb
===================================================================
--- MacRuby/branches/testing/bootstraptest/test_thread.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bootstraptest/test_thread.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/bs.c
===================================================================
--- MacRuby/branches/testing/bs.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/bs.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -186,6 +186,7 @@
break;
}
}
+ free(type_modifier);
}
static inline bool
@@ -693,6 +694,8 @@
case BS_XML_INFORMAL_PROTOCOL:
{
+ if (protocol_name != NULL)
+ free(protocol_name);
protocol_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(protocol_name, "name");
break;
@@ -824,6 +827,9 @@
func_ptr = bs_arg->function_pointer;
func_ptr_arg_depth = xmlTextReaderDepth(reader);
}
+ else {
+ bs_arg->function_pointer = NULL;
+ }
}
else {
BAIL("argument defined outside of a " \
@@ -896,6 +902,9 @@
func_ptr = bs_retval->function_pointer;
func_ptr_arg_depth = xmlTextReaderDepth(reader);
}
+ else {
+ bs_retval->function_pointer = NULL;
+ }
}
else {
BAIL("return value defined outside a function/method");
@@ -921,10 +930,11 @@
ASSERT_ALLOC(bs_informal_method);
bs_informal_method->name = sel_registerName(selector);
+ free(selector);
bs_informal_method->class_method =
get_boolean_attribute(reader, "class_method", false);
bs_informal_method->type = method_type;
- bs_informal_method->protocol_name = protocol_name;
+ bs_informal_method->protocol_name = strdup(protocol_name);
bs_element = bs_informal_method;
bs_element_type = BS_ELEMENT_INFORMAL_PROTOCOL_METHOD;
@@ -940,6 +950,7 @@
ASSERT_ALLOC(method);
method->name = sel_registerName(selector);
+ free(selector);
method->class_method =
get_boolean_attribute(reader, "class_method", false);
method->variadic =
@@ -1081,6 +1092,9 @@
success = true;
bails:
+ if (protocol_name != NULL)
+ free(protocol_name);
+
xmlFreeTextReader(reader);
return success;
@@ -1106,10 +1120,165 @@
return status;
}
+#define SAFE_FREE(x) do { if ((x) != NULL) free(x); } while (0)
+
+static void bs_free_retval(bs_element_retval_t *bs_retval);
+static void bs_free_arg(bs_element_arg_t *bs_arg);
+
+static void
+bs_free_function_pointer(bs_element_function_pointer_t *bs_func_ptr)
+{
+ if (bs_func_ptr != NULL) {
+ unsigned i;
+ for (i = 0; i < bs_func_ptr->args_count; i++)
+ bs_free_arg(&bs_func_ptr->args[i]);
+ SAFE_FREE(bs_func_ptr->args);
+ bs_free_retval(bs_func_ptr->retval);
+ SAFE_FREE(bs_func_ptr);
+ }
+}
+
+static void
+bs_free_retval(bs_element_retval_t *bs_retval)
+{
+ if (bs_retval == NULL)
+ return;
+ SAFE_FREE(bs_retval->type);
+ bs_free_function_pointer(bs_retval->function_pointer);
+}
+
+static void
+bs_free_arg(bs_element_arg_t *bs_arg)
+{
+ SAFE_FREE(bs_arg->type);
+ SAFE_FREE(bs_arg->sel_of_type);
+ bs_free_function_pointer(bs_arg->function_pointer);
+}
+
+static void
+bs_free_method(bs_element_method_t *bs_method)
+{
+ unsigned i;
+ for (i = 0; i < bs_method->args_count; i++)
+ bs_free_arg(&bs_method->args[i]);
+ SAFE_FREE(bs_method->args);
+ bs_free_retval(bs_method->retval);
+ SAFE_FREE(bs_method->suggestion);
+}
+
void
bs_element_free(bs_element_type_t type, void *value)
{
- /* TODO */
+ assert(value != NULL);
+
+ switch (type) {
+ case BS_ELEMENT_STRUCT:
+ {
+ bs_element_struct_t *bs_struct = (bs_element_struct_t *)value;
+ unsigned i;
+ SAFE_FREE(bs_struct->name);
+ SAFE_FREE(bs_struct->type);
+ for (i = 0; i < bs_struct->fields_count; i++) {
+ SAFE_FREE(bs_struct->fields[i].name);
+ SAFE_FREE(bs_struct->fields[i].type);
+ }
+ SAFE_FREE(bs_struct->fields);
+ break;
+ }
+
+ case BS_ELEMENT_CFTYPE:
+ {
+ bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
+ SAFE_FREE(bs_cftype->name);
+ SAFE_FREE(bs_cftype->type);
+ SAFE_FREE(bs_cftype->tollfree);
+ break;
+ }
+
+ case BS_ELEMENT_OPAQUE:
+ {
+ bs_element_opaque_t *bs_opaque = (bs_element_opaque_t *)value;
+ SAFE_FREE(bs_opaque->name);
+ SAFE_FREE(bs_opaque->type);
+ break;
+ }
+
+ case BS_ELEMENT_CONSTANT:
+ {
+ bs_element_constant_t *bs_const = (bs_element_constant_t *)value;
+ SAFE_FREE(bs_const->name);
+ SAFE_FREE(bs_const->type);
+ SAFE_FREE(bs_const->suggestion);
+ break;
+ }
+
+ case BS_ELEMENT_STRING_CONSTANT:
+ {
+ bs_element_string_constant_t *bs_str_const =
+ (bs_element_string_constant_t *)value;
+ SAFE_FREE(bs_str_const->name);
+ SAFE_FREE(bs_str_const->value);
+ break;
+ }
+
+ case BS_ELEMENT_ENUM:
+ {
+ bs_element_enum_t *bs_enum = (bs_element_enum_t *)value;
+ SAFE_FREE(bs_enum->name);
+ SAFE_FREE(bs_enum->value);
+ SAFE_FREE(bs_enum->suggestion);
+ break;
+ }
+
+ case BS_ELEMENT_FUNCTION:
+ {
+ unsigned i;
+ bs_element_function_t *bs_func = (bs_element_function_t *)value;
+ free(bs_func->name);
+ for (i = 0; i < bs_func->args_count; i++)
+ bs_free_arg(&bs_func->args[i]);
+ SAFE_FREE(bs_func->args);
+ bs_free_retval(bs_func->retval);
+ break;
+ }
+
+ case BS_ELEMENT_FUNCTION_ALIAS:
+ {
+ bs_element_function_alias_t *bs_func_alias =
+ (bs_element_function_alias_t *)value;
+ SAFE_FREE(bs_func_alias->name);
+ SAFE_FREE(bs_func_alias->original);
+ break;
+ }
+
+ case BS_ELEMENT_CLASS:
+ {
+ bs_element_class_t *bs_class = (bs_element_class_t *)value;
+ unsigned i;
+ free(bs_class->name);
+ for (i = 0; i < bs_class->class_methods_count; i++)
+ bs_free_method(&bs_class->class_methods[i]);
+ SAFE_FREE(bs_class->class_methods);
+ for (i = 0; i < bs_class->instance_methods_count; i++)
+ bs_free_method(&bs_class->instance_methods[i]);
+ SAFE_FREE(bs_class->instance_methods);
+ break;
+ }
+
+ case BS_ELEMENT_INFORMAL_PROTOCOL_METHOD:
+ {
+ bs_element_informal_protocol_method_t *bs_iprotm =
+ (bs_element_informal_protocol_method_t *)value;
+ SAFE_FREE(bs_iprotm->protocol_name);
+ SAFE_FREE(bs_iprotm->type);
+ break;
+ }
+
+ default:
+ fprintf(stderr, "unknown value %p of type %d passed to bs_free()",
+ value, type);
+ }
+ free(value);
}
#if 0
Modified: MacRuby/branches/testing/class.c
===================================================================
--- MacRuby/branches/testing/class.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/class.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -23,7 +23,7 @@
static VALUE
class_init(VALUE obj)
{
- RCLASS(obj)->ptr = ALLOC(rb_classext_t);
+ GC_WB(&RCLASS(obj)->ptr, ALLOC(rb_classext_t));
RCLASS_IV_TBL(obj) = 0;
RCLASS_M_TBL(obj) = 0;
RCLASS_SUPER(obj) = 0;
@@ -44,6 +44,7 @@
assert(ocklass != NULL);
assert(class_isMetaClass(ocklass) == 0);
+ assert(rb_objc_class_tbl != NULL);
if (st_lookup(rb_objc_class_tbl, (st_data_t)ocklass, (st_data_t *)&rbklass))
return rbklass;
@@ -100,6 +101,34 @@
return rbklass;
}
+void rb_objc_install_array_primitives(Class);
+void rb_objc_install_hash_primitives(Class);
+void rb_objc_install_string_primitives(Class);
+
+bool
+rb_objc_install_primitives(Class ocklass, Class ocsuper)
+{
+ if (rb_cArray != 0 && rb_cHash != 0 && rb_cString != 0) {
+ do {
+ if (ocsuper == RCLASS_OCID(rb_cArray)) {
+ rb_objc_install_array_primitives(ocklass);
+ return true;
+ }
+ if (ocsuper == RCLASS_OCID(rb_cHash)) {
+ rb_objc_install_hash_primitives(ocklass);
+ return true;
+ }
+ if (ocsuper == RCLASS_OCID(rb_cString)) {
+ rb_objc_install_string_primitives(ocklass);
+ return true;
+ }
+ ocsuper = class_getSuperclass(ocsuper);
+ }
+ while (ocsuper != NULL);
+ }
+ return false;
+}
+
static VALUE
rb_objc_alloc_class(const char *name, VALUE super, VALUE flags, VALUE klass)
{
@@ -144,6 +173,9 @@
if (name == NULL)
FL_SET(obj, RCLASS_ANONYMOUS);
+ if (klass != 0)
+ rb_objc_install_primitives(ocklass, ocsuper);
+
return obj;
}
@@ -296,17 +328,27 @@
RCLASS_SUPER(clone) = RCLASS_SUPER(orig);
#if WITH_OBJC
{
- 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);
+ Class ocsuper;
+ extern VALUE rb_cStringRuby;
+ extern VALUE rb_cArrayRuby;
+ extern VALUE rb_cHashRuby;
+ if (orig == rb_cStringRuby
+ || orig == rb_cArrayRuby
+ || orig == rb_cHashRuby) {
+ ocsuper = RCLASS_OCID(orig);
+ rb_warn("cloning class `%s' is not supported, creating a " \
+ "subclass instead", rb_class2name(orig));
+ }
+ else {
+ ocsuper = class_getSuperclass(RCLASS_OCID(orig));
+ }
+ class_setSuperclass(RCLASS(clone)->ocklass, ocsuper);
}
#endif
if (RCLASS_IV_TBL(orig)) {
ID id;
- RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(orig));
+ GC_WB(&RCLASS_IV_TBL(clone), st_copy(RCLASS_IV_TBL(orig)));
id = rb_intern("__classpath__");
st_delete(RCLASS_IV_TBL(clone), (st_data_t*)&id, 0);
id = rb_intern("__classid__");
@@ -314,7 +356,8 @@
}
if (RCLASS_M_TBL(orig)) {
struct clone_method_data data;
- data.tbl = RCLASS_M_TBL(clone) = st_init_numtable();
+ GC_WB(&RCLASS_M_TBL(clone), st_init_numtable());
+ data.tbl = RCLASS_M_TBL(clone);
data.klass = clone;
st_foreach(RCLASS_M_TBL(orig), clone_method,
(st_data_t)&data);
@@ -333,7 +376,11 @@
if (FL_TEST(orig, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't copy singleton class");
}
- return rb_mod_init_copy(clone, orig);
+ clone = rb_mod_init_copy(clone, orig);
+#if WITH_OBJC
+ rb_objc_install_primitives(RCLASS_OCID(clone), RCLASS_OCID(orig));
+#endif
+ return clone;
}
VALUE
@@ -378,7 +425,7 @@
{
if (FL_TEST(klass, FL_SINGLETON)) {
if (!RCLASS_IV_TBL(klass)) {
- RCLASS_IV_TBL(klass) = st_init_numtable();
+ GC_WB(&RCLASS_IV_TBL(klass), st_init_numtable());
}
st_insert(RCLASS_IV_TBL(klass), rb_intern("__attached__"), obj);
}
@@ -387,30 +434,46 @@
VALUE
rb_make_metaclass(VALUE obj, VALUE super)
{
- if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
+ bool pure;
+
+#if WITH_OBJC
+ pure = rb_objc_is_non_native(obj);
+#else
+ pure = false;
+#endif
+
+ if (!pure && BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
return RBASIC(obj)->klass = rb_cClass;
}
else {
VALUE metasuper;
VALUE klass;
+
#if WITH_OBJC
- {
- NEWOBJ(obj2, struct RClass);
- OBJSETUP(obj2, rb_cClass, T_CLASS);
- klass = (VALUE)obj2;
+ if (!pure && BUILTIN_TYPE(obj) == T_CLASS) {
+ NEWOBJ(obj2, struct RClass);
+ OBJSETUP(obj2, rb_cClass, T_CLASS);
+ klass = (VALUE)obj2;
+ rb_objc_retain(klass);
+ class_init(klass);
+ OBJ_INFECT(klass, super);
+ RCLASS_SUPER(klass) = super;
+ RCLASS_M_TBL(klass) = st_init_numtable();
+ RCLASS(klass)->ocklass = RBASIC(super)->isa;
+ RBASIC(obj)->klass = klass;
}
- rb_objc_retain(klass);
- class_init(klass);
- OBJ_INFECT(klass, super);
- RCLASS_SUPER(klass) = super;
- RCLASS_M_TBL(klass) = st_init_numtable();
- RCLASS(klass)->ocklass = RBASIC(super)->isa;
+ else {
+ klass = rb_class_boot(super);
+ *(Class *)obj = RCLASS_OCID(klass);
+ if (!pure)
+ RBASIC(obj)->klass = klass;
+ }
#else
- klass = rb_class_boot(super);
+ klass = rb_class_boot(super);
+ RBASIC(obj)->klass = klass;
#endif
+ FL_SET(klass, FL_SINGLETON);
- FL_SET(klass, FL_SINGLETON);
- RBASIC(obj)->klass = klass;
rb_singleton_class_attached(klass, obj);
metasuper = RBASIC(rb_class_real(super))->klass;
@@ -623,23 +686,26 @@
if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
rb_raise(rb_eArgError, "cyclic include detected");
- /* ignore if the module included already in superclasses */
- for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
- switch (BUILTIN_TYPE(p)) {
- case T_ICLASS:
- if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
- if (!superclass_seen) {
- c = p; /* move insertion point */
- }
- goto skip;
- }
- break;
- case T_CLASS:
- superclass_seen = Qtrue;
- break;
- }
- }
- c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
+ /* ignore if the module included already in superclasses */
+ for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
+ switch (BUILTIN_TYPE(p)) {
+ case T_ICLASS:
+ if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
+ if (!superclass_seen) {
+ c = p; /* move insertion point */
+ }
+ goto skip;
+ }
+ break;
+ case T_CLASS:
+ superclass_seen = Qtrue;
+ break;
+ }
+ }
+#if WITH_OBJC
+ rb_objc_sync_ruby_methods(module, klass);
+#endif
+ c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
changed = 1;
skip:
module = RCLASS_SUPER(module);
@@ -867,9 +933,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
*/
@@ -907,8 +973,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
@@ -959,9 +1025,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
@@ -970,10 +1036,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)) {
@@ -1045,6 +1113,20 @@
}
DEFER_INTS;
+#if WITH_OBJC
+ if (rb_objc_is_non_native(obj)) {
+ Class ocklass;
+
+ ocklass = *(Class *)obj;
+ klass = rb_objc_import_class(ocklass);
+ if (class_isMetaClass(ocklass))
+ return klass;
+
+ if (!FL_TEST(klass, FL_SINGLETON))
+ klass = rb_make_metaclass(obj, klass);
+ return klass;
+ }
+#endif
if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) &&
rb_iv_get(RBASIC(obj)->klass, "__attached__") == obj) {
klass = RBASIC(obj)->klass;
@@ -1052,6 +1134,7 @@
else {
klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
}
+#if !WITH_OBJC
if (OBJ_TAINTED(obj)) {
OBJ_TAINT(klass);
}
@@ -1059,6 +1142,7 @@
FL_UNSET(klass, FL_TAINT);
}
if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass);
+#endif
ALLOW_INTS;
return klass;
Modified: MacRuby/branches/testing/common.mk
===================================================================
--- MacRuby/branches/testing/common.mk 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/common.mk 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)/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/branches/testing/compar.c
===================================================================
--- MacRuby/branches/testing/compar.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/compar.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/compile.c
===================================================================
--- MacRuby/branches/testing/compile.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/compile.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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);
@@ -863,7 +902,12 @@
iseq->arg_opts = i;
iseq->arg_opt_table = ALLOC_N(VALUE, i);
+#if WITH_OBJC
+ CFArrayGetValues((CFArrayRef)labels, CFRangeMake(0, i),
+ (const void **)iseq->arg_opt_table);
+#else
MEMCPY(iseq->arg_opt_table, RARRAY_PTR(labels), VALUE, i);
+#endif
for (j = 0; j < i; j++) {
iseq->arg_opt_table[j] &= ~1;
}
@@ -1020,7 +1064,7 @@
default:
dump_disasm_list(FIRST_ELEMENT(anchor));
dump_disasm_list(list);
- rb_compile_error(RSTRING_PTR(iseq->filename), line,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), line,
"error: set_sequence");
break;
}
@@ -1039,7 +1083,7 @@
case ISEQ_ELEMENT_INSN:
{
int j, len, insn;
- char *types;
+ const char *types;
VALUE *operands;
iobj = (INSN *)list;
@@ -1061,7 +1105,7 @@
/* operand check */
if (iobj->operand_size != len - 1) {
dump_disasm_list(list);
- rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), iobj->line_no,
"operand size miss! (%d for %d)",
iobj->operand_size, len - 1);
return 0;
@@ -1076,7 +1120,7 @@
/* label(destination position) */
lobj = (LABEL *)operands[j];
if (lobj->set != Qtrue) {
- rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), iobj->line_no,
"unknown label");
}
if (lobj->sp == -1) {
@@ -1101,7 +1145,7 @@
lobj = (LABEL *)(lv & ~1);
if (lobj->set != Qtrue) {
- rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), iobj->line_no,
"unknown label");
}
rb_hash_aset(map, obj, INT2FIX(lobj->position - (pos+len)));
@@ -1151,7 +1195,7 @@
}
break;
default:
- rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), iobj->line_no,
"unknown operand type: %c", type);
return 0;
}
@@ -1220,7 +1264,7 @@
#if 0 /* XXX */
/* this check need dead code elimination */
if (sp != 1) {
- rb_bug("SP is not 0 on %s (%d)\n", RSTRING_PTR(iseq->name), sp);
+ rb_bug("SP is not 0 on %s (%d)\n", RSTRING_CPTR(iseq->name), sp);
}
#endif
@@ -1248,23 +1292,22 @@
static int
iseq_set_exception_table(rb_iseq_t *iseq)
{
- VALUE *tptr, *ptr;
int tlen, i;
struct iseq_catch_table_entry *entry;
tlen = RARRAY_LEN(iseq->compile_data->catch_table_ary);
- tptr = RARRAY_PTR(iseq->compile_data->catch_table_ary);
- iseq->catch_table = ALLOC_N(struct iseq_catch_table_entry, tlen);
+ GC_WB(&iseq->catch_table, ALLOC_N(struct iseq_catch_table_entry, tlen));
+
iseq->catch_table_size = tlen;
for (i = 0; i < tlen; i++) {
- ptr = RARRAY_PTR(tptr[i]);
+ VALUE a = RARRAY_AT(iseq->compile_data->catch_table_ary, i);
entry = &iseq->catch_table[i];
- entry->type = ptr[0] & 0xffff;
- entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
- entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
- entry->iseq = ptr[3];
+ entry->type = RARRAY_AT(a, 0) & 0xffff;
+ entry->start = label_get_position((LABEL *)(RARRAY_AT(a, 1) & ~1));
+ entry->end = label_get_position((LABEL *)(RARRAY_AT(a, 2) & ~1));
+ GC_WB(&entry->iseq, RARRAY_AT(a, 3));
/* register iseq as mark object */
if (entry->iseq != 0) {
@@ -1272,15 +1315,15 @@
}
/* stack depth */
- if (ptr[4]) {
- LABEL *lobj = (LABEL *)(ptr[4] & ~1);
+ if (RARRAY_AT(a, 4)) {
+ LABEL *lobj = (LABEL *)(RARRAY_AT(a, 4) & ~1);
entry->cont = label_get_position(lobj);
entry->sp = label_get_sp(lobj);
/* TODO: Dirty Hack! Fix me */
if (entry->type == CATCH_TYPE_RESCUE ||
entry->type == CATCH_TYPE_BREAK ||
- (((ptr[0] & 0x10000) == 0)
+ (((RARRAY_AT(a, 0) & 0x10000) == 0)
&& entry->type == CATCH_TYPE_NEXT)) {
entry->sp--;
}
@@ -1660,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 ||
@@ -1722,7 +1765,7 @@
dump_disasm_list((LINK_ELEMENT *)iobj);
dump_disasm_list((LINK_ELEMENT *)lobj);
printf("\n-- %d, %d\n", lobj->sc_state, nstate);
- rb_compile_error(RSTRING_PTR(iseq->filename), iobj->lineno,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), iobj->lineno,
"insn_set_sc_state error\n");
return 0;
}
@@ -1824,7 +1867,7 @@
case SCS_XX:
goto normal_insn;
default:
- rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), iobj->line_no,
"unreachable");
}
/* remove useless pop */
@@ -1985,7 +2028,7 @@
iseq_add_mark_object_compile_time(iseq, ary);
#if WITH_OBJC
if (node_root->flags & NODE_ARRAY_NAMED_ARGS)
- FL_SET(ary, RARRAY_NAMED_ARGS);
+ rb_ary_set_named_args(ary, true);
#endif
ADD_INSN1(ret, nd_line(node_root), duparray, ary);
}
@@ -2109,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;
@@ -2255,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;
@@ -2294,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);
@@ -2350,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);
@@ -2388,7 +2425,6 @@
case NODE_VCALL:
case NODE_FCALL:
case NODE_ATTRASGN:{
- LABEL *lfalse = NULL;
int self = Qtrue;
switch (type) {
@@ -2400,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);
}
@@ -2425,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;
}
@@ -2445,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,
@@ -2457,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:
@@ -2472,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 "),
@@ -2481,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"));
}
@@ -2493,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 */
}
@@ -2518,7 +2555,7 @@
make_name_for_block(rb_iseq_t *iseq)
{
if (iseq->parent_iseq == 0) {
- return rb_sprintf("block in %s", RSTRING_PTR(iseq->name));
+ return rb_sprintf("block in %s", RSTRING_CPTR(iseq->name));
}
else {
int level = 1;
@@ -2527,7 +2564,7 @@
ip = ip->parent_iseq;
level++;
}
- return rb_sprintf("block (%d levels) in %s", level, RSTRING_PTR(ip->name));
+ return rb_sprintf("block (%d levels) in %s", level, RSTRING_CPTR(ip->name));
}
}
@@ -2778,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)));
}
@@ -3102,7 +3132,6 @@
}
else {
rb_iseq_t *ip;
- next_by_throw:
ip = iseq;
while (ip) {
level = 0x8000;
@@ -3164,7 +3193,6 @@
else {
rb_iseq_t *ip;
unsigned long level;
- redo_by_throw:
level = 0x8000 | 0x4000;
ip = iseq;
while (ip) {
@@ -3249,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),
@@ -3410,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;
}
@@ -3623,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);
@@ -3823,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,
@@ -4223,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 =
@@ -4274,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));
@@ -4387,7 +4443,7 @@
LABEL *lfin = NEW_LABEL(nd_line(node));
LABEL *ltrue = NEW_LABEL(nd_line(node));
VALUE key = rb_sprintf("flipflag/%s-%p-%d",
- RSTRING_PTR(iseq->name), iseq,
+ RSTRING_CPTR(iseq->name), iseq,
iseq->compile_data->flip_cnt++);
iseq_add_mark_object_compile_time(iseq, key);
@@ -4473,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;
}
@@ -4610,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++) {
@@ -4766,7 +4829,7 @@
if (sym == symRedo) return CATCH_TYPE_REDO;
if (sym == symNext) return CATCH_TYPE_NEXT;
rb_raise(rb_eSyntaxError, "invalid exception symbol: %s",
- RSTRING_PTR(rb_inspect(sym)));
+ RSTRING_CPTR(rb_inspect(sym)));
return 0;
}
@@ -4777,28 +4840,27 @@
int i;
for (i=0; i<RARRAY_LEN(exception); i++) {
- VALUE v, type, *ptr, eiseqval;
+ VALUE v, type, eiseqval;
LABEL *lstart, *lend, *lcont;
int sp;
- RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY,
+ RB_GC_GUARD(v) = rb_convert_type(RARRAY_AT(exception, i), T_ARRAY,
"Array", "to_ary");
if (RARRAY_LEN(v) != 6) {
rb_raise(rb_eSyntaxError, "wrong exception entry");
}
- ptr = RARRAY_PTR(v);
- type = get_exception_sym2type(ptr[0]);
- if (ptr[1] == Qnil) {
+ type = get_exception_sym2type(RARRAY_AT(v, 0));
+ if (RARRAY_AT(v, 1) == Qnil) {
eiseqval = 0;
}
else {
- eiseqval = iseq_load(0, ptr[1], iseq->self, Qnil);
+ eiseqval = iseq_load(0, RARRAY_AT(v, 1), iseq->self, Qnil);
}
- lstart = register_label(iseq, labels_table, ptr[2]);
- lend = register_label(iseq, labels_table, ptr[3]);
- lcont = register_label(iseq, labels_table, ptr[4]);
- sp = NUM2INT(ptr[5]);
+ lstart = register_label(iseq, labels_table, RARRAY_AT(v, 2));
+ lend = register_label(iseq, labels_table, RARRAY_AT(v, 3));
+ lcont = register_label(iseq, labels_table, RARRAY_AT(v, 4));
+ sp = NUM2INT(RARRAY_AT(v, 5));
ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont);
}
@@ -4812,7 +4874,6 @@
VALUE body, struct st_table *labels_table)
{
/* TODO: body should be freezed */
- VALUE *ptr = RARRAY_PTR(body);
int len = RARRAY_LEN(body);
int i, j;
int line_no = 0;
@@ -4827,7 +4888,7 @@
}
for (i=0; i<len; i++) {
- VALUE obj = ptr[i];
+ VALUE obj = RARRAY_AT(body, i);
if (SYMBOL_P(obj)) {
LABEL *label = register_label(iseq, labels_table, obj);
@@ -4842,16 +4903,16 @@
VALUE insn_id;
VALUE insn;
- insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0];
+ insn = (argc < 0) ? Qnil : RARRAY_AT(obj, 0);
if (st_lookup(insn_table, insn, &insn_id) == 0) {
/* TODO: exception */
RB_GC_GUARD(insn) = rb_inspect(insn);
- rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
- "unknown instruction: %s", RSTRING_PTR(insn));
+ rb_compile_error(RSTRING_CPTR(iseq->filename), line_no,
+ "unknown instruction: %s", RSTRING_CPTR(insn));
}
if (argc != insn_len(insn_id)-1) {
- rb_compile_error(RSTRING_PTR(iseq->filename), line_no,
+ rb_compile_error(RSTRING_CPTR(iseq->filename), line_no,
"operand size mismatch");
}
@@ -4964,7 +5025,7 @@
iseq->local_size = opt + iseq->local_table_size;
for (i=0; i<RARRAY_LEN(locals); i++) {
- VALUE lv = RARRAY_PTR(locals)[i];
+ VALUE lv = RARRAY_AT(locals, i);
tbl[i] = FIXNUM_P(lv) ? FIX2INT(lv) : SYM2ID(CHECK_SYMBOL(lv));
}
Modified: MacRuby/branches/testing/compile.h
===================================================================
--- MacRuby/branches/testing/compile.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/compile.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/complex.c (from rev 232, MacRuby/trunk/complex.c)
===================================================================
--- MacRuby/branches/testing/complex.c (rev 0)
+++ MacRuby/branches/testing/complex.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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_AT(a, 0);
+ theta = RARRAY_AT(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_AT(a, 0);
+ theta = RARRAY_AT(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_AT(a, 0);
+ dat->image = RARRAY_AT(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_CLEN(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_AT(a, 0)) || RSTRING_CLEN(RARRAY_AT(a, 1)) > 0) {
+ VALUE s = f_inspect(self);
+ rb_raise(rb_eArgError, "invalid value for Complex: %s",
+ StringValuePtr(s));
+ }
+ return RARRAY_AT(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_AT(a, 0)))
+ return RARRAY_AT(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));
+}
Modified: MacRuby/branches/testing/configure.in
===================================================================
--- MacRuby/branches/testing/configure.in 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/configure.in 2008-05-28 20:03:03 UTC (rev 233)
@@ -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])]
@@ -1202,7 +1296,7 @@
rhapsody*) : ${LDSHARED='cc -dynamic -bundle -undefined suppress'}
: ${LDFLAGS=""}
rb_cv_dlopen=yes ;;
- darwin*) : ${LDSHARED='cc -dynamic -bundle -undefined suppress -flat_namespace'}
+ darwin*) : ${LDSHARED='$(CC) -dynamic -bundle -undefined suppress -flat_namespace'}
: ${LDFLAGS=""}
: ${LIBPATHENV=DYLD_LIBRARY_PATH}
rb_cv_dlopen=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
@@ -1535,7 +1630,7 @@
;;
darwin*)
LIBRUBY_SO='lib$(RUBY_SO_NAME).$(MAJOR).$(MINOR).$(TEENY).dylib'
- LIBRUBY_LDSHARED='cc -dynamiclib -undefined suppress -flat_namespace'
+ LIBRUBY_LDSHARED='$(CC) -dynamiclib -undefined suppress -flat_namespace'
LIBRUBY_DLDFLAGS='-install_name $(libdir)/lib$(RUBY_SO_NAME).dylib -current_version $(MAJOR).$(MINOR).$(TEENY) -compatibility_version $(MAJOR).$(MINOR)'
LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).$(MAJOR).$(MINOR).dylib lib$(RUBY_SO_NAME).dylib'
;;
@@ -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/branches/testing/cont.c
===================================================================
--- MacRuby/branches/testing/cont.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/cont.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/debug.c
===================================================================
--- MacRuby/branches/testing/debug.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/debug.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -13,14 +13,17 @@
#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
RUBY_ENCODING_INLINE_MAX = ENCODING_INLINE_MAX,
RUBY_ENCODING_SHIFT = ENCODING_SHIFT,
RUBY_ENCODING_MASK = ENCODING_MASK,
@@ -29,6 +32,7 @@
RUBY_ENC_CODERANGE_7BIT = ENC_CODERANGE_7BIT,
RUBY_ENC_CODERANGE_VALID = ENC_CODERANGE_VALID,
RUBY_ENC_CODERANGE_BROKEN = ENC_CODERANGE_BROKEN,
+#endif
RUBY_FL_MARK = FL_MARK,
RUBY_FL_RESERVED = FL_RESERVED,
RUBY_FL_FINALIZE = FL_FINALIZE,
@@ -67,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)
{
@@ -133,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/branches/testing/debug.h
===================================================================
--- MacRuby/branches/testing/debug.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/debug.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/dir.c
===================================================================
--- MacRuby/branches/testing/dir.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/dir.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -386,6 +378,7 @@
dir_initialize(VALUE dir, VALUE dirname)
{
struct dir_data *dp;
+ const char *dirname_cstr;
FilePathValue(dirname);
Data_Get_Struct(dir, struct dir_data, dp);
@@ -393,17 +386,18 @@
if (dp->path) free(dp->path);
dp->dir = NULL;
dp->path = NULL;
- dp->dir = opendir(RSTRING_PTR(dirname));
+ dirname_cstr = RSTRING_CPTR(dirname);
+ dp->dir = opendir(dirname_cstr);
if (dp->dir == NULL) {
if (errno == EMFILE || errno == ENFILE) {
rb_gc();
- dp->dir = opendir(RSTRING_PTR(dirname));
+ dp->dir = opendir(dirname_cstr);
}
if (dp->dir == NULL) {
- rb_sys_fail(RSTRING_PTR(dirname));
+ rb_sys_fail(dirname_cstr);
}
}
- dp->path = strdup(RSTRING_PTR(dirname));
+ dp->path = strdup(dirname_cstr);
return dir;
}
@@ -470,6 +464,7 @@
int len = strlen(c) + strlen(dirp->path) + 4;
VALUE s = rb_str_new(0, len);
snprintf(RSTRING_PTR(s), len+1, "#<%s:%s>", c, dirp->path);
+ RSTRING_SYNC(s);
return s;
}
return rb_funcall(dir, rb_intern("to_s"), 0, 0);
@@ -580,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
@@ -687,8 +682,9 @@
static void
dir_chdir(VALUE path)
{
- if (chdir(RSTRING_PTR(path)) < 0)
- rb_sys_fail(RSTRING_PTR(path));
+ const char *cpath = RSTRING_CPTR(path);
+ if (chdir(cpath) < 0)
+ rb_sys_fail(cpath);
}
static int chdir_blocking = 0;
@@ -719,6 +715,7 @@
chdir_thread = Qnil;
dir_chdir(args->old_path);
}
+ rb_objc_release(args->old_path);
return Qnil;
}
@@ -789,6 +786,7 @@
char *cwd = my_getcwd();
args.old_path = rb_tainted_str_new2(cwd); xfree(cwd);
+ rb_objc_retain(args.old_path);
args.new_path = path;
args.done = Qfalse;
return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
@@ -826,11 +824,11 @@
static void
check_dirname(volatile VALUE *dir)
{
- char *path, *pend;
+ const char *path, *pend;
rb_secure(2);
FilePathValue(*dir);
- path = RSTRING_PTR(*dir);
+ path = RSTRING_CPTR(*dir);
if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) {
*dir = rb_str_new(path, pend - path);
}
@@ -849,10 +847,12 @@
dir_s_chroot(VALUE dir, VALUE path)
{
#if defined(HAVE_CHROOT) && !defined(__CHECKER__)
+ const char *path_cstr = RSTRING_CPTR(path);
+
check_dirname(&path);
- if (chroot(RSTRING_PTR(path)) == -1)
- rb_sys_fail(RSTRING_PTR(path));
+ if (chroot(path_cstr) == -1)
+ rb_sys_fail(path_cstr);
return INT2FIX(0);
#else
@@ -879,6 +879,7 @@
{
VALUE path, vmode;
int mode;
+ const char *path_cstr;
if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
mode = NUM2INT(vmode);
@@ -888,8 +889,9 @@
}
check_dirname(&path);
- if (mkdir(RSTRING_PTR(path), mode) == -1)
- rb_sys_fail(RSTRING_PTR(path));
+ path_cstr = RSTRING_CPTR(path);
+ if (mkdir(path_cstr, mode) == -1)
+ rb_sys_fail(path_cstr);
return INT2FIX(0);
}
@@ -906,9 +908,12 @@
static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
{
+ const char *dir_cstr;
+
check_dirname(&dir);
- if (rmdir(RSTRING_PTR(dir)) < 0)
- rb_sys_fail(RSTRING_PTR(dir));
+ dir_cstr = RSTRING_CPTR(dir);
+ if (rmdir(dir_cstr) < 0)
+ rb_sys_fail(dir_cstr);
return INT2FIX(0);
}
@@ -1547,23 +1552,27 @@
static VALUE
rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
{
+ const char *cstr;
+ long clen;
long offset = 0;
VALUE ary;
StringValue(str);
ary = rb_ary_new();
+ cstr = RSTRING_CPTR(str);
+ clen = RSTRING_CLEN(str);
- while (offset < RSTRING_LEN(str)) {
- int status = push_glob(ary, RSTRING_PTR(str) + offset, flags);
- char *p, *pend;
+ while (offset < clen) {
+ int status = push_glob(ary, cstr + offset, flags);
+ const char *p, *pend;
if (status) GLOB_JUMP_TAG(status);
- if (offset >= RSTRING_LEN(str)) break;
- p = RSTRING_PTR(str) + offset;
+ if (offset >= clen) break;
+ p = cstr + offset;
p += strlen(p) + 1;
- pend = RSTRING_PTR(str) + RSTRING_LEN(str);
+ pend = cstr + clen;
while (p < pend && !*p)
p++;
- offset = p - RSTRING_PTR(str);
+ offset = p - cstr;
}
return ary;
@@ -1579,7 +1588,7 @@
int status;
VALUE str = argv[i];
StringValue(str);
- status = push_glob(ary, RSTRING_PTR(str), flags);
+ status = push_glob(ary, RSTRING_CPTR(str), flags);
if (status) GLOB_JUMP_TAG(status);
}
@@ -1653,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"]
@@ -1681,7 +1690,7 @@
ary = rb_push_glob(str, flags);
}
else {
- volatile VALUE v = ary;
+ VALUE v = ary;
ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
}
@@ -1788,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.
@@ -1850,7 +1859,7 @@
StringValue(pattern);
FilePathStringValue(path);
- if (fnmatch(RSTRING_PTR(pattern), RSTRING_PTR(path), flags) == 0)
+ if (fnmatch(RSTRING_CPTR(pattern), RSTRING_CPTR(path), flags) == 0)
return Qtrue;
return Qfalse;
Modified: MacRuby/branches/testing/dln.c
===================================================================
--- MacRuby/branches/testing/dln.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/dln.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -366,6 +366,7 @@
return -1;
}
sym_tbl = sym_hash(&hdr, syms);
+ GC_ROOT(&sym_tbl);
if (sym_tbl == NULL) { /* file may be start with #! */
char c = '\0';
char buf[MAXPATHLEN];
@@ -408,6 +409,7 @@
}
dln_init_p = 1;
undef_tbl = st_init_strtable();
+ GC_ROOT(&undef_tbl);
close(fd);
return 0;
@@ -1568,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);
@@ -1584,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;
@@ -1642,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,
@@ -1694,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)
@@ -1726,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);
@@ -1747,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/branches/testing/dln.h
===================================================================
--- MacRuby/branches/testing/dln.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/dln.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/dmyencoding.c
===================================================================
--- MacRuby/branches/testing/dmyencoding.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/dmyencoding.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,3 +1,2 @@
-#define NO_ENCDB_H 1
#define NO_LOCALE_CHARMAP 1
#include "encoding.c"
Modified: MacRuby/branches/testing/dmytranscode.c
===================================================================
--- MacRuby/branches/testing/dmytranscode.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/dmytranscode.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,2 +0,0 @@
-#define NO_TRANSDB_H 1
-#include "transcode.c"
Modified: MacRuby/branches/testing/doc/NEWS
===================================================================
--- MacRuby/branches/testing/doc/NEWS 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/doc/NEWS 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/enc/depend
===================================================================
--- MacRuby/branches/testing/enc/depend 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/enc/depend 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/enc/make_encdb.rb
===================================================================
--- MacRuby/branches/testing/enc/make_encdb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/enc/make_encdb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/enc/make_encmake.rb
===================================================================
--- MacRuby/branches/testing/enc/make_encmake.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/enc/make_encmake.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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]
Copied: MacRuby/branches/testing/enc/prelude.rb (from rev 232, MacRuby/trunk/enc/prelude.rb)
===================================================================
--- MacRuby/branches/testing/enc/prelude.rb (rev 0)
+++ MacRuby/branches/testing/enc/prelude.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,6 @@
+%w'enc/encdb enc/trans/transdb'.each do |init|
+ begin
+ require(init)
+ rescue LoadError
+ end
+end
Modified: MacRuby/branches/testing/enc/trans/make_transdb.rb
===================================================================
--- MacRuby/branches/testing/enc/trans/make_transdb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/enc/trans/make_transdb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/enc/trans/utf_16_32.c
===================================================================
--- MacRuby/branches/testing/enc/trans/utf_16_32.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/enc/trans/utf_16_32.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/encoding.c
===================================================================
--- MacRuby/branches/testing/encoding.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/encoding.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -20,6 +20,102 @@
static ID id_encoding, id_base_encoding;
static VALUE rb_cEncoding;
+#if WITH_OBJC
+
+static CFMutableDictionaryRef __encodings = NULL;
+
+static VALUE
+enc_new(const CFStringEncoding *enc)
+{
+ return Data_Wrap_Struct(rb_cEncoding, NULL, NULL, (void *)enc);
+}
+
+static void
+enc_init_db(void)
+{
+ const CFStringEncoding *e;
+
+ __encodings = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+
+ e = CFStringGetListOfAvailableEncodings();
+ while (e != NULL && *e != kCFStringEncodingInvalidId) {
+ VALUE iana;
+ VALUE encoding;
+
+ encoding = enc_new(e);
+
+ iana = (VALUE)CFStringConvertEncodingToIANACharSetName(*e);
+ if (iana != 0) {
+ const char *name;
+ char *p;
+
+ name = RSTRING_CPTR(iana);
+ p = strchr(name, '-');
+ if ((p = strchr(name, '-')) != NULL
+ || islower(*name)) {
+ char *tmp = alloca(strlen(name));
+ strcpy(tmp, name);
+ if (p != NULL) {
+ p = tmp + (p - name);
+ do {
+ *p = '_';
+ p++;
+ p = strchr(p, '-');
+ }
+ while (p != NULL);
+ }
+ if (islower(*tmp))
+ *tmp = toupper(*tmp);
+ name = tmp;
+ }
+ rb_define_const(rb_cEncoding, name, encoding);
+ }
+ CFDictionarySetValue(__encodings, (const void *)(*e),
+ (const void *)encoding);
+ e++;
+ }
+
+ assert(CFDictionaryGetCount((CFDictionaryRef)__encodings) > 0);
+}
+
+static VALUE
+enc_make(const CFStringEncoding *enc)
+{
+ VALUE v;
+ v = (VALUE)CFDictionaryGetValue( (CFDictionaryRef)__encodings,
+ (const void *)(*enc));
+ assert(v != 0);
+ return v;
+}
+
+VALUE
+rb_enc_from_encoding(rb_encoding *enc)
+{
+ return enc_make(enc);
+}
+
+static inline CFStringEncoding
+rb_enc_to_enc(VALUE v)
+{
+ return *(CFStringEncoding *)DATA_PTR(v);
+}
+
+static inline CFStringEncoding *
+rb_enc_to_enc_ptr(VALUE v)
+{
+ return (CFStringEncoding *)DATA_PTR(v);
+}
+
+rb_encoding *
+rb_to_encoding(VALUE v)
+{
+ if (TYPE(v) == T_STRING)
+ return rb_enc_find2(v);
+ return rb_enc_to_enc_ptr(v);
+}
+
+#else
+
struct rb_encoding_entry {
const char *name;
rb_encoding *enc;
@@ -34,29 +130,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))
@@ -81,9 +155,6 @@
{
VALUE enc = Data_Wrap_Struct(rb_cEncoding, enc_mark, 0, encoding);
encoding->auxiliary_data = (void *)enc;
-#if WITH_OBJC
- rb_objc_retain(enc);
-#endif
return enc;
}
@@ -111,7 +182,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;
}
@@ -254,9 +325,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) {
@@ -264,7 +334,6 @@
}
set_encoding_const(name, rb_enc_from_index(idx));
}
-#endif
static void
enc_check_duplication(const char *name)
@@ -296,7 +365,6 @@
return idx;
}
-#ifndef NO_ENCDB_H
static int
enc_replicate(int idx, const char *name, rb_encoding *origenc)
{
@@ -313,8 +381,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);
@@ -324,7 +392,6 @@
}
return enc_replicate(idx, name, rb_enc_from_index(origidx));
}
-#endif
int
rb_define_dummy_encoding(const char *name)
@@ -336,9 +403,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());
@@ -347,13 +413,17 @@
ENC_SET_DUMMY(enc);
return index;
}
-#endif
+#endif // WITH_OBJC
int
rb_enc_dummy_p(rb_encoding *enc)
{
+#if WITH_OBJC
+ return Qfalse;
+#else
VALUE encoding = rb_enc_from_encoding(enc);
return ENC_DUMMY_P(encoding);
+#endif
}
/*
@@ -375,6 +445,7 @@
return rb_enc_dummy_p(rb_to_encoding(enc)) ? Qtrue : Qfalse;
}
+#if !WITH_OBJC
static int
enc_alias(const char *alias, int idx)
{
@@ -399,9 +470,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);
@@ -410,7 +480,6 @@
}
return enc_alias(alias, idx);
}
-#endif
enum {
ENCINDEX_ASCII,
@@ -540,7 +609,7 @@
enc_capable(VALUE obj)
{
if (SPECIAL_CONST_P(obj)) return Qfalse;
- switch (BUILTIN_TYPE(obj)) {
+ switch (/*BUILTIN_*/TYPE(obj)) {
case T_STRING:
case T_REGEXP:
case T_FILE:
@@ -576,6 +645,7 @@
rb_raise(rb_eTypeError, "wrong argument type %s (not encode capable)", etype);
}
}
+#endif
ID
rb_id_encoding(void)
@@ -586,6 +656,7 @@
return id_encoding;
}
+#if !WITH_OBJC
int
rb_enc_internal_get_index(VALUE obj)
{
@@ -617,7 +688,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))) {
@@ -655,10 +726,18 @@
rb_enc_name(rb_enc_get(str2)));
return enc;
}
+#endif
rb_encoding*
rb_enc_compatible(VALUE str1, VALUE str2)
{
+#if WITH_OBJC
+ /* TODO */
+ rb_encoding *enc = rb_enc_get(str1);
+ if (enc == rb_enc_get(str2))
+ return enc;
+ return NULL;
+#else
int idx1, idx2;
rb_encoding *enc1, *enc2;
@@ -710,15 +789,17 @@
return enc2;
}
return 0;
+#endif
}
+#if !WITH_OBJC
void
rb_enc_copy(VALUE obj1, VALUE obj2)
{
rb_enc_associate_index(obj1, rb_enc_get_index(obj2));
}
+#endif
-
/*
* call-seq:
* obj.encoding => encoding
@@ -736,6 +817,7 @@
return rb_enc_from_encoding(enc);
}
+#if !WITH_OBJC
int
rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
{
@@ -817,6 +899,7 @@
{
return (ONIGENC_IS_ASCII_CODE(c)?ONIGENC_ASCII_CODE_TO_LOWER_CASE(c):(c));
}
+#endif
/*
* call-seq:
@@ -830,11 +913,24 @@
static VALUE
enc_inspect(VALUE self)
{
+#if WITH_OBJC
+ char buffer[512];
+ VALUE enc_name;
+ long n;
+
+ enc_name = (VALUE)CFStringGetNameOfEncoding(rb_enc_to_enc(self));
+
+ n = snprintf(buffer, sizeof buffer, "#<%s:%s>", rb_obj_classname(self),
+ RSTRING_CPTR(enc_name));
+
+ return rb_str_new(buffer, n);
+#else
VALUE str = rb_sprintf("#<%s:%s%s>", rb_obj_classname(self),
rb_enc_name((rb_encoding*)DATA_PTR(self)),
(ENC_DUMMY_P(self) ? " (dummy)" : ""));
ENCODING_CODERANGE_SET(str, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
return str;
+#endif
}
/*
@@ -848,7 +944,11 @@
static VALUE
enc_name(VALUE self)
{
+#if WITH_OBJC
+ return (VALUE)CFStringConvertEncodingToIANACharSetName(rb_enc_to_enc(self));
+#else
return rb_usascii_str_new2(rb_enc_name((rb_encoding*)DATA_PTR(self)));
+#endif
}
static VALUE
@@ -878,6 +978,17 @@
static VALUE
enc_list(VALUE klass)
{
+#if WITH_OBJC
+ VALUE ary;
+ const CFStringEncoding *e;
+
+ ary = rb_ary_new();
+ e = CFStringGetListOfAvailableEncodings();
+ while (e != NULL && *e != kCFStringEncodingInvalidId) {
+ rb_ary_push(ary, enc_make(e));
+ e++;
+ }
+#else
VALUE ary = rb_ary_new2(enc_table.count);
int i;
for (i = 0; i < enc_table.count; ++i) {
@@ -886,6 +997,7 @@
rb_ary_push(ary, rb_enc_from_encoding(enc));
}
}
+#endif
return ary;
}
@@ -902,8 +1014,36 @@
*
*/
static VALUE
+enc_find2(VALUE enc)
+{
+ CFStringRef str;
+ CFStringEncoding e;
+
+ str = (CFStringRef)StringValue(enc);
+ if (CFStringCompare(str, CFSTR("ASCII-8BIT"),
+ kCFCompareCaseInsensitive) == 0) {
+ str = CFSTR("ASCII");
+ }
+ else if (CFStringCompare(str, CFSTR("SJIS"),
+ kCFCompareCaseInsensitive) == 0) {
+ str = CFSTR("Shift-JIS");
+ }
+
+ e = CFStringConvertIANACharSetNameToEncoding(str);
+ if (e == kCFStringEncodingInvalidId)
+ return Qnil;
+ return enc_make(&e);
+}
+
+static VALUE
enc_find(VALUE klass, VALUE enc)
{
+#if WITH_OBJC
+ VALUE e = enc_find2(enc);
+ if (e == Qnil)
+ rb_raise(rb_eArgError, "unknown encoding name - %s", RSTRING_PTR(enc));
+ return e;
+#else
int idx;
StringValue(enc);
@@ -915,6 +1055,7 @@
rb_raise(rb_eArgError, "unknown encoding name - %s", RSTRING_PTR(enc));
}
return rb_enc_from_encoding(rb_enc_from_index(idx));
+#endif
}
/*
@@ -960,6 +1101,7 @@
return enc_find(klass, str);
}
+#if !WITH_OBJC
rb_encoding *
rb_ascii8bit_encoding(void)
{
@@ -1022,7 +1164,24 @@
{
return rb_enc_from_encoding(rb_default_external_encoding());
}
+#endif
+#if WITH_OBJC
+static rb_encoding *default_external;
+
+rb_encoding *
+rb_default_external_encoding(void)
+{
+ return default_external;
+}
+
+VALUE
+rb_enc_default_external(void)
+{
+ return enc_make(default_external);
+}
+#endif
+
/*
* call-seq:
* Encoding.default_external => enc
@@ -1040,7 +1199,11 @@
void
rb_enc_set_default_external(VALUE encoding)
{
+#if WITH_OBJC
+ default_external = rb_enc_to_enc_ptr(encoding);
+#else
default_external_index = rb_enc_to_index(rb_to_encoding(encoding));
+#endif
}
/*
@@ -1065,7 +1228,10 @@
VALUE
rb_locale_charmap(VALUE klass)
{
-#if defined NO_LOCALE_CHARMAP
+#if WITH_OBJC
+ CFStringEncoding enc = CFStringGetSystemEncoding();
+ return (VALUE)CFStringConvertEncodingToIANACharSetName(enc);
+#elif defined NO_LOCALE_CHARMAP
return rb_usascii_str_new2("ASCII-8BIT");
#elif defined HAVE_LANGINFO_H
char *codeset;
@@ -1078,6 +1244,7 @@
#endif
}
+#if !WITH_OBJC
static void
set_encoding_const(const char *name, rb_encoding *enc)
{
@@ -1133,6 +1300,7 @@
rb_ary_push(ary, str);
return ST_CONTINUE;
}
+#endif
/*
* call-seq:
@@ -1153,11 +1321,22 @@
static VALUE
rb_enc_name_list(VALUE klass)
{
+#if WITH_OBJC
+ VALUE ary, list;
+ long i, count;
+
+ ary = rb_ary_new();
+ list = enc_list(klass);
+ for (i = 0, count = RARRAY_LEN(list); i < count; i++)
+ rb_ary_push(ary, enc_name(RARRAY_AT(list, i)));
+#else
VALUE ary = rb_ary_new2(enc_table.names->num_entries);
st_foreach(enc_table.names, rb_enc_name_list_i, (st_data_t)ary);
+#endif
return ary;
}
+#if !WITH_OBJC
static int
rb_enc_aliases_enc_i(st_data_t name, st_data_t orig, st_data_t arg)
{
@@ -1181,6 +1360,7 @@
rb_hash_aset(aliases, key, str);
return ST_CONTINUE;
}
+#endif
/*
* call-seq:
@@ -1197,13 +1377,86 @@
static VALUE
rb_enc_aliases(VALUE klass)
{
+#if WITH_OBJC
+ /* TODO: the CFString IANA <-> charset code does support aliases, we should
+ * find a way to return them here.
+ */
+ return rb_hash_new();
+#else
VALUE aliases[2];
aliases[0] = rb_hash_new();
aliases[1] = rb_ary_new();
st_foreach(enc_table.names, rb_enc_aliases_enc_i, (st_data_t)aliases);
return aliases[0];
+#endif
}
+VALUE
+rb_enc_name2(rb_encoding *enc)
+{
+ CFStringRef str;
+ if (enc != NULL
+ && (str = CFStringConvertEncodingToIANACharSetName(*enc)) != NULL)
+ return (VALUE)str;
+ return Qnil;
+}
+
+const char *
+rb_enc_name(rb_encoding *enc)
+{
+ VALUE str = rb_enc_name2(enc);
+ return str == Qnil ? NULL : RSTRING_CPTR(str);
+}
+
+long
+rb_enc_mbminlen(rb_encoding *enc)
+{
+ return rb_enc_mbmaxlen(enc);
+}
+
+long
+rb_enc_mbmaxlen(rb_encoding *enc)
+{
+ return enc == NULL
+ ? 1 : CFStringGetMaximumSizeForEncoding(1, *enc);
+}
+
+rb_encoding *
+rb_enc_find(const char *name)
+{
+ return rb_enc_find2(rb_str_new2(name));
+}
+
+rb_encoding *
+rb_enc_find2(VALUE name)
+{
+ VALUE e = enc_find2(name);
+ return e == Qnil ? NULL : rb_enc_to_enc_ptr(e);
+}
+
+rb_encoding *
+rb_enc_get(VALUE obj)
+{
+ int type = TYPE(obj);
+ if (type == T_STRING) {
+ CFStringEncoding enc = CFStringGetFastestEncoding((CFStringRef)obj);
+ if (enc == kCFStringEncodingInvalidId)
+ return NULL;
+ return rb_enc_to_enc_ptr(enc_make(&enc));
+ }
+ else {
+ /* TODO */
+ return NULL;
+ }
+}
+
+rb_encoding *
+rb_locale_encoding(void)
+{
+ CFStringEncoding enc = CFStringGetSystemEncoding();
+ return rb_enc_to_enc_ptr(enc_make(&enc));
+}
+
void
Init_Encoding(void)
{
Modified: MacRuby/branches/testing/enum.c
===================================================================
--- MacRuby/branches/testing/enum.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/enum.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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,14 +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");
}
- memo = rb_node_newnode(NODE_MEMO, v, i, 0);
+#endif
+ memo = rb_node_newnode(NODE_MEMO, rb_yield(i), i, 0);
rb_ary_push(ary, (VALUE)memo);
return Qnil;
}
@@ -629,66 +679,73 @@
static int
sort_by_cmp(const void *ap, const void *bp, void *data)
{
+#if WITH_OBJC
+ VALUE a = ((NODE *)ap)->u1.value;
+ VALUE b = ((NODE *)bp)->u1.value;
+#else
VALUE a = (*(NODE *const *)ap)->u1.value;
VALUE b = (*(NODE *const *)bp)->u1.value;
+#endif
VALUE ary = (VALUE)data;
+#if !WITH_OBJC
if (RBASIC(ary)->klass) {
rb_raise(rb_eRuntimeError, "sort_by reentered");
}
+#endif
return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
}
/*
* 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
@@ -696,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"]
*/
@@ -722,57 +779,74 @@
else {
ary = rb_ary_new();
}
+#if !WITH_OBJC
RBASIC(ary)->klass = 0;
+#endif
rb_block_call(obj, id_each, 0, 0, sort_by_i, ary);
if (RARRAY_LEN(ary) > 1) {
+#if WITH_OBJC
+ CFArraySortValues((CFMutableArrayRef)ary,
+ CFRangeMake(0, RARRAY_LEN(ary)),
+ (CFComparatorFunction)sort_by_cmp, (void *)ary);
+#else
ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary), sizeof(VALUE),
sort_by_cmp, (void *)ary);
+#endif
}
+#if !WITH_OBJC
if (RBASIC(ary)->klass) {
rb_raise(rb_eRuntimeError, "sort_by reentered");
}
+#endif
for (i=0; i<RARRAY_LEN(ary); i++) {
- RARRAY_PTR(ary)[i] = RNODE(RARRAY_PTR(ary)[i])->u2.value;
+ rb_ary_store(ary, i, RNODE(RARRAY_AT(ary, i))->u2.value);
}
+#if !WITH_OBJC
RBASIC(ary)->klass = rb_cArray;
+#endif
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
@@ -785,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
@@ -815,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
@@ -832,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;
}
@@ -846,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
@@ -881,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
@@ -921,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;
}
@@ -938,17 +998,19 @@
}
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;
}
else {
VALUE ary = memo[1];
- RARRAY_PTR(ary)[0] = i;
- RARRAY_PTR(ary)[1] = *memo;
+ rb_ary_store(ary, 0, i);
+ rb_ary_store(ary, 1, *memo);
cmp = rb_yield(ary);
if (rb_cmpint(cmp, i, *memo) < 0) {
*memo = i;
@@ -962,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"
@@ -990,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;
}
@@ -1007,17 +1071,19 @@
}
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;
}
else {
VALUE ary = memo[1];
- RARRAY_PTR(ary)[0] = i;
- RARRAY_PTR(ary)[1] = *memo;
+ rb_ary_store(ary, 0, i);
+ rb_ary_store(ary, 1, *memo);
cmp = rb_yield(ary);
if (rb_cmpint(cmp, i, *memo) > 0) {
*memo = i;
@@ -1030,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)
@@ -1058,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;
@@ -1080,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;
@@ -1091,14 +1161,14 @@
else {
VALUE ary = memo[2];
- RARRAY_PTR(ary)[0] = i;
- RARRAY_PTR(ary)[1] = memo[0];
+ rb_ary_store(ary, 0, i);
+ rb_ary_store(ary, 1, memo[0]);
n = rb_cmpint(rb_yield(ary), i, memo[0]);
if (n < 0) {
memo[0] = i;
}
- RARRAY_PTR(ary)[0] = i;
- RARRAY_PTR(ary)[1] = memo[1];
+ rb_ary_store(ary, 0, i);
+ rb_ary_store(ary, 1, memo[1]);
n = rb_cmpint(rb_yield(ary), i, memo[1]);
if (n > 0) {
memo[1] = i;
@@ -1111,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)
@@ -1137,8 +1207,8 @@
rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)result);
}
if (result[0] != Qundef) {
- RARRAY_PTR(ary)[0] = result[0];
- RARRAY_PTR(ary)[1] = result[1];
+ rb_ary_store(ary, 0, result[0]);
+ rb_ary_store(ary, 1, result[1]);
}
return ary;
}
@@ -1148,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;
@@ -1163,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"
*/
@@ -1189,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;
@@ -1204,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"
*/
@@ -1224,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;
@@ -1253,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"]
*/
@@ -1278,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();
}
@@ -1291,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
@@ -1322,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
@@ -1348,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);
@@ -1370,16 +1477,16 @@
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++) {
- if (NIL_P(RARRAY_PTR(args)[i])) {
+ if (NIL_P(RARRAY_AT(args, i))) {
rb_ary_push(tmp, Qnil);
}
else {
VALUE v[2];
- v[1] = RARRAY_PTR(args)[i];
+ v[1] = RARRAY_AT(args, i);
rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, 0);
if (v[0] == Qundef) {
- RARRAY_PTR(args)[i] = Qnil;
+ rb_ary_store(args, i, Qnil);
v[0] = Qnil;
}
rb_ary_push(tmp, v[0]);
@@ -1398,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
@@ -1407,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
@@ -1424,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];
}
@@ -1473,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
@@ -1501,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]--;
@@ -1515,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];
}
@@ -1539,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]) {
@@ -1551,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
@@ -1576,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_PTR(ary)[i]);
- }
+ while (n < 0 || 0 < --n) {
+ for (i=0; i<len; i++) {
+ rb_yield(RARRAY_AT(ary, i));
+ }
}
return Qnil; /* not reached */
}
@@ -1637,10 +1782,17 @@
rb_define_method(rb_mEnumerable,"sort", enum_sort, 0);
rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0);
rb_define_method(rb_mEnumerable,"grep", enum_grep, 1);
+#if WITH_OBJC
+ /* FIXME we cannot define count because it overlaps with
+ * NSArray#count, NSDictionary#count, etc...
+ */
+ rb_define_method(rb_mEnumerable,"_count", enum_count, -1);
+#else
rb_define_method(rb_mEnumerable,"count", enum_count, -1);
+#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);
@@ -1658,8 +1810,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);
@@ -1669,7 +1821,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/branches/testing/enumerator.c
===================================================================
--- MacRuby/branches/testing/enumerator.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/enumerator.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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,15 +220,10 @@
{
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;
- }
- if (argc) ptr->args = rb_ary_new4(argc, argv);
+ 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;
ptr->no_next = Qfalse;
@@ -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
@@ -320,7 +298,7 @@
{
struct enumerator *e;
int argc = 0;
- VALUE *argv = 0;
+ const VALUE *argv = 0;
if (!rb_block_given_p()) return obj;
e = enumerator_ptr(obj);
@@ -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
@@ -353,14 +332,14 @@
struct enumerator *e = enumerator_ptr(obj);
VALUE memo = 0;
int argc = 0;
- VALUE *argv = 0;
+ const VALUE *argv = 0;
RETURN_ENUMERATOR(obj, 0, 0);
if (e->args) {
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/branches/testing/error.c
===================================================================
--- MacRuby/branches/testing/error.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/error.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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;
@@ -290,7 +293,7 @@
etype = "Symbol";
}
else if (rb_special_const_p(x)) {
- etype = RSTRING_PTR(rb_obj_as_string(x));
+ etype = RSTRING_CPTR(rb_obj_as_string(x));
}
else {
etype = rb_obj_classname(x);
@@ -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)
@@ -447,7 +450,7 @@
klass = CLASS_OF(exc);
exc = rb_obj_as_string(exc);
- if (RSTRING_LEN(exc) == 0) {
+ if (RSTRING_CLEN(exc) == 0) {
return rb_str_dup(rb_class_name(klass));
}
@@ -513,7 +516,7 @@
rb_raise(rb_eTypeError, err);
}
for (i=0;i<RARRAY_LEN(bt);i++) {
- if (TYPE(RARRAY_PTR(bt)[i]) != T_STRING) {
+ if (TYPE(RARRAY_AT(bt, i)) != T_STRING) {
rb_raise(rb_eTypeError, err);
}
}
@@ -768,10 +771,10 @@
break;
default:
d = rb_protect(rb_inspect, obj, 0);
- if (NIL_P(d) || RSTRING_LEN(d) > 65) {
+ if (NIL_P(d) || RSTRING_CLEN(d) > 65) {
d = rb_any_to_s(obj);
}
- desc = RSTRING_PTR(d);
+ desc = RSTRING_CPTR(d);
break;
}
if (desc && desc[0] != '#') {
@@ -814,7 +817,7 @@
{
VALUE s = rb_str_inspect(rb_str_new2(str));
- rb_raise(rb_eArgError, "invalid value for %s: %s", type, RSTRING_PTR(s));
+ rb_raise(rb_eArgError, "invalid value for %s: %s", type, RSTRING_CPTR(s));
}
/*
@@ -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;
@@ -925,7 +928,7 @@
StringValue(str);
mesg = rb_sprintf("%s - %.*s", err,
- (int)RSTRING_LEN(str), RSTRING_PTR(str));
+ (int)RSTRING_CLEN(str), RSTRING_CPTR(str));
}
else {
mesg = rb_str_new2(err);
@@ -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/branches/testing/eval.c
===================================================================
--- MacRuby/branches/testing/eval.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/eval.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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));
}
}
@@ -697,12 +700,12 @@
if (file) {
warn_printf("Exception `%s' at %s:%d - %s\n",
rb_obj_classname(th->errinfo),
- file, line, RSTRING_PTR(e));
+ file, line, RSTRING_CPTR(e));
}
else {
warn_printf("Exception `%s' - %s\n",
rb_obj_classname(th->errinfo),
- RSTRING_PTR(e));
+ RSTRING_CPTR(e));
}
}
POP_TAG();
@@ -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);
}
}
@@ -1376,19 +1373,22 @@
ID id = mid;
struct cache_entry *ent;
rb_thread_t *th = GET_THREAD();
+#if WITH_OBJC
+ unsigned redo = 0;
+#endif
rb_call0_redo:
#if WITH_OBJC
# define REDO_PERHAPS() \
- do { \
+ if (!redo) { \
ID newid = rb_objc_missing_sel(mid, argc); \
if (newid != mid) { \
id = mid = newid; \
+ redo = 1; \
goto rb_call0_redo; \
} \
- } \
- while (0)
+ }
#else
# define REDO_PERHAPS()
#endif
@@ -1442,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);
}
@@ -1481,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
@@ -1493,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
@@ -1573,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
@@ -1647,7 +1648,7 @@
ary = backtrace(-1);
for (i = 0; i < RARRAY_LEN(ary); i++) {
- printf("\tfrom %s\n", RSTRING_PTR(RARRAY_PTR(ary)[i]));
+ printf("\tfrom %s\n", RSTRING_CPTR(RARRAY_AT(ary, i)));
}
}
@@ -1760,7 +1761,7 @@
if (0) { /* for debug */
extern VALUE ruby_iseq_disasm(VALUE);
- printf("%s\n", RSTRING_PTR(ruby_iseq_disasm(iseqval)));
+ printf("%s\n", RSTRING_CPTR(ruby_iseq_disasm(iseqval)));
}
/* save new env */
@@ -1795,11 +1796,11 @@
mesg = rb_attr_get(errinfo, rb_intern("mesg"));
if (!NIL_P(errat) && TYPE(errat) == T_ARRAY &&
(bt2 = backtrace(-2), RARRAY_LEN(bt2) > 0)) {
- if (!NIL_P(mesg) && TYPE(mesg) == T_STRING && !RSTRING_LEN(mesg)) {
+ if (!NIL_P(mesg) && TYPE(mesg) == T_STRING && !RSTRING_CLEN(mesg)) {
rb_str_update(mesg, 0, 0, rb_str_new2(": "));
- rb_str_update(mesg, 0, 0, RARRAY_PTR(errat)[0]);
+ rb_str_update(mesg, 0, 0, RARRAY_AT(errat, 0));
}
- RARRAY_PTR(errat)[0] = RARRAY_PTR(bt2)[0];
+ rb_ary_store(errat, 0, RARRAY_AT(bt2, 0));
}
}
rb_exc_raise(errinfo);
@@ -1832,7 +1833,7 @@
rb_f_eval(int argc, VALUE *argv, VALUE self)
{
VALUE src, scope, vfile, vline;
- char *file = "(eval)";
+ const char *file = "(eval)";
int line = 1;
rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline);
@@ -1854,7 +1855,7 @@
}
if (!NIL_P(vfile))
- file = RSTRING_PTR(vfile);
+ file = RSTRING_CPTR(vfile);
return eval(self, src, scope, file, line);
}
@@ -2007,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
*/
@@ -2022,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);
@@ -2039,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
*/
@@ -2200,7 +2201,7 @@
* def c() end
* private :a
* end
- * Mod.private_instance_methods #=> ["a", "c"]
+ * Mod.private_instance_methods #=> [:a, :c]
*/
static VALUE
@@ -2655,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/branches/testing/eval_error.c
===================================================================
--- MacRuby/branches/testing/eval_error.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/eval_error.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -10,7 +10,7 @@
rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);
if (cfp) {
- return RSTRING_PTR(cfp->iseq->filename);
+ return RSTRING_CPTR(cfp->iseq->filename);
}
else {
return 0;
@@ -91,7 +91,7 @@
VALUE errat = Qnil; /* OK */
VALUE errinfo = GET_THREAD()->errinfo;
volatile VALUE eclass, e;
- char *einfo;
+ const char *einfo;
long elen;
if (NIL_P(errinfo))
@@ -118,12 +118,12 @@
error_pos();
}
else {
- VALUE mesg = RARRAY_PTR(errat)[0];
+ VALUE mesg = RARRAY_AT(errat, 0);
if (NIL_P(mesg))
error_pos();
else {
- warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg));
+ warn_print2(RSTRING_CPTR(mesg), RSTRING_CLEN(mesg));
}
}
@@ -131,8 +131,8 @@
if (EXEC_TAG() == 0) {
e = rb_funcall(errinfo, rb_intern("message"), 0, 0);
StringValue(e);
- einfo = RSTRING_PTR(e);
- elen = RSTRING_LEN(e);
+ einfo = RSTRING_CPTR(e);
+ elen = RSTRING_CLEN(e);
}
else {
einfo = "";
@@ -149,14 +149,14 @@
epath = rb_class_name(eclass);
if (elen == 0) {
warn_print(": ");
- warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
+ warn_print2(RSTRING_CPTR(epath), RSTRING_CLEN(epath));
warn_print("\n");
}
else {
char *tail = 0;
long len = elen;
- if (RSTRING_PTR(epath)[0] == '#')
+ if (RSTRING_CPTR(epath)[0] == '#')
epath = 0;
if ((tail = memchr(einfo, '\n', elen)) != 0) {
len = tail - einfo;
@@ -166,7 +166,7 @@
warn_print2(einfo, len);
if (epath) {
warn_print(" (");
- warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
+ warn_print2(RSTRING_CPTR(epath), RSTRING_CLEN(epath));
warn_print(")\n");
}
if (tail) {
@@ -179,7 +179,6 @@
if (!NIL_P(errat)) {
long i;
long len = RARRAY_LEN(errat);
- VALUE *ptr = RARRAY_PTR(errat);
int skip = eclass == rb_eSysStackError;
#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
@@ -187,8 +186,9 @@
#define TRACE_TAIL 5
for (i = 1; i < len; i++) {
- if (TYPE(ptr[i]) == T_STRING) {
- warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i]));
+ VALUE v = RARRAY_AT(errat, i);
+ if (TYPE(v) == T_STRING) {
+ warn_printf("\tfrom %s\n", RSTRING_CPTR(v));
}
if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
warn_printf("\t ... %ld levels...\n",
Modified: MacRuby/branches/testing/eval_intern.h
===================================================================
--- MacRuby/branches/testing/eval_intern.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/eval_intern.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/eval_jump.c
===================================================================
--- MacRuby/branches/testing/eval_jump.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/eval_jump.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -36,7 +36,7 @@
}
if (!tt) {
VALUE desc = rb_inspect(tag);
- rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_PTR(desc));
+ rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_CPTR(desc));
}
rb_trap_restore_mask();
th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);
@@ -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/branches/testing/eval_method.c
===================================================================
--- MacRuby/branches/testing/eval_method.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/eval_method.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/dbm/dbm.c
===================================================================
--- MacRuby/branches/testing/ext/dbm/dbm.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/dbm/dbm.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -345,7 +345,7 @@
}
for (i = 0; i < RARRAY_LEN(ary); i++) {
- keystr = RARRAY_PTR(ary)[i];
+ keystr = RARRAY_AT(ary, i);
StringValue(keystr);
key.dptr = RSTRING_PTR(keystr);
key.dsize = RSTRING_LEN(keystr);
@@ -407,7 +407,7 @@
if (RARRAY_LEN(pair) < 2) {
rb_raise(rb_eArgError, "pair must be [key, value]");
}
- fdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
+ fdbm_store(dbm, RARRAY_AT(pair, 0), RARRAY_AT(pair, 1));
return Qnil;
}
@@ -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/branches/testing/ext/digest/defs.h
===================================================================
--- MacRuby/branches/testing/ext/digest/defs.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/digest/defs.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/dl/cfunc.c
===================================================================
--- MacRuby/branches/testing/ext/dl/cfunc.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/dl/cfunc.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -260,7 +260,7 @@
if( i >= DLSTACK_SIZE ){
rb_raise(rb_eDLError, "too many arguments (stack overflow)");
}
- stack[i] = NUM2LONG(RARRAY_PTR(ary)[i]);
+ stack[i] = NUM2LONG(RARRAY_AT(ary, i));
}
/* calltype == CFUNC_CDECL */
Modified: MacRuby/branches/testing/ext/dl/win32/lib/win32/registry.rb
===================================================================
--- MacRuby/branches/testing/ext/dl/win32/lib/win32/registry.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/dl/win32/lib/win32/registry.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/dl/win32/lib/win32/resolv.rb
===================================================================
--- MacRuby/branches/testing/ext/dl/win32/lib/win32/resolv.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/dl/win32/lib/win32/resolv.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/extmk.rb
===================================================================
--- MacRuby/branches/testing/ext/extmk.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/extmk.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -84,6 +85,7 @@
end
def extmake(target)
+GC.start
print "#{$message} #{target}\n"
$stdout.flush
if $force_static or $static_ext[target]
@@ -287,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)
@@ -337,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)}
@@ -398,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)
@@ -425,6 +431,8 @@
FileUtils::makedirs('ext')
Dir::chdir('ext')
+GC.start
+
hdrdir = $hdrdir
$hdrdir = ($top_srcdir = relative_from(srcdir, $topdir = "..")) + "/include"
exts.each do |d|
@@ -550,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/branches/testing/ext/gdbm/gdbm.c
===================================================================
--- MacRuby/branches/testing/ext/gdbm/gdbm.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/gdbm/gdbm.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/iconv/iconv.c
===================================================================
--- MacRuby/branches/testing/ext/iconv/iconv.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/iconv/iconv.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -144,9 +144,9 @@
if (RHASH_SIZE(charset_map)) {
VALUE key = rb_funcall2(val, rb_intern("downcase"), 0, 0);
StringValuePtr(key);
- if (st_lookup(RHASH_TBL(charset_map), key, &val)) {
+ val = rb_hash_aref(charset_map, key);
+ if (val != Qnil)
*code = val;
- }
}
return StringValuePtr(*code);
}
@@ -353,7 +353,7 @@
unsigned int i;
rescue = iconv_fail(error, Qnil, Qnil, env, 0);
if (TYPE(rescue) == T_ARRAY) {
- str = RARRAY_LEN(rescue) > 0 ? RARRAY_PTR(rescue)[0] : Qnil;
+ str = RARRAY_LEN(rescue) > 0 ? RARRAY_AT(rescue, 0) : Qnil;
}
if (FIXNUM_P(str) && (i = FIX2INT(str)) <= 0xff) {
char c = i;
@@ -446,8 +446,8 @@
rescue = iconv_fail(error, ret, str, env, errmsg);
if (TYPE(rescue) == T_ARRAY) {
if ((len = RARRAY_LEN(rescue)) > 0)
- rb_str_concat(ret, RARRAY_PTR(rescue)[0]);
- if (len > 1 && !NIL_P(str = RARRAY_PTR(rescue)[1])) {
+ rb_str_concat(ret, RARRAY_AT(rescue, 0));
+ if (len > 1 && !NIL_P(str = RARRAY_AT(rescue, 1))) {
StringValue(str);
inlen = length = RSTRING_LEN(str);
instart = inptr = RSTRING_PTR(str);
@@ -760,7 +760,7 @@
if (!rb_block_given_p())
return ary;
for (i = 0; i < RARRAY_LEN(ary); i++) {
- rb_yield(RARRAY_PTR(ary)[i]);
+ rb_yield(RARRAY_AT(ary, i));
}
#else
rb_notimplement();
Modified: MacRuby/branches/testing/ext/json/ext/generator/generator.c
===================================================================
--- MacRuby/branches/testing/ext/json/ext/generator/generator.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/json/ext/generator/generator.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -188,7 +188,7 @@
OBJ_INFECT(result, self);
rb_str_buf_append(result, state->array_nl);
for (i = 0; i < len; i++) {
- VALUE element = RARRAY_PTR(self)[i];
+ VALUE element = RARRAY_AT(self, i);
if (RTEST(rb_hash_aref(state->seen, rb_obj_id(element)))) {
rb_raise(eCircularDatastructure,
"circular data structures not supported!");
@@ -215,7 +215,7 @@
rb_str_buf_cat2(result, "[");
rb_str_buf_append(result, state->array_nl);
for (i = 0; i < len; i++) {
- VALUE element = RARRAY_PTR(self)[i];
+ VALUE element = RARRAY_AT(self, i);
OBJ_INFECT(result, element);
if (i > 0) rb_str_buf_append(result, delim);
rb_str_buf_append(result, shift);
@@ -251,7 +251,7 @@
rb_str_buf_cat2(result, "[");
OBJ_INFECT(result, self);
for (i = 0; i < len; i++) {
- VALUE element = RARRAY_PTR(self)[i];
+ VALUE element = RARRAY_AT(self, i);
OBJ_INFECT(result, element);
if (i > 0) rb_str_buf_cat2(result, ",");
element = rb_funcall(element, i_to_json, 0);
Modified: MacRuby/branches/testing/ext/nkf/nkf-utf8/nkf.c
===================================================================
--- MacRuby/branches/testing/ext/nkf/nkf-utf8/nkf.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/nkf/nkf-utf8/nkf.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/nkf/nkf.c
===================================================================
--- MacRuby/branches/testing/ext/nkf/nkf.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/nkf/nkf.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/lib/openssl/digest.rb
===================================================================
--- MacRuby/branches/testing/ext/openssl/lib/openssl/digest.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/lib/openssl/digest.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/openssl_missing.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/openssl_missing.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/openssl_missing.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/openssl_missing.h
===================================================================
--- MacRuby/branches/testing/ext/openssl/openssl_missing.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/openssl_missing.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_asn1.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_asn1.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_asn1.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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.
@@ -306,14 +306,14 @@
static VALUE
decode_bool(unsigned char* der, int length)
{
- int bool;
+ int flag;
unsigned char *p;
p = der;
- if((bool = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0)
+ if((flag = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0)
ossl_raise(eASN1Error, NULL);
- return bool ? Qtrue : Qfalse;
+ return flag ? Qtrue : Qfalse;
}
static VALUE
@@ -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/branches/testing/ext/openssl/ossl_config.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_config.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_config.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_digest.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_digest.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_digest.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_hmac.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_hmac.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_hmac.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_ocsp.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_ocsp.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_ocsp.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -462,7 +462,7 @@
/* All ary's members should be X509Extension */
Check_Type(ext, T_ARRAY);
for (i = 0; i < RARRAY_LEN(ext); i++)
- OSSL_Check_Kind(RARRAY_PTR(ext)[i], cX509Ext);
+ OSSL_Check_Kind(RARRAY_AT(ext, i), cX509Ext);
}
error = 0;
@@ -491,7 +491,7 @@
sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free);
single->singleExtensions = NULL;
for(i = 0; i < RARRAY_LEN(ext); i++){
- x509ext = DupX509ExtPtr(RARRAY_PTR(ext)[i]);
+ x509ext = DupX509ExtPtr(RARRAY_AT(ext, i));
if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
X509_EXTENSION_free(x509ext);
error = 1;
Modified: MacRuby/branches/testing/ext/openssl/ossl_pkey_dh.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_pkey_dh.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_pkey_dh.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_pkey_dsa.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_pkey_dsa.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_pkey_dsa.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_pkey_ec.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_pkey_ec.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_pkey_ec.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -1576,10 +1576,7 @@
}
#else /* defined NO_EC */
-# warning >>> OpenSSL is compiled without EC support <<<
-
void Init_ossl_ec()
{
}
-
#endif /* NO_EC */
Modified: MacRuby/branches/testing/ext/openssl/ossl_pkey_rsa.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_pkey_rsa.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_pkey_rsa.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_ssl.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_ssl.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_ssl.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
{
@@ -511,7 +519,7 @@
if(!NIL_P(val)){
if(TYPE(val) == T_ARRAY){
for(i = 0; i < RARRAY_LEN(val); i++){
- client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]);
+ client_ca = GetX509CertPtr(RARRAY_AT(val, i));
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
/* Copies X509_NAME => FREE it. */
ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
@@ -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/branches/testing/ext/openssl/ossl_ssl_session.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_ssl_session.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_ssl_session.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_version.h
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_version.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_version.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_x509cert.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_x509cert.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_x509cert.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -647,13 +647,13 @@
Check_Type(ary, T_ARRAY);
/* All ary's members should be X509Extension */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
+ OSSL_Check_Kind(RARRAY_AT(ary, i), cX509Ext);
}
GetX509(self, x509);
sk_X509_EXTENSION_pop_free(x509->cert_info->extensions, X509_EXTENSION_free);
x509->cert_info->extensions = NULL;
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
+ ext = DupX509ExtPtr(RARRAY_AT(ary, i));
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
X509_EXTENSION_free(ext);
Modified: MacRuby/branches/testing/ext/openssl/ossl_x509crl.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_x509crl.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_x509crl.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -288,13 +288,13 @@
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Revoked */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Rev);
+ OSSL_Check_Kind(RARRAY_AT(ary, i), cX509Rev);
}
GetX509CRL(self, crl);
sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free);
crl->crl->revoked = NULL;
for (i=0; i<RARRAY_LEN(ary); i++) {
- rev = DupX509RevokedPtr(RARRAY_PTR(ary)[i]);
+ rev = DupX509RevokedPtr(RARRAY_AT(ary, i));
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
ossl_raise(eX509CRLError, NULL);
}
@@ -462,13 +462,13 @@
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Extensions */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
+ OSSL_Check_Kind(RARRAY_AT(ary, i), cX509Ext);
}
GetX509CRL(self, crl);
sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free);
crl->crl->extensions = NULL;
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
+ ext = DupX509ExtPtr(RARRAY_AT(ary, i));
if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
X509_EXTENSION_free(ext);
ossl_raise(eX509CRLError, NULL);
Modified: MacRuby/branches/testing/ext/openssl/ossl_x509ext.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_x509ext.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_x509ext.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/openssl/ossl_x509name.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_x509name.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_x509name.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -355,7 +355,11 @@
ia5str = INT2NUM(V_ASN1_IA5STRING);
rb_define_const(cX509Name, "DEFAULT_OBJECT_TYPE", utf8str);
hash = rb_hash_new();
+#if WITH_OBJC
+ rb_funcall(hash, rb_intern("default="), 1, utf8str);
+#else
RHASH(hash)->ifnone = utf8str;
+#endif
rb_hash_aset(hash, rb_str_new2("C"), ptrstr);
rb_hash_aset(hash, rb_str_new2("countryName"), ptrstr);
rb_hash_aset(hash, rb_str_new2("serialNumber"), ptrstr);
Modified: MacRuby/branches/testing/ext/openssl/ossl_x509req.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_x509req.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_x509req.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -404,13 +404,13 @@
Check_Type(ary, T_ARRAY);
for (i=0;i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Attr);
+ OSSL_Check_Kind(RARRAY_AT(ary, i), cX509Attr);
}
GetX509Req(self, req);
sk_X509_ATTRIBUTE_pop_free(req->req_info->attributes, X509_ATTRIBUTE_free);
req->req_info->attributes = NULL;
for (i=0;i<RARRAY_LEN(ary); i++) {
- item = RARRAY_PTR(ary)[i];
+ item = RARRAY_AT(ary, i);
attr = DupX509AttrPtr(item);
if (!X509_REQ_add1_attr(req, attr)) {
ossl_raise(eX509ReqError, NULL);
Modified: MacRuby/branches/testing/ext/openssl/ossl_x509revoked.c
===================================================================
--- MacRuby/branches/testing/ext/openssl/ossl_x509revoked.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/openssl/ossl_x509revoked.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -176,13 +176,13 @@
Check_Type(ary, T_ARRAY);
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
+ OSSL_Check_Kind(RARRAY_AT(ary, i), cX509Ext);
}
GetX509Rev(self, rev);
sk_X509_EXTENSION_pop_free(rev->extensions, X509_EXTENSION_free);
rev->extensions = NULL;
for (i=0; i<RARRAY_LEN(ary); i++) {
- item = RARRAY_PTR(ary)[i];
+ item = RARRAY_AT(ary, i);
ext = DupX509ExtPtr(item);
if(!X509_REVOKED_add_ext(rev, ext, -1)) {
ossl_raise(eX509RevError, NULL);
Modified: MacRuby/branches/testing/ext/purelib.rb
===================================================================
--- MacRuby/branches/testing/ext/purelib.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/purelib.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,3 +1,3 @@
-if nul = $:.index("-")
+if nul = $:.find_index {|path| /\A(?:\.\/)*-\z/ =~ path}
$:[nul..-1] = ["."]
end
Modified: MacRuby/branches/testing/ext/racc/cparse/cparse.c
===================================================================
--- MacRuby/branches/testing/ext/racc/cparse/cparse.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/racc/cparse/cparse.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -84,7 +84,7 @@
}
#define AREF(s, idx) \
- ((0 <= idx && idx < RARRAY_LEN(s)) ? RARRAY_PTR(s)[idx] : Qnil)
+ ((0 <= idx && idx < RARRAY_LEN(s)) ? RARRAY_AT(s, idx) : Qnil)
/* -----------------------------------------------------------------------
Parser Stack Interfaces
@@ -98,7 +98,7 @@
{
if (len < 0) return Qnil; /* system error */
if (len > RARRAY_LEN(stack)) len = RARRAY_LEN(stack);
- return rb_ary_new4(len, RARRAY_PTR(stack) + RARRAY_LEN(stack) - len);
+ return rb_ary_new4(len, RARRAY_AT(stack, RARRAY_LEN(stack) - len));
}
static void
@@ -115,7 +115,7 @@
#define PUSH(s, i) rb_ary_store(s, RARRAY_LEN(s), i)
#define POP(s) rb_ary_pop(s)
#define LAST_I(s) \
- ((RARRAY_LEN(s) > 0) ? RARRAY_PTR(s)[RARRAY_LEN(s) - 1] : Qnil)
+ ((RARRAY_LEN(s) > 0) ? RARRAY_AT(s, RARRAY_LEN(s) - 1) : Qnil)
#define GET_TAIL(s, len) get_stack_tail(s, len)
#define CUT_TAIL(s, len) cut_stack_tail(s, len)
@@ -327,21 +327,21 @@
Check_Type(arg, T_ARRAY);
if (!(13 <= RARRAY_LEN(arg) && RARRAY_LEN(arg) <= 14))
rb_raise(RaccBug, "[Racc Bug] wrong arg.size %ld", RARRAY_LEN(arg));
- v->action_table = assert_array (RARRAY_PTR(arg)[ 0]);
- v->action_check = assert_array (RARRAY_PTR(arg)[ 1]);
- v->action_default = assert_array (RARRAY_PTR(arg)[ 2]);
- v->action_pointer = assert_array (RARRAY_PTR(arg)[ 3]);
- v->goto_table = assert_array (RARRAY_PTR(arg)[ 4]);
- v->goto_check = assert_array (RARRAY_PTR(arg)[ 5]);
- v->goto_default = assert_array (RARRAY_PTR(arg)[ 6]);
- v->goto_pointer = assert_array (RARRAY_PTR(arg)[ 7]);
- v->nt_base = assert_integer(RARRAY_PTR(arg)[ 8]);
- v->reduce_table = assert_array (RARRAY_PTR(arg)[ 9]);
- v->token_table = assert_hash (RARRAY_PTR(arg)[10]);
- v->shift_n = assert_integer(RARRAY_PTR(arg)[11]);
- v->reduce_n = assert_integer(RARRAY_PTR(arg)[12]);
+ v->action_table = assert_array (RARRAY_AT(arg, 0));
+ v->action_check = assert_array (RARRAY_AT(arg, 1));
+ v->action_default = assert_array (RARRAY_AT(arg, 2));
+ v->action_pointer = assert_array (RARRAY_AT(arg, 3));
+ v->goto_table = assert_array (RARRAY_AT(arg, 4));
+ v->goto_check = assert_array (RARRAY_AT(arg, 5));
+ v->goto_default = assert_array (RARRAY_AT(arg, 6));
+ v->goto_pointer = assert_array (RARRAY_AT(arg, 7));
+ v->nt_base = assert_integer(RARRAY_AT(arg, 8));
+ v->reduce_table = assert_array (RARRAY_AT(arg, 9));
+ v->token_table = assert_hash (RARRAY_AT(arg,10));
+ v->shift_n = assert_integer(RARRAY_AT(arg,11));
+ v->reduce_n = assert_integer(RARRAY_AT(arg,12));
if (RARRAY_LEN(arg) > 13) {
- v->use_result_var = RTEST(RARRAY_PTR(arg)[13]);
+ v->use_result_var = RTEST(RARRAY_AT(arg, 13));
}
else {
v->use_result_var = Qtrue;
@@ -557,7 +557,7 @@
accept:
if (v->debug) rb_funcall(v->parser, id_d_accept, 0);
- v->retval = RARRAY_PTR(v->vstack)[0];
+ v->retval = RARRAY_AT(v->vstack, 0);
v->fin = CP_FIN_ACCEPT;
return;
@@ -686,9 +686,9 @@
VALUE goto_state;
Data_Get_Struct(data, struct cparse_params, v);
- reduce_len = RARRAY_PTR(v->reduce_table)[v->ruleno];
- reduce_to = RARRAY_PTR(v->reduce_table)[v->ruleno+1];
- method_id = RARRAY_PTR(v->reduce_table)[v->ruleno+2];
+ reduce_len = RARRAY_AT(v->reduce_table, v->ruleno);
+ reduce_to = RARRAY_AT(v->reduce_table, v->ruleno+1);
+ method_id = RARRAY_AT(v->reduce_table, v->ruleno+2);
len = NUM2LONG(reduce_len);
mid = value_to_id(method_id);
@@ -703,10 +703,10 @@
else {
if (mid != id_noreduce) {
tmp_v = GET_TAIL(v->vstack, len);
- tmp = RARRAY_PTR(tmp_v)[0];
+ tmp = RARRAY_AT(tmp_v, 0);
}
else {
- tmp = RARRAY_PTR(v->vstack)[ RARRAY_LEN(v->vstack) - len ];
+ tmp = RARRAY_AT(v->vstack, RARRAY_LEN(v->vstack) - len);
}
CUT_TAIL(v->vstack, len);
if (v->debug) {
Modified: MacRuby/branches/testing/ext/readline/extconf.rb
===================================================================
--- MacRuby/branches/testing/ext/readline/extconf.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/readline/extconf.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/readline/readline.c
===================================================================
--- MacRuby/branches/testing/ext/readline/readline.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/readline/readline.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -27,6 +27,17 @@
#include <unistd.h>
#endif
+#if WITH_OBJC
+/* We cannot use the GC memory functions here because the underlying libedit
+ * function will call free() on the memory, resulting in a leak.
+ */
+# undef ALLOC_N
+# define ALLOC_N(type,n) ((type *)malloc(sizeof(type) * (n)))
+# undef REALLOC_N
+# define REALLOC_N(var,type,n) \
+ (var)=(type*)realloc((char*)(var),(n) * sizeof(type))
+#endif
+
static VALUE mReadline;
#define COMPLETION_PROC "completion_proc"
@@ -43,29 +54,41 @@
# 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)
{
VALUE tmp, add_hist, result;
- char *prompt = NULL;
+ const char *prompt = NULL;
char *buff;
int status;
rb_secure(4);
if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) {
SafeStringValue(tmp);
- prompt = RSTRING_PTR(tmp);
+ prompt = RSTRING_CPTR(tmp);
}
if (!isatty(0) && errno == EBADF) rb_raise(rb_eIOError, "stdin closed");
@@ -92,7 +115,9 @@
}
if (buff) {
result = rb_tainted_str_new2(buff);
+#if !WITH_OBJC
rb_enc_associate(result, rb_locale_encoding());
+#endif
}
else
result = Qnil;
@@ -177,9 +202,9 @@
return NULL;
result = ALLOC_N(char *, matches + 2);
for (i = 0; i < matches; i++) {
- temp = rb_obj_as_string(RARRAY_PTR(ary)[i]);
- result[i + 1] = ALLOC_N(char, RSTRING_LEN(temp) + 1);
- strcpy(result[i + 1], RSTRING_PTR(temp));
+ temp = rb_obj_as_string(RARRAY_AT(ary, i));
+ result[i + 1] = ALLOC_N(char, RSTRING_CLEN(temp) + 1);
+ strcpy(result[i + 1], RSTRING_CPTR(temp));
}
result[matches + 1] = NULL;
@@ -254,10 +279,10 @@
}
else {
SafeStringValue(str);
- if (RSTRING_LEN(str) == 0) {
+ if (RSTRING_CLEN(str) == 0) {
rl_completion_append_character = '\0';
} else {
- rl_completion_append_character = RSTRING_PTR(str)[0];
+ rl_completion_append_character = RSTRING_CPTR(str)[0];
}
}
return self;
@@ -277,8 +302,7 @@
if (rl_completion_append_character == '\0')
return Qnil;
- str = rb_str_new("", 1);
- RSTRING_PTR(str)[0] = rl_completion_append_character;
+ str = rb_str_new((char *)&rl_completion_append_character, 1);
return str;
#else
rb_notimplement();
@@ -296,14 +320,14 @@
SafeStringValue(str);
if (basic_word_break_characters == NULL) {
basic_word_break_characters =
- ALLOC_N(char, RSTRING_LEN(str) + 1);
+ ALLOC_N(char, RSTRING_CLEN(str) + 1);
}
else {
- REALLOC_N(basic_word_break_characters, char, RSTRING_LEN(str) + 1);
+ REALLOC_N(basic_word_break_characters, char, RSTRING_CLEN(str) + 1);
}
strncpy(basic_word_break_characters,
- RSTRING_PTR(str), RSTRING_LEN(str));
- basic_word_break_characters[RSTRING_LEN(str)] = '\0';
+ RSTRING_CPTR(str), RSTRING_CLEN(str));
+ basic_word_break_characters[RSTRING_CLEN(str)] = '\0';
rl_basic_word_break_characters = basic_word_break_characters;
return self;
#else
@@ -336,14 +360,14 @@
SafeStringValue(str);
if (completer_word_break_characters == NULL) {
completer_word_break_characters =
- ALLOC_N(char, RSTRING_LEN(str) + 1);
+ ALLOC_N(char, RSTRING_CLEN(str) + 1);
}
else {
- REALLOC_N(completer_word_break_characters, char, RSTRING_LEN(str) + 1);
+ REALLOC_N(completer_word_break_characters, char, RSTRING_CLEN(str) + 1);
}
strncpy(completer_word_break_characters,
- RSTRING_PTR(str), RSTRING_LEN(str));
- completer_word_break_characters[RSTRING_LEN(str)] = '\0';
+ RSTRING_CPTR(str), RSTRING_CLEN(str));
+ completer_word_break_characters[RSTRING_CLEN(str)] = '\0';
rl_completer_word_break_characters = completer_word_break_characters;
return self;
#else
@@ -376,14 +400,14 @@
SafeStringValue(str);
if (basic_quote_characters == NULL) {
basic_quote_characters =
- ALLOC_N(char, RSTRING_LEN(str) + 1);
+ ALLOC_N(char, RSTRING_CLEN(str) + 1);
}
else {
- REALLOC_N(basic_quote_characters, char, RSTRING_LEN(str) + 1);
+ REALLOC_N(basic_quote_characters, char, RSTRING_CLEN(str) + 1);
}
strncpy(basic_quote_characters,
- RSTRING_PTR(str), RSTRING_LEN(str));
- basic_quote_characters[RSTRING_LEN(str)] = '\0';
+ RSTRING_CPTR(str), RSTRING_CLEN(str));
+ basic_quote_characters[RSTRING_CLEN(str)] = '\0';
rl_basic_quote_characters = basic_quote_characters;
return self;
@@ -417,13 +441,13 @@
SafeStringValue(str);
if (completer_quote_characters == NULL) {
completer_quote_characters =
- ALLOC_N(char, RSTRING_LEN(str) + 1);
+ ALLOC_N(char, RSTRING_CLEN(str) + 1);
}
else {
- REALLOC_N(completer_quote_characters, char, RSTRING_LEN(str) + 1);
+ REALLOC_N(completer_quote_characters, char, RSTRING_CLEN(str) + 1);
}
- strncpy(completer_quote_characters, RSTRING_PTR(str), RSTRING_LEN(str));
- completer_quote_characters[RSTRING_LEN(str)] = '\0';
+ strncpy(completer_quote_characters, RSTRING_CPTR(str), RSTRING_CLEN(str));
+ completer_quote_characters[RSTRING_CLEN(str)] = '\0';
rl_completer_quote_characters = completer_quote_characters;
return self;
@@ -457,13 +481,13 @@
SafeStringValue(str);
if (filename_quote_characters == NULL) {
filename_quote_characters =
- ALLOC_N(char, RSTRING_LEN(str) + 1);
+ ALLOC_N(char, RSTRING_CLEN(str) + 1);
}
else {
- REALLOC_N(filename_quote_characters, char, RSTRING_LEN(str) + 1);
+ REALLOC_N(filename_quote_characters, char, RSTRING_CLEN(str) + 1);
}
- strncpy(filename_quote_characters, RSTRING_PTR(str), RSTRING_LEN(str));
- filename_quote_characters[RSTRING_LEN(str)] = '\0';
+ strncpy(filename_quote_characters, RSTRING_CPTR(str), RSTRING_CLEN(str));
+ filename_quote_characters[RSTRING_CLEN(str)] = '\0';
rl_filename_quote_characters = filename_quote_characters;
return self;
@@ -524,7 +548,7 @@
if (i < 0) {
i += history_length;
}
- entry = replace_history_entry(i, RSTRING_PTR(str), NULL);
+ entry = replace_history_entry(i, RSTRING_CPTR(str), NULL);
if (entry == NULL) {
rb_raise(rb_eIndexError, "invalid index");
}
@@ -540,7 +564,7 @@
{
rb_secure(4);
SafeStringValue(str);
- add_history(RSTRING_PTR(str));
+ add_history(RSTRING_CPTR(str));
return self;
}
@@ -553,7 +577,7 @@
while (argc--) {
str = *argv++;
SafeStringValue(str);
- add_history(RSTRING_PTR(str));
+ add_history(RSTRING_CPTR(str));
}
return self;
}
@@ -569,7 +593,7 @@
entry = remove_history(index);
if (entry) {
val = rb_tainted_str_new2(entry->line);
- free(entry->line);
+ free((void *)entry->line);
free(entry);
return val;
}
@@ -608,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/branches/testing/ext/sdbm/init.c
===================================================================
--- MacRuby/branches/testing/ext/sdbm/init.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/sdbm/init.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -323,7 +323,7 @@
}
for (i = 0; i < RARRAY_LEN(ary); i++) {
- keystr = RARRAY_PTR(ary)[i];
+ keystr = RARRAY_AT(ary, i);
StringValue(keystr);
key.dptr = RSTRING_PTR(keystr);
key.dsize = RSTRING_LEN(keystr);
@@ -418,7 +418,7 @@
if (RARRAY_LEN(pair) < 2) {
rb_raise(rb_eArgError, "pair must be [key, value]");
}
- fsdbm_store(dbm, RARRAY_PTR(pair)[0], RARRAY_PTR(pair)[1]);
+ fsdbm_store(dbm, RARRAY_AT(pair, 0), RARRAY_AT(pair, 1));
return Qnil;
}
@@ -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/branches/testing/ext/socket/socket.c
===================================================================
--- MacRuby/branches/testing/ext/socket/socket.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/socket/socket.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -3054,7 +3054,7 @@
for (res = res0; res; res = res->ai_next) {
ary = ipaddr(res->ai_addr, do_not_reverse_lookup);
if (res->ai_canonname) {
- RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname);
+ rb_ary_store(ary, 2, rb_str_new2(res->ai_canonname));
}
rb_ary_push(ary, INT2FIX(res->ai_family));
rb_ary_push(ary, INT2FIX(res->ai_socktype));
@@ -3296,16 +3296,16 @@
sa = tmp;
MEMZERO(&hints, struct addrinfo, 1);
if (RARRAY_LEN(sa) == 3) {
- af = RARRAY_PTR(sa)[0];
- port = RARRAY_PTR(sa)[1];
- host = RARRAY_PTR(sa)[2];
+ af = RARRAY_AT(sa, 0);
+ port = RARRAY_AT(sa, 1);
+ host = RARRAY_AT(sa, 2);
}
else if (RARRAY_LEN(sa) >= 4) {
- af = RARRAY_PTR(sa)[0];
- port = RARRAY_PTR(sa)[1];
- host = RARRAY_PTR(sa)[3];
+ af = RARRAY_AT(sa, 0);
+ port = RARRAY_AT(sa, 1);
+ host = RARRAY_AT(sa, 3);
if (NIL_P(host)) {
- host = RARRAY_PTR(sa)[2];
+ host = RARRAY_AT(sa, 2);
}
else {
/*
Modified: MacRuby/branches/testing/ext/stringio/stringio.c
===================================================================
--- MacRuby/branches/testing/ext/stringio/stringio.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/stringio/stringio.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -191,7 +191,7 @@
ptr->flags = FMODE_READWRITE;
break;
}
- ptr->string = string;
+ GC_WB(&ptr->string, string);
}
static VALUE
@@ -307,7 +307,8 @@
ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
ptr->pos = 0;
ptr->lineno = 0;
- return ptr->string = string;
+ GC_WB(&ptr->string, string);
+ return string;
}
/*
@@ -614,6 +615,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));
@@ -639,7 +643,11 @@
return Qnil;
}
p = RSTRING_PTR(ptr->string)+ptr->pos;
+#if WITH_OBJC
+ len = 1;
+#else
len = rb_enc_mbclen(p, RSTRING_END(ptr->string), enc);
+#endif
ptr->pos += len;
return rb_enc_str_new(p, len, rb_enc_get(ptr->string));
}
@@ -700,11 +708,15 @@
if (NIL_P(c)) return Qnil;
if (FIXNUM_P(c)) {
int cc = FIX2INT(c);
+#if WITH_OBJC
+ c = rb_str_new((char *)&cc, 1);
+#else
char buf[16];
enc = rb_enc_get(ptr->string);
rb_enc_mbcput(cc, buf, enc);
c = rb_enc_str_new(buf, rb_enc_codelen(cc, enc), enc);
+#endif
}
else {
SafeStringValue(c);
@@ -713,7 +725,11 @@
/* get logical position */
lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos - 1;
for (;;) {
+#if WITH_OBJC
+ clen = 1;
+#else
clen = rb_enc_mbclen(p, pend, enc);
+#endif
if (p+clen >= pend) break;
p += clen;
lpos++;
@@ -926,6 +942,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);
}
@@ -1233,7 +1251,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/branches/testing/ext/strscan/strscan.c
===================================================================
--- MacRuby/branches/testing/ext/strscan/strscan.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/strscan/strscan.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -122,7 +122,9 @@
static VALUE
infect(VALUE str, struct strscanner *p)
{
+#if !WITH_OBJC
OBJ_INFECT(str, p->str);
+#endif
return str;
}
@@ -130,7 +132,9 @@
str_new(struct strscanner *p, const char *ptr, long len)
{
VALUE str = rb_str_new(ptr, len);
+#if !WITH_OBJC
rb_enc_copy(str, p->str);
+#endif
return str;
}
@@ -197,7 +201,7 @@
Data_Get_Struct(self, struct strscanner, p);
rb_scan_args(argc, argv, "11", &str, &need_dup);
StringValue(str);
- p->str = str;
+ GC_WB(&p->str, str);
return self;
}
@@ -229,7 +233,7 @@
Data_Get_Struct(vorig, struct strscanner, orig);
if (self != orig) {
self->flags = orig->flags;
- self->str = orig->str;
+ GC_WB(&self->str, orig->str);
self->prev = orig->prev;
self->curr = orig->curr;
onig_region_copy(&self->regs, &orig->regs);
@@ -321,7 +325,7 @@
Data_Get_Struct(self, struct strscanner, p);
StringValue(str);
- p->str = rb_str_dup(str);
+ GC_WB(&p->str, rb_str_dup(str));
rb_obj_freeze(p->str);
p->curr = 0;
CLEAR_MATCH_STATUS(p);
@@ -403,7 +407,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 +419,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 +1258,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/branches/testing/ext/syck/emitter.c
===================================================================
--- MacRuby/branches/testing/ext/syck/emitter.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/syck/emitter.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -108,7 +108,11 @@
syck_new_emitter(void)
{
SyckEmitter *e;
+#if WITH_OBJC
+ e = xmalloc(sizeof(SyckEmitter));
+#else
e = S_ALLOC( SyckEmitter );
+#endif
e->headless = 0;
e->use_header = 0;
e->use_version = 0;
@@ -1194,7 +1198,10 @@
*/
if ( e->markers == NULL )
{
- GC_WB(&e->markers, st_init_numtable());
+ e->markers = st_init_numtable();
+#if WITH_OBJC
+ rb_objc_retain(e->markers);
+#endif
}
/*
Modified: MacRuby/branches/testing/ext/syck/implicit.c
===================================================================
--- MacRuby/branches/testing/ext/syck/implicit.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/syck/implicit.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -44,9 +44,9 @@
}
}
-char *syck_match_implicit( char *str, size_t len )
+char *syck_match_implicit( const char *str, size_t len )
{
- char *cursor, *limit, *marker;
+ const char *cursor, *limit, *marker;
cursor = str;
limit = str + len;
@@ -1608,7 +1608,7 @@
}
char *
-syck_type_id_to_uri( char *type_id )
+syck_type_id_to_uri( const char *type_id )
{
char *cursor, *limit, *marker;
Modified: MacRuby/branches/testing/ext/syck/rubyext.c
===================================================================
--- MacRuby/branches/testing/ext/syck/rubyext.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/syck/rubyext.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -2,7 +2,7 @@
/*
* rubyext.c
*
- * $Author: akr $
+ * $Author: mame $
*
* Copyright (C) 2003-2005 why the lucky stiff
*/
@@ -25,9 +25,11 @@
struct RClass klass;
/*struct RFloat flonum;*/
/*struct RString string;*/
+ /*struct RRegexp regexp;*/
+#if !WITH_OBJC
struct RArray array;
- /*struct RRegexp regexp;*/
struct RHash hash;
+#endif
/*struct RData data;*/
struct RStruct rstruct;
/*struct RBignum bignum;*/
@@ -54,7 +56,7 @@
static VALUE sym_scalar, sym_seq, sym_map;
static VALUE sym_1quote, sym_2quote, sym_fold, sym_literal, sym_plain, sym_inline;
static VALUE cDate, cNode, cMap, cSeq, cScalar, cOut, cParser, cResolver, cPrivateType, cDomainType, cYObject, cBadAlias, cDefaultKey, cMergeKey, cEmitter;
-static VALUE oDefaultResolver, oGenericResolver;
+static VALUE oDefaultResolver, oGenericResolver, oColon, oDoubleColon;
/*
* my private collection of numerical oddities.
@@ -148,8 +150,8 @@
if (!NIL_P(str2))
{
StringValue(str2);
- len = RSTRING_LEN(str2);
- memcpy( buf + skip, RSTRING_PTR(str2), len );
+ len = RSTRING_CLEN(str2);
+ memcpy( buf + skip, RSTRING_CPTR(str2), len );
}
}
len += skip;
@@ -169,13 +171,13 @@
if (!NIL_P(tmp = rb_check_string_type(port))) {
taint = OBJ_TAINTED(port); /* original taintedness */
port = tmp;
- syck_parser_str( parser, RSTRING_PTR(port), RSTRING_LEN(port), NULL );
+ syck_parser_str( parser, RSTRING_CPTR(port), RSTRING_CLEN(port), NULL );
}
else if (rb_respond_to(port, s_read)) {
if (rb_respond_to(port, s_binmode)) {
rb_funcall2(port, s_binmode, 0, 0);
}
- syck_parser_str( parser, (char *)port, 0, rb_syck_io_str_read );
+ syck_parser_str( parser, (const char *)port, 0, rb_syck_io_str_read );
}
else {
rb_raise(rb_eTypeError, "instance of IO needed");
@@ -742,7 +744,11 @@
VALUE pobj;
SyckParser *parser = syck_new_parser();
+#if WITH_OBJC
+ GC_WB(&parser->bonus, xmalloc( sizeof(struct parser_xtra) ));
+#else
parser->bonus = S_ALLOC( struct parser_xtra );
+#endif
S_MEMZERO( parser->bonus, struct parser_xtra, 1 );
pobj = Data_Wrap_Struct( class, syck_mark_parser, rb_syck_free_parser, parser );
@@ -819,10 +825,10 @@
bonus = (struct parser_xtra *)parser->bonus;
bonus->taint = syck_parser_assign_io(parser, &port);
- bonus->data = rb_hash_new();
- bonus->resolver = rb_attr_get( self, s_resolver );
+ GC_WB(&bonus->data, rb_hash_new());
+ GC_WB(&bonus->resolver, rb_attr_get( self, s_resolver ));
if ( NIL_P( proc ) ) bonus->proc = 0;
- else bonus->proc = proc;
+ else GC_WB(&bonus->proc, proc);
return syck_parse( parser );
}
@@ -846,13 +852,13 @@
bonus = (struct parser_xtra *)parser->bonus;
bonus->taint = syck_parser_assign_io(parser, &port);
- bonus->resolver = rb_attr_get( self, s_resolver );
+ GC_WB(&bonus->resolver, rb_attr_get( self, s_resolver ));
bonus->proc = 0;
while ( 1 )
{
/* Reset hash for tracking nodes */
- bonus->data = rb_hash_new();
+ GC_WB(&bonus->data, rb_hash_new());
/* Parse a document */
v = syck_parse( parser );
@@ -884,7 +890,6 @@
static VALUE
syck_resolver_initialize(VALUE self)
{
- VALUE tags = rb_hash_new();
rb_ivar_set(self, s_tags, rb_hash_new());
return self;
}
@@ -916,7 +921,6 @@
VALUE
syck_resolver_detect_implicit(VALUE self, VALUE val)
{
- char *type_id;
return rb_str_new2( "" );
}
@@ -1009,10 +1013,10 @@
VALUE ivname = rb_ary_entry( vars, 0 );
char *ivn;
StringValue( ivname );
- ivn = S_ALLOCA_N( char, RSTRING_LEN(ivname) + 2 );
+ ivn = S_ALLOCA_N( char, RSTRING_CLEN(ivname) + 2 );
ivn[0] = '@';
ivn[1] = '\0';
- strncat( ivn, RSTRING_PTR(ivname), RSTRING_LEN(ivname) );
+ strncat( ivn, RSTRING_CPTR(ivname), RSTRING_CLEN(ivname) );
rb_iv_set( obj, ivn, rb_ary_entry( vars, 1 ) );
return Qnil;
}
@@ -1024,9 +1028,9 @@
syck_const_find(VALUE const_name)
{
VALUE tclass = rb_cObject;
- VALUE tparts = rb_str_split( const_name, "::" );
- int i = 0;
- for ( i = 0; i < RARRAY_LEN(tparts); i++ ) {
+ VALUE tparts = rb_str_split2( const_name, oDoubleColon );
+ int i = 0, count;
+ for ( i = 0, count = RARRAY_LEN(tparts); i < count; i++ ) {
VALUE tpart = rb_to_id( rb_ary_entry( tparts, i ) );
if ( !rb_const_defined( tclass, tpart ) ) return Qnil;
tclass = rb_const_get( tclass, tpart );
@@ -1040,15 +1044,14 @@
VALUE
syck_resolver_transfer(VALUE self, VALUE type, VALUE val)
{
- if (NIL_P(type) || RSTRING_LEN(StringValue(type)) == 0)
+ if (NIL_P(type) || RSTRING_CLEN(StringValue(type)) == 0)
{
type = rb_funcall( self, s_detect_implicit, 1, val );
}
- if ( ! (NIL_P(type) || RSTRING_LEN(StringValue(type)) == 0) )
+ if ( ! (NIL_P(type) || RSTRING_CLEN(StringValue(type)) == 0) )
{
VALUE str_xprivate = rb_str_new2( "x-private" );
- VALUE colon = rb_str_new2( ":" );
VALUE tags = rb_attr_get(self, s_tags);
VALUE target_class = rb_hash_aref( tags, type );
VALUE subclass = target_class;
@@ -1060,17 +1063,17 @@
if ( NIL_P( target_class ) )
{
VALUE subclass_parts = rb_ary_new();
- VALUE parts = rb_str_split( type, ":" );
+ VALUE parts = rb_str_split2( type, oColon );
while ( RARRAY_LEN(parts) > 1 )
{
VALUE partial;
rb_ary_unshift( subclass_parts, rb_ary_pop( parts ) );
- partial = rb_ary_join( parts, colon );
+ partial = rb_ary_join( parts, oColon );
target_class = rb_hash_aref( tags, partial );
if ( NIL_P( target_class ) )
{
- rb_str_append( partial, colon );
+ rb_str_append( partial, oColon );
target_class = rb_hash_aref( tags, partial );
}
@@ -1084,7 +1087,7 @@
RTEST( rb_funcall( target_class, s_tag_subclasses, 0 ) ) )
{
VALUE subclass_v;
- subclass = rb_ary_join( subclass_parts, colon );
+ subclass = rb_ary_join( subclass_parts, oColon );
subclass = rb_funcall( target_class, s_tag_read_class, 1, subclass );
subclass_v = syck_const_find( subclass );
@@ -1144,17 +1147,17 @@
}
else
{
- VALUE parts = rb_str_split( type, ":" );
+ VALUE parts = rb_str_split2( type, oColon );
VALUE scheme = rb_ary_shift( parts );
if ( rb_str_cmp( scheme, str_xprivate ) == 0 )
{
- VALUE name = rb_ary_join( parts, colon );
+ VALUE name = rb_ary_join( parts, oColon );
obj = rb_funcall( cPrivateType, s_new, 2, name, val );
}
else
{
VALUE domain = rb_ary_shift( parts );
- VALUE name = rb_ary_join( parts, colon );
+ VALUE name = rb_ary_join( parts, oColon );
obj = rb_funcall( cDomainType, s_new, 3, domain, name, val );
}
}
@@ -1175,7 +1178,7 @@
if ( !NIL_P(tmp) )
{
- char *taguri = syck_type_id_to_uri( RSTRING_PTR(tmp) );
+ char *taguri = syck_type_id_to_uri( RSTRING_CPTR(tmp) );
val = rb_str_new2( taguri );
S_FREE( taguri );
}
@@ -1195,7 +1198,7 @@
if ( !NIL_P(tmp) )
{
val = tmp;
- type_id = syck_match_implicit( RSTRING_PTR(val), RSTRING_LEN(val) );
+ type_id = syck_match_implicit( RSTRING_CPTR(val), RSTRING_CLEN(val) );
return rb_str_new2( type_id );
}
@@ -1454,8 +1457,8 @@
Data_Get_Struct( self, SyckNode, node );
StringValue( val );
- node->data.str->ptr = syck_strndup( RSTRING_PTR(val), RSTRING_LEN(val) );
- node->data.str->len = RSTRING_LEN(val);
+ node->data.str->ptr = syck_strndup( RSTRING_CPTR(val), RSTRING_CLEN(val) );
+ node->data.str->len = RSTRING_CLEN(val);
node->data.str->style = scalar_none;
rb_iv_set( self, "@value", val );
@@ -1714,7 +1717,7 @@
if ( !NIL_P( type_id ) ) {
StringValue( type_id );
- node->type_id = syck_strndup( RSTRING_PTR(type_id), RSTRING_LEN(type_id) );
+ node->type_id = syck_strndup( RSTRING_CPTR(type_id), RSTRING_CLEN(type_id) );
}
rb_iv_set( self, "@type_id", type_id );
@@ -1886,7 +1889,11 @@
VALUE pobj;
SyckEmitter *emitter = syck_new_emitter();
+#if WITH_OBJC
+ GC_WB(&emitter->bonus, xmalloc( sizeof(struct emitter_xtra) ));
+#else
emitter->bonus = S_ALLOC( struct emitter_xtra );
+#endif
S_MEMZERO( emitter->bonus, struct emitter_xtra, 1 );
pobj = Data_Wrap_Struct( class, syck_mark_emitter, rb_syck_free_emitter, emitter );
@@ -1911,8 +1918,8 @@
bonus = (struct emitter_xtra *)emitter->bonus;
bonus->oid = Qnil;
- bonus->port = rb_str_new2( "" );
- bonus->data = rb_hash_new();
+ GC_WB(&bonus->port, rb_str_new2( "" ));
+ GC_WB(&bonus->data, rb_hash_new());
if (rb_scan_args(argc, argv, "01", &options) == 0)
{
@@ -1921,11 +1928,11 @@
}
else if ( !NIL_P(tmp = rb_check_string_type(options)) )
{
- bonus->port = tmp;
+ GC_WB(&bonus->port, tmp);
}
else if ( rb_respond_to( options, s_write ) )
{
- bonus->port = options;
+ GC_WB(&bonus->port, options);
}
else
{
@@ -1946,7 +1953,6 @@
syck_emitter_emit(int argc, VALUE *argv, VALUE self)
{
VALUE oid, proc;
- char *anchor_name;
SyckEmitter *emitter;
struct emitter_xtra *bonus;
SYMID symple;
@@ -1958,7 +1964,7 @@
bonus = (struct emitter_xtra *)emitter->bonus;
/* Calculate anchors, normalize nodes, build a simpler symbol table */
- bonus->oid = oid;
+ GC_WB(&bonus->oid, oid);
if ( !NIL_P( oid ) && RTEST( rb_funcall( bonus->data, s_haskey, 1, oid ) ) ) {
symple = rb_hash_aref( bonus->data, oid );
} else {
@@ -2157,6 +2163,11 @@
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( "::" );
+ rb_global_variable( &oDoubleColon );
+
/*
* Define YAML::Syck::Parser class
*/
Modified: MacRuby/branches/testing/ext/syck/syck.c
===================================================================
--- MacRuby/branches/testing/ext/syck/syck.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/syck/syck.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -63,7 +63,7 @@
long
syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
{
- char *beg;
+ const char *beg;
long len = 0;
ASSERT( str != NULL );
@@ -157,7 +157,11 @@
syck_new_parser(void)
{
SyckParser *p;
+#if WITH_OBJC
+ p = xmalloc(sizeof(SyckParser));
+#else
p = S_ALLOC( SyckParser );
+#endif
S_MEMZERO( p, SyckParser, 1 );
p->lvl_capa = ALLOC_CT;
p->levels = S_ALLOC_N( SyckLevel, p->lvl_capa );
@@ -313,7 +317,7 @@
}
void
-syck_parser_str( SyckParser *p, char *ptr, long len, SyckIoStrRead read )
+syck_parser_str( SyckParser *p, const char *ptr, long len, SyckIoStrRead read )
{
ASSERT( p != NULL );
free_any_io( p );
Modified: MacRuby/branches/testing/ext/syck/syck.h
===================================================================
--- MacRuby/branches/testing/ext/syck/syck.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/syck/syck.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -48,17 +48,10 @@
#define ALLOC_CT 8
#define SYCK_BUFFERSIZE 4096
-#if 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))
@@ -208,7 +201,7 @@
struct _syck_str {
/* String buffer pointers */
- char *beg, *ptr, *end;
+ const char *beg, *ptr, *end;
/* Function which string -> buffer */
SyckIoStrRead read;
};
@@ -358,9 +351,9 @@
int syck_add_sym( SyckParser *, char * );
int syck_lookup_sym( SyckParser *, SYMID, char ** );
int syck_try_implicit( SyckNode * );
-char *syck_type_id_to_uri( char * );
+char *syck_type_id_to_uri( const char * );
void try_tag_implicit( SyckNode *, int );
-char *syck_match_implicit( char *, size_t );
+char *syck_match_implicit( const char *, size_t );
/*
* API prototypes
@@ -408,7 +401,7 @@
void syck_parser_bad_anchor_handler( SyckParser *, SyckBadAnchorHandler );
void syck_parser_set_input_type( SyckParser *, enum syck_parser_input );
void syck_parser_file( SyckParser *, FILE *, SyckIoFileRead );
-void syck_parser_str( SyckParser *, char *, long, SyckIoStrRead );
+void syck_parser_str( SyckParser *, const char *, long, SyckIoStrRead );
void syck_parser_str_auto( SyckParser *, char *, SyckIoStrRead );
SyckLevel *syck_parser_current_level( SyckParser * );
void syck_parser_add_level( SyckParser *, int, enum syck_level_status );
Modified: MacRuby/branches/testing/ext/syslog/syslog.txt
===================================================================
--- MacRuby/branches/testing/ext/syslog/syslog.txt 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/syslog/syslog.txt 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/tk/extconf.rb
===================================================================
--- MacRuby/branches/testing/ext/tk/extconf.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/tk/extconf.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/tk/lib/multi-tk.rb
===================================================================
--- MacRuby/branches/testing/ext/tk/lib/multi-tk.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/tk/lib/multi-tk.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/tk/lib/tk/autoload.rb
===================================================================
--- MacRuby/branches/testing/ext/tk/lib/tk/autoload.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/tk/lib/tk/autoload.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/tk/stubs.c
===================================================================
--- MacRuby/branches/testing/ext/tk/stubs.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/tk/stubs.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/tk/tcltklib.c
===================================================================
--- MacRuby/branches/testing/ext/tk/tcltklib.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/tk/tcltklib.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
@@ -1170,15 +1236,15 @@
case T_BIGNUM:
/* time is micro-second value */
divmod = rb_funcall(time, rb_intern("divmod"), 1, LONG2NUM(1000000));
- tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]);
- tcl_time.usec = NUM2LONG(RARRAY_PTR(divmod)[1]);
+ tcl_time.sec = NUM2LONG(RARRAY_AT(divmod, 0));
+ tcl_time.usec = NUM2LONG(RARRAY_AT(divmod, 1));
break;
case T_FLOAT:
/* time is second value */
divmod = rb_funcall(time, rb_intern("divmod"), 1, INT2FIX(1));
- tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]);
- tcl_time.usec = (long)(NUM2DBL(RARRAY_PTR(divmod)[1]) * 1000000);
+ tcl_time.sec = NUM2LONG(RARRAY_AT(divmod, 0));
+ tcl_time.usec = (long)(NUM2DBL(RARRAY_AT(divmod, 1)) * 1000000);
default:
{
@@ -5620,7 +5686,7 @@
}
/* set result */
- RARRAY_PTR(q->result)[0] = ret;
+ rb_ary_store(q->result, 0, ret);
/* complete */
*(q->done) = -1;
@@ -5745,7 +5811,7 @@
DUMP2("back from handler (current thread:%lx)", current);
/* get result & free allocated memory */
- ret = RARRAY_PTR(result)[0];
+ ret = RARRAY_AT(result, 0);
free(alloc_done);
if (argv) free(argv);
@@ -5979,7 +6045,7 @@
}
/* set result */
- RARRAY_PTR(q->result)[0] = ret;
+ rb_ary_store(q->result, 0, ret);
/* complete */
*(q->done) = -1;
@@ -6102,7 +6168,7 @@
DUMP2("back from handler (current thread:%lx)", current);
/* get result & free allocated memory */
- ret = RARRAY_PTR(result)[0];
+ ret = RARRAY_AT(result, 0);
free(alloc_done);
free(eval_str);
@@ -7093,7 +7159,7 @@
}
/* set result */
- RARRAY_PTR(q->result)[0] = ret;
+ rb_ary_store(q->result, 0, ret);
/* complete */
*(q->done) = -1;
@@ -7218,7 +7284,7 @@
DUMP2("back from handler (current thread:%lx)", current);
/* get result & free allocated memory */
- ret = RARRAY_PTR(result)[0];
+ ret = RARRAY_AT(result, 0);
//free(alloc_done);
ckfree((char*)alloc_done);
@@ -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/branches/testing/ext/tk/tkutil/tkutil.c
===================================================================
--- MacRuby/branches/testing/ext/tk/tkutil/tkutil.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/tk/tkutil/tkutil.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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;
@@ -268,8 +279,8 @@
/* size = RARRAY_LEN(ary); */
size = 0;
for(idx = 0; idx < RARRAY_LEN(ary); idx++) {
- if (TYPE(RARRAY_PTR(ary)[idx]) == T_HASH) {
- size += 2 * RHASH_SIZE(RARRAY_PTR(ary)[idx]);
+ if (TYPE(RARRAY_AT(ary, idx)) == T_HASH) {
+ size += 2 * RHASH_SIZE(RARRAY_AT(ary, idx));
} else {
size++;
}
@@ -277,7 +288,7 @@
dst = rb_ary_new2(size);
for(idx = 0; idx < RARRAY_LEN(ary); idx++) {
- val = RARRAY_PTR(ary)[idx];
+ val = RARRAY_AT(ary, idx);
str_val = Qnil;
switch(TYPE(val)) {
case T_ARRAY:
@@ -308,7 +319,7 @@
}
size2 = RARRAY_LEN(val);
for(idx2 = 0; idx2 < size2; idx2++) {
- val2 = RARRAY_PTR(val)[idx2];
+ val2 = RARRAY_AT(val, idx2);
switch(TYPE(val2)) {
case T_ARRAY:
str_val = ary2list(val2, enc_flag, self);
@@ -369,13 +380,13 @@
if (RTEST(dst_enc) && !NIL_P(sys_enc)) {
for(idx = 0; idx < RARRAY_LEN(dst); idx++) {
- str_val = RARRAY_PTR(dst)[idx];
+ str_val = RARRAY_AT(dst, idx);
if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) {
str_val = rb_funcall(self, ID_toUTF8, 1, str_val);
} else {
str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val);
}
- RARRAY_PTR(dst)[idx] = str_val;
+ rb_ary_store(dst, idx, str_val);
}
val = rb_apply(cTclTkLib, ID_merge_tklist, dst);
if (TYPE(dst_enc) == T_STRING) {
@@ -421,7 +432,7 @@
size = RARRAY_LEN(ary);
dst = rb_ary_new2(size);
for(idx = 0; idx < RARRAY_LEN(ary); idx++) {
- val = RARRAY_PTR(ary)[idx];
+ val = RARRAY_AT(ary, idx);
str_val = Qnil;
switch(TYPE(val)) {
case T_ARRAY:
@@ -462,13 +473,13 @@
if (RTEST(dst_enc) && !NIL_P(sys_enc)) {
for(idx = 0; idx < RARRAY_LEN(dst); idx++) {
- str_val = RARRAY_PTR(dst)[idx];
+ str_val = RARRAY_AT(dst, idx);
if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) {
str_val = rb_funcall(self, ID_toUTF8, 1, str_val);
} else {
str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val);
}
- RARRAY_PTR(dst)[idx] = str_val;
+ rb_ary_store(dst, idx, str_val);
}
val = rb_apply(cTclTkLib, ID_merge_tklist, dst);
if (TYPE(dst_enc) == T_STRING) {
@@ -504,27 +515,27 @@
len = RARRAY_LEN(assoc);
for(i = 0; i < len; i++) {
- pair = RARRAY_PTR(assoc)[i];
+ pair = RARRAY_AT(assoc, i);
if (TYPE(pair) != T_ARRAY) {
rb_ary_push(dst, key2keyname(pair));
continue;
}
switch(RARRAY_LEN(assoc)) {
case 2:
- rb_ary_push(dst, RARRAY_PTR(pair)[2]);
+ rb_ary_push(dst, RARRAY_AT(pair, 2));
case 1:
- rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
+ rb_ary_push(dst, key2keyname(RARRAY_AT(pair, 0)));
case 0:
continue;
default:
- rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
+ rb_ary_push(dst, key2keyname(RARRAY_AT(pair, 0)));
val = rb_ary_new2(RARRAY_LEN(pair) - 1);
for(j = 1; j < RARRAY_LEN(pair); j++) {
- rb_ary_push(val, RARRAY_PTR(pair)[j]);
+ rb_ary_push(val, RARRAY_AT(pair, j));
}
rb_ary_push(dst, val);
@@ -552,27 +563,27 @@
len = RARRAY_LEN(assoc);
for(i = 0; i < len; i++) {
- pair = RARRAY_PTR(assoc)[i];
+ pair = RARRAY_AT(assoc, i);
if (TYPE(pair) != T_ARRAY) {
rb_ary_push(dst, key2keyname(pair));
continue;
}
switch(RARRAY_LEN(assoc)) {
case 2:
- rb_ary_push(dst, get_eval_string_core(RARRAY_PTR(pair)[2], Qtrue, self));
+ rb_ary_push(dst, get_eval_string_core(RARRAY_AT(pair, 2), Qtrue, self));
case 1:
- rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
+ rb_ary_push(dst, key2keyname(RARRAY_AT(pair, 0)));
case 0:
continue;
default:
- rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
+ rb_ary_push(dst, key2keyname(RARRAY_AT(pair, 0)));
val = rb_ary_new2(RARRAY_LEN(pair) - 1);
for(j = 1; j < RARRAY_LEN(pair); j++) {
- rb_ary_push(val, RARRAY_PTR(pair)[j]);
+ rb_ary_push(val, RARRAY_AT(pair, j));
}
rb_ary_push(dst, get_eval_string_core(val, Qtrue, self));
@@ -594,7 +605,7 @@
{
volatile VALUE ary;
- ary = RARRAY_PTR(args)[0];
+ ary = RARRAY_AT(args, 0);
if (key == Qundef) return ST_CONTINUE;
#if 0
@@ -605,7 +616,7 @@
if (val == TK_None) return ST_CHECK;
- rb_ary_push(ary, get_eval_string_core(val, Qnil, RARRAY_PTR(args)[1]));
+ rb_ary_push(ary, get_eval_string_core(val, Qnil, RARRAY_AT(args, 1)));
return ST_CHECK;
}
@@ -636,21 +647,21 @@
{
volatile VALUE ary;
- ary = RARRAY_PTR(args)[0];
+ ary = RARRAY_AT(args, 0);
if (key == Qundef) return ST_CONTINUE;
#if 0
rb_ary_push(ary, key2keyname(key));
if (val != TK_None) {
rb_ary_push(ary, get_eval_string_core(val, Qtrue,
- RARRAY_PTR(args)[1]));
+ RARRAY_AT(args, 1)));
}
#endif
rb_ary_push(ary, key2keyname(key));
if (val == TK_None) return ST_CHECK;
- rb_ary_push(ary, get_eval_string_core(val, Qtrue, RARRAY_PTR(args)[1]));
+ rb_ary_push(ary, get_eval_string_core(val, Qtrue, RARRAY_AT(args, 1)));
return ST_CHECK;
}
@@ -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:
@@ -1279,7 +1294,7 @@
buf = ALLOC_N(char, len + 1);
for(i = 0; i < len; i++) {
- ptr = RSTRING_PTR(RARRAY_PTR(list)[i]);
+ ptr = RSTRING_PTR(RARRAY_AT(list, i));
if (*ptr == '%' && *(ptr + 2) == '\0') {
*(buf + i) = *(ptr + 1);
} else {
@@ -1355,20 +1370,20 @@
* ivar ==> symbol
*/
for(idx = 0; idx < len; idx++) {
- inf = RARRAY_PTR(key_inf)[idx];
+ inf = RARRAY_AT(key_inf, idx);
if (TYPE(inf) != T_ARRAY) continue;
- *(key + real_len) = NUM2CHR(RARRAY_PTR(inf)[0]);
- *(type + real_len) = NUM2CHR(RARRAY_PTR(inf)[1]);
+ *(key + real_len) = NUM2CHR(RARRAY_AT(inf, 0));
+ *(type + real_len) = NUM2CHR(RARRAY_AT(inf, 1));
*(ivar + real_len)
= rb_intern(
RSTRING_PTR(
rb_str_cat2(rb_str_new2("@"),
- rb_id2name(SYM2ID(RARRAY_PTR(inf)[2])))
+ rb_id2name(SYM2ID(RARRAY_AT(inf, 2))))
)
);
- rb_attr(self, SYM2ID(RARRAY_PTR(inf)[2]), 1, 0, Qtrue);
+ rb_attr(self, SYM2ID(RARRAY_AT(inf, 2)), 1, 0, Qtrue);
real_len++;
}
*(key + real_len) = '\0';
@@ -1382,9 +1397,9 @@
*/
len = RARRAY_LEN(proc_inf);
for(idx = 0; idx < len; idx++) {
- inf = RARRAY_PTR(proc_inf)[idx];
+ inf = RARRAY_AT(proc_inf, idx);
if (TYPE(inf) != T_ARRAY) continue;
- rb_hash_aset(proc, RARRAY_PTR(inf)[0], RARRAY_PTR(inf)[1]);
+ rb_hash_aset(proc, RARRAY_AT(inf, 0), RARRAY_AT(inf, 1));
}
rb_const_set(self, ID_SUBST_INFO,
@@ -1441,9 +1456,9 @@
}
if (NIL_P(proc)) {
- rb_ary_push(dst, RARRAY_PTR(val_ary)[idx]);
+ rb_ary_push(dst, RARRAY_AT(val_ary, idx));
} else {
- rb_ary_push(dst, rb_funcall(proc, ID_call, 1, RARRAY_PTR(val_ary)[idx]));
+ rb_ary_push(dst, rb_funcall(proc, ID_call, 1, RARRAY_AT(val_ary, idx)));
}
}
@@ -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/branches/testing/ext/win32ole/win32ole.c
===================================================================
--- MacRuby/branches/testing/ext/win32ole/win32ole.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/win32ole/win32ole.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ext/zlib/zlib.c
===================================================================
--- MacRuby/branches/testing/ext/zlib/zlib.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ext/zlib/zlib.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/file.c
===================================================================
--- MacRuby/branches/testing/file.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/file.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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"
@@ -141,7 +145,7 @@
rb_secure(4);
for (i=0; i<RARRAY_LEN(vargs); i++) {
- path = rb_get_path(RARRAY_PTR(vargs)[i]);
+ path = rb_get_path(RARRAY_AT(vargs, i));
(*func)(StringValueCStr(path), arg);
}
@@ -829,7 +833,7 @@
rb_secure(2);
FilePathValue(fname);
if (lstat(StringValueCStr(fname), &st) == -1) {
- rb_sys_fail(RSTRING_PTR(fname));
+ rb_sys_fail(RSTRING_CPTR(fname));
}
return stat_new(&st);
#else
@@ -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
@@ -1565,13 +1569,13 @@
FilePathValue(fname1);
fname1 = rb_str_new4(fname1);
FilePathValue(fname2);
- if (access(RSTRING_PTR(fname1), 0)) return Qfalse;
- if (access(RSTRING_PTR(fname2), 0)) return Qfalse;
+ if (access(RSTRING_CPTR(fname1), 0)) return Qfalse;
+ if (access(RSTRING_CPTR(fname2), 0)) return Qfalse;
#endif
fname1 = rb_file_expand_path(fname1, Qnil);
fname2 = rb_file_expand_path(fname2, Qnil);
- if (RSTRING_LEN(fname1) != RSTRING_LEN(fname2)) return Qfalse;
- if (rb_memcicmp(RSTRING_PTR(fname1), RSTRING_PTR(fname2), RSTRING_LEN(fname1)))
+ if (RSTRING_CLEN(fname1) != RSTRING_CLEN(fname2)) return Qfalse;
+ if (rb_memcicmp(RSTRING_CPTR(fname1), RSTRING_CPTR(fname2), RSTRING_CLEN(fname1)))
return Qfalse;
#endif
return Qtrue;
@@ -1658,7 +1662,7 @@
rb_secure(2);
FilePathValue(fname);
if (lstat(StringValueCStr(fname), &st) == -1) {
- rb_sys_fail(RSTRING_PTR(fname));
+ rb_sys_fail(RSTRING_CPTR(fname));
}
return rb_file_ftype(&st);
@@ -1724,7 +1728,7 @@
struct stat st;
if (rb_stat(fname, &st) < 0)
- rb_sys_fail(RSTRING_PTR(fname));
+ rb_sys_fail(RSTRING_CPTR(fname));
return stat_mtime(&st);
}
@@ -1769,7 +1773,7 @@
struct stat st;
if (rb_stat(fname, &st) < 0)
- rb_sys_fail(RSTRING_PTR(fname));
+ rb_sys_fail(RSTRING_CPTR(fname));
return stat_ctime(&st);
}
@@ -2159,7 +2163,7 @@
#endif
const char *e1, *e2;
int len = 5;
- int l1 = RSTRING_LEN(s1), l2 = RSTRING_LEN(s2);
+ int l1 = RSTRING_CLEN(s1), l2 = RSTRING_CLEN(s2);
e1 = e2 = "";
if (l1 > max_pathlen) {
@@ -2175,8 +2179,8 @@
len += l1 + l2;
buf = ALLOCA_N(char, len);
snprintf(buf, len, "(%.*s%s, %.*s%s)",
- l1, RSTRING_PTR(s1), e1,
- l2, RSTRING_PTR(s2), e2);
+ l1, RSTRING_CPTR(s1), e1,
+ l2, RSTRING_CPTR(s2), e2);
rb_sys_fail(buf);
}
@@ -2263,7 +2267,7 @@
rb_secure(2);
FilePathValue(path);
buf = xmalloc(size);
- while ((rv = readlink(RSTRING_PTR(path), buf, size)) == size
+ while ((rv = readlink(RSTRING_CPTR(path), buf, size)) == size
#ifdef _AIX
|| (rv < 0 && errno == ERANGE) /* quirky behavior of GPFS */
#endif
@@ -2273,7 +2277,7 @@
}
if (rv < 0) {
free(buf);
- rb_sys_fail(RSTRING_PTR(path));
+ rb_sys_fail(RSTRING_CPTR(path));
}
v = rb_tainted_str_new(buf, rv);
xfree(buf);
@@ -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,14 +2588,24 @@
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);
@@ -2587,6 +2633,7 @@
#endif
s++;
tainted = 1;
+ SET_EXTERNAL_ENCODING();
}
else {
#ifdef HAVE_PWD_H
@@ -2642,6 +2689,7 @@
BUFCHECK(dirlen > buflen);
strcpy(buf, dir);
free(dir);
+ SET_EXTERNAL_ENCODING();
}
p = chompdirsep(skiproot(buf));
s += 2;
@@ -2650,8 +2698,13 @@
#endif
else if (!is_absolute_path(s)) {
if (!NIL_P(dname)) {
+ 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();
@@ -2661,6 +2714,7 @@
BUFCHECK(dirlen > buflen);
strcpy(buf, dir);
xfree(dir);
+ SET_EXTERNAL_ENCODING();
}
#if defined DOSISH || defined __CYGWIN__
if (isdirsep(*s)) {
@@ -2699,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__
@@ -2720,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__
@@ -2742,21 +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));
}
/*
@@ -2790,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;
@@ -2829,17 +2974,17 @@
rb_file_s_basename(int argc, VALUE *argv)
{
VALUE fname, fext, basename;
- char *name, *p;
+ const char *name, *p;
#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);
}
FilePathStringValue(fname);
- if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
+ if (RSTRING_CLEN(fname) == 0 || !*(name = RSTRING_CPTR(fname)))
return fname;
name = skipprefix(name);
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
@@ -2867,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_LEN(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;
}
@@ -2932,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;
}
@@ -2953,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;
}
@@ -3022,16 +3207,44 @@
static VALUE
rb_file_join(VALUE ary, VALUE sep)
{
- long len, i;
+#if WITH_OBJC
+ CFMutableStringRef mstr;
+ long count;
+
+ mstr = CFStringCreateMutable(NULL, 0);
+
+ count = RARRAY_LEN(ary);
+ if (count > 0) {
+ long i;
+ for (i = 0; i < count; i++) {
+ VALUE tmp = RARRAY_AT(ary, i);
+ switch (TYPE(tmp)) {
+ case T_STRING:
+ break;
+ case T_ARRAY:
+ tmp = rb_file_join(tmp, sep);
+ break;
+ default:
+ FilePathStringValue(tmp);
+ }
+ if (i > 0)
+ CFStringAppend(mstr, (CFStringRef)sep);
+ CFStringAppend(mstr, (CFStringRef)tmp);
+ }
+ }
+ CFMakeCollectable(mstr);
+ return (VALUE)mstr;
+#else
+ long len, i, count;
VALUE result, tmp;
char *name, *tail;
if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0);
len = 1;
- for (i=0; i<RARRAY_LEN(ary); i++) {
- if (TYPE(RARRAY_PTR(ary)[i]) == T_STRING) {
- len += RSTRING_LEN(RARRAY_PTR(ary)[i]);
+ for (i=0, count=RARRAY_LEN(ary); i<count; i++) {
+ if (TYPE(RARRAY_AT(ary, i)) == T_STRING) {
+ len += RSTRING_LEN(RARRAY_AT(ary, i));
}
else {
len += 10;
@@ -3044,7 +3257,7 @@
result = rb_str_buf_new(len);
OBJ_INFECT(result, ary);
for (i=0; i<RARRAY_LEN(ary); i++) {
- tmp = RARRAY_PTR(ary)[i];
+ tmp = RARRAY_AT(ary, i);
switch (TYPE(tmp)) {
case T_STRING:
break;
@@ -3074,6 +3287,7 @@
}
return result;
+#endif
}
/*
@@ -3118,7 +3332,7 @@
FilePathValue(path);
#ifdef HAVE_TRUNCATE
if (truncate(StringValueCStr(path), pos) < 0)
- rb_sys_fail(RSTRING_PTR(path));
+ rb_sys_fail(RSTRING_CPTR(path));
#else
# ifdef HAVE_CHSIZE
{
@@ -3126,16 +3340,16 @@
# ifdef _WIN32
if ((tmpfd = open(StringValueCStr(path), O_RDWR)) < 0) {
- rb_sys_fail(RSTRING_PTR(path));
+ rb_sys_fail(RSTRING_CPTR(path));
}
# else
if ((tmpfd = open(StringValueCStr(path), 0)) < 0) {
- rb_sys_fail(RSTRING_PTR(path));
+ rb_sys_fail(RSTRING_CPTR(path));
}
# endif
if (chsize(tmpfd, pos) < 0) {
close(tmpfd);
- rb_sys_fail(RSTRING_PTR(path));
+ rb_sys_fail(RSTRING_CPTR(path));
}
close(tmpfd);
}
@@ -3273,7 +3487,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;
@@ -3288,7 +3502,6 @@
rb_sys_fail(fptr->path);
}
}
- exit:
#endif
return INT2FIX(0);
}
@@ -3460,7 +3673,7 @@
CHECK(1);
if (rb_stat(argv[1], &st) == -1) {
- rb_sys_fail(RSTRING_PTR(argv[1]));
+ rb_sys_fail(RSTRING_CPTR(argv[1]));
}
switch (cmd) {
@@ -3549,7 +3762,7 @@
rb_secure(2);
FilePathValue(fname);
if (stat(StringValueCStr(fname), &st) == -1) {
- rb_sys_fail(RSTRING_PTR(fname));
+ rb_sys_fail(RSTRING_CPTR(fname));
}
if (DATA_PTR(obj)) {
free(DATA_PTR(obj));
@@ -4191,7 +4404,7 @@
path_check_0(VALUE path, int execpath)
{
struct stat st;
- char *p0 = StringValueCStr(path);
+ const char *p0 = StringValueCStr(path);
char *p = 0, *s;
if (!is_absolute_path(p0)) {
@@ -4203,7 +4416,8 @@
rb_str_cat2(newpath, "/");
rb_str_cat2(newpath, p0);
- p0 = RSTRING_PTR(path = newpath);
+ path = newpath;
+ p0 = RSTRING_CPTR(path);
}
for (;;) {
#ifndef S_IWOTH
@@ -4280,14 +4494,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)
{
- char *path, *found;
- char *f = RSTRING_PTR(*filep);
- VALUE fname;
+ const char *path, *found;
+ const char *f = RSTRING_CPTR(*filep);
+ VALUE fname, load_path;
long i, j;
if (f[0] == '~') {
@@ -4313,35 +4527,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_PTR(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_LEN(str) == 0) continue;
- path = RSTRING_PTR(str);
- found = dln_find_file(StringValueCStr(fname), path);
+ if (RSTRING_CLEN(str) == 0) continue;
+ path = RSTRING_CPTR(str);
+ 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);
- char *lpath;
+ const char *lpath;
+ char fbuf[MAXPATHLEN];
if (f[0] == '~') {
path = rb_file_expand_path(path, Qnil);
@@ -4372,24 +4589,24 @@
rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
}
- if (rb_load_path) {
- long i;
+ 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;i<RARRAY_LEN(rb_load_path);i++) {
- VALUE str = RARRAY_PTR(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_LEN(str) > 0) {
+ if (RSTRING_CLEN(str) > 0) {
rb_ary_push(tmp, str);
}
}
tmp = rb_ary_join(tmp, rb_str_new2(PATH_SEP));
- if (RSTRING_LEN(tmp) == 0) {
+ if (RSTRING_CLEN(tmp) == 0) {
lpath = 0;
}
else {
- lpath = RSTRING_PTR(tmp);
+ lpath = RSTRING_CPTR(tmp);
}
}
else {
@@ -4399,7 +4616,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/branches/testing/gc.c
===================================================================
--- MacRuby/branches/testing/gc.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/gc.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,4 +1,4 @@
- /**********************************************************************
+/**********************************************************************
gc.c -
@@ -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>
@@ -45,7 +47,9 @@
#define AUTO_MEMORY_UNSCANNED 1
#define AUTO_OBJECT_SCANNED 2
#define AUTO_OBJECT_UNSCANNED 3
+#define AUTO_COLLECT_RATIO_COLLECTION (0 << 0)
#define AUTO_COLLECT_GENERATIONAL_COLLECTION (1 << 0)
+#define AUTO_COLLECT_FULL_COLLECTION (1 << 0)
#define AUTO_LOG_COLLECTIONS (1 << 1)
#define AUTO_LOG_REGIONS (1 << 4)
#define AUTO_LOG_UNUSUAL (1 << 5)
@@ -56,10 +60,18 @@
auto_zone_t *, size_t, auto_memory_type_t, boolean_t, boolean_t);
extern void *auto_zone_write_barrier_memmove(
auto_zone_t *, void *, const void *, size_t);
+extern void auto_zone_set_associative_ref(auto_zone_t *, void *, void *,
+ void *);
+extern void *auto_zone_get_associative_ref(auto_zone_t *, void *, void *);
extern auto_zone_t *auto_zone(void);
+typedef struct auto_zone_cursor *auto_zone_cursor_t;
+typedef void (*auto_zone_foreach_object_t) (auto_zone_cursor_t cursor,
+ void (*op) (void *ptr, void *data), void* data);
typedef struct {
uint32_t unused1;
- void *unused2;
+ void (*batch_invalidate) (auto_zone_t *zone,
+ auto_zone_foreach_object_t foreach, auto_zone_cursor_t cursor,
+ size_t cursor_size);
void *unused3;
void *unused4;
void *unused5;
@@ -73,9 +85,18 @@
size_t unused11;
} auto_collection_control_t;
extern auto_collection_control_t *auto_collection_parameters(auto_zone_t *);
+typedef struct {
+ malloc_statistics_t malloc_statistics;
+ uint32_t version;
+ size_t num_collections[2];
+ boolean_t last_collection_was_generational;
+ size_t bytes_in_use_after_last_collection[2];
+ size_t bytes_allocated_after_last_collection[2];
+ size_t bytes_freed_during_last_collection[2];
+ // durations not included
+} auto_statistics_t;
# endif
static auto_zone_t *__auto_zone = NULL;
-static long gc_count = 0;
static long xmalloc_count = 0;
#endif
@@ -94,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__
@@ -127,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
@@ -152,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;
@@ -170,6 +181,8 @@
struct RFile file;
struct RNode node;
struct RMatch match;
+ struct RRational rational;
+ struct RComplex complex;
} as;
#ifdef GC_DEBUG
char *file;
@@ -177,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 */
@@ -222,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)
{
@@ -236,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);
}
@@ -271,13 +375,25 @@
*/
static VALUE
-gc_stress_set(VALUE self, VALUE bool)
+gc_stress_set(VALUE self, VALUE flag)
{
rb_secure(2);
- ruby_gc_stress = RTEST(bool);
- return bool;
+ ruby_gc_stress = RTEST(flag);
+ return flag;
}
+static int garbage_collect(void);
+
+void
+rb_gc_malloc_increase(size_t size)
+{
+ malloc_increase += size;
+ if (!dont_gc && (ruby_gc_stress || malloc_increase > malloc_limit))
+ garbage_collect();
+}
+
+#if WITH_OBJC
+
void *
ruby_xmalloc(size_t size)
{
@@ -287,59 +403,148 @@
rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
}
if (size == 0) size = 1;
- malloc_increase += size;
-
- if (ruby_gc_stress || malloc_increase > malloc_limit) {
- garbage_collect();
+ rb_gc_malloc_increase(size);
+
+ if (__auto_zone == NULL) {
+ fprintf(stderr,
+ "The client that links against MacRuby was not built for "\
+ "GC. Please turn on garbage collection (-fobjc-gc) and "\
+ "try again.\n");
+ exit(1);
}
-#if WITH_OBJC
- assert(__auto_zone != NULL);
- 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();
}
- //auto_zone_retain(__auto_zone, mem);
+
+ 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) {
@@ -349,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)
{
@@ -446,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);
@@ -472,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) {
@@ -491,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;
@@ -547,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();
}
}
@@ -566,6 +839,7 @@
RANY(obj)->file = rb_sourcefile();
RANY(obj)->line = rb_sourceline();
#endif
+
return obj;
}
@@ -573,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;
}
@@ -596,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++;
}
@@ -612,79 +891,14 @@
#endif
return v;
#else
- return rb_newobj_from_heap();
+ rb_objspace_t *objspace = &rb_objspace;
+ return rb_newobj_from_heap(objspace);
#endif
}
#else /* !WITH_OBJC */
-struct finalize_at_exit {
- VALUE v;
- struct finalize_at_exit *next;
-};
-
-static struct finalize_at_exit *finalize_at_exit_head = NULL;
-
void
-rb_objc_keep_for_exit_finalize(VALUE v)
-{
- if (finalize_at_exit_head == NULL) {
- finalize_at_exit_head = (struct finalize_at_exit *)malloc(
- sizeof(struct finalize_at_exit));
- finalize_at_exit_head->v = v;
- finalize_at_exit_head->next = NULL;
- }
- else {
- struct finalize_at_exit *entry;
- entry = (struct finalize_at_exit *)malloc(
- sizeof(struct finalize_at_exit));
- entry->v = v;
- entry->next = finalize_at_exit_head;
- finalize_at_exit_head = entry;
- }
-}
-
-static inline void
-rb_objc_finalize(VALUE obj)
-{
- struct finalize_at_exit *entry;
-
- //printf("rb_objc_finalize %p\n", (void *)obj);
-
- for (entry = finalize_at_exit_head; entry != NULL; entry = entry->next) {
- if (obj == entry->v)
- entry->v = Qnil;
- }
-
- switch (RBASIC(obj)->flags & T_MASK) {
- case T_FILE:
- if (RFILE(obj)->fptr != NULL)
- rb_io_fptr_finalize(RFILE(obj)->fptr);
- break;
- default:
- rb_bug("rb_objc_finalize: unhandled object type 0x%X",
- RBASIC(obj)->flags & T_MASK);
- }
-}
-
-static id
-rb_objc_imp_finalize(id rcv, SEL sel)
-{
- void *p;
-
- assert(!rb_objc_is_non_native((VALUE)rcv));
- rb_objc_finalize((VALUE)rcv);
-}
-
-static void
-rb_objc_define_finalizer(VALUE klass)
-{
- Class ocklass = (Class)RCLASS(klass)->ocklass;
- assert(class_addMethod(ocklass, sel_registerName("finalize"),
- (IMP)rb_objc_imp_finalize, "@@:"));
-}
-
-void
rb_objc_wb(void *dst, void *newval)
{
if (!SPECIAL_CONST_P(newval)) {
@@ -715,27 +929,32 @@
}
void
-rb_objc_weak(void *addr)
-{
- if (addr != NULL)
- auto_assign_weak_reference(__auto_zone, *(void **)addr, addr, NULL);
-}
-
-void
rb_objc_retain(void *addr)
{
- if (addr != NULL)
+ if (addr != NULL && !SPECIAL_CONST_P(addr))
auto_zone_retain(__auto_zone, addr);
}
void
rb_objc_release(void *addr)
{
- if (addr != NULL && auto_zone_retain_count(__auto_zone, addr) > 0)
+ if (addr != NULL && !SPECIAL_CONST_P(addr))
auto_zone_release(__auto_zone, addr);
}
void
+rb_objc_set_associative_ref(void *obj, void *key, void *val)
+{
+ auto_zone_set_associative_ref(__auto_zone, obj, key, val);
+}
+
+void *
+rb_objc_get_associative_ref(void *obj, void *key)
+{
+ return auto_zone_get_associative_ref(__auto_zone, obj, key);
+}
+
+void
rb_gc_register_address(VALUE *addr)
{
rb_objc_root(addr);
@@ -767,9 +986,7 @@
rb_objc_newobj(size_t size)
{
void *obj;
- malloc_increase += size;
- if (!dont_gc && (ruby_gc_stress || malloc_increase > malloc_limit))
- garbage_collect();
+ rb_gc_malloc_increase(size);
#if USE_OBJECTS_POOL
if (objects_pool == NULL)
objects_pool = malloc(sizeof(void *) * OBJECTS_POOL_SIZE);
@@ -864,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
@@ -873,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)
@@ -888,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
@@ -910,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;
@@ -919,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++;
}
@@ -984,7 +1162,7 @@
}
static void
-gc_mark_rest(void)
+gc_mark_rest(rb_objspace_t *objspace)
{
VALUE tmp_arry[MARK_STACK_MAX];
VALUE *p;
@@ -992,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;
@@ -1128,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;
@@ -1136,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);
@@ -1155,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;
@@ -1172,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:
@@ -1183,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:
@@ -1197,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:
@@ -1225,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:
@@ -1262,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;
@@ -1288,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;
@@ -1326,13 +1537,13 @@
long i, len = RARRAY_LEN(obj);
VALUE *ptr = RARRAY_PTR(obj);
for (i=0; i < len; i++) {
- gc_mark(*ptr++, lev);
+ gc_mark(objspace, *ptr++, lev);
}
}
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;
@@ -1353,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;
@@ -1400,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;
@@ -1424,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 {
@@ -1440,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;
@@ -1476,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 */
@@ -1485,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;
@@ -1502,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;
@@ -1521,7 +1749,8 @@
}
malloc_increase = 0;
if (freed < free_min) {
- add_heap();
+ set_heaps_increment(objspace);
+ heaps_increment(objspace);
}
during_gc = 0;
@@ -1530,8 +1759,9 @@
deferred_final_list = final_list;
return;
}
- free_unused_heaps();
+ free_unused_heaps(objspace);
}
+
#endif /* !WITH_OBJC */
void
@@ -1541,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:
@@ -1568,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:
@@ -1581,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);
@@ -1599,13 +1829,13 @@
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));
@@ -1626,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:
@@ -1657,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\
@@ -1678,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];
@@ -1701,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__ */
@@ -1711,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;
@@ -1736,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),
@@ -1754,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();
@@ -1767,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();
@@ -1796,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 */
@@ -1807,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;
}
@@ -1822,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
@@ -1844,32 +2078,19 @@
rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
#endif
}
+
#else /* !WITH_OBJC */
+
static int
garbage_collect(void)
{
if (dont_gc)
return Qtrue;
-
auto_collect(__auto_zone, AUTO_COLLECT_GENERATIONAL_COLLECTION, NULL);
-
- gc_count++;
-#if 0
- if (malloc_increase > malloc_limit) {
- auto_statistics_t stats;
- size_t live, freed;
- auto_zone_statistics(__auto_zone, &stats);
- live = stats.bytes_in_use_after_last_collection[1] / sizeof(RVALUE);
- freed = stats.bytes_freed_during_last_collection[1] / sizeof(RVALUE);
- malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
- printf("malloc_increase was %ld, malloc_limit is now %ld\n", malloc_increase, malloc_limit);
- }
-#endif
malloc_increase = 0;
-
return Qtrue;
}
+
#endif
void
@@ -1898,6 +2119,7 @@
return Qnil;
}
+#if !WITH_OBJC
void
ruby_set_stack_size(size_t size)
{
@@ -1907,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
@@ -2044,6 +2212,20 @@
*/
#if WITH_OBJC
+static bool
+rb_objc_is_placeholder(void *obj)
+{
+ static void *placeholder_dict = NULL;
+ static void *placeholder_ary = NULL;
+ void *obj_klass;
+ if (placeholder_dict == NULL)
+ placeholder_dict = objc_getClass("__NSPlaceholderDictionary");
+ if (placeholder_ary == NULL)
+ placeholder_ary = objc_getClass("__NSPlaceholderArray");
+ obj_klass = *(void **)obj;
+ return obj_klass == placeholder_dict || obj_klass == placeholder_ary;
+}
+
struct rb_objc_recorder_context {
VALUE class_of;
int count;
@@ -2065,11 +2247,22 @@
if (type != AUTO_OBJECT_SCANNED && type != AUTO_OBJECT_UNSCANNED)
continue;
if (ctx->class_of != 0) {
- if (ctx->class_of == rb_cClass) {
- /* Class is a special case. */
- if (TYPE(r->address) != T_CLASS
+ if (ctx->class_of == rb_cClass || ctx->class_of == rb_cModule) {
+ /* Class/Module are a special case. */
+ if (rb_objc_is_non_native(r->address)
|| FL_TEST(r->address, FL_SINGLETON))
continue;
+ if (ctx->class_of == rb_cClass) {
+ /* Only match classes. */
+ if (BUILTIN_TYPE(r->address) != T_CLASS)
+ continue;
+ }
+ else {
+ /* Match classes & modules. */
+ if (BUILTIN_TYPE(r->address) != T_CLASS
+ && BUILTIN_TYPE(r->address) != T_MODULE)
+ continue;
+ }
}
else {
unsigned ok = 0;
@@ -2096,6 +2289,10 @@
continue;
}
}
+ else {
+ if (rb_objc_is_placeholder((void *)r->address))
+ continue;
+ }
rb_yield((VALUE)r->address);
ctx->count++;
}
@@ -2107,22 +2304,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;
@@ -2149,9 +2338,9 @@
}
}
- return INT2FIX(n);
+ return SIZET2NUM(n);
+}
#endif
-}
/*
* call-seq:
@@ -2192,65 +2381,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)
*
@@ -2258,12 +2407,29 @@
*
*/
+#if WITH_OBJC
+static CFMutableDictionaryRef __os_finalizers = NULL;
+#endif
+
static VALUE
undefine_final(VALUE os, VALUE obj)
{
+#if WITH_OBJC
+ if (__os_finalizers != NULL)
+ CFDictionaryRemoveValue(__os_finalizers, (const void *)obj);
+
+ if (rb_objc_is_non_native(obj)) {
+ rb_objc_flag_set(obj, FL_FINALIZE, false);
+ }
+ else {
+ FL_UNSET(obj, FL_FINALIZE);
+ }
+#else
+ rb_objspace_t *objspace = &rb_objspace;
if (finalizer_table) {
st_delete(finalizer_table, (st_data_t*)&obj, 0);
}
+#endif
return obj;
}
@@ -2279,8 +2445,13 @@
static VALUE
define_final(int argc, VALUE *argv, VALUE os)
{
+#if WITH_OBJC
VALUE obj, block, table;
+ if (__os_finalizers == NULL)
+ __os_finalizers = CFDictionaryCreateMutable(NULL, 0, NULL,
+ &kCFTypeDictionaryValueCallBacks);
+
rb_scan_args(argc, argv, "11", &obj, &block);
if (argc == 1) {
block = rb_block_proc();
@@ -2289,6 +2460,36 @@
rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
rb_obj_classname(block));
}
+
+ table = (VALUE)CFDictionaryGetValue((CFDictionaryRef)__os_finalizers,
+ (const void *)obj);
+
+ if (table == 0) {
+ table = rb_ary_new();
+ CFDictionarySetValue(__os_finalizers, (const void *)obj,
+ (const void *)table);
+ }
+
+ rb_ary_push(table, block);
+
+ if (rb_objc_is_non_native(obj)) {
+ rb_objc_flag_set(obj, FL_FINALIZE, true);
+ }
+ else {
+ FL_SET(obj, FL_FINALIZE);
+ }
+#else
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE obj, block, table;
+
+ rb_scan_args(argc, argv, "11", &obj, &block);
+ if (argc == 1) {
+ block = rb_block_proc();
+ }
+ else if (!rb_respond_to(block, rb_intern("call"))) {
+ rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
+ rb_obj_classname(block));
+ }
need_call_final = 1;
FL_SET(obj, FL_FINALIZE);
@@ -2304,21 +2505,51 @@
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
VALUE table;
+ if (__os_finalizers == NULL)
+ return;
+
+ if (rb_objc_is_non_native(obj)) {
+ if (!rb_objc_flag_check(obj, FL_FINALIZE))
+ return;
+ }
+ else {
+ if (!FL_TEST(obj, FL_FINALIZE))
+ return;
+ }
+
+ table = (VALUE)CFDictionaryGetValue((CFDictionaryRef)__os_finalizers,
+ (const void *)obj);
+
+ if (table == 0) {
+ CFDictionaryRemoveValue(__os_finalizers, (const void *)dest);
+ }
+ else {
+ CFDictionarySetValue(__os_finalizers, (const void *)dest,
+ (const void *)table);
+ }
+#else
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE table;
+
if (!finalizer_table) return;
if (!FL_TEST(obj, FL_FINALIZE)) return;
if (st_lookup(finalizer_table, obj, &table)) {
st_insert(finalizer_table, dest, table);
}
FL_SET(dest, FL_FINALIZE);
+#endif
}
+#if !WITH_OBJC
static VALUE
run_single_final(VALUE arg)
{
@@ -2328,25 +2559,16 @@
}
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_PTR(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));
@@ -2360,40 +2582,95 @@
}
rb_thread_critical = critical_save;
}
+#endif
#if WITH_OBJC
+static CFMutableArrayRef __exit_finalize = NULL;
+static void
+rb_objc_finalize_pure_ruby_obj(VALUE obj)
+{
+ switch (RBASIC(obj)->flags & T_MASK) {
+ case T_FILE:
+ if (RFILE(obj)->fptr != NULL) {
+ rb_io_fptr_finalize(RFILE(obj)->fptr);
+ }
+ break;
+ }
+}
+
void
+rb_objc_keep_for_exit_finalize(VALUE v)
+{
+ if (__exit_finalize == NULL) {
+ __exit_finalize = CFArrayCreateMutable(NULL, 0,
+ &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(__exit_finalize, (void *)v);
+}
+
+static void rb_call_os_finalizer2(VALUE, VALUE);
+
+static void
+os_finalize_cb(const void *key, const void *val, void *context)
+{
+ rb_call_os_finalizer2((VALUE)key, (VALUE)val);
+}
+
+void
rb_gc_call_finalizer_at_exit(void)
{
- struct finalize_at_exit *entry;
+ if (__exit_finalize != NULL) {
+ long i, count;
+ for (i = 0, count = CFArrayGetCount((CFArrayRef)__exit_finalize);
+ i < count;
+ i++) {
+ VALUE v;
+ v = (VALUE)CFArrayGetValueAtIndex((CFArrayRef)__exit_finalize, i);
+ rb_objc_finalize_pure_ruby_obj(v);
+ }
+ CFArrayRemoveAllValues(__exit_finalize);
+ CFRelease(__exit_finalize);
+ }
- for (entry = finalize_at_exit_head; entry != NULL; entry = entry->next)
- if (entry->v != Qnil)
- rb_objc_finalize(entry->v);
+ if (__os_finalizers != NULL) {
+ CFDictionaryApplyFunction((CFDictionaryRef)__os_finalizers,
+ os_finalize_cb, NULL);
+ CFDictionaryRemoveAllValues(__os_finalizers);
+ CFRelease(__os_finalizers);
+ }
+
+ auto_collect(__auto_zone, AUTO_COLLECT_FULL_COLLECTION, NULL);
}
#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++;
@@ -2401,14 +2678,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++;
}
@@ -2421,7 +2698,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)));
@@ -2433,7 +2709,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));
}
@@ -2443,6 +2718,14 @@
}
during_gc = 0;
}
+
+void
+rb_gc(void)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ garbage_collect(objspace);
+ gc_finalize_deferred(objspace);
+}
#endif
/*
@@ -2466,6 +2749,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;
@@ -2476,6 +2762,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 */
@@ -2485,17 +2775,22 @@
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)) {
auto_memory_type_t type =
auto_zone_get_layout_type_no_lock(__auto_zone, p0);
- if (type == AUTO_OBJECT_SCANNED || type == AUTO_OBJECT_UNSCANNED)
+ 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)))
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);
}
@@ -2513,7 +2808,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.
@@ -2525,7 +2820,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
@@ -2564,9 +2859,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);
}
@@ -2600,10 +2897,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) {
@@ -2632,63 +2933,181 @@
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.
*/
+#if WITH_OBJC
+static void (*old_batch_invalidate)(auto_zone_t *,
+ auto_zone_foreach_object_t, auto_zone_cursor_t, size_t);
+
+static VALUE
+run_single_final(VALUE arg)
+{
+ VALUE *args = (VALUE *)arg;
+ rb_eval_cmd(args[0], args[1], (int)args[2]);
+ return Qnil;
+}
+
+static void
+rb_call_os_finalizer2(VALUE obj, VALUE table)
+{
+ long i, count;
+ VALUE args[3];
+ int status, critical_save;
+
+ critical_save = rb_thread_critical;
+ rb_thread_critical = Qtrue;
+
+ args[1] = rb_ary_new3(1, rb_obj_id(obj));
+ args[2] = (VALUE)rb_safe_level();
+
+ for (i = 0, count = RARRAY_LEN(table); i < count; i++) {
+ args[0] = RARRAY_AT(table, i);
+ rb_protect(run_single_final, (VALUE)args, &status);
+ }
+
+ rb_thread_critical = critical_save;
+}
+
+static void
+rb_call_os_finalizer(void *obj)
+{
+ if (__os_finalizers != NULL) {
+ VALUE table;
+
+ table = (VALUE)CFDictionaryGetValue((CFDictionaryRef)__os_finalizers,
+ (const void *)obj);
+
+ if (table != 0) {
+ rb_call_os_finalizer2((VALUE)obj, table);
+ CFDictionaryRemoveValue(__os_finalizers, (const void *)obj);
+ }
+ }
+}
+
+static void
+__rb_objc_finalize(void *obj, void *data)
+{
+ //printf("finalize %p <%s>\n",obj, class_getName(*(Class *)obj));
+ if (rb_objc_is_non_native((VALUE)obj)) {
+ static SEL sel = NULL;
+ long flag;
+ flag = rb_objc_remove_flags(obj);
+ if ((flag & FL_FINALIZE) == FL_FINALIZE)
+ rb_call_os_finalizer(obj);
+ if ((flag & FL_EXIVAR) == FL_EXIVAR)
+ rb_free_generic_ivar((VALUE)obj);
+ if (sel == NULL)
+ sel = sel_registerName("finalize");
+ objc_msgSend(obj, sel);
+ }
+ else {
+ if (FL_TEST(obj, FL_FINALIZE))
+ rb_call_os_finalizer(obj);
+ if (FL_TEST(obj, FL_EXIVAR))
+ rb_free_generic_ivar((VALUE)obj);
+ }
+}
+
+static void
+rb_objc_batch_invalidate(auto_zone_t *zone,
+ auto_zone_foreach_object_t foreach,
+ 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
+
void
Init_PreGC(void)
{
#if WITH_OBJC
+ auto_collection_control_t *control;
+
__auto_zone = auto_zone();
//auto_zone_register_thread(__auto_zone);
- finalizer_table = st_init_strtable();
- GC_ROOT(&finalizer_table);
- auto_collection_parameters(__auto_zone)->scan_external_callout =
+
+ control = auto_collection_parameters(__auto_zone);
+ control->scan_external_callout =
rb_objc_scan_external_callout;
if (getenv("GC_DEBUG"))
- auto_collection_parameters(__auto_zone)->log =
- AUTO_LOG_COLLECTIONS | AUTO_LOG_REGIONS | AUTO_LOG_UNUSUAL;
+ control->log = AUTO_LOG_COLLECTIONS | AUTO_LOG_REGIONS
+ | AUTO_LOG_UNUSUAL;
+ old_batch_invalidate = control->batch_invalidate;
+ control->batch_invalidate = rb_objc_batch_invalidate;
#endif
}
@@ -2696,7 +3115,6 @@
Init_PostGC(void)
{
#if WITH_OBJC
- rb_objc_define_finalizer(rb_cIO);
# if 0
/* It is better to let Foundation start the dedicated collection thread
* when necessary.
@@ -2717,29 +3135,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/branches/testing/gem_prelude.rb
===================================================================
--- MacRuby/branches/testing/gem_prelude.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/gem_prelude.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/golf_prelude.rb
===================================================================
--- MacRuby/branches/testing/golf_prelude.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/golf_prelude.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/hash.c
===================================================================
--- MacRuby/branches/testing/hash.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/hash.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -32,6 +32,10 @@
}
VALUE rb_cHash;
+#if WITH_OBJC
+VALUE rb_cCFHash;
+VALUE rb_cHashRuby;
+#endif
static VALUE envtbl;
static ID id_hash, id_yield, id_default;
@@ -42,23 +46,28 @@
return (VALUE)rb_eql(args[0], args[1]);
}
-static int
+int
rb_any_cmp(VALUE a, VALUE b)
{
VALUE args[2];
if (a == b) return 0;
+ if (a == Qundef || b == Qundef) return -1;
if (FIXNUM_P(a) && FIXNUM_P(b)) {
return a != b;
}
+ if (SYMBOL_P(a) && SYMBOL_P(b)) {
+ return a != b;
+ }
+#if WITH_OBJC
+ if (TYPE(a) == T_STRING && TYPE(b) == T_STRING)
+ return rb_str_hash_cmp(a, b);
+#else
if (TYPE(a) == T_STRING && RBASIC(a)->klass == rb_cString &&
TYPE(b) == T_STRING && RBASIC(b)->klass == rb_cString) {
return rb_str_hash_cmp(a, b);
}
- if (a == Qundef || b == Qundef) return -1;
- if (SYMBOL_P(a) && SYMBOL_P(b)) {
- return a != b;
- }
+#endif
args[0] = a;
args[1] = b;
@@ -75,15 +84,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:
@@ -91,8 +101,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 = {
@@ -100,6 +116,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 {
@@ -134,6 +155,7 @@
}
}
+#if !WITH_OBJC
typedef int rb_foreach_func(VALUE, VALUE, VALUE);
struct hash_foreach_arg {
@@ -188,10 +210,30 @@
}
return Qnil;
}
+#endif
void
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
{
+#if WITH_OBJC
+ CFIndex i, count;
+ const void **keys;
+ const void **values;
+
+ count = CFDictionaryGetCount((CFDictionaryRef)hash);
+ if (count == 0)
+ return;
+
+ keys = (const void **)alloca(sizeof(void *) * count);
+ values = (const void **)alloca(sizeof(void *) * count);
+
+ CFDictionaryGetKeysAndValues((CFDictionaryRef)hash, keys, values);
+
+ for (i = 0; i < count; i++) {
+ if ((*func)((VALUE)keys[i], (VALUE)values[i], farg) != ST_CONTINUE)
+ break;
+ }
+#else
struct hash_foreach_arg arg;
if (!RHASH(hash)->ntbl)
@@ -201,25 +243,150 @@
arg.func = (rb_foreach_func *)func;
arg.arg = farg;
rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
+#endif
}
+#if WITH_OBJC
+
+# define HASH_KEY_CALLBACKS(h) \
+ ((CFDictionaryKeyCallBacks *)((uint8_t *)h + 52))
+
+static Boolean
+rb_cfdictionary_equal_cb(const void *v1, const void *v2)
+{
+ return v1 == v2 || !rb_any_cmp((VALUE)v1, (VALUE)v2);
+}
+
+static CFHashCode
+rb_cfdictionary_hash_cb(const void *v)
+{
+ return (CFHashCode)rb_any_hash((VALUE)v);
+}
+
+const void *
+rb_cfdictionary_retain_cb(CFAllocatorRef allocator, const void *v)
+{
+ rb_objc_retain(v);
+ return v;
+}
+
+void
+rb_cfdictionary_release_cb(CFAllocatorRef allocator, const void *v)
+{
+ rb_objc_release(v);
+}
+
+/* TODO optimize me */
+struct rb_objc_hash_struct {
+ VALUE ifnone;
+ bool has_proc_default;
+};
+
+/* This variable will always stay NULL, we only use its address. */
+static void *rb_objc_hash_assoc_key = NULL;
+
+static struct rb_objc_hash_struct *
+rb_objc_hash_get_struct(VALUE hash)
+{
+ return rb_objc_get_associative_ref((void *)hash, &rb_objc_hash_assoc_key);
+}
+
+static struct rb_objc_hash_struct *
+rb_objc_hash_get_struct2(VALUE hash)
+{
+ struct rb_objc_hash_struct *s;
+
+ s = rb_objc_hash_get_struct(hash);
+ if (s == NULL) {
+ s = xmalloc(sizeof(struct rb_objc_hash_struct));
+ rb_objc_set_associative_ref((void *)hash, &rb_objc_hash_assoc_key, s);
+ s->ifnone = Qnil;
+ s->has_proc_default = false;
+ }
+ return s;
+}
+
+static void
+rb_objc_hash_set_struct(VALUE hash, VALUE ifnone, bool has_proc_default)
+{
+ struct rb_objc_hash_struct *s;
+
+ s = rb_objc_hash_get_struct2(hash);
+
+ GC_WB(&s->ifnone, ifnone);
+ s->has_proc_default = has_proc_default;
+}
+#endif
+
static VALUE
hash_alloc(VALUE klass)
{
+#if WITH_OBJC
+ CFDictionaryKeyCallBacks keys_cb;
+ CFDictionaryValueCallBacks values_cb;
+ VALUE hash;
+
+ memset(&keys_cb, 0, sizeof(keys_cb));
+ keys_cb.retain = rb_cfdictionary_retain_cb;
+ keys_cb.release = rb_cfdictionary_release_cb;
+ keys_cb.equal = rb_cfdictionary_equal_cb;
+ keys_cb.hash = rb_cfdictionary_hash_cb;
+
+ memset(&values_cb, 0, sizeof(values_cb));
+ values_cb.retain = rb_cfdictionary_retain_cb;
+ values_cb.release = rb_cfdictionary_release_cb;
+ values_cb.equal = rb_cfdictionary_equal_cb;
+
+ hash = (VALUE)CFDictionaryCreateMutable(NULL, 0, &keys_cb, &values_cb);
+ if (klass != 0 && klass != rb_cHash && klass != rb_cHashRuby)
+ *(Class *)hash = RCLASS_OCID(klass);
+
+ CFMakeCollectable((CFTypeRef)hash);
+ rb_gc_malloc_increase(sizeof(void *));
+
+ return hash;
+#else
NEWOBJ(hash, struct RHash);
OBJSETUP(hash, klass, T_HASH);
hash->ifnone = Qnil;
return (VALUE)hash;
+#endif
}
VALUE
rb_hash_new(void)
{
+#if WITH_OBJC
+ return hash_alloc(0);
+#else
return hash_alloc(rb_cHash);
+#endif
}
+#if WITH_OBJC
+
+static inline void
+rb_hash_modify_check(VALUE hash)
+{
+ long mask;
+ mask = rb_objc_flag_get_mask(hash);
+ if (mask == 0) {
+ bool _CFDictionaryIsMutable(void *);
+ if (!_CFDictionaryIsMutable((void *)hash))
+ mask |= FL_FREEZE;
+ }
+ if ((mask & FL_FREEZE) == FL_FREEZE)
+ rb_raise(rb_eRuntimeError, "can't modify frozen/immutable hash");
+ if ((mask & FL_TAINT) == FL_TAINT && rb_safe_level() >= 4)
+ rb_raise(rb_eSecurityError, "Insecure: can't modify hash");
+}
+
+#define rb_hash_modify rb_hash_modify_check
+
+#else
+
static void
rb_hash_modify_check(VALUE hash)
{
@@ -243,7 +410,9 @@
rb_hash_modify_check(hash);
rb_hash_tbl(hash);
}
+#endif
+
/*
* call-seq:
* Hash.new => hash
@@ -289,12 +458,21 @@
if (argc > 0) {
rb_raise(rb_eArgError, "wrong number of arguments");
}
+#if WITH_OBJC
+ rb_objc_hash_set_struct(hash, rb_block_proc(), true);
+#else
RHASH(hash)->ifnone = rb_block_proc();
FL_SET(hash, HASH_PROC_DEFAULT);
+#endif
}
else {
rb_scan_args(argc, argv, "01", &ifnone);
+#if WITH_OBJC
+ if (ifnone != Qnil)
+ rb_objc_hash_set_struct(hash, ifnone, false);
+#else
RHASH(hash)->ifnone = ifnone;
+#endif
}
return hash;
@@ -322,10 +500,32 @@
if (argc == 1) {
tmp = rb_hash_s_try_convert(Qnil, argv[0]);
if (!NIL_P(tmp)) {
+#if WITH_OBJC
+ CFIndex i, count;
+ const void **keys;
+ const void **values;
+
hash = hash_alloc(klass);
+ count = CFDictionaryGetCount((CFDictionaryRef)tmp);
+ if (count == 0)
+ return;
+
+ keys = (const void **)alloca(sizeof(void *) * count);
+ values = (const void **)alloca(sizeof(void *) * count);
+
+ CFDictionaryGetKeysAndValues((CFDictionaryRef)tmp, keys, values);
+
+ for (i = 0; i < count; i++)
+ CFDictionarySetValue((CFMutableDictionaryRef)hash,
+ keys[i], values[i]);
+
+ return hash;
+#else
+ hash = hash_alloc(klass);
if (RHASH(argv[0])->ntbl) {
GC_WB(&RHASH(hash)->ntbl, st_copy(RHASH(argv[0])->ntbl));
}
+#endif
return hash;
}
@@ -335,11 +535,11 @@
hash = hash_alloc(klass);
for (i = 0; i < RARRAY_LEN(tmp); ++i) {
- VALUE v = rb_check_array_type(RARRAY_PTR(tmp)[i]);
-
+ VALUE v = rb_check_array_type(RARRAY_AT(tmp, i));
+
if (NIL_P(v)) continue;
if (RARRAY_LEN(v) < 1 || 2 < RARRAY_LEN(v)) continue;
- rb_hash_aset(hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]);
+ rb_hash_aset(hash, RARRAY_AT(v, 0), RARRAY_AT(v, 1));
}
return hash;
}
@@ -379,12 +579,14 @@
return rb_check_convert_type(hash, T_HASH, "Hash", "to_hash");
}
+#if !WITH_OBJC
static int
rb_hash_rehash_i(VALUE key, VALUE value, st_table *tbl)
{
if (key != Qundef) st_insert(tbl, key, value);
return ST_CONTINUE;
}
+#endif
/*
* call-seq:
@@ -409,6 +611,29 @@
static VALUE
rb_hash_rehash(VALUE hash)
{
+#if WITH_OBJC
+ CFIndex i, count;
+ const void **keys;
+ const void **values;
+
+ rb_hash_modify_check(hash);
+
+ count = CFDictionaryGetCount((CFDictionaryRef)hash);
+ if (count == 0)
+ return hash;
+
+ keys = (const void **)alloca(sizeof(void *) * count);
+ values = (const void **)alloca(sizeof(void *) * count);
+
+ CFDictionaryGetKeysAndValues((CFDictionaryRef)hash, keys, values);
+ CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
+
+ for (i = 0; i < count; i++)
+ CFDictionarySetValue((CFMutableDictionaryRef)hash,
+ (const void *)keys[i], (const void *)values[i]);
+
+ return hash;
+#else
st_table *tbl;
if (RHASH(hash)->iter_lev > 0) {
@@ -423,6 +648,7 @@
GC_WB(&RHASH(hash)->ntbl, tbl);
return hash;
+#endif
}
/*
@@ -444,9 +670,16 @@
{
VALUE val;
+#if WITH_OBJC
+ if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash, (const void *)key,
+ (const void **)&val)) {
+ return rb_funcall(hash, id_default, 1, key);
+ }
+#else
if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
return rb_funcall(hash, id_default, 1, key);
}
+#endif
return val;
}
@@ -455,9 +688,16 @@
{
VALUE val;
+#if WITH_OBJC
+ if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash, (const void *)key,
+ (const void **)&val)) {
+ return Qnil;
+ }
+#else
if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
return Qnil; /* without Hash#default */
}
+#endif
return val;
}
@@ -503,7 +743,12 @@
if (block_given && argc == 2) {
rb_warn("block supersedes default value argument");
}
+#if WITH_OBJC
+ if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash, (const void *)key,
+ (const void **)&val)) {
+#else
if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
+#endif
if (block_given) return rb_yield(key);
if (argc == 1) {
rb_raise(rb_eKeyError, "key not found");
@@ -530,21 +775,36 @@
* 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
*/
static VALUE
rb_hash_default(int argc, VALUE *argv, VALUE hash)
{
+#if WITH_OBJC
+ struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash);
VALUE key;
+ if (s == NULL || s->ifnone == Qnil)
+ return Qnil;
+
rb_scan_args(argc, argv, "01", &key);
+ if (s->has_proc_default) {
+ if (argc == 0) return Qnil;
+ return rb_funcall(s->ifnone, id_yield, 2, hash, key);
+ }
+ return s->ifnone;
+#else
+ VALUE key;
+
+ rb_scan_args(argc, argv, "01", &key);
if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
if (argc == 0) return Qnil;
return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, key);
}
return RHASH(hash)->ifnone;
+#endif
}
/*
@@ -571,9 +831,13 @@
rb_hash_set_default(VALUE hash, VALUE ifnone)
{
rb_hash_modify(hash);
+#if WITH_OBJC
+ rb_objc_hash_set_struct(hash, ifnone, false);
+#else
RHASH(hash)->ifnone = ifnone;
FL_UNSET(hash, HASH_PROC_DEFAULT);
return ifnone;
+#endif
}
/*
@@ -594,10 +858,17 @@
static VALUE
rb_hash_default_proc(VALUE hash)
{
+#if WITH_OBJC
+ struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash);
+ if (s != NULL && s->has_proc_default)
+ return s->ifnone;
+ return Qnil;
+#else
if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
return RHASH(hash)->ifnone;
}
return Qnil;
+#endif
}
static int
@@ -646,6 +917,16 @@
static VALUE
rb_hash_delete_key(VALUE hash, VALUE key)
{
+#if WITH_OBJC
+ VALUE val;
+ if (CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
+ (const void *)key, (const void **)&val)) {
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)hash,
+ (const void *)key);
+ return val;
+ }
+ return Qundef;
+#else
st_data_t ktmp = (st_data_t)key, val;
if (!RHASH(hash)->ntbl)
@@ -659,6 +940,7 @@
else if (st_delete(RHASH(hash)->ntbl, &ktmp, &val))
return (VALUE)val;
return Qundef;
+#endif
}
/*
@@ -730,9 +1012,34 @@
* h #=> {2=>"b", 3=>"c"}
*/
+#if WITH_OBJC
+static VALUE rb_hash_keys(VALUE);
+#endif
+
static VALUE
rb_hash_shift(VALUE hash)
{
+#if WITH_OBJC
+ VALUE keys, key, val;
+
+ keys = rb_hash_keys(hash);
+ if (RARRAY_LEN(keys) == 0) {
+ struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash);
+
+ if (s == NULL || s->ifnone == Qnil)
+ return Qnil;
+
+ if (s->has_proc_default)
+ return rb_funcall(s->ifnone, id_yield, 2, hash, Qnil);
+ return s->ifnone;
+ }
+
+ key = RARRAY_AT(keys, 0);
+ val = rb_hash_aref(hash, key);
+ rb_hash_delete(hash, key);
+
+ return rb_assoc_new(key, val);
+#else
struct shift_var var;
rb_hash_modify(hash);
@@ -752,6 +1059,7 @@
else {
return RHASH(hash)->ifnone;
}
+#endif
}
static int
@@ -779,6 +1087,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;
@@ -795,13 +1104,26 @@
VALUE
rb_hash_reject_bang(VALUE hash)
{
+#if WITH_OBJC
+ CFIndex n;
+
+ RETURN_ENUMERATOR(hash, 0, 0);
+ n = CFDictionaryGetCount((CFDictionaryRef)hash);
+ rb_hash_delete_if(hash);
+ if (n == CFDictionaryGetCount((CFDictionaryRef)hash))
+ return Qnil;
+ return hash;
+#else
int n;
+
+ RETURN_ENUMERATOR(hash, 0, 0);
if (!RHASH(hash)->ntbl)
return Qnil;
n = RHASH(hash)->ntbl->num_entries;
rb_hash_delete_if(hash);
if (n == RHASH(hash)->ntbl->num_entries) return Qnil;
return hash;
+#endif
}
/*
@@ -829,7 +1151,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)
@@ -895,6 +1217,9 @@
rb_hash_clear(VALUE hash)
{
rb_hash_modify_check(hash);
+#if WITH_OBJC
+ CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
+#else
if (!RHASH(hash)->ntbl)
return hash;
if (RHASH(hash)->ntbl->num_entries > 0) {
@@ -903,6 +1228,7 @@
else
st_clear(RHASH(hash)->ntbl);
}
+#endif
return hash;
}
@@ -929,12 +1255,18 @@
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
rb_hash_modify(hash);
- if (TYPE(key) != T_STRING || st_lookup(RHASH(hash)->ntbl, key, 0)) {
+#if WITH_OBJC
+ CFDictionarySetValue((CFMutableDictionaryRef)hash, (const void *)key,
+ (const void *)val);
+#else
+ 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 {
st_add_direct(RHASH(hash)->ntbl, rb_str_new4(key), val);
}
+#endif
return val;
}
@@ -967,6 +1299,13 @@
if (hash == hash2) return hash;
rb_hash_clear(hash);
rb_hash_foreach(hash2, replace_i, hash);
+#if WITH_OBJC
+ {
+ struct rb_objc_hash_struct *s = rb_objc_hash_get_struct(hash2);
+ if (s != NULL)
+ rb_objc_hash_set_struct(hash, s->ifnone, s->has_proc_default);
+ }
+#else
RHASH(hash)->ifnone = RHASH(hash2)->ifnone;
if (FL_TEST(hash2, HASH_PROC_DEFAULT)) {
FL_SET(hash, HASH_PROC_DEFAULT);
@@ -974,6 +1313,7 @@
else {
FL_UNSET(hash, HASH_PROC_DEFAULT);
}
+#endif
return hash;
}
@@ -994,9 +1334,13 @@
static VALUE
rb_hash_size(VALUE hash)
{
+#if WITH_OBJC
+ return INT2FIX(CFDictionaryGetCount((CFDictionaryRef)hash));
+#else
if (!RHASH(hash)->ntbl)
return INT2FIX(0);
return INT2FIX(RHASH(hash)->ntbl->num_entries);
+#endif
}
@@ -1129,7 +1473,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
@@ -1150,16 +1494,20 @@
VALUE str2;
if (key == Qundef) return ST_CONTINUE;
- if (RSTRING_LEN(str) > 1) {
+ if (RSTRING_CLEN(str) > 1) {
rb_str_cat2(str, ", ");
}
str2 = rb_inspect(key);
rb_str_buf_append(str, str2);
+#if !WITH_OBJC
OBJ_INFECT(str, str2);
+#endif
rb_str_buf_cat2(str, "=>");
str2 = rb_inspect(value);
rb_str_buf_append(str, str2);
+#if !WITH_OBJC
OBJ_INFECT(str, str2);
+#endif
return ST_CONTINUE;
}
@@ -1186,7 +1534,7 @@
* 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
@@ -1261,7 +1609,7 @@
*
*/
-static VALUE
+VALUE
rb_hash_values(VALUE hash)
{
VALUE ary;
@@ -1290,11 +1638,17 @@
static VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
+#if WITH_OBJC
+ if (CFDictionaryContainsKey((CFDictionaryRef)hash, (const void *)key))
+ return Qtrue;
+#else
if (!RHASH(hash)->ntbl)
return Qfalse;
if (st_lookup(RHASH(hash)->ntbl, key, 0)) {
return Qtrue;
}
+#endif
+
return Qfalse;
}
@@ -1325,12 +1679,17 @@
static VALUE
rb_hash_has_value(VALUE hash, VALUE val)
{
+#if WITH_OBJC
+ return CFDictionaryContainsValue((CFDictionaryRef)hash, (const void *)val)
+ ? Qtrue : Qfalse;
+#else
VALUE data[2];
data[0] = Qfalse;
data[1] = val;
rb_hash_foreach(hash, rb_hash_search_value, (st_data_t)data);
return data[0];
+#endif
}
struct equal_data {
@@ -1386,8 +1745,13 @@
}
if (RHASH_SIZE(hash1) != RHASH_SIZE(hash2))
return Qfalse;
+#if WITH_OBJC
+ return CFEqual((CFTypeRef)hash1, (CFTypeRef)hash2) ? Qtrue : Qfalse;
+#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)))
@@ -1397,6 +1761,7 @@
data.tbl = RHASH(hash2)->ntbl;
data.eql = eql;
return rb_exec_recursive(recursive_eql, hash1, (VALUE)&data);
+#endif
}
/*
@@ -1438,6 +1803,7 @@
return hash_equal(hash1, hash2, Qtrue);
}
+#if !WITH_OBJC
static int
hash_i(VALUE key, VALUE val, int *hval)
{
@@ -1462,6 +1828,7 @@
rb_hash_foreach(hash, hash_i, (st_data_t)&hval);
return INT2FIX(hval);
}
+#endif
/*
* call-seq:
@@ -1471,11 +1838,13 @@
* will have the same hash code (and will compare using <code>eql?</code>).
*/
+#if !WITH_OBJC
static VALUE
rb_hash_hash(VALUE hash)
{
return rb_exec_recursive(recursive_hash, hash, 0);
}
+#endif
static int
rb_hash_invert_i(VALUE key, VALUE value, VALUE hash)
@@ -1493,7 +1862,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"}
*
*/
@@ -1541,6 +1910,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}
*/
@@ -1682,11 +2054,6 @@
return ary;
}
-static const struct st_hash_type identhash = {
- st_numcmp,
- st_numhash,
-};
-
/*
* call-seq:
* hsh.compare_by_identity => hsh
@@ -1707,9 +2074,13 @@
rb_hash_compare_by_id(VALUE hash)
{
rb_hash_modify(hash);
+#if WITH_OBJC
+ HASH_KEY_CALLBACKS(hash)->equal = NULL;
+#else
RHASH(hash)->ntbl->type = &identhash;
rb_hash_rehash(hash);
return hash;
+#endif
}
/*
@@ -1724,12 +2095,16 @@
static VALUE
rb_hash_compare_by_id_p(VALUE hash)
{
+#if WITH_OBJC
+ return HASH_KEY_CALLBACKS(hash)->equal == NULL ? Qtrue : Qfalse;
+#else
if (!RHASH(hash)->ntbl)
return Qfalse;
if (RHASH(hash)->ntbl->type == &identhash) {
return Qtrue;
}
return Qfalse;
+#endif
}
static int path_tainted = -1;
@@ -1771,12 +2146,12 @@
static VALUE
env_delete(VALUE obj, VALUE name)
{
- char *nam, *val;
+ const char *nam, *val;
rb_secure(4);
SafeStringValue(name);
- nam = RSTRING_PTR(name);
- if (strlen(nam) != RSTRING_LEN(name)) {
+ nam = RSTRING_CPTR(name);
+ if (strlen(nam) != RSTRING_CLEN(name)) {
rb_raise(rb_eArgError, "bad environment variable name");
}
val = getenv(nam);
@@ -1810,12 +2185,12 @@
static VALUE
rb_f_getenv(VALUE obj, VALUE name)
{
- char *nam, *env;
+ const char *nam, *env;
rb_secure(4);
SafeStringValue(name);
- nam = RSTRING_PTR(name);
- if (strlen(nam) != RSTRING_LEN(name)) {
+ nam = RSTRING_CPTR(name);
+ if (strlen(nam) != RSTRING_CLEN(name)) {
rb_raise(rb_eArgError, "bad environment variable name");
}
env = getenv(nam);
@@ -1841,7 +2216,7 @@
{
VALUE key, if_none;
long block_given;
- char *nam, *env;
+ const char *nam, *env;
rb_secure(4);
rb_scan_args(argc, argv, "11", &key, &if_none);
@@ -1850,8 +2225,8 @@
rb_warn("block supersedes default value argument");
}
SafeStringValue(key);
- nam = RSTRING_PTR(key);
- if (strlen(nam) != RSTRING_LEN(key)) {
+ nam = RSTRING_CPTR(key);
+ if (strlen(nam) != RSTRING_CLEN(key)) {
rb_raise(rb_eArgError, "bad environment variable name");
}
env = getenv(nam);
@@ -1872,7 +2247,7 @@
}
static void
-path_tainted_p(char *path)
+path_tainted_p(const char *path)
{
path_tainted = rb_path_check(path)?0:1;
}
@@ -1998,7 +2373,7 @@
static VALUE
env_aset(VALUE obj, VALUE nm, VALUE val)
{
- char *name, *value;
+ const char *name, *value;
if (rb_safe_level() >= 4) {
rb_raise(rb_eSecurityError, "can't change environment variable");
@@ -2009,11 +2384,11 @@
}
StringValue(nm);
StringValue(val);
- name = RSTRING_PTR(nm);
- value = RSTRING_PTR(val);
- if (strlen(name) != RSTRING_LEN(nm))
+ name = RSTRING_CPTR(nm);
+ value = RSTRING_CPTR(val);
+ if (strlen(name) != RSTRING_CLEN(nm))
rb_raise(rb_eArgError, "bad environment variable name");
- if (strlen(value) != RSTRING_LEN(val))
+ if (strlen(value) != RSTRING_CLEN(val))
rb_raise(rb_eArgError, "bad environment variable value");
ruby_setenv(name, value);
@@ -2064,7 +2439,7 @@
rb_secure(4);
keys = env_keys();
for (i=0; i<RARRAY_LEN(keys); i++) {
- rb_yield(RARRAY_PTR(keys)[i]);
+ rb_yield(RARRAY_AT(keys, i));
}
return ehash;
}
@@ -2099,7 +2474,7 @@
rb_secure(4);
values = env_values();
for (i=0; i<RARRAY_LEN(values); i++) {
- rb_yield(RARRAY_PTR(values)[i]);
+ rb_yield(RARRAY_AT(values, i));
}
return ehash;
}
@@ -2127,26 +2502,27 @@
FREE_ENVIRON(environ);
for (i=0; i<RARRAY_LEN(ary); i+=2) {
- rb_yield(rb_assoc_new(RARRAY_PTR(ary)[i], RARRAY_PTR(ary)[i+1]));
+ rb_yield(rb_assoc_new(RARRAY_AT(ary, i), RARRAY_AT(ary, i+1)));
}
return ehash;
}
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++) {
- VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
+ VALUE val = rb_f_getenv(Qnil, RARRAY_AT(keys, i));
if (!NIL_P(val)) {
- if (RTEST(rb_yield_values(2, RARRAY_PTR(keys)[i], val))) {
- FL_UNSET(RARRAY_PTR(keys)[i], FL_TAINT);
- env_delete(Qnil, RARRAY_PTR(keys)[i]);
+ if (RTEST(rb_yield_values(2, RARRAY_AT(keys, i), val))) {
+ FL_UNSET(RARRAY_AT(keys, i), FL_TAINT);
+ env_delete(Qnil, RARRAY_AT(keys, i));
del++;
}
}
@@ -2156,9 +2532,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;
}
@@ -2202,8 +2579,8 @@
return result;
}
-static VALUE
-env_clear(void)
+VALUE
+rb_env_clear(void)
{
volatile VALUE keys;
long i;
@@ -2211,9 +2588,9 @@
rb_secure(4);
keys = env_keys();
for (i=0; i<RARRAY_LEN(keys); i++) {
- VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
+ VALUE val = rb_f_getenv(Qnil, RARRAY_AT(keys, i));
if (!NIL_P(val)) {
- env_delete(Qnil, RARRAY_PTR(keys)[i]);
+ env_delete(Qnil, RARRAY_AT(keys, i));
}
}
return envtbl;
@@ -2319,7 +2696,7 @@
rb_secure(4);
s = StringValuePtr(key);
- if (strlen(s) != RSTRING_LEN(key))
+ if (strlen(s) != RSTRING_CLEN(key))
rb_raise(rb_eArgError, "bad environment variable name");
if (getenv(s)) return Qtrue;
return Qfalse;
@@ -2332,7 +2709,7 @@
rb_secure(4);
s = StringValuePtr(key);
- if (strlen(s) != RSTRING_LEN(key))
+ if (strlen(s) != RSTRING_CLEN(key))
rb_raise(rb_eArgError, "bad environment variable name");
e = getenv(s);
if (e) return rb_assoc_new(key, rb_tainted_str_new2(e));
@@ -2352,7 +2729,7 @@
char *s = strchr(*env, '=');
if (s++) {
long len = strlen(s);
- if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
+ if (RSTRING_CLEN(obj) == len && strncmp(s, RSTRING_CPTR(obj), len) == 0) {
FREE_ENVIRON(environ);
return Qtrue;
}
@@ -2376,7 +2753,7 @@
char *s = strchr(*env, '=');
if (s++) {
long len = strlen(s);
- if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
+ if (RSTRING_CLEN(obj) == len && strncmp(s, RSTRING_CPTR(obj), len) == 0) {
VALUE result = rb_assoc_new(rb_tainted_str_new(*env, s-*env-1), obj);
FREE_ENVIRON(environ);
return result;
@@ -2401,7 +2778,7 @@
char *s = strchr(*env, '=');
if (s++) {
long len = strlen(s);
- if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
+ if (RSTRING_CLEN(value) == len && strncmp(s, RSTRING_CPTR(value), len) == 0) {
str = env_str_new(*env, s-*env-1);
FREE_ENVIRON(environ);
return str;
@@ -2458,7 +2835,7 @@
char *s = strchr(*env, '=');
if (s) {
VALUE key = env_str_new(*env, s-*env);
- VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
+ VALUE val = env_str_new2(getenv(RSTRING_CPTR(key)));
env_delete(Qnil, key);
return rb_assoc_new(key, val);
}
@@ -2498,7 +2875,7 @@
rb_hash_foreach(hash, env_replace_i, keys);
for (i=0; i<RARRAY_LEN(keys); i++) {
- env_delete(env, RARRAY_PTR(keys)[i]);
+ env_delete(env, RARRAY_AT(keys, i));
}
return env;
}
@@ -2538,7 +2915,141 @@
*
*/
+#if WITH_OBJC
+
+#define NSCFDICTIONARY() RCLASS_OCID(rb_cCFHash)
+
+#define PREPARE_RCV(x) \
+ Class old = *(Class *)x; \
+ *(Class *)x = NSCFDICTIONARY();
+
+#define RESTORE_RCV(x) \
+ *(Class *)x = old;
+
+bool
+rb_objc_hash_is_pure(VALUE ary)
+{
+ return *(Class *)ary == NSCFDICTIONARY();
+}
+
+static CFIndex
+imp_rb_hash_count(void *rcv, SEL sel)
+{
+ CFIndex count;
+ PREPARE_RCV(rcv);
+ count = CFDictionaryGetCount((CFDictionaryRef)rcv);
+ RESTORE_RCV(rcv);
+ return count;
+}
+
+static void *
+imp_rb_hash_keyEnumerator(void *rcv, SEL sel)
+{
+ void *keys;
+ static SEL objectEnumerator = 0;
+ PREPARE_RCV(rcv);
+ keys = (void *)rb_hash_keys((VALUE)rcv);
+ RESTORE_RCV(rcv);
+ if (objectEnumerator == 0)
+ objectEnumerator = sel_registerName("objectEnumerator");
+ return objc_msgSend(keys, objectEnumerator);
+}
+
+static void *
+imp_rb_hash_objectForKey(void *rcv, SEL sel, void *key)
+{
+ void *obj;
+ PREPARE_RCV(rcv);
+ if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)rcv, (const void *)key,
+ (const void **)&obj)) {
+ obj = NULL;
+ }
+ RESTORE_RCV(rcv);
+ return obj;
+}
+
+static void
+imp_rb_hash_setObjectForKey(void *rcv, SEL sel, void *obj, void *key)
+{
+ PREPARE_RCV(rcv);
+ CFDictionarySetValue((CFMutableDictionaryRef)rcv, (const void *)key,
+ (const void *)obj);
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_hash_getObjectsAndKeys(void *rcv, SEL sel, void **objs, void **keys)
+{
+ PREPARE_RCV(rcv);
+ CFDictionaryGetKeysAndValues((CFDictionaryRef)rcv, (const void **)keys,
+ (const void **)objs);
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_hash_removeObjectForKey(void *rcv, SEL sel, void *key)
+{
+ PREPARE_RCV(rcv);
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)rcv, (const void *)key);
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_hash_removeAllObjects(void *rcv, SEL sel)
+{
+ PREPARE_RCV(rcv);
+ CFDictionaryRemoveAllValues((CFMutableDictionaryRef)rcv);
+ RESTORE_RCV(rcv);
+}
+
+static bool
+imp_rb_hash_isEqual(void *rcv, SEL sel, void *other)
+{
+ bool res;
+ PREPARE_RCV(rcv);
+ res = CFEqual((CFTypeRef)rcv, (CFTypeRef)other);
+ RESTORE_RCV(rcv);
+ return res;
+}
+
+static bool
+imp_rb_hash_containsObject(void *rcv, SEL sel, void *obj)
+{
+ bool res;
+ PREPARE_RCV(rcv);
+ res = CFDictionaryContainsValue((CFTypeRef)rcv, (const void *)obj);
+ RESTORE_RCV(rcv);
+ return res;
+}
+
void
+rb_objc_install_hash_primitives(Class klass)
+{
+#define INSTALL_METHOD(selname, imp) \
+ do { \
+ SEL sel = sel_registerName(selname); \
+ Method method = class_getInstanceMethod(klass, sel); \
+ assert(method != NULL); \
+ assert(class_addMethod(klass, sel, (IMP)imp, \
+ method_getTypeEncoding(method))); \
+ } \
+ while(0)
+
+ INSTALL_METHOD("count", imp_rb_hash_count);
+ INSTALL_METHOD("keyEnumerator", imp_rb_hash_keyEnumerator);
+ INSTALL_METHOD("objectForKey:", imp_rb_hash_objectForKey);
+ INSTALL_METHOD("getObjects:andKeys:", imp_rb_hash_getObjectsAndKeys);
+ INSTALL_METHOD("setObject:forKey:", imp_rb_hash_setObjectForKey);
+ INSTALL_METHOD("removeObjectForKey:", imp_rb_hash_removeObjectForKey);
+ INSTALL_METHOD("removeAllObjects", imp_rb_hash_removeAllObjects);
+ INSTALL_METHOD("isEqual:", imp_rb_hash_isEqual);
+ INSTALL_METHOD("containsObject:", imp_rb_hash_containsObject);
+
+#undef INSTALL_METHOD
+}
+#endif
+
+void
Init_Hash(void)
{
id_hash = rb_intern("hash");
@@ -2546,8 +3057,11 @@
id_default = rb_intern("default");
#if WITH_OBJC
- rb_cHash = rb_define_class("Hash",
- rb_objc_import_class((Class)objc_getClass("NSMutableDictionary")));
+ rb_cCFHash = rb_objc_import_class((Class)objc_getClass("NSCFDictionary"));
+ rb_cHash = rb_objc_import_class((Class)objc_getClass("NSDictionary"));
+ rb_cHashRuby = rb_objc_import_class((Class)objc_getClass("NSMutableDictionary"));
+ FL_UNSET(rb_cHashRuby, RCLASS_OBJC_IMPORTED);
+ rb_const_set(rb_cObject, rb_intern("Hash"), rb_cHashRuby);
#else
rb_cHash = rb_define_class("Hash", rb_cObject);
#endif
@@ -2568,7 +3082,9 @@
rb_define_method(rb_cHash,"==", rb_hash_equal, 1);
rb_define_method(rb_cHash,"[]", rb_hash_aref, 1);
+#if !WITH_OBJC
rb_define_method(rb_cHash,"hash", rb_hash_hash, 0);
+#endif
rb_define_method(rb_cHash,"eql?", rb_hash_eql, 1);
rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1);
rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2);
@@ -2632,7 +3148,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/branches/testing/include/ruby/defines.h
===================================================================
--- MacRuby/branches/testing/include/ruby/defines.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/include/ruby/defines.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -283,6 +291,7 @@
# define MACOSX
# endif
# include <ffi/ffi.h>
+# include <CoreFoundation/CoreFoundation.h>
# define ASSERT_NO_OBJC() (assert(1 == 0))
void rb_objc_wb(void *dst, void *newval);
void rb_objc_root(void *addr);
Modified: MacRuby/branches/testing/include/ruby/encoding.h
===================================================================
--- MacRuby/branches/testing/include/ruby/encoding.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/include/ruby/encoding.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -17,6 +17,13 @@
#else
# include <varargs.h>
#endif
+
+#if WITH_OBJC
+
+typedef CFStringEncoding rb_encoding;
+
+#else
+
#include "ruby/oniguruma.h"
#define ENCODING_INLINE_MAX 1023
@@ -42,10 +49,12 @@
ENCODING_GET_INLINED(obj) : \
rb_enc_internal_get_index(obj))
-#define ENCODING_IS_ASCII8BIT(obj) (ENCODING_GET_INLINED(obj) == 0)
+#if WITH_OBJC
+# define ENCODING_IS_ASCII8BIT(obj) (1)
+#else
+# define ENCODING_IS_ASCII8BIT(obj) (ENCODING_GET_INLINED(obj) == 0)
+#endif
-#define ENCODING_MAXNAMELEN 42
-
#define ENC_CODERANGE_MASK (FL_USER8|FL_USER9)
#define ENC_CODERANGE_UNKNOWN 0
#define ENC_CODERANGE_7BIT FL_USER8
@@ -71,7 +80,10 @@
} while (0)
typedef OnigEncodingType rb_encoding;
+#endif
+#define ENCODING_MAXNAMELEN 42
+
int rb_enc_replicate(const char *, rb_encoding *);
int rb_define_dummy_encoding(const char *);
int rb_enc_dummy_p(rb_encoding *);
@@ -104,12 +116,26 @@
/* name -> rb_encoding */
rb_encoding * rb_enc_find(const char *name);
+#if WITH_OBJC
+rb_encoding * rb_enc_find2(VALUE name);
+#endif
+
/* encoding -> name */
+#if WITH_OBJC
+const char *rb_enc_name(rb_encoding *);
+VALUE rb_enc_name2(rb_encoding *);
+#else
#define rb_enc_name(enc) (enc)->name
+#endif
/* encoding -> minlen/maxlen */
+#if WITH_OBJC
+long rb_enc_mbminlen(rb_encoding *);
+long rb_enc_mbmaxlen(rb_encoding *);
+#else
#define rb_enc_mbminlen(enc) (enc)->min_enc_len
#define rb_enc_mbmaxlen(enc) (enc)->max_enc_len
+#endif
/* -> mbclen (no error notification: 0 < ret <= e-p, no exception) */
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc);
@@ -144,6 +170,17 @@
/* ptr, ptr, encoding -> newline_or_not */
#define rb_enc_is_newline(p,end,enc) ONIGENC_IS_MBC_NEWLINE(enc,(UChar*)(p),(UChar*)(end))
+#if WITH_OBJC
+#define rb_enc_isctype(c,t,enc) (iswctype(c,t))
+#define rb_enc_isascii(c,enc) (iswascii(c))
+#define rb_enc_isalpha(c,enc) (iswalpha(c))
+#define rb_enc_islower(c,enc) (iswlower(c))
+#define rb_enc_isupper(c,enc) (iswupper(c))
+#define rb_enc_isalnum(c,enc) (iswalnum(c))
+#define rb_enc_isprint(c,enc) (iswprint(c))
+#define rb_enc_isspace(c,enc) (iswspace(c))
+#define rb_enc_isdigit(c,enc) (iswdigit(c))
+#else
#define rb_enc_isctype(c,t,enc) ONIGENC_IS_CODE_CTYPE(enc,c,t)
#define rb_enc_isascii(c,enc) ONIGENC_IS_CODE_ASCII(c)
#define rb_enc_isalpha(c,enc) ONIGENC_IS_CODE_ALPHA(enc,c)
@@ -153,6 +190,7 @@
#define rb_enc_isprint(c,enc) ONIGENC_IS_CODE_PRINT(enc,c)
#define rb_enc_isspace(c,enc) ONIGENC_IS_CODE_SPACE(enc,c)
#define rb_enc_isdigit(c,enc) ONIGENC_IS_CODE_DIGIT(enc,c)
+#endif
#define rb_enc_asciicompat(enc) (!rb_enc_dummy_p(enc) && rb_enc_mbminlen(enc)==1)
@@ -176,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/branches/testing/include/ruby/intern.h
===================================================================
--- MacRuby/branches/testing/include/ruby/intern.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/include/ruby/intern.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -77,6 +77,12 @@
VALUE rb_ary_cmp(VALUE, VALUE);
VALUE rb_ary_replace(VALUE copy, VALUE orig);
VALUE rb_get_values_at(VALUE, long, int, VALUE*, VALUE(*)(VALUE,long));
+#if WITH_OBJC
+VALUE rb_ary_elt(VALUE, long);
+void rb_ary_set_named_args(VALUE, bool);
+bool rb_ary_is_named_args(VALUE);
+bool rb_objc_ary_is_pure(VALUE);
+#endif
/* bignum.c */
VALUE rb_big_clone(VALUE);
void rb_big_2comp(VALUE);
@@ -121,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);
@@ -215,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)
@@ -297,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 *);
@@ -314,10 +341,11 @@
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);
+void rb_objc_set_associative_ref(void *, void *, void *);
+void *rb_objc_get_associative_ref(void *, void *);
# define rb_gc_mark_locations(x,y)
# define rb_mark_tbl(x)
# define rb_mark_set(x)
@@ -345,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);
@@ -354,6 +383,10 @@
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
/* io.c */
#define rb_defout rb_stdout
RUBY_EXTERN VALUE rb_fs;
@@ -378,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);
@@ -445,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);
@@ -466,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);
@@ -482,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);
@@ -562,6 +602,9 @@
VALUE rb_str_intern(VALUE);
VALUE rb_sym_to_s(VALUE);
VALUE rb_str_length(VALUE);
+#if WITH_OBJC
+bool rb_objc_str_is_pure(VALUE);
+#endif
/* struct.c */
VALUE rb_struct_new(VALUE, ...);
VALUE rb_struct_define(const char*, ...);
@@ -651,6 +694,9 @@
VALUE rb_require_framework(int, VALUE *, VALUE);
VALUE rb_objc_resolve_const_value(VALUE, VALUE, ID);
ID rb_objc_missing_sel(ID mid, int arity);
+void rb_objc_install_ivar_cluster(Class);
+void *rb_objc_get_ivar_cluster(void *);
+void rb_objc_set_ivar_cluster(void *, void *);
#endif
/* version.c */
void ruby_show_version(void);
Modified: MacRuby/branches/testing/include/ruby/missing.h
===================================================================
--- MacRuby/branches/testing/include/ruby/missing.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/include/ruby/missing.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/include/ruby/node.h
===================================================================
--- MacRuby/branches/testing/include/ruby/node.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/include/ruby/node.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/include/ruby/ruby.h
===================================================================
--- MacRuby/branches/testing/include/ruby/ruby.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/include/ruby/ruby.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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,11 +380,17 @@
# 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))
/* obsolete API - use StringValue() */
-char *rb_str2cstr(VALUE,long*);
+const char *rb_str2cstr(VALUE,long*);
/* obsolete API - use StringValuePtr() */
#define STR2CSTR(x) rb_str2cstr((VALUE)(x),0)
@@ -389,14 +410,10 @@
if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\
} while (0)
#if WITH_OBJC
-void rb_objc_keep_for_exit_finalize(VALUE v);
# define OBJSETUP(obj,c,t) do {\
__OBJSETUP(obj,c,t);\
if (c != 0) \
RBASIC(obj)->isa = (void *)RCLASS_OCID(c); \
- if (!SPECIAL_CONST_P(obj) \
- && (BUILTIN_TYPE(obj) == T_FILE /*|| BUILTIN_TYPE(obj) == T_DATA*/)) \
- rb_objc_keep_for_exit_finalize((VALUE)obj); \
} while (0)
#else
# define OBJSETUP(obj,c,t) __OBJSETUP(obj,c,t)
@@ -484,6 +501,7 @@
#define ELTS_SHARED FL_USER2
+#if !WITH_OBJC
#define RSTRING_EMBED_LEN_MAX ((sizeof(VALUE)*3)/sizeof(char)-1)
struct RString {
struct RBasic basic;
@@ -499,20 +517,40 @@
char ary[RSTRING_EMBED_LEN_MAX];
} as;
};
-#define RSTRING_NOEMBED FL_USER1
-#define RSTRING_EMBED_LEN_MASK (FL_USER2|FL_USER3|FL_USER4|FL_USER5|FL_USER6)
-#define RSTRING_EMBED_LEN_SHIFT (FL_USHIFT+2)
-#define RSTRING_LEN(str) \
+# define RSTRING_NOEMBED FL_USER1
+# define RSTRING_EMBED_LEN_MASK (FL_USER2|FL_USER3|FL_USER4|FL_USER5|FL_USER6)
+# define RSTRING_EMBED_LEN_SHIFT (FL_USHIFT+2)
+# define RSTRING_LEN(str) \
(!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
(long)((RBASIC(str)->flags >> RSTRING_EMBED_LEN_SHIFT) & \
(RSTRING_EMBED_LEN_MASK >> RSTRING_EMBED_LEN_SHIFT)) : \
RSTRING(str)->as.heap.len)
-#define RSTRING_PTR(str) \
+# define RSTRING_PTR(str) \
(!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
RSTRING(str)->as.ary : \
RSTRING(str)->as.heap.ptr)
+#else
+/* IMPORTANT: try to avoid using RSTRING_PTR/RSTRING_LEN if necessary,
+ * because they can be slow operations in non-8bit strings.
+ * If you modify RSTRING_PTR, you need to call RSTRING_SYNC in order to
+ * synchronize its content with the real string storage.
+ * RSTRING_PTR/RSTRING_LEN deal with bytes. If you want to access a C string
+ * pointer, please use RSTRING_CPTR instead which is faster.
+ */
+char *rb_str_byteptr(VALUE);
+long rb_str_bytelen(VALUE);
+void rb_str_bytesync(VALUE);
+const char *rb_str_cstr(VALUE);
+long rb_str_clen(VALUE);
+# define RSTRING_PTR(str) (rb_str_byteptr((VALUE)str))
+# define RSTRING_LEN(str) (rb_str_bytelen((VALUE)str))
+# define RSTRING_SYNC(str) (rb_str_bytesync((VALUE)str))
+# define RSTRING_CPTR(str) (rb_str_cstr((VALUE)str))
+# define RSTRING_CLEN(str) (rb_str_clen((VALUE)str))
+#endif
#define RSTRING_END(str) (RSTRING_PTR(str)+RSTRING_LEN(str))
+#if !WITH_OBJC
struct RArray {
struct RBasic basic;
long len;
@@ -522,10 +560,18 @@
} aux;
VALUE *ptr;
};
-#define RARRAY_LEN(a) RARRAY(a)->len
-#define RARRAY_PTR(a) RARRAY(a)->ptr
-#if WITH_OBJC
-# define RARRAY_NAMED_ARGS FL_USER1
+# define RARRAY_LEN(a) RARRAY(a)->len
+# define RARRAY_PTR(a) RARRAY(a)->ptr
+# define RARRAY_AT(a,i) RARRAY_PTR(a)[i]
+#else
+# define RARRAY_LEN(a) (CFArrayGetCount((CFArrayRef)a))
+/* IMPORTANT: try to avoid using RARRAY_PTR if necessary, because it's
+ * a _much_ slower operation than RARRAY_AT. RARRAY_PTR is only provided for
+ * compatibility but should _not_ be used intensively.
+ */
+const VALUE *rb_ary_ptr(VALUE);
+# define RARRAY_PTR(a) (rb_ary_ptr((VALUE)a))
+# define RARRAY_AT(a,i) ((VALUE)CFArrayGetValueAtIndex((CFArrayRef)a, (long)i))
#endif
struct RRegexp {
@@ -535,6 +581,7 @@
char *str;
};
+#if !WITH_OBJC
struct RHash {
struct RBasic basic;
struct st_table *ntbl; /* possibly 0 */
@@ -542,10 +589,13 @@
VALUE ifnone;
};
/* RHASH_TBL allocates st_table if not available. */
-#define RHASH_TBL(h) rb_hash_tbl(h)
-#define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev)
-#define RHASH_IFNONE(h) (RHASH(h)->ifnone)
-#define RHASH_SIZE(h) (RHASH(h)->ntbl ? RHASH(h)->ntbl->num_entries : 0)
+# define RHASH_TBL(h) rb_hash_tbl(h)
+# define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev)
+# define RHASH_IFNONE(h) (RHASH(h)->ifnone)
+# define RHASH_SIZE(h) (RHASH(h)->ntbl ? RHASH(h)->ntbl->num_entries : 0)
+#else
+# define RHASH_SIZE(h) (CFDictionaryGetCount((CFDictionaryRef)h))
+#endif
#define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0)
struct RFile {
@@ -553,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*);
@@ -634,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 : \
@@ -647,12 +710,17 @@
#define RFLOAT(obj) (R_CAST(RFloat)(obj))
#define RSTRING(obj) (R_CAST(RString)(obj))
#define RREGEXP(obj) (R_CAST(RRegexp)(obj))
-#define RARRAY(obj) (R_CAST(RArray)(obj))
-#define RHASH(obj) (R_CAST(RHash)(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
#define RDATA(obj) (R_CAST(RData)(obj))
#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
@@ -697,12 +765,23 @@
#define FL_UNSET(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags &= ~(f);} while (0)
#define FL_REVERSE(x,f) do {if (FL_ABLE(x)) RBASIC(x)->flags ^= (f);} while (0)
-#define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT)
-#define OBJ_TAINT(x) FL_SET((x), FL_TAINT)
+#if WITH_OBJC
+# define OBJ_TAINTED(x) (rb_obj_tainted((VALUE)x))
+# define OBJ_TAINT(x) (rb_obj_taint((VALUE)x))
+#else
+# define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT)
+# define OBJ_TAINT(x) FL_SET((x), FL_TAINT)
+#endif
+
#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT;} while (0)
-#define OBJ_FROZEN(x) FL_TEST((x), FL_FREEZE)
-#define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE)
+#if WITH_OBJC
+# define OBJ_FROZEN(x) (rb_obj_frozen_p((VALUE)x))
+# define OBJ_FREEZE(x) (rb_obj_freeze((VALUE)x))
+#else
+# define OBJ_FROZEN(x) FL_TEST((x), FL_FREEZE)
+# define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE)
+#endif
#define ALLOC_N(type,n) (type*)xmalloc2((n),sizeof(type))
#define ALLOC(type) (type*)xmalloc(sizeof(type))
@@ -711,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 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);
@@ -841,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 *);
@@ -878,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;
@@ -892,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;
@@ -940,57 +1014,18 @@
RUBY_EXTERN VALUE rb_stdin, rb_stdout, rb_stderr;
#if WITH_OBJC
-/* We need to know if a given Objective-C class is either a metaclass
- * or a Ruby class. We could use the runtime API to do that but it's
- * unfortunately too slow, because these are C function calls. Instead we
- * directly read the information in memory.
- */
-# if __OBJC2__
-# error ObjC 2.0 is not supported yet
-# else
-struct __FakeObjcClass {
- Class isa;
- Class super_class;
- const char *name;
- long version;
- long info;
- long instance_size;
- void *ivars;
- void *methodLists;
- void *cache;
- void *protocols;
-};
-# define __IS_NON_NATIVE_CLS(k) \
- (!((((struct __FakeObjcClass *)k)->info & CLS_META) == CLS_META) \
- && ((struct __FakeObjcClass *)k)->version != ruby_version_code)
-# endif
-# define OCCLASS_WEAK_COPY_METHODS(src, dest) \
- do { \
- ((struct __FakeObjcClass *)src)->methodLists = \
- ((struct __FakeObjcClass *)dest)->methodLists; \
- } \
- while (0)
-extern const int ruby_version_code;
static inline unsigned
rb_objc_is_non_native(VALUE obj)
{
void *isa = RBASIC(obj)->isa;
-#if 0
- return isa != NULL ? __IS_NON_NATIVE_CLS(isa) : 0;
-#else
- if (isa == NULL
- || (rb_cString != 0 && isa == RCLASS_OCID(rb_cString))
- || (rb_cArray != 0 && isa == RCLASS_OCID(rb_cArray))
- || (rb_cHash != 0 && isa == RCLASS_OCID(rb_cHash))
- || class_isMetaClass(isa))
+ if (isa == NULL || class_isMetaClass(isa))
return 0;
while (isa != NULL) {
- if (isa == RCLASS(rb_cObject)->ocklass)
+ if (rb_cObject != 0 && isa == RCLASS_OCID(rb_cObject))
return 0;
isa = (void *)class_getSuperclass(isa);
}
return 1;
-#endif
}
#endif
@@ -1007,6 +1042,15 @@
if (obj == Qfalse) return rb_cFalseClass;
}
#if WITH_OBJC
+ extern VALUE rb_cCFString;
+ extern VALUE rb_cCFArray;
+ extern VALUE rb_cCFHash;
+ if (rb_cCFString != 0 && *(Class *)obj == RCLASS_OCID(rb_cCFString))
+ return rb_cCFString;
+ if (rb_cCFArray != 0 && *(Class *)obj == RCLASS_OCID(rb_cCFArray))
+ return rb_cCFArray;
+ if (rb_cCFHash != 0 && *(Class *)obj == RCLASS_OCID(rb_cCFHash))
+ return rb_cCFHash;
VALUE rb_objc_import_class(Class);
if (rb_objc_is_non_native(obj))
return rb_objc_import_class(RBASIC(obj)->isa);
@@ -1027,6 +1071,23 @@
if (obj == Qnil) return T_NIL;
if (obj == Qfalse) return T_FALSE;
}
+#if WITH_OBJC
+ /* FIXME this is super slow */
+ else if (rb_cHash != 0
+ && rb_cArray != 0
+ && rb_cString != 0) {
+ Class k = *(Class *)obj;
+ while (k != NULL) {
+ if (k == RCLASS_OCID(rb_cHash))
+ return T_HASH;
+ if (k == RCLASS_OCID(rb_cArray))
+ return T_ARRAY;
+ if (k == RCLASS_OCID(rb_cString))
+ return T_STRING;
+ k = class_getSuperclass(k);
+ }
+ }
+#endif
return BUILTIN_TYPE(obj);
}
Modified: MacRuby/branches/testing/include/ruby/win32.h
===================================================================
--- MacRuby/branches/testing/include/ruby/win32.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/include/ruby/win32.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/inits.c
===================================================================
--- MacRuby/branches/testing/inits.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/inits.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/insns.def
===================================================================
--- MacRuby/branches/testing/insns.def 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/insns.def 2008-05-28 20:03:03 UTC (rev 233)
@@ -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_PTR(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
@@ -439,7 +436,7 @@
(VALUE val) // inc += 1 - num;
{
val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num));
- FL_SET(val, RARRAY_NAMED_ARGS);
+ rb_ary_set_named_args(val, true);
POPN(num);
}
@@ -464,7 +461,7 @@
(VALUE val)
{
val = rb_ary_dup(ary);
- FL_SET(val, RARRAY_NAMED_ARGS);
+ rb_ary_set_named_args(val, true);
}
/**
@@ -557,7 +554,7 @@
/* NODE_CASE */
for (i = 0; i < RARRAY_LEN(ary); i++) {
/* TODO: fix me (use another method dispatch) */
- if (RTEST(rb_funcall2(RARRAY_PTR(ary)[i], idEqq, 1, &obj))) {
+ if (RTEST(rb_funcall2(RARRAY_AT(ary, i), idEqq, 1, &obj))) {
result = Qtrue;
break;
}
@@ -567,7 +564,7 @@
obj = Qfalse;
/* NODE_WHEN */
for (i = 0; i < RARRAY_LEN(ary); i++) {
- if (RTEST(RARRAY_PTR(ary)[i])) {
+ if (RTEST(RARRAY_AT(ary, i))) {
obj = result = Qtrue;
break;
}
@@ -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);
@@ -1330,7 +1324,13 @@
}
else {
VALUE val;
+#if WITH_OBJC
+ if (CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
+ (const void *)key,
+ (const void **)&val)) {
+#else
if (st_lookup(RHASH_TBL(hash), key, &val)) {
+#endif
JUMP(FIX2INT(val));
}
else {
Modified: MacRuby/branches/testing/instruby.rb
===================================================================
--- MacRuby/branches/testing/instruby.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/instruby.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -272,10 +276,13 @@
end
end
+$installing_rdoc = false
+
install?(:rdoc) do
if $rdocdir
puts "installing rdoc"
+ $installing_rdoc = true
ridatadir = File.join(CONFIG['datadir'], 'ri/$(MAJOR).$(MINOR).$(TEENY)/system')
Config.expand(ridatadir)
makedirs [ridatadir]
@@ -290,7 +297,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 +311,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 +334,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
@@ -424,6 +431,8 @@
Dir.glob(File.join(to, '**', '.svn')).each { |x| rm_rf(x) }
end
+unless $installing_rdoc
+
install_stuff('Xcode templates', 'misc/xcode-templates',
'/Library/Application Support/Developer/3.0/Xcode', 0755)
install_stuff('samples', 'sample-macruby',
@@ -431,6 +440,7 @@
if RUBY_FRAMEWORK
puts "installing framework"
+ # Creating framework infrastructure.
base = File.join(CONFIG["prefix"], '..')
resources = File.join(base, 'Resources')
mkdir_p resources, :mode => 0755
@@ -438,6 +448,8 @@
mkdir_p File.join(resources, 'English.lproj'), :mode => 0755
install File.join('framework/InfoPlist.strings'),
File.join(resources, 'English.lproj')
+ rm_f File.join(base, '..', 'Current') if
+ File.symlink?(with_destdir(File.join(base, '..', 'Current')))
ln_sfh MACRUBY_VERSION.to_s, File.join(base, '..', 'Current')
ln_sfh 'Versions/Current/Headers', File.join(base, '../../Headers')
ln_sfh 'Versions/Current/MacRuby', File.join(base, '../../MacRuby')
@@ -446,6 +458,7 @@
ln_sfh "usr/include/ruby-#{RUBY_VERSION}", File.join(base, 'Headers')
ln_sfh "../#{CONFIG['arch']}/ruby/config.h",
File.join(base, "usr/include/ruby-#{RUBY_VERSION}/ruby/config.h")
+ # Installing executable links.
dest_bin = '/usr/local/bin'
mkdir_p dest_bin, :mode => 0755
Dir.entries(CONFIG['bindir']).each do |bin|
@@ -454,6 +467,28 @@
link.sub!(/#{MACRUBY_VERSION}/, 'Current')
ln_sfh link, File.join(dest_bin, File.basename(bin))
end
+ # Installing man pages links.
+ dest_man = '/usr/local/share/man'
+ mkdir_p dest_man, :mode => 0755
+ Dir.entries(CONFIG['mandir']).each do |mandir|
+ next if mandir[0] == '.'
+ if File.stat(File.join(CONFIG['mandir'], mandir)).directory?
+ mkdir_p File.join(dest_man, File.basename(mandir)), :mode => 0755
+ Dir.entries(File.join(CONFIG['mandir'], mandir)).each do |man|
+ next if man[0] == '.'
+ link = File.join("../../../../../", CONFIG['mandir'], mandir, man)
+ link.sub!(/#{MACRUBY_VERSION}/, 'Current')
+ ln_sfh link, File.join(dest_man, File.basename(mandir),
+ File.basename(man))
+ end
+ else
+ link = File.join("../../../../", CONFIG['mandir'], mandir)
+ link.sub!(/#{MACRUBY_VERSION}/, 'Current')
+ ln_sfh link, File.join(dest_man, File.basename(mandir))
+ end
+ end
end
+end # unless $installing_rdoc
+
# vi:set sw=2:
Modified: MacRuby/branches/testing/io.c
===================================================================
--- MacRuby/branches/testing/io.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/io.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
@@ -323,7 +337,7 @@
fptr->rbuf_capa = len;
else
fptr->rbuf_capa = 8192;
- fptr->rbuf = ALLOC_N(char, fptr->rbuf_capa);
+ GC_WB(&fptr->rbuf, ALLOC_N(char, fptr->rbuf_capa));
}
if (fptr->rbuf_capa < len + fptr->rbuf_len) {
rb_raise(rb_eIOError, "ungetc failed");
@@ -464,6 +478,11 @@
io->fptr = 0;
+#if WITH_OBJC
+ void rb_objc_keep_for_exit_finalize(VALUE);
+ rb_objc_keep_for_exit_finalize((VALUE)io);
+#endif
+
return (VALUE)io;
}
@@ -474,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 &&
@@ -495,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)
{
@@ -517,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
@@ -529,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
@@ -568,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)) {
@@ -679,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));
}
}
@@ -695,7 +716,7 @@
fptr->wbuf_off = 0;
fptr->wbuf_len = 0;
fptr->wbuf_capa = 8192;
- fptr->wbuf = ALLOC_N(char, fptr->wbuf_capa);
+ GC_WB(&fptr->wbuf, ALLOC_N(char, fptr->wbuf_capa));
}
if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) ||
(fptr->wbuf && fptr->wbuf_capa <= fptr->wbuf_len + len)) {
@@ -798,7 +819,7 @@
return rb_funcall(io, id_write, 1, str);
}
io = tmp;
- if (RSTRING_LEN(str) == 0) return INT2FIX(0);
+ if (RSTRING_CLEN(str) == 0) return INT2FIX(0);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
@@ -1012,7 +1033,7 @@
fptr->rbuf_off = 0;
fptr->rbuf_len = 0;
fptr->rbuf_capa = 8192;
- fptr->rbuf = ALLOC_N(char, fptr->rbuf_capa);
+ GC_WB(&fptr->rbuf, ALLOC_N(char, fptr->rbuf_capa));
}
if (fptr->rbuf_len == 0) {
retry:
@@ -1278,9 +1299,10 @@
long len = RSTRING_LEN(str) - offset;
long n = len;
int c;
+ char *ptr = RSTRING_PTR(str);
while (n > 0) {
- c = read_buffered_data(RSTRING_PTR(str)+offset, n, fptr);
+ c = read_buffered_data(ptr+offset, n, fptr);
if (c > 0) {
offset += c;
if ((n -= c) <= 0) break;
@@ -1307,6 +1329,7 @@
str = rb_str_new(ptr, len);
n = io_fread(str, 0, &of);
MEMCPY(ptr, RSTRING_PTR(str), char, n);
+ RSTRING_SYNC(str);
return n;
}
@@ -1344,10 +1367,11 @@
io_enc_str(VALUE str, rb_io_t *fptr)
{
OBJ_TAINT(str);
+#if !WITH_OBJC
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));
}
@@ -1355,6 +1379,7 @@
/* just one encoding, so associate it with the string */
rb_enc_associate(str, io_read_encoding(fptr));
}
+#endif
return str;
}
@@ -1365,7 +1390,9 @@
long n;
long pos = 0;
rb_encoding *enc = io_input_encoding(fptr);
+#if !WITH_OBJC
int cr = fptr->enc2 ? ENC_CODERANGE_BROKEN : 0;
+#endif
if (siz == 0) siz = BUFSIZ;
if (NIL_P(str)) {
@@ -1378,20 +1405,25 @@
READ_CHECK(fptr);
n = io_fread(str, bytes, fptr);
if (n == 0 && bytes == 0) {
- break;
+ break;
}
bytes += n;
+#if !WITH_OBJC
if (cr != ENC_CODERANGE_BROKEN)
pos = rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
+#endif
if (bytes < siz) break;
siz += BUFSIZ;
rb_str_resize(str, siz);
}
if (bytes != siz) rb_str_resize(str, bytes);
str = io_enc_str(str, fptr);
+#if !WITH_OBJC
if (!fptr->enc2) {
ENC_CODERANGE_SET(str, cr);
}
+#endif
+ RSTRING_SYNC(str);
return str;
}
@@ -1468,6 +1500,7 @@
}
}
rb_str_resize(str, n);
+ RSTRING_SYNC(str);
if (n == 0)
return Qnil;
@@ -1501,7 +1534,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
@@ -1655,7 +1688,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);
@@ -1687,6 +1720,7 @@
return Qnil;
}
rb_str_resize(str, n);
+ RSTRING_SYNC(str);
return str;
}
@@ -1730,6 +1764,7 @@
RSTRING_PTR(str)[last++] = c;
}
if (limit > 0 && limit == pending) {
+#if !WITH_OBJC
char *p = fptr->rbuf+fptr->rbuf_off;
char *pp = p + limit;
char *pl = rb_enc_left_char_head(p, pp, enc);
@@ -1740,6 +1775,7 @@
limit = pending;
rb_str_set_len(str, RSTRING_LEN(str)-diff);
}
+#endif
}
read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
limit -= pending;
@@ -1808,7 +1844,9 @@
int len = 0;
long pos = 0;
rb_encoding *enc = io_input_encoding(fptr);
+#if !WITH_OBJC
int cr = fptr->enc2 ? ENC_CODERANGE_BROKEN : 0;
+#endif
for (;;) {
long pending = READ_DATA_PENDING_COUNT(fptr);
@@ -1831,8 +1869,10 @@
read_buffered_data(RSTRING_PTR(str)+len, pending, fptr);
}
len += pending;
+#if !WITH_OBJC
if (cr != ENC_CODERANGE_BROKEN)
pos = rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
+#endif
if (e) break;
}
rb_thread_wait_fd(fptr->fd);
@@ -1843,8 +1883,11 @@
}
}
+ RSTRING_SYNC(str);
str = io_enc_str(str, fptr);
+#if !WITH_OBJC
if (!fptr->enc2) ENC_CODERANGE_SET(str, cr);
+#endif
fptr->lineno++;
ARGF.lineno = INT2FIX(fptr->lineno);
return str;
@@ -1875,6 +1918,7 @@
}
}
if (!NIL_P(rs)) {
+#if !WITH_OBJC
rb_encoding *enc_rs, *enc_io;
GetOpenFile(io, fptr);
@@ -1895,13 +1939,14 @@
}
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))) {
rs = rs2;
}
}
+#endif
}
*rsp = rs;
*limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
@@ -1925,8 +1970,12 @@
else if (limit == 0) {
return rb_enc_str_new(0, 0, io_read_encoding(fptr));
}
- else if (rs == rb_default_rs && limit < 0 &&
- rb_enc_asciicompat(io_read_encoding(fptr))) {
+ else if (rs == rb_default_rs && limit < 0
+#if WITH_OBJC
+ ) {
+#else
+ && rb_enc_asciicompat(io_read_encoding(fptr))) {
+#endif
return rb_io_getline_fast(fptr);
}
else {
@@ -1951,12 +2000,14 @@
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;
+#if !WITH_OBJC
pp = rb_enc_left_char_head(s, p, enc);
if (pp != p) continue;
+#endif
if (!rspara) rscheck(rsptr, rslen, rs);
if (memcmp(p, rsptr, rslen) == 0) break;
}
@@ -2077,9 +2128,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
@@ -2226,46 +2277,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"
@@ -2275,8 +2451,6 @@
rb_io_getc(VALUE io)
{
rb_io_t *fptr;
- int r, n;
- VALUE str;
rb_encoding *enc;
GetOpenFile(io, fptr);
@@ -2284,38 +2458,8 @@
enc = io_input_encoding(fptr);
READ_CHECK(fptr);
- if (io_fillbuf(fptr) < 0) {
- return Qnil;
- }
- 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;
- }
- }
- }
- 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)
{
@@ -2429,19 +2573,21 @@
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 {
SafeStringValue(c);
@@ -2996,6 +3142,7 @@
}
rb_str_resize(str, n);
OBJ_TAINT(str);
+ RSTRING_SYNC(str);
return str;
}
@@ -3143,7 +3290,7 @@
return flags;
}
-static int
+int
rb_io_mode_modenum(const char *mode)
{
int flags = 0;
@@ -3217,11 +3364,24 @@
{
const char *p0, *p1;
char *enc2name;
+#if WITH_OBJC
+ rb_encoding *enc1, *enc2;
+#else
int idx, idx2;
-
+#endif
+
p0 = strrchr(estr, ':');
if (!p0) p1 = estr;
else p1 = p0 + 1;
+#if WITH_OBJC
+ enc1 = rb_enc_find(p1);
+ if (enc1 != NULL) {
+ fptr->enc = enc1;
+ }
+ else {
+ rb_warn("Unsupported encoding %s ignored", p1);
+ }
+#else
idx = rb_enc_find_index(p1);
if (idx >= 0) {
fptr->enc = rb_enc_from_index(idx);
@@ -3229,28 +3389,49 @@
else {
rb_warn("Unsupported encoding %s ignored", p1);
}
+#endif
if (p0) {
int n = p0 - estr;
if (n > ENCODING_MAXNAMELEN) {
+#if WITH_OBJC
+ enc2 = NULL;
+#else
idx2 = -1;
+#endif
}
else {
enc2name = ALLOCA_N(char, n+1);
memcpy(enc2name, estr, n);
enc2name[n] = '\0';
estr = enc2name;
+#if WITH_OBJC
+ enc2 = rb_enc_find(enc2name);
+#else
idx2 = rb_enc_find_index(enc2name);
+#endif
}
+#if WITH_OBJC
+ if (enc2 == NULL) {
+#else
if (idx2 < 0) {
+#endif
rb_warn("Unsupported encoding %.*s ignored", n, estr);
}
+#if WITH_OBJC
+ else if (enc1 == enc2) {
+#else
else if (idx2 == idx) {
+#endif
rb_warn("Ignoring internal encoding %.*s: it is identical to external encoding %s",
n, estr, p1);
}
else {
+#if WITH_OBJC
+ fptr->enc2 = enc2;
+#else
fptr->enc2 = rb_enc_from_index(idx2);
+#endif
}
}
}
@@ -3302,6 +3483,7 @@
rb_sys_fail(fname);
}
}
+ UPDATE_MAXFD(fd);
return fd;
}
@@ -3430,7 +3612,7 @@
struct pipe_list *list;
list = ALLOC(struct pipe_list);
- GC_GB(&list->fptr, fptr);
+ list->fptr = fptr;
list->next = pipe_list;
pipe_list = list;
}
@@ -3507,7 +3689,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];
@@ -3544,26 +3726,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;
@@ -3578,12 +3774,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;
@@ -3591,6 +3811,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]);
@@ -3598,29 +3819,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);
@@ -3675,6 +3905,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) {
@@ -3685,16 +3919,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
@@ -3727,27 +3971,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);
}
/*
@@ -3760,7 +4007,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.
*
@@ -3950,7 +4199,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".
@@ -3972,7 +4221,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.
*
@@ -4095,6 +4344,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;
@@ -4470,6 +4737,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);
}
@@ -4479,11 +4749,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_PTR(ary)[i];
- if (recur) {
- tmp = rb_str_new2("[...]");
- }
+ tmp = RARRAY_AT(ary, i);
rb_io_puts(1, &tmp, out);
}
return Qnil;
@@ -4547,8 +4819,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);
}
@@ -4627,10 +4902,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;
@@ -4763,6 +5040,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);
@@ -4906,19 +5184,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
@@ -4934,11 +5219,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);
@@ -4966,8 +5266,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
@@ -5104,7 +5404,7 @@
}
static VALUE
-argf_getline(int argc, VALUE *argv)
+argf_getline(int argc, VALUE *argv, VALUE argf)
{
VALUE line;
@@ -5149,6 +5449,8 @@
lineno = INT2FIX(n);
}
+static VALUE argf_gets(int, VALUE *, VALUE);
+
/*
* call-seq:
* gets(sep=$/) => string or nil
@@ -5183,11 +5485,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;
}
@@ -5198,7 +5509,7 @@
VALUE line;
if (rb_rs != rb_default_rs) {
- return rb_f_gets(0, 0);
+ return rb_f_gets(0, 0, argf);
}
retry:
@@ -5218,6 +5529,8 @@
return line;
}
+static VALUE argf_readline(int, VALUE *, VALUE);
+
/*
* call-seq:
* readline(sep=$/) => string
@@ -5229,13 +5542,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();
}
@@ -5243,6 +5565,8 @@
return line;
}
+static VALUE argf_readlines(int, VALUE *, VALUE);
+
/*
* call-seq:
* readlines(sep=$/) => array
@@ -5254,12 +5578,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);
}
@@ -5317,7 +5650,7 @@
if (!NIL_P(read)) {
Check_Type(read, T_ARRAY);
for (i=0; i<RARRAY_LEN(read); i++) {
- GetOpenFile(rb_io_get_io(RARRAY_PTR(read)[i]), fptr);
+ GetOpenFile(rb_io_get_io(RARRAY_AT(read, i)), fptr);
rb_fd_set(fptr->fd, &fds[0]);
if (READ_DATA_PENDING(fptr)) { /* check for buffered data */
pending++;
@@ -5337,7 +5670,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_PTR(write)[i]));
+ VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AT(write, i)));
GetOpenFile(write_io, fptr);
rb_fd_set(fptr->fd, &fds[1]);
if (max < fptr->fd) max = fptr->fd;
@@ -5350,7 +5683,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_PTR(except)[i]);
+ VALUE io = rb_io_get_io(RARRAY_AT(except, i));
VALUE write_io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_fd_set(fptr->fd, &fds[2]);
@@ -5382,7 +5715,7 @@
if (interrupt_flag == 0) {
if (rp) {
- list = RARRAY_PTR(res)[0];
+ list = RARRAY_AT(res, 0);
for (i=0; i< RARRAY_LEN(read); i++) {
VALUE obj = rb_ary_entry(read, i);
VALUE io = rb_io_get_io(obj);
@@ -5395,7 +5728,7 @@
}
if (wp) {
- list = RARRAY_PTR(res)[1];
+ list = RARRAY_AT(res, 1);
for (i=0; i< RARRAY_LEN(write); i++) {
VALUE obj = rb_ary_entry(write, i);
VALUE io = rb_io_get_io(obj);
@@ -5408,7 +5741,7 @@
}
if (ep) {
- list = RARRAY_PTR(res)[2];
+ list = RARRAY_AT(res, 2);
for (i=0; i< RARRAY_LEN(except); i++) {
VALUE obj = rb_ary_entry(except, i);
VALUE io = rb_io_get_io(obj);
@@ -5859,6 +6192,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]);
@@ -5929,23 +6263,18 @@
rb_ary_push(args, argv[0]);
rb_ary_concat(args, v);
MEMCPY(RARRAY_PTR(args)+1, RARRAY_PTR(v), VALUE, RARRAY_LEN(v));
-
- arg->io = rb_f_open(RARRAY_LEN(args), RARRAY_PTR(args));
+
+ 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;
@@ -6090,9 +6419,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.
@@ -6192,7 +7052,7 @@
}
static VALUE
-argf_tell(void)
+argf_tell(VALUE argf)
{
if (!next_argv()) {
rb_raise(rb_eArgError, "no stream to tell");
@@ -6202,7 +7062,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");
@@ -6212,7 +7072,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");
@@ -6222,7 +7082,7 @@
}
static VALUE
-argf_rewind(void)
+argf_rewind(VALUE argf)
{
if (!next_argv()) {
rb_raise(rb_eArgError, "no stream to rewind");
@@ -6232,7 +7092,7 @@
}
static VALUE
-argf_fileno(void)
+argf_fileno(VALUE argf)
{
if (!next_argv()) {
rb_raise(rb_eArgError, "no stream");
@@ -6242,7 +7102,7 @@
}
static VALUE
-argf_to_io(void)
+argf_to_io(VALUE argf)
{
next_argv();
ARGF_FORWARD(0, 0);
@@ -6250,7 +7110,7 @@
}
static VALUE
-argf_eof(void)
+argf_eof(VALUE argf)
{
if (current_file) {
if (init_p == 0) return Qtrue;
@@ -6363,13 +7223,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 {
@@ -6385,7 +7245,7 @@
}
static VALUE
-argf_getbyte(void)
+argf_getbyte(VALUE argf)
{
VALUE ch;
@@ -6407,7 +7267,7 @@
}
static VALUE
-argf_readchar(void)
+argf_readchar(VALUE argf)
{
VALUE ch;
@@ -6429,12 +7289,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();
}
@@ -6442,15 +7302,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
@@ -6465,6 +7325,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();
@@ -6551,9 +7422,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;
@@ -6597,8 +7468,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
@@ -6700,6 +7569,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);
@@ -6734,6 +7604,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);
@@ -6761,8 +7632,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);
@@ -6827,11 +7700,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);
@@ -6843,13 +7715,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);
@@ -6859,13 +7732,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);
@@ -6896,6 +7770,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/branches/testing/iseq.c
===================================================================
--- MacRuby/branches/testing/iseq.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/iseq.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -49,8 +49,8 @@
if (ptr) {
iseq = ptr;
/* It's possible that strings are freed
- * GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name),
- * RSTRING_PTR(iseq->filename));
+ * GC_INFO("%s @ %s\n", RSTRING_CPTR(iseq->name),
+ * RSTRING_CPTR(iseq->filename));
*/
if (iseq->iseq != iseq->iseq_encoded) {
RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
@@ -75,7 +75,7 @@
if (ptr) {
iseq = ptr;
- RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
+ RUBY_GC_INFO("%s @ %s\n", RSTRING_CPTR(iseq->name), RSTRING_CPTR(iseq->filename));
RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
RUBY_MARK_UNLESS_NULL(iseq->name);
RUBY_MARK_UNLESS_NULL(iseq->filename);
@@ -186,7 +186,7 @@
sizeof(struct iseq_compile_data_storage));
GC_WB(&iseq->compile_data->storage_head, iseq->compile_data->storage_head);
- iseq->compile_data->catch_table_ary = rb_ary_new();
+ GC_WB(&iseq->compile_data->catch_table_ary, rb_ary_new());
iseq->compile_data->storage_head->pos = 0;
iseq->compile_data->storage_head->next = 0;
iseq->compile_data->storage_head->size =
@@ -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);
@@ -533,7 +543,7 @@
rb_iseq_t *iseq = iseq_check(self);
snprintf(buff, sizeof(buff), "<ISeq:%s@%s>",
- RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
+ RSTRING_CPTR(iseq->name), RSTRING_CPTR(iseq->filename));
return rb_str_new2(buff);
}
@@ -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);
@@ -745,7 +756,7 @@
int line_no = find_line_no(iseqdat, pos);
int prev = find_prev_line_no(iseqdat, pos);
if (line_no && line_no != prev) {
- snprintf(buff, sizeof(buff), "%-70s(%4d)", RSTRING_PTR(str),
+ snprintf(buff, sizeof(buff), "%-70s(%4d)", RSTRING_CPTR(str),
line_no);
str = rb_str_new2(buff);
}
@@ -754,7 +765,7 @@
/* for debug */
struct iseq_insn_info_entry *entry = get_insn_info(iseqdat, pos);
snprintf(buff, sizeof(buff), "%-60s(line: %d, sp: %d)",
- RSTRING_PTR(str), entry->line_no, entry->sp);
+ RSTRING_CPTR(str), entry->line_no, entry->sp);
str = rb_str_new2(buff);
}
@@ -763,7 +774,7 @@
rb_str_concat(ret, str);
}
else {
- printf("%s\n", RSTRING_PTR(str));
+ printf("%s\n", RSTRING_CPTR(str));
}
return len;
}
@@ -811,9 +822,10 @@
rb_str_cat2(str, "== disasm: ");
rb_str_concat(str, iseq_inspect(iseqdat->self));
- if ((i = RSTRING_LEN(str)) < header_minlen) {
+ if ((i = RSTRING_CLEN(str)) < header_minlen) {
rb_str_resize(str, header_minlen);
memset(RSTRING_PTR(str) + i, '=', header_minlen - i);
+ RSTRING_SYNC(str);
}
rb_str_cat2(str, "\n");
@@ -1166,7 +1178,7 @@
body = rb_ary_new();
for (i=0, pos=0; i<RARRAY_LEN(nbody); i++) {
- VALUE ary = RARRAY_PTR(nbody)[i];
+ VALUE ary = RARRAY_AT(nbody, i);
VALUE label;
if (st_lookup(labels_table, pos, &label)) {
Modified: MacRuby/branches/testing/lib/cgi.rb
===================================================================
--- MacRuby/branches/testing/lib/cgi.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/cgi.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/complex.rb
===================================================================
--- MacRuby/branches/testing/lib/complex.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/complex.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/csv.rb
===================================================================
--- MacRuby/branches/testing/lib/csv.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/csv.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/date.rb
===================================================================
--- MacRuby/branches/testing/lib/date.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/date.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/debug.rb
===================================================================
--- MacRuby/branches/testing/lib/debug.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/debug.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/drb/drb.rb
===================================================================
--- MacRuby/branches/testing/lib/drb/drb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/drb/drb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/erb.rb
===================================================================
--- MacRuby/branches/testing/lib/erb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/erb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/getoptlong.rb
===================================================================
--- MacRuby/branches/testing/lib/getoptlong.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/getoptlong.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/ipaddr.rb
===================================================================
--- MacRuby/branches/testing/lib/ipaddr.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/ipaddr.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/irb/cmd/help.rb
===================================================================
--- MacRuby/branches/testing/lib/irb/cmd/help.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/irb/cmd/help.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/irb/init.rb
===================================================================
--- MacRuby/branches/testing/lib/irb/init.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/irb/init.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -240,6 +240,7 @@
yield proc{|rc| home+"/irb#{rc.sub(/\A_?/, '.')}"}
yield proc{|rc| home+"/_irb#{rc}"}
yield proc{|rc| home+"/$irb#{rc}"}
+ yield proc{|rc| "/etc/irb#{rc}"}
end
# loading modules
Modified: MacRuby/branches/testing/lib/irb/workspace.rb
===================================================================
--- MacRuby/branches/testing/lib/irb/workspace.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/irb/workspace.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/irb.rb
===================================================================
--- MacRuby/branches/testing/lib/irb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/irb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/mathn.rb
===================================================================
--- MacRuby/branches/testing/lib/mathn.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/mathn.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/mkmf.rb
===================================================================
--- MacRuby/branches/testing/lib/mkmf.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/mkmf.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
@@ -763,7 +785,10 @@
def have_header(header, &b)
checking_for header do
if try_cpp(cpp_include(header), &b)
- $defs.push(format("-DHAVE_%s", header.tr("a-z./\055", "A-Z___")))
+ # FIXME: cannot use this in MacRuby yet
+ #$defs.push(format("-DHAVE_%s", header.tr("a-z./\055", "A-Z___")))
+ str = header.tr("a-z", "A-Z").tr("./\055", "_")
+ $defs.push(format("-DHAVE_%s", str))
true
else
false
@@ -945,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}
@@ -956,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}
@@ -999,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
@@ -1019,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 = []
@@ -1036,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
@@ -1057,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
@@ -1069,9 +1143,37 @@
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
- sym = header.tr("a-z./\055", "A-Z___")
+ # FIXME: cannot use this in MacRuby yet
+ #sym = header.tr("a-z./\055", "A-Z___")
+ sym = header.tr("a-z", "A-Z").tr("./\055", "_")
hdr = ["#ifndef #{sym}\n#define #{sym}\n"]
for line in $defs
case line
@@ -1136,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
@@ -1173,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
@@ -1207,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"
@@ -1283,6 +1393,7 @@
end
mk
end
+# :startdoc:
def dummy_makefile(srcdir)
configuration(srcdir) << <<RULES << CLEANINGS
@@ -1398,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
@@ -1629,6 +1744,8 @@
mfile.close if mfile
end
+# :stopdoc:
+
def init_mkmf(config = CONFIG)
$makefile_created = false
$arg_config = []
@@ -1682,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"}
@@ -1689,6 +1811,8 @@
end
end
+# :startdoc:
+
init_mkmf
$make = with_config("make-prog", ENV["MAKE"] || "make")
Modified: MacRuby/branches/testing/lib/net/http.rb
===================================================================
--- MacRuby/branches/testing/lib/net/http.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/net/http.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/net/pop.rb
===================================================================
--- MacRuby/branches/testing/lib/net/pop.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/net/pop.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/net/smtp.rb
===================================================================
--- MacRuby/branches/testing/lib/net/smtp.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/net/smtp.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/net/telnet.rb
===================================================================
--- MacRuby/branches/testing/lib/net/telnet.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/net/telnet.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/open3.rb
===================================================================
--- MacRuby/branches/testing/lib/open3.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/open3.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/pstore.rb
===================================================================
--- MacRuby/branches/testing/lib/pstore.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/pstore.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rational.rb
===================================================================
--- MacRuby/branches/testing/lib/rational.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rational.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/code_objects.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/code_objects.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/code_objects.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/generator/html.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/generator/html.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/generator/html.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/generator.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/generator.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/generator.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
Copied: MacRuby/branches/testing/lib/rdoc/markup/attribute_manager.rb (from rev 232, MacRuby/trunk/lib/rdoc/markup/attribute_manager.rb)
===================================================================
--- MacRuby/branches/testing/lib/rdoc/markup/attribute_manager.rb (rev 0)
+++ MacRuby/branches/testing/lib/rdoc/markup/attribute_manager.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,274 @@
+require 'rdoc/markup/inline'
+
+class RDoc::Markup::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)
+ RDoc::Markup::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 do |name|
+ current |= RDoc::Markup::Attribute.bitmap_for(name)
+ end
+
+ new_set.each do |name|
+ new |= RDoc::Markup::Attribute.bitmap_for(name)
+ end
+
+ 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 | RDoc::Markup::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 ArgumentError, "Word flags may not start with '<'" if
+ start[0,1] == '<'
+
+ bitmap = RDoc::Markup::Attribute.bitmap_for name
+
+ if start == stop then
+ MATCHING_WORD_PAIRS[start] = bitmap
+ else
+ pattern = /(#{Regexp.escape start})(\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] = RDoc::Markup::Attribute.bitmap_for name
+ end
+
+ def add_special(pattern, name)
+ SPECIAL[pattern] = RDoc::Markup::Attribute.bitmap_for name
+ end
+
+ def flow(str)
+ @str = str
+
+ puts("Before flow, str='#{@str.dump}'") if $DEBUG_RDOC
+ mask_protected_sequences
+
+ @attrs = RDoc::Markup::AttrSpan.new @str.length
+
+ puts("After protecting, str='#{@str.dump}'") if $DEBUG_RDOC
+
+ convert_attrs(@str, @attrs)
+ convert_html(@str, @attrs)
+ convert_specials(str, @attrs)
+
+ unmask_protected_sequences
+
+ puts("After flow, str='#{@str.dump}'") if $DEBUG_RDOC
+
+ return split_into_flow
+ end
+
+ 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].chr == "\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 & RDoc::Markup::Attribute::SPECIAL) != 0 then
+ i += 1 while
+ i < str_len and (@attrs[i] & RDoc::Markup::Attribute::SPECIAL) != 0
+
+ res << RDoc::Markup::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].chr == "\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
+
Modified: MacRuby/branches/testing/lib/rdoc/markup/inline.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/markup/inline.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/markup/inline.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/markup/to_html.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/markup/to_html.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/markup/to_html.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/markup.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/markup.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/markup.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/options.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/options.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/options.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/parsers/parse_rb.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/parsers/parse_rb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/parsers/parse_rb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/rdoc.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/rdoc.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/rdoc.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/ri/descriptions.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/ri/descriptions.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/ri/descriptions.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/ri/display.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/ri/display.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/ri/display.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/ri/driver.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/ri/driver.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/ri/driver.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/ri/formatter.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/ri/formatter.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/ri/formatter.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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(/ /, ' ')}</td><td>}
+ %{<tr valign="top"><td>#{li.label.gsub(/ /, ' ')}</td><td>}
end
else
fail "unknown list type"
Modified: MacRuby/branches/testing/lib/rdoc/ri/util.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/ri/util.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/ri/util.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/ri/writer.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/ri/writer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/ri/writer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc/template.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc/template.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc/template.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rdoc.rb
===================================================================
--- MacRuby/branches/testing/lib/rdoc.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rdoc.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/resolv.rb
===================================================================
--- MacRuby/branches/testing/lib/resolv.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/resolv.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rexml/document.rb
===================================================================
--- MacRuby/branches/testing/lib/rexml/document.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rexml/document.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/builder.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/builder.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/builder.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/command_manager.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/command_manager.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/command_manager.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/cleanup_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/cleanup_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/cleanup_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/environment_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/environment_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/environment_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/fetch_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/fetch_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/fetch_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/install_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/install_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/install_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/list_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/list_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/list_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/mirror_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/mirror_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/mirror_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/pristine_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/pristine_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/pristine_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -126,6 +126,7 @@
end
installer.generate_bin
+ installer.build_extensions
end
end
Modified: MacRuby/branches/testing/lib/rubygems/commands/query_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/query_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/query_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/sources_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/sources_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/sources_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/specification_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/specification_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/specification_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/uninstall_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/uninstall_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/uninstall_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/unpack_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/unpack_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/unpack_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/commands/update_command.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/commands/update_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/commands/update_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/custom_require.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/custom_require.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/custom_require.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/defaults.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/defaults.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/defaults.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/dependency_installer.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/dependency_installer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/dependency_installer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/doc_manager.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/doc_manager.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/doc_manager.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/exceptions.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/exceptions.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/exceptions.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/format.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/format.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/format.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/indexer/abstract_index_builder.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/indexer/abstract_index_builder.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/indexer/abstract_index_builder.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/lib/rubygems/indexer/latest_index_builder.rb (from rev 232, MacRuby/trunk/lib/rubygems/indexer/latest_index_builder.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/indexer/latest_index_builder.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/indexer/latest_index_builder.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,35 @@
+require 'rubygems/indexer'
+
+##
+# Construct the latest Gem index file.
+
+class Gem::Indexer::LatestIndexBuilder < Gem::Indexer::AbstractIndexBuilder
+
+ def start_index
+ super
+
+ @index = Gem::SourceIndex.new
+ end
+
+ def end_index
+ super
+
+ latest = @index.latest_specs.sort.map { |spec| spec.original_name }
+
+ @file.write latest.join("\n")
+ end
+
+ def cleanup
+ super
+
+ compress @file.path
+
+ @files.delete 'latest_index' # HACK installed via QuickIndexBuilder :/
+ end
+
+ def add(spec)
+ @index.add_spec(spec)
+ end
+
+end
+
Modified: MacRuby/branches/testing/lib/rubygems/indexer/master_index_builder.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/indexer/master_index_builder.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/indexer/master_index_builder.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/indexer/quick_index_builder.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/indexer/quick_index_builder.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/indexer/quick_index_builder.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/indexer.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/indexer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/indexer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/install_update_options.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/install_update_options.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/install_update_options.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/installer.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/installer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/installer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/lib/rubygems/package (from rev 232, MacRuby/trunk/lib/rubygems/package)
Deleted: MacRuby/branches/testing/lib/rubygems/package/f_sync_dir.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/f_sync_dir.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package/f_sync_dir.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,24 +0,0 @@
-#++
-# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'rubygems/package'
-
-module Gem::Package::FSyncDir
-
- private
-
- ##
- # make sure this hits the disc
-
- def fsync_dir(dirname)
- 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
-
Copied: MacRuby/branches/testing/lib/rubygems/package/f_sync_dir.rb (from rev 232, MacRuby/trunk/lib/rubygems/package/f_sync_dir.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package/f_sync_dir.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/package/f_sync_dir.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,24 @@
+#++
+# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
+# See LICENSE.txt for additional licensing information.
+#--
+
+require 'rubygems/package'
+
+module Gem::Package::FSyncDir
+
+ private
+
+ ##
+ # make sure this hits the disc
+
+ def fsync_dir(dirname)
+ 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
+
Deleted: MacRuby/branches/testing/lib/rubygems/package/tar_header.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_header.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_header.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,245 +0,0 @@
-#++
-# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'rubygems/package'
-
-##
-#--
-# 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)
-# };
-#++
-
-class Gem::Package::TarHeader
-
- FIELDS = [
- :checksum,
- :devmajor,
- :devminor,
- :gid,
- :gname,
- :linkname,
- :magic,
- :mode,
- :mtime,
- :name,
- :prefix,
- :size,
- :typeflag,
- :uid,
- :uname,
- :version,
- ]
-
- PACK_FORMAT = 'a100' + # name
- 'a8' + # mode
- 'a8' + # uid
- 'a8' + # gid
- 'a12' + # size
- 'a12' + # mtime
- 'a7a' + # chksum
- 'a' + # typeflag
- 'a100' + # linkname
- 'a6' + # magic
- 'a2' + # version
- 'a32' + # uname
- 'a32' + # gname
- 'a8' + # devmajor
- 'a8' + # devminor
- 'a155' # prefix
-
- UNPACK_FORMAT = 'A100' + # name
- 'A8' + # mode
- 'A8' + # uid
- 'A8' + # gid
- 'A12' + # size
- 'A12' + # mtime
- 'A8' + # checksum
- 'A' + # typeflag
- 'A100' + # linkname
- 'A6' + # magic
- 'A2' + # version
- 'A32' + # uname
- 'A32' + # gname
- 'A8' + # devmajor
- 'A8' + # devminor
- 'A155' # prefix
-
- attr_reader(*FIELDS)
-
- def self.from(stream)
- header = stream.read 512
- empty = (header == "\0" * 512)
-
- fields = header.unpack UNPACK_FORMAT
-
- 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
-
- new :name => name,
- :mode => mode,
- :uid => uid,
- :gid => gid,
- :size => size,
- :mtime => mtime,
- :checksum => checksum,
- :typeflag => typeflag,
- :linkname => linkname,
- :magic => magic,
- :version => version,
- :uname => uname,
- :gname => gname,
- :devmajor => devmajor,
- :devminor => devminor,
- :prefix => prefix,
-
- :empty => empty
-
- # HACK unfactor for Rubinius
- #new :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 => empty
- end
-
- def initialize(vals)
- unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
- 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 do |name|
- instance_variable_set "@#{name}", vals[name]
- end
-
- @empty = vals[:empty]
- end
-
- def empty?
- @empty
- end
-
- def ==(other)
- self.class === other and
- @checksum == other.checksum and
- @devmajor == other.devmajor and
- @devminor == other.devminor and
- @gid == other.gid and
- @gname == other.gname and
- @linkname == other.linkname and
- @magic == other.magic and
- @mode == other.mode and
- @mtime == other.mtime and
- @name == other.name and
- @prefix == other.prefix and
- @size == other.size and
- @typeflag == other.typeflag and
- @uid == other.uid and
- @uname == other.uname and
- @version == other.version
- end
-
- def to_s
- update_checksum
- header
- end
-
- def update_checksum
- header = header " " * 8
- @checksum = oct calculate_checksum(header), 6
- end
-
- private
-
- def calculate_checksum(header)
- header.unpack("C*").inject { |a, b| a + b }
- end
-
- def header(checksum = @checksum)
- header = [
- name,
- oct(mode, 7),
- oct(uid, 7),
- oct(gid, 7),
- oct(size, 11),
- oct(mtime, 11),
- checksum,
- " ",
- typeflag,
- linkname,
- magic,
- oct(version, 2),
- uname,
- gname,
- oct(devmajor, 7),
- oct(devminor, 7),
- prefix
- ]
-
- header = header.pack PACK_FORMAT
-
- header << ("\0" * ((512 - header.size) % 512))
- end
-
- def oct(num, len)
- "%0#{len}o" % num
- end
-
-end
-
Copied: MacRuby/branches/testing/lib/rubygems/package/tar_header.rb (from rev 232, MacRuby/trunk/lib/rubygems/package/tar_header.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package/tar_header.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_header.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,245 @@
+#++
+# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
+# See LICENSE.txt for additional licensing information.
+#--
+
+require 'rubygems/package'
+
+##
+#--
+# 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)
+# };
+#++
+
+class Gem::Package::TarHeader
+
+ FIELDS = [
+ :checksum,
+ :devmajor,
+ :devminor,
+ :gid,
+ :gname,
+ :linkname,
+ :magic,
+ :mode,
+ :mtime,
+ :name,
+ :prefix,
+ :size,
+ :typeflag,
+ :uid,
+ :uname,
+ :version,
+ ]
+
+ PACK_FORMAT = 'a100' + # name
+ 'a8' + # mode
+ 'a8' + # uid
+ 'a8' + # gid
+ 'a12' + # size
+ 'a12' + # mtime
+ 'a7a' + # chksum
+ 'a' + # typeflag
+ 'a100' + # linkname
+ 'a6' + # magic
+ 'a2' + # version
+ 'a32' + # uname
+ 'a32' + # gname
+ 'a8' + # devmajor
+ 'a8' + # devminor
+ 'a155' # prefix
+
+ UNPACK_FORMAT = 'A100' + # name
+ 'A8' + # mode
+ 'A8' + # uid
+ 'A8' + # gid
+ 'A12' + # size
+ 'A12' + # mtime
+ 'A8' + # checksum
+ 'A' + # typeflag
+ 'A100' + # linkname
+ 'A6' + # magic
+ 'A2' + # version
+ 'A32' + # uname
+ 'A32' + # gname
+ 'A8' + # devmajor
+ 'A8' + # devminor
+ 'A155' # prefix
+
+ attr_reader(*FIELDS)
+
+ def self.from(stream)
+ header = stream.read 512
+ empty = (header == "\0" * 512)
+
+ fields = header.unpack UNPACK_FORMAT
+
+ 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
+
+ new :name => name,
+ :mode => mode,
+ :uid => uid,
+ :gid => gid,
+ :size => size,
+ :mtime => mtime,
+ :checksum => checksum,
+ :typeflag => typeflag,
+ :linkname => linkname,
+ :magic => magic,
+ :version => version,
+ :uname => uname,
+ :gname => gname,
+ :devmajor => devmajor,
+ :devminor => devminor,
+ :prefix => prefix,
+
+ :empty => empty
+
+ # HACK unfactor for Rubinius
+ #new :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 => empty
+ end
+
+ def initialize(vals)
+ unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
+ 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 do |name|
+ instance_variable_set "@#{name}", vals[name]
+ end
+
+ @empty = vals[:empty]
+ end
+
+ def empty?
+ @empty
+ end
+
+ def ==(other)
+ self.class === other and
+ @checksum == other.checksum and
+ @devmajor == other.devmajor and
+ @devminor == other.devminor and
+ @gid == other.gid and
+ @gname == other.gname and
+ @linkname == other.linkname and
+ @magic == other.magic and
+ @mode == other.mode and
+ @mtime == other.mtime and
+ @name == other.name and
+ @prefix == other.prefix and
+ @size == other.size and
+ @typeflag == other.typeflag and
+ @uid == other.uid and
+ @uname == other.uname and
+ @version == other.version
+ end
+
+ def to_s
+ update_checksum
+ header
+ end
+
+ def update_checksum
+ header = header " " * 8
+ @checksum = oct calculate_checksum(header), 6
+ end
+
+ private
+
+ def calculate_checksum(header)
+ header.unpack("C*").inject { |a, b| a + b }
+ end
+
+ def header(checksum = @checksum)
+ header = [
+ name,
+ oct(mode, 7),
+ oct(uid, 7),
+ oct(gid, 7),
+ oct(size, 11),
+ oct(mtime, 11),
+ checksum,
+ " ",
+ typeflag,
+ linkname,
+ magic,
+ oct(version, 2),
+ uname,
+ gname,
+ oct(devmajor, 7),
+ oct(devminor, 7),
+ prefix
+ ]
+
+ header = header.pack PACK_FORMAT
+
+ header << ("\0" * ((512 - header.size) % 512))
+ end
+
+ def oct(num, len)
+ "%0#{len}o" % num
+ end
+
+end
+
Deleted: MacRuby/branches/testing/lib/rubygems/package/tar_input.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_input.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_input.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,219 +0,0 @@
-#++
-# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'rubygems/package'
-
-class Gem::Package::TarInput
-
- include Gem::Package::FSyncDir
- include Enumerable
-
- attr_reader :metadata
-
- private_class_method :new
-
- def self.open(io, security_policy = nil, &block)
- is = new io, security_policy
-
- yield is
- ensure
- is.close if is
- end
-
- def initialize(io, security_policy = nil)
- @io = io
- @tarreader = Gem::Package::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
- 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 Gem::Package::FormatError, "No metadata found!" unless has_meta
- end
-
- def close
- @io.close
- @tarreader.close
- end
-
- def each(&block)
- @tarreader.each do |entry|
- next unless entry.full_name == "data.tar.gz"
- is = zipped_stream entry
-
- begin
- Gem::Package::TarReader.new is do |inner|
- inner.each(&block)
- end
- ensure
- is.close if is
- end
- end
-
- @tarreader.rewind
- end
-
- def extract_entry(destdir, entry, expected_md5sum = nil)
- if entry.directory? then
- dest = File.join(destdir, entry.full_name)
-
- if File.dir? dest then
- @fileops.chmod entry.header.mode, dest, :verbose=>false
- else
- @fileops.mkdir_p dest, :mode => entry.header.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
-
- open destfile, "wb", entry.header.mode do |os|
- loop do
- data = entry.read 4096
- break unless data
- # HACK shouldn't we check the MD5 before writing to disk?
- md5 << data if expected_md5sum
- os.write(data)
- end
-
- os.fsync
- end
-
- @fileops.chmod entry.header.mode, destfile, :verbose => false
- fsync_dir File.dirname(destfile)
- fsync_dir File.join(File.dirname(destfile), "..")
-
- if expected_md5sum && expected_md5sum != md5.hexdigest then
- raise Gem::Package::BadCheckSum
- end
- 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
-
- ##
- # 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
-
-end
-
Copied: MacRuby/branches/testing/lib/rubygems/package/tar_input.rb (from rev 232, MacRuby/trunk/lib/rubygems/package/tar_input.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package/tar_input.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_input.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,219 @@
+#++
+# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
+# See LICENSE.txt for additional licensing information.
+#--
+
+require 'rubygems/package'
+
+class Gem::Package::TarInput
+
+ include Gem::Package::FSyncDir
+ include Enumerable
+
+ attr_reader :metadata
+
+ private_class_method :new
+
+ def self.open(io, security_policy = nil, &block)
+ is = new io, security_policy
+
+ yield is
+ ensure
+ is.close if is
+ end
+
+ def initialize(io, security_policy = nil)
+ @io = io
+ @tarreader = Gem::Package::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
+ 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 Gem::Package::FormatError, "No metadata found!" unless has_meta
+ end
+
+ def close
+ @io.close
+ @tarreader.close
+ end
+
+ def each(&block)
+ @tarreader.each do |entry|
+ next unless entry.full_name == "data.tar.gz"
+ is = zipped_stream entry
+
+ begin
+ Gem::Package::TarReader.new is do |inner|
+ inner.each(&block)
+ end
+ ensure
+ is.close if is
+ end
+ end
+
+ @tarreader.rewind
+ end
+
+ def extract_entry(destdir, entry, expected_md5sum = nil)
+ if entry.directory? then
+ dest = File.join(destdir, entry.full_name)
+
+ if File.dir? dest then
+ @fileops.chmod entry.header.mode, dest, :verbose=>false
+ else
+ @fileops.mkdir_p dest, :mode => entry.header.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
+
+ open destfile, "wb", entry.header.mode do |os|
+ loop do
+ data = entry.read 4096
+ break unless data
+ # HACK shouldn't we check the MD5 before writing to disk?
+ md5 << data if expected_md5sum
+ os.write(data)
+ end
+
+ os.fsync
+ end
+
+ @fileops.chmod entry.header.mode, destfile, :verbose => false
+ fsync_dir File.dirname(destfile)
+ fsync_dir File.join(File.dirname(destfile), "..")
+
+ if expected_md5sum && expected_md5sum != md5.hexdigest then
+ raise Gem::Package::BadCheckSum
+ end
+ 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
+
+ ##
+ # 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
+
+end
+
Deleted: MacRuby/branches/testing/lib/rubygems/package/tar_output.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_output.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_output.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,143 +0,0 @@
-#++
-# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'rubygems/package'
-
-##
-# TarOutput is a wrapper to TarWriter that builds gem-format tar file.
-#
-# Gem-format tar files contain the following files:
-# [data.tar.gz] A gzipped tar file containing the files that compose the gem
-# which will be extracted into the gem/ dir on installation.
-# [metadata.gz] A YAML format Gem::Specification.
-# [data.tar.gz.sig] A signature for the gem's data.tar.gz.
-# [metadata.gz.sig] A signature for the gem's metadata.gz.
-#
-# See TarOutput::open for usage details.
-
-class Gem::Package::TarOutput
-
- ##
- # Creates a new TarOutput which will yield a TarWriter object for the
- # data.tar.gz portion of a gem-format tar file.
- #
- # See #initialize for details on +io+ and +signer+.
- #
- # See #add_gem_contents for details on adding metadata to the tar file.
-
- def self.open(io, signer = nil, &block) # :yield: data_tar_writer
- tar_outputter = new io, signer
- tar_outputter.add_gem_contents(&block)
- tar_outputter.add_metadata
- tar_outputter.add_signatures
-
- ensure
- tar_outputter.close
- end
-
- ##
- # Creates a new TarOutput that will write a gem-format tar file to +io+. If
- # +signer+ is given, the data.tar.gz and metadata.gz will be signed and
- # the signatures will be added to the tar file.
-
- def initialize(io, signer)
- @io = io
- @signer = signer
-
- @tar_writer = Gem::Package::TarWriter.new @io
-
- @metadata = nil
-
- @data_signature = nil
- @meta_signature = nil
- end
-
- ##
- # Yields a TarWriter for the data.tar.gz inside a gem-format tar file.
- # The yielded TarWriter has been extended with a #metadata= method for
- # attaching a YAML format Gem::Specification which will be written by
- # add_metadata.
-
- def add_gem_contents
- @tar_writer.add_file "data.tar.gz", 0644 do |inner|
- sio = @signer ? StringIO.new : nil
- Zlib::GzipWriter.wrap(sio || inner) do |os|
-
- Gem::Package::TarWriter.new os do |data_tar_writer|
- def data_tar_writer.metadata() @metadata end
- def data_tar_writer.metadata=(metadata) @metadata = metadata end
-
- yield data_tar_writer
-
- @metadata = data_tar_writer.metadata
- end
- end
-
- # if we have a signing key, then sign the data
- # digest and return the signature
- if @signer then
- digest = Gem::Security::OPT[:dgst_algo].digest sio.string
- @data_signature = @signer.sign digest
- inner.write sio.string
- end
- end
-
- self
- end
-
- ##
- # Adds metadata.gz to the gem-format tar file which was saved from a
- # previous #add_gem_contents call.
-
- def add_metadata
- return if @metadata.nil?
-
- @tar_writer.add_file "metadata.gz", 0644 do |io|
- begin
- sio = @signer ? StringIO.new : nil
- gzos = Zlib::GzipWriter.new(sio || io)
- 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 then
- digest = Gem::Security::OPT[:dgst_algo].digest sio.string
- @meta_signature = @signer.sign digest
- io.write sio.string
- end
- end
- end
- end
-
- ##
- # Adds data.tar.gz.sig and metadata.gz.sig to the gem-format tar files if
- # a Gem::Security::Signer was sent to initialize.
-
- def add_signatures
- if @data_signature then
- @tar_writer.add_file 'data.tar.gz.sig', 0644 do |io|
- io.write @data_signature
- end
- end
-
- if @meta_signature then
- @tar_writer.add_file 'metadata.gz.sig', 0644 do |io|
- io.write @meta_signature
- end
- end
- end
-
- ##
- # Closes the TarOutput.
-
- def close
- @tar_writer.close
- end
-
-end
-
Copied: MacRuby/branches/testing/lib/rubygems/package/tar_output.rb (from rev 232, MacRuby/trunk/lib/rubygems/package/tar_output.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package/tar_output.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_output.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,143 @@
+#++
+# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
+# See LICENSE.txt for additional licensing information.
+#--
+
+require 'rubygems/package'
+
+##
+# TarOutput is a wrapper to TarWriter that builds gem-format tar file.
+#
+# Gem-format tar files contain the following files:
+# [data.tar.gz] A gzipped tar file containing the files that compose the gem
+# which will be extracted into the gem/ dir on installation.
+# [metadata.gz] A YAML format Gem::Specification.
+# [data.tar.gz.sig] A signature for the gem's data.tar.gz.
+# [metadata.gz.sig] A signature for the gem's metadata.gz.
+#
+# See TarOutput::open for usage details.
+
+class Gem::Package::TarOutput
+
+ ##
+ # Creates a new TarOutput which will yield a TarWriter object for the
+ # data.tar.gz portion of a gem-format tar file.
+ #
+ # See #initialize for details on +io+ and +signer+.
+ #
+ # See #add_gem_contents for details on adding metadata to the tar file.
+
+ def self.open(io, signer = nil, &block) # :yield: data_tar_writer
+ tar_outputter = new io, signer
+ tar_outputter.add_gem_contents(&block)
+ tar_outputter.add_metadata
+ tar_outputter.add_signatures
+
+ ensure
+ tar_outputter.close
+ end
+
+ ##
+ # Creates a new TarOutput that will write a gem-format tar file to +io+. If
+ # +signer+ is given, the data.tar.gz and metadata.gz will be signed and
+ # the signatures will be added to the tar file.
+
+ def initialize(io, signer)
+ @io = io
+ @signer = signer
+
+ @tar_writer = Gem::Package::TarWriter.new @io
+
+ @metadata = nil
+
+ @data_signature = nil
+ @meta_signature = nil
+ end
+
+ ##
+ # Yields a TarWriter for the data.tar.gz inside a gem-format tar file.
+ # The yielded TarWriter has been extended with a #metadata= method for
+ # attaching a YAML format Gem::Specification which will be written by
+ # add_metadata.
+
+ def add_gem_contents
+ @tar_writer.add_file "data.tar.gz", 0644 do |inner|
+ sio = @signer ? StringIO.new : nil
+ Zlib::GzipWriter.wrap(sio || inner) do |os|
+
+ Gem::Package::TarWriter.new os do |data_tar_writer|
+ def data_tar_writer.metadata() @metadata end
+ def data_tar_writer.metadata=(metadata) @metadata = metadata end
+
+ yield data_tar_writer
+
+ @metadata = data_tar_writer.metadata
+ end
+ end
+
+ # if we have a signing key, then sign the data
+ # digest and return the signature
+ if @signer then
+ digest = Gem::Security::OPT[:dgst_algo].digest sio.string
+ @data_signature = @signer.sign digest
+ inner.write sio.string
+ end
+ end
+
+ self
+ end
+
+ ##
+ # Adds metadata.gz to the gem-format tar file which was saved from a
+ # previous #add_gem_contents call.
+
+ def add_metadata
+ return if @metadata.nil?
+
+ @tar_writer.add_file "metadata.gz", 0644 do |io|
+ begin
+ sio = @signer ? StringIO.new : nil
+ gzos = Zlib::GzipWriter.new(sio || io)
+ 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 then
+ digest = Gem::Security::OPT[:dgst_algo].digest sio.string
+ @meta_signature = @signer.sign digest
+ io.write sio.string
+ end
+ end
+ end
+ end
+
+ ##
+ # Adds data.tar.gz.sig and metadata.gz.sig to the gem-format tar files if
+ # a Gem::Security::Signer was sent to initialize.
+
+ def add_signatures
+ if @data_signature then
+ @tar_writer.add_file 'data.tar.gz.sig', 0644 do |io|
+ io.write @data_signature
+ end
+ end
+
+ if @meta_signature then
+ @tar_writer.add_file 'metadata.gz.sig', 0644 do |io|
+ io.write @meta_signature
+ end
+ end
+ end
+
+ ##
+ # Closes the TarOutput.
+
+ def close
+ @tar_writer.close
+ end
+
+end
+
Copied: MacRuby/branches/testing/lib/rubygems/package/tar_reader (from rev 232, MacRuby/trunk/lib/rubygems/package/tar_reader)
Deleted: MacRuby/branches/testing/lib/rubygems/package/tar_reader/entry.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_reader/entry.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_reader/entry.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,99 +0,0 @@
-#++
-# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'rubygems/package'
-
-class Gem::Package::TarReader::Entry
-
- attr_reader :header
-
- def initialize(header, io)
- @closed = false
- @header = header
- @io = io
- @orig_pos = @io.pos
- @read = 0
- end
-
- def check_closed # :nodoc:
- raise IOError, "closed #{self.class}" if closed?
- end
-
- def bytes_read
- @read
- end
-
- def close
- @closed = true
- end
-
- def closed?
- @closed
- end
-
- def eof?
- check_closed
-
- @read >= @header.size
- end
-
- def full_name
- if @header.prefix != "" then
- File.join @header.prefix, @header.name
- else
- @header.name
- end
- end
-
- def getc
- check_closed
-
- return nil if @read >= @header.size
-
- ret = @io.getc
- @read += 1 if ret
-
- ret
- end
-
- def directory?
- @header.typeflag == "5"
- end
-
- def file?
- @header.typeflag == "0"
- end
-
- def pos
- check_closed
-
- bytes_read
- end
-
- def read(len = nil)
- check_closed
-
- return nil if @read >= @header.size
-
- len ||= @header.size - @read
- max_read = [len, @header.size - @read].min
-
- ret = @io.read max_read
- @read += ret.size
-
- ret
- end
-
- def rewind
- check_closed
-
- raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
-
- @io.pos = @orig_pos
- @read = 0
- end
-
-end
-
Copied: MacRuby/branches/testing/lib/rubygems/package/tar_reader/entry.rb (from rev 232, MacRuby/trunk/lib/rubygems/package/tar_reader/entry.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package/tar_reader/entry.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_reader/entry.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,99 @@
+#++
+# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
+# See LICENSE.txt for additional licensing information.
+#--
+
+require 'rubygems/package'
+
+class Gem::Package::TarReader::Entry
+
+ attr_reader :header
+
+ def initialize(header, io)
+ @closed = false
+ @header = header
+ @io = io
+ @orig_pos = @io.pos
+ @read = 0
+ end
+
+ def check_closed # :nodoc:
+ raise IOError, "closed #{self.class}" if closed?
+ end
+
+ def bytes_read
+ @read
+ end
+
+ def close
+ @closed = true
+ end
+
+ def closed?
+ @closed
+ end
+
+ def eof?
+ check_closed
+
+ @read >= @header.size
+ end
+
+ def full_name
+ if @header.prefix != "" then
+ File.join @header.prefix, @header.name
+ else
+ @header.name
+ end
+ end
+
+ def getc
+ check_closed
+
+ return nil if @read >= @header.size
+
+ ret = @io.getc
+ @read += 1 if ret
+
+ ret
+ end
+
+ def directory?
+ @header.typeflag == "5"
+ end
+
+ def file?
+ @header.typeflag == "0"
+ end
+
+ def pos
+ check_closed
+
+ bytes_read
+ end
+
+ def read(len = nil)
+ check_closed
+
+ return nil if @read >= @header.size
+
+ len ||= @header.size - @read
+ max_read = [len, @header.size - @read].min
+
+ ret = @io.read max_read
+ @read += ret.size
+
+ ret
+ end
+
+ def rewind
+ check_closed
+
+ raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
+
+ @io.pos = @orig_pos
+ @read = 0
+ end
+
+end
+
Deleted: MacRuby/branches/testing/lib/rubygems/package/tar_reader.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_reader.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_reader.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,86 +0,0 @@
-#++
-# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'rubygems/package'
-
-class Gem::Package::TarReader
-
- include Gem::Package
-
- class UnexpectedEOF < StandardError; end
-
- def self.new(io)
- reader = super
-
- return reader unless block_given?
-
- begin
- yield reader
- ensure
- reader.close
- end
-
- nil
- end
-
- def initialize(io)
- @io = io
- @init_pos = io.pos
- end
-
- def close
- end
-
- def each
- loop do
- return if @io.eof?
-
- header = Gem::Package::TarHeader.from @io
- return if header.empty?
-
- entry = Gem::Package::TarReader::Entry.new header, @io
- size = entry.header.size
-
- yield entry
-
- skip = (512 - (size % 512)) % 512
-
- if @io.respond_to? :seek then
- # avoid reading...
- @io.seek(size - entry.bytes_read, IO::SEEK_CUR)
- else
- pending = size - entry.bytes_read
-
- while pending > 0 do
- 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
-
- alias each_entry each
-
- ##
- # NOTE: Do not call #rewind during #each
-
- def rewind
- if @init_pos == 0 then
- raise Gem::Package::NonSeekableIO unless @io.respond_to? :rewind
- @io.rewind
- else
- raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
- @io.pos = @init_pos
- end
- end
-
-end
-
Copied: MacRuby/branches/testing/lib/rubygems/package/tar_reader.rb (from rev 232, MacRuby/trunk/lib/rubygems/package/tar_reader.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package/tar_reader.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_reader.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,86 @@
+#++
+# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
+# See LICENSE.txt for additional licensing information.
+#--
+
+require 'rubygems/package'
+
+class Gem::Package::TarReader
+
+ include Gem::Package
+
+ class UnexpectedEOF < StandardError; end
+
+ def self.new(io)
+ reader = super
+
+ return reader unless block_given?
+
+ begin
+ yield reader
+ ensure
+ reader.close
+ end
+
+ nil
+ end
+
+ def initialize(io)
+ @io = io
+ @init_pos = io.pos
+ end
+
+ def close
+ end
+
+ def each
+ loop do
+ return if @io.eof?
+
+ header = Gem::Package::TarHeader.from @io
+ return if header.empty?
+
+ entry = Gem::Package::TarReader::Entry.new header, @io
+ size = entry.header.size
+
+ yield entry
+
+ skip = (512 - (size % 512)) % 512
+
+ if @io.respond_to? :seek then
+ # avoid reading...
+ @io.seek(size - entry.bytes_read, IO::SEEK_CUR)
+ else
+ pending = size - entry.bytes_read
+
+ while pending > 0 do
+ 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
+
+ alias each_entry each
+
+ ##
+ # NOTE: Do not call #rewind during #each
+
+ def rewind
+ if @init_pos == 0 then
+ raise Gem::Package::NonSeekableIO unless @io.respond_to? :rewind
+ @io.rewind
+ else
+ raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
+ @io.pos = @init_pos
+ end
+ end
+
+end
+
Deleted: MacRuby/branches/testing/lib/rubygems/package/tar_writer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_writer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_writer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,180 +0,0 @@
-#++
-# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'rubygems/package'
-
-class Gem::Package::TarWriter
-
- class FileOverflow < 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(io)
- @io = io
- end
-
- def write(data)
- @io.write data
- end
-
- end
-
- def self.new(io)
- writer = super
-
- return writer unless block_given?
-
- begin
- yield writer
- ensure
- writer.close
- end
-
- nil
- end
-
- def initialize(io)
- @io = io
- @closed = false
- end
-
- def add_file(name, mode)
- check_closed
-
- raise Gem::Package::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) if block_given?
-
- size = @io.pos - init_pos - 512
-
- remainder = (512 - (size % 512)) % 512
- @io.write "\0" * remainder
-
- final_pos = @io.pos
- @io.pos = init_pos
-
- header = Gem::Package::TarHeader.new :name => name, :mode => mode,
- :size => size, :prefix => prefix
-
- @io.write header
- @io.pos = final_pos
-
- self
- end
-
- def add_file_simple(name, mode, size)
- check_closed
-
- name, prefix = split_name name
-
- header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
- :size => size, :prefix => prefix).to_s
-
- @io.write header
- os = BoundedStream.new @io, size
-
- yield os if block_given?
-
- min_padding = size - os.written
- @io.write("\0" * min_padding)
-
- remainder = (512 - (size % 512)) % 512
- @io.write("\0" * remainder)
-
- self
- end
-
- def check_closed
- raise IOError, "closed #{self.class}" if closed?
- end
-
- def close
- check_closed
-
- @io.write "\0" * 1024
- flush
-
- @closed = true
- end
-
- def closed?
- @closed
- end
-
- def flush
- check_closed
-
- @io.flush if @io.respond_to? :flush
- end
-
- def mkdir(name, mode)
- check_closed
-
- name, prefix = split_name(name)
-
- header = Gem::Package::TarHeader.new :name => name, :mode => mode,
- :typeflag => "5", :size => 0,
- :prefix => prefix
-
- @io.write header
-
- self
- end
-
- def split_name(name) # :nodoc:
- raise Gem::Package::TooLongFileName if name.size > 256
-
- if name.size <= 100 then
- 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
-
- if name.size > 100 or prefix.size > 155 then
- raise Gem::Package::TooLongFileName
- end
- end
-
- return name, prefix
- end
-
-end
-
Copied: MacRuby/branches/testing/lib/rubygems/package/tar_writer.rb (from rev 232, MacRuby/trunk/lib/rubygems/package/tar_writer.rb)
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package/tar_writer.rb (rev 0)
+++ MacRuby/branches/testing/lib/rubygems/package/tar_writer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,180 @@
+#++
+# Copyright (C) 2004 Mauricio Julio Fern\xE1ndez Pradier
+# See LICENSE.txt for additional licensing information.
+#--
+
+require 'rubygems/package'
+
+class Gem::Package::TarWriter
+
+ class FileOverflow < 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(io)
+ @io = io
+ end
+
+ def write(data)
+ @io.write data
+ end
+
+ end
+
+ def self.new(io)
+ writer = super
+
+ return writer unless block_given?
+
+ begin
+ yield writer
+ ensure
+ writer.close
+ end
+
+ nil
+ end
+
+ def initialize(io)
+ @io = io
+ @closed = false
+ end
+
+ def add_file(name, mode)
+ check_closed
+
+ raise Gem::Package::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) if block_given?
+
+ size = @io.pos - init_pos - 512
+
+ remainder = (512 - (size % 512)) % 512
+ @io.write "\0" * remainder
+
+ final_pos = @io.pos
+ @io.pos = init_pos
+
+ header = Gem::Package::TarHeader.new :name => name, :mode => mode,
+ :size => size, :prefix => prefix
+
+ @io.write header
+ @io.pos = final_pos
+
+ self
+ end
+
+ def add_file_simple(name, mode, size)
+ check_closed
+
+ name, prefix = split_name name
+
+ header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
+ :size => size, :prefix => prefix).to_s
+
+ @io.write header
+ os = BoundedStream.new @io, size
+
+ yield os if block_given?
+
+ min_padding = size - os.written
+ @io.write("\0" * min_padding)
+
+ remainder = (512 - (size % 512)) % 512
+ @io.write("\0" * remainder)
+
+ self
+ end
+
+ def check_closed
+ raise IOError, "closed #{self.class}" if closed?
+ end
+
+ def close
+ check_closed
+
+ @io.write "\0" * 1024
+ flush
+
+ @closed = true
+ end
+
+ def closed?
+ @closed
+ end
+
+ def flush
+ check_closed
+
+ @io.flush if @io.respond_to? :flush
+ end
+
+ def mkdir(name, mode)
+ check_closed
+
+ name, prefix = split_name(name)
+
+ header = Gem::Package::TarHeader.new :name => name, :mode => mode,
+ :typeflag => "5", :size => 0,
+ :prefix => prefix
+
+ @io.write header
+
+ self
+ end
+
+ def split_name(name) # :nodoc:
+ raise Gem::Package::TooLongFileName if name.size > 256
+
+ if name.size <= 100 then
+ 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
+
+ if name.size > 100 or prefix.size > 155 then
+ raise Gem::Package::TooLongFileName
+ end
+ end
+
+ return name, prefix
+ end
+
+end
+
Modified: MacRuby/branches/testing/lib/rubygems/package.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/package.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/package.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/remote_fetcher.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/remote_fetcher.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/remote_fetcher.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/requirement.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/requirement.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/requirement.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -16,6 +16,8 @@
include Comparable
+ attr_reader :requirements
+
OPS = {
"=" => lambda { |v, r| v == r },
"!=" => lambda { |v, r| v != r },
Modified: MacRuby/branches/testing/lib/rubygems/rubygems_version.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/rubygems_version.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/rubygems_version.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/security.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/security.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/security.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -4,6 +4,7 @@
# See LICENSE.txt for permissions.
#++
+require 'rubygems'
require 'rubygems/gem_openssl'
# = Signed Gems README
Modified: MacRuby/branches/testing/lib/rubygems/server.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/server.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/server.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/source_index.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/source_index.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/source_index.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/source_info_cache.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/source_info_cache.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/source_info_cache.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/source_info_cache_entry.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/source_info_cache_entry.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/source_info_cache_entry.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/specification.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/specification.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/specification.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/uninstaller.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/uninstaller.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/uninstaller.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/user_interaction.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/user_interaction.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/user_interaction.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems/version_option.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems/version_option.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems/version_option.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/rubygems.rb
===================================================================
--- MacRuby/branches/testing/lib/rubygems.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/rubygems.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/set.rb
===================================================================
--- MacRuby/branches/testing/lib/set.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/set.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/shellwords.rb
===================================================================
--- MacRuby/branches/testing/lib/shellwords.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/shellwords.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/test/unit/testcase.rb
===================================================================
--- MacRuby/branches/testing/lib/test/unit/testcase.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/test/unit/testcase.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -48,7 +48,7 @@
# one suite, creating a new instance of the fixture for
# each method.
def self.suite
- method_names = public_instance_methods(true)
+ method_names = public_instance_methods(true).map { |m| m.to_s }
tests = method_names.delete_if {|method_name| method_name !~ /^test./}
suite = TestSuite.new(name)
tests.sort.each do
Modified: MacRuby/branches/testing/lib/webrick/httprequest.rb
===================================================================
--- MacRuby/branches/testing/lib/webrick/httprequest.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/webrick/httprequest.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/webrick/httpservlet/filehandler.rb
===================================================================
--- MacRuby/branches/testing/lib/webrick/httpservlet/filehandler.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/webrick/httpservlet/filehandler.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/xmlrpc/client.rb
===================================================================
--- MacRuby/branches/testing/lib/xmlrpc/client.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/xmlrpc/client.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/lib/yaml/store.rb
===================================================================
--- MacRuby/branches/testing/lib/yaml/store.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/lib/yaml/store.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/load.c
===================================================================
--- MacRuby/branches/testing/load.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/load.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -23,21 +23,26 @@
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;
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
- rb_ary_push(ary, rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil));
+ rb_ary_push(ary, rb_file_expand_path(RARRAY_AT(load_path, i), Qnil));
}
return ary;
}
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;
@@ -56,9 +61,9 @@
long i;
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
- VALUE p = RARRAY_PTR(load_path)[i];
+ VALUE p = RARRAY_AT(load_path, i);
const char *s = StringValuePtr(p);
- long n = RSTRING_LEN(p);
+ long n = RSTRING_CLEN(p);
if (vlen < n + len + 1) continue;
if (n && (strncmp(name, s, n) || name[n] != '/')) continue;
@@ -103,7 +108,7 @@
{
VALUE v, features, p, load_path = 0;
const char *f, *e;
- long i, len, elen, n;
+ long i, count, len, elen, n;
st_table *loading_tbl;
st_data_t data;
int type;
@@ -120,16 +125,16 @@
type = 0;
}
features = get_loaded_features();
- for (i = 0; i < RARRAY_LEN(features); ++i) {
- v = RARRAY_PTR(features)[i];
- f = StringValuePtr(v);
- if ((n = RSTRING_LEN(v)) < len) continue;
+ for (i = 0, count = RARRAY_LEN(features); i < count; ++i) {
+ v = RARRAY_AT(features, i);
+ f = StringValueCStr(v);
+ 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_LEN(p) + 1;
+ f += RSTRING_CLEN(p) + 1;
}
if (!*(e = f + len)) {
if (ext) continue;
@@ -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) {
@@ -171,7 +176,7 @@
if (ext && *ext) return 0;
bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
- buf = RSTRING_PTR(bufstr);
+ buf = RSTRING_PTR(bufstr); /* ok */
MEMCPY(buf, feature, char, len);
for (i = 0; (e = loadable_ext[i]) != 0; i++) {
strncpy(buf + len, e, DLEXT_MAXLEN + 1);
@@ -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;
@@ -264,7 +275,7 @@
VALUE iseq;
th->parse_in_eval++;
- node = (NODE *)rb_load_file(RSTRING_PTR(fname));
+ node = (NODE *)rb_load_file(RSTRING_CPTR(fname));
th->parse_in_eval--;
loaded = Qtrue;
iseq = rb_iseq_new(node, rb_str_new2("<top (required)>"),
@@ -400,12 +411,12 @@
search_required(VALUE fname, volatile VALUE *path)
{
VALUE tmp;
- char *ext, *ftptr;
+ const char *ext, *ftptr;
int type, ft = 0;
const char *loading;
*path = 0;
- ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
+ ext = strrchr(ftptr = RSTRING_CPTR(fname), '.');
if (ext && !strchr(ext, '/')) {
if (IS_RBEXT(ext)) {
if (rb_feature_p(ftptr, ext, Qtrue, Qfalse, &loading)) {
@@ -414,7 +425,7 @@
}
if ((tmp = rb_find_file(fname)) != 0) {
tmp = rb_file_expand_path(tmp, Qnil);
- ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
+ ext = strrchr(ftptr = RSTRING_CPTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, Qtrue, Qtrue, 0))
*path = tmp;
return 'r';
@@ -426,12 +437,12 @@
if (loading) *path = rb_str_new2(loading);
return 's';
}
- tmp = rb_str_new(RSTRING_PTR(fname), ext - RSTRING_PTR(fname));
+ tmp = rb_str_new(RSTRING_CPTR(fname), ext - RSTRING_CPTR(fname));
#ifdef DLEXT2
OBJ_FREEZE(tmp);
if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
tmp = rb_file_expand_path(tmp, Qnil);
- ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
+ ext = strrchr(ftptr = RSTRING_CPTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
*path = tmp;
return 's';
@@ -441,7 +452,7 @@
OBJ_FREEZE(tmp);
if ((tmp = rb_find_file(tmp)) != 0) {
tmp = rb_file_expand_path(tmp, Qnil);
- ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
+ ext = strrchr(ftptr = RSTRING_CPTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
*path = tmp;
return 's';
@@ -455,7 +466,7 @@
}
if ((tmp = rb_find_file(fname)) != 0) {
tmp = rb_file_expand_path(tmp, Qnil);
- ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
+ ext = strrchr(ftptr = RSTRING_CPTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
*path = tmp;
return 's';
@@ -473,14 +484,14 @@
case 0:
if (ft)
break;
- ftptr = RSTRING_PTR(tmp);
+ ftptr = RSTRING_CPTR(tmp);
return rb_feature_p(ftptr, 0, Qfalse, Qtrue, 0);
default:
if (ft)
break;
case 1:
- ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
+ ext = strrchr(ftptr = RSTRING_CPTR(tmp), '.');
if (rb_feature_p(ftptr, ext, !--type, Qtrue, &loading) && !loading)
break;
*path = tmp;
@@ -492,14 +503,14 @@
load_failed(VALUE fname)
{
rb_raise(rb_eLoadError, "no such file to load -- %s",
- RSTRING_PTR(fname));
+ RSTRING_CPTR(fname));
}
static VALUE
load_ext(VALUE path)
{
SCOPE_SET(NOEX_PUBLIC);
- return (VALUE)dln_load(RSTRING_PTR(path));
+ return (VALUE)dln_load(RSTRING_CPTR(path));
}
VALUE
@@ -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,9 +533,11 @@
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_PTR(path)))) {
+ if (!path || !(ftptr = load_lock(RSTRING_CPTR(path)))) {
result = Qfalse;
}
else {
@@ -611,7 +622,7 @@
ID id = rb_to_id(sym);
Check_SafeStr(file);
- rb_autoload(mod, id, RSTRING_PTR(file));
+ rb_autoload(mod, id, RSTRING_CPTR(file));
return Qnil;
}
@@ -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/branches/testing/marshal.c
===================================================================
--- MacRuby/branches/testing/marshal.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/marshal.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -54,7 +54,7 @@
#define TYPE_FALSE 'F'
#define TYPE_FIXNUM 'i'
-#define TYPE_EXTENDED 'e'
+#define TYPE_EXTENDED_R 'e'
#define TYPE_UCLASS 'C'
#define TYPE_OBJECT 'o'
#define TYPE_DATA 'd'
@@ -162,7 +162,7 @@
class2path(VALUE klass)
{
VALUE path = rb_class_path(klass);
- char *n = RSTRING_PTR(path);
+ const char *n = RSTRING_CPTR(path);
if (n[0] == '#') {
rb_raise(rb_eTypeError, "can't dump anonymous %s %s",
@@ -182,7 +182,7 @@
{
VALUE buf = arg->str;
rb_str_buf_cat(buf, s, n);
- if (arg->dest && RSTRING_LEN(buf) >= BUFSIZ) {
+ if (arg->dest && RSTRING_CLEN(buf) >= BUFSIZ) {
if (arg->taint) OBJ_TAINT(buf);
rb_io_write(arg->dest, buf);
rb_str_resize(buf, 0);
@@ -417,7 +417,7 @@
}
while (BUILTIN_TYPE(klass) == T_ICLASS) {
path = rb_class2name(RBASIC(klass)->klass);
- w_byte(TYPE_EXTENDED, arg);
+ w_byte(TYPE_EXTENDED_R, arg);
w_unique(path, arg);
klass = RCLASS_SUPER(klass);
}
@@ -427,7 +427,7 @@
w_class(char type, VALUE obj, struct dump_arg *arg, int check)
{
volatile VALUE p;
- char *path;
+ const char *path;
st_data_t real_obj;
VALUE klass;
@@ -438,20 +438,28 @@
w_extended(klass, arg, check);
w_byte(type, arg);
p = class2path(rb_class_real(klass));
- path = RSTRING_PTR(p);
+ path = RSTRING_CPTR(p);
w_unique(path, arg);
}
static void
+#if WITH_OBJC
+w_uclass(VALUE obj, bool is_pure, struct dump_arg *arg)
+#else
w_uclass(VALUE obj, VALUE super, struct dump_arg *arg)
+#endif
{
VALUE klass = CLASS_OF(obj);
w_extended(klass, arg, Qtrue);
klass = rb_class_real(klass);
+#if WITH_OBJC
+ if (!is_pure) {
+#else
if (klass != super) {
+#endif
w_byte(TYPE_UCLASS, arg);
- w_unique(RSTRING_PTR(class2path(klass)), arg);
+ w_unique(RSTRING_CPTR(class2path(klass)), arg);
}
}
@@ -467,6 +475,17 @@
static void
w_encoding(VALUE obj, long num, struct dump_call_arg *arg)
{
+ rb_encoding *enc = 0;
+#if WITH_OBJC
+ VALUE name;
+
+ enc = rb_enc_get(obj);
+ if (enc == NULL) {
+ w_long(num, arg->arg);
+ return;
+ }
+ name = rb_enc_name2(enc);
+#else
int encidx = rb_enc_get_index(obj);
rb_encoding *enc = 0;
st_data_t name;
@@ -485,6 +504,7 @@
name = (st_data_t)rb_str_new2(rb_enc_name(enc));
st_insert(arg->arg->encodings, (st_data_t)rb_enc_name(enc), name);
} while (0);
+#endif
w_object(name, arg->arg, arg->limit);
}
@@ -525,8 +545,12 @@
st_table *ivtbl = 0;
st_data_t num;
int hasiv = 0;
+#if WITH_OBJC
+#define has_ivars(obj, ivtbl) ((ivtbl = rb_generic_ivar_table(obj)) != 0)
+#else
#define has_ivars(obj, ivtbl) ((ivtbl = rb_generic_ivar_table(obj)) != 0 || \
(!SPECIAL_CONST_P(obj) && !ENCODING_IS_ASCII8BIT(obj)))
+#endif
if (limit == 0) {
rb_raise(rb_eArgError, "exceed depth limit");
@@ -574,24 +598,11 @@
else {
if (OBJ_TAINTED(obj)) arg->taint = Qtrue;
- st_add_direct(arg->data, obj, arg->data->num_entries);
+ if (rb_respond_to(obj, s_mdump)) {
+ volatile VALUE v;
- {
- 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);
- }
- }
+ st_add_direct(arg->data, obj, arg->data->num_entries);
- if (rb_respond_to(obj, s_mdump)) {
- VALUE v;
-
v = rb_funcall(obj, s_mdump, 0, 0);
w_class(TYPE_USRMARSHAL, obj, arg, Qfalse);
w_object(v, arg, limit);
@@ -611,17 +622,36 @@
w_byte(TYPE_IVAR, arg);
}
w_class(TYPE_USERDEF, obj, arg, Qfalse);
- w_bytes(RSTRING_PTR(v), RSTRING_LEN(v), arg);
+ w_bytes(RSTRING_CPTR(v), RSTRING_CLEN(v), arg);
if (hasiv2) {
w_ivar(v, ivtbl2, &c_arg);
}
else if (hasiv) {
w_ivar(obj, ivtbl, &c_arg);
}
+ st_add_direct(arg->data, obj, arg->data->num_entries);
return;
}
- switch (BUILTIN_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");
@@ -629,7 +659,7 @@
w_byte(TYPE_CLASS, arg);
{
volatile VALUE path = class2path(obj);
- w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
+ w_bytes(RSTRING_CPTR(path), RSTRING_CLEN(path), arg);
}
break;
@@ -637,7 +667,7 @@
w_byte(TYPE_MODULE, arg);
{
VALUE path = class2path(obj);
- w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
+ w_bytes(RSTRING_CPTR(path), RSTRING_CLEN(path), arg);
}
break;
@@ -674,9 +704,13 @@
break;
case T_STRING:
+#if WITH_OBJC
+ w_uclass(obj, rb_objc_str_is_pure(obj), arg);
+#else
w_uclass(obj, rb_cString, arg);
+#endif
w_byte(TYPE_STRING, arg);
- w_bytes(RSTRING_PTR(obj), RSTRING_LEN(obj), arg);
+ w_bytes(RSTRING_CPTR(obj), RSTRING_CLEN(obj), arg);
break;
case T_REGEXP:
@@ -687,10 +721,20 @@
break;
case T_ARRAY:
+#if WITH_OBJC
+ w_uclass(obj, rb_objc_ary_is_pure(obj), arg);
+#else
w_uclass(obj, rb_cArray, arg);
+#endif
w_byte(TYPE_ARRAY, arg);
{
long len = RARRAY_LEN(obj);
+#if WITH_OBJC
+ long i;
+ w_long(len, arg);
+ for (i = 0; i < len; i++)
+ w_object(RARRAY_AT(obj, i), arg, limit);
+#else
VALUE *ptr = RARRAY_PTR(obj);
w_long(len, arg);
@@ -698,11 +742,20 @@
w_object(*ptr, arg, limit);
ptr++;
}
+#endif
}
break;
case T_HASH:
+#if WITH_OBJC
+ w_uclass(obj, rb_objc_hash_is_pure(obj), arg);
+#else
w_uclass(obj, rb_cHash, arg);
+#endif
+#if WITH_OBJC
+ w_byte(TYPE_HASH, arg);
+ /* TODO: encode ifnone too */
+#else
if (NIL_P(RHASH(obj)->ifnone)) {
w_byte(TYPE_HASH, arg);
}
@@ -713,11 +766,14 @@
else {
w_byte(TYPE_HASH_DEF, arg);
}
+#endif
w_long(RHASH_SIZE(obj), arg);
rb_hash_foreach(obj, hash_each, (st_data_t)&c_arg);
+#if !WITH_OBJC
if (!NIL_P(RHASH(obj)->ifnone)) {
w_object(RHASH(obj)->ifnone, arg, limit);
}
+#endif
break;
case T_STRUCT:
@@ -730,7 +786,7 @@
w_long(len, arg);
mem = rb_struct_members(obj);
for (i=0; i<len; i++) {
- w_symbol(SYM2ID(RARRAY_PTR(mem)[i]), arg);
+ w_symbol(SYM2ID(RARRAY_AT(mem, i)), arg);
w_object(RSTRUCT_PTR(obj)[i], arg, limit);
}
}
@@ -855,6 +911,8 @@
arg.str = port;
}
+ RSTRING_PTR(arg.str); /* force bytestring creation */
+
arg.symbols = st_init_numtable();
arg.data = st_init_numtable();
arg.taint = Qfalse;
@@ -894,8 +952,8 @@
int c;
if (TYPE(arg->src) == T_STRING) {
- if (RSTRING_LEN(arg->src) > arg->offset) {
- c = (unsigned char)RSTRING_PTR(arg->src)[arg->offset++];
+ if (RSTRING_CLEN(arg->src) > arg->offset) {
+ c = (unsigned char)RSTRING_CPTR(arg->src)[arg->offset++];
}
else {
rb_raise(rb_eArgError, "marshal data too short");
@@ -967,8 +1025,8 @@
if (len == 0) return rb_str_new(0, 0);
if (TYPE(arg->src) == T_STRING) {
- if (RSTRING_LEN(arg->src) - arg->offset >= len) {
- str = rb_str_new(RSTRING_PTR(arg->src)+arg->offset, len);
+ if (RSTRING_CLEN(arg->src) - arg->offset >= len) {
+ str = rb_str_new(RSTRING_CPTR(arg->src)+arg->offset, len);
arg->offset += len;
}
else {
@@ -982,7 +1040,7 @@
str = rb_funcall2(src, s_read, 1, &n);
if (NIL_P(str)) goto too_short;
StringValue(str);
- if (RSTRING_LEN(str) != len) goto too_short;
+ if (RSTRING_CLEN(str) != len) goto too_short;
if (OBJ_TAINTED(str)) arg->taint = Qtrue;
}
return str;
@@ -1004,7 +1062,7 @@
r_symreal(struct load_arg *arg)
{
volatile VALUE s = r_bytes(arg);
- ID id = rb_intern(RSTRING_PTR(s));
+ ID id = rb_intern(RSTRING_CPTR(s));
st_insert(arg->symbols, arg->symbols->num_entries, id);
@@ -1088,11 +1146,14 @@
while (len--) {
ID id = r_symbol(arg);
VALUE val = r_object(arg);
+#if !WITH_OBJC
if (id == rb_id_encoding()) {
int idx = rb_enc_find_index(StringValueCStr(val));
if (idx > 0) rb_enc_associate_index(obj, idx);
}
- else {
+ else
+#endif
+ {
rb_ivar_set(obj, id, val);
}
}
@@ -1170,7 +1231,7 @@
}
break;
- case TYPE_EXTENDED:
+ case TYPE_EXTENDED_R:
{
VALUE m = path2module(r_unique(arg));
@@ -1188,21 +1249,30 @@
case TYPE_UCLASS:
{
VALUE c = path2class(r_unique(arg));
+ bool non_native;
if (FL_TEST(c, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "singleton can't be loaded");
}
v = r_object0(arg, 0, extmod);
- if (rb_special_const_p(v) || TYPE(v) == T_OBJECT || TYPE(v) == T_CLASS) {
- format_error:
- rb_raise(rb_eArgError, "dump format error (user class)");
+#if WITH_OBJC
+ if (rb_objc_is_non_native(v)) {
+ *(Class *)v = RCLASS_OCID(c);
}
- if (TYPE(v) == T_MODULE || !RTEST(rb_class_inherited_p(c, RBASIC(v)->klass))) {
- VALUE tmp = rb_obj_alloc(c);
+ else
+#endif
+ {
+ if (rb_special_const_p(v) || TYPE(v) == T_OBJECT || TYPE(v) == T_CLASS) {
+format_error:
+ rb_raise(rb_eArgError, "dump format error (user class)");
+ }
+ if (TYPE(v) == T_MODULE || !RTEST(rb_class_inherited_p(c, RBASIC(v)->klass))) {
+ VALUE tmp = rb_obj_alloc(c);
- if (TYPE(v) != TYPE(tmp)) goto format_error;
+ if (TYPE(v) != TYPE(tmp)) goto format_error;
+ }
+ RBASIC(v)->klass = c;
}
- RBASIC(v)->klass = c;
}
break;
@@ -1233,7 +1303,7 @@
{
double d, t = 0.0;
VALUE str = r_bytes(arg);
- const char *ptr = RSTRING_PTR(str);
+ const char *ptr = RSTRING_CPTR(str);
if (strcmp(ptr, "nan") == 0) {
d = t / t;
@@ -1247,7 +1317,7 @@
else {
char *e;
d = strtod(ptr, &e);
- d = load_mantissa(d, e, RSTRING_LEN(str) - (e - ptr));
+ d = load_mantissa(d, e, strlen(ptr) - (e - ptr));
}
v = DOUBLE2NUM(d);
v = r_entry(v, arg);
@@ -1272,7 +1342,7 @@
rb_big_resize((VALUE)big, (len + 1) * 2 / sizeof(BDIGIT));
#endif
digits = RBIGNUM_DIGITS(big);
- MEMCPY(digits, RSTRING_PTR(data), char, len * 2);
+ MEMCPY(digits, RSTRING_CPTR(data), char, len * 2);
#if SIZEOF_BDIGITS > SIZEOF_SHORT
MEMZERO((char *)digits + len * 2, char,
RBIGNUM_LEN(big) * sizeof(BDIGIT) - len * 2);
@@ -1340,9 +1410,11 @@
VALUE value = r_object(arg);
rb_hash_aset(v, key, value);
}
+#if !WITH_OBJC
if (type == TYPE_HASH_DEF) {
RHASH(v)->ifnone = r_object(arg);
}
+#endif
v = r_leave(v, arg);
}
break;
@@ -1373,11 +1445,11 @@
for (i=0; i<len; i++) {
slot = r_symbol(arg);
- if (RARRAY_PTR(mem)[i] != ID2SYM(slot)) {
+ if (RARRAY_AT(mem, i) != ID2SYM(slot)) {
rb_raise(rb_eTypeError, "struct %s not compatible (:%s for :%s)",
rb_class2name(klass),
rb_id2name(slot),
- rb_id2name(SYM2ID(RARRAY_PTR(mem)[i])));
+ rb_id2name(SYM2ID(RARRAY_AT(mem, i))));
}
rb_ary_push(values, r_object(arg));
}
@@ -1473,7 +1545,7 @@
{
volatile VALUE str = r_bytes(arg);
- v = rb_path2class(RSTRING_PTR(str));
+ v = rb_path2class(RSTRING_CPTR(str));
v = r_entry(v, arg);
v = r_leave(v, arg);
}
@@ -1483,7 +1555,7 @@
{
volatile VALUE str = r_bytes(arg);
- v = path2class(RSTRING_PTR(str));
+ v = path2class(RSTRING_CPTR(str));
v = r_entry(v, arg);
v = r_leave(v, arg);
}
@@ -1493,7 +1565,7 @@
{
volatile VALUE str = r_bytes(arg);
- v = path2module(RSTRING_PTR(str));
+ v = path2module(RSTRING_CPTR(str));
v = r_entry(v, arg);
v = r_leave(v, arg);
}
@@ -1616,9 +1688,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/branches/testing/math.c
===================================================================
--- MacRuby/branches/testing/math.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/math.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/misc/README
===================================================================
--- MacRuby/branches/testing/misc/README 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/misc/README 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/misc/ruby-mode.el
===================================================================
--- MacRuby/branches/testing/misc/ruby-mode.el 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/misc/ruby-mode.el 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/misc/ruby-style.el
===================================================================
--- MacRuby/branches/testing/misc/ruby-style.el 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/misc/ruby-style.el 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/missing/lgamma_r.c
===================================================================
--- MacRuby/branches/testing/missing/lgamma_r.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/missing/lgamma_r.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/missing/tgamma.c
===================================================================
--- MacRuby/branches/testing/missing/tgamma.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/missing/tgamma.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/missing/vsnprintf.c
===================================================================
--- MacRuby/branches/testing/missing/vsnprintf.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/missing/vsnprintf.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/numeric.c
===================================================================
--- MacRuby/branches/testing/numeric.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/numeric.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -156,8 +156,8 @@
return Qfalse;
}
- *x = RARRAY_PTR(ary)[0];
- *y = RARRAY_PTR(ary)[1];
+ *x = RARRAY_AT(ary, 0);
+ *y = RARRAY_AT(ary, 1);
return Qtrue;
}
@@ -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
*
@@ -1863,14 +1887,31 @@
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc);
break;
}
+#if WITH_OBJC
+ /* TODO */
+ rb_notimplement();
+#else
enc = rb_to_encoding(argv[0]);
if (!enc) enc = rb_ascii8bit_encoding();
if (i < 0 || (n = rb_enc_codelen(i, enc)) <= 0) goto out_of_range;
str = rb_enc_str_new(0, n, enc);
rb_enc_mbcput(i, RSTRING_PTR(str), enc);
return str;
+#endif
}
+static VALUE
+int_numerator(VALUE num)
+{
+ return num;
+}
+
+static VALUE
+int_denominator(VALUE num)
+{
+ return INT2FIX(1);
+}
+
/********************************************************************
*
* Document-class: Fixnum
@@ -1919,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",
@@ -1939,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;
@@ -2008,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);
}
@@ -2173,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));
@@ -2196,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;
@@ -2214,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);
}
}
@@ -2238,7 +2285,7 @@
static VALUE
fix_div(VALUE x, VALUE y)
{
- return fix_divide(x, y, Qtrue);
+ return fix_divide(x, y, '/');
}
/*
@@ -2251,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"));
}
/*
@@ -2314,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);
}
@@ -2380,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) {
@@ -2393,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) {
@@ -2589,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
@@ -2601,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);
}
@@ -2620,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);
}
@@ -2639,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);
}
@@ -2736,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)
@@ -2744,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) {
@@ -2795,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
@@ -3115,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");
@@ -3142,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);
@@ -3156,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);
@@ -3212,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/branches/testing/objc.m
===================================================================
--- MacRuby/branches/testing/objc.m 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/objc.m 2008-05-28 20:03:03 UTC (rev 233)
@@ -460,6 +460,7 @@
{
char v = RTEST(rval);
*(id *)ocval = (id)CFNumberCreate(NULL, kCFNumberCharType, &v);
+ CFMakeCollectable(*(id *)ocval);
return true;
}
@@ -467,6 +468,7 @@
{
double v = RFLOAT_VALUE(rval);
*(id *)ocval = (id)CFNumberCreate(NULL, kCFNumberDoubleType, &v);
+ CFMakeCollectable(*(id *)ocval);
return true;
}
@@ -487,8 +489,18 @@
*(id *)ocval = (id)CFNumberCreate(NULL, kCFNumberLongType, &v);
#endif
}
+ CFMakeCollectable(*(id *)ocval);
return true;
}
+
+ case T_SYMBOL:
+ {
+ ID name = SYM2ID(rval);
+ *(id *)ocval = (id)CFStringCreateWithCString(NULL, rb_id2name(name),
+ kCFStringEncodingASCII); /* XXX this is temporary */
+ CFMakeCollectable(*(id *)ocval);
+ return true;
+ }
}
return false;
@@ -599,34 +611,97 @@
return Data_Wrap_Struct(bs_boxed->klass, NULL, NULL, data);
}
+static long
+rebuild_new_struct_ary(ffi_type **elements, VALUE orig, VALUE new)
+{
+ long n = 0;
+ while ((*elements) != NULL) {
+ if ((*elements)->type == FFI_TYPE_STRUCT) {
+ long i, n2 = rebuild_new_struct_ary((*elements)->elements, orig, new);
+ VALUE tmp = rb_ary_new();
+ for (i = 0; i < n2; i++) {
+ if (RARRAY_LEN(orig) == 0)
+ return 0;
+ rb_ary_push(tmp, rb_ary_shift(orig));
+ }
+ rb_ary_push(new, tmp);
+ }
+ elements++;
+ n++;
+ }
+ return n;
+}
+
static void
rb_objc_rval_to_ocval(VALUE rval, const char *octype, void **ocval)
{
- bool ok;
+ bs_element_boxed_t *bs_boxed;
+ bool ok = true;
octype = rb_objc_skip_octype_modifiers(octype);
if (*octype == _C_VOID)
return;
- {
- bs_element_boxed_t *bs_boxed;
- if (st_lookup(bs_boxeds, (st_data_t)octype,
- (st_data_t *)&bs_boxed)) {
- void *data = bs_element_boxed_get_data(bs_boxed, rval, &ok);
- if (ok) {
- if (data == NULL)
- *(void **)ocval = NULL;
- else
- memcpy(ocval, data, bs_boxed->ffi_type->size);
+ if (st_lookup(bs_boxeds, (st_data_t)octype, (st_data_t *)&bs_boxed)) {
+ void *data;
+ if (TYPE(rval) == T_ARRAY && bs_boxed->type == BS_ELEMENT_STRUCT) {
+ bs_element_struct_t *bs_struct;
+ long i, n;
+ size_t pos;
+
+ bs_struct = (bs_element_struct_t *)bs_boxed->value;
+
+ n = RARRAY_LEN(rval);
+ if (n < bs_struct->fields_count)
+ rb_raise(rb_eArgError,
+ "not enough elements in array `%s' to create " \
+ "structure `%s' (%d for %d)",
+ RSTRING_CPTR(rb_inspect(rval)), bs_struct->name, n,
+ bs_struct->fields_count);
+
+ if (n > bs_struct->fields_count) {
+ VALUE new_rval = rb_ary_new();
+ VALUE orig = rval;
+ rval = rb_ary_dup(rval);
+ rebuild_new_struct_ary(bs_boxed->ffi_type->elements, rval,
+ new_rval);
+ n = RARRAY_LEN(new_rval);
+ if (RARRAY_LEN(rval) != 0 || n != bs_struct->fields_count) {
+ rb_raise(rb_eArgError,
+ "too much elements in array `%s' to create " \
+ "structure `%s' (%d for %d)",
+ RSTRING_CPTR(rb_inspect(orig)),
+ bs_struct->name, RARRAY_LEN(orig),
+ bs_struct->fields_count);
+ }
+ rval = new_rval;
}
- goto bails;
+
+ data = alloca(bs_boxed->ffi_type->size);
+
+ for (i = 0, pos = 0; i < bs_struct->fields_count; i++) {
+ VALUE o = RARRAY_AT(rval, i);
+ char *field_type = bs_struct->fields[i].type;
+ rb_objc_rval_to_ocval(o, field_type, data + pos);
+ pos += rb_objc_octype_to_ffitype(field_type)->size;
+ }
}
-
- if (st_lookup(bs_cftypes, (st_data_t)octype, NULL))
- octype = "@";
+ else {
+ data = bs_element_boxed_get_data(bs_boxed, rval, &ok);
+ }
+ if (ok) {
+ if (data == NULL)
+ *(void **)ocval = NULL;
+ else
+ memcpy(ocval, data, bs_boxed->ffi_type->size);
+ }
+ goto bails;
}
+ if (st_lookup(bs_cftypes, (st_data_t)octype, NULL))
+ octype = "@";
+
if (*octype != _C_BOOL) {
if (rval == Qtrue)
rval = INT2FIX(1);
@@ -634,7 +709,6 @@
rval = INT2FIX(0);
}
- ok = true;
switch (*octype) {
case _C_ID:
case _C_CLASS:
@@ -685,7 +759,12 @@
break;
case _C_CHR:
- *(char *)ocval = (char) NUM2INT(rb_Integer(rval));
+ if (TYPE(rval) == T_STRING && RSTRING_CLEN(rval) == 1) {
+ *(char *)ocval = RSTRING_CPTR(rval)[0];
+ }
+ else {
+ *(char *)ocval = (char) NUM2INT(rb_Integer(rval));
+ }
break;
case _C_SHT:
@@ -792,59 +871,7 @@
*rbval = Qnil;
}
else {
- /* FIXME this is a temporary hack, until String/Array/Hash will be
- * supporting their CF equivalents.
- */
- static Class nscfstring = NULL;
- static Class nscfarray = NULL;
- static Class nscfdictionary = NULL;
- Class klass;
-
- if (nscfstring == NULL)
- nscfstring = objc_getClass("NSCFString");
- if (nscfarray == NULL)
- nscfarray = objc_getClass("NSCFArray");
- if (nscfdictionary == NULL)
- nscfdictionary = objc_getClass("NSCFDictionary");
-
- klass = (Class)object_getClass(ocid);
-
- if (klass == nscfstring) {
- const char *p;
- p = [ocid UTF8String];
- *rbval = rb_enc_str_new(p, strlen(p), rb_utf8_encoding());
- }
- else if (klass == nscfarray) {
- unsigned i, count;
-
- count = [ocid count];
- *rbval = rb_ary_new();
- for (i = 0, count = [ocid count]; i < count; i++) {
- id ocelem = [ocid objectAtIndex:i];
- VALUE elem;
- rb_objc_ocval_to_rbval((void **)&ocelem, "@", &elem);
- rb_ary_push(*rbval, elem);
- }
- }
- else if (klass == nscfdictionary) {
- unsigned i, count;
- id *keys, *values;
-
- count = [ocid count];
- keys = (id *)alloca(sizeof(id) * count);
- values = (id *)alloca(sizeof(id) * count);
- [ocid getObjects:values andKeys:keys];
- *rbval = rb_hash_new();
- for (i = 0; i < count; i++) {
- VALUE key, value;
- rb_objc_ocval_to_rbval((void **)&keys[i], "@", &key);
- rb_objc_ocval_to_rbval((void **)&values[i], "@", &value);
- rb_hash_aset(*rbval, key, value);
- }
- }
- else {
- *rbval = rb_objc_boot_ocid(ocid);
- }
+ *rbval = rb_objc_boot_ocid(ocid);
}
return true;
@@ -924,6 +951,13 @@
*rbval = rb_float_new(*(double *)ocval);
break;
+ case _C_SEL:
+ {
+ const char *selname = sel_getName(*(SEL *)ocval);
+ *rbval = rb_str_new2(selname);
+ }
+ break;
+
case _C_CHARPTR:
*rbval = *(void **)ocval == NULL
? Qnil
@@ -1087,7 +1121,7 @@
ffi_argtypes[i + 2] = rb_objc_octype_to_ffitype(type);
assert(ffi_argtypes[i + 2]->size > 0);
ffi_args[i + 2] = (void *)alloca(ffi_argtypes[i + 2]->size);
- rb_objc_rval_to_ocval(RARRAY_PTR(argv)[i], type, ffi_args[i + 2]);
+ rb_objc_rval_to_ocval(RARRAY_AT(argv, i), type, ffi_args[i + 2]);
}
ffi_argtypes[count] = NULL;
@@ -1295,7 +1329,6 @@
}
}
-#if 0
static int
__rb_objc_add_ruby_method(ID mid, NODE *body, VALUE mod)
{
@@ -1305,15 +1338,26 @@
if (body == NULL || body->nd_body->nd_body == NULL)
return ST_CONTINUE;
- if (VISI(body->nd_body->nd_noex) != NOEX_PUBLIC)
+ if ((body->nd_body->nd_noex & NOEX_MASK) != NOEX_PUBLIC)
return ST_CONTINUE;
rb_objc_sync_ruby_method(mod, mid, body->nd_body->nd_body, 0);
return ST_CONTINUE;
}
-#endif
+void
+rb_objc_sync_ruby_methods(VALUE mod, VALUE klass)
+{
+ for (;;) {
+ st_foreach(RCLASS_M_TBL(mod), __rb_objc_add_ruby_method,
+ (st_data_t)klass);
+ mod = RCLASS_SUPER(mod);
+ if (mod == 0 || BUILTIN_TYPE(mod) != T_ICLASS)
+ break;
+ }
+}
+
static inline unsigned
is_ignored_selector(SEL sel)
{
@@ -2065,6 +2109,7 @@
case BS_ELEMENT_STRUCT:
{
setup_bs_boxed_type(type, value);
+ do_not_free = true;
break;
}
@@ -2077,7 +2122,7 @@
bs_class_new = (bs_element_indexed_class_t *)
malloc(sizeof(bs_element_indexed_class_t));
- bs_class_new->name = strdup(bs_class->name);
+ bs_class_new->name = bs_class->name;
#define INDEX_METHODS(table, ary, len) \
do { \
@@ -2106,6 +2151,8 @@
st_insert(bs_classes, (st_data_t)bs_class_new->name,
(st_data_t)bs_class_new);
+ free(bs_class);
+ do_not_free = true;
break;
}
@@ -2120,6 +2167,9 @@
st_insert(t, (st_data_t)bs_inf_prot_method->name,
(st_data_t)bs_inf_prot_method->type);
+ free(bs_inf_prot_method->protocol_name);
+ free(bs_inf_prot_method);
+ do_not_free = true;
break;
}
@@ -2128,6 +2178,7 @@
bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
st_insert(bs_cftypes, (st_data_t)bs_cftype->type,
(st_data_t)bs_cftype);
+ do_not_free = true;
break;
}
}
@@ -2293,270 +2344,37 @@
return Qtrue;
}
-static NSUInteger
-imp_rb_ary_count(void *rcv, SEL sel)
+static const char *
+imp_rb_boxed_objCType(void *rcv, SEL sel)
{
- return RARRAY_LEN(rcv);
-}
+ VALUE klass, type;
-static void *
-imp_rb_ary_objectAtIndex(void *rcv, SEL sel, NSUInteger idx)
-{
- VALUE element;
- void *ptr;
-
- if (idx >= RARRAY_LEN(rcv))
- [NSException raise:@"NSRangeException"
- format:@"index (%d) beyond bounds (%d)", idx, RARRAY_LEN(rcv)];
-
- element = RARRAY_PTR(rcv)[idx];
-
- if (!rb_objc_rval_to_ocid(element, &ptr))
- [NSException raise:@"NSException"
- format:@"element (%s) at index (%d) cannot be passed to " \
- "Objective-C", RSTRING_PTR(rb_inspect(element)), idx];
-
- if (ptr == NULL)
- ptr = [NSNull null];
-
- return ptr;
-}
-
-static void
-imp_rb_ary_insertObjectAtIndex(void *rcv, SEL sel, void *obj, NSUInteger idx)
-{
- VALUE robj;
-
- if (obj == NULL)
- [NSException raise:@"NSInvalidArgumentException"
- format:@"given object is nil"];
-
- if (idx >= RARRAY_LEN(rcv))
- [NSException raise:@"NSRangeException"
- format:@"index (%d) beyond bounds (%d)", idx, RARRAY_LEN(rcv)];
-
- rb_objc_ocid_to_rval(&obj, &robj);
-
- rb_ary_store((VALUE)rcv, idx, robj);
-}
-
-static void
-imp_rb_ary_removeObjectAtIndex(void *rcv, SEL sel, NSUInteger idx)
-{
- if (idx >= RARRAY_LEN(rcv))
- [NSException raise:@"NSRangeException"
- format:@"index (%d) beyond bounds (%d)", idx, RARRAY_LEN(rcv)];
+ klass = CLASS_OF(rcv);
+ type = rb_boxed_objc_type(klass);
- rb_ary_delete_at((VALUE)rcv, idx);
+ return StringValuePtr(type);
}
static void
-imp_rb_ary_addObject(void *rcv, SEL sel, void *obj)
+imp_rb_boxed_getValue(void *rcv, SEL sel, void *buffer)
{
- VALUE robj;
+ bs_element_boxed_t *bs_boxed;
+ void *data;
+ bool ok;
- rb_objc_ocid_to_rval(&obj, &robj);
+ bs_boxed = rb_klass_get_bs_boxed(CLASS_OF(rcv));
- rb_ary_push((VALUE)rcv, robj);
-}
-
-static void
-imp_rb_ary_removeLastObject(void *rcv, SEL sel)
-{
- if (RARRAY_LEN(rcv) == 0)
- [NSException raise:@"NSRangeException"
- format:@"array doesn't contain any object"];
-
- rb_ary_delete_at((VALUE)rcv, RARRAY_LEN(rcv) - 1);
-}
-
-static void
-imp_rb_ary_replaceObjectAtIndexWithObject(void *rcv, SEL sel, NSUInteger idx,
- void *obj)
-{
- VALUE robj;
-
- if (idx >= RARRAY_LEN(rcv))
- [NSException raise:@"NSRangeException"
- format:@"index (%d) beyond bounds (%d)", idx, RARRAY_LEN(rcv)];
-
- rb_objc_ocid_to_rval(&obj, &robj);
-
- rb_ary_store((VALUE)rcv, idx, robj);
-}
-
-static NSUInteger
-imp_rb_hash_count(void *rcv, SEL sel)
-{
- return RHASH_SIZE(rcv);
-}
-
-static void *
-imp_rb_hash_objectForKey(void *rcv, SEL sel, void *key)
-{
- VALUE rkey;
- VALUE val;
- void *ptr;
-
- rb_objc_ocid_to_rval(&key, &rkey);
-
- val = rb_hash_aref((VALUE)rcv, rkey);
-
- if (!rb_objc_rval_to_ocid(val, &ptr))
+ data = bs_element_boxed_get_data(bs_boxed, (VALUE)rcv, &ok);
+ if (!ok)
[NSException raise:@"NSException"
- format:@"element (%s) at key (%s) cannot be passed to Objective-C",
- RSTRING_PTR(rb_inspect(val)), RSTRING_PTR(rb_inspect(rkey))];
-
- if (ptr == NULL
- && RHASH(rcv)->ntbl != NULL
- && st_lookup(RHASH(rcv)->ntbl, (st_data_t)rkey, 0))
- ptr = [NSNull null];
-
- return ptr;
-}
-
-static void *
-imp_rb_hash_keyEnumerator(void *rcv, SEL sel)
-{
- VALUE keys;
-
- keys = rb_funcall((VALUE)rcv, rb_intern("keys"), 0, NULL);
- return [(NSArray *)keys objectEnumerator];
-}
-
-static void
-imp_rb_hash_setObjectForKey(void *rcv, SEL sel, void *obj, void *key)
-{
- VALUE robj, rkey;
-
- rb_objc_ocid_to_rval(&obj, &robj);
- rb_objc_ocid_to_rval(&key, &rkey);
-
- rb_hash_aset((VALUE)rcv, rkey, robj);
-}
-
-static void
-imp_rb_hash_removeObjectForKey(void *rcv, SEL sel, void *key)
-{
- VALUE rkey;
-
- rb_objc_ocid_to_rval(&key, &rkey);
-
- rb_hash_delete((VALUE)rcv, rkey);
-}
-
-static NSUInteger
-imp_rb_string_length(void *rcv, SEL sel)
-{
- return NUM2INT(rb_str_length((VALUE)rcv));
-}
-
-static long
-imp_rb_string_hash(void *rcv, SEL sel)
-{
- /* FIXME this is a temporary hack to make sure our custom NSString
- * subclass can be properly hashed.
- * We won't need that once String is re-implemented on top of CFString.
- */
- UniChar *buf;
- int i;
- buf = alloca(sizeof(UniChar) * RSTRING_LEN(rcv));
- for (i = 0; i < RSTRING_LEN(rcv); i++)
- buf[i] = (UniChar)RSTRING_PTR(rcv)[i];
- return CFStringHashCharacters(buf, RSTRING_LEN(rcv));
-}
-
-static UniChar
-imp_rb_string_characterAtIndex(void *rcv, SEL sel, NSUInteger idx)
-{
- VALUE rstr;
- NSString* ocstr;
- int length = NUM2INT(rb_str_length((VALUE)rcv));
- UniChar c;
- rb_encoding *enc;
-
- if (idx >= length)
- [NSException raise:@"NSRangeException"
- format:@"index (%d) beyond bounds (%d)", idx, length];
-
- enc = rb_enc_get((VALUE)rcv);
- if (enc == rb_usascii_encoding() || enc == rb_ascii8bit_encoding())
- return (UniChar)RSTRING_PTR(rcv)[idx];
-
- if (enc != rb_utf8_encoding())
- [NSException raise:@"NSException"
- format:@"encoding (%s) not supported", enc->name];
-
- /* FIXME all of this is temporary, and will be addressed once String is
- * reimplemented on top of CFString
- */
-
- rstr = rb_str_substr((VALUE)rcv, idx, 1);
- ocstr = [NSString stringWithCString:RSTRING_PTR(rstr)
- encoding:NSUTF8StringEncoding];
- return [ocstr characterAtIndex:0];
-}
-
-static void
-imp_rb_string_getCharactersRange(void *rcv, SEL sel, unichar *buffer,
- NSRange range)
-{
- VALUE rstr;
- NSString* ocstr;
- NSData* data;
- int length = NUM2INT(rb_str_length((VALUE)rcv));
- rb_encoding *enc;
-
- if (NSMaxRange(range) > length)
- [NSException raise:@"NSRangeException"
- format:@"range (%@) beyond bounds (%d)", NSStringFromRange(range),
- length];
-
- enc = rb_enc_get((VALUE)rcv);
- if (enc == rb_usascii_encoding() || enc == rb_ascii8bit_encoding()) {
- int i;
- for (i = range.location; i < range.location + range.length; i++) {
- *buffer = (UniChar)RSTRING_PTR(rcv)[i];
- buffer++;
- }
- return;
+ format:@"can't get internal data for boxed type `%s'",
+ RSTRING_PTR(rb_inspect((VALUE)rcv))];
+ if (data == NULL) {
+ *(void **)buffer = NULL;
}
-
- /* FIXME all of this is temporary, and will be addressed once String is
- * reimplemented on top of CFString
- */
-
- if (enc != rb_utf8_encoding())
- [NSException raise:@"NSException"
- format:@"encoding (%s) not supported", enc->name];
-
- rstr = rb_str_substr((VALUE)rcv, range.location, range.length);
- ocstr = [NSString stringWithCString:RSTRING_PTR(rstr) encoding:NSUTF8StringEncoding];
- data = [ocstr dataUsingEncoding:NSUTF16LittleEndianStringEncoding];
- [data getBytes:buffer];
-}
-
-static void
-imp_rb_string_replaceCharactersInRangeWithString(void *rcv, SEL sel,
- NSRange range, void *str)
-{
- VALUE newstr;
- VALUE rstr;
- int length = NUM2INT(rb_str_length((VALUE)rcv));
-
- if (length < range.location + range.length) {
- [NSException raise:@"NSRangeException"
- format:@"range (%@) beyond bounds (%d)",
- NSStringFromRange(range), length];
+ else {
+ memcpy(buffer, data, bs_boxed->ffi_type->size);
}
-
- newstr = rb_str_substr((VALUE)rcv, 0, range.location);
- rb_objc_ocid_to_rval(&str, &rstr);
- rb_str_concat(newstr, rstr);
- rb_str_concat(newstr, rb_str_substr((VALUE)rcv,
- range.location + range.length, length));
-
- rb_funcall((VALUE)rcv, rb_intern("replace"), 1, newstr);
}
static inline void
@@ -2580,46 +2398,12 @@
{
Class klass;
- /* Array */
- klass = RCLASS_OCID(rb_cArray);
- rb_objc_install_method(klass, @selector(count), (IMP)imp_rb_ary_count);
- rb_objc_install_method(klass, @selector(objectAtIndex:),
- (IMP)imp_rb_ary_objectAtIndex);
- rb_objc_install_method(klass, @selector(insertObject:atIndex:),
- (IMP)imp_rb_ary_insertObjectAtIndex);
- rb_objc_install_method(klass, @selector(removeObjectAtIndex:),
- (IMP)imp_rb_ary_removeObjectAtIndex);
- rb_objc_install_method(klass, @selector(addObject:),
- (IMP)imp_rb_ary_addObject);
- rb_objc_install_method(klass, @selector(removeLastObject),
- (IMP)imp_rb_ary_removeLastObject);
- rb_objc_install_method(klass, @selector(replaceObjectAtIndex:withObject:),
- (IMP)imp_rb_ary_replaceObjectAtIndexWithObject);
-
- /* Hash */
- klass = RCLASS_OCID(rb_cHash);
- rb_objc_install_method(klass, @selector(count), (IMP)imp_rb_hash_count);
- rb_objc_install_method(klass, @selector(objectForKey:),
- (IMP)imp_rb_hash_objectForKey);
- rb_objc_install_method(klass, @selector(keyEnumerator),
- (IMP)imp_rb_hash_keyEnumerator);
- rb_objc_install_method(klass, @selector(setObject:forKey:),
- (IMP)imp_rb_hash_setObjectForKey);
- rb_objc_install_method(klass, @selector(removeObjectForKey:),
- (IMP)imp_rb_hash_removeObjectForKey);
-
- /* String */
- klass = RCLASS_OCID(rb_cString);
- rb_objc_override_method(klass, @selector(length),
- (IMP)imp_rb_string_length);
- rb_objc_override_method(klass, @selector(hash),
- (IMP)imp_rb_string_hash);
- rb_objc_install_method(klass, @selector(characterAtIndex:),
- (IMP)imp_rb_string_characterAtIndex);
- rb_objc_install_method(klass, @selector(getCharacters:range:),
- (IMP)imp_rb_string_getCharactersRange);
- rb_objc_install_method(klass, @selector(replaceCharactersInRange:withString:),
- (IMP)imp_rb_string_replaceCharactersInRangeWithString);
+ /* Boxed */
+ klass = RCLASS_OCID(rb_cBoxed);
+ rb_objc_override_method(klass, @selector(objCType),
+ (IMP)imp_rb_boxed_objCType);
+ rb_objc_override_method(klass, @selector(getValue:),
+ (IMP)imp_rb_boxed_getValue);
}
static void *
@@ -2810,7 +2594,299 @@
}
#endif
+#if 0
+/* XXX the ivar cluster API is not used yet, and may not simply be used.
+ */
+#define IVAR_CLUSTER_NAME "__rivars__"
void
+rb_objc_install_ivar_cluster(Class klass)
+{
+ assert(class_addIvar(klass, IVAR_CLUSTER_NAME, sizeof(void *),
+ log2(sizeof(void *)), "^v") == YES);
+}
+
+void *
+rb_objc_get_ivar_cluster(void *obj)
+{
+ void *v = NULL;
+ assert(object_getInstanceVariable((id)obj, IVAR_CLUSTER_NAME, &v) != NULL);
+ return v;
+}
+
+void
+rb_objc_set_ivar_cluster(void *obj, void *v)
+{
+ assert(object_setInstanceVariable((id)obj, IVAR_CLUSTER_NAME, v) != NULL);
+}
+#endif
+
+static CFMutableDictionaryRef __obj_flags;
+
+long
+rb_objc_flag_get_mask(const void *obj)
+{
+ if (__obj_flags == NULL)
+ return 0;
+
+ return (long)CFDictionaryGetValue(__obj_flags, obj);
+}
+
+bool
+rb_objc_flag_check(const void *obj, int flag)
+{
+ long v;
+
+ v = rb_objc_flag_get_mask(obj);
+ if (v == 0)
+ return false;
+
+ return (v & flag) == flag;
+}
+
+void
+rb_objc_flag_set(const void *obj, int flag, bool val)
+{
+ long v;
+
+ if (__obj_flags == NULL) {
+ __obj_flags = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+ }
+ v = (long)CFDictionaryGetValue(__obj_flags, obj);
+ if (val) {
+ v |= flag;
+ }
+ else {
+ v ^= flag;
+ }
+ CFDictionarySetValue(__obj_flags, obj, (void *)v);
+}
+
+long
+rb_objc_remove_flags(const void *obj)
+{
+ long flag;
+ if (CFDictionaryGetValueIfPresent(__obj_flags, obj,
+ (const void **)&flag)) {
+ CFDictionaryRemoveValue(__obj_flags, obj);
+ return flag;
+ }
+ return 0;
+}
+
+static void
+rb_objc_get_types_for_format_str(char **octypes, const int len, VALUE *args,
+ const char *format_str, char **new_fmt)
+{
+ unsigned i, j, format_str_len;
+
+ format_str_len = strlen(format_str);
+ i = j = 0;
+
+ while (i < format_str_len) {
+ bool sharp_modifier = false;
+ bool star_modifier = false;
+ if (format_str[i++] != '%')
+ continue;
+ if (i < format_str_len && format_str[i] == '%') {
+ i++;
+ continue;
+ }
+ while (i < format_str_len) {
+ char *type = NULL;
+ switch (format_str[i]) {
+ case '#':
+ sharp_modifier = true;
+ break;
+
+ case '*':
+ star_modifier = true;
+ type = "i"; // C_INT;
+ break;
+
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ type = "i"; // _C_INT;
+ break;
+
+ case 'c':
+ case 'C':
+ type = "c"; // _C_CHR;
+ break;
+
+ case 'D':
+ case 'O':
+ case 'U':
+ type = "l"; // _C_LNG;
+ break;
+
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ type = "d"; // _C_DBL;
+ break;
+
+ case 's':
+ case 'S':
+ {
+ if (i - 1 > 0) {
+ long k = i - 1;
+ while (k > 0 && format_str[k] == '0')
+ k--;
+ if (k < i && format_str[k] == '.')
+ args[j] = (VALUE)CFSTR("");
+ }
+ type = "*"; // _C_CHARPTR;
+ }
+ break;
+
+ case 'p':
+ type = "^"; // _C_PTR;
+ break;
+
+ case '@':
+ type = "@"; // _C_ID;
+ break;
+
+ case 'B':
+ case 'b':
+ {
+ VALUE arg = args[j];
+ switch (TYPE(arg)) {
+ case T_STRING:
+ arg = rb_str_to_inum(arg, 0, Qtrue);
+ break;
+ }
+ arg = rb_big2str(arg, 2);
+ if (sharp_modifier) {
+ VALUE prefix = format_str[i] == 'B'
+ ? (VALUE)CFSTR("0B") : (VALUE)CFSTR("0b");
+ rb_str_update(arg, 0, 0, prefix);
+ }
+ if (*new_fmt == NULL)
+ *new_fmt = strdup(format_str);
+ (*new_fmt)[i] = '@';
+ args[j] = arg;
+ type = "@";
+ }
+ break;
+ }
+
+ i++;
+
+ if (type != NULL) {
+ if (len == 0 || j >= len)
+ rb_raise(rb_eArgError,
+ "Too much tokens in the format string `%s' "\
+ "for the given %d argument(s)", format_str, len);
+ octypes[j++] = type;
+ if (!star_modifier)
+ break;
+ }
+ }
+ }
+ for (; j < len; j++)
+ octypes[j] = "@"; // _C_ID;
+}
+
+VALUE
+rb_str_format(int argc, const VALUE *argv, VALUE fmt)
+{
+ char **types;
+ ffi_type *ffi_rettype, **ffi_argtypes;
+ void *ffi_ret, **ffi_args;
+ ffi_cif *cif;
+ int i;
+ void *null;
+ char *new_fmt;
+
+ if (argc == 0)
+ return fmt;
+
+ types = (char **)alloca(sizeof(char *) * argc);
+ ffi_argtypes = (ffi_type **)alloca(sizeof(ffi_type *) * argc + 4);
+ ffi_args = (void **)alloca(sizeof(void *) * argc + 4);
+
+ null = NULL;
+ new_fmt = NULL;
+
+ rb_objc_get_types_for_format_str(types, argc, (VALUE *)argv,
+ RSTRING_CPTR(fmt), &new_fmt);
+ if (new_fmt != NULL) {
+ fmt = (VALUE)CFStringCreateWithCString(NULL, new_fmt,
+ kCFStringEncodingUTF8);
+ free(new_fmt);
+ CFMakeCollectable((void *)fmt);
+ }
+
+ for (i = 0; i < argc; i++) {
+ ffi_argtypes[i + 3] = rb_objc_octype_to_ffitype(types[i]);
+ ffi_args[i + 3] = (void *)alloca(ffi_argtypes[i + 3]->size);
+ rb_objc_rval_to_ocval(argv[i], types[i], ffi_args[i + 3]);
+ }
+
+ ffi_argtypes[0] = &ffi_type_pointer;
+ ffi_args[0] = &null;
+ ffi_argtypes[1] = &ffi_type_pointer;
+ ffi_args[1] = &null;
+ ffi_argtypes[2] = &ffi_type_pointer;
+ ffi_args[2] = &fmt;
+
+ ffi_argtypes[argc + 4] = NULL;
+ ffi_args[argc + 4] = NULL;
+
+ ffi_rettype = &ffi_type_pointer;
+
+ cif = (ffi_cif *)alloca(sizeof(ffi_cif));
+
+ if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, argc + 3, ffi_rettype, ffi_argtypes)
+ != FFI_OK)
+ rb_fatal("can't prepare cif for CFStringCreateWithFormat");
+
+ ffi_ret = NULL;
+
+ ffi_call(cif, FFI_FN(CFStringCreateWithFormat), &ffi_ret, ffi_args);
+
+ if (ffi_ret != NULL) {
+ CFMakeCollectable((CFTypeRef)ffi_ret);
+ return (VALUE)ffi_ret;
+ }
+ return Qnil;
+}
+
+extern bool __CFStringIsMutable(void *);
+extern bool _CFArrayIsMutable(void *);
+extern bool _CFDictionaryIsMutable(void *);
+
+bool
+rb_objc_is_immutable(VALUE v)
+{
+ switch(TYPE(v)) {
+ case T_STRING:
+ return !__CFStringIsMutable((void *)v);
+ case T_ARRAY:
+ return !_CFArrayIsMutable((void *)v);
+ case T_HASH:
+ return !_CFDictionaryIsMutable((void *)v);
+ }
+ return false;
+}
+
+static void
+timer_cb(CFRunLoopTimerRef timer, void *ctx)
+{
+ RUBY_VM_CHECK_INTS();
+}
+
+void
Init_ObjC(void)
{
rb_objc_retain(bs_constants = st_init_numtable());
@@ -2822,10 +2898,13 @@
rb_objc_retain(bs_inf_prot_imethods = st_init_numtable());
rb_objc_retain(bs_cftypes = st_init_strtable());
- bs_const_magic_cookie = rb_str_new2("bs_const_magic_cookie");
- rb_objc_class_magic_cookie = rb_str_new2("rb_objc_class_magic_cookie");
+ rb_objc_retain(
+ bs_const_magic_cookie = rb_str_new2("bs_const_magic_cookie"));
+ rb_objc_retain(
+ rb_objc_class_magic_cookie = rb_str_new2("rb_objc_class_magic_cookie"));
- rb_cBoxed = rb_define_class("Boxed", rb_cObject);
+ rb_cBoxed = rb_define_class("Boxed",
+ rb_objc_import_class(objc_getClass("NSValue")));
rb_define_singleton_method(rb_cBoxed, "objc_type", rb_boxed_objc_type, 0);
rb_define_singleton_method(rb_cBoxed, "opaque?", rb_boxed_is_opaque, 0);
rb_define_singleton_method(rb_cBoxed, "fields", rb_boxed_fields, 0);
@@ -2840,4 +2919,21 @@
#endif
rb_define_global_function("load_bridge_support_file", rb_objc_load_bs, 1);
+
+ {
+ CFRunLoopTimerRef timer;
+ timer = CFRunLoopTimerCreate(NULL,
+ CFAbsoluteTimeGetCurrent(), 0.1, 0, 0, timer_cb, NULL);
+ CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopDefaultMode);
+ }
}
+
+ at interface Protocol
+ at end
+
+ at implementation Protocol (MRFindProtocol)
++(id)protocolWithName:(NSString *)name
+{
+ return (id)objc_getProtocol([name UTF8String]);
+}
+ at end
Modified: MacRuby/branches/testing/object.c
===================================================================
--- MacRuby/branches/testing/object.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/object.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -157,6 +157,13 @@
static void
init_copy(VALUE dest, VALUE obj)
{
+#if WITH_OBJC
+ if (rb_objc_is_non_native(obj)) {
+ if (rb_objc_flag_check(obj, FL_TAINT))
+ rb_objc_flag_set(dest, FL_TAINT);
+ goto call_init_copy;
+ }
+#endif
if (OBJ_FROZEN(dest)) {
rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest));
}
@@ -197,6 +204,7 @@
}
break;
}
+call_init_copy:
rb_funcall(dest, id_init_copy, 1, obj);
}
@@ -232,6 +240,15 @@
if (rb_special_const_p(obj)) {
rb_raise(rb_eTypeError, "can't clone %s", rb_obj_classname(obj));
}
+#if WITH_OBJC
+ if (rb_objc_is_non_native(obj)) {
+ clone = rb_obj_alloc(rb_obj_class(obj));
+ init_copy(clone, obj);
+ if (OBJ_FROZEN(obj))
+ OBJ_FREEZE(clone);
+ return clone;
+ }
+#endif
clone = rb_obj_alloc(rb_obj_class(obj));
#if WITH_OBJC
RBASIC(clone)->isa = RBASIC(obj)->isa;
@@ -321,12 +338,20 @@
{
VALUE str2;
const char *ivname;
+ const char *cstr;
+ cstr = RSTRING_CPTR(str);
+
/* need not to show internal data */
if (CLASS_OF(value) == 0) return ST_CONTINUE;
if (!rb_is_instance_id(id)) return ST_CONTINUE;
- if (RSTRING_PTR(str)[0] == '-') { /* first element */
+
+ if (cstr[0] == '-') { /* first element */
+#if WITH_OBJC
+ rb_str_update(str, 0, 0, rb_str_new2("#"));
+#else
RSTRING_PTR(str)[0] = '#';
+#endif
rb_str_cat2(str, " ");
}
else {
@@ -352,7 +377,11 @@
rb_ivar_foreach(obj, inspect_i, str);
}
rb_str_cat2(str, ">");
+#if WITH_OBJC
+ rb_str_update(str, 0, 0, rb_str_new2("#"));
+#else
RSTRING_PTR(str)[0] = '#';
+#endif
OBJ_INFECT(str, obj);
return str;
@@ -367,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"
*/
@@ -648,7 +677,12 @@
VALUE
rb_obj_tainted(VALUE obj)
{
- if (OBJ_TAINTED(obj))
+#if WITH_OBJC
+ if (!SPECIAL_CONST_P(obj) && rb_objc_is_non_native(obj)) {
+ return rb_objc_flag_check(obj, FL_TAINT) ? Qtrue : Qfalse;
+ }
+#endif
+ if (FL_TEST(obj, FL_TAINT))
return Qtrue;
return Qfalse;
}
@@ -666,11 +700,17 @@
rb_obj_taint(VALUE obj)
{
rb_secure(4);
+#if WITH_OBJC
+ if (!SPECIAL_CONST_P(obj) && rb_objc_is_non_native(obj)) {
+ rb_objc_flag_set(obj, FL_TAINT, true);
+ return obj;
+ }
+#endif
if (!OBJ_TAINTED(obj)) {
if (OBJ_FROZEN(obj)) {
rb_error_frozen("object");
}
- OBJ_TAINT(obj);
+ FL_SET(obj, FL_TAINT);
}
return obj;
}
@@ -687,6 +727,12 @@
rb_obj_untaint(VALUE obj)
{
rb_secure(3);
+#if WITH_OBJC
+ if (!SPECIAL_CONST_P(obj) && rb_objc_is_non_native(obj)) {
+ rb_objc_flag_set(obj, FL_TAINT, false);
+ return obj;
+ }
+#endif
if (OBJ_TAINTED(obj)) {
if (OBJ_FROZEN(obj)) {
rb_error_frozen("object");
@@ -730,13 +776,21 @@
if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) {
rb_raise(rb_eSecurityError, "Insecure: can't freeze object");
}
- OBJ_FREEZE(obj);
- if (SPECIAL_CONST_P(obj)) {
+ else if (SPECIAL_CONST_P(obj)) {
if (!immediate_frozen_tbl) {
immediate_frozen_tbl = st_init_numtable();
+ GC_ROOT(&immediate_frozen_tbl);
}
st_insert(immediate_frozen_tbl, obj, (st_data_t)Qtrue);
}
+#if WITH_OBJC
+ else if (rb_objc_is_non_native(obj)) {
+ rb_objc_flag_set(obj, FL_FREEZE, true);
+ }
+#endif
+ else {
+ FL_SET(obj, FL_FREEZE);
+ }
}
return obj;
}
@@ -755,11 +809,18 @@
VALUE
rb_obj_frozen_p(VALUE obj)
{
- if (OBJ_FROZEN(obj)) return Qtrue;
if (SPECIAL_CONST_P(obj)) {
if (!immediate_frozen_tbl) return Qfalse;
if (st_lookup(immediate_frozen_tbl, obj, 0)) return Qtrue;
+ return Qfalse;
}
+#if WITH_OBJC
+ if (rb_objc_is_non_native(obj)) {
+ return rb_objc_is_immutable(obj) || rb_objc_flag_check(obj, FL_FREEZE)
+ ? Qtrue : Qfalse;
+ }
+#endif
+ if (FL_TEST(obj, FL_FREEZE)) return Qtrue;
return Qfalse;
}
@@ -1077,8 +1138,8 @@
* end
* end
* Mod.class #=> Module
- * Mod.constants #=> ["E", "PI", "CONST"]
- * Mod.instance_methods #=> ["meth"]
+ * Mod.constants #=> [:CONST, :PI, :E]
+ * Mod.instance_methods #=> [:meth]
*
*/
@@ -1124,7 +1185,7 @@
static VALUE
rb_mod_freeze(VALUE mod)
{
- rb_mod_to_s(mod);
+ rb_class_name(mod);
return rb_obj_freeze(mod);
}
@@ -1346,15 +1407,17 @@
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;
#if WITH_OBJC
class_setSuperclass(RCLASS(klass)->ocklass, RCLASS(super)->ocklass);
+ rb_objc_install_primitives(RCLASS(klass)->ocklass, RCLASS(super)->ocklass);
#endif
rb_make_metaclass(klass, RBASIC(super)->klass);
rb_class_inherited(super, klass);
@@ -1384,9 +1447,11 @@
rb_raise(rb_eTypeError, "can't create instance of singleton class");
}
obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0);
+#if !WITH_OBJC
if (rb_obj_class(obj) != rb_class_real(klass)) {
rb_raise(rb_eTypeError, "wrong instance allocation");
}
+#endif
return obj;
}
@@ -1418,15 +1483,9 @@
#if WITH_OBJC
if (FL_TEST(klass, RCLASS_OBJC_IMPORTED)) {
static SEL sel_new = 0;
- id ocid;
if (sel_new == 0)
sel_new = sel_registerName("new");
- ocid = objc_msgSend((id)RCLASS_OCID(klass), sel_new);
- /* FIXME this is a temporary solution until the Ruby primitive classes
- * are re-implemented using their CF equivalents.
- */
- unsigned rb_objc_ocid_to_rval(void **ocval, VALUE *rbval);
- rb_objc_ocid_to_rval((void **)&ocid, &obj);
+ obj = (VALUE)objc_msgSend((id)RCLASS_OCID(klass), sel_new);
return obj;
}
#endif
@@ -1442,9 +1501,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
*
*/
@@ -1529,7 +1589,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
@@ -1645,8 +1705,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
*/
@@ -2047,7 +2107,7 @@
*
* Integer(123.999) #=> 123
* Integer("0x1a") #=> 26
- * Integer(Time.new) #=> 1049896590
+ * Integer(Time.new) #=> 1204973019
*/
static VALUE
@@ -2068,16 +2128,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;
@@ -2086,26 +2146,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) {
@@ -2125,12 +2190,12 @@
double
rb_str_to_dbl(VALUE str, int badcheck)
{
- char *s;
+ const char *s;
long len;
StringValue(str);
- s = RSTRING_PTR(str);
- len = RSTRING_LEN(str);
+ s = RSTRING_CPTR(str);
+ len = RSTRING_CLEN(str);
if (s) {
if (s[len]) { /* no sentinel somehow */
char *p = ALLOCA_N(char, len+1);
@@ -2167,13 +2232,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");
}
}
@@ -2217,15 +2276,15 @@
return RFLOAT_VALUE(rb_Float(val));
}
-char*
+const char*
rb_str2cstr(VALUE str, long *len)
{
StringValue(str);
- if (len) *len = RSTRING_LEN(str);
- else if (RTEST(ruby_verbose) && RSTRING_LEN(str) != strlen(RSTRING_PTR(str))) {
+ if (len) *len = RSTRING_CLEN(str);
+ else if (RTEST(ruby_verbose) && RSTRING_CLEN(str) != strlen(RSTRING_CPTR(str))) {
rb_warn("string contains \\0 character");
}
- return RSTRING_PTR(str);
+ return RSTRING_CPTR(str);
}
VALUE
@@ -2300,6 +2359,15 @@
return obj;
}
+#if WITH_OBJC
+static VALUE
+rb_obj_is_pure(VALUE recv)
+{
+ return rb_objc_is_non_native(recv) ? Qtrue : Qfalse;
+}
+#endif
+
+
/*
* Document-class: Class
*
@@ -2458,6 +2526,10 @@
rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1);
rb_define_method(rb_mKernel, "tap", rb_obj_tap, 0);
+#if WITH_OBJC
+ rb_define_method(rb_mKernel, "__pure__?", rb_obj_is_pure, 0);
+#endif
+
rb_define_global_function("sprintf", rb_f_sprintf, -1); /* in sprintf.c */
rb_define_global_function("format", rb_f_sprintf, -1); /* in sprintf.c */
Modified: MacRuby/branches/testing/pack.c
===================================================================
--- MacRuby/branches/testing/pack.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/pack.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -446,19 +446,23 @@
#endif
StringValue(fmt);
- p = RSTRING_PTR(fmt);
- pend = p + RSTRING_LEN(fmt);
+ p = RSTRING_CPTR(fmt);
+ pend = p + RSTRING_CLEN(fmt);
res = rb_str_buf_new(0);
+#if WITH_OBJC
+ RSTRING_PTR(res); /* create bytestring */
+#endif
+
items = RARRAY_LEN(ary);
idx = 0;
#define TOO_FEW (rb_raise(rb_eArgError, toofew), 0)
-#define THISFROM (items > 0 ? RARRAY_PTR(ary)[idx] : TOO_FEW)
-#define NEXTFROM (items-- > 0 ? RARRAY_PTR(ary)[idx++] : TOO_FEW)
+#define THISFROM (items > 0 ? RARRAY_AT(ary, idx) : TOO_FEW)
+#define NEXTFROM (items-- > 0 ? RARRAY_AT(ary, idx++) : TOO_FEW)
while (p < pend) {
- if (RSTRING_PTR(fmt) + RSTRING_LEN(fmt) != pend) {
+ if (RSTRING_CPTR(fmt) + RSTRING_CLEN(fmt) != pend) {
rb_raise(rb_eRuntimeError, "format string modified");
}
type = *p++; /* get data type */
@@ -508,9 +512,11 @@
}
else {
StringValue(from);
- ptr = RSTRING_PTR(from);
- plen = RSTRING_LEN(from);
+ ptr = RSTRING_CPTR(from);
+ plen = RSTRING_CLEN(from);
+#if !WITH_OBJC
OBJ_INFECT(res, from);
+#endif
}
if (p[-1] == '*')
@@ -841,14 +847,14 @@
case 'X': /* back up byte */
shrink:
- plen = RSTRING_LEN(res);
+ plen = RSTRING_CLEN(res);
if (plen < len)
rb_raise(rb_eArgError, "X outside of string");
rb_str_set_len(res, plen - len);
break;
case '@': /* null fill to absolute position */
- len -= RSTRING_LEN(res);
+ len -= RSTRING_CLEN(res);
if (len > 0) goto grow;
len = -len;
if (len > 0) goto shrink;
@@ -879,8 +885,8 @@
case 'm': /* base64 encoded string */
from = NEXTFROM;
StringValue(from);
- ptr = RSTRING_PTR(from);
- plen = RSTRING_LEN(from);
+ ptr = RSTRING_CPTR(from);
+ plen = RSTRING_CLEN(from);
if (len <= 2)
len = 45;
@@ -910,9 +916,9 @@
from = THISFROM;
if (!NIL_P(from)) {
StringValue(from);
- if (RSTRING_LEN(from) < len) {
+ if (RSTRING_CLEN(from) < len) {
rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
- RSTRING_LEN(from), len);
+ RSTRING_CLEN(from), len);
}
}
len = 1;
@@ -947,9 +953,9 @@
VALUE big128 = rb_uint2big(128);
while (TYPE(from) == T_BIGNUM) {
from = rb_big_divmod(from, big128);
- c = NUM2INT(RARRAY_PTR(from)[1]) | 0x80; /* mod */
+ c = NUM2INT(RARRAY_AT(from, 1)) | 0x80; /* mod */
rb_str_buf_cat(buf, &c, sizeof(char));
- from = RARRAY_PTR(from)[0]; /* div */
+ from = RARRAY_AT(from, 0); /* div */
}
}
@@ -1047,8 +1053,8 @@
{
char buff[1024];
long i = 0, n = 0, prev = EOF;
- unsigned char *s = (unsigned char*)RSTRING_PTR(from);
- unsigned char *send = s + RSTRING_LEN(from);
+ const unsigned char *s = (unsigned char*)RSTRING_CPTR(from);
+ const unsigned char *send = s + RSTRING_CLEN(from);
while (s < send) {
if ((*s > 126) ||
@@ -1140,7 +1146,9 @@
{
VALUE s = rb_str_new(ptr, len);
+#if !WITH_OBJC
OBJ_INFECT(s, str);
+#endif
return s;
}
@@ -1287,8 +1295,8 @@
pack_unpack(VALUE str, VALUE fmt)
{
static const char *hexdigits = "0123456789abcdef0123456789ABCDEFx";
- char *s, *send;
- char *p, *pend;
+ const char *s, *send;
+ const char *p, *pend;
VALUE ary;
char type;
long len;
@@ -1309,10 +1317,10 @@
StringValue(str);
StringValue(fmt);
- s = RSTRING_PTR(str);
- send = s + RSTRING_LEN(str);
- p = RSTRING_PTR(fmt);
- pend = p + RSTRING_LEN(fmt);
+ s = RSTRING_CPTR(str);
+ send = s + RSTRING_CLEN(str);
+ p = RSTRING_CPTR(fmt);
+ pend = p + RSTRING_CLEN(fmt);
ary = block_p ? Qnil : rb_ary_new();
while (p < pend) {
@@ -1365,7 +1373,7 @@
if (len > send - s) len = send - s;
{
long end = len;
- char *t = s + len - 1;
+ const char *t = s + len - 1;
while (t >= s) {
if (*t != ' ' && *t != '\0') break;
@@ -1378,7 +1386,7 @@
case 'Z':
{
- char *t = s;
+ const char *t = s;
if (len > send-s) len = send-s;
while (t < s+len && *t) t++;
@@ -1411,6 +1419,7 @@
else bits = *s++;
*t++ = (bits & 1) ? '1' : '0';
}
+ RSTRING_SYNC(bitstr);
}
break;
@@ -1431,6 +1440,7 @@
else bits = *s++;
*t++ = (bits & 128) ? '1' : '0';
}
+ RSTRING_SYNC(bitstr);
}
break;
@@ -1453,6 +1463,7 @@
bits = *s++;
*t++ = hexdigits[bits & 15];
}
+ RSTRING_SYNC(bitstr);
}
break;
@@ -1475,6 +1486,7 @@
bits = *s++;
*t++ = hexdigits[(bits >> 4) & 15];
}
+ RSTRING_SYNC(bitstr);
}
break;
@@ -1553,6 +1565,7 @@
}
PACK_ITEM_ADJUST();
break;
+
case 'L':
PACK_LENGTH_ADJUST(unsigned long,4);
while (len-- > 0) {
@@ -1573,6 +1586,7 @@
}
PACK_ITEM_ADJUST();
break;
+
case 'Q':
PACK_LENGTH_ADJUST_SIZE(QUAD_SIZE);
while (len-- > 0) {
@@ -1769,6 +1783,7 @@
}
rb_str_set_len(buf, total);
+ RSTRING_SYNC(buf);
UNPACK_PUSH(buf);
}
break;
@@ -1819,6 +1834,7 @@
}
}
rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
+ RSTRING_SYNC(buf);
UNPACK_PUSH(buf);
}
break;
@@ -1847,18 +1863,19 @@
s++;
}
rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
+ RSTRING_SYNC(buf);
UNPACK_PUSH(buf);
}
break;
case '@':
- if (len > RSTRING_LEN(str))
+ if (len > RSTRING_CLEN(str))
rb_raise(rb_eArgError, "@ outside of string");
- s = RSTRING_PTR(str) + len;
+ s = RSTRING_CPTR(str) + len;
break;
case 'X':
- if (len > s - RSTRING_PTR(str))
+ if (len > s - RSTRING_CPTR(str))
rb_raise(rb_eArgError, "X outside of string");
s -= len;
break;
@@ -1871,13 +1888,37 @@
case 'P':
if (sizeof(char *) <= send - s) {
+ VALUE tmp = Qnil;
char *t;
- VALUE tmp;
memcpy(&t, s, sizeof(char *));
s += sizeof(char *);
if (t) {
+#if WITH_OBJC
+ VALUE a;
+ long i, count;
+ if (!(a = rb_str_associated(str))) {
+ rb_raise(rb_eArgError, "no associated pointer");
+ }
+ count = RARRAY_LEN(a);
+ for (i = 0; i < count; i++) {
+ VALUE p = RARRAY_AT(a, i);
+ if (TYPE(p) == T_STRING && RSTRING_CPTR(p) == t) {
+ if (len < RSTRING_CLEN(p)) {
+ tmp = rb_tainted_str_new(t, len);
+ rb_str_associate(tmp, a);
+ }
+ else {
+ tmp = p;
+ }
+ break;
+ }
+ }
+ if (i == count) {
+ rb_raise(rb_eArgError, "non associated pointer");
+ }
+#else
VALUE a, *p, *pend;
if (!(a = rb_str_associated(str))) {
@@ -1901,6 +1942,7 @@
if (p == pend) {
rb_raise(rb_eArgError, "non associated pointer");
}
+#endif
}
else {
tmp = Qnil;
@@ -1916,13 +1958,32 @@
if (send - s < sizeof(char *))
break;
else {
- VALUE tmp;
+ VALUE tmp = Qnil;
char *t;
memcpy(&t, s, sizeof(char *));
s += sizeof(char *);
if (t) {
+#if WITH_OBJC
+ VALUE a;
+ long i, count;
+
+ if (!(a = rb_str_associated(str))) {
+ rb_raise(rb_eArgError, "no associated pointer");
+ }
+ count = RARRAY_LEN(a);
+ for (i = 0; i < count; i++) {
+ VALUE p = RARRAY_AT(a, i);
+ if (TYPE(p) == T_STRING && RSTRING_CPTR(p) == t) {
+ tmp = p;
+ break;
+ }
+ }
+ if (i == count) {
+ rb_raise(rb_eArgError, "non associated pointer");
+ }
+#else
VALUE a, *p, *pend;
if (!(a = rb_str_associated(str))) {
@@ -1931,7 +1992,7 @@
p = RARRAY_PTR(a);
pend = p + RARRAY_LEN(a);
while (p < pend) {
- if (TYPE(*p) == T_STRING && RSTRING_PTR(*p) == t) {
+ if (TYPE(*p) == T_STRING && RSTRING_CPTR(*p) == t) {
tmp = *p;
break;
}
@@ -1940,6 +2001,7 @@
if (p == pend) {
rb_raise(rb_eArgError, "non associated pointer");
}
+#endif
}
else {
tmp = Qnil;
Modified: MacRuby/branches/testing/parse.y
===================================================================
--- MacRuby/branches/testing/parse.y 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/parse.y 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -217,7 +217,10 @@
int parser_lpar_beg;
int parser_in_single;
int parser_in_def;
+#if WITH_OBJC
int parser_in_def_named_args;
+ char parser_named_mid[1024];
+#endif
int parser_compile_for_eval;
VALUE parser_cur_mid;
int parser_in_defined;
@@ -266,14 +269,23 @@
#endif
};
-#define UTF8_ENC() (parser->utf8 ? parser->utf8 : \
+#if WITH_OBJC
+# define UTF8_ENC() (NULL)
+#else
+# define UTF8_ENC() (parser->utf8 ? parser->utf8 : \
(parser->utf8 = rb_utf8_encoding()))
+#endif
#define STR_NEW(p,n) rb_enc_str_new((p),(n),parser->enc)
#define STR_NEW0() rb_usascii_str_new(0,0)
#define STR_NEW2(p) rb_enc_str_new((p),strlen(p),parser->enc)
#define STR_NEW3(p,n,e,func) parser_str_new((p),(n),(e),(func),parser->enc)
-#define STR_ENC(m) ((m)?parser->enc:rb_usascii_encoding())
-#define ENC_SINGLE(cr) ((cr)==ENC_CODERANGE_7BIT)
+#if WITH_OBJC
+# define STR_ENC(m) (parser->enc)
+# define ENC_SINGLE(cr) (1)
+#else
+# define STR_ENC(m) ((m)?parser->enc:rb_usascii_encoding())
+# define ENC_SINGLE(cr) ((cr)==ENC_CODERANGE_7BIT)
+#endif
#define TOK_INTERN(mb) rb_intern3(tok(), toklen(), STR_ENC(mb))
#ifdef YYMALLOC
@@ -297,7 +309,10 @@
#define lpar_beg (parser->parser_lpar_beg)
#define in_single (parser->parser_in_single)
#define in_def (parser->parser_in_def)
-#define in_def_named_args (parser->parser_in_def_named_args)
+#if WITH_OBJC
+# define in_def_named_args (parser->parser_in_def_named_args)
+# define named_mid (parser->parser_named_mid)
+#endif
#define compile_for_eval (parser->parser_compile_for_eval)
#define cur_mid (parser->parser_cur_mid)
#define in_defined (parser->parser_in_defined)
@@ -417,8 +432,10 @@
#define local_var(id) local_var_gen(parser, id);
static int arg_var_gen(struct parser_params*, ID);
#define arg_var(id) arg_var_gen(parser, id)
-static int named_arg_gen(struct parser_params*, ID);
-#define named_arg(id) named_arg_gen(parser, id)
+#if WITH_OBJC
+static int named_arg_gen(struct parser_params*, ID, int);
+# define named_arg(id, flag) named_arg_gen(parser, id, flag)
+#endif
static int local_id_gen(struct parser_params*, ID);
#define local_id(id) local_id_gen(parser, id)
static ID *local_tbl_gen(struct parser_params*);
@@ -562,10 +579,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, ...);
@@ -1796,9 +1811,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
@@ -1830,6 +1847,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
{
/*%%%*/
@@ -2905,7 +2953,10 @@
$<id>$ = cur_mid;
cur_mid = $2;
in_def++;
+#if WITH_OBJC
in_def_named_args = 0;
+ named_arg($2, 1);
+#endif
/*%%%*/
local_push(0);
/*%
@@ -2917,13 +2968,23 @@
{
/*%%%*/
NODE *body = remove_begin($5);
+ ID mid = $2;
reduce_nodes(&body);
- $$ = NEW_DEFN(cur_mid, $4, body, NOEX_PRIVATE);
+#if WITH_OBJC
+ if (in_def_named_args > 0)
+ mid = rb_intern(named_mid);
+#endif
+ $$ = NEW_DEFN(mid, $4, body, NOEX_PRIVATE);
fixpos($$, $4);
+#if WITH_OBJC
if (in_def_named_args > 0
- && in_def_named_args !=
- $$->nd_defn->nd_args->nd_frml - 1)
- yyerror("invalid use of named arguments in method definition");
+ && in_def_named_args
+ != $$->nd_defn->nd_args->nd_frml - 1) {
+ yyerror("invalid use of named arguments in " \
+ "method definition");
+ }
+ in_def_named_args = 0;
+#endif
local_pop();
in_def--;
cur_mid = $<id>3;
@@ -2937,6 +2998,10 @@
{
in_single++;
lex_state = EXPR_END; /* force for args */
+#if WITH_OBJC
+ in_def_named_args = 0;
+ named_arg($5, 1);
+#endif
/*%%%*/
local_push(0);
/*%
@@ -2948,9 +3013,23 @@
{
/*%%%*/
NODE *body = remove_begin($8);
+ ID mid = $5;
reduce_nodes(&body);
- $$ = NEW_DEFS($2, $5, $7, body);
+#if WITH_OBJC
+ if (in_def_named_args > 0)
+ mid = rb_intern(named_mid);
+#endif
+ $$ = NEW_DEFS($2, mid, $7, body);
fixpos($$, $2);
+#if WITH_OBJC
+ if (in_def_named_args > 0
+ && in_def_named_args
+ != $$->nd_defn->nd_args->nd_frml - 1) {
+ yyerror("invalid use of named arguments in " \
+ "method definition");
+ }
+ in_def_named_args = 0;
+#endif
local_pop();
in_single--;
/*%
@@ -4239,12 +4318,16 @@
}
| tIDENTIFIER tASSOC tIDENTIFIER
{
- named_arg($1);
+#if WITH_OBJC
+ named_arg($1, 0);
+#endif
$$ = $3;
}
| tLABEL tIDENTIFIER
{
- named_arg($1);
+#if WITH_OBJC
+ named_arg($1, 0);
+#endif
$$ = $2;
}
;
@@ -4641,8 +4724,10 @@
# define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128)
#endif
+#if !WITH_OBJC
#define parser_mbclen() mbclen((lex_p-1),lex_pend,parser->enc)
#define parser_precise_mbclen() rb_enc_precise_mbclen((lex_p-1),lex_pend,parser->enc)
+#endif
#define is_identchar(p,e,enc) (rb_enc_isalnum(*p,enc) || (*p) == '_' || !ISASCII(*p))
#define parser_is_identchar() (!parser->eofp && is_identchar((lex_p-1),lex_pend,parser->enc))
@@ -4678,11 +4763,19 @@
if (len > max_line_margin * 2 + 10) {
if (lex_p - p > max_line_margin) {
+#if WITH_OBJC
+ p = lex_p - max_line_margin;
+#else
p = rb_enc_prev_char(p, lex_p - max_line_margin, rb_enc_get(lex_lastline));
+#endif
pre = "...";
}
if (pe - lex_p > max_line_margin) {
+#if WITH_OBJC
+ pe = lex_p + max_line_margin;
+#else
pe = rb_enc_prev_char(lex_p, lex_p + max_line_margin, rb_enc_get(lex_lastline));
+#endif
post = "...";
}
len = pe - p;
@@ -4721,11 +4814,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;
}
}
@@ -4782,7 +4872,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);
}
@@ -4791,20 +4881,52 @@
static VALUE
lex_get_str(struct parser_params *parser, VALUE s)
{
- char *beg, *end, *pend;
+#if WITH_OBJC
+ long beg, len, n;
+ CFRange search_range;
+ VALUE v;
+
+ beg = 0;
+ n = CFStringGetLength((CFStringRef)s);
+ if (lex_gets_ptr > 0) {
+ if (n == lex_gets_ptr)
+ return Qnil;
+ beg += lex_gets_ptr;
+ }
+ if (CFStringFindCharacterFromSet((CFStringRef)s,
+ CFCharacterSetGetPredefined(kCFCharacterSetNewline),
+ CFRangeMake(beg, n - beg),
+ 0,
+ &search_range)) {
+ lex_gets_ptr = search_range.location + 1;
+ len = search_range.location - beg;
+ }
+ else {
+ lex_gets_ptr = n;
+ len = lex_gets_ptr - beg;
+ }
+ v = (VALUE)CFStringCreateWithSubstring(NULL, (CFStringRef)s,
+ CFRangeMake(beg, lex_gets_ptr - beg));
+ CFMakeCollectable((CFTypeRef)v);
+ return v;
+#else
+ const char *cptr, *beg, *end, *pend;
+ long clen;
- beg = RSTRING_PTR(s);
+ cptr = beg = RSTRING_PTR(s);
+ clen = RSTRING_LEN(s);
if (lex_gets_ptr) {
- if (RSTRING_LEN(s) == lex_gets_ptr) return Qnil;
+ if (clen == lex_gets_ptr) return Qnil;
beg += lex_gets_ptr;
}
- pend = RSTRING_PTR(s) + RSTRING_LEN(s);
+ pend = cptr + clen;
end = beg;
while (end < pend) {
if (*end++ == '\n') break;
}
- lex_gets_ptr = end - RSTRING_PTR(s);
+ lex_gets_ptr = end - cptr;
return rb_enc_str_new(beg, end - beg, rb_enc_get(s));
+#endif
}
static VALUE
@@ -4916,7 +5038,17 @@
{
VALUE str;
+#if WITH_OBJC
+ if (p[n] != '\0') {
+ /* Let's not create unnecessary bytestrings. */
+ long slen = strlen(p);
+ if (slen < n)
+ n = slen;
+ }
+#endif
+
str = rb_enc_str_new(p, n, enc);
+#if !WITH_OBJC
if (!(func & STR_FUNC_REGEXP) && rb_enc_asciicompat(enc)) {
if (rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT) {
rb_enc_associate(str, rb_usascii_encoding());
@@ -4925,6 +5057,7 @@
rb_enc_associate(str, rb_ascii8bit_encoding());
}
}
+#endif
return str;
}
@@ -5242,8 +5375,14 @@
static void
parser_tokaddmbc(struct parser_params *parser, int c, rb_encoding *enc)
{
+#if WITH_OBJC
+ /* FIXME */
+ char *buf = tokspace(1);
+ *(buf) = c;
+#else
int len = rb_enc_codelen(c, enc);
rb_enc_mbcput(c, tokspace(len), enc);
+#endif
}
static int
@@ -5320,7 +5459,7 @@
return -1;
default:
- tokadd('\\');
+ tokadd('\\');
tokadd(c);
}
return 0;
@@ -5361,19 +5500,25 @@
dispose_string(VALUE str)
{
/* TODO: should use another API? */
+#if !WITH_OBJC
if (RBASIC(str)->flags & RSTRING_NOEMBED)
xfree(RSTRING_PTR(str));
+#endif
rb_gc_force_recycle(str);
}
static int
parser_tokadd_mbchar(struct parser_params *parser, int c)
{
+#if WITH_OBJC
+ int len = 1;
+#else
int len = parser_precise_mbclen();
if (!MBCLEN_CHARFOUND_P(len)) {
compile_error(PARSER_ARG "invalid multibyte char");
return -1;
}
+#endif
tokadd(c);
lex_p += --len;
if (len > 0) tokcopy(len);
@@ -5686,8 +5831,8 @@
long len;
VALUE str = 0;
- eos = RSTRING_PTR(here->nd_lit);
- len = RSTRING_LEN(here->nd_lit) - 1;
+ eos = RSTRING_CPTR(here->nd_lit);
+ len = RSTRING_CLEN(here->nd_lit) - 1;
indent = (func = *eos++) & STR_FUNC_INDENT;
if ((c = nextc()) == -1) {
@@ -5705,7 +5850,7 @@
if (!(func & STR_FUNC_EXPAND)) {
do {
- p = RSTRING_PTR(lex_lastline);
+ p = RSTRING_CPTR(lex_lastline);
pend = lex_pend;
if (pend > p) {
switch (pend[-1]) {
@@ -5816,8 +5961,15 @@
static void
parser_set_encode(struct parser_params *parser, const char *name)
{
+ rb_encoding *enc;
+#if WITH_OBJC
+ enc = rb_enc_find(name);
+ if (enc == NULL) {
+ rb_raise(rb_eArgError, "unknown encoding name: %s", name);
+ }
+ /* TODO should raise if the encoding is not ASCII compatible */
+#else
int idx = rb_enc_find_index(name);
- rb_encoding *enc;
if (idx < 0) {
rb_raise(rb_eArgError, "unknown encoding name: %s", name);
@@ -5826,6 +5978,7 @@
if (!rb_enc_asciicompat(enc)) {
rb_raise(rb_eArgError, "%s is not ASCII compatible", rb_enc_name(enc));
}
+#endif
parser->enc = enc;
}
@@ -5891,10 +6044,16 @@
{
VALUE name = 0, val = 0;
const char *beg, *end, *vbeg, *vend;
-#define str_copy(_s, _p, _n) ((_s) \
+#if WITH_OBJC
+# define str_copy(_s, _p, _n) ((_s) \
+ ? CFStringPad((CFMutableStringRef)_s, CFMakeCollectable(CFStringCreateWithCString(NULL, _p, kCFStringEncodingUTF8)), _n, 0) \
+ : ((_s) = STR_NEW((_p), (_n))))
+#else
+# define str_copy(_s, _p, _n) ((_s) \
? (rb_str_resize((_s), (_n)), \
MEMCPY(RSTRING_PTR(_s), (_p), char, (_n)), (_s)) \
: ((_s) = STR_NEW((_p), (_n))))
+#endif
if (len <= 7) return Qfalse;
if (!(beg = magic_comment_marker(str, len))) return Qfalse;
@@ -5955,13 +6114,13 @@
str_copy(name, beg, n);
#ifndef RIPPER
do {
- if (STRNCASECMP(p->name, RSTRING_PTR(name), n) == 0) {
+ if (STRNCASECMP(p->name, RSTRING_CPTR(name), n) == 0) {
n = vend - vbeg;
if (p->length) {
n = (*p->length)(parser, vbeg, n);
}
str_copy(val, vbeg, n);
- (*p->func)(parser, RSTRING_PTR(name), RSTRING_PTR(val));
+ (*p->func)(parser, RSTRING_CPTR(name), RSTRING_CPTR(val));
break;
}
} while (++p < magic_comments + sizeof(magic_comments) / sizeof(*p));
@@ -6012,7 +6171,7 @@
beg = str;
while ((*str == '-' || *str == '_' || ISALNUM(*str)) && ++str < send);
s = rb_str_new(beg, parser_encode_length(parser, beg, str - beg));
- parser_set_encode(parser, RSTRING_PTR(s));
+ parser_set_encode(parser, RSTRING_CPTR(s));
rb_str_resize(s, 0);
}
@@ -6039,6 +6198,10 @@
}
pushback(c);
parser->enc = rb_enc_get(lex_lastline);
+#if !WITH_OBJC
+ if (parser->enc == NULL)
+ parser->enc = rb_utf8_encoding();
+#endif
}
#define IS_ARG() (lex_state == EXPR_ARG || lex_state == EXPR_CMDARG)
@@ -6675,7 +6838,7 @@
if (c == 'o' || c == 'O') {
/* prefixed octal */
c = nextc();
- if (c == '_') {
+ if (c == '_' || !ISDIGIT(c)) {
yyerror("numeric literal without digits");
}
}
@@ -6788,7 +6951,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));
@@ -7200,17 +7363,27 @@
break;
}
+#if !WITH_OBJC
mb = ENC_CODERANGE_7BIT;
+#endif
do {
+#if !WITH_OBJC
if (!ISASCII(c)) mb = ENC_CODERANGE_UNKNOWN;
+#endif
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();
@@ -7255,7 +7428,11 @@
}
}
+#if WITH_OBJC
+ if (lex_state != EXPR_DOT) {
+#else
if (mb == ENC_CODERANGE_7BIT && lex_state != EXPR_DOT) {
+#endif
const struct kwtable *kw;
/* See if it is a reserved word. */
@@ -7360,7 +7537,6 @@
{
NODE *n = (rb_node_newnode)(type, a0, a1, a2);
nd_set_line(n, ruby_sourceline);
- n->nd_file = ruby_sourcefile;
return n;
}
@@ -7392,21 +7568,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)
@@ -7506,15 +7683,22 @@
return head;
}
-static void
+static int
literal_concat0(struct parser_params *parser, VALUE head, VALUE tail)
{
+#if !WITH_OBJC
if (!rb_enc_compatible(head, tail)) {
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 */
@@ -7534,7 +7718,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 {
@@ -7544,7 +7733,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;
@@ -8178,23 +8368,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*);
@@ -8204,14 +8394,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;
@@ -8253,7 +8443,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:
@@ -8268,7 +8458,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))) {
@@ -8283,7 +8473,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 {
@@ -8472,19 +8662,20 @@
return vtable_size(lvtbl->args) - 1;
}
-static int named_arg_gen(struct parser_params *parser, ID id)
+#if WITH_OBJC
+static int
+named_arg_gen(struct parser_params *parser, ID id, int init)
{
- char buf[256];
-
- strlcpy(buf, rb_id2name(cur_mid), sizeof buf);
- if (in_def_named_args == 0)
- strlcat(buf, ":", sizeof buf);
- strlcat(buf, rb_id2name(id), sizeof buf);
- strlcat(buf, ":", sizeof buf);
- cur_mid = rb_intern(buf);
-
- in_def_named_args++;
+ if (init)
+ memset(named_mid, 0, sizeof named_mid);
+
+ strlcat(named_mid, rb_id2name(id), sizeof named_mid);
+ strlcat(named_mid, ":", sizeof named_mid);
+
+ if (!init)
+ in_def_named_args++;
}
+#endif
static int
local_var_gen(struct parser_params *parser, ID id)
@@ -8580,6 +8771,9 @@
static void
reg_fragment_setenc_gen(struct parser_params* parser, VALUE str, int options)
{
+#if WITH_OBJC
+ /* TODO */
+#else
int c = RE_OPTION_ENCODING_IDX(options);
if (c) {
@@ -8614,6 +8808,7 @@
compile_error(PARSER_ARG
"regexp encoding option '%c' differs from source encoding '%s'",
c, rb_enc_name(rb_enc_get(str)));
+#endif
}
static void
@@ -8624,7 +8819,7 @@
err = rb_reg_check_preprocess(str);
if (err != Qnil) {
err = rb_obj_as_string(err);
- compile_error(PARSER_ARG "%s", RSTRING_PTR(err));
+ compile_error(PARSER_ARG "%s", RSTRING_CPTR(err));
RB_GC_GUARD(err);
}
}
@@ -8725,7 +8920,7 @@
rb_str_append(rb_str_cat(rb_attr_get(err, mesg), "\n", 1), m);
}
else {
- compile_error(PARSER_ARG "%s", RSTRING_PTR(m));
+ compile_error(PARSER_ARG "%s", RSTRING_CPTR(m));
}
return Qnil;
}
@@ -8853,13 +9048,13 @@
static struct symbols {
ID last_id;
- st_table *sym_id;
- st_table *id_str;
- st_table *ivar2_id;
- st_table *id_ivar2;
#if WITH_OBJC
+ CFMutableDictionaryRef sym_id;
+ CFMutableDictionaryRef id_str;
VALUE *op_sym;
#else
+ st_table *sym_id;
+ st_table *id_str;
VALUE op_sym[tLAST_TOKEN];
#endif
} global_symbols = {tLAST_TOKEN >> ID_SCOPE_SHIFT};
@@ -8897,21 +9092,24 @@
void
Init_sym(void)
{
- global_symbols.sym_id = st_init_table_with_size(&symhash, 1000);
+#if WITH_OBJC
+ CFDictionaryKeyCallBacks cb;
+ global_symbols.sym_id = CFDictionaryCreateMutable(NULL,
+ 0, NULL, NULL);
GC_ROOT(&global_symbols.sym_id);
- global_symbols.id_str = st_init_numtable_with_size(1000);
+ global_symbols.id_str = CFDictionaryCreateMutable(NULL,
+ 0, NULL, &kCFTypeDictionaryValueCallBacks);
GC_ROOT(&global_symbols.id_str);
- global_symbols.ivar2_id = st_init_table_with_size(&ivar2_hash_type, 1000);
- GC_ROOT(&global_symbols.ivar2_id);
- global_symbols.id_ivar2 = st_init_numtable_with_size(1000);
- GC_ROOT(&global_symbols.id_ivar2);
-#if WITH_OBJC
global_symbols.op_sym = xmalloc(sizeof(VALUE) * tLAST_TOKEN);
GC_ROOT(&global_symbols.op_sym);
+#else
+ global_symbols.sym_id = st_init_table_with_size(&symhash, 1000);
+ global_symbols.id_str = st_init_numtable_with_size(1000);
#endif
rb_intern2("", 0);
}
+#if !WITH_OBJC
void
rb_gc_mark_symbols(void)
{
@@ -8919,6 +9117,7 @@
rb_gc_mark_locations(global_symbols.op_sym,
global_symbols.op_sym + tLAST_TOKEN);
}
+#endif
static ID
internal_id_gen(struct parser_params *parser)
@@ -8946,7 +9145,11 @@
++m;
if (m < e && is_identchar(m, e, enc)) {
if (!ISASCII(*m)) mb = 1;
+#if WITH_OBJC
+ m += 1;
+#else
m += rb_enc_mbclen(m, e, enc);
+#endif
}
break;
default:
@@ -8962,7 +9165,11 @@
int
rb_symname_p(const char *name)
{
+#if WITH_OBJC
+ return rb_enc_symname_p(name, NULL);
+#else
return rb_enc_symname_p(name, rb_ascii8bit_encoding());
+#endif
}
int
@@ -9043,7 +9250,11 @@
id:
if (m >= e || (*m != '_' && !rb_enc_isalpha(*m, enc) && ISASCII(*m)))
return Qfalse;
+#if WITH_OBJC
+ while (m < e && is_identchar(m, e, enc)) m += 1;
+#else
while (m < e && is_identchar(m, e, enc)) m += rb_enc_mbclen(m, e, enc);
+#endif
if (localid) {
switch (*m) {
case '!': case '?': case '=': ++m;
@@ -9063,10 +9274,9 @@
ID id;
int last;
int mb;
+#if !WITH_OBJC
struct RString fake_str;
-#if WITH_OBJC
fake_str.basic.isa = NULL;
-#endif
fake_str.basic.flags = T_STRING|RSTRING_NOEMBED|FL_FREEZE;
fake_str.basic.klass = rb_cString;
fake_str.as.heap.len = len;
@@ -9077,6 +9287,22 @@
if (st_lookup(global_symbols.sym_id, str, (st_data_t *)&id))
return id;
+#else
+ long sname = strlen(name);
+ assert(len <= sname);
+ if (sname != len) {
+ char *tmp = (char *)alloca(len + 1);
+ memcpy(tmp, name, len);
+ tmp[len] = '\0';
+ m = name = tmp;
+ e = m + len;
+ }
+ SEL name_hash = sel_registerName(name);
+ id = (ID)CFDictionaryGetValue((CFDictionaryRef)global_symbols.sym_id,
+ (const void *)name_hash);
+ if (id != 0)
+ return id;
+#endif
last = len-1;
id = 0;
@@ -9084,7 +9310,13 @@
case '$':
id |= ID_GLOBAL;
if ((mb = is_special_global_name(++m, e, enc)) != 0) {
- if (!--mb) enc = rb_ascii8bit_encoding();
+ if (!--mb) {
+#if WITH_OBJC
+ enc = NULL;
+#else
+ enc = rb_ascii8bit_encoding();
+#endif
+ }
goto new_id;
}
break;
@@ -9139,11 +9371,16 @@
}
else {
mb = 1;
+#if WITH_OBJC
+ m += 1;
+#else
m += rb_enc_mbclen(m, e, enc);
+#endif
}
}
}
if (m - name < len) id = ID_JUNK;
+#if !WITH_OBJC
if (enc != rb_usascii_encoding()) {
/*
* this clause makes sense only when called from other than
@@ -9157,20 +9394,32 @@
}
mbstr:;
}
+#endif
new_id:
id |= ++global_symbols.last_id << ID_SCOPE_SHIFT;
id_register:
str = rb_enc_str_new(name, len, enc);
OBJ_FREEZE(str);
+#if WITH_OBJC
+ CFDictionarySetValue(global_symbols.sym_id, (const void *)name_hash,
+ (const void *)id);
+ CFDictionarySetValue(global_symbols.id_str, (const void *)id,
+ (const void *)str);
+#else
st_add_direct(global_symbols.sym_id, (st_data_t)str, id);
st_add_direct(global_symbols.id_str, id, (st_data_t)str);
+#endif
return id;
}
ID
rb_intern2(const char *name, long len)
{
+#if WITH_OBJC
+ return rb_intern3(name, len, NULL);
+#else
return rb_intern3(name, len, rb_usascii_encoding());
+#endif
}
#undef rb_intern
@@ -9186,13 +9435,17 @@
rb_encoding *enc;
ID id;
+#if WITH_OBJC
+ enc = rb_enc_get(str);
+#else
if (rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT) {
enc = rb_usascii_encoding();
}
else {
enc = rb_enc_get(str);
}
- id = rb_intern3(RSTRING_PTR(str), RSTRING_LEN(str), enc);
+#endif
+ id = rb_intern3(RSTRING_CPTR(str), RSTRING_CLEN(str), enc);
RB_GC_GUARD(str);
return id;
}
@@ -9218,16 +9471,20 @@
}
}
+#if WITH_OBJC
+ data = (VALUE)CFDictionaryGetValue(
+ (CFDictionaryRef)global_symbols.id_str,
+ (const void *)id);
+ if (data != 0)
+ return data;
+#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;
-#if WITH_OBJC
- RBASIC(str)->isa = RCLASS(rb_cString)->ocklass;
-#endif
- }
return str;
}
+#endif
if (is_attrset_id(id)) {
ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL;
@@ -9240,12 +9497,20 @@
str = rb_str_dup(str);
rb_str_cat(str, "=", 1);
rb_intern_str(str);
+#if WITH_OBJC
+ data = (VALUE)CFDictionaryGetValue(
+ (CFDictionaryRef)global_symbols.id_str,
+ (const void *)id);
+ if (data != 0)
+ return data;
+#else
if (st_lookup(global_symbols.id_str, id, &data)) {
VALUE str = (VALUE)data;
if (RBASIC(str)->klass == 0)
RBASIC(str)->klass = rb_cString;
return str;
}
+#endif
}
return 0;
}
@@ -9256,7 +9521,7 @@
VALUE str = rb_id2str(id);
if (!str) return 0;
- return RSTRING_PTR(str);
+ return RSTRING_CPTR(str);
}
static int
@@ -9285,9 +9550,15 @@
VALUE
rb_sym_all_symbols(void)
{
+#if WITH_OBJC
+ VALUE ary = rb_ary_new();
+ CFDictionaryApplyFunction((CFDictionaryRef)global_symbols.sym_id,
+ (CFDictionaryApplierFunction)symbols_i, (void *)ary);
+#else
VALUE ary = rb_ary_new2(global_symbols.sym_id->num_entries);
st_foreach(global_symbols.sym_id, symbols_i, ary);
+#endif
return ary;
}
@@ -9372,11 +9643,13 @@
#ifdef YYMALLOC
parser->heap = NULL;
#endif
+#if WITH_OBJC
+ parser->enc = NULL;
+#else
parser->enc = rb_usascii_encoding();
+#endif
}
-extern void rb_mark_source_filename(char *);
-
#ifdef RIPPER
#define parser_mark ripper_parser_mark
#define parser_free ripper_parser_free
@@ -9395,7 +9668,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);
@@ -9422,6 +9694,9 @@
prev = local->prev;
xfree(local);
}
+#ifndef RIPPER
+ xfree(p->parser_ruby_sourcefile);
+#endif
xfree(p);
}
@@ -9803,14 +10078,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)
@@ -9848,7 +10121,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);
@@ -9862,17 +10134,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_PTR(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;
@@ -9983,7 +10253,7 @@
{
StringValue(msg);
if (obj == Qundef) {
- rb_raise(rb_eArgError, "%s", RSTRING_PTR(msg));
+ rb_raise(rb_eArgError, "%s", RSTRING_CPTR(msg));
}
return Qnil;
}
Modified: MacRuby/branches/testing/prelude.rb
===================================================================
--- MacRuby/branches/testing/prelude.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/prelude.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/proc.c
===================================================================
--- MacRuby/branches/testing/proc.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/proc.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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;
}
@@ -680,7 +681,7 @@
line_no = iseq->insn_info_table[0].line_no;
}
str = rb_sprintf("#<%s:%p@%s:%d%s>", cname, (void *)self,
- RSTRING_PTR(iseq->filename),
+ RSTRING_CPTR(iseq->filename),
line_no, is_lambda);
}
else {
@@ -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);
}
/*
@@ -1504,9 +1505,15 @@
{
volatile VALUE a;
+#if WITH_OBJC
+ if (TYPE(args) != T_ARRAY) {
+ return rb_method_call(1, &args, method);
+ }
+#else
if (CLASS_OF(args) != rb_cArray) {
args = rb_ary_new3(1, args);
}
+#endif
a = args;
return rb_method_call(RARRAY_LEN(a), RARRAY_PTR(a), method);
@@ -1597,7 +1604,6 @@
*
* b = fred(99)
* eval("param", b.binding) #=> 99
- * eval("param", b) #=> 99
*/
static VALUE
proc_binding(VALUE self)
@@ -1609,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");
}
@@ -1623,11 +1629,15 @@
static VALUE
make_curry_proc(VALUE proc, VALUE passed, VALUE arity)
{
+#if WITH_OBJC
+ VALUE args = rb_ary_new3(3, proc, passed, arity);
+#else
VALUE args = rb_ary_new2(3);
RARRAY_PTR(args)[0] = proc;
RARRAY_PTR(args)[1] = passed;
RARRAY_PTR(args)[2] = arity;
RARRAY_LEN(args) = 3;
+#endif
rb_ary_freeze(passed);
rb_ary_freeze(args);
return rb_proc_new(curry, args);
@@ -1637,9 +1647,9 @@
curry(VALUE dummy, VALUE args, int argc, VALUE *argv)
{
VALUE proc, passed, arity;
- proc = RARRAY_PTR(args)[0];
- passed = RARRAY_PTR(args)[1];
- arity = RARRAY_PTR(args)[2];
+ proc = RARRAY_AT(args, 0);
+ passed = RARRAY_AT(args, 1);
+ arity = RARRAY_AT(args, 2);
passed = rb_ary_plus(passed, rb_ary_new4(argc, argv));
rb_ary_freeze(passed);
Modified: MacRuby/branches/testing/process.c
===================================================================
--- MacRuby/branches/testing/process.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/process.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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;
@@ -1022,7 +1045,7 @@
args = ALLOCA_N(char*, argc+1);
for (i=0; i<argc; i++) {
- args[i] = RSTRING_PTR(argv[i]);
+ args[i] = (char *)RSTRING_CPTR(argv[i]);
}
args[i] = 0;
if (args[0]) {
@@ -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;
@@ -1161,11 +1188,11 @@
args = ALLOCA_N(char*, argc + 1);
for (i = 0; i < argc; i++) {
- args[i] = RSTRING_PTR(argv[i]);
+ args[i] = RSTRING_CPTR(argv[i]);
}
args[i] = (char*) 0;
if (args[0])
- return proc_spawn_v(args, prog ? RSTRING_PTR(prog) : 0);
+ return proc_spawn_v(args, prog ? RSTRING_CPTR(prog) : 0);
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;
@@ -1219,32 +1587,101 @@
if (RARRAY_LEN(tmp) != 2) {
rb_raise(rb_eArgError, "wrong first argument");
}
- prog = RARRAY_PTR(tmp)[0];
- argv[0] = RARRAY_PTR(tmp)[1];
+ prog = RARRAY_AT(tmp, 0);
+ argv[0] = RARRAY_AT(tmp, 1);
SafeStringValue(prog);
StringValueCStr(prog);
prog = rb_str_new4(prog);
- name = RSTRING_PTR(prog);
+ name = RSTRING_CPTR(prog);
}
for (i = 0; i < argc; i++) {
SafeStringValue(argv[i]);
argv[i] = rb_str_new4(argv[i]);
StringValueCStr(argv[i]);
}
- security(name ? name : RSTRING_PTR(argv[0]));
+ security(name ? name : RSTRING_CPTR(argv[0]));
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_PTR(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_PTR(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_PTR(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_PTR(prog));
+ 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
@@ -1816,7 +2898,7 @@
rb_pid_t pid;
pid = rb_spawn(argc, argv);
- if (pid == -1) rb_sys_fail(RSTRING_PTR(argv[0]));
+ if (pid == -1) rb_sys_fail(RSTRING_CPTR(argv[0]));
#if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
return PIDT2NUM(pid);
#else
@@ -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
@@ -2992,7 +4102,7 @@
groups = ALLOCA_N(rb_gid_t, ngroups);
for (i = 0; i < ngroups && i < RARRAY_LEN(ary); i++) {
- VALUE g = RARRAY_PTR(ary)[i];
+ VALUE g = RARRAY_AT(ary, i);
if (FIXNUM_P(g)) {
groups[i] = NUM2GIDT(g);
@@ -3004,10 +4114,10 @@
groups[i] = NUM2GIDT(g);
}
else {
- gr = getgrnam(RSTRING_PTR(tmp));
+ gr = getgrnam(RSTRING_CPTR(tmp));
if (gr == NULL)
rb_raise(rb_eArgError,
- "can't find group for %s", RSTRING_PTR(tmp));
+ "can't find group for %s", RSTRING_CPTR(tmp));
groups[i] = gr->gr_gid;
}
}
@@ -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/branches/testing/random.c
===================================================================
--- MacRuby/branches/testing/random.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/random.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/range.c
===================================================================
--- MacRuby/branches/testing/range.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/range.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -748,15 +750,15 @@
return Qfalse;
}
else if (TYPE(beg) == T_STRING && TYPE(end) == T_STRING &&
- RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1) {
+ RSTRING_CLEN(beg) == 1 && RSTRING_CLEN(end) == 1) {
if (NIL_P(val)) return Qfalse;
if (TYPE(val) == T_STRING) {
- if (RSTRING_LEN(val) == 0 || RSTRING_LEN(val) > 1)
+ if (RSTRING_CLEN(val) == 0 || RSTRING_CLEN(val) > 1)
return Qfalse;
else {
- char b = RSTRING_PTR(beg)[0];
- char e = RSTRING_PTR(end)[0];
- char v = RSTRING_PTR(val)[0];
+ char b = RSTRING_CPTR(beg)[0];
+ char e = RSTRING_CPTR(end)[0];
+ char v = RSTRING_CPTR(val)[0];
if (ISASCII(b) && ISASCII(e) && ISASCII(v)) {
if (b <= v && v < e) return Qtrue;
Copied: MacRuby/branches/testing/rational.c (from rev 232, MacRuby/trunk/rational.c)
===================================================================
--- MacRuby/branches/testing/rational.c (rev 0)
+++ MacRuby/branches/testing/rational.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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_AT(a, 0);
+ dat->den = RARRAY_AT(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_AT(a, 0),
+ f_expt(INT2FIX(FLT_RADIX), RARRAY_AT(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_CLEN(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_AT(a, 0);
+ if (RARRAY_LEN(a) != 2)
+ exp = Qnil;
+ else
+ exp = RARRAY_AT(a, 1);
+
+ a = f_split(ifp, a_dot_pat);
+ ip = RARRAY_AT(a, 0);
+ if (RARRAY_LEN(a) != 2)
+ fp = Qnil;
+ else
+ fp = RARRAY_AT(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_AT(a, 0)) || RSTRING_CLEN(RARRAY_AT(a, 1)) > 0) {
+ VALUE s = f_inspect(self);
+ rb_raise(rb_eArgError, "invalid value for Rational: %s",
+ StringValuePtr(s));
+ }
+ return RARRAY_AT(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_AT(a, 0)))
+ return RARRAY_AT(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);
+}
Modified: MacRuby/branches/testing/re.c
===================================================================
--- MacRuby/branches/testing/re.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/re.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -181,9 +288,7 @@
*option = 0;
switch (c) {
- case 'n':
- *kcode = -1;
- return (*option = ARG_ENCODING_NONE);
+#if !WITH_OBJC
case 'e':
*kcode = rb_enc_find_index("EUC-JP");
break;
@@ -193,6 +298,14 @@
case 'u':
*kcode = rb_enc_find_index("UTF-8");
break;
+#else
+ case 'e':
+ case 's':
+ case 'u':
+#endif
+ case 'n':
+ *kcode = -1;
+ return (*option = ARG_ENCODING_NONE);
default:
*kcode = -1;
return (*option = char_to_option(c));
@@ -219,10 +332,16 @@
p = s; pend = p + len;
while (p<pend) {
+#if WITH_OBJC
+ c = *p;
+ clen = 1;
+ if (0) {}
+#else
c = rb_enc_ascget(p, pend, &clen, enc);
if (c == -1) {
p += mbclen(p, pend, enc);
}
+#endif
else if (c != '/' && rb_enc_isprint(c, enc)) {
p += clen;
}
@@ -237,9 +356,18 @@
else {
p = s;
while (p<pend) {
+#if WITH_OBJC
+ c = *p;
+ clen = 1;
+#else
c = rb_enc_ascget(p, pend, &clen, enc);
+#endif
if (c == '\\' && p+clen < pend) {
+#if WITH_OBJC
+ int n = clen + (pend - (p+clen));
+#else
int n = clen + mbclen(p+clen, pend, enc);
+#endif
rb_str_buf_cat(str, p, n);
p += n;
continue;
@@ -249,12 +377,14 @@
rb_str_buf_cat(str, &c, 1);
rb_str_buf_cat(str, p, clen);
}
+#if !WITH_OBJC
else if (c == -1) {
int l = mbclen(p, pend, enc);
rb_str_buf_cat(str, p, l);
p += l;
continue;
}
+#endif
else if (rb_enc_isprint(c, enc)) {
rb_str_buf_cat(str, p, clen);
}
@@ -277,7 +407,9 @@
{
VALUE str = rb_str_buf_new2("/");
+#if !WITH_OBJC
rb_enc_copy(str, re);
+#endif
rb_reg_expr_str(str, s, len);
rb_str_buf_cat2(str, "/");
if (re) {
@@ -309,9 +441,15 @@
rb_reg_source(VALUE re)
{
VALUE str;
+ const char *cstr;
+ long clen;
rb_reg_check(re);
- str = rb_enc_str_new(RREGEXP(re)->str,RREGEXP(re)->len, rb_enc_get(re));
+ cstr = RREGEXP(re)->str;
+ clen = RREGEXP(re)->len;
+ if (clen == 0)
+ cstr = NULL;
+ str = rb_enc_str_new(cstr, clen, rb_enc_get(re));
if (OBJ_TAINTED(re)) OBJ_TAINT(str);
return str;
}
@@ -326,7 +464,7 @@
*
* /ab+c/ix.inspect #=> "/ab+c/ix"
*
-*/
+ */
static VALUE
rb_reg_inspect(VALUE re)
@@ -368,7 +506,9 @@
rb_reg_check(re);
+#if !WITH_OBJC
rb_enc_copy(str, re);
+#endif
options = RREGEXP(re)->ptr->options;
ptr = (UChar*)RREGEXP(re)->str;
len = RREGEXP(re)->len;
@@ -410,9 +550,17 @@
if (*ptr == ':' && ptr[len-1] == ')') {
int r;
Regexp *rp;
+ OnigEncoding oenc;
+
+#if WITH_OBJC
+ oenc = ONIG_ENCODING_ASCII;
+#else
+ oenc = rb_enc_get(re);
+#endif
+
r = onig_alloc_init(&rp, ONIG_OPTION_DEFAULT,
ONIGENC_CASE_FOLD_DEFAULT,
- rb_enc_get(re),
+ oenc,
OnigDefaultSyntax);
if (r == 0) {
++ptr;
@@ -439,7 +587,9 @@
rb_str_buf_cat2(str, ":");
rb_reg_expr_str(str, (char*)ptr, len);
rb_str_buf_cat2(str, ")");
+#if !WITH_OBJC
rb_enc_copy(str, re);
+#endif
OBJ_INFECT(str, re);
return str;
@@ -450,7 +600,7 @@
{
VALUE desc = rb_reg_desc(s, len, re);
- rb_raise(rb_eRegexpError, "%s: %s", err, RSTRING_PTR(desc));
+ rb_raise(rb_eRegexpError, "%s: %s", err, RSTRING_CPTR(desc));
}
static VALUE
@@ -459,7 +609,9 @@
char opts[6];
VALUE desc = rb_str_buf_new2(err);
+#if !WITH_OBJC
rb_enc_associate(desc, enc);
+#endif
rb_str_buf_cat2(desc, ": /");
rb_reg_expr_str(desc, s, len);
opts[0] = '/';
@@ -477,7 +629,7 @@
static VALUE
rb_reg_error_desc(VALUE str, int options, const char *err)
{
- return rb_enc_reg_error_desc(RSTRING_PTR(str), RSTRING_LEN(str),
+ return rb_enc_reg_error_desc(RSTRING_CPTR(str), RSTRING_CLEN(str),
rb_enc_get(str), options, err);
}
@@ -559,7 +711,7 @@
* /(?<foo>.)(?<foo>.)/.names
* #=> ["foo"]
*
- * /(.)(.)/.names'
+ * /(.)(.)/.names
* #=> []
*/
@@ -600,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
* #=> {}
*/
@@ -623,6 +775,7 @@
Regexp *rp;
int r;
OnigErrorInfo einfo;
+ OnigEncoding oenc;
/* Handle escaped characters first. */
@@ -631,8 +784,14 @@
from that.
*/
+#if WITH_OBJC
+ oenc = ONIG_ENCODING_ASCII;
+#else
+ oenc = enc;
+#endif
+
r = onig_alloc_init(&rp, flags, ONIGENC_CASE_FOLD_DEFAULT,
- enc, OnigDefaultSyntax);
+ oenc, OnigDefaultSyntax);
if (r) {
onig_error_code_to_str((UChar*)err, r);
return 0;
@@ -696,7 +855,7 @@
struct re_registers *regs;
int num_regs;
int i, num_pos, c;
- char *s, *p, *q, *e;
+ const char *s, *p, *q, *e;
rb_encoding *enc;
pair_t *pairs;
@@ -731,12 +890,16 @@
}
qsort(pairs, num_pos, sizeof(pair_t), pair_byte_cmp);
- s = p = RSTRING_PTR(RMATCH(match)->str);
- e = s + RSTRING_LEN(RMATCH(match)->str);
+ s = p = RSTRING_CPTR(RMATCH(match)->str);
+ e = s + RSTRING_CLEN(RMATCH(match)->str);
c = 0;
for (i = 0; i < num_pos; i++) {
q = s + pairs[i].byte_pos;
+#if WITH_OBJC
+ c += q-p;
+#else
c += rb_enc_strlen(p, q, enc);
+#endif
pairs[i].char_pos = c;
p = q;
}
@@ -1014,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
*/
@@ -1040,100 +1203,120 @@
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)));
+}
+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",
rb_enc_name(rb_enc_get(str)));
}
+#endif
rb_reg_check(re);
- /* ignorecase status */
- 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_from_index(ENCODING_GET(re))),
- rb_enc_name(rb_enc_get(str)));
- }
+ enc = rb_enc_get(str);
+#if !WITH_OBJC
+ 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);
- r = onig_new(®2, (UChar* )RSTRING_PTR(unescaped),
- (UChar* )(RSTRING_PTR(unescaped) + RSTRING_LEN(unescaped)),
- reg->options, enc,
- OnigDefaultSyntax, &einfo);
- if (r) {
- onig_error_code_to_str((UChar*)err, r, &einfo);
- rb_reg_raise((char* )pattern, RREGEXP(re)->len, err, re);
- }
+ if (unescaped == Qnil) {
+ rb_raise(rb_eArgError, "regexp preprocess failed: %s", err);
+ }
- GC_WB(&RREGEXP(re)->ptr, reg2);
- onig_free(reg);
- RB_GC_GUARD(unescaped);
+#if WITH_OBJC
+ enc = (rb_encoding *)ONIG_ENCODING_ASCII;
+#endif
+
+ r = onig_new(®, (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);
}
+
+ 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;
}
else {
- range = RSTRING_LEN(str) - pos;
+ 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);
- if (pos > 0 && ONIGENC_MBC_MAXLEN(enc) != 1 && pos < RSTRING_LEN(str)) {
- string = (UChar*)RSTRING_PTR(str);
-
if (range > 0) {
p = onigenc_get_right_adjust_char_head(enc, string, string + pos);
}
@@ -1142,6 +1325,7 @@
}
return p - string;
}
+#endif
return pos;
}
@@ -1152,7 +1336,13 @@
int result;
VALUE match;
struct re_registers *pregs;
- char *range = RSTRING_PTR(str);
+ 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);
#if WITH_OBJC
static struct re_registers *regs = NULL;
if (regs == NULL) {
@@ -1165,24 +1355,37 @@
pregs = ®s;
#endif
- if (pos > RSTRING_LEN(str) || pos < 0) {
+ if (pos > clen || pos < 0) {
rb_backref_set(Qnil);
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_LEN(str);
+ range += RSTRING_CLEN(str);
}
+ MEMZERO(®s, struct re_registers, 1);
result = onig_search(RREGEXP(re)->ptr,
- (UChar*)(RSTRING_PTR(str)),
- ((UChar*)(RSTRING_PTR(str)) + RSTRING_LEN(str)),
- ((UChar*)(RSTRING_PTR(str)) + pos),
+ (UChar*)cstr,
+ ((UChar*)cstr + clen),
+ ((UChar*)cstr + pos),
((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;
@@ -1194,6 +1397,9 @@
}
}
+#if WITH_OBJC
+ match = match_alloc(rb_cMatch);
+#else
match = rb_backref_get();
if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
match = match_alloc(rb_cMatch);
@@ -1204,8 +1410,10 @@
else
FL_UNSET(match, FL_TAINT);
}
+#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;
@@ -1315,7 +1523,7 @@
if (BEG(0) == -1) return Qnil;
str = RMATCH(match)->str;
pos = END(0);
- str = rb_str_subseq(str, pos, RSTRING_LEN(str) - pos);
+ str = rb_str_subseq(str, pos, RSTRING_CLEN(str) - pos);
if (OBJ_TAINTED(match)) OBJ_TAINT(str);
return str;
}
@@ -1528,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.
@@ -1800,8 +2007,12 @@
}
chbuf[chlen++] = byte;
- while (chlen < chmaxlen &&
- MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(chbuf, chbuf+chlen, enc))) {
+ while (chlen < chmaxlen
+#if WITH_OBJC
+ && 1) {
+#else
+ && MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(chbuf, chbuf+chlen, enc))) {
+#endif
byte = read_escaped_byte(&p, end, err);
if (byte == -1) {
return -1;
@@ -1809,11 +2020,13 @@
chbuf[chlen++] = byte;
}
+#if !WITH_OBJC
l = rb_enc_precise_mbclen(chbuf, chbuf+chlen, enc);
if (MBCLEN_INVALID_P(l)) {
strcpy(err, "invalid multibyte escape");
return -1;
}
+#endif
if (1 < chlen || (chbuf[0] & 0x80)) {
rb_str_buf_cat(buf, chbuf, chlen);
@@ -1861,12 +2074,14 @@
len = rb_uv_to_utf8(utf8buf, uv);
rb_str_buf_cat(buf, utf8buf, len);
+#if !WITH_OBJC
if (*encp == 0)
*encp = rb_utf8_encoding();
else if (*encp != rb_utf8_encoding()) {
strcpy(err, "UTF-8 character in non UTF-8 regexp");
return -1;
}
+#endif
}
return 0;
}
@@ -1939,12 +2154,16 @@
char smallbuf[2];
while (p < end) {
+#if WITH_OBJC
+ int chlen = 1;
+#else
int chlen = rb_enc_precise_mbclen(p, end, enc);
if (!MBCLEN_CHARFOUND_P(chlen)) {
strcpy(err, "invalid multibyte character");
return -1;
}
chlen = MBCLEN_CHARFOUND_LEN(chlen);
+#endif
if (1 < chlen || (*p & 0x80)) {
rb_str_buf_cat(buf, p, chlen);
p += chlen;
@@ -2037,18 +2256,23 @@
buf = rb_str_buf_new(0);
+ *fixed_enc = 0;
if (rb_enc_asciicompat(enc))
*fixed_enc = 0;
else {
*fixed_enc = enc;
+#if !WITH_OBJC
rb_enc_associate(buf, enc);
+#endif
}
if (unescape_nonascii(p, end, enc, buf, fixed_enc, err) != 0)
return Qnil;
if (*fixed_enc) {
+#if !WITH_OBJC
rb_enc_associate(buf, *fixed_enc);
+#endif
}
return buf;
@@ -2060,12 +2284,12 @@
rb_encoding *fixed_enc = 0;
onig_errmsg_buffer err = "";
VALUE buf;
- char *p, *end;
+ const char *p, *end;
rb_encoding *enc;
StringValue(str);
- p = RSTRING_PTR(str);
- end = p + RSTRING_LEN(str);
+ p = RSTRING_CPTR(str);
+ end = p + RSTRING_CLEN(str);
enc = rb_enc_get(str);
buf = rb_reg_preprocess(p, end, enc, &fixed_enc, err);
@@ -2086,21 +2310,27 @@
int i;
VALUE result = 0;
int argc = RARRAY_LEN(ary);
+#if !WITH_OBJC
VALUE *argv = RARRAY_PTR(ary);
+#endif
if (argc == 0) {
rb_raise(rb_eArgError, "no arguments given");
}
for (i = 0; i < argc; i++) {
+#if WITH_OBJC
+ VALUE str = RARRAY_AT(ary, i);
+#else
VALUE str = argv[i];
+#endif
VALUE buf;
- char *p, *end;
+ const char *p, *end;
rb_encoding *src_enc;
StringValue(str);
- p = RSTRING_PTR(str);
- end = p + RSTRING_LEN(str);
+ p = RSTRING_CPTR(str);
+ end = p + RSTRING_CLEN(str);
src_enc = rb_enc_get(str);
buf = rb_reg_preprocess(p, end, src_enc, &fixed_enc, err);
@@ -2122,7 +2352,9 @@
rb_str_buf_append(result, str);
}
if (regexp_enc) {
+#if !WITH_OBJC
rb_enc_associate(result, regexp_enc);
+#endif
}
return result;
@@ -2135,7 +2367,11 @@
struct RRegexp *re = RREGEXP(obj);
VALUE unescaped;
rb_encoding *fixed_enc = 0;
+#if WITH_OBJC
+ rb_encoding *a_enc = enc;
+#else
rb_encoding *a_enc = rb_ascii8bit_encoding();
+#endif
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify regexp");
@@ -2162,11 +2398,15 @@
enc = fixed_enc;
}
}
+#if !WITH_OBJC
else if (!(options & ARG_ENCODING_FIXED)) {
enc = rb_usascii_encoding();
}
+#endif
+#if !WITH_OBJC
rb_enc_associate((VALUE)re, enc);
+#endif
if ((options & ARG_ENCODING_FIXED) || fixed_enc) {
re->basic.flags |= KCODE_FIXED;
}
@@ -2174,7 +2414,8 @@
re->basic.flags |= REG_ENCODING_NONE;
}
- GC_WB(&re->ptr, make_regexp(RSTRING_PTR(unescaped), RSTRING_LEN(unescaped), enc,
+ GC_WB(&re->ptr, make_regexp(RSTRING_CPTR(unescaped),
+ RSTRING_CLEN(unescaped), enc,
options & ARG_REG_OPTION_MASK, err));
if (!re->ptr) return -1;
GC_WB(&re->str, ALLOC_N(char, len+1));
@@ -2191,6 +2432,8 @@
int ret;
rb_encoding *enc = rb_enc_get(str);
if (options & ARG_ENCODING_NONE) {
+#if !WITH_OBJC
+ /* TODO */
rb_encoding *ascii8bit = rb_ascii8bit_encoding();
if (enc != ascii8bit) {
if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
@@ -2199,8 +2442,9 @@
}
enc = ascii8bit;
}
+#endif
}
- ret = rb_reg_initialize(obj, RSTRING_PTR(str), RSTRING_LEN(str), enc,
+ ret = rb_reg_initialize(obj, RSTRING_CPTR(str), RSTRING_CLEN(str), enc,
options, err);
RB_GC_GUARD(str);
return ret;
@@ -2254,7 +2498,11 @@
VALUE
rb_reg_new(const char *s, long len, int options)
{
+#if WITH_OBJC
+ return rb_enc_reg_new(s, len, NULL, options);
+#else
return rb_enc_reg_new(s, len, rb_ascii8bit_encoding(), options);
+#endif
}
VALUE
@@ -2278,9 +2526,13 @@
rb_reg_regcomp(VALUE str)
{
volatile VALUE save_str = str;
- if (reg_cache && RREGEXP(reg_cache)->len == RSTRING_LEN(str)
+ if (reg_cache && RREGEXP(reg_cache)->len == RSTRING_CLEN(str)
+#if WITH_OBJC
+ && rb_enc_get(reg_cache) == rb_enc_get(str)
+#else
&& ENCODING_GET(reg_cache) == ENCODING_GET(str)
- && memcmp(RREGEXP(reg_cache)->str, RSTRING_PTR(str), RSTRING_LEN(str)) == 0)
+#endif
+ && memcmp(RREGEXP(reg_cache)->str, RSTRING_CPTR(str), RSTRING_CLEN(str)) == 0)
return reg_cache;
return reg_cache = rb_reg_new_str(save_str, 0);
@@ -2336,7 +2588,11 @@
if (FL_TEST(re1, KCODE_FIXED) != FL_TEST(re2, KCODE_FIXED)) return Qfalse;
if (RREGEXP(re1)->ptr->options != RREGEXP(re2)->ptr->options) return Qfalse;
if (RREGEXP(re1)->len != RREGEXP(re2)->len) return Qfalse;
+#if WITH_OBJC
+ if (rb_enc_get(re1) != rb_enc_get(re2)) return Qfalse;
+#else
if (ENCODING_GET(re1) != ENCODING_GET(re2)) return Qfalse;
+#endif
if (memcmp(RREGEXP(re1)->str, RREGEXP(re2)->str, RREGEXP(re1)->len) == 0) {
return Qtrue;
}
@@ -2620,7 +2876,9 @@
if (argc == 3 && !NIL_P(argv[2])) {
char *kcode = StringValuePtr(argv[2]);
if (kcode[0] == 'n' || kcode[1] == 'N') {
+#if !WITH_OBJC
enc = rb_ascii8bit_encoding();
+#endif
flags |= ARG_ENCODING_FIXED;
}
else {
@@ -2630,7 +2888,7 @@
str = argv[0];
ptr = StringValuePtr(str);
if (enc
- ? rb_reg_initialize(self, ptr, RSTRING_LEN(str), enc, flags, err)
+ ? rb_reg_initialize(self, ptr, RSTRING_CLEN(str), enc, flags, err)
: rb_reg_initialize_str(self, str, flags, err)) {
rb_reg_raise_str(str, flags, err);
}
@@ -2642,19 +2900,31 @@
rb_reg_quote(VALUE str)
{
rb_encoding *enc = rb_enc_get(str);
- char *s, *send, *t;
+ const char *s, *send;
+ char *t;
VALUE tmp;
int c, clen;
+#if WITH_OBJC
+ int ascii_only = 0;
+#else
int ascii_only = rb_enc_str_asciionly_p(str);
+#endif
- s = RSTRING_PTR(str);
- send = s + RSTRING_LEN(str);
+ s = RSTRING_CPTR(str);
+ if (s == NULL)
+ return str;
+ send = s + RSTRING_CLEN(str);
while (s < send) {
- c = rb_enc_ascget(s, send, &clen, enc);
+#if WITH_OBJC
+ c = *s;
+ clen = 1;
+#else
+ c = rb_enc_ascget(s, send, &clen, enc);
if (c == -1) {
s += mbclen(s, send, enc);
continue;
}
+#endif
switch (c) {
case '[': case ']': case '{': case '}':
case '(': case ')': case '|': case '-':
@@ -2668,24 +2938,32 @@
}
if (ascii_only) {
str = rb_str_new3(str);
+#if !WITH_OBJC
rb_enc_associate(str, rb_usascii_encoding());
+#endif
}
return str;
meta_found:
- tmp = rb_str_new(0, RSTRING_LEN(str)*2);
+ tmp = rb_str_new(0, RSTRING_CLEN(str)*2);
+#if !WITH_OBJC
if (ascii_only) {
rb_enc_associate(tmp, rb_usascii_encoding());
}
else {
rb_enc_copy(tmp, str);
}
+#endif
t = RSTRING_PTR(tmp);
/* copy upto metacharacter */
- memcpy(t, RSTRING_PTR(str), s - RSTRING_PTR(str));
- t += s - RSTRING_PTR(str);
+ memcpy(t, RSTRING_CPTR(str), s - RSTRING_CPTR(str));
+ t += s - RSTRING_CPTR(str);
while (s < send) {
+#if WITH_OBJC
+ c = *s;
+ clen = 1;
+#else
c = rb_enc_ascget(s, send, &clen, enc);
if (c == -1) {
int n = mbclen(s, send, enc);
@@ -2694,6 +2972,7 @@
*t++ = *s++;
continue;
}
+#endif
s += clen;
switch (c) {
case '[': case ']': case '{': case '}':
@@ -2731,7 +3010,10 @@
*t++ = c;
}
rb_str_resize(tmp, t - RSTRING_PTR(tmp));
+ RSTRING_SYNC(tmp);
+#if !WITH_OBJC
OBJ_INFECT(tmp, str);
+#endif
return tmp;
}
@@ -2867,9 +3149,11 @@
rb_raise(rb_eArgError, "incompatible encodings: %s and %s",
rb_enc_name(has_ascii_incompat), rb_enc_name(enc));
}
+#if !WITH_OBJC
else if (rb_enc_str_asciionly_p(e)) {
has_asciionly = 1;
}
+#endif
else {
if (!has_ascii_compat_fixed)
has_ascii_compat_fixed = enc;
@@ -2890,12 +3174,15 @@
}
}
+#if !WITH_OBJC
if (i == 0) {
rb_enc_copy(source, v);
}
+#endif
rb_str_append(source, v);
}
+#if !WITH_OBJC
if (has_ascii_incompat) {
result_enc = has_ascii_incompat;
}
@@ -2907,6 +3194,7 @@
}
rb_enc_associate(source, result_enc);
+#endif
return rb_class_new_instance(1, &source, rb_cRegexp);
}
}
@@ -2966,23 +3254,29 @@
rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp)
{
VALUE val = 0;
- char *p, *s, *e;
+ const char *p, *s, *e;
int no, clen;
rb_encoding *str_enc = rb_enc_get(str);
rb_encoding *src_enc = rb_enc_get(src);
+#if !WITH_OBJC
rb_enc_check(str, src);
- p = s = RSTRING_PTR(str);
- e = s + RSTRING_LEN(str);
+#endif
+ p = s = RSTRING_CPTR(str);
+ e = s + RSTRING_CLEN(str);
while (s < e) {
+ const char *ss;
+#if WITH_OBJC
+ int c = *s;
+ clen = 1;
+#else
int c = rb_enc_ascget(s, e, &clen, str_enc);
- char *ss;
-
if (c == -1) {
s += mbclen(s, e, str_enc);
continue;
}
+#endif
ss = s;
s += clen;
@@ -2993,6 +3287,10 @@
}
rb_enc_str_buf_cat(val, p, ss-p, str_enc);
+#if WITH_OBJC
+ c = *s;
+ clen = 1;
+#else
c = rb_enc_ascget(s, e, &clen, str_enc);
if (c == -1) {
s += mbclen(s, e, str_enc);
@@ -3000,6 +3298,7 @@
p = s;
continue;
}
+#endif
s += clen;
p = s;
@@ -3015,14 +3314,26 @@
break;
case 'k':
+#if WITH_OBJC
+ clen = 1;
+ if (s < e && *s == '<') {
+#else
if (s < e && rb_enc_ascget(s, e, &clen, str_enc) == '<') {
- char *name, *name_end;
+#endif
+ const char *name, *name_end;
name_end = name = s + clen;
while (name_end < e) {
+#if WITH_OBJC
+ c = *name_end;
+ clen = 1;
+ if (c == '>') break;
+ name_end += clen;
+#else
c = rb_enc_ascget(name_end, e, &clen, str_enc);
if (c == '>') break;
name_end += c == -1 ? mbclen(name_end, e, str_enc) : clen;
+#endif
}
if (name_end < e) {
no = name_to_backref_number(regs, regexp, name, name_end);
@@ -3043,11 +3354,11 @@
break;
case '`':
- rb_enc_str_buf_cat(val, RSTRING_PTR(src), BEG(0), src_enc);
+ rb_enc_str_buf_cat(val, RSTRING_CPTR(src), BEG(0), src_enc);
continue;
case '\'':
- rb_enc_str_buf_cat(val, RSTRING_PTR(src)+END(0), RSTRING_LEN(src)-END(0), src_enc);
+ rb_enc_str_buf_cat(val, RSTRING_CPTR(src)+END(0), RSTRING_CLEN(src)-END(0), src_enc);
continue;
case '+':
@@ -3068,7 +3379,7 @@
if (no >= 0) {
if (no >= regs->num_regs) continue;
if (BEG(no) == -1) continue;
- rb_enc_str_buf_cat(val, RSTRING_PTR(src)+BEG(no), END(no)-BEG(no), src_enc);
+ rb_enc_str_buf_cat(val, RSTRING_CPTR(src)+BEG(no), END(no)-BEG(no), src_enc);
}
}
@@ -3137,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
@@ -3153,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;
@@ -3249,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/branches/testing/regexec.c
===================================================================
--- MacRuby/branches/testing/regexec.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/regexec.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -186,6 +186,7 @@
region->allocated = n;
}
else if (region->allocated < n) {
+ region->allocated = 0;
GC_WB(®ion->beg, (int* )xrealloc(region->beg, n * sizeof(int)));
GC_WB(®ion->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/branches/testing/regint.h
===================================================================
--- MacRuby/branches/testing/regint.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/regint.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/regparse.c
===================================================================
--- MacRuby/branches/testing/regparse.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/regparse.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -825,6 +825,7 @@
switch (e->back_num) {
case 0:
+ *nums = 0;
break;
case 1:
*nums = &(e->back_ref1);
Modified: MacRuby/branches/testing/ruby.1
===================================================================
--- MacRuby/branches/testing/ruby.1 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ruby.1 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/ruby.c
===================================================================
--- MacRuby/branches/testing/ruby.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/ruby.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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,11 +84,16 @@
int verbose;
int yydebug;
char *script;
+ VALUE script_name;
VALUE e_script;
struct {
struct {
VALUE name;
+#if WITH_OBJC
+ rb_encoding *enc;
+#else
int index;
+#endif
} enc;
} src, ext;
};
@@ -130,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",
@@ -142,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
@@ -155,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))
@@ -207,10 +206,11 @@
return rb_str_new(s, l);
}
ret = rb_str_new(0, l + newl - oldl);
- ptr = RSTRING_PTR(ret);
+ ptr = RSTRING_PTR(ret); /* ok */
memcpy(ptr, newp, newl);
memcpy(ptr + newl, s + oldl, l - oldl);
ptr[l + newl - oldl] = 0;
+ RSTRING_SYNC(ret);
return ret;
}
@@ -229,6 +229,7 @@
{
const char sep = PATH_SEP_CHAR;
const char *p, *s;
+ VALUE load_path = GET_VM()->load_path;
p = path;
while (*p) {
@@ -236,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;
}
}
@@ -260,11 +261,12 @@
if (*s) {
if (!buf) {
buf = rb_str_new(p, len);
- p = RSTRING_PTR(buf);
+ p = RSTRING_CPTR(buf);
}
else {
rb_str_resize(buf, len);
- p = strncpy(RSTRING_PTR(buf), p, len);
+ p = strncpy(RSTRING_PTR(buf), p, len); /* ok */
+ RSTRING_SYNC(buf);
}
}
if (cygwin_conv_to_posix_path(p, rubylib) == 0)
@@ -301,7 +303,7 @@
static VALUE
expand_include_path(VALUE path)
{
- char *p = RSTRING_PTR(path);
+ const char *p = RSTRING_CPTR(path);
if (!p)
return path;
if (*p == '.' && p[1] == '/')
@@ -334,6 +336,7 @@
void
ruby_init_loadpath(void)
{
+ VALUE load_path;
#if defined LOAD_RELATIVE
char libpath[MAXPATHLEN + 1];
char *p;
@@ -380,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"));
@@ -463,14 +467,13 @@
process_sflag(struct cmdline_options *opt)
{
if (opt->sflag) {
- long n;
- VALUE *args;
+ long i, n;
VALUE argv = rb_argv;
n = RARRAY_LEN(argv);
- args = RARRAY_PTR(argv);
+ i = 0;
while (n > 0) {
- VALUE v = *args++;
+ VALUE v = RARRAY_AT(argv, i++);
char *s = StringValuePtr(v);
char *p;
int hyphen = Qfalse;
@@ -502,7 +505,7 @@
else {
rb_str_cat(name_error[0], s, p - s);
}
- name_error[1] = args[-1];
+ name_error[1] = RARRAY_AT(argv, -1);
rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError));
}
}
@@ -845,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);
}
@@ -919,16 +922,25 @@
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();
}
+#if WITH_OBJC
+static rb_encoding *
+opt_enc_find(VALUE enc_name)
+{
+ rb_encoding *enc = rb_enc_find2(enc_name);
+ if (enc == NULL)
+ rb_raise(rb_eRuntimeError, "unknown encoding name - %s",
+ RSTRING_CPTR(enc_name));
+ return enc;
+}
+#else
static int
opt_enc_index(VALUE enc_name)
{
- const char *s = RSTRING_PTR(enc_name);
+ const char *s = RSTRING_CPTR(enc_name);
int i = rb_enc_find_index(s);
if (i < 0) {
@@ -939,8 +951,16 @@
}
return i;
}
+#endif
+VALUE rb_progname;
+VALUE rb_argv0;
+
+#if WITH_OBJC
+static rb_encoding *src_encoding;
+#else
static int src_encoding_index = -1; /* TODO: VM private */
+#endif
static VALUE
process_options(VALUE arg)
@@ -951,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;
@@ -1013,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) {
@@ -1032,55 +1054,88 @@
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) {
+#if WITH_OBJC
+ opt->ext.enc.enc = opt_enc_find(opt->ext.enc.name);
+#else
opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
+#endif
}
if (opt->src.enc.name != 0) {
+#if WITH_OBJC
+ opt->src.enc.enc = opt_enc_find(opt->src.enc.name);
+ src_encoding = opt->src.enc.enc;
+#else
opt->src.enc.index = opt_enc_index(opt->src.enc.name);
src_encoding_index = opt->src.enc.index;
+#endif
}
+#if WITH_OBJC
+ if (opt->ext.enc.enc != NULL) {
+ enc = opt->ext.enc.enc;
+ }
+#else
if (opt->ext.enc.index >= 0) {
enc = rb_enc_from_index(opt->ext.enc.index);
}
+#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
+ if (opt->src.enc.enc != NULL) {
+ eenc = opt->src.enc.enc;
+ }
+#else
if (opt->src.enc.index >= 0) {
eenc = rb_enc_from_index(opt->src.enc.index);
}
+#endif
else {
- eenc = rb_locale_encoding();
+ eenc = lenc;
}
+#if !WITH_OBJC
rb_enc_associate(opt->e_script, eenc);
+#endif
require_libraries();
tree = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
}
@@ -1098,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) {
@@ -1106,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 *
@@ -1155,15 +1209,21 @@
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;
while (!NIL_P(line = rb_io_gets(f))) {
line_start++;
- if (RSTRING_LEN(line) > 2
- && RSTRING_PTR(line)[0] == '#'
- && RSTRING_PTR(line)[1] == '!') {
- if ((p = strstr(RSTRING_PTR(line), "ruby")) != 0) {
+ const char *lineptr = RSTRING_CPTR(line);
+ if (RSTRING_CLEN(line) > 2
+ && lineptr[0] == '#'
+ && lineptr[1] == '!') {
+ if ((p = strstr(lineptr, "ruby")) != 0) {
goto start_read;
}
}
@@ -1179,7 +1239,7 @@
if (NIL_P(line))
return 0;
- if ((p = strstr(RSTRING_PTR(line), "ruby")) == 0) {
+ if ((p = strstr(RSTRING_CPTR(line), "ruby")) == 0) {
/* not ruby script, kick the program */
char **argv;
char *path;
@@ -1231,11 +1291,20 @@
}
rb_io_ungetc(f, INT2FIX('#'));
if (no_src_enc && opt->src.enc.name) {
+#if WITH_OBJC
+ opt->src.enc.enc = opt_enc_find(opt->src.enc.name);
+ src_encoding = opt->src.enc.enc;
+#else
opt->src.enc.index = opt_enc_index(opt->src.enc.name);
src_encoding_index = opt->src.enc.index;
+#endif
}
if (no_ext_enc && opt->ext.enc.name) {
+#if WITH_OBJC
+ opt->ext.enc.enc = opt_enc_find(opt->ext.enc.name);
+#else
opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
+#endif
}
}
else if (!NIL_P(c)) {
@@ -1243,6 +1312,14 @@
}
require_libraries(); /* Why here? unnatural */
}
+#if WITH_OBJC
+ if (opt->src.enc.enc != NULL) {
+ enc = opt->src.enc.enc;
+ }
+ else {
+ enc = rb_locale_encoding();
+ }
+#else
if (opt->src.enc.index >= 0) {
enc = rb_enc_from_index(opt->src.enc.index);
}
@@ -1252,6 +1329,7 @@
else {
enc = rb_usascii_encoding();
}
+#endif
rb_funcall(f, rb_intern("set_encoding"), 1, rb_enc_from_encoding(enc));
tree = (NODE *)rb_parser_compile_file(parser, fname, f, line_start);
rb_funcall(f, rb_intern("set_encoding"), 1, rb_parser_encoding(parser));
@@ -1270,13 +1348,14 @@
struct cmdline_options opt;
MEMZERO(&opt, opt, 1);
+#if WITH_OBJC
+ opt.src.enc.enc = src_encoding;
+#else
opt.src.enc.index = src_encoding_index;
+#endif
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
@@ -1292,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++) {
@@ -1322,14 +1402,15 @@
static void
set_arg0(VALUE val, ID id)
{
- char *s, *t;
+ const char *s;
+ char *t;
long i;
if (origarg.argv == 0)
rb_raise(rb_eRuntimeError, "$0 not initialized");
StringValue(val);
- s = RSTRING_PTR(val);
- i = RSTRING_LEN(val);
+ s = RSTRING_CPTR(val);
+ i = RSTRING_CLEN(val);
#if defined(PSTAT_SETCMD)
if (i > PST_CLEN) {
union pstun un;
@@ -1501,8 +1582,13 @@
args.argc = argc;
args.argv = argv;
args.opt = &opt;
+#if WITH_OBJC
+ opt.src.enc.enc = src_encoding;
+ opt.ext.enc.enc = NULL;
+#else
opt.src.enc.index = src_encoding_index;
opt.ext.enc.index = -1;
+#endif
tree = (NODE *)rb_vm_call_cfunc(rb_vm_top_self(),
process_options, (VALUE)&args,
0, rb_progname);
Modified: MacRuby/branches/testing/sample/test.rb
===================================================================
--- MacRuby/branches/testing/sample/test.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/sample/test.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1668,7 +1668,7 @@
$proc2.call
test_ok($x == 5)
-if defined? Process.kill
+if false#defined? Process.kill
test_check "signal"
$x = 0
@@ -2182,6 +2182,7 @@
test_ok(File.expand_path(".", "//") == "//")
test_ok(File.expand_path("sub", "//") == "//sub")
+=begin # crashes in 1.9+macruby
# test_check "Proc#binding"
ObjectSpace.each_object(Proc){|o|
begin
@@ -2190,6 +2191,7 @@
rescue ArgumentError
end
}
+=end
test_check "gc"
begin
Modified: MacRuby/branches/testing/sample-macruby/Scripts/hello_world.rb
===================================================================
--- MacRuby/branches/testing/sample-macruby/Scripts/hello_world.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/sample-macruby/Scripts/hello_world.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -13,15 +13,14 @@
app = NSApplication.sharedApplication
app.delegate = AppDelegate.alloc.init
-frame = NSRect.new(NSPoint.new(200, 300), NSSize.new(250, 100))
-win = NSWindow.alloc.initWithContentRect(frame,
+win = NSWindow.alloc.initWithContentRect([200, 300, 250, 100],
styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask,
backing:NSBackingStoreBuffered,
defer:false)
win.title = 'Hello World'
win.level = 3
-hel = NSButton.alloc.initWithFrame(NSRect.new(NSPoint.new(10, 10), NSSize.new(80, 80)))
+hel = NSButton.alloc.initWithFrame([10, 10, 80, 80])
win.contentView.addSubview(hel)
hel.bezelStyle = 4
hel.title = 'Hello!'
@@ -31,8 +30,7 @@
beep = NSSound.alloc.initWithContentsOfFile('/System/Library/Sounds/Tink.Aiff', byReference:true)
hel.sound = beep
-bye = NSButton.alloc.initWithFrame(
- NSRect.new(NSPoint.new(100, 10), NSSize.new(80, 80)))
+bye = NSButton.alloc.initWithFrame([100, 10, 80, 80])
win.contentView.addSubview(bye)
bye.bezelStyle = 4
bye.target = app
Modified: MacRuby/branches/testing/sample-macruby/Scripts/transparent_hello.rb
===================================================================
--- MacRuby/branches/testing/sample-macruby/Scripts/transparent_hello.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/sample-macruby/Scripts/transparent_hello.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -30,8 +30,8 @@
application = NSApplication.sharedApplication
# Create the window
-frame = NSRect.new(NSPoint.new(0, 0), NSSize.new(450, 200))
-window = NSWindow.alloc.initWithContentRect(frame,
+frame = [0, 0, 450, 200]
+window = NSWindow.alloc.initWithContentRect(frame,
styleMask:NSBorderlessWindowMask,
backing:NSBackingStoreBuffered,
defer:false)
@@ -56,13 +56,6 @@
window.makeKeyAndOrderFront(nil)
window.orderFrontRegardless
-# Prepare a timer that will auto-terminate our application
-$stderr.puts "Starting. Application will automatically quit in 5 seconds."
-NSTimer.scheduledTimerWithTimeInterval(5.0,
- target:application,
- selector:'terminate:',
- userInfo:nil,
- repeats:false)
-
# And start the application event loop
+$stderr.puts "Starting. Press ^C to quit."
application.run
Modified: MacRuby/branches/testing/signal.c
===================================================================
--- MacRuby/branches/testing/signal.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/signal.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
@@ -330,7 +330,7 @@
goto str_signal;
case T_STRING:
- s = RSTRING_PTR(argv[0]);
+ s = RSTRING_CPTR(argv[0]);
if (s[0] == '-') {
negative++;
s++;
@@ -351,7 +351,7 @@
str = rb_check_string_type(argv[0]);
if (!NIL_P(str)) {
- s = RSTRING_PTR(str);
+ s = RSTRING_CPTR(str);
goto str_signal;
}
rb_raise(rb_eArgError, "bad signal type %s",
@@ -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
@@ -714,45 +719,45 @@
command = rb_check_string_type(*cmd);
if (!NIL_P(command)) {
SafeStringValue(command); /* taint check */
- switch (RSTRING_LEN(command)) {
+ switch (RSTRING_CLEN(command)) {
case 0:
goto sig_ign;
break;
case 14:
- if (strncmp(RSTRING_PTR(command), "SYSTEM_DEFAULT", 14) == 0) {
+ if (strncmp(RSTRING_CPTR(command), "SYSTEM_DEFAULT", 14) == 0) {
func = SIG_DFL;
*cmd = 0;
}
break;
case 7:
- if (strncmp(RSTRING_PTR(command), "SIG_IGN", 7) == 0) {
+ if (strncmp(RSTRING_CPTR(command), "SIG_IGN", 7) == 0) {
sig_ign:
func = SIG_IGN;
*cmd = 0;
}
- else if (strncmp(RSTRING_PTR(command), "SIG_DFL", 7) == 0) {
+ else if (strncmp(RSTRING_CPTR(command), "SIG_DFL", 7) == 0) {
sig_dfl:
func = default_handler(sig);
*cmd = 0;
}
- else if (strncmp(RSTRING_PTR(command), "DEFAULT", 7) == 0) {
+ else if (strncmp(RSTRING_CPTR(command), "DEFAULT", 7) == 0) {
goto sig_dfl;
}
break;
case 6:
- if (strncmp(RSTRING_PTR(command), "IGNORE", 6) == 0) {
+ if (strncmp(RSTRING_CPTR(command), "IGNORE", 6) == 0) {
goto sig_ign;
}
break;
case 4:
- if (strncmp(RSTRING_PTR(command), "EXIT", 4) == 0) {
+ if (strncmp(RSTRING_CPTR(command), "EXIT", 4) == 0) {
func = sighandler;
*cmd = Qundef;
}
break;
}
if (func == wrong_trap) {
- rb_raise(rb_eArgError, "wrong trap - %s", RSTRING_PTR(command));
+ rb_raise(rb_eArgError, "wrong trap - %s", RSTRING_CPTR(command));
}
}
else {
@@ -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/branches/testing/sprintf.c
===================================================================
--- MacRuby/branches/testing/sprintf.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/sprintf.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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"
@@ -243,6 +391,7 @@
return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
}
+#if !WITH_OBJC
VALUE
rb_str_format(int argc, const VALUE *argv, VALUE fmt)
{
@@ -281,7 +430,7 @@
StringValue(fmt);
enc = rb_enc_get(fmt);
fmt = rb_str_new4(fmt);
- p = RSTRING_PTR(fmt);
+ p = RSTRING_PTR(fmt); /* ok */
end = p + RSTRING_LEN(fmt);
blen = 0;
bsiz = 120;
@@ -766,7 +915,7 @@
if (isnan(fval) || isinf(fval)) {
const char *expr;
- if (isnan(fval)) {
+ if (isnan(fval)) {
expr = "NaN";
}
else {
@@ -789,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));
}
@@ -854,6 +987,7 @@
if (tainted) OBJ_TAINT(result);
return result;
}
+#endif
static void
fmt_setup(char *buf, int c, int flags, int width, int prec)
@@ -928,6 +1062,12 @@
VALUE
rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
{
+#if WITH_OBJC
+ char buffer[512];
+ int n;
+ n = vsnprintf(buffer, sizeof buffer, fmt, ap);
+ return rb_enc_str_new(buffer, n, enc);
+#else
rb_printf_buffer f;
VALUE result;
@@ -945,6 +1085,7 @@
rb_str_resize(result, (char *)f._p - RSTRING_PTR(result));
return result;
+#endif
}
VALUE
Modified: MacRuby/branches/testing/st.c
===================================================================
--- MacRuby/branches/testing/st.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/st.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/string.c
===================================================================
--- MacRuby/branches/testing/string.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/string.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -26,8 +26,13 @@
#endif
VALUE rb_cString;
+#if WITH_OBJC
+VALUE rb_cCFString;
+VALUE rb_cStringRuby;
+#endif
VALUE rb_cSymbol;
+#if !WITH_OBJC
#define STR_TMPLOCK FL_USER7
#define STR_NOEMBED FL_USER1
#define STR_SHARED FL_USER2 /* = ELTS_SHARED */
@@ -91,11 +96,138 @@
}\
} while (0)
-#define is_ascii_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT)
-#define is_broken_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN)
+#else
-#define STR_ENC_GET(str) rb_enc_from_index(ENCODING_GET(str))
+static void *rb_str_cfdata_key;
+static inline void
+rb_str_cfdata_set(VALUE str, void *cfdata)
+{
+ rb_objc_set_associative_ref((void *)str, &rb_str_cfdata_key,
+ cfdata);
+}
+
+static inline void *
+rb_str_cfdata2(VALUE str)
+{
+ return rb_objc_get_associative_ref((void *)str, &rb_str_cfdata_key);
+}
+
+static inline bool
+rb_objc_str_is_bytestring(VALUE str)
+{
+ return rb_str_cfdata2(str) != NULL;
+}
+
+static void *
+rb_str_cfdata(VALUE str)
+{
+ void *cfdata;
+
+ assert(str != 0);
+
+ cfdata = rb_str_cfdata2(str);
+ if (cfdata == NULL) {
+ CFMutableDataRef mdata;
+ long len;
+
+ if (CFStringGetLength((CFStringRef)str) == 0) {
+ mdata = CFDataCreateMutable(NULL, 0);
+ }
+ else {
+ CFDataRef data;
+ data = CFStringCreateExternalRepresentation(NULL,
+ (CFStringRef)str, kCFStringEncodingUTF8, 0);
+ if (data == NULL)
+ return NULL;
+ mdata = CFDataCreateMutableCopy(NULL, 0, data);
+ len = CFDataGetLength(data);
+ rb_gc_malloc_increase(len);
+ /* This is a hack to make sure a sentinel byte is created at the
+ * end of the buffer.
+ */
+ CFDataSetLength(mdata, len + 1);
+ CFDataSetLength(mdata, len);
+ CFRelease((CFTypeRef)data);
+ }
+ cfdata = (void *)mdata;
+ rb_str_cfdata_set(str, cfdata);
+ CFMakeCollectable(mdata);
+ }
+ return cfdata;
+}
+
+char *
+rb_str_byteptr(VALUE str)
+{
+ return (char *)CFDataGetMutableBytePtr(
+ (CFMutableDataRef)rb_str_cfdata(str));
+}
+
+long
+rb_str_bytelen(VALUE str)
+{
+ return CFDataGetLength((CFDataRef)rb_str_cfdata(str));
+}
+
+void
+rb_str_bytesync(VALUE str)
+{
+ void *cfdata;
+
+ cfdata = rb_str_cfdata2(str);
+ if (cfdata != NULL) {
+ CFDataRef data;
+ CFIndex datalen;
+ const UInt8 *dataptr;
+ CFStringRef bytestr;
+ const char *strptr;
+
+ data = (CFDataRef)cfdata;
+ datalen = CFDataGetLength(data);
+ dataptr = CFDataGetBytePtr(data);
+ bytestr = CFStringCreateWithBytesNoCopy(
+ NULL,
+ dataptr,
+ datalen,
+ kCFStringEncodingUTF8,
+ false,
+ kCFAllocatorNull);
+ rb_gc_malloc_increase(datalen);
+ if (bytestr != NULL) {
+ CFStringReplaceAll((CFMutableStringRef)str, (CFStringRef)bytestr);
+ CFRelease(bytestr);
+ rb_str_cfdata_set(str, NULL);
+ }
+ }
+}
+
+VALUE
+rb_str_freeze(VALUE str)
+{
+ rb_obj_freeze(str);
+ return str;
+}
+
+static VALUE
+rb_str_bytestring_m(VALUE str)
+{
+ return rb_objc_str_is_bytestring(str) ? Qtrue : Qfalse;
+}
+#endif
+
+#if WITH_OBJC
+/* TODO */
+# define is_ascii_string(str) (1)
+# define is_broken_string(str) (0)
+# define STR_ENC_GET(str) (NULL)
+#else
+# define is_ascii_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT)
+# define is_broken_string(str) (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN)
+# define STR_ENC_GET(str) rb_enc_from_index(ENCODING_GET(str))
+#endif
+
+#if !WITH_OBJC
static int
single_byte_optimizable(VALUE str)
{
@@ -112,15 +244,17 @@
* "\xa1" in Shift_JIS for example. */
return 0;
}
+#endif
VALUE rb_fs;
+#if !WITH_OBJC
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
@@ -313,13 +447,17 @@
return Qtrue;
return Qfalse;
}
+#endif
static inline void
str_mod_check(VALUE s, const char *p, long len)
{
+#if !WITH_OBJC
+ /* TODO */
if (RSTRING_PTR(s) != p || RSTRING_LEN(s) != len){
rb_raise(rb_eRuntimeError, "string modified");
}
+#endif
}
static inline void
@@ -333,6 +471,17 @@
static VALUE
str_alloc(VALUE klass)
{
+#if WITH_OBJC
+ VALUE str;
+
+ str = (VALUE)CFStringCreateMutable(NULL, 0);
+ if (klass != 0
+ && klass != rb_cString
+ && klass != rb_cStringRuby
+ && klass != rb_cSymbol)
+ *(Class *)str = RCLASS_OCID(klass);
+ CFMakeCollectable((CFTypeRef)str);
+#else
NEWOBJ(str, struct RString);
OBJSETUP(str, klass, T_STRING);
@@ -343,10 +492,28 @@
str->as.heap.ptr = 0;
str->as.heap.len = 0;
str->as.heap.aux.capa = 0;
+#endif
return (VALUE)str;
}
+#if WITH_OBJC
+static void
+rb_objc_str_set_bytestring(VALUE str, const char *dataptr, long datalen)
+{
+ CFMutableDataRef data;
+
+ assert(dataptr != NULL);
+ assert(datalen > 0);
+
+ data = CFDataCreateMutable(NULL, 0);
+ CFDataAppendBytes(data, (const UInt8 *)dataptr, datalen);
+ rb_gc_malloc_increase(datalen);
+ rb_str_cfdata_set(str, data);
+ CFMakeCollectable(data);
+}
+#endif
+
static VALUE
str_new(VALUE klass, const char *ptr, long len)
{
@@ -357,9 +524,54 @@
}
str = str_alloc(klass);
+#if WITH_OBJC
+ bool need_padding = len > 0;
+ if (ptr != NULL) {
+ if (len == 0) {
+ char c = 0;
+ rb_objc_str_set_bytestring(str, &c, 1);
+ }
+ else {
+ long slen;
+ slen = strlen(ptr);
+
+ if (slen == len) {
+ CFStringAppendCString((CFMutableStringRef)str, ptr,
+ kCFStringEncodingUTF8);
+ need_padding = false;
+ if (CFStringGetLength((CFStringRef)str) != len)
+ rb_objc_str_set_bytestring(str, ptr, len);
+ }
+ else {
+ if (slen == 0 || len < slen) {
+ CFStringRef substr;
+
+ substr = CFStringCreateWithBytes(NULL, (const UInt8 *)ptr,
+ len, kCFStringEncodingUTF8, false);
+
+ rb_gc_malloc_increase(32 + (sizeof(UniChar) * len));
+
+ if (substr != NULL) {
+ CFStringAppend((CFMutableStringRef)str, substr);
+ CFRelease(substr);
+ }
+ else {
+ rb_objc_str_set_bytestring(str, ptr, len);
+ }
+ }
+ else {
+ rb_objc_str_set_bytestring(str, ptr, len);
+ }
+ }
+ }
+ }
+ rb_gc_malloc_increase(32 + (sizeof(UniChar) * len));
+ if (need_padding)
+ CFStringPad((CFMutableStringRef)str, CFSTR(" "), len, 0);
+#else
if (len > RSTRING_EMBED_LEN_MAX) {
RSTRING(str)->as.heap.aux.capa = len;
- RSTRING(str)->as.heap.ptr = ALLOC_N(char,len+1);
+ GC_WB(&RSTRING(str)->as.heap.ptr, ALLOC_N(char,len+1));
STR_SET_NOEMBED(str);
}
if (ptr) {
@@ -367,6 +579,7 @@
}
STR_SET_LEN(str, len);
RSTRING_PTR(str)[len] = '\0';
+#endif
return str;
}
@@ -381,7 +594,7 @@
{
VALUE str = str_new(rb_cString, ptr, len);
- ENCODING_CODERANGE_SET(str, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
+ //ENCODING_CODERANGE_SET(str, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
return str;
}
@@ -390,17 +603,20 @@
{
VALUE str = str_new(rb_cString, ptr, len);
- rb_enc_associate(str, enc);
+ // TODO we should pass the real encoding
+ //rb_enc_associate(str, enc);
return str;
}
VALUE
rb_str_new2(const char *ptr)
{
+ long len;
if (!ptr) {
rb_raise(rb_eArgError, "NULL pointer given");
}
- return rb_str_new(ptr, strlen(ptr));
+ len = strlen(ptr);
+ return rb_str_new(len == 0 ? NULL : ptr, len);
}
VALUE
@@ -416,7 +632,6 @@
rb_tainted_str_new(const char *ptr, long len)
{
VALUE str = rb_str_new(ptr, len);
-
OBJ_TAINT(str);
return str;
}
@@ -425,11 +640,11 @@
rb_tainted_str_new2(const char *ptr)
{
VALUE str = rb_str_new2(ptr);
-
OBJ_TAINT(str);
return str;
}
+#if !WITH_OBJC
static VALUE
str_replace_shared(VALUE str2, VALUE str)
{
@@ -530,8 +745,31 @@
OBJ_FREEZE(str);
return str;
}
+#else
+static VALUE
+str_new3(VALUE klass, VALUE str)
+{
+ return rb_str_dup(str);
+}
+
VALUE
+rb_str_new3(VALUE str)
+{
+ VALUE str2 = str_new3(rb_obj_class(str), str);
+
+ // TODO OBJ_INFECT(str2, str);
+ return str2;
+}
+
+VALUE
+rb_str_new4(VALUE orig)
+{
+ return rb_str_new3(orig);
+}
+#endif
+
+VALUE
rb_str_new5(VALUE obj, const char *ptr, long len)
{
return str_new(rb_obj_class(obj), ptr, len);
@@ -544,13 +782,15 @@
{
VALUE str = str_alloc(rb_cString);
+#if !WITH_OBJC
if (capa < STR_BUF_MIN_SIZE) {
capa = STR_BUF_MIN_SIZE;
}
FL_SET(str, STR_NOEMBED);
RSTRING(str)->as.heap.aux.capa = capa;
- RSTRING(str)->as.heap.ptr = ALLOC_N(char, capa+1);
+ GC_WB(&RSTRING(str)->as.heap.ptr, ALLOC_N(char, capa+1));
RSTRING(str)->as.heap.ptr[0] = '\0';
+#endif
return str;
}
@@ -576,9 +816,11 @@
void
rb_str_free(VALUE str)
{
+#if !WITH_OBJC
if (!STR_EMBED_P(str) && !STR_SHARED_P(str)) {
xfree(RSTRING(str)->as.heap.ptr);
}
+#endif
}
VALUE
@@ -590,6 +832,10 @@
void
rb_str_shared_replace(VALUE str, VALUE str2)
{
+#if WITH_OBJC
+ rb_str_modify(str);
+ CFStringReplaceAll((CFMutableStringRef)str, (CFStringRef)str2);
+#else
rb_encoding *enc;
int cr;
if (str == str2) return;
@@ -625,6 +871,7 @@
STR_UNSET_NOCAPA(str2);
rb_enc_associate(str, enc);
ENC_CODERANGE_SET(str, cr);
+#endif
}
static ID id_to_s;
@@ -651,6 +898,13 @@
{
VALUE dup = str_alloc(rb_obj_class(str));
rb_str_replace(dup, str);
+#if WITH_OBJC
+ {
+ void *data = rb_str_cfdata2(str);
+ if (data != NULL)
+ rb_str_cfdata_set(dup, data);
+ }
+#endif
return dup;
}
@@ -672,6 +926,7 @@
return str;
}
+#if !WITH_OBJC
long
rb_enc_strlen(const char *p, const char *e, rb_encoding *enc)
{
@@ -754,10 +1009,15 @@
if (!*cr) *cr = ENC_CODERANGE_7BIT;
return c;
}
+#endif
static long
str_strlen(VALUE str, rb_encoding *enc)
{
+#if WITH_OBJC
+ /* TODO should use CFStringGetMaximumSizeForEncoding too */
+ return RSTRING_CLEN(str);
+#else
const char *p, *e;
int n, cr;
@@ -803,6 +1063,7 @@
ENC_CODERANGE_SET(str, cr);
}
return n;
+#endif
}
/*
@@ -832,7 +1093,7 @@
static VALUE
rb_str_bytesize(VALUE str)
{
- return INT2NUM(RSTRING_LEN(str));
+ return INT2NUM(rb_str_bytelen(str));
}
/*
@@ -848,7 +1109,7 @@
static VALUE
rb_str_empty(VALUE str)
{
- if (RSTRING_LEN(str) == 0)
+ if (CFStringGetLength((CFStringRef)str) == 0)
return Qtrue;
return Qfalse;
}
@@ -866,6 +1127,13 @@
VALUE
rb_str_plus(VALUE str1, VALUE str2)
{
+#if WITH_OBJC
+ VALUE str3 = rb_str_new(0, 0);
+ rb_str_buf_append(str3, str1);
+ rb_str_buf_append(str3, str2);
+ if (OBJ_TAINTED(str1) || OBJ_TAINTED(str2))
+ OBJ_TAINT(str3);
+#else
VALUE str3;
rb_encoding *enc;
@@ -881,6 +1149,7 @@
OBJ_TAINT(str3);
ENCODING_CODERANGE_SET(str3, rb_enc_to_index(enc),
ENC_CODERANGE_AND(ENC_CODERANGE(str1), ENC_CODERANGE(str2)));
+#endif
return str3;
}
@@ -900,17 +1169,22 @@
VALUE str2;
long n, len;
+ n = RSTRING_CLEN(str);
len = NUM2LONG(times);
if (len < 0) {
rb_raise(rb_eArgError, "negative argument");
}
- if (len && LONG_MAX/len < RSTRING_LEN(str)) {
+ if (len && LONG_MAX/len < n) {
rb_raise(rb_eArgError, "argument too big");
}
- str2 = rb_str_new5(str, 0, len *= RSTRING_LEN(str));
+#if WITH_OBJC
+ str2 = rb_str_new(NULL, 0);
+ CFStringPad((CFMutableStringRef)str2, (CFStringRef)str,
+ len * n, 0);
+#else
+ str2 = rb_str_new5(str, 0, len *= n);
if (len) {
- n = RSTRING_LEN(str);
memcpy(RSTRING_PTR(str2), RSTRING_PTR(str), n);
while (n <= len/2) {
memcpy(RSTRING_PTR(str2) + n, RSTRING_PTR(str2), n);
@@ -921,6 +1195,7 @@
RSTRING_PTR(str2)[RSTRING_LEN(str2)] = '\0';
OBJ_INFECT(str2, str);
rb_enc_cr_str_copy_for_substr(str2, str);
+#endif
return str2;
}
@@ -935,8 +1210,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
@@ -950,17 +1225,24 @@
return rb_str_format(1, &arg, str);
}
-static void
+static inline void
str_modifiable(VALUE str)
{
+#if WITH_OBJC
+ bool __CFStringIsMutable(void *);
+ if (!__CFStringIsMutable((void *)str))
+ rb_raise(rb_eRuntimeError, "can't modify immutable string");
+#else
if (FL_TEST(str, STR_TMPLOCK)) {
rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked");
}
+#endif
if (OBJ_FROZEN(str)) rb_error_frozen("string");
if (!OBJ_TAINTED(str) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify string");
}
+#if !WITH_OBJC
static int
str_independent(VALUE str)
{
@@ -982,18 +1264,23 @@
}
STR_SET_NOEMBED(str);
ptr[len] = 0;
- RSTRING(str)->as.heap.ptr = ptr;
+ GC_WB(&RSTRING(str)->as.heap.ptr, ptr);
RSTRING(str)->as.heap.len = len;
RSTRING(str)->as.heap.aux.capa = len;
STR_UNSET_NOCAPA(str);
}
+#endif
void
rb_str_modify(VALUE str)
{
+#if WITH_OBJC
+ str_modifiable(str);
+#else
if (!str_independent(str))
str_make_independent(str);
ENC_CODERANGE_CLEAR(str);
+#endif
}
void
@@ -1001,6 +1288,7 @@
{
/* sanity check */
if (OBJ_FROZEN(str)) rb_error_frozen("string");
+#if !WITH_OBJC
if (STR_ASSOC_P(str)) {
/* already associated */
rb_ary_concat(RSTRING(str)->as.heap.aux.shared, add);
@@ -1025,15 +1313,18 @@
RBASIC(add)->klass = 0;
RSTRING(str)->as.heap.aux.shared = add;
}
+#endif
}
VALUE
rb_str_associated(VALUE str)
{
+#if !WITH_OBJC
if (STR_SHARED_P(str)) str = RSTRING(str)->as.heap.aux.shared;
if (STR_ASSOC_P(str)) {
return RSTRING(str)->as.heap.aux.shared;
}
+#endif
return Qfalse;
}
@@ -1051,19 +1342,55 @@
char *
rb_string_value_ptr(volatile VALUE *ptr)
{
- return RSTRING_PTR(rb_string_value(ptr));
+ return (char *)RSTRING_CPTR(rb_string_value(ptr));
}
+#if WITH_OBJC
+const char *
+rb_str_cstr(VALUE ptr)
+{
+ CFDataRef data;
+ const char *cptr;
+
+ data = (CFDataRef)rb_str_cfdata2(ptr);
+ if (data == NULL) {
+ cptr = CFStringGetCStringPtr((CFStringRef)ptr, 0);
+ if (cptr == NULL) {
+ long len;
+ len = CFStringGetLength((CFStringRef)ptr);
+ if (len == 0)
+ return "";
+ else
+ data = (CFDataRef)rb_str_cfdata(ptr);
+ }
+ }
+ return data == NULL ? cptr : (const char *)CFDataGetBytePtr(data);
+}
+
+long
+rb_str_clen(VALUE ptr)
+{
+ CFDataRef data = (CFDataRef)rb_str_cfdata2(ptr);
+ return data == NULL
+ ? CFStringGetLength((CFStringRef)ptr)
+ : CFDataGetLength(data);
+}
+#endif
+
char *
rb_string_value_cstr(volatile VALUE *ptr)
{
+#if WITH_OBJC
VALUE str = rb_string_value(ptr);
+ return (char *)rb_str_cstr(str);
+#else
char *s = RSTRING_PTR(str);
if (!s || RSTRING_LEN(str) != strlen(s)) {
rb_raise(rb_eArgError, "string contains null byte");
}
return s;
+#endif
}
VALUE
@@ -1090,6 +1417,7 @@
return rb_check_string_type(str);
}
+#if !WITH_OBJC
char*
rb_enc_nth(const char *p, const char *e, int nth, rb_encoding *enc)
{
@@ -1203,34 +1531,100 @@
if (!pp) return e - p;
return pp - p;
}
-#endif
+#endif /* NONASCII_MASK */
+#endif /* WITH_OBJC */
/* byte offset to char offset */
long
rb_str_sublen(VALUE str, long pos)
{
+#if WITH_OBJC
+ return pos;
+#else
if (single_byte_optimizable(str) || pos < 0)
return pos;
else {
char *p = RSTRING_PTR(str);
return rb_enc_strlen(p, p + pos, STR_ENC_GET(str));
}
+#endif
}
VALUE
rb_str_subseq(VALUE str, long beg, long len)
{
+#if WITH_OBJC
+ CFDataRef data;
+ CFMutableStringRef substr;
+ long n;
+
+#if 1
+ data = NULL;
+ n = CFStringGetLength((CFStringRef)str);
+#else
+ /* the world is not prepared for this yet */
+ data = (CFDataRef)rb_str_cfdata2(str);
+ if (data != NULL) {
+ n = CFDataGetLength(data);
+ }
+ else {
+ n = CFStringGetLength((CFStringRef)str);
+ }
+#endif
+
+ if (beg < 0)
+ beg += n;
+ if (beg > n || beg < 0)
+ return Qnil;
+ if (beg + len > n)
+ return (VALUE)CFSTR("");
+
+ substr = CFStringCreateMutable(NULL, 0);
+
+ if (data != NULL) {
+ const UInt8 *bytes;
+ CFMutableDataRef subdata;
+
+ bytes = CFDataGetBytePtr(data);
+ subdata = CFDataCreateMutable(NULL, 0);
+ CFDataAppendBytes(subdata, bytes + beg, len);
+ rb_str_cfdata_set((VALUE)substr, subdata);
+ CFMakeCollectable(subdata);
+ rb_gc_malloc_increase(sizeof(UInt8) * len);
+
+ RSTRING_SYNC(substr);
+ }
+ else {
+ if (len == 1) {
+ UniChar c = CFStringGetCharacterAtIndex((CFStringRef)str, beg);
+ CFStringAppendCharacters(substr, &c, 1);
+ }
+ else {
+ UniChar *buffer = alloca(sizeof(UniChar) * len);
+ CFStringGetCharacters((CFStringRef)str, CFRangeMake(beg, len),
+ buffer);
+ CFStringAppendCharacters(substr, buffer, len);
+ }
+ rb_gc_malloc_increase(sizeof(UniChar) * len);
+ }
+ CFMakeCollectable(substr);
+ return (VALUE)substr;
+#else
VALUE str2 = rb_str_new5(str, RSTRING_PTR(str)+beg, len);
rb_enc_cr_str_copy_for_substr(str2, str);
OBJ_INFECT(str2, str);
return str2;
+#endif
}
VALUE
rb_str_substr(VALUE str, long beg, long len)
{
+#if WITH_OBJC
+ return rb_str_subseq(str, beg, len);
+#else
rb_encoding *enc = STR_ENC_GET(str);
VALUE str2;
char *p, *s = RSTRING_PTR(str), *e = s + RSTRING_LEN(str);
@@ -1296,8 +1690,10 @@
}
return str2;
+#endif
}
+#if !WITH_OBJC
VALUE
rb_str_freeze(VALUE str)
{
@@ -1307,10 +1703,16 @@
}
return rb_obj_freeze(str);
}
+#endif
VALUE
rb_str_dup_frozen(VALUE str)
{
+#if WITH_OBJC
+ str = rb_str_dup(str);
+ rb_str_freeze(str);
+ return str;
+#else
if (STR_SHARED_P(str) && RSTRING(str)->as.heap.aux.shared) {
VALUE shared = RSTRING(str)->as.heap.aux.shared;
if (RSTRING_LEN(shared) == RSTRING_LEN(str)) {
@@ -1322,33 +1724,42 @@
str = rb_str_dup(str);
OBJ_FREEZE(str);
return str;
+#endif
}
VALUE
rb_str_locktmp(VALUE str)
{
+#if !WITH_OBJC
if (FL_TEST(str, STR_TMPLOCK)) {
rb_raise(rb_eRuntimeError, "temporal locking already locked string");
}
FL_SET(str, STR_TMPLOCK);
+#endif
return str;
}
VALUE
rb_str_unlocktmp(VALUE str)
{
+#if !WITH_OBJC
if (!FL_TEST(str, STR_TMPLOCK)) {
rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string");
}
FL_UNSET(str, STR_TMPLOCK);
+#endif
return str;
}
void
rb_str_set_len(VALUE str, long len)
{
+#if WITH_OBJC
+ rb_str_resize(str, len);
+#else
STR_SET_LEN(str, len);
RSTRING_PTR(str)[len] = '\0';
+#endif
}
VALUE
@@ -1361,6 +1772,18 @@
}
rb_str_modify(str);
+#if WITH_OBJC
+ slen = RSTRING_CLEN(str);
+ if (slen != len) {
+ void *cfdata;
+
+ CFStringPad((CFMutableStringRef)str, CFSTR(" "), len, 0);
+
+ cfdata = rb_str_cfdata2(str);
+ if (cfdata != NULL)
+ CFDataSetLength((CFMutableDataRef)cfdata, len);
+ }
+#else
slen = RSTRING_LEN(str);
if (len != slen) {
if (STR_EMBED_P(str)) {
@@ -1393,12 +1816,50 @@
RSTRING(str)->as.heap.len = len;
RSTRING(str)->as.heap.ptr[len] = '\0'; /* sentinel */
}
+#endif
return str;
}
+#if WITH_OBJC
+static void
+rb_objc_str_cat(VALUE str, const char *ptr, long len, int cfstring_encoding)
+{
+ CFMutableDataRef data;
+
+ data = (CFMutableDataRef)rb_str_cfdata2(str);
+ if (data != NULL) {
+ CFDataAppendBytes(data, (const UInt8 *)ptr, len);
+ }
+ else {
+ long slen;
+ if (ptr[len] != '\0') {
+ char *p = alloca(len + 1);
+ memcpy(p, ptr, len);
+ p[len] = '\0';
+ ptr = p;
+ }
+ slen = strlen(ptr);
+ if (slen == len) {
+ CFStringAppendCString((CFMutableStringRef)str, ptr,
+ cfstring_encoding);
+ }
+ else {
+ CFStringRef substr = CFStringCreateWithBytes(NULL,
+ (const UInt8 *)ptr,
+ len, cfstring_encoding, false);
+ CFStringAppend((CFMutableStringRef)str, substr);
+ CFRelease(substr);
+ }
+ }
+}
+#endif
+
VALUE
rb_str_buf_cat(VALUE str, const char *ptr, long len)
{
+#if WITH_OBJC
+ rb_objc_str_cat(str, ptr, len, kCFStringEncodingASCII);
+#else
long capa, total;
if (len == 0) return str;
@@ -1426,6 +1887,7 @@
memcpy(RSTRING_PTR(str) + RSTRING_LEN(str), ptr, len);
STR_SET_LEN(str, total);
RSTRING_PTR(str)[total] = '\0'; /* sentinel */
+#endif
return str;
}
@@ -1442,6 +1904,7 @@
if (len < 0) {
rb_raise(rb_eArgError, "negative string size (or size too big)");
}
+#if !WITH_OBJC
if (STR_ASSOC_P(str)) {
rb_str_modify(str);
if (STR_EMBED_P(str)) str_make_independent(str);
@@ -1451,6 +1914,7 @@
RSTRING(str)->as.heap.ptr[RSTRING(str)->as.heap.len] = '\0'; /* sentinel */
return str;
}
+#endif
return rb_str_buf_cat(str, ptr, len);
}
@@ -1461,6 +1925,7 @@
return rb_str_cat(str, ptr, strlen(ptr));
}
+#if !WITH_OBJC
static VALUE
rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, long len,
int ptr_encindex, int ptr_cr, int *ptr_cr_ret)
@@ -1580,17 +2045,27 @@
ENCODING_CODERANGE_SET(str, res_encindex, res_cr);
return str;
}
+#endif
VALUE
rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *ptr_enc)
{
+#if WITH_OBJC
+ rb_objc_str_cat(str, ptr, len, kCFStringEncodingUTF8);
+ return str;
+#else
return rb_enc_cr_str_buf_cat(str, ptr, len,
rb_enc_to_index(ptr_enc), ENC_CODERANGE_UNKNOWN, NULL);
+#endif
}
VALUE
rb_str_buf_cat_ascii(VALUE str, const char *ptr)
{
+#if WITH_OBJC
+ rb_objc_str_cat(str, ptr, strlen(ptr), kCFStringEncodingASCII);
+ return str;
+#else
/* ptr must reference NUL terminated ASCII string. */
int encindex = ENCODING_GET(str);
rb_encoding *enc = rb_enc_from_index(encindex);
@@ -1610,11 +2085,41 @@
}
return str;
}
+#endif
}
VALUE
rb_str_buf_append(VALUE str, VALUE str2)
{
+#if WITH_OBJC
+ CFMutableDataRef mdata;
+ CFDataRef data;
+ long str2len;
+
+ str2len = RSTRING_CLEN(str2);
+
+ if (str2len == 0)
+ return str;
+
+ data = (CFDataRef)rb_str_cfdata2(str2);
+ if (data != NULL) {
+ mdata = (CFMutableDataRef)rb_str_cfdata(str);
+ CFDataAppendBytes(mdata, CFDataGetBytePtr(data),
+ CFDataGetLength(data));
+ }
+ else {
+ mdata = (CFMutableDataRef)rb_str_cfdata2(str);
+ if (mdata == NULL) {
+ CFStringAppend((CFMutableStringRef)str, (CFStringRef)str2);
+ }
+ else {
+ data = (CFDataRef)rb_str_cfdata(str2);
+ CFDataAppendBytes(mdata, CFDataGetBytePtr(data),
+ CFDataGetLength(data));
+ }
+ }
+ rb_gc_malloc_increase(sizeof(UniChar) * str2len);
+#else
int str2_cr;
str2_cr = ENC_CODERANGE(str2);
@@ -1624,6 +2129,7 @@
OBJ_INFECT(str, str2);
ENC_CODERANGE_SET(str2, str2_cr);
+#endif
return str;
}
@@ -1631,11 +2137,12 @@
VALUE
rb_str_append(VALUE str, VALUE str2)
{
- rb_encoding *enc;
- int cr, cr2;
-
StringValue(str2);
+#if !WITH_OBJC
if (RSTRING_LEN(str2) > 0 && STR_ASSOC_P(str)) {
+ rb_encoding *enc;
+ int cr, cr2;
+
long len = RSTRING_LEN(str)+RSTRING_LEN(str2);
enc = rb_enc_check(str, str2);
cr = ENC_CODERANGE(str);
@@ -1651,6 +2158,7 @@
OBJ_INFECT(str, str2);
return str;
}
+#endif
return rb_str_buf_append(str, str2);
}
@@ -1675,6 +2183,14 @@
rb_str_concat(VALUE str1, VALUE str2)
{
if (FIXNUM_P(str2)) {
+#if WITH_OBJC
+ int c = FIX2INT(str2);
+
+ rb_str_modify(str1);
+ CFStringAppendCharacters((CFMutableStringRef)str1, (const UniChar *)&c,
+ 1);
+ rb_gc_malloc_increase(sizeof(UniChar));
+#else
rb_encoding *enc = STR_ENC_GET(str1);
int c = FIX2INT(str2);
int pos = RSTRING_LEN(str1);
@@ -1684,11 +2200,14 @@
rb_str_resize(str1, pos+len);
rb_enc_mbcput(c, RSTRING_PTR(str1)+pos, enc);
ENC_CODERANGE_SET(str1, cr);
+#endif
return str1;
}
return rb_str_append(str1, str2);
}
+#if !WITH_OBJC
+
typedef unsigned int ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1; /* unsigned 1-byte quantities */
@@ -1832,6 +2351,34 @@
return 1;
}
+#else
+
+int
+rb_memhash(const void *ptr, long len)
+{
+ CFDataRef data;
+ int code;
+
+ data = CFDataCreate(NULL, (const UInt8 *)ptr, len);
+ code = CFHash(data);
+ CFRelease((CFTypeRef)data);
+ return code;
+}
+
+int
+rb_str_hash(VALUE str)
+{
+ return CFHash((CFTypeRef)str);
+}
+
+int
+rb_str_hash_cmp(VALUE str1, VALUE str2)
+{
+ return CFEqual((CFTypeRef)str1, (CFTypeRef)str2) ? 0 : 1;
+}
+
+#endif
+
/*
* call-seq:
* str.hash => fixnum
@@ -1851,6 +2398,9 @@
int
rb_str_comparable(VALUE str1, VALUE str2)
{
+#if WITH_OBJC
+ return Qtrue;
+#else
int idx1 = ENCODING_GET(str1);
int idx2 = ENCODING_GET(str2);
int rc1, rc2;
@@ -1868,11 +2418,15 @@
return Qtrue;
}
return Qfalse;
+#endif
}
int
rb_str_cmp(VALUE str1, VALUE str2)
{
+#if WITH_OBJC
+ return CFStringCompare((CFStringRef)str1, (CFStringRef)str2, 0);
+#else
long len;
int retval;
rb_encoding *enc;
@@ -1894,8 +2448,12 @@
}
if (retval > 0) return 1;
return -1;
+#endif
}
+#if WITH_OBJC
+bool rb_objc_str_is_pure(VALUE);
+#endif
/*
* call-seq:
@@ -1918,11 +2476,30 @@
}
return rb_equal(str2, str1);
}
+#if WITH_OBJC
+ len = RSTRING_CLEN(str1);
+ if (len != RSTRING_CLEN(str2))
+ return Qfalse;
+ if (rb_str_cfdata2(str1) != NULL || rb_str_cfdata2(str2) != NULL)
+ return memcmp(RSTRING_CPTR(str1), RSTRING_CPTR(str2), len) == 0 ? Qtrue : Qfalse;
+ if (!rb_objc_str_is_pure(str2)) {
+ /* This is to work around a strange bug in CFEqual's objc
+ * dispatching.
+ */
+ VALUE tmp = str1;
+ str1 = str2;
+ str2 = tmp;
+ }
+ if (CFEqual((CFTypeRef)str1, (CFTypeRef)str2))
+ return Qtrue;
+#else
if (!rb_str_comparable(str1, str2)) return Qfalse;
if (RSTRING_LEN(str1) == (len = RSTRING_LEN(str2)) &&
memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2), len) == 0) {
return Qtrue;
}
+#endif
+
return Qfalse;
}
@@ -1939,10 +2516,15 @@
if (TYPE(str2) != T_STRING || RSTRING_LEN(str1) != RSTRING_LEN(str2))
return Qfalse;
+#if WITH_OBJC
+ if (CFEqual((CFTypeRef)str1, (CFTypeRef)str2))
+ return Qtrue;
+#else
if (!rb_str_comparable(str1, str2)) return Qfalse;
if (memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2),
lesser(RSTRING_LEN(str1), RSTRING_LEN(str2))) == 0)
return Qtrue;
+#endif
return Qfalse;
}
@@ -2013,6 +2595,10 @@
static VALUE
rb_str_casecmp(VALUE str1, VALUE str2)
{
+#if WITH_OBJC
+ return INT2FIX(CFStringCompare((CFStringRef)str1, (CFStringRef)str2,
+ kCFCompareCaseInsensitive));
+#else
long len;
rb_encoding *enc;
char *p1, *p1end, *p2, *p2end;
@@ -2042,11 +2628,21 @@
if (RSTRING_LEN(str1) == RSTRING_LEN(str2)) return INT2FIX(0);
if (RSTRING_LEN(str1) > RSTRING_LEN(str2)) return INT2FIX(1);
return INT2FIX(-1);
+#endif
}
static long
rb_str_index(VALUE str, VALUE sub, long offset)
{
+#if WITH_OBJC
+ CFRange r;
+ return (CFStringFindWithOptions((CFStringRef)str,
+ (CFStringRef)sub,
+ CFRangeMake(offset, CFStringGetLength((CFStringRef)str) - offset),
+ 0,
+ &r))
+ ? r.location : -1;
+#else
long pos;
char *s, *sptr;
long len, slen;
@@ -2084,9 +2680,9 @@
s = t;
}
return pos + offset;
+#endif
}
-
/*
* call-seq:
* str.index(substring [, offset]) => fixnum or nil
@@ -2101,6 +2697,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
*/
@@ -2159,6 +2756,23 @@
static long
rb_str_rindex(VALUE str, VALUE sub, long pos)
{
+#if WITH_OBJC
+ CFRange r;
+ long sublen, strlen;
+ sublen = RSTRING_CLEN(sub);
+ strlen = RSTRING_CLEN(str);
+ if (sublen == 0 && strlen == 0)
+ return 0;
+ if (pos <= sublen) {
+ pos = strlen < sublen ? strlen : sublen;
+ }
+ return (CFStringFindWithOptions((CFStringRef)str,
+ (CFStringRef)sub,
+ CFRangeMake(0, pos+1),
+ kCFCompareBackwards,
+ &r))
+ ? r.location : -1;
+#else
long len, slen;
char *s, *sbeg, *e, *t;
rb_encoding *enc;
@@ -2192,6 +2806,7 @@
pos--;
}
return -1;
+#endif
}
@@ -2210,6 +2825,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
*/
@@ -2280,7 +2896,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
@@ -2311,7 +2927,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
@@ -2351,6 +2967,7 @@
NEIGHBOR_WRAPPED
};
+#if !WITH_OBJC
static enum neighbor_char
enc_succ_char(char *p, int len, rb_encoding *enc)
{
@@ -2414,6 +3031,7 @@
}
}
}
+#endif
/*
overwrite +p+ by succeeding letter in +enc+ and returns
@@ -2427,6 +3045,10 @@
static enum neighbor_char
enc_succ_alnum_char(char *p, int len, rb_encoding *enc, char *carry)
{
+#if WITH_OBJC
+ /* TODO rewrite me */
+ return NEIGHBOR_NOT_CHAR;
+#else
enum neighbor_char ret;
int c;
int ctype;
@@ -2478,6 +3100,7 @@
MEMCPY(carry, p, char, len);
enc_succ_char(carry, len, enc);
return NEIGHBOR_WRAPPED;
+#endif
}
@@ -2509,6 +3132,69 @@
VALUE
rb_str_succ(VALUE orig)
{
+#if WITH_OBJC
+ UniChar *buf;
+ UniChar carry;
+ long i, len;
+ bool modified;
+
+ len = CFStringGetLength((CFStringRef)orig);
+ if (len == 0)
+ return orig;
+
+ buf = (UniChar *)alloca(sizeof(UniChar) * (len + 1));
+ buf++;
+
+ CFStringGetCharacters((CFStringRef)orig, CFRangeMake(0, len), buf);
+ modified = false;
+ carry = 0;
+
+ for (i = len - 1; i >= 0; i--) {
+ UniChar c = buf[i];
+ if (iswdigit(c)) {
+ modified = true;
+ if (c != '9') {
+ buf[i]++;
+ carry = 0;
+ break;
+ }
+ else {
+ buf[i] = '0';
+ carry = '1';
+ }
+ }
+ else if (iswalpha(c)) {
+ bool lower = islower(c);
+ UniChar e = lower ? 'z' : 'Z';
+ modified = true;
+ if (c != e) {
+ buf[i]++;
+ carry = 0;
+ break;
+ }
+ else {
+ carry = buf[i] = lower ? 'a' : 'A';
+ }
+ }
+ }
+
+ if (!modified) {
+ buf[len-1]++;
+ }
+ else if (carry != 0) {
+ buf--;
+ *buf = carry;
+ len++;
+ }
+
+ CFMutableStringRef newstr;
+
+ newstr = CFStringCreateMutable(NULL, 0);
+ CFStringAppendCharacters(newstr, buf, len);
+ CFMakeCollectable(newstr);
+
+ return (VALUE)newstr;
+#else
rb_encoding *enc;
VALUE str;
char *sbeg, *s, *e;
@@ -2517,10 +3203,12 @@
char carry[ONIGENC_CODE_TO_MBC_MAXLEN] = "\1";
int carry_pos = 0, carry_len = 1;
- str = rb_str_new5(orig, RSTRING_PTR(orig), RSTRING_LEN(orig));
+ str = rb_str_new5(orig, RSTRING_CPTR(orig), RSTRING_CLEN(orig));
+#if !WITH_OBJC
rb_enc_cr_str_copy_for_substr(str, orig);
OBJ_INFECT(str, orig);
- if (RSTRING_LEN(str) == 0) return str;
+#endif
+ if (RSTRING_CLEN(str) == 0) return str;
enc = STR_ENC_GET(orig);
sbeg = RSTRING_PTR(str);
@@ -2532,8 +3220,10 @@
neighbor = enc_succ_alnum_char(s, l, enc, carry);
if (neighbor == NEIGHBOR_NOT_CHAR)
continue;
- if (neighbor == NEIGHBOR_FOUND)
+ if (neighbor == NEIGHBOR_FOUND) {
+ RSTRING_SYNC(str);
return str;
+ }
c = 1;
carry_pos = s - sbeg;
carry_len = l;
@@ -2544,8 +3234,10 @@
enum neighbor_char neighbor;
if ((l = rb_enc_precise_mbclen(s, e, enc)) <= 0) continue;
neighbor = enc_succ_char(s, l, enc);
- if (neighbor == NEIGHBOR_FOUND)
- return str;
+ if (neighbor == NEIGHBOR_FOUND) {
+ RSTRING_SYNC(str);
+ return str;
+ }
if (rb_enc_precise_mbclen(s, s+l, enc) != l) {
/* wrapped to \0...\0. search next valid char. */
enc_succ_char(s, l, enc);
@@ -2557,6 +3249,14 @@
carry_pos = s - sbeg;
}
}
+#if WITH_OBJC
+ CFMutableDataRef data = (CFMutableDataRef)rb_str_cfdata(str);
+ CFDataSetLength(data, RSTRING_LEN(str) + carry_len);
+ s = (char *)CFDataGetMutableBytePtr(data);
+ memmove(s + carry_len, s, RSTRING_LEN(str) - carry_pos);
+ memmove(s, carry, carry_len);
+ RSTRING_SYNC(str);
+#else
RESIZE_CAPA(str, RSTRING_LEN(str) + carry_len);
s = RSTRING_PTR(str) + carry_pos;
memmove(s + carry_len, s, RSTRING_LEN(str) - carry_pos);
@@ -2564,7 +3264,9 @@
STR_SET_LEN(str, RSTRING_LEN(str) + carry_len);
RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0';
rb_enc_str_coderange(str);
+#endif
return str;
+#endif
}
@@ -2618,13 +3320,33 @@
rb_scan_args(argc, argv, "11", &end, &exclusive);
excl = RTEST(exclusive);
- succ = rb_intern("succ");
StringValue(end);
+#if WITH_OBJC
+ if (RSTRING_CLEN(beg) == 1 && RSTRING_CLEN(end) == 1) {
+ UniChar c = CFStringGetCharacterAtIndex((CFStringRef)beg, 0);
+ UniChar e = CFStringGetCharacterAtIndex((CFStringRef)end, 0);
+
+ if (c > e || (excl && c == e))
+ return beg;
+ for (;;) {
+ CFMutableStringRef substr;
+ substr = CFStringCreateMutable(NULL, 0);
+ CFStringAppendCharacters(substr, &c, 1);
+ CFMakeCollectable(substr);
+ rb_yield((VALUE)substr);
+ if (!excl && c == e)
+ break;
+ c++;
+ if (excl && c == e)
+ break;
+ }
+ return beg;
+#else
enc = rb_enc_check(beg, end);
- if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 &&
+ if (RSTRING_CLEN(beg) == 1 && RSTRING_CLEN(end) == 1 &&
is_ascii_string(beg) && is_ascii_string(end)) {
- char c = RSTRING_PTR(beg)[0];
- char e = RSTRING_PTR(end)[0];
+ char c = RSTRING_CPTR(beg)[0];
+ char e = RSTRING_CPTR(end)[0];
if (c > e || (excl && c == e)) return beg;
for (;;) {
@@ -2634,10 +3356,12 @@
if (excl && c == e) break;
}
return beg;
+#endif
}
n = rb_str_cmp(beg, end);
if (n > 0 || (excl && n == 0)) return beg;
+ succ = rb_intern("succ");
after_end = rb_funcall(end, succ, 0, 0);
current = beg;
while (!rb_str_equal(current, after_end)) {
@@ -2646,7 +3370,7 @@
current = rb_funcall(current, succ, 0, 0);
StringValue(current);
if (excl && rb_str_equal(current, end)) break;
- if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
+ if (RSTRING_CLEN(current) > RSTRING_CLEN(end) || RSTRING_CLEN(current) == 0)
break;
}
@@ -2673,7 +3397,7 @@
num_index:
str = rb_str_substr(str, idx, 1);
- if (!NIL_P(str) && RSTRING_LEN(str) == 0) return Qnil;
+ if (!NIL_P(str) && RSTRING_CLEN(str) == 0) return Qnil;
return str;
case T_REGEXP:
@@ -2774,6 +3498,10 @@
rb_str_splice_0(VALUE str, long beg, long len, VALUE val)
{
rb_str_modify(str);
+#if WITH_OBJC
+ CFStringReplace((CFMutableStringRef)str, CFRangeMake(beg, len),
+ (CFStringRef)val);
+#else
if (len < RSTRING_LEN(val)) {
/* expand string */
RESIZE_CAPA(str, RSTRING_LEN(str) + RSTRING_LEN(val) - len + 1);
@@ -2795,22 +3523,29 @@
RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0';
}
OBJ_INFECT(str, val);
+#endif
}
static void
rb_str_splice(VALUE str, long beg, long len, VALUE val)
{
long slen;
+#if !WITH_OBJC
char *p, *e;
rb_encoding *enc;
int singlebyte = single_byte_optimizable(str);
+#endif
if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len);
StringValue(val);
rb_str_modify(str);
+#if WITH_OBJC
+ slen = CFStringGetLength((CFStringRef)str);
+#else
enc = rb_enc_check(str, val);
slen = str_strlen(str, enc);
+#endif
if (slen < beg) {
out_of_range:
@@ -2825,6 +3560,9 @@
if (slen < len || slen < beg + len) {
len = slen - beg;
}
+#if WITH_OBJC
+ rb_str_splice_0(str, beg, len, val);
+#else
p = str_nth(RSTRING_PTR(str), RSTRING_END(str), beg, enc, singlebyte);
if (!p) p = RSTRING_END(str);
e = str_nth(p, RSTRING_END(str), len, enc, singlebyte);
@@ -2834,6 +3572,7 @@
len = e - p; /* physical length */
rb_str_splice_0(str, beg, len, val);
rb_enc_associate(str, enc);
+#endif
}
void
@@ -2873,9 +3612,13 @@
end = END(nth);
len = end - start;
StringValue(val);
+#if !WITH_OBJC
enc = rb_enc_check(str, val);
+#endif
rb_str_splice_0(str, start, len, val);
+#if !WITH_OBJC
rb_enc_associate(str, enc);
+#endif
}
static VALUE
@@ -3004,7 +3747,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"
@@ -3098,13 +3841,17 @@
pat = get_pat(argv[0], 1);
if (rb_reg_search(pat, str, 0, 0) >= 0) {
rb_encoding *enc;
+#if !WITH_OBJC
int cr = ENC_CODERANGE(str);
+#endif
match = rb_backref_get();
regs = RMATCH_REGS(match);
if (iter || !NIL_P(hash)) {
+#if !WITH_OBJC
char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);
+#endif
if (iter) {
rb_match_busy(match);
@@ -3114,13 +3861,16 @@
repl = rb_hash_aref(hash, rb_str_subseq(str, BEG(0), END(0) - BEG(0)));
repl = rb_obj_as_string(repl);
}
+#if !WITH_OBJC
str_mod_check(str, p, len);
+#endif
str_frozen_check(str);
if (iter) rb_backref_set(match);
}
else {
repl = rb_reg_regsub(repl, str, regs, pat);
}
+#if !WITH_OBJC
enc = rb_enc_compatible(str, repl);
if (!enc) {
rb_encoding *str_enc = STR_ENC_GET(str);
@@ -3133,9 +3883,14 @@
}
enc = STR_ENC_GET(repl);
}
+#endif
rb_str_modify(str);
+#if WITH_OBJC
+ RSTRING_SYNC(str);
+ rb_str_splice_0(str, BEG(0), END(0) - BEG(0), repl);
+ if (OBJ_TAINTED(repl)) tainted = 1;
+#else
rb_enc_associate(str, enc);
- if (OBJ_TAINTED(repl)) tainted = 1;
if (ENC_CODERANGE_UNKNOWN < cr && cr < ENC_CODERANGE_BROKEN) {
int cr2 = ENC_CODERANGE(repl);
if (cr2 == ENC_CODERANGE_UNKNOWN || cr2 > cr) cr = cr2;
@@ -3154,6 +3909,7 @@
STR_SET_LEN(str, RSTRING_LEN(str) + RSTRING_LEN(repl) - plen);
RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0';
ENC_CODERANGE_SET(str, cr);
+#endif
if (tainted) OBJ_TAINT(str);
return str;
@@ -3189,7 +3945,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"
*/
@@ -3209,7 +3965,7 @@
long beg, n;
long offset, blen, slen, len;
int iter = 0;
- char *sp, *cp;
+ const char *sp, *cp;
int tainted = 0;
rb_encoding *str_enc;
@@ -3238,12 +3994,19 @@
return rb_str_dup(str);
}
+#if WITH_OBJC
+ dest = rb_str_new5(str, NULL, 0);
+ slen = RSTRING_CLEN(str);
+ sp = RSTRING_CPTR(str);
+ cp = sp;
+#else
blen = RSTRING_LEN(str) + 30; /* len + margin */
dest = rb_str_buf_new(blen);
sp = RSTRING_PTR(str);
slen = RSTRING_LEN(str);
cp = sp;
str_enc = STR_ENC_GET(str);
+#endif
do {
n++;
@@ -3273,7 +4036,7 @@
len = beg - offset; /* copy pre-match substr */
if (len) {
- rb_enc_str_buf_cat(dest, cp, len, str_enc);
+ rb_enc_str_buf_cat(dest, cp, len, str_enc);
}
rb_str_buf_append(dest, val);
@@ -3284,30 +4047,45 @@
* Always consume at least one character of the input string
* in order to prevent infinite loops.
*/
- if (RSTRING_LEN(str) <= END(0)) break;
- len = rb_enc_mbclen(RSTRING_PTR(str)+END(0), RSTRING_END(str), str_enc);
- rb_enc_str_buf_cat(dest, RSTRING_PTR(str)+END(0), len, str_enc);
+ if (slen <= END(0)) break;
+#if WITH_OBJC
+ len = 1;
+#else
+ len = rb_enc_mbclen(sp+END(0), sp+slen, str_enc);
+#endif
+ rb_enc_str_buf_cat(dest, sp+END(0), len, str_enc);
offset = END(0) + len;
}
- cp = RSTRING_PTR(str) + offset;
- if (offset > RSTRING_LEN(str)) break;
+ cp = sp + offset;
+ if (offset > slen) break;
beg = rb_reg_search(pat, str, offset, 0);
} while (beg >= 0);
- if (RSTRING_LEN(str) > offset) {
- rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
+ if (slen > offset) {
+ rb_enc_str_buf_cat(dest, cp, slen - offset, str_enc);
}
rb_backref_set(match);
+#if WITH_OBJC
if (bang) {
+ RSTRING_SYNC(str);
+ RSTRING_SYNC(dest);
+ CFStringReplaceAll((CFMutableStringRef)str, (CFStringRef)dest);
+ }
+ else {
+ if (!tainted && OBJ_TAINTED(str))
+ tainted = 1;
+ str = dest;
+ }
+#else
+ if (bang) {
rb_str_shared_replace(str, dest);
}
else {
RBASIC(dest)->klass = rb_obj_class(str);
-#if WITH_OBJC
RBASIC(dest)->isa = RCLASS_OCID(RBASIC(dest)->klass);
-#endif
OBJ_INFECT(dest, str);
str = dest;
}
+#endif
if (tainted) OBJ_TAINT(str);
return str;
@@ -3359,7 +4137,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}"
*/
@@ -3381,12 +4159,27 @@
* s.replace "world" #=> "world"
*/
-static VALUE
+VALUE
rb_str_replace(VALUE str, VALUE str2)
{
long len;
if (str == str2) return str;
-
+#if WITH_OBJC
+ rb_str_modify(str);
+ CFDataRef data = (CFDataRef)rb_str_cfdata2(str2);
+ if (data != NULL) {
+ CFMutableDataRef mdata;
+
+ mdata = CFDataCreateMutableCopy(NULL, 0, data);
+ rb_gc_malloc_increase(CFDataGetLength(data));
+ rb_str_cfdata_set(str, mdata);
+ CFMakeCollectable(mdata);
+ }
+ CFStringReplaceAll((CFMutableStringRef)str, (CFStringRef)str2);
+ rb_gc_malloc_increase(CFStringGetLength((CFStringRef)str2) * sizeof(UniChar));
+ if (OBJ_TAINTED(str2))
+ OBJ_TAINT(str);
+#else
StringValue(str2);
len = RSTRING_LEN(str2);
if (STR_ASSOC_P(str2)) {
@@ -3410,6 +4203,7 @@
OBJ_INFECT(str, str2);
rb_enc_cr_str_exact_copy(str, str2);
+#endif
return str;
}
@@ -3426,6 +4220,11 @@
static VALUE
rb_str_clear(VALUE str)
{
+#if WITH_OBJC
+ rb_str_modify(str);
+ CFStringDelete((CFMutableStringRef)str,
+ CFRangeMake(0, CFStringGetLength((CFStringRef)str)));
+#else
/* rb_str_modify() */ /* no need for str_make_independent */
if (str_independent(str) && !STR_EMBED_P(str)) {
free(RSTRING_PTR(str));
@@ -3434,6 +4233,7 @@
STR_SET_EMBED_LEN(str, 0);
RSTRING_PTR(str)[0] = 0;
ENC_CODERANGE_CLEAR(str);
+#endif
return str;
}
@@ -3463,10 +4263,11 @@
rb_str_getbyte(VALUE str, VALUE index)
{
long pos = NUM2LONG(index);
+ long n = RSTRING_LEN(str);
if (pos < 0)
- pos += RSTRING_LEN(str);
- if (pos < 0 || RSTRING_LEN(str) <= pos)
+ pos += n;
+ if (pos < 0 || n <= pos)
return Qnil;
return INT2FIX((unsigned char)RSTRING_PTR(str)[pos]);
@@ -3483,21 +4284,76 @@
{
long pos = NUM2LONG(index);
int byte = NUM2INT(value);
+ long n = RSTRING_LEN(str);
rb_str_modify(str);
- if (pos < -RSTRING_LEN(str) || RSTRING_LEN(str) <= pos)
+ if (pos < -n || n <= pos)
rb_raise(rb_eIndexError, "index %ld out of string", pos);
if (pos < 0)
- pos += RSTRING_LEN(str);
+ pos += n;
RSTRING_PTR(str)[pos] = byte;
+#if WITH_OBJC
+ RSTRING_SYNC(str);
+#endif
return value;
}
+
/*
* call-seq:
+ * str.reverse! => str
+ *
+ * Reverses <i>str</i> in place.
+ */
+
+static VALUE
+rb_str_reverse_bang(VALUE str)
+{
+#if WITH_OBJC
+ CFIndex i, n;
+ UniChar *buffer;
+
+ n = CFStringGetLength((CFStringRef)str);
+ if (n <= 1)
+ return rb_str_dup(str);
+
+ buffer = (UniChar *)alloca(sizeof(UniChar) * n);
+ CFStringGetCharacters((CFStringRef)str, CFRangeMake(0, n), buffer);
+ for (i = 0; i < (n / 2); i++) {
+ UniChar c = buffer[i];
+ buffer[i] = buffer[n - i - 1];
+ buffer[n - i - 1] = c;
+ }
+ CFStringDelete((CFMutableStringRef)str, CFRangeMake(0, n));
+ CFStringAppendCharacters((CFMutableStringRef)str, (const UniChar *)buffer, n);
+#else
+ char *s, *e, c;
+
+ if (RSTRING_LEN(str) > 1) {
+ rb_str_modify(str);
+ s = RSTRING_PTR(str);
+ e = RSTRING_END(str) - 1;
+
+ if (single_byte_optimizable(str)) {
+ while (s < e) {
+ c = *s;
+ *s++ = *e;
+ *e-- = c;
+ }
+ }
+ else {
+ rb_str_shared_replace(str, rb_str_reverse(str));
+ }
+ }
+#endif
+ return str;
+}
+
+/*
+ * call-seq:
* str.reverse => new_str
*
* Returns a new string with the characters from <i>str</i> in reverse order.
@@ -3508,6 +4364,11 @@
static VALUE
rb_str_reverse(VALUE str)
{
+#if WITH_OBJC
+ VALUE obj = rb_str_dup(str);
+ rb_str_reverse_bang(obj);
+ return obj;
+#else
rb_encoding *enc;
VALUE obj;
char *s, *e, *p;
@@ -3539,43 +4400,11 @@
rb_enc_cr_str_copy_for_substr(obj, str);
return obj;
+#endif
}
-
/*
* call-seq:
- * str.reverse! => str
- *
- * Reverses <i>str</i> in place.
- */
-
-static VALUE
-rb_str_reverse_bang(VALUE str)
-{
- char *s, *e, c;
-
- if (RSTRING_LEN(str) > 1) {
- rb_str_modify(str);
- s = RSTRING_PTR(str);
- e = RSTRING_END(str) - 1;
-
- if (single_byte_optimizable(str)) {
- while (s < e) {
- c = *s;
- *s++ = *e;
- *e-- = c;
- }
- }
- else {
- rb_str_shared_replace(str, rb_str_reverse(str));
- }
- }
- return str;
-}
-
-
-/*
- * call-seq:
* str.include? other_str => true or false
* str.include? fixnum => true or false
*
@@ -3624,13 +4453,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);
}
@@ -3670,7 +4501,11 @@
static VALUE
rb_str_to_s(VALUE str)
{
+#if WITH_OBJC
+ if (!rb_objc_str_is_pure(str)) {
+#else
if (rb_obj_class(str) != rb_cString) {
+#endif
VALUE dup = str_alloc(rb_cString);
rb_str_replace(dup, str);
return dup;
@@ -3681,11 +4516,16 @@
static void
str_cat_char(VALUE str, int c, rb_encoding *enc)
{
+#if WITH_OBJC
+ CFStringAppendCharacters((CFMutableStringRef)str,
+ (const UniChar *)&c, 1);
+#else
char s[16];
int n = rb_enc_codelen(c, enc);
rb_enc_mbcput(c, s, enc);
rb_enc_str_buf_cat(str, s, n, enc);
+#endif
}
static void
@@ -3704,25 +4544,45 @@
*
* str = "hello"
* str[3] = "\b"
- * str.inspect #=> "\"hel\bo\""
+ * str.inspect #=> "\"hel\\bo\""
*/
VALUE
rb_str_inspect(VALUE str)
{
rb_encoding *enc = STR_ENC_GET(str);
- char *p, *pend;
- VALUE result = rb_str_buf_new2("");
+ const char *p, *pend;
+ VALUE result;
+#if WITH_OBJC
+ if (rb_objc_str_is_bytestring(str)) {
+ p = (const char *)RSTRING_PTR(str);
+ pend = (const char *)RSTRING_END(str);
+ }
+ else {
+ p = RSTRING_CPTR(str);
+ pend = p + RSTRING_CLEN(str);
+ }
+ if (p == NULL)
+ return rb_str_new2("\"\"");
+#else
+ p = RSTRING_PTR(str); pend = RSTRING_END(str);
+#endif
+ result = rb_str_buf_new2("");
+#if !WITH_OBJC
if (!rb_enc_asciicompat(enc)) enc = rb_usascii_encoding();
rb_enc_associate(result, enc);
+#endif
str_cat_char(result, '"', enc);
- p = RSTRING_PTR(str); pend = RSTRING_END(str);
while (p < pend) {
int c;
int n;
int cc;
+#if WITH_OBJC
+ c = *p;
+ n = 1;
+#else
n = rb_enc_precise_mbclen(p, pend, enc);
if (!MBCLEN_CHARFOUND_P(n)) {
p++;
@@ -3733,13 +4593,18 @@
c = rb_enc_codepoint(p, pend, enc);
n = rb_enc_codelen(c, enc);
+#endif
p += n;
if (c == '"'|| c == '\\' ||
(c == '#' &&
p < pend &&
+#if WITH_OBJC
+ ((cc = *p),
+#else
MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&
(cc = rb_enc_codepoint(p,pend,enc),
+#endif
(cc == '$' || cc == '@' || cc == '{')))) {
prefix_escape(result, c, enc);
}
@@ -3773,7 +4638,7 @@
else {
char buf[5];
char *s;
- char *q;
+ const char *q;
escape_codepoint:
for (q = p-n; q < p; q++) {
@@ -3811,7 +4676,18 @@
VALUE result;
len = 2; /* "" */
+#if WITH_OBJC
+ if (rb_objc_str_is_bytestring(str)) {
+ p = RSTRING_PTR(str);
+ pend = RSTRING_END(str);
+ }
+ else {
+ p = RSTRING_CPTR(str);
+ pend = p + RSTRING_CLEN(str);
+ }
+#else
p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
+#endif
while (p < pend) {
unsigned char c = *p++;
switch (c) {
@@ -3838,7 +4714,7 @@
}
if (!rb_enc_asciicompat(enc0)) {
len += 19; /* ".force_encoding('')" */
- len += strlen(enc0->name);
+ len += strlen(rb_enc_name(enc0));
}
result = rb_str_new5(str, 0, len);
@@ -3900,13 +4776,18 @@
}
*q++ = '"';
if (!rb_enc_asciicompat(enc0)) {
- sprintf(q, ".force_encoding(\"%s\")", enc0->name);
+ sprintf(q, ".force_encoding(\"%s\")", rb_enc_name(enc0));
+#if !WITH_OBJC
enc0 = rb_ascii8bit_encoding();
+#endif
}
OBJ_INFECT(result, str);
/* result from dump is ASCII */
+#if !WITH_OBJC
rb_enc_associate(result, enc0);
+#endif
+ RSTRING_SYNC(result);
return result;
}
@@ -3923,6 +4804,15 @@
static VALUE
rb_str_upcase_bang(VALUE str)
{
+#if WITH_OBJC
+ CFHashCode h;
+ rb_str_modify(str);
+ h = CFHash((CFTypeRef)str);
+ CFStringUppercase((CFMutableStringRef)str, NULL);
+ if (h == CFHash((CFTypeRef)str))
+ return Qnil;
+ return str;
+#else
rb_encoding *enc;
char *s, *send;
int modify = 0;
@@ -3945,6 +4835,7 @@
ENC_CODERANGE_SET(str, cr);
if (modify) return str;
return Qnil;
+#endif
}
@@ -3981,6 +4872,15 @@
static VALUE
rb_str_downcase_bang(VALUE str)
{
+#if WITH_OBJC
+ CFHashCode h;
+ rb_str_modify(str);
+ h = CFHash((CFTypeRef)str);
+ CFStringLowercase((CFMutableStringRef)str, NULL);
+ if (h == CFHash((CFTypeRef)str))
+ return Qnil;
+ return str;
+#else
rb_encoding *enc;
char *s, *send;
int modify = 0;
@@ -4003,6 +4903,7 @@
ENC_CODERANGE_SET(str, cr);
if (modify) return str;
return Qnil;
+#endif
}
@@ -4044,6 +4945,37 @@
static VALUE
rb_str_capitalize_bang(VALUE str)
{
+#if WITH_OBJC
+ CFStringRef tmp;
+ long i, n;
+ bool changed;
+ UniChar c;
+ UniChar *buffer;
+
+ rb_str_modify(str);
+ n = CFStringGetLength((CFStringRef)str);
+ if (n == 0)
+ return Qnil;
+ buffer = (UniChar *)alloca(sizeof(UniChar) * n);
+ CFStringGetCharacters((CFStringRef)str, CFRangeMake(0, n), buffer);
+ changed = false;
+ if (iswlower(buffer[0])) {
+ buffer[0] = towupper(buffer[0]);
+ changed = true;
+ }
+ for (i = 1; i < n; i++) {
+ if (iswupper(buffer[i])) {
+ buffer[i] = towlower(buffer[i]);
+ changed = true;
+ }
+ }
+ if (!changed)
+ return Qnil;
+ tmp = CFStringCreateWithCharacters(NULL, buffer, n);
+ CFStringReplaceAll((CFMutableStringRef)str, tmp);
+ CFRelease(tmp);
+ return str;
+#else
rb_encoding *enc;
char *s, *send;
int modify = 0;
@@ -4073,6 +5005,7 @@
ENC_CODERANGE_SET(str, cr);
if (modify) return str;
return Qnil;
+#endif
}
@@ -4110,6 +5043,40 @@
static VALUE
rb_str_swapcase_bang(VALUE str)
{
+#if WITH_OBJC
+ CFIndex i, n;
+ UniChar *buffer;
+ bool changed;
+
+ n = CFStringGetLength((CFStringRef)str);
+ if (n == 0)
+ return rb_str_dup(str);
+
+ buffer = (UniChar *)CFStringGetCharactersPtr((CFStringRef)str);
+ if (buffer == NULL) {
+ buffer = (UniChar *)alloca(sizeof(UniChar) * n);
+ CFStringGetCharacters((CFStringRef)str, CFRangeMake(0, n), buffer);
+ }
+ for (i = 0, changed = false; i < n; i++) {
+ UniChar c = buffer[i];
+ if (iswlower(c)) {
+ c = towupper(c);
+ }
+ else if (iswupper(c)) {
+ c = towlower(c);
+ }
+ else {
+ continue;
+ }
+ changed = true;
+ buffer[i] = c;
+ }
+ if (!changed)
+ return Qnil;
+ CFStringDelete((CFMutableStringRef)str, CFRangeMake(0, n));
+ CFStringAppendCharacters((CFMutableStringRef)str, (const UniChar *)buffer, n);
+ return str;
+#else
rb_encoding *enc;
char *s, *send;
int modify = 0;
@@ -4137,6 +5104,7 @@
ENC_CODERANGE_SET(str, cr);
if (modify) return str;
return Qnil;
+#endif
}
@@ -4160,6 +5128,7 @@
return str;
}
+#if !WITH_OBJC
typedef unsigned char *USTR;
struct tr {
@@ -4201,10 +5170,353 @@
}
static VALUE rb_str_delete_bang(int,VALUE*,VALUE);
+#endif
+#if WITH_OBJC
+typedef void str_charset_find_cb
+(CFRange *, const CFRange *, CFStringRef, UniChar, void *);
+
+static void
+str_charset_find(CFStringRef str, VALUE *charsets, int charset_count,
+ bool squeeze_mode, str_charset_find_cb *cb, void *ctx)
+{
+ int i;
+ long n;
+ bool changed;
+ CFMutableCharacterSetRef charset;
+ CFRange search_range, result_range;
+
+ if (charset_count == 0)
+ return;
+
+ n = CFStringGetLength((CFStringRef)str);
+ if (n == 0)
+ return;
+
+ for (i = 0, charset = NULL; i < charset_count; i++) {
+ VALUE s = charsets[i];
+ bool exclude;
+ const char *sptr, *p;
+
+ StringValue(s);
+
+ sptr = RSTRING_CPTR(s);
+ exclude = sptr[0] == '^';
+
+ p = NULL;
+ if (exclude || (p = strchr(sptr, '-')) != NULL) {
+ CFMutableCharacterSetRef subset;
+ const char *b, *e;
+
+ b = exclude ? sptr + 1 : sptr;
+ e = sptr + strlen(sptr) - 1;
+ subset = CFCharacterSetCreateMutable(NULL);
+ if (p == NULL)
+ p = strchr(b, '-');
+ while (p != NULL) {
+ if (p > b && *(p - 1) != '\\' && *(p + 1) != '\0') {
+ CFCharacterSetAddCharactersInRange(subset,
+ CFRangeMake(*(p - 1), *(p + 1) - *(p - 1) + 1));
+ }
+ if (p > b) {
+ CFStringRef substr;
+ substr = CFStringCreateWithBytes(NULL,
+ (const UInt8 *)b,
+ (CFIndex)p - (CFIndex)b,
+ kCFStringEncodingUTF8,
+ false);
+ CFCharacterSetAddCharactersInString(subset, substr);
+ CFRelease(substr);
+ }
+ if (p == b) {
+ p = NULL;
+ }
+ else {
+ b = p + 2;
+ p = strchr(b, '-');
+ }
+ }
+ if (b <= e) {
+ CFStringRef substr;
+ substr = CFStringCreateWithBytes(NULL,
+ (const UInt8 *)b,
+ (CFIndex)e - (CFIndex)b + 1,
+ kCFStringEncodingUTF8,
+ false);
+ CFCharacterSetAddCharactersInString(subset, substr);
+ CFRelease(substr);
+ }
+
+ if (exclude)
+ CFCharacterSetInvert(subset);
+
+ if (charset == NULL) {
+ charset = subset;
+ }
+ else {
+ CFCharacterSetIntersect(charset, subset);
+ CFRelease(subset);
+ }
+ }
+ else {
+ if (charset == NULL) {
+ charset = CFCharacterSetCreateMutable(NULL);
+ CFCharacterSetAddCharactersInString(charset, (CFStringRef)s);
+ }
+ else {
+ CFCharacterSetRef subset;
+ subset = CFCharacterSetCreateWithCharactersInString(NULL,
+ (CFStringRef)s);
+ CFCharacterSetIntersect(charset, subset);
+ CFRelease(subset);
+ }
+ }
+ }
+
+ search_range = CFRangeMake(0, n);
+#if 0
+ while (search_range.length != 0
+ && CFStringFindCharacterFromSet(
+ (CFStringRef)str,
+ (CFCharacterSetRef)charset,
+ search_range,
+ 0,
+ &result_range)) {
+ (*cb)(&search_range, (const CFRange *)&result_range, str, ctx);
+ }
+#else
+ CFStringInlineBuffer buf;
+ UniChar previous_char = 0;
+ CFStringInitInlineBuffer((CFStringRef)str, &buf, search_range);
+ do {
+ long i;
+ bool mutated = false;
+
+ if (search_range.location + search_range.length < n) {
+ n = search_range.location + search_range.length;
+ CFStringInitInlineBuffer((CFStringRef)str, &buf, CFRangeMake(0, n));
+ }
+
+ result_range.length = 0;
+
+ for (i = search_range.location;
+ i < search_range.location + search_range.length;
+ i++) {
+
+ UniChar c;
+
+ c = CFStringGetCharacterFromInlineBuffer(&buf, i);
+ if (CFCharacterSetIsCharacterMember((CFCharacterSetRef)charset,
+ c)) {
+ if (result_range.length == 0) {
+ result_range.location = i;
+ result_range.length = 1;
+ previous_char = c;
+ }
+ else {
+ if (result_range.location + result_range.length == i
+ && (!squeeze_mode || previous_char == c)) {
+ result_range.length++;
+ }
+ else {
+ (*cb)(&search_range, (const CFRange *)&result_range,
+ str, previous_char, ctx);
+ result_range.location = i;
+ result_range.length = 1;
+ previous_char = c;
+ if (search_range.location + search_range.length < n) {
+ result_range.location -= n
+ - (search_range.location + search_range.length);
+ mutated = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (!mutated) {
+ if (result_range.length != 0) {
+ (*cb)(&search_range, (const CFRange *)&result_range, str,
+ previous_char, ctx);
+ result_range.length = 0;
+ previous_char = 0;
+ }
+ }
+ }
+ while (search_range.length != 0 && result_range.length != 0);
+#endif
+
+ CFRelease(charset);
+}
+
+struct tr_trans_cb_ctx {
+ VALUE orepl;
+ const char *src;
+ long src_len;
+ const char *repl;
+ long repl_len;
+ int sflag;
+ bool changed;
+ CFStringRef opt;
+};
+
+static inline void
+trans_replace(CFMutableStringRef str, const CFRange *result_range,
+ CFStringRef substr, CFRange *search_range, int sflag)
+{
+ assert(result_range->location + result_range->length
+ <= CFStringGetLength((CFStringRef)str));
+ if (sflag == 0) {
+ long n;
+ for (n = result_range->location;
+ n < result_range->location + result_range->length;
+ n++)
+ CFStringReplace(str, CFRangeMake(n, 1), substr);
+ }
+ else {
+ CFStringReplace(str, *result_range, substr);
+ search_range->location = result_range->location + 1;
+ search_range->length = RSTRING_CLEN(str) - search_range->location;
+ }
+}
+
+static void
+rb_str_trans_cb(CFRange *search_range, const CFRange *result_range,
+ CFStringRef str, UniChar character, void *ctx)
+{
+ struct tr_trans_cb_ctx *_ctx;
+
+ _ctx = (struct tr_trans_cb_ctx *)ctx;
+ if (_ctx->repl_len == 0) {
+ CFStringDelete((CFMutableStringRef)str, *result_range);
+ search_range->length -= result_range->length
+ + (result_range->location - search_range->location);
+ search_range->location = result_range->location;
+ }
+ else if (_ctx->repl_len == 1) {
+ trans_replace((CFMutableStringRef)str, result_range,
+ (CFStringRef)_ctx->orepl, search_range, _ctx->sflag);
+ }
+ else if (_ctx->repl_len > 1) {
+ if (_ctx->src_len == 1) {
+ if (_ctx->opt == NULL) {
+ _ctx->opt = CFStringCreateWithBytes(NULL,
+ (const UInt8 *)_ctx->repl, 1, kCFStringEncodingUTF8,
+ false);
+ }
+ trans_replace((CFMutableStringRef)str, result_range,
+ (CFStringRef)_ctx->opt, search_range, _ctx->sflag);
+ }
+ else {
+ /* TODO: support all syntaxes */
+ char sb, se, rb, re;
+ long n;
+ bool s_is_range, r_is_range;
+ CFStringRef substr;
+ bool release_substr;
+ long delta;
+
+ if (_ctx->src_len == 3 && _ctx->src[1] == '-') {
+ sb = _ctx->src[0];
+ se = _ctx->src[2];
+ s_is_range = true;
+ }
+ else {
+ s_is_range = false;
+ if (_ctx->src[0] == '^' || strchr(_ctx->src, '-') != NULL)
+ rb_raise(rb_eRuntimeError, "src argument value (%s) not " \
+ "supported yet", _ctx->src);
+ }
+
+ if (_ctx->repl_len == 3 && _ctx->repl[1] == '-') {
+ rb = _ctx->repl[0];
+ re = _ctx->repl[2];
+ r_is_range = true;
+ }
+ else {
+ r_is_range = false;
+ if (_ctx->repl[0] == '^' || strchr(_ctx->repl, '-') != NULL)
+ rb_raise(rb_eRuntimeError, "repl argument value (%s) not " \
+ "supported yet", _ctx->repl);
+ }
+
+ if (s_is_range) {
+ assert(sb <= character && se >= character);
+ delta = character - sb;
+ }
+ else {
+ char *p;
+ p = strchr(_ctx->src, character);
+ assert(p != NULL);
+ delta = (long)p - (long)_ctx->src;
+ }
+
+ if ((r_is_range && delta > (re - rb))
+ || (!r_is_range && delta > _ctx->repl_len)) {
+ if (_ctx->opt == NULL) {
+ _ctx->opt = CFStringCreateWithBytes(NULL,
+ (const UInt8 *)&_ctx->repl[_ctx->repl_len - 1],
+ 1,
+ kCFStringEncodingUTF8,
+ false);
+ }
+ substr = _ctx->opt;
+ release_substr = false;
+ }
+ else {
+ const char r = r_is_range
+ ? rb + delta : _ctx->repl[delta];
+ substr = CFStringCreateWithBytes(NULL, (const UInt8 *)&r, 1,
+ kCFStringEncodingUTF8, false);
+ release_substr = true;
+ }
+
+ trans_replace((CFMutableStringRef)str, result_range,
+ (CFStringRef)substr, search_range, _ctx->sflag);
+
+ if (release_substr)
+ CFRelease(substr);
+ }
+ }
+ _ctx->changed = true;
+}
+#endif
+
static VALUE
tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
{
+#if WITH_OBJC
+ struct tr_trans_cb_ctx _ctx;
+
+ StringValue(src);
+ StringValue(repl);
+
+ if (RSTRING_CLEN(str) == 0)
+ return Qnil;
+
+ rb_str_modify(str);
+
+ _ctx.orepl = repl;
+ _ctx.src = RSTRING_CPTR(src);
+ _ctx.repl = RSTRING_CPTR(repl);
+
+ /* TODO: support non-8-bit src/repl */
+ assert(_ctx.src != NULL && _ctx.repl != NULL);
+
+ _ctx.src_len = strlen(_ctx.src);
+ _ctx.repl_len = strlen(_ctx.repl);
+ _ctx.sflag = sflag;
+ _ctx.changed = false;
+ _ctx.opt = NULL;
+
+ str_charset_find((CFStringRef)str, &src, 1, _ctx.repl_len > 1,
+ rb_str_trans_cb, &_ctx);
+
+ if (_ctx.opt != NULL)
+ CFRelease(_ctx.opt);
+
+ return _ctx.changed ? str : Qnil;
+#else
SIGNED_VALUE trans[256];
rb_encoding *enc, *e1, *e2;
struct tr trsrc, trrepl;
@@ -4325,7 +5637,7 @@
t += tlen;
}
*t = '\0';
- RSTRING(str)->as.heap.ptr = buf;
+ GC_WB(&RSTRING(str)->as.heap.ptr, buf);
RSTRING(str)->as.heap.len = t - buf;
STR_SET_NOEMBED(str);
RSTRING(str)->as.heap.aux.capa = max;
@@ -4389,20 +5701,22 @@
xfree(RSTRING(str)->as.heap.ptr);
}
*t = '\0';
- RSTRING(str)->as.heap.ptr = buf;
+ GC_WB(&RSTRING(str)->as.heap.ptr, buf);
RSTRING(str)->as.heap.len = t - buf;
STR_SET_NOEMBED(str);
RSTRING(str)->as.heap.aux.capa = max;
}
if (modify) {
+#if !WITH_OBJC
rb_enc_associate(str, enc);
+#endif
return str;
}
return Qnil;
+#endif
}
-
/*
* call-seq:
* str.tr!(from_str, to_str) => str or nil
@@ -4440,10 +5754,11 @@
rb_str_tr(VALUE str, VALUE src, VALUE repl)
{
str = rb_str_dup(str);
- tr_trans(str, src, repl, 0);
+ rb_str_tr_bang(str, src, repl);
return str;
}
+#if !WITH_OBJC
static void
tr_setup_table(VALUE str, char stable[256], int first,
VALUE *tablep, VALUE *ctablep, rb_encoding *enc)
@@ -4517,6 +5832,10 @@
}
}
+#else
+
+#endif
+
/*
* call-seq:
* str.delete!([other_str]+) => str or nil
@@ -4525,9 +5844,34 @@
* <code>nil</code> if <i>str</i> was not modified.
*/
+#if WITH_OBJC
+static void
+rb_str_delete_bang_cb(CFRange *search_range, const CFRange *result_range,
+ CFStringRef str, UniChar character, void *ctx)
+{
+ CFStringDelete((CFMutableStringRef)str, *result_range);
+ search_range->length -= result_range->length
+ + (result_range->location - search_range->location);
+ search_range->location = result_range->location;
+ *(bool *)ctx = true;
+}
+#endif
+
static VALUE
rb_str_delete_bang(int argc, VALUE *argv, VALUE str)
{
+#if WITH_OBJC
+ bool changed;
+ if (argc < 1)
+ rb_raise(rb_eArgError, "wrong number of arguments");
+ rb_str_modify(str);
+ changed = false;
+ str_charset_find((CFStringRef)str, argv, argc, false,
+ rb_str_delete_bang_cb, &changed);
+ if (!changed)
+ return Qnil;
+ return str;
+#else
char squeez[256];
rb_encoding *enc = 0;
char *s, *send, *t;
@@ -4570,9 +5914,9 @@
ENC_CODERANGE_SET(str, cr);
if (modify) return str;
return Qnil;
+#endif
}
-
/*
* call-seq:
* str.delete([other_str]+) => new_str
@@ -4604,9 +5948,42 @@
* <code>nil</code> if no changes were made.
*/
+#if WITH_OBJC
+static void
+rb_str_squeeze_bang_cb(CFRange *search_range, const CFRange *result_range,
+ CFStringRef str, UniChar character, void *ctx)
+{
+ if (result_range->length > 1) {
+ CFRange to_delete = *result_range;
+ to_delete.length--;
+ CFStringDelete((CFMutableStringRef)str, to_delete);
+ search_range->length -= result_range->length
+ + (result_range->location - search_range->location);
+ search_range->location = result_range->location + 1;
+ *(bool *)ctx = true;
+ }
+}
+#endif
+
static VALUE
rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str)
{
+#if WITH_OBJC
+ bool changed;
+ VALUE all_chars;
+ if (argc == 0) {
+ argc = 1;
+ all_chars = (VALUE)CFSTR("a-z");
+ argv = &all_chars;
+ }
+ rb_str_modify(str);
+ changed = false;
+ str_charset_find((CFStringRef)str, argv, argc, true,
+ rb_str_squeeze_bang_cb, &changed);
+ if (!changed)
+ return Qnil;
+ return str;
+#else
char squeez[256];
rb_encoding *enc = 0;
VALUE del = 0, nodel = 0;
@@ -4651,6 +6028,7 @@
if (modify) return str;
return Qnil;
+#endif
}
@@ -4710,7 +6088,7 @@
rb_str_tr_s(VALUE str, VALUE src, VALUE repl)
{
str = rb_str_dup(str);
- tr_trans(str, src, repl, 1);
+ rb_str_tr_s_bang(str, src, repl);
return str;
}
@@ -4731,9 +6109,27 @@
* a.count "ej-m" #=> 4
*/
+#if WITH_OBJC
+static void
+rb_str_count_cb(CFRange *search_range, const CFRange *result_range,
+ CFStringRef str, UniChar character, void *ctx)
+{
+ (*(int *)ctx) += result_range->length;
+}
+#endif
+
static VALUE
rb_str_count(int argc, VALUE *argv, VALUE str)
{
+#if WITH_OBJC
+ int count;
+ if (argc < 1)
+ rb_raise(rb_eArgError, "wrong number of arguments");
+ count = 0;
+ str_charset_find((CFStringRef)str, argv, argc, false,
+ rb_str_count_cb, &count);
+ return INT2NUM(count);
+#else
char table[256];
rb_encoding *enc = 0;
VALUE del = 0, nodel = 0;
@@ -4765,6 +6161,7 @@
s += clen;
}
return INT2NUM(i);
+#endif
}
@@ -4817,15 +6214,23 @@
VALUE spat;
VALUE limit;
int awk_split = Qfalse;
+ int spat_string = Qfalse;
long beg, end, i = 0;
int lim = 0;
VALUE result, tmp;
+ const char *cstr;
+ long clen;
+#if !WITH_OBJC
+ cstr = RSTRING_CPTR(str);
+#endif
+ clen = RSTRING_CLEN(str);
+
if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
lim = NUM2INT(limit);
if (lim <= 0) limit = Qnil;
else if (lim == 1) {
- if (RSTRING_LEN(str) == 0)
+ if (clen == 0)
return rb_ary_new2(0);
return rb_ary_new3(1, str);
}
@@ -4833,6 +6238,7 @@
}
enc = STR_ENC_GET(str);
+ result = rb_ary_new();
if (NIL_P(spat)) {
if (!NIL_P(rb_fs)) {
spat = rb_fs;
@@ -4843,35 +6249,101 @@
else {
fs_set:
if (TYPE(spat) == T_STRING) {
+#if WITH_OBJC
+ spat_string = Qtrue;
+ if (RSTRING_CLEN(spat) == 1
+ && CFStringGetCharacterAtIndex((CFStringRef)spat, 0) == ' ') {
+ awk_split = Qtrue;
+ }
+#else
+ const char *spat_cstr;
+ long spat_clen;
rb_encoding *enc2 = STR_ENC_GET(spat);
+ spat_cstr = RSTRING_CPTR(spat);
+ spat_clen = RSTRING_CLEN(spat);
if (rb_enc_mbminlen(enc2) == 1) {
- if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' '){
- awk_split = Qtrue;
+ if (spat_clen == 1 && spat_cstr[0] == ' '){
+ awk_split = Qtrue;
+ }
}
- }
else {
int l;
- if (rb_enc_ascget(RSTRING_PTR(spat), RSTRING_END(spat), &l, enc2) == ' ' &&
- RSTRING_LEN(spat) == l) {
+ if (rb_enc_ascget(spat_cstr, spat_cstr+spat_clen, &l, enc2) == ' ' &&
+ spat_clen == l) {
awk_split = Qtrue;
}
}
if (!awk_split) {
spat = rb_reg_regcomp(rb_reg_quote(spat));
}
+#endif
}
else {
spat = get_pat(spat, 1);
}
}
- result = rb_ary_new();
beg = 0;
+#if WITH_OBJC
+ if (awk_split || spat_string) {
+ CFRange search_range;
+ CFCharacterSetRef charset;
+ if (spat == Qnil)
+ charset = CFCharacterSetGetPredefined(
+ kCFCharacterSetWhitespaceAndNewline);
+ search_range = CFRangeMake(0, clen);
+ do {
+ CFRange result_range;
+ CFRange substr_range;
+ if (spat != Qnil) {
+ if (!CFStringFindWithOptions((CFStringRef)str,
+ (CFStringRef)spat,
+ search_range,
+ 0,
+ &result_range))
+ break;
+ }
+ else {
+ if (!CFStringFindCharacterFromSet((CFStringRef)str,
+ charset,
+ search_range,
+ 0,
+ &result_range))
+ break;
+ }
+
+ substr_range.location = search_range.location;
+ substr_range.length = result_range.location
+ - search_range.location;
+
+ if (awk_split == Qfalse || substr_range.length > 0) {
+ VALUE substr;
+
+ substr = rb_str_subseq(str, substr_range.location,
+ substr_range.length);
+
+ if (awk_split == Qtrue) {
+ CFStringTrimWhitespace((CFMutableStringRef)substr);
+ if (CFStringGetLength((CFStringRef)substr) > 0)
+ rb_ary_push(result, substr);
+ }
+ else {
+ rb_ary_push(result, substr);
+ }
+ }
+
+ search_range.location = result_range.location
+ + result_range.length;
+ search_range.length = clen - search_range.location;
+ }
+ while ((limit == Qnil || --lim > 1));
+ beg = search_range.location;
+#else
if (awk_split) {
- char *ptr = RSTRING_PTR(str);
- char *eptr = RSTRING_END(str);
- char *bptr = ptr;
+ const char *ptr = cstr;
+ const char *eptr = cstr+clen;
+ const char *bptr = ptr;
int skip = 1;
int c;
@@ -4901,6 +6373,7 @@
}
}
}
+#endif
}
else {
long start = beg;
@@ -4911,22 +6384,34 @@
while ((end = rb_reg_search(spat, str, start, 0)) >= 0) {
regs = RMATCH_REGS(rb_backref_get());
if (start == end && BEG(0) == END(0)) {
- if (!RSTRING_PTR(str)) {
+#if WITH_OBJC
+ if (0) {
+#else
+ if (!cstr) {
rb_ary_push(result, rb_str_new("", 0));
+#endif
break;
}
else if (last_null == 1) {
+#if WITH_OBJC
+ rb_ary_push(result, rb_str_subseq(str, beg, 1));
+#else
rb_ary_push(result, rb_str_subseq(str, beg,
- rb_enc_mbclen(RSTRING_PTR(str)+beg,
- RSTRING_END(str),
+ rb_enc_mbclen(cstr+beg,
+ cstr+clen,
enc)));
+#endif
beg = start;
}
else {
- if (RSTRING_PTR(str)+start == RSTRING_END(str))
+ if (start == clen)
start++;
else
- start += rb_enc_mbclen(RSTRING_PTR(str)+start,RSTRING_END(str),enc);
+#if WITH_OBJC
+ start += 1;
+#else
+ start += rb_enc_mbclen(cstr+start,cstr+clen,enc);
+#endif
last_null = 1;
continue;
}
@@ -4948,16 +6433,18 @@
if (!NIL_P(limit) && lim <= ++i) break;
}
}
- if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) {
- if (RSTRING_LEN(str) == beg)
+ if (clen > 0 && (!NIL_P(limit) || clen > beg || lim < 0)) {
+ if (clen == beg) {
tmp = rb_str_new5(str, 0, 0);
- else
- tmp = rb_str_subseq(str, beg, RSTRING_LEN(str)-beg);
+ }
+ else {
+ tmp = rb_str_subseq(str, beg, clen-beg);
+ }
rb_ary_push(result, tmp);
}
if (NIL_P(limit) && lim == 0) {
while (RARRAY_LEN(result) > 0 &&
- RSTRING_LEN(RARRAY_PTR(result)[RARRAY_LEN(result)-1]) == 0)
+ RSTRING_CLEN(RARRAY_AT(result, RARRAY_LEN(result)-1)) == 0)
rb_ary_pop(result);
}
@@ -4974,6 +6461,13 @@
return rb_str_split_m(1, &sep, str);
}
+VALUE
+rb_str_split2(VALUE str, VALUE sep)
+{
+ StringValue(str);
+ StringValue(sep);
+ return rb_str_split_m(1, &sep, str);
+}
/*
* Document-method: lines
@@ -4995,9 +6489,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}
@@ -5024,6 +6517,73 @@
static VALUE
rb_str_each_line(int argc, VALUE *argv, VALUE str)
{
+#if WITH_OBJC
+ VALUE rs;
+ CFArrayRef ranges;
+ long n;
+ CFStringRef substr;
+ CFRange sub_range, search_range, res_range;
+ bool zero_sep;
+
+ if (rb_scan_args(argc, argv, "01", &rs) == 0) {
+ rs = rb_rs;
+ }
+ RETURN_ENUMERATOR(str, argc, argv);
+ if (NIL_P(rs)) {
+ rb_yield(str);
+ return str;
+ }
+ StringValue(rs);
+ zero_sep = CFStringGetLength((CFStringRef)rs) == 0;
+ if (zero_sep) {
+ rs = rb_default_rs;
+ }
+ n = CFStringGetLength((CFStringRef)str);
+ search_range = CFRangeMake(0, n);
+ sub_range = CFRangeMake(0, 0);
+
+#define YIELD_SUBSTR(range) \
+ do { \
+ VALUE mcopy; \
+ substr = CFStringCreateWithSubstring(NULL, (CFStringRef)str, \
+ range); \
+ mcopy = (VALUE)CFStringCreateMutableCopy(NULL, 0, \
+ (CFStringRef)substr); \
+ CFMakeCollectable((CFTypeRef)mcopy); \
+ rb_yield(mcopy); \
+ CFRelease(substr); \
+ } \
+ while (0)
+
+ while (CFStringFindWithOptions((CFStringRef)str, (CFStringRef)rs,
+ search_range, 0, &res_range)) {
+ if (zero_sep
+ && sub_range.length > 0
+ && sub_range.location + sub_range.length
+ == res_range.location) {
+ sub_range.length += res_range.length;
+ }
+ else {
+ if (sub_range.length > 0)
+ YIELD_SUBSTR(sub_range);
+ sub_range = CFRangeMake(search_range.location,
+ res_range.location - search_range.location + res_range.length);
+ }
+ search_range.location = res_range.location + res_range.length;
+ search_range.length = n - search_range.location;
+ }
+
+ if (sub_range.length != 0)
+ YIELD_SUBSTR(sub_range);
+
+ if (search_range.location < n)
+ YIELD_SUBSTR(CFRangeMake(search_range.location,
+ n - search_range.location));
+
+#undef YIELD_SUBSTR
+
+ return str;
+#else
rb_encoding *enc;
VALUE rs;
int newline;
@@ -5032,9 +6592,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);
@@ -5108,6 +6671,7 @@
}
return str;
+#endif
}
@@ -5140,11 +6704,15 @@
static VALUE
rb_str_each_byte(VALUE str)
{
- long i;
+ long n, i;
+ char *ptr;
RETURN_ENUMERATOR(str, 0, 0);
- for (i=0; i<RSTRING_LEN(str); i++) {
- rb_yield(INT2FIX(RSTRING_PTR(str)[i] & 0xff));
+
+ n = RSTRING_LEN(str);
+ ptr = RSTRING_PTR(str);
+ for (i=0; i<n; i++) {
+ rb_yield(INT2FIX(ptr[i] & 0xff));
}
return str;
}
@@ -5179,6 +6747,24 @@
static VALUE
rb_str_each_char(VALUE str)
{
+#if WITH_OBJC
+ CFStringInlineBuffer buf;
+ long i, n;
+
+ RETURN_ENUMERATOR(str, 0, 0);
+ n = CFStringGetLength((CFStringRef)str);
+ CFStringInitInlineBuffer((CFStringRef)str, &buf, CFRangeMake(0, n));
+ for (i = 0; i < n; i++) {
+ UniChar c;
+ VALUE s;
+
+ c = CFStringGetCharacterFromInlineBuffer(&buf, i);
+ s = rb_str_new(NULL, 0);
+ CFStringAppendCharacters((CFMutableStringRef)s, &c, 1);
+ rb_yield(s);
+ }
+ return str;
+#else
int i, len, n;
const char *ptr;
rb_encoding *enc;
@@ -5193,8 +6779,10 @@
rb_yield(rb_str_subseq(str, i, n));
}
return str;
+#endif
}
+#if !WITH_OBJC
static long
chopped_length(VALUE str)
{
@@ -5212,6 +6800,7 @@
}
return p - beg;
}
+#endif
/*
* call-seq:
@@ -5225,6 +6814,27 @@
static VALUE
rb_str_chop_bang(VALUE str)
{
+#if WITH_OBJC
+ long n;
+ const char *p;
+ CFRange r;
+
+ n = CFStringGetLength((CFStringRef)str);
+ if (n == 0)
+ return Qnil;
+ rb_str_modify(str);
+ p = RSTRING_CPTR(str);
+ r = CFRangeMake(n - 1, 1);
+ if (n >= 2 && p[n - 1] == '\n' && p[n - 2] == '\r') {
+ /* We need this to pass the tests, but this is most probably
+ * unnecessary.
+ */
+ r.location--;
+ r.length++;
+ }
+ CFStringDelete((CFMutableStringRef)str, r);
+ return str;
+#else
if (RSTRING_LEN(str) > 0) {
long len;
rb_str_modify(str);
@@ -5234,6 +6844,7 @@
return str;
}
return Qnil;
+#endif
}
@@ -5257,10 +6868,16 @@
static VALUE
rb_str_chop(VALUE str)
{
+#if WITH_OBJC
+ VALUE str2 = rb_str_dup(str);
+ rb_str_chop_bang(str2);
+ return str2;
+#else
VALUE str2 = rb_str_new5(str, RSTRING_PTR(str), chopped_length(str));
rb_enc_cr_str_copy_for_substr(str2, str);
OBJ_INFECT(str2, str);
return str2;
+#endif
}
@@ -5275,6 +6892,51 @@
static VALUE
rb_str_chomp_bang(int argc, VALUE *argv, VALUE str)
{
+#if WITH_OBJC
+ VALUE rs;
+ long len, rslen;
+ CFRange range_result;
+
+ if (rb_scan_args(argc, argv, "01", &rs) == 0)
+ rs = rb_rs;
+ rb_str_modify(str);
+ if (rs == Qnil)
+ return Qnil;
+ len = CFStringGetLength((CFStringRef)str);
+ if (len == 0)
+ return Qnil;
+ rslen = CFStringGetLength((CFStringRef)rs);
+ range_result = CFRangeMake(len, 0);
+ if (rs == rb_default_rs
+ || rslen == 0
+ || (rslen == 1
+ && CFStringGetCharacterAtIndex((CFStringRef)rs, 0) == '\n')) {
+ UniChar c;
+ c = CFStringGetCharacterAtIndex((CFStringRef)str,
+ range_result.location - 1);
+ if (c == '\n') {
+ range_result.location--;
+ range_result.length++;
+ c = CFStringGetCharacterAtIndex((CFStringRef)str,
+ range_result.location - 1);
+ }
+ if (c == '\r' && (rslen > 0 || range_result.location != len)) {
+ /* MS is the devil */
+ range_result.location--;
+ range_result.length++;
+ }
+ }
+ else {
+ StringValue(rs);
+ CFStringFindWithOptions((CFStringRef)str, (CFStringRef)rs,
+ CFRangeMake(len - rslen, rslen), 0, &range_result);
+ }
+ if (range_result.length == 0
+ || range_result.location + range_result.length > len)
+ return Qnil;
+ CFStringDelete((CFMutableStringRef)str, range_result);
+ return str;
+#else
rb_encoding *enc;
VALUE rs;
int newline;
@@ -5366,6 +7028,7 @@
return str;
}
return Qnil;
+#endif
}
@@ -5408,9 +7071,58 @@
* "hello".lstrip! #=> nil
*/
+#if WITH_OBJC
static VALUE
+rb_str_strip_bang2(VALUE str, int direction)
+{
+ long i, n, orig_n;
+ CFStringInlineBuffer buf;
+ CFCharacterSetRef charset;
+ bool changed;
+
+ rb_str_modify(str);
+ n = orig_n = CFStringGetLength((CFStringRef)str);
+ if (n == 0)
+ return Qnil;
+ CFStringInitInlineBuffer((CFStringRef)str, &buf, CFRangeMake(0, n));
+ charset = CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline);
+ changed = false;
+
+ if (direction >= 0) {
+ for (i = n - 1; i >= 0; i--) {
+ UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, i);
+ if (!CFCharacterSetIsCharacterMember(charset, c))
+ break;
+ }
+ if (i < n - 1) {
+ CFRange range = CFRangeMake(i + 1, n - i - 1);
+ CFStringDelete((CFMutableStringRef)str, range);
+ n -= range.length;
+ }
+ }
+
+ if (direction <= 0) {
+ for (i = 0; i < n; i++) {
+ UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, i);
+ if (!CFCharacterSetIsCharacterMember(charset, c))
+ break;
+ }
+ if (i > 0) {
+ CFRange range = CFRangeMake(0, i);
+ CFStringDelete((CFMutableStringRef)str, range);
+ }
+ }
+
+ return orig_n != n ? str : Qnil;
+}
+#endif
+
+static VALUE
rb_str_lstrip_bang(VALUE str)
{
+#if WITH_OBJC
+ return rb_str_strip_bang2(str, -1);
+#else
rb_encoding *enc;
char *s, *t, *e;
@@ -5435,6 +7147,7 @@
return str;
}
return Qnil;
+#endif
}
@@ -5473,6 +7186,9 @@
static VALUE
rb_str_rstrip_bang(VALUE str)
{
+#if WITH_OBJC
+ return rb_str_strip_bang2(str, 1);
+#else
rb_encoding *enc;
char *s, *t, *e;
int space_seen = Qfalse;
@@ -5502,6 +7218,7 @@
return str;
}
return Qnil;
+#endif
}
@@ -5536,11 +7253,15 @@
static VALUE
rb_str_strip_bang(VALUE str)
{
+#if WITH_OBJC
+ return rb_str_strip_bang2(str, 0);
+#else
VALUE l = rb_str_lstrip_bang(str);
VALUE r = rb_str_rstrip_bang(str);
if (NIL_P(l) && NIL_P(r)) return Qnil;
return str;
+#endif
}
@@ -5563,14 +7284,41 @@
}
static VALUE
-scan_once(VALUE str, VALUE pat, long *start)
+scan_once(VALUE str, VALUE pat, long *start, long strlen, bool pat_is_string)
{
rb_encoding *enc;
VALUE result, match;
struct re_registers *regs;
long i;
+#if WITH_OBJC
+ if (pat_is_string) {
+ /* XXX this is sometimes slower than the regexp search, especially for
+ * long pattern strings
+ */
+ CFRange result_range;
+ if (CFStringFindWithOptions((CFStringRef)str,
+ (CFStringRef)pat,
+ CFRangeMake(*start, strlen - *start),
+ 0,
+ &result_range)) {
+ CFStringRef str = CFStringCreateWithSubstring(NULL,
+ (CFStringRef)str, result_range);
+ *start = result_range.location + result_range.length + 1;
+ result = (VALUE)CFStringCreateMutableCopy(NULL, 0, str);
+ CFRelease(str);
+ CFMakeCollectable((CFTypeRef)result);
+ }
+ else {
+ result = Qnil;
+ }
+ return result;
+ }
+#endif
+
+#if !WITH_OBJC
enc = STR_ENC_GET(str);
+#endif
if (rb_reg_search(pat, str, *start, 0) >= 0) {
match = rb_backref_get();
regs = RMATCH_REGS(match);
@@ -5578,10 +7326,12 @@
/*
* Always consume at least one character of the input string
*/
+#if !WITH_OBJC
if (RSTRING_LEN(str) > END(0))
*start = END(0)+rb_enc_mbclen(RSTRING_PTR(str)+END(0),
RSTRING_END(str), enc);
else
+#endif
*start = END(0)+1;
}
else {
@@ -5638,13 +7388,16 @@
VALUE result;
long start = 0;
VALUE match = Qnil;
- char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);
-
- pat = get_pat(pat, 1);
+ long len = CFStringGetLength((CFStringRef)str);
+ bool pat_is_string = TYPE(pat) == T_STRING;
+
+ if (!pat_is_string)
+ pat = get_pat(pat, 1);
if (!rb_block_given_p()) {
VALUE ary = rb_ary_new();
- while (!NIL_P(result = scan_once(str, pat, &start))) {
+ while (!NIL_P(result = scan_once(str, pat, &start, len,
+ pat_is_string))) {
match = rb_backref_get();
rb_ary_push(ary, result);
}
@@ -5652,11 +7405,13 @@
return ary;
}
- while (!NIL_P(result = scan_once(str, pat, &start))) {
+ while (!NIL_P(result = scan_once(str, pat, &start, len, pat_is_string))) {
match = rb_backref_get();
rb_match_busy(match);
rb_yield(result);
+#if !WITH_OBJC
str_mod_check(str, p, len);
+#endif
rb_backref_set(match); /* restore $~ value */
}
rb_backref_set(match);
@@ -5737,8 +7492,9 @@
if (RSTRING_LEN(salt) < 2)
rb_raise(rb_eArgError, "salt too short (need >=2 bytes)");
- if (RSTRING_PTR(str)) s = RSTRING_PTR(str);
- else s = "";
+ s = RSTRING_PTR(str);
+ if (s == NULL)
+ s = "";
result = rb_str_new2(crypt(s, RSTRING_PTR(salt)));
OBJ_INFECT(result, str);
OBJ_INFECT(result, salt);
@@ -5769,7 +7525,11 @@
VALUE
rb_str_intern(VALUE s)
{
+#if WITH_OBJC
+ VALUE str = s;
+#else
VALUE str = RB_GC_GUARD(s);
+#endif
ID id;
if (OBJ_TAINTED(str) && rb_safe_level() >= 1) {
@@ -5779,7 +7539,6 @@
return ID2SYM(id);
}
-
/*
* call-seq:
* str.ord => integer
@@ -5792,11 +7551,18 @@
VALUE
rb_str_ord(VALUE s)
{
+#if WITH_OBJC
+ if (CFStringGetLength((CFStringRef)s) == 0)
+ rb_raise(rb_eArgError, "empty string");
+ return INT2NUM(CFStringGetCharacterAtIndex((CFStringRef)s, 0));
+#else
int c;
c = rb_enc_codepoint(RSTRING_PTR(s), RSTRING_END(s), STR_ENC_GET(s));
return INT2NUM(c);
+#endif
}
+
/*
* call-seq:
* str.sum(n=16) => integer
@@ -5816,11 +7582,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;
@@ -5856,9 +7624,66 @@
}
}
+#if WITH_OBJC
+static inline void
+rb_str_justify0(VALUE str, VALUE pad, long width, long padwidth, long index)
+{
+ do {
+ if (padwidth > width) {
+ pad = (VALUE)CFStringCreateWithSubstring(
+ NULL,
+ (CFStringRef)pad,
+ CFRangeMake(0, width));
+ CFMakeCollectable((CFTypeRef)pad);
+ }
+ CFStringInsert((CFMutableStringRef)str, index, (CFStringRef)pad);
+ width -= padwidth;
+ }
+ while (width > 0);
+}
+#endif
+
static VALUE
rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag)
{
+#if WITH_OBJC
+ VALUE w, pad;
+ long n, width, padwidth;
+
+ rb_scan_args(argc, argv, "11", &w, &pad);
+ width = NUM2LONG(w);
+ n = CFStringGetLength((CFStringRef)str);
+
+ str = rb_str_dup(str);
+ if (width < 0 || width <= n)
+ return str;
+ width -= n;
+
+ if (NIL_P(pad)) {
+ pad = rb_str_new(" ", 1);
+ padwidth = 1;
+ }
+ else {
+ StringValue(pad);
+ padwidth = CFStringGetLength((CFStringRef)pad);
+ }
+
+ if (jflag == 'c') {
+ rb_str_justify0(str, pad, ceil(width / 2.0), padwidth, n);
+ rb_str_justify0(str, pad, floor(width / 2.0), padwidth, 0);
+ }
+ else if (jflag == 'l') {
+ rb_str_justify0(str, pad, width, padwidth, n);
+ }
+ else if (jflag == 'r') {
+ rb_str_justify0(str, pad, width, padwidth, 0);
+ }
+ else {
+ rb_bug("invalid jflag");
+ }
+
+ return str;
+#else
rb_encoding *enc;
VALUE w;
long width, len, flen = 1, fclen = 1;
@@ -5933,6 +7758,7 @@
if (!NIL_P(pad)) OBJ_INFECT(res, pad);
rb_enc_associate(res, enc);
return res;
+#endif
}
@@ -6012,6 +7838,7 @@
{
long pos;
int regex = Qfalse;
+ long strlen, seplen;
if (TYPE(sep) == T_REGEXP) {
pos = rb_reg_search(sep, str, 0, 0);
@@ -6026,6 +7853,7 @@
rb_obj_classname(sep));
}
pos = rb_str_index(str, sep, 0);
+ seplen = CFStringGetLength((CFStringRef)sep);
}
if (pos < 0) {
failed:
@@ -6033,12 +7861,14 @@
}
if (regex) {
sep = rb_str_subpat(str, sep, 0);
- if (pos == 0 && RSTRING_LEN(sep) == 0) goto failed;
+ seplen = CFStringGetLength((CFStringRef)sep);
+ if (pos == 0 && seplen == 0) goto failed;
}
+ strlen = CFStringGetLength((CFStringRef)str);
return rb_ary_new3(3, rb_str_subseq(str, 0, pos),
sep,
- rb_str_subseq(str, pos+RSTRING_LEN(sep),
- RSTRING_LEN(str)-pos-RSTRING_LEN(sep)));
+ rb_str_subseq(str, pos+seplen,
+ strlen-pos-seplen));
}
/*
@@ -6059,6 +7889,7 @@
{
long pos = RSTRING_LEN(str);
int regex = Qfalse;
+ long seplen;
if (TYPE(sep) == T_REGEXP) {
pos = rb_reg_search(sep, str, pos, 1);
@@ -6080,10 +7911,13 @@
}
if (regex) {
sep = rb_reg_nth_match(0, rb_backref_get());
+ if (sep == Qnil)
+ return rb_ary_new3(3, rb_str_new(0,0),rb_str_new(0,0), str);
}
+ seplen = RSTRING_CLEN(sep);
return rb_ary_new3(3, rb_str_substr(str, 0, pos),
sep,
- rb_str_substr(str,pos+str_strlen(sep,STR_ENC_GET(sep)),RSTRING_LEN(str)));
+ rb_str_substr(str, pos + seplen, seplen));
}
/*
@@ -6101,10 +7935,15 @@
for (i=0; i<argc; i++) {
VALUE tmp = rb_check_string_type(argv[i]);
if (NIL_P(tmp)) continue;
+#if WITH_OBJC
+ if (CFStringHasPrefix((CFStringRef)str, (CFStringRef)tmp))
+ return Qtrue;
+#else
rb_enc_check(str, tmp);
if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue;
if (memcmp(RSTRING_PTR(str), RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0)
return Qtrue;
+#endif
}
return Qfalse;
}
@@ -6126,6 +7965,10 @@
for (i=0; i<argc; i++) {
VALUE tmp = rb_check_string_type(argv[i]);
if (NIL_P(tmp)) continue;
+#if WITH_OBJC
+ if (CFStringHasSuffix((CFStringRef)str, (CFStringRef)tmp))
+ return Qtrue;
+#else
enc = rb_enc_check(str, tmp);
if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue;
p = RSTRING_PTR(str);
@@ -6134,6 +7977,7 @@
continue;
if (memcmp(s, RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0)
return Qtrue;
+#endif
}
return Qfalse;
}
@@ -6159,7 +8003,28 @@
rb_str_force_encoding(VALUE str, VALUE enc)
{
str_modifiable(str);
+#if WITH_OBJC
+# if 0
+ CFDataRef data = rb_str_cfdata2(str);
+ if (data != NULL) {
+ CFStringRef substr;
+ CFStringEncoding *cfenc;
+
+ cfenc = rb_to_encoding(enc);
+ assert(cfenc != NULL);
+
+ substr = CFStringCreateFromExternalRepresentation(NULL, data, *cfenc);
+
+ if (substr) {
+ CFStringReplaceAll((CFMutableStringRef)str, substr);
+ CFRelease(substr);
+ rb_str_cfdata_set(str, NULL);
+ }
+ }
+# endif
+#else
rb_enc_associate(str, rb_to_encoding(enc));
+#endif
return str;
}
@@ -6177,9 +8042,13 @@
static VALUE
rb_str_valid_encoding_p(VALUE str)
{
+#if WITH_OBJC
+ rb_notimplement();
+#else
int cr = rb_enc_str_coderange(str);
return cr == ENC_CODERANGE_BROKEN ? Qfalse : Qtrue;
+#endif
}
/*
@@ -6195,9 +8064,13 @@
static VALUE
rb_str_is_ascii_only_p(VALUE str)
{
+#if WITH_OBJC
+ rb_notimplement();
+#else
int cr = rb_enc_str_coderange(str);
return cr == ENC_CODERANGE_7BIT ? Qtrue : Qfalse;
+#endif
}
/**********************************************************************
@@ -6227,9 +8100,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
*
*/
@@ -6253,26 +8126,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.
@@ -6283,6 +8136,18 @@
static VALUE
sym_inspect(VALUE sym)
{
+#if WITH_OBJC
+ ID id = SYM2ID(sym);
+ VALUE str;
+
+ sym = rb_id2str(id);
+ if (!rb_enc_symname_p(RSTRING_CPTR(sym), NULL)) {
+ sym = rb_str_inspect(sym);
+ }
+ str = rb_str_new(":", 1);
+ rb_str_buf_append(str, sym);
+ return str;
+#else
VALUE str, klass = Qundef;
ID id = SYM2ID(sym);
rb_encoding *enc;
@@ -6293,7 +8158,7 @@
RSTRING_PTR(str)[0] = ':';
memcpy(RSTRING_PTR(str)+1, RSTRING_PTR(sym), RSTRING_LEN(sym));
if (RSTRING_LEN(sym) != strlen(RSTRING_PTR(sym)) ||
- !rb_enc_symname_p(RSTRING_PTR(sym), enc)) {
+ !rb_enc_symname_p(RSTRING_PTR(sym), enc)) {
str = rb_str_inspect(str);
strncpy(RSTRING_PTR(str), ":\"", 2);
}
@@ -6302,6 +8167,7 @@
rb_str_append(str, rb_inspect(klass));
}
return str;
+#endif
}
@@ -6478,6 +8344,129 @@
return id;
}
+#if WITH_OBJC
+#define NSCFSTRING() (RCLASS_OCID(rb_cCFString))
+
+#define PREPARE_RCV(x) \
+ Class old = *(Class *)x; \
+ *(Class *)x = NSCFSTRING();
+
+#define RESTORE_RCV(x) \
+ *(Class *)x = old;
+
+bool
+rb_objc_str_is_pure(VALUE str)
+{
+ return *(Class *)str == NSCFSTRING();
+}
+
+static CFIndex
+imp_rb_str_length(void *rcv, SEL sel)
+{
+ CFIndex length;
+ PREPARE_RCV(rcv);
+ length = CFStringGetLength((CFStringRef)rcv);
+ RESTORE_RCV(rcv);
+ return length;
+}
+
+static UniChar
+imp_rb_str_characterAtIndex(void *rcv, SEL sel, CFIndex idx)
+{
+ UniChar character;
+ PREPARE_RCV(rcv);
+ character = CFStringGetCharacterAtIndex((CFStringRef)rcv, idx);
+ RESTORE_RCV(rcv);
+ return character;
+}
+
+static void
+imp_rb_str_getCharactersRange(void *rcv, SEL sel, UniChar *buffer,
+ CFRange range)
+{
+ PREPARE_RCV(rcv);
+ CFStringGetCharacters((CFStringRef)rcv, range, buffer);
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_str_replaceCharactersInRangeWithString(void *rcv, SEL sel,
+ CFRange range, void *str)
+{
+ PREPARE_RCV(rcv);
+ CFStringReplace((CFMutableStringRef)rcv, range, (CFStringRef)str);
+ RESTORE_RCV(rcv);
+}
+
+static const UniChar *
+imp_rb_str_fastCharacterContents(void *rcv, SEL sel)
+{
+ const UniChar *ptr;
+ PREPARE_RCV(rcv);
+ ptr = CFStringGetCharactersPtr((CFStringRef)rcv);
+ RESTORE_RCV(rcv);
+ return ptr;
+}
+
+static const char *
+imp_rb_str_fastCStringContents(void *rcv, SEL sel, bool nullTerminaisonRequired)
+{
+ const char *cstr;
+ PREPARE_RCV(rcv);
+ cstr = CFStringGetCStringPtr((CFStringRef)rcv, 0);
+ /* XXX nullTerminaisonRequired should perhaps be honored */
+ RESTORE_RCV(rcv);
+ return cstr;
+}
+
+static CFStringEncoding
+imp_rb_str_fastestEncodingInCFStringEncoding(void *rcv, SEL sel)
+{
+ CFStringEncoding encoding;
+ PREPARE_RCV(rcv);
+ encoding = CFStringGetFastestEncoding((CFStringRef)rcv);
+ RESTORE_RCV(rcv);
+ return encoding;
+}
+
+static bool
+imp_rb_str_isEqual(void *rcv, SEL sel, void *other)
+{
+ bool flag;
+ PREPARE_RCV(rcv);
+ flag = CFEqual((CFTypeRef)rcv, (CFTypeRef)other);
+ RESTORE_RCV(rcv);
+ return flag;
+}
+
+void
+rb_objc_install_string_primitives(Class klass)
+{
+#define INSTALL_METHOD(selname, imp) \
+ do { \
+ SEL sel = sel_registerName(selname); \
+ Method method = class_getInstanceMethod(klass, sel); \
+ assert(method != NULL); \
+ assert(class_addMethod(klass, sel, (IMP)imp, \
+ method_getTypeEncoding(method))); \
+ } \
+ while(0)
+
+ INSTALL_METHOD("length", imp_rb_str_length);
+ INSTALL_METHOD("characterAtIndex:", imp_rb_str_characterAtIndex);
+ INSTALL_METHOD("getCharacters:range:", imp_rb_str_getCharactersRange);
+ INSTALL_METHOD("replaceCharactersInRange:withString:",
+ imp_rb_str_replaceCharactersInRangeWithString);
+ INSTALL_METHOD("_fastCharacterContents", imp_rb_str_fastCharacterContents);
+ INSTALL_METHOD("_fastCStringContents:", imp_rb_str_fastCStringContents);
+ INSTALL_METHOD("_fastestEncodingInCFStringEncoding",
+ imp_rb_str_fastestEncodingInCFStringEncoding);
+ INSTALL_METHOD("isEqual:", imp_rb_str_isEqual);
+
+#undef INSTALL_METHOD
+}
+#endif
+
/*
* A <code>String</code> object holds and manipulates an arbitrary sequence of
* bytes, typically representing characters. String objects may be created
@@ -6495,8 +8484,13 @@
Init_String(void)
{
#if WITH_OBJC
- rb_cString = rb_define_class("String",
- rb_objc_import_class((Class)objc_getClass("NSMutableString")));
+ rb_cCFString = rb_objc_import_class((Class)objc_getClass("NSCFString"));
+ rb_cString = rb_objc_import_class((Class)objc_getClass("NSString"));
+ rb_cStringRuby =
+ rb_objc_import_class((Class)objc_getClass("NSMutableString"));
+ FL_UNSET(rb_cStringRuby, RCLASS_OBJC_IMPORTED);
+ rb_const_set(rb_cObject, rb_intern("String"), rb_cStringRuby);
+ rb_define_method(rb_cString, "__bytestring__?", rb_str_bytestring_m, 0);
#else
rb_cString = rb_define_class("String", rb_cObject);
#endif
@@ -6508,7 +8502,11 @@
rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
rb_define_method(rb_cString, "==", rb_str_equal, 1);
rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
+#if 1
+/* FIXME remove me once we use the objc dispatch for everything
+/*#if !WITH_OBJC*/
rb_define_method(rb_cString, "hash", rb_str_hash_m, 0);
+#endif
rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);
rb_define_method(rb_cString, "+", rb_str_plus, 1);
rb_define_method(rb_cString, "*", rb_str_times, 1);
@@ -6516,7 +8514,12 @@
rb_define_method(rb_cString, "[]", rb_str_aref_m, -1);
rb_define_method(rb_cString, "[]=", rb_str_aset_m, -1);
rb_define_method(rb_cString, "insert", rb_str_insert, 2);
+#if !WITH_OBJC
+ /* This method cannot be defined because it exists in
+ * NSString already.
+ */
rb_define_method(rb_cString, "length", rb_str_length, 0);
+#endif
rb_define_method(rb_cString, "size", rb_str_length, 0);
rb_define_method(rb_cString, "bytesize", rb_str_bytesize, 0);
rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
@@ -6634,7 +8637,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/branches/testing/struct.c
===================================================================
--- MacRuby/branches/testing/struct.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/struct.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -59,6 +59,9 @@
static VALUE
rb_struct_s_members_m(VALUE klass)
{
+#if WITH_OBJC
+ return rb_ary_dup(rb_struct_s_members(klass));
+#else
VALUE members, ary;
VALUE *p, *pend;
@@ -71,6 +74,7 @@
}
return ary;
+#endif
}
/*
@@ -82,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
@@ -100,7 +104,7 @@
members = rb_struct_members(obj);
slot = ID2SYM(id);
for (i=0; i<RARRAY_LEN(members); i++) {
- if (RARRAY_PTR(members)[i] == slot) {
+ if (RARRAY_AT(members, i) == slot) {
return RSTRUCT_PTR(obj)[i];
}
}
@@ -127,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,
@@ -157,7 +161,7 @@
members = rb_struct_members(obj);
rb_struct_modify(obj);
for (i=0; i<RARRAY_LEN(members); i++) {
- slot = RARRAY_PTR(members)[i];
+ slot = RARRAY_AT(members, i);
if (rb_id_attrset(SYM2ID(slot)) == rb_frame_this_func()) {
return RSTRUCT_PTR(obj)[i] = val;
}
@@ -181,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);
@@ -201,7 +205,7 @@
rb_define_singleton_method(nstr, "[]", rb_class_new_instance, -1);
rb_define_singleton_method(nstr, "members", rb_struct_s_members_m, 0);
for (i=0; i< RARRAY_LEN(members); i++) {
- ID id = SYM2ID(RARRAY_PTR(members)[i]);
+ ID id = SYM2ID(RARRAY_AT(members, i));
if (rb_is_local_id(id) || rb_is_const_id(id)) {
if (i < N_REF_FUNC) {
rb_define_method_id(nstr, id, ref_func[i], 0);
@@ -308,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
@@ -324,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_PTR(rest)[i]);
- RARRAY_PTR(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_AT(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);
@@ -501,7 +505,7 @@
if (i > 0) {
rb_str_cat2(str, ", ");
}
- slot = RARRAY_PTR(members)[i];
+ slot = RARRAY_AT(members, i);
id = SYM2ID(slot);
if (rb_is_local_id(id) || rb_is_const_id(id)) {
rb_str_append(str, rb_id2str(id));
@@ -576,7 +580,7 @@
members = rb_struct_members(s);
len = RARRAY_LEN(members);
for (i=0; i<len; i++) {
- if (SYM2ID(RARRAY_PTR(members)[i]) == id) {
+ if (SYM2ID(RARRAY_AT(members, i)) == id) {
return RSTRUCT_PTR(s)[i];
}
}
@@ -637,7 +641,7 @@
RARRAY_LEN(members), RSTRUCT_LEN(s));
}
for (i=0; i<len; i++) {
- if (SYM2ID(RARRAY_PTR(members)[i]) == id) {
+ if (SYM2ID(RARRAY_AT(members, i)) == id) {
RSTRUCT_PTR(s)[i] = val;
return val;
}
Modified: MacRuby/branches/testing/template/insns.inc.tmpl
===================================================================
--- MacRuby/branches/testing/template/insns.inc.tmpl 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/template/insns.inc.tmpl 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/template/insns_info.inc.tmpl
===================================================================
--- MacRuby/branches/testing/template/insns_info.inc.tmpl 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/template/insns_info.inc.tmpl 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/template/opt_sc.inc.tmpl
===================================================================
--- MacRuby/branches/testing/template/opt_sc.inc.tmpl 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/template/opt_sc.inc.tmpl 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/template/optunifs.inc.tmpl
===================================================================
--- MacRuby/branches/testing/template/optunifs.inc.tmpl 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/template/optunifs.inc.tmpl 2008-05-28 20:03:03 UTC (rev 233)
@@ -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, ...};
*/
Copied: MacRuby/branches/testing/test/erb/hello.erb (from rev 232, MacRuby/trunk/test/erb/hello.erb)
===================================================================
--- MacRuby/branches/testing/test/erb/hello.erb (rev 0)
+++ MacRuby/branches/testing/test/erb/hello.erb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,4 @@
+= hello
+<% 3.times do |n| %>
+* <%= n %>
+<% end %>
Modified: MacRuby/branches/testing/test/erb/test_erb.rb
===================================================================
--- MacRuby/branches/testing/test/erb/test_erb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/erb/test_erb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/gdbm/test_gdbm.rb
===================================================================
--- MacRuby/branches/testing/test/gdbm/test_gdbm.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/gdbm/test_gdbm.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/io/nonblock/test_flush.rb
===================================================================
--- MacRuby/branches/testing/test/io/nonblock/test_flush.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/io/nonblock/test_flush.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/net/imap/test_imap.rb
===================================================================
--- MacRuby/branches/testing/test/net/imap/test_imap.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/net/imap/test_imap.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/openssl/test_ssl.rb
===================================================================
--- MacRuby/branches/testing/test/openssl/test_ssl.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/openssl/test_ssl.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/openssl/utils.rb
===================================================================
--- MacRuby/branches/testing/test/openssl/utils.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/openssl/utils.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rdoc/test_rdoc_c_parser.rb
===================================================================
--- MacRuby/branches/testing/test/rdoc/test_rdoc_c_parser.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rdoc/test_rdoc_c_parser.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rdoc/test_rdoc_markup_attribute_manager.rb
===================================================================
--- MacRuby/branches/testing/test/rdoc/test_rdoc_markup_attribute_manager.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rdoc/test_rdoc_markup_attribute_manager.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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>")
Copied: MacRuby/branches/testing/test/rdoc/test_rdoc_ri_default_display.rb (from rev 232, MacRuby/trunk/test/rdoc/test_rdoc_ri_default_display.rb)
===================================================================
--- MacRuby/branches/testing/test/rdoc/test_rdoc_ri_default_display.rb (rev 0)
+++ MacRuby/branches/testing/test/rdoc/test_rdoc_ri_default_display.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rdoc/test_rdoc_ri_formatter.rb
===================================================================
--- MacRuby/branches/testing/test/rdoc/test_rdoc_ri_formatter.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rdoc/test_rdoc_ri_formatter.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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')
Copied: MacRuby/branches/testing/test/ruby/allpairs.rb (from rev 232, MacRuby/trunk/test/ruby/allpairs.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/allpairs.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/allpairs.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/envutil.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/envutil.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/envutil.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/ruby/lbtest.rb (from rev 232, MacRuby/trunk/test/ruby/lbtest.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/lbtest.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/lbtest.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/marshaltestlib.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/marshaltestlib.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/marshaltestlib.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_array.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_array.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_array.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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,20 +186,16 @@
# From rubicon
- def setup
- @cls = Array
- end
-
def test_00_new
a = @cls.new()
- assert_instance_of(@cls, a)
+ assert_kind_of(@cls, a)
assert_equal(0, a.length)
assert_nil(a[0])
end
def test_01_square_brackets
a = @cls[ 5, 4, 3, 2, 1 ]
- assert_instance_of(@cls, a)
+ assert_kind_of(@cls, a)
assert_equal(5, a.length)
5.times { |i| assert_equal(5-i, a[i]) }
assert_nil(a[6])
@@ -461,7 +467,7 @@
def test_collect
a = @cls[ 1, 'cat', 1..1 ]
- assert_equal([ Fixnum, String, Range], a.collect {|e| e.class} )
+ assert_equal([ Fixnum, NSCFString, Range], a.collect {|e| e.class} )
assert_equal([ 99, 99, 99], a.collect { 99 } )
assert_equal([], @cls[].collect { 99 })
@@ -475,8 +481,8 @@
# also update map!
def test_collect!
a = @cls[ 1, 'cat', 1..1 ]
- assert_equal([ Fixnum, String, Range], a.collect! {|e| e.class} )
- assert_equal([ Fixnum, String, Range], a)
+ assert_equal([ Fixnum, NSCFString, Range], a.collect! {|e| e.class} )
+ assert_equal([ Fixnum, NSCFString, Range], a)
a = @cls[ 1, 'cat', 1..1 ]
assert_equal([ 99, 99, 99], a.collect! { 99 } )
@@ -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'))
@@ -787,8 +801,8 @@
# also update collect!
def test_map!
a = @cls[ 1, 'cat', 1..1 ]
- assert_equal(@cls[ Fixnum, String, Range], a.map! {|e| e.class} )
- assert_equal(@cls[ Fixnum, String, Range], a)
+ assert_equal(@cls[ Fixnum, NSCFString, Range], a.map! {|e| e.class} )
+ assert_equal(@cls[ Fixnum, NSCFString, Range], a)
a = @cls[ 1, 'cat', 1..1 ]
assert_equal(@cls[ 99, 99, 99], a.map! { 99 } )
@@ -1119,6 +1133,28 @@
assert_equal(@cls[], @cls[].sort!)
end
+ def test_sort_with_callcc
+ begin
+ respond_to?(:callcc) or require 'continuation'
+ rescue LoadError; return
+ end
+ 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 +1265,302 @@
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 })
+
+=begin
+ a = [0, 1]
+ e = a.rindex
+ assert_equal(1, e.next)
+ a.clear
+ assert_raise(StopIteration) { e.next }
+=end
+
+ 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(NSCFArray, 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_each2
+ a = [0, 1, 2, 3, 4, 5]
+ r = []
+ a.each do |x|
+ r << x
+ a.pop
+ a.pop
+ end
+ assert_equal([0, 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/branches/testing/test/ruby/test_assignment.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_assignment.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_assignment.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -490,7 +490,6 @@
end
end
-require 'require_relative'
require_relative 'sentence'
class TestAssignmentGen < Test::Unit::TestCase
Syntax = {
Modified: MacRuby/branches/testing/test/ruby/test_beginendblock.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_beginendblock.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_beginendblock.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,6 +1,5 @@
require 'test/unit'
require 'tempfile'
-require 'require_relative'
require_relative 'envutil'
class TestBeginEndBlock < Test::Unit::TestCase
Modified: MacRuby/branches/testing/test/ruby/test_bignum.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_bignum.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_bignum.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_class.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_class.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_class.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/ruby/test_comparable.rb (from rev 232, MacRuby/trunk/test/ruby/test_comparable.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_comparable.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_comparable.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/ruby/test_complex.rb (from rev 232, MacRuby/trunk/test/ruby/test_complex.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_complex.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_complex.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_continuation.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_continuation.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_continuation.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,6 +1,7 @@
require 'test/unit'
require 'continuation'
require 'fiber'
+require_relative 'envutil'
class TestContinuation < Test::Unit::TestCase
def test_create
Modified: MacRuby/branches/testing/test/ruby/test_enum.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_enum.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_enum.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_enumerator.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_enumerator.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_enumerator.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_env.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_env.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_env.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_eval.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_eval.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_eval.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_exception.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_exception.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_exception.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_file.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_file.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_file.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,6 +1,5 @@
require 'test/unit'
require 'tempfile'
-require 'require_relative'
require_relative 'ut_eof'
class TestFile < Test::Unit::TestCase
Modified: MacRuby/branches/testing/test/ruby/test_file_exhaustive.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_file_exhaustive.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_file_exhaustive.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_fixnum.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_fixnum.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_fixnum.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_float.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_float.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_float.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_hash.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_hash.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_hash.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,5 +1,4 @@
require 'test/unit'
-require 'continuation'
class TestHash < Test::Unit::TestCase
@@ -105,12 +104,12 @@
def test_s_new
h = @cls.new
- assert_instance_of(@cls, h)
+ assert_kind_of(@cls, h)
assert_nil(h.default)
assert_nil(h['spurious'])
h = @cls.new('default')
- assert_instance_of(@cls, h)
+ assert_kind_of(@cls, h)
assert_equal('default', h.default)
assert_equal('default', h['spurious'])
@@ -671,6 +670,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 +720,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 }
@@ -798,6 +800,10 @@
end
def test_callcc
+ begin
+ respond_to?(:callcc) or require 'continuation'
+ rescue LoadError; return
+ end
h = {1=>2}
c = nil
f = false
Modified: MacRuby/branches/testing/test/ruby/test_integer.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_integer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_integer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/ruby/test_integer_comb.rb (from rev 232, MacRuby/trunk/test/ruby/test_integer_comb.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_integer_comb.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_integer_comb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_io.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_io.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_io.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_io_m17n.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_io_m17n.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_io_m17n.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_iterator.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_iterator.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_iterator.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_literal.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_literal.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_literal.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_m17n.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_m17n.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_m17n.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_m17n_comb.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_m17n_comb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_m17n_comb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_marshal.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_marshal.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_marshal.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,5 +1,4 @@
require 'test/unit'
-require 'require_relative'
require_relative 'marshaltestlib'
class TestMarshal < Test::Unit::TestCase
Modified: MacRuby/branches/testing/test/ruby/test_math.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_math.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_math.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_method.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_method.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_method.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_module.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_module.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_module.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_numeric.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_numeric.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_numeric.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
Copied: MacRuby/branches/testing/test/ruby/test_objc.rb (from rev 232, MacRuby/trunk/test/ruby/test_objc.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_objc.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_objc.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,147 @@
+require 'test/unit'
+
+class TestObjC < Test::Unit::TestCase
+
+ def setup
+ framework 'Foundation'
+ end
+
+ def test_all_objects_inherit_from_nsobject
+ assert_kind_of(NSObject, true)
+ assert_kind_of(NSObject, false)
+ assert_kind_of(NSObject, 42)
+ assert_kind_of(NSObject, 42.42)
+ assert_kind_of(NSObject, 42_000_000_000_000)
+ assert_kind_of(NSObject, 'foo')
+ assert_kind_of(NSObject, [])
+ end
+
+ class ClassWithNamedArg
+ def doSomethingWith(x, andObject:y, andObject:z)
+ x + y + z
+ end
+ def doSomethingWith(x, andObject:y)
+ x + y
+ end
+ end
+
+ def test_named_argument
+ o = ClassWithNamedArg.new
+ a = o.doSomethingWith('x', andObject:'y', andObject:'z')
+ assert_equal('xyz', a)
+
+ a = o.performSelector('doSomethingWith:andObject:',
+ withObject:'x', withObject:'y')
+ assert_equal('xy', a)
+ end
+
+ def test_named_argument_metaclass
+ o = Object.new
+ def o.doSomethingWith(x, andObject:y, andObject:z)
+ (x + y + z) * 2
+ end
+ def o.doSomethingWith(x, andObject:y)
+ (x + y) * 2
+ end
+
+ a = o.doSomethingWith('x', andObject:'y', andObject:'z')
+ assert_equal('xyzxyz', a)
+
+ a = o.performSelector('doSomethingWith:andObject:',
+ withObject:'x', withObject:'y')
+ assert_equal('xyxy', a)
+ end
+
+ module DispatchModule
+ def foo(x)
+ x
+ end
+ def foo(x, with:y)
+ x + y
+ end
+ end
+ class DispatchClass
+ include DispatchModule
+ end
+ def test_objc_dispatch_on_module_function
+ o = DispatchClass.new
+ r = o.performSelector('foo:', withObject:'xxx')
+ assert_equal('xxx', r)
+ r = o.performSelector('foo:with:', withObject:'xxx', withObject:'yyy')
+ assert_equal('xxxyyy', r)
+ end
+
+ def test_pure_objc_ivar
+ o = NSObject.alloc.init
+ assert_kind_of(NSObject, o)
+ o.instance_variable_set(:@foo, 'foo')
+ GC.start
+ assert_equal('foo', o.instance_variable_get(:@foo))
+ end
+
+ def test_method_variadic
+ p = NSPredicate.predicateWithFormat('foo == 1')
+ assert_kind_of(NSPredicate, p)
+ assert_equal('foo == 1', p.predicateFormat)
+ p = NSPredicate.predicateWithFormat('foo == %@', 'bar')
+ assert_kind_of(NSPredicate, p)
+ assert_equal('foo == "bar"', p.predicateFormat)
+ p = NSPredicate.predicateWithFormat('%@ == %@', 'foo', 'bar')
+ assert_kind_of(NSPredicate, p)
+ assert_equal('"foo" == "bar"', p.predicateFormat)
+ end
+
+ def test_struct_create
+ p = NSPoint.new
+ assert_kind_of(NSPoint, p)
+ assert_equal(0.0, p.x)
+ assert_equal(0.0, p.y)
+
+ p = NSPoint.new(1, 2)
+ assert_equal(1.0, p.x)
+ assert_equal(2.0, p.y)
+
+ assert_raise(ArgumentError) { NSPoint.new(1) }
+ assert_raise(ArgumentError) { NSPoint.new(1, 2, 3) }
+ assert_raise(ArgumentError) { NSPoint.new('x', 'y') }
+
+ r = NSRect.new
+ assert_equal(NSPoint.new(0, 0), r.origin)
+ assert_equal(NSSize.new(0, 0), r.size)
+
+ r = NSRect.new(NSPoint.new(1, 2), NSSize.new(3, 4))
+ assert_equal(NSPoint.new(1, 2), r.origin)
+ assert_equal(NSSize.new(3, 4), r.size)
+
+ r.origin.x = 42
+ r.size.width = 42
+
+ assert_equal(NSRect.new(NSPoint.new(42, 2), NSSize.new(42, 4)), r)
+ end
+
+ def test_create_struct_with_array
+ s = NSStringFromSize([1, 2])
+ assert_equal(NSSize.new(1, 2), NSSizeFromString(s))
+
+ assert_raise(ArgumentError) { NSStringFromSize([]) }
+ assert_raise(ArgumentError) { NSStringFromSize([1]) }
+ assert_raise(ArgumentError) { NSStringFromSize([1, 2, 3]) }
+
+ s = NSStringFromRect([[1, 2], [3, 4]])
+ assert_equal(NSRect.new(NSPoint.new(1, 2), NSSize.new(3, 4)),
+ NSRectFromString(s))
+
+ a = [1, 2, 3, 4]
+ s = NSStringFromRect(a)
+ assert_equal(NSRect.new(NSPoint.new(1, 2), NSSize.new(3, 4)),
+ NSRectFromString(s))
+ assert_equal([1, 2, 3, 4], a)
+
+ assert_raise(ArgumentError) { NSStringFromRect([]) }
+ assert_raise(ArgumentError) { NSStringFromRect([1]) }
+ assert_raise(ArgumentError) { NSStringFromRect([1, 2]) }
+ assert_raise(ArgumentError) { NSStringFromRect([1, 2, 3, 4, 5]) }
+ end
+
+end
+
Copied: MacRuby/branches/testing/test/ruby/test_object.rb (from rev 232, MacRuby/trunk/test/ruby/test_object.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_object.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_object.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_objectspace.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_objectspace.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_objectspace.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_pack.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_pack.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_pack.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/ruby/test_parse.rb (from rev 232, MacRuby/trunk/test/ruby/test_parse.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_parse.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_parse.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_pipe.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_pipe.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_pipe.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,5 +1,4 @@
require 'test/unit'
-require 'require_relative'
require_relative 'ut_eof'
class TestPipe < Test::Unit::TestCase
Modified: MacRuby/branches/testing/test/ruby/test_process.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_process.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_process.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_rand.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_rand.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_rand.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_range.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_range.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_range.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/ruby/test_rational.rb (from rev 232, MacRuby/trunk/test/ruby/test_rational.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_rational.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_rational.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/ruby/test_rational2.rb (from rev 232, MacRuby/trunk/test/ruby/test_rational2.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_rational2.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_rational2.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_regexp.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_regexp.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_regexp.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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)
Copied: MacRuby/branches/testing/test/ruby/test_rubyoptions.rb (from rev 232, MacRuby/trunk/test/ruby/test_rubyoptions.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_rubyoptions.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_rubyoptions.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_settracefunc.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_settracefunc.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_settracefunc.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_sprintf.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_sprintf.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_sprintf.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_sprintf_comb.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_sprintf_comb.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_sprintf_comb.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_string.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_string.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_string.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -764,6 +861,17 @@
assert_nil(S("hello").rindex(?z))
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
def test_rjust
@@ -931,6 +1039,8 @@
assert_nil(a.slice!(S("plugh")))
assert_equal(S("FooBar"), a)
end
+
+ assert_raise(ArgumentError) { "foo".slice! }
end
def test_split
@@ -954,6 +1064,10 @@
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([], "".split(//, 1))
+ assert_equal(["\0"], "\0".split(//))
+ assert_equal(["*.c", "lib", "ext"], "\n\n\n\n\n\n*.c\n\n\n\nlib\n\n\n\n\next\n".split)
end
def test_squeeze
@@ -1044,6 +1158,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!
@@ -1209,7 +1337,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
@@ -1398,5 +1526,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(NSCFString, 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/branches/testing/test/ruby/test_stringchar.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_stringchar.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_stringchar.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -65,6 +65,13 @@
end
def test_char
+ assert_equal('', "")
+ assert_equal(0, ''.size)
+ assert_equal("\0", "\000")
+ assert_equal("\0", [0].pack('C'))
+ assert_equal(1, "\0".size)
+ assert_equal("./\055", './-')
+
# character constants(assumes ASCII)
assert_equal(?a, "a"[0])
assert_equal(?a, ?a)
Modified: MacRuby/branches/testing/test/ruby/test_struct.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_struct.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_struct.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_symbol.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_symbol.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_symbol.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_system.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_system.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_system.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,6 +1,5 @@
require 'test/unit'
require 'tmpdir'
-require 'require_relative'
require_relative 'envutil'
class TestSystem < Test::Unit::TestCase
Modified: MacRuby/branches/testing/test/ruby/test_thread.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_thread.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_thread.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_time.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_time.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_time.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_trace.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_trace.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_trace.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_transcode.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_transcode.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_transcode.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_utf16.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_utf16.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_utf16.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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")))
Copied: MacRuby/branches/testing/test/ruby/test_utf32.rb (from rev 232, MacRuby/trunk/test/ruby/test_utf32.rb)
===================================================================
--- MacRuby/branches/testing/test/ruby/test_utf32.rb (rev 0)
+++ MacRuby/branches/testing/test/ruby/test_utf32.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_variable.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_variable.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_variable.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/ruby/test_yield.rb
===================================================================
--- MacRuby/branches/testing/test/ruby/test_yield.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/ruby/test_yield.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -74,7 +74,6 @@
end
end
-require 'require_relative'
require_relative 'sentence'
class TestRubyYieldGen < Test::Unit::TestCase
Syntax = {
Copied: MacRuby/branches/testing/test/rubygems/gem_installer_test_case.rb (from rev 232, MacRuby/trunk/test/rubygems/gem_installer_test_case.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/gem_installer_test_case.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/gem_installer_test_case.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/rubygems/gem_package_tar_test_case.rb (from rev 232, MacRuby/trunk/test/rubygems/gem_package_tar_test_case.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/gem_package_tar_test_case.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/gem_package_tar_test_case.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/gemutilities.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/gemutilities.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/gemutilities.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/mockgemui.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/mockgemui.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/mockgemui.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/rubygems/private_key.pem (from rev 232, MacRuby/trunk/test/rubygems/private_key.pem)
===================================================================
--- MacRuby/branches/testing/test/rubygems/private_key.pem (rev 0)
+++ MacRuby/branches/testing/test/rubygems/private_key.pem 2008-05-28 20:03:03 UTC (rev 233)
@@ -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-----
Copied: MacRuby/branches/testing/test/rubygems/public_cert.pem (from rev 232, MacRuby/trunk/test/rubygems/public_cert.pem)
===================================================================
--- MacRuby/branches/testing/test/rubygems/public_cert.pem (rev 0)
+++ MacRuby/branches/testing/test/rubygems/public_cert.pem 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_command_manager.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_command_manager.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_command_manager.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_environment_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_environment_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_environment_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_fetch_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_fetch_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_fetch_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_install_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_install_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_install_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_query_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_query_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_query_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_server_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_server_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_server_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_sources_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_sources_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_sources_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_specification_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_specification_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_specification_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_commands_unpack_command.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_unpack_command.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_unpack_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/rubygems/test_gem_commands_update_command.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_commands_update_command.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_commands_update_command.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_commands_update_command.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_dependency_installer.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_dependency_installer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_dependency_installer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_ext_configure_builder.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_ext_configure_builder.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_ext_configure_builder.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_format.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_format.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_format.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_indexer.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_indexer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_indexer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_installer.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_installer.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_installer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/rubygems/test_gem_package_tar_header.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_package_tar_header.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_package_tar_header.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_package_tar_header.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/rubygems/test_gem_package_tar_input.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_package_tar_input.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_package_tar_input.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_package_tar_input.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/rubygems/test_gem_package_tar_output.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_package_tar_output.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_package_tar_output.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_package_tar_output.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_package_tar_reader.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader_entry.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_package_tar_reader_entry.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader_entry.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_package_tar_reader_entry.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
+
Copied: MacRuby/branches/testing/test/rubygems/test_gem_package_tar_writer.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_package_tar_writer.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_package_tar_writer.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_package_tar_writer.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_remote_fetcher.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_remote_fetcher.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_remote_fetcher.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_server.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_server.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_server.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_source_index.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_source_index.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_source_index.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_source_info_cache.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_source_info_cache.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_source_info_cache.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_gem_source_info_cache_entry.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_source_info_cache_entry.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_gem_source_info_cache_entry.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/rubygems/test_gem_uninstaller.rb (from rev 232, MacRuby/trunk/test/rubygems/test_gem_uninstaller.rb)
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_gem_uninstaller.rb (rev 0)
+++ MacRuby/branches/testing/test/rubygems/test_gem_uninstaller.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_open_uri.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_open_uri.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_open_uri.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/rubygems/test_package.rb
===================================================================
--- MacRuby/branches/testing/test/rubygems/test_package.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/rubygems/test_package.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/stringio/test_stringio.rb
===================================================================
--- MacRuby/branches/testing/test/stringio/test_stringio.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/stringio/test_stringio.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/strscan/test_stringscanner.rb
===================================================================
--- MacRuby/branches/testing/test/strscan/test_stringscanner.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/strscan/test_stringscanner.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/test_generator.rb
===================================================================
--- MacRuby/branches/testing/test/test_generator.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/test_generator.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -1,4 +0,0 @@
-require 'pathname'
-require Pathname.new(__FILE__).dirname.join('inlinetest.rb')
-target = __FILE__[/test_(.*\.rb)$/, 1]
-InlineTest.loadtest__END__part(target)
Copied: MacRuby/branches/testing/test/test_pstore.rb (from rev 232, MacRuby/trunk/test/test_pstore.rb)
===================================================================
--- MacRuby/branches/testing/test/test_pstore.rb (rev 0)
+++ MacRuby/branches/testing/test/test_pstore.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test/webrick/test_filehandler.rb
===================================================================
--- MacRuby/branches/testing/test/webrick/test_filehandler.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test/webrick/test_filehandler.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/xmlrpc/test_cookie.rb (from rev 232, MacRuby/trunk/test/xmlrpc/test_cookie.rb)
===================================================================
--- MacRuby/branches/testing/test/xmlrpc/test_cookie.rb (rev 0)
+++ MacRuby/branches/testing/test/xmlrpc/test_cookie.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
Copied: MacRuby/branches/testing/test/yaml/test_yamlstore.rb (from rev 232, MacRuby/trunk/test/yaml/test_yamlstore.rb)
===================================================================
--- MacRuby/branches/testing/test/yaml/test_yamlstore.rb (rev 0)
+++ MacRuby/branches/testing/test/yaml/test_yamlstore.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/test-macruby/test_boxed.rb
===================================================================
--- MacRuby/branches/testing/test-macruby/test_boxed.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/test-macruby/test_boxed.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -4,9 +4,78 @@
def setup
framework 'Foundation'
+ bundle = '/tmp/_test_bs.bundle'
+ if !File.exist?(bundle) or File.mtime(bundle) < File.mtime(__FILE__)
+ s = <<EOS
+#import <Foundation/Foundation.h>
+ at interface NSObject (MacRubyNSPointAdditions)
+- (float)x;
+- (float)y;
+ at end
+ at interface TestBoxed : NSObject
+ at end
+ at implementation TestBoxed
+- (void)testPoint:(NSPoint)point x:(float)x y:(float)y
+{
+ if (point.x != x)
+ [NSException raise:@"NSException"
+ format:@"point.x (%f) != x (%f)", point.x, x];
+
+ if (point.y != y)
+ [NSException raise:@"NSException"
+ format:@"point.y (%f) != y (%f)", point.y, y];
+}
+- (void)testPointAsObject:(id)point x:(float)x y:(float)y
+{
+ Class boxed;
+ boxed = NSClassFromString(@"Boxed");
+
+ if (![point isKindOfClass:boxed])
+ [NSException raise:@"NSException"
+ format:@"point (%@) isn't a boxed type", point];
+
+ if (![point isKindOfClass:[NSValue class]])
+ [NSException raise:@"NSException"
+ format:@"point (%@) isn't a value type", point];
+
+#if 0 // FIXME this cannot be tested yet
+ if ([point x] != x)
+ [NSException raise:@"NSException"
+ format:@"[point x] (%f) != x (%f)", [point x], x];
+
+ if ([point y] != y)
+ [NSException raise:@"NSException"
+ format:@"[point y] (%f) != y (%f)", [point y], y];
+#endif
+
+ if (strcmp([point objCType], @encode(NSPoint)) != 0)
+ [NSException raise:@"NSException"
+ format:@"[point objCType] (%s) != @encode(NSPoint) (%s)",
+ [point objCType], @encode(NSPoint)];
+
+ NSPoint p;
+ [point getValue:&p];
+ [self testPoint:p x:x y:y];
+}
+- (NSPoint)testReturnPointWithX:(float)x y:(float)y
+{
+ NSPoint p;
+ p.x = x;
+ p.y = y;
+ return p;
+}
+ at end
+EOS
+ File.open('/tmp/_test.m', 'w') { |io| io.write(s) }
+ system("gcc /tmp/_test.m -bundle -o #{bundle} -framework Foundation -fobjc-gc-only") or exit 1
+ end
+ require 'dl'; DL.dlopen(bundle)
end
def test_boxed_classes
+ assert_kind_of(Class, Boxed)
+ assert_equal(NSValue, Boxed.superclass)
+
# struct
assert(NSRect.ancestors.include?(Boxed))
assert('{_NSRect={_NSPoint=ff}{_NSSize=ff}}', NSRect.objc_type)
@@ -80,14 +149,32 @@
end
def test_struct_nsstring_marshalling
- r = NSRange.new(1.0, 4.0)
+ r = NSRange.new(1, 4)
assert_kind_of(NSString, NSStringFromRange(r))
- # FIXME not passing yet
- #assert_equal('{1.0, 4.0}', NSStringFromRange(r))
+ assert_equal('{1, 4}', NSStringFromRange(r))
assert_equal(r, NSRangeFromString(NSStringFromRange(r)))
rect = NSRect.new(NSPoint.new(42.0, 1042.0), NSSize.new(123, 456))
assert_equal(NSPoint.new(42.0, 1042.0),
NSPointFromString(NSStringFromPoint(rect.origin)))
end
+ def test_nspoint_in_objc
+ p = NSPoint.new(42.0, 99.0)
+ o = TestBoxed.new
+ o.testPoint(p, x:42.0, y:99.0)
+ o.testPointAsObject(p, x:42.0, y:99.0)
+ assert_equal(p, o.testReturnPointWithX(42.0, y:99.0))
+ end
+
+ class MethodReturningBoxed
+ def foo
+ NSPoint.new(1, 2)
+ end
+ end
+ def test_objc_call_pure_method_returning_boxed
+ o = MethodReturningBoxed.new
+ assert_equal(NSPoint.new(1, 2), o.send(:foo))
+ assert_equal(NSPoint.new(1, 2), o.performSelector(:foo))
+ end
+
end
Copied: MacRuby/branches/testing/test-macruby/test_hash.rb (from rev 232, MacRuby/trunk/test-macruby/test_hash.rb)
===================================================================
--- MacRuby/branches/testing/test-macruby/test_hash.rb (rev 0)
+++ MacRuby/branches/testing/test-macruby/test_hash.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -0,0 +1,89 @@
+require 'test/unit'
+
+class TestHash < Test::Unit::TestCase
+
+ def test_hash_class
+ assert(Hash.is_a?(Class))
+ assert(Hash.ancestors.include?(NSDictionary))
+ assert(Hash.ancestors.include?(NSMutableDictionary))
+ end
+
+ def test_hash_create
+ h = {}
+ assert_kind_of(Hash, h)
+ h = {'a' => 100}
+ assert_kind_of(Hash, h)
+ h = Hash.new
+ assert_kind_of(Hash, h)
+ h = Hash.alloc.init
+ assert_kind_of(Hash, h)
+ h = Hash['a', 100, 'b', 200]
+ assert_kind_of(Hash, h)
+ h = Hash['a' => 100, 'b' => 200]
+ assert_kind_of(Hash, h)
+ end
+
+ class MyHash < Hash; end
+ def test_hash_create_subclass
+ assert(MyHash.ancestors.include?(Hash))
+ h = MyHash.new
+ assert_kind_of(MyHash, h)
+ h = MyHash.alloc.init
+ assert_kind_of(MyHash, h)
+ h = MyHash['a', 100, 'b', 200]
+ assert_kind_of(MyHash, h)
+ h = MyHash['a' => 100, 'b' => 200]
+ assert_kind_of(MyHash, h)
+ end
+
+ def test_hash_cannot_modify_immutable
+ h = NSDictionary.new
+ assert_raise(RuntimeError) { h[1] = 1 }
+ assert_raise(RuntimeError) { h.clear }
+ h = NSDictionary.alloc.init
+ assert_raise(RuntimeError) { h[1] = 1 }
+ assert_raise(RuntimeError) { h.clear }
+ end
+
+ def test_hash_get_set
+ h = {}
+ h[1] = 2
+ assert_equal(2, h[1])
+ h['foo'] = 3
+ assert_equal(3, h['foo'])
+ assert_equal(3, h[String.new('foo')])
+ h[[1,2]] = 4
+ assert_equal(4, h[[1,2]])
+ assert_equal(4, h[Array.new([1,2])])
+ h[:sym] = 5
+ assert_equal(5, h[:sym])
+ assert_equal(5, h['sym'.intern])
+ end
+
+ def test_hash_count
+ h = {}
+ assert_equal(0, h.size)
+ assert_equal(0, h.count)
+ assert(h.empty?)
+ h[1] = 2
+ assert_equal(1, h.size)
+ assert_equal(1, h.count)
+ assert(!h.empty?)
+ h[1] = nil
+ assert_equal(1, h.size)
+ assert_equal(1, h.count)
+ assert(!h.empty?)
+ h.delete(1)
+ assert_equal(0, h.size)
+ assert_equal(0, h.count)
+ assert(h.empty?)
+ end
+
+ def test_hash_clear
+ h = {1=>2}
+ h.clear
+ assert(h.empty?)
+ assert_equal(nil, h[1])
+ end
+
+end
Modified: MacRuby/branches/testing/thread.c
===================================================================
--- MacRuby/branches/testing/thread.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/thread.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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);
@@ -440,8 +449,8 @@
if (!proc || !RTEST(loc = rb_proc_location(proc))) {
rb_raise(rb_eThreadError, "already initialized thread");
}
- file = RSTRING_PTR(RARRAY_PTR(loc)[0]);
- if (NIL_P(line = RARRAY_PTR(loc)[1])) {
+ file = RSTRING_CPTR(RARRAY_AT(loc, 0));
+ if (NIL_P(line = RARRAY_AT(loc, 1))) {
rb_raise(rb_eThreadError, "already initialized thread - %s",
file);
}
@@ -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/branches/testing/thread_pthread.c
===================================================================
--- MacRuby/branches/testing/thread_pthread.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/thread_pthread.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/thread_win32.c
===================================================================
--- MacRuby/branches/testing/thread_win32.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/thread_win32.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/time.c
===================================================================
--- MacRuby/branches/testing/time.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/time.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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);
@@ -418,14 +425,14 @@
if (!NIL_P(s)) {
tm->tm_mon = -1;
for (i=0; i<12; i++) {
- if (RSTRING_LEN(s) == 3 &&
- STRCASECMP(months[i], RSTRING_PTR(s)) == 0) {
+ if (RSTRING_CLEN(s) == 3 &&
+ STRCASECMP(months[i], RSTRING_CPTR(s)) == 0) {
tm->tm_mon = i;
break;
}
}
if (tm->tm_mon == -1) {
- char c = RSTRING_PTR(s)[0];
+ char c = RSTRING_CPTR(s)[0];
if ('0' <= c && c <= '9') {
tm->tm_mon = obj2long(s)-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';
@@ -2082,8 +2090,8 @@
rb_raise(rb_eArgError, "format should have ASCII compatible encoding");
}
format = rb_str_new4(format);
- fmt = RSTRING_PTR(format);
- len = RSTRING_LEN(format);
+ fmt = RSTRING_CPTR(format);
+ len = RSTRING_CLEN(format);
if (len == 0) {
rb_warning("strftime called with empty format string");
}
@@ -2097,7 +2105,7 @@
rb_str_cat(str, buf, len);
p += strlen(p);
if (buf != buffer) {
- free(buf);
+ xfree(buf);
buf = buffer;
}
for (fmt = p; p < pe && !*p; ++p);
@@ -2106,11 +2114,13 @@
return str;
}
else {
- len = rb_strftime(&buf, RSTRING_PTR(format), &tobj->tm);
+ len = rb_strftime(&buf, RSTRING_CPTR(format), &tobj->tm);
}
str = rb_str_new(buf, len);
- if (buf != buffer) free(buf);
+ if (buf != buffer) xfree(buf);
+#if !WITH_OBJC
rb_enc_copy(str, format);
+#endif
return str;
}
@@ -2226,7 +2236,7 @@
rb_copy_generic_ivar(time, str);
StringValue(str);
- buf = (unsigned char *)RSTRING_PTR(str);
+ buf = (unsigned char *)RSTRING_PTR(str); /* ok */
if (RSTRING_LEN(str) != 8) {
rb_raise(rb_eTypeError, "marshaled time format differ");
}
Modified: MacRuby/branches/testing/tool/compile_prelude.rb
===================================================================
--- MacRuby/branches/testing/tool/compile_prelude.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/tool/compile_prelude.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/tool/instruction.rb
===================================================================
--- MacRuby/branches/testing/tool/instruction.rb 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/tool/instruction.rb 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/transcode.c
===================================================================
--- MacRuby/branches/testing/transcode.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/transcode.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -10,6 +10,9 @@
**********************************************************************/
#include "ruby/ruby.h"
+
+#if !WITH_OBJC
+
#include "ruby/encoding.h"
#define PType (int)
#include "transcode_data.h"
@@ -85,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 *
@@ -177,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;
@@ -390,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.
*/
@@ -405,51 +404,71 @@
{
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);
+ str = rb_str_dup(str);
+ return rb_str_transcode_bang(argc, argv, str);
+}
- 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;
+#else // WITH_OBJC
+
+static VALUE
+rb_str_transcode(int argc, VALUE *argv, VALUE self)
+{
+ /* TODO */
+ return self;
}
+static VALUE
+rb_str_transcode_bang(int argc, VALUE *argv, VALUE self)
+{
+ /* TODO */
+ return self;
+}
+
+#endif
+
void
Init_transcode(void)
{
+#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"));
+#endif
rb_define_method(rb_cString, "encode", rb_str_transcode, -1);
rb_define_method(rb_cString, "encode!", rb_str_transcode_bang, -1);
Modified: MacRuby/branches/testing/util.c
===================================================================
--- MacRuby/branches/testing/util.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/util.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -279,18 +279,18 @@
long slen;
char buf[1024];
- if (RSTRING_LEN(str) > 1000)
+ if (RSTRING_CLEN(str) > 1000)
rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
- RSTRING_LEN(str));
+ RSTRING_CLEN(str));
#if defined(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32)
/* Style 0 */
- slen = RSTRING_LEN(str);
+ slen = RSTRING_CLEN(str);
rb_str_cat(str, suffix, extlen);
#if defined(DJGPP)
if (_USE_LFN) return;
#else
- if (valid_filename(RSTRING_PTR(str))) return;
+ if (valid_filename(RSTRING_CPTR(str))) return;
#endif
/* Fooey, style 0 failed. Fix str before continuing. */
@@ -298,7 +298,7 @@
#endif
slen = extlen;
- t = buf; baselen = 0; s = RSTRING_PTR(str);
+ t = buf; baselen = 0; s = RSTRING_CPTR(str);
while ((*t = *s) && *s != '.') {
baselen++;
if (*s == '\\' || *s == '/') baselen = 0;
@@ -335,8 +335,7 @@
fallback:
(void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
}
- rb_str_resize(str, strlen(buf));
- memcpy(RSTRING_PTR(str), buf, RSTRING_LEN(str));
+ rb_str_replace(str, rb_str_new(buf, strlen(buf)));
}
#if defined(__CYGWIN32__) || defined(_WIN32)
Modified: MacRuby/branches/testing/variable.c
===================================================================
--- MacRuby/branches/testing/variable.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/variable.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -161,9 +161,11 @@
st_insert(RCLASS_IV_TBL(klass), classpath, path);
st_delete(RCLASS_IV_TBL(klass), (st_data_t*)&classid, 0);
}
+#if !WITH_OBJC
if (TYPE(path) != T_STRING) {
rb_bug("class path is not set properly");
}
+#endif
return path;
}
return find_class_path(klass);
@@ -230,7 +232,7 @@
OBJ_FREEZE(str);
rb_ivar_set(klass, classpath, str);
#if WITH_OBJC
- rb_objc_rename_class(klass, RSTRING_PTR(str));
+ rb_objc_rename_class(klass, RSTRING_CPTR(str));
#endif
}
@@ -285,7 +287,7 @@
char *
rb_class2name(VALUE klass)
{
- return RSTRING_PTR(rb_class_name(klass));
+ return (char *)RSTRING_CPTR(rb_class_name(klass));
}
char *
@@ -467,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;
@@ -721,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
@@ -750,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);
}
@@ -777,23 +784,48 @@
entry1->var = entry2->var;
}
+#if WITH_OBJC
+static CFMutableDictionaryRef generic_iv_dict = NULL;
+const void * rb_cfdictionary_retain_cb(CFAllocatorRef, const void *);
+void rb_cfdictionary_release_cb(CFAllocatorRef, const void *);
+#else
static int special_generic_ivar = 0;
static st_table *generic_iv_tbl;
+#endif
st_table*
rb_generic_ivar_table(VALUE obj)
{
+#if WITH_OBJC
+ return NULL;
+#else
st_data_t tbl;
if (!FL_TEST(obj, FL_EXIVAR)) return 0;
if (!generic_iv_tbl) return 0;
if (!st_lookup(generic_iv_tbl, obj, &tbl)) return 0;
return (st_table *)tbl;
+#endif
}
static VALUE
generic_ivar_get(VALUE obj, ID id, int warn)
{
+#if WITH_OBJC
+ if (generic_iv_dict != NULL) {
+ CFDictionaryRef obj_dict;
+
+ if (CFDictionaryGetValueIfPresent(generic_iv_dict,
+ (const void *)obj, (const void **)&obj_dict)
+ && obj_dict != NULL) {
+ VALUE val;
+
+ if (CFDictionaryGetValueIfPresent(obj_dict, (const void *)id,
+ (const void **)&val))
+ return val;
+ }
+ }
+#else
st_data_t tbl;
VALUE val;
@@ -804,6 +836,7 @@
}
}
}
+#endif
if (warn) {
rb_warning("instance variable %s not initialized", rb_id2name(id));
}
@@ -813,6 +846,41 @@
static void
generic_ivar_set(VALUE obj, ID id, VALUE val)
{
+#if WITH_OBJC
+ CFMutableDictionaryRef obj_dict;
+
+ if (rb_special_const_p(obj)) {
+ if (rb_obj_frozen_p(obj))
+ rb_error_frozen("object");
+ }
+ if (generic_iv_dict == NULL) {
+ CFDictionaryValueCallBacks values_cb;
+
+ memset(&values_cb, 0, sizeof(values_cb));
+ values_cb.retain = rb_cfdictionary_retain_cb;
+ values_cb.release = rb_cfdictionary_release_cb;
+
+ generic_iv_dict = CFDictionaryCreateMutable(NULL, 0, NULL, &values_cb);
+ obj_dict = NULL;
+ }
+ else {
+ obj_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(
+ (CFDictionaryRef)generic_iv_dict, (const void *)obj);
+ }
+ if (obj_dict == NULL) {
+ CFDictionaryValueCallBacks values_cb;
+
+ memset(&values_cb, 0, sizeof(values_cb));
+ values_cb.retain = rb_cfdictionary_retain_cb;
+ values_cb.release = rb_cfdictionary_release_cb;
+
+ obj_dict = CFDictionaryCreateMutable(NULL, 0, NULL, &values_cb);
+ CFDictionarySetValue(generic_iv_dict, (const void *)obj,
+ (const void *)obj_dict);
+ CFMakeCollectable(obj_dict);
+ }
+ CFDictionarySetValue(obj_dict, (const void *)id, (const void *)val);
+#else
st_table *tbl;
st_data_t data;
@@ -832,11 +900,24 @@
return;
}
st_insert((st_table *)data, id, val);
+#endif
}
static VALUE
generic_ivar_defined(VALUE obj, ID id)
{
+#if WITH_OBJC
+ CFMutableDictionaryRef obj_dict;
+
+ if (generic_iv_dict != NULL
+ && CFDictionaryGetValueIfPresent((CFDictionaryRef)generic_iv_dict,
+ (const void *)obj, (const void **)&obj_dict) && obj_dict != NULL) {
+ if (CFDictionaryGetValueIfPresent(obj_dict, (const void *)id, NULL))
+ return Qtrue;
+ }
+ return Qfalse;
+
+#else
st_table *tbl;
st_data_t data;
VALUE val;
@@ -848,11 +929,33 @@
return Qtrue;
}
return Qfalse;
+#endif
}
static int
generic_ivar_remove(VALUE obj, ID id, VALUE *valp)
{
+#if WITH_OBJC
+ CFMutableDictionaryRef obj_dict;
+ VALUE val;
+
+ if (generic_iv_dict == NULL)
+ return 0;
+
+ obj_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(
+ (CFDictionaryRef)generic_iv_dict, (const void *)obj);
+ if (obj_dict == NULL)
+ return 0;
+
+ if (CFDictionaryGetValueIfPresent(obj_dict, (const void *)id,
+ (const void **)&val)) {
+ *valp = val;
+ CFDictionaryRemoveValue(obj_dict, (const void *)id);
+ return 1;
+ }
+
+ return 0;
+#else
st_table *tbl;
st_data_t data;
int status;
@@ -866,8 +969,10 @@
st_free_table((st_table *)data);
}
return status;
+#endif
}
+#if !WITH_OBJC
void
rb_mark_generic_ivar(VALUE obj)
{
@@ -902,20 +1007,49 @@
if (special_generic_ivar == 0) return;
st_foreach_safe(generic_iv_tbl, givar_i, 0);
}
+#endif
void
rb_free_generic_ivar(VALUE obj)
{
+#if WITH_OBJC
+ if (generic_iv_dict != NULL)
+ CFDictionaryRemoveValue(generic_iv_dict, (const void *)obj);
+#else
st_data_t tbl;
if (!generic_iv_tbl) return;
if (st_delete(generic_iv_tbl, &obj, &tbl))
st_free_table((st_table *)tbl);
+#endif
}
void
rb_copy_generic_ivar(VALUE clone, VALUE obj)
{
+#if WITH_OBJC
+ CFMutableDictionaryRef obj_dict;
+ CFMutableDictionaryRef clone_dict;
+ VALUE val;
+
+ if (generic_iv_dict == NULL)
+ return;
+
+ obj_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(
+ (CFDictionaryRef)generic_iv_dict, (const void *)obj);
+ if (obj_dict == NULL)
+ return;
+
+ if (CFDictionaryGetValueIfPresent((CFDictionaryRef)generic_iv_dict,
+ (const void *)clone, (const void **)&clone_dict)
+ && clone_dict != NULL)
+ CFDictionaryRemoveValue(generic_iv_dict, (const void *)clone);
+
+ clone_dict = CFDictionaryCreateMutableCopy(NULL, 0, obj_dict);
+ CFDictionarySetValue(generic_iv_dict, (const void *)clone,
+ (const void *)clone_dict);
+ CFMakeCollectable(clone_dict);
+#else
st_data_t data;
if (!generic_iv_tbl) return;
@@ -942,6 +1076,7 @@
FL_SET(clone, FL_EXIVAR);
}
}
+#endif
}
static VALUE
@@ -953,7 +1088,7 @@
st_data_t index;
#if WITH_OBJC
- if (rb_objc_is_non_native(obj))
+ if (!rb_special_const_p(obj) && rb_objc_is_non_native(obj))
return generic_ivar_get(obj, id, warn);
#endif
@@ -1005,16 +1140,16 @@
long i, len;
int ivar_extended;
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+ rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
+ if (OBJ_FROZEN(obj)) rb_error_frozen("object");
#if WITH_OBJC
- if (rb_objc_is_non_native(obj)) {
+ if (!rb_special_const_p(obj) && rb_objc_is_non_native(obj)) {
+ rb_objc_flag_set(obj, FL_EXIVAR, true);
generic_ivar_set(obj, id, val);
return val;
}
#endif
-
- if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
- rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
- if (OBJ_FROZEN(obj)) rb_error_frozen("object");
switch (TYPE(obj)) {
case T_OBJECT:
iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
@@ -1053,7 +1188,7 @@
newptr = ALLOC_N(VALUE, newsize);
MEMCPY(newptr, ptr, VALUE, len);
RBASIC(obj)->flags &= ~ROBJECT_EMBED;
- ROBJECT(obj)->as.heap.ivptr = newptr;
+ GC_WB(&ROBJECT(obj)->as.heap.ivptr, newptr);
}
else {
REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
@@ -1065,7 +1200,7 @@
ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
}
}
- ROBJECT_IVPTR(obj)[index] = val;
+ GC_WB(&ROBJECT_IVPTR(obj)[index], val);
break;
case T_CLASS:
case T_MODULE:
@@ -1076,6 +1211,7 @@
break;
default:
generic_ivar_set(obj, id, val);
+ FL_SET(obj, FL_EXIVAR);
break;
}
return val;
@@ -1087,6 +1223,11 @@
VALUE val;
struct st_table *iv_index_tbl;
st_data_t index;
+#if WITH_OBJC
+ if (!rb_special_const_p(obj) && rb_objc_is_non_native(obj)) {
+ return generic_ivar_defined(obj, id);
+ }
+#endif
switch (TYPE(obj)) {
case T_OBJECT:
iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
@@ -1147,27 +1288,44 @@
void rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
{
+#if WITH_OBJC
+ if (!rb_special_const_p(obj) && rb_objc_is_non_native(obj))
+ goto generic;
+#endif
switch (TYPE(obj)) {
case T_OBJECT:
obj_ivar_each(obj, func, arg);
- break;
+ return;
case T_CLASS:
case T_MODULE:
if (RCLASS_IV_TBL(obj)) {
st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
}
- break;
- default:
- if (!generic_iv_tbl) break;
- if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
- st_data_t tbl;
+ return;
+ }
+ if (!FL_TEST(obj, FL_EXIVAR) && !rb_special_const_p(obj))
+ return;
+generic:
+#if WITH_OBJC
+ if (generic_iv_dict != NULL) {
+ CFDictionaryRef obj_dict;
- if (st_lookup(generic_iv_tbl, obj, &tbl)) {
- st_foreach_safe((st_table *)tbl, func, arg);
- }
+ obj_dict = (CFDictionaryRef)CFDictionaryGetValue(
+ (CFDictionaryRef)generic_iv_dict, (const void *)obj);
+ if (obj_dict != NULL)
+ CFDictionaryApplyFunction(obj_dict,
+ (CFDictionaryApplierFunction)func, (void *)arg);
+ }
+#else
+ 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);
}
- break;
}
+#endif
}
static int
@@ -1193,7 +1351,7 @@
* @iv = 3
* end
* end
- * Fred.new.instance_variables #=> ["@iv"]
+ * Fred.new.instance_variables #=> [:@iv]
*/
VALUE
@@ -1339,7 +1497,7 @@
#endif
RDATA(av)->dfree != (RUBY_DATA_FUNC)st_free_table) {
VALUE desc = rb_inspect(av);
- rb_raise(rb_eTypeError, "wrong autoload table: %s", RSTRING_PTR(desc));
+ rb_raise(rb_eTypeError, "wrong autoload table: %s", RSTRING_CPTR(desc));
}
return (struct st_table *)DATA_PTR(av);
}
@@ -1411,7 +1569,7 @@
VALUE file;
NODE *load = autoload_delete(klass, id);
- if (!load || !(file = load->nd_lit) || rb_provided(RSTRING_PTR(file))) {
+ if (!load || !(file = load->nd_lit)) {
return Qfalse;
}
return rb_require_safe(file, load->nd_nth);
@@ -1430,10 +1588,10 @@
}
file = ((NODE *)load)->nd_lit;
Check_Type(file, T_STRING);
- if (!RSTRING_PTR(file)) {
+ if (RSTRING_CLEN(file) == 0) {
rb_raise(rb_eArgError, "empty file name");
}
- if (!rb_provided(RSTRING_PTR(file))) {
+ if (!rb_provided(RSTRING_CPTR(file))) {
return file;
}
@@ -1470,7 +1628,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;
@@ -1638,8 +1796,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>.
*/
@@ -1924,8 +2082,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/branches/testing/version.c
===================================================================
--- MacRuby/branches/testing/version.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/version.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/version.h
===================================================================
--- MacRuby/branches/testing/version.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/version.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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;
@@ -52,7 +52,7 @@
#endif
#if WITH_OBJC
-# define MACRUBY_VERSION 0.1
+# define MACRUBY_VERSION 0.2
# define RUBY_DESCRIPTION \
"MacRuby version " STRINGIZE(MACRUBY_VERSION) \
" (ruby "RUBY_VERSION \
Modified: MacRuby/branches/testing/vm.c
===================================================================
--- MacRuby/branches/testing/vm.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/vm.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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
@@ -732,9 +729,9 @@
rb_iseq_t *iseq = cfp->iseq;
line_no = vm_get_sourceline(cfp);
- file = RSTRING_PTR(iseq->filename);
+ file = (char *)RSTRING_CPTR(iseq->filename);
str = rb_sprintf("%s:%d:in `%s'",
- file, line_no, RSTRING_PTR(iseq->name));
+ 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;
@@ -1017,7 +1015,11 @@
OP(LTLT, LTLT), (C(String), C(Array));
OP(AREF, AREF), (C(Array), C(Hash));
OP(ASET, ASET), (C(Array), C(Hash));
+#if WITH_OBJC
+ OP(Length, LENGTH), (C(Array), C(Hash));
+#else
OP(Length, LENGTH), (C(Array), C(String), C(Hash));
+#endif
OP(Succ, SUCC), (C(Fixnum), C(String), C(Time));
OP(GT, GT), (C(Fixnum));
OP(GE, GE), (C(Fixnum));
@@ -1142,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);
@@ -1159,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;
@@ -1405,14 +1408,14 @@
if (cfp->pc != 0) {
rb_iseq_t *iseq = cfp->iseq;
int line_no = vm_get_sourceline(cfp);
- char *file = RSTRING_PTR(iseq->filename);
+ const char *file = RSTRING_CPTR(iseq->filename);
str = rb_sprintf("%s:%d:in `%s'",
- file, line_no, RSTRING_PTR(iseq->name));
+ file, line_no, RSTRING_CPTR(iseq->name));
}
}
else if (cfp->method_id) {
str = rb_sprintf("`%s#%s' (cfunc)",
- RSTRING_PTR(rb_class_name(cfp->method_class)),
+ RSTRING_CPTR(rb_class_name(cfp->method_class)),
rb_id2name(cfp->method_id));
}
@@ -1492,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);
@@ -1584,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++;
@@ -1642,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);
@@ -1655,7 +1659,6 @@
mark_event_hooks(th->event_hooks);
}
- RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
RUBY_MARK_LEAVE("thread");
}
#else
@@ -1857,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);
@@ -1876,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/branches/testing/vm_core.h
===================================================================
--- MacRuby/branches/testing/vm_core.h 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/vm_core.h 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/vm_dump.c
===================================================================
--- MacRuby/branches/testing/vm_dump.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/vm_dump.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -98,11 +98,11 @@
}
else {
pc = cfp->pc - cfp->iseq->iseq_encoded;
- iseq_name = RSTRING_PTR(cfp->iseq->name);
+ iseq_name = RSTRING_CPTR(cfp->iseq->name);
line = vm_get_sourceline(cfp);
if (line) {
char fn[MAX_POSBUF+1];
- snprintf(fn, MAX_POSBUF, "%s", RSTRING_PTR(cfp->iseq->filename));
+ snprintf(fn, MAX_POSBUF, "%s", RSTRING_CPTR(cfp->iseq->filename));
snprintf(posbuf, MAX_POSBUF, "%s:%d", fn, line);
}
}
@@ -257,7 +257,7 @@
else {
argc = iseq->argc;
local_size = iseq->local_size;
- name = RSTRING_PTR(iseq->name);
+ name = RSTRING_CPTR(iseq->name);
}
/* stack trace header */
@@ -575,7 +575,7 @@
bt = vm_backtrace(th, 0);
if (TYPE(bt) == T_ARRAY)
for (i = 0; i < RARRAY_LEN(bt); i++) {
- dp(RARRAY_PTR(bt)[i]);
+ dp(RARRAY_AT(bt, i));
}
}
Modified: MacRuby/branches/testing/vm_evalbody.c
===================================================================
--- MacRuby/branches/testing/vm_evalbody.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/vm_evalbody.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/vm_insnhelper.c
===================================================================
--- MacRuby/branches/testing/vm_insnhelper.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/vm_insnhelper.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -2,7 +2,7 @@
insnhelper.c - instruction helper functions.
- $Author: nobu $
+ $Author: matz $
Copyright (C) 2007 Koichi Sasada
@@ -240,7 +240,6 @@
/* expand top of stack? */
if (flag & VM_CALL_ARGS_SPLAT_BIT) {
VALUE ary = *(cfp->sp - 1);
- VALUE *ptr;
int i;
VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
@@ -249,13 +248,12 @@
}
else {
int len = RARRAY_LEN(tmp);
- ptr = RARRAY_PTR(tmp);
cfp->sp -= 1;
CHECK_STACK_OVERFLOW(cfp, len);
for (i = 0; i < len; i++) {
- *cfp->sp++ = ptr[i];
+ *cfp->sp++ = RARRAY_AT(tmp, i);
}
argc += i-1;
}
@@ -873,7 +871,7 @@
svar = (struct RValues *)th->local_svar;
if ((VALUE)svar == Qnil) {
svar = new_value();
- th->local_svar = (VALUE)svar;
+ GC_WB(&th->local_svar, (VALUE)svar);
}
}
return svar;
@@ -911,16 +909,13 @@
switch (key) {
case 0:
- svar->v1 = val;
- //GC_WB(&svar->v1, val);
+ GC_WB(&svar->v1, val);
return;
case 1:
- svar->v2 = val;
- //GC_WB(&svar->v2, val);
+ GC_WB(&svar->v2, val);
return;
case 2:
- svar->basic.klass = val;
- //GC_WB(&svar->basic.klass, val);
+ GC_WB(&svar->basic.klass, val);
return;
default: {
VALUE hash = svar->v3;
@@ -987,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)
@@ -1041,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_PTR(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);
}
}
}
@@ -1125,7 +1126,7 @@
if (/* *pmn == NULL
&&*/ *pnum == 2
&& TYPE(argv[1]) == T_ARRAY
- && FL_TEST(argv[1], RARRAY_NAMED_ARGS)) {
+ && rb_ary_is_named_args(argv[1])) {
unsigned i, count;
@@ -1138,30 +1139,26 @@
count = RARRAY_LEN(argv[1]);
for (i = 0; i < count; i += 2) {
- VALUE sym = RARRAY_PTR(argv[1])[i];
+ VALUE sym = RARRAY_AT(argv[1], i);
if (TYPE(sym) != T_SYMBOL)
rb_bug("expected symbol for first pair element");
strncat(buf, rb_id2name(SYM2ID(sym)), sizeof buf);
strncat(buf, ":", sizeof buf);
}
-//printf("buf is %s\n", buf);
-
id = rb_intern(buf);
if ((mn = rb_method_node(CLASS_OF(recv), id)) != NULL
|| (mn = rb_objc_define_objc_mid_closure(recv, id, NULL)) != NULL) {
-#if 1
unsigned j, newnum = 1 + (count / 2);
void **new_argv = alloca(sizeof(void *) * newnum);
new_argv[0] = (void *)argv[0];
for (i = 0, j = 1; i < count; i += 2, j++) {
- new_argv[j] = (void *)RARRAY_PTR(argv[1])[i + 1];
+ new_argv[j] = (void *)RARRAY_AT(argv[1], i + 1);
}
argv = cfp->sp - newnum;
cfp->bp -= newnum - *pnum;
memcpy(argv, new_argv, sizeof(void *) * newnum);
-#endif
*pmn = mn;
*pid = id;
*pnum = newnum;
@@ -1169,8 +1166,8 @@
else {
VALUE h = rb_hash_new();
for (i = 0; i < count; i += 2) {
- rb_hash_aset(h, RARRAY_PTR(argv[1])[i],
- RARRAY_PTR(argv[1])[i+1]);
+ rb_hash_aset(h, RARRAY_AT(argv[1], i),
+ RARRAY_AT(argv[1], i+1));
}
argv[1] = h;
}
@@ -1437,7 +1434,7 @@
{
int is_splat = flag & 0x01;
int space_size = num + is_splat;
- VALUE *base = cfp->sp, *ptr;
+ VALUE *base = cfp->sp;
volatile VALUE tmp_ary;
int len;
@@ -1448,7 +1445,6 @@
cfp->sp += space_size;
tmp_ary = ary;
- ptr = RARRAY_PTR(ary);
len = RARRAY_LEN(ary);
if (flag & 0x02) {
@@ -1461,11 +1457,18 @@
}
}
for (j=0; i<num; i++, j++) {
- VALUE v = ptr[len - j - 1];
+ VALUE v = RARRAY_AT(ary, len - j - 1);
*base++ = v;
}
if (is_splat) {
+#if WITH_OBJC
+ *base = rb_ary_new();
+ CFArrayAppendArray((CFMutableArrayRef)*base,
+ (CFArrayRef)ary,
+ CFRangeMake(0, len - j));
+#else
*base = rb_ary_new4(len - j, ptr);
+#endif
}
}
else {
@@ -1480,14 +1483,21 @@
}
break;
}
- *bptr-- = ptr[i];
+ *bptr-- = RARRAY_AT(ary, i);
}
if (is_splat) {
if (num > len) {
*bptr = rb_ary_new();
}
else {
+#if WITH_OBJC
+ *base = rb_ary_new();
+ CFArrayAppendArray((CFMutableArrayRef)*base,
+ (CFArrayRef)ary,
+ CFRangeMake(num, len - num));
+#else
*bptr = rb_ary_new4(len - num, ptr + num);
+#endif
}
}
}
Modified: MacRuby/branches/testing/win32/Makefile.sub
===================================================================
--- MacRuby/branches/testing/win32/Makefile.sub 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/win32/Makefile.sub 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/branches/testing/win32/win32.c
===================================================================
--- MacRuby/branches/testing/win32/win32.c 2008-05-28 19:32:29 UTC (rev 232)
+++ MacRuby/branches/testing/win32/win32.c 2008-05-28 20:03:03 UTC (rev 233)
@@ -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/20080528/fe3b1c7d/attachment-0001.htm
More information about the macruby-changes
mailing list