diff options
author | ser <ser@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-09-22 12:40:45 +0000 |
---|---|---|
committer | ser <ser@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-09-22 12:40:45 +0000 |
commit | 8b53e39a2e6110cf13827c88673a3ef2667991cf (patch) | |
tree | eb1fa37c2a675b75c295285b5c313ba05801c2b8 | |
parent | f36a3f0ea57aa05a72cb58937c7a737455a98a38 (diff) | |
download | ruby-rexml_adds_tests.tar.gz |
Second merge from trunk.rexml_adds_tests
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/rexml_adds_tests@19455 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
124 files changed, 5045 insertions, 2283 deletions
@@ -1,3 +1,787 @@ +Sun Sep 21 21:52:41 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * math.c (math_log): should check argc. + +Sun Sep 21 21:20:24 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c: added two macros. + + * rational.c: ditto. + +Sun Sep 21 18:06:38 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c (nucomp_s_convert): checks argc. + + * rational.c (nurat_s_convert): ditto. + +Sun Sep 21 10:19:04 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c (nucomp_s_canonicalize_internal): checks exactness of + imag only. + + * rational.c (nurat_s_convert): accepts non real value + (Rational(a,b) as a/b). + + * complex.c (nucomp_s_convert): refined. + +Sun Sep 21 09:37:57 2008 James Edward Gray II <jeg2@ruby-lang.org> + + * lib/csv/csv.rb: Reworked CSV's parser and generator to be m17n. Data + is now parsed in the Encoding it is in without need for translation. + * lib/csv/csv.rb: Improved inspect() messages for better IRb support. + * lib/csv/csv.rb: Fixed header writing bug reported by Dov Murik. + * lib/csv/csv.rb: Use custom separators in parsing header Strings as + suggested by Shmulik Regev. + * lib/csv/csv.rb: Added a :write_headers option for outputting headers. + * lib/csv/csv.rb: Handle open() calls in binary mode whenever we can to + workaround a Windows issue where line-ending translation can cause an + off-by-one error in seeking back to a non-zero starting position after + auto-discovery for :row_sep as suggested by Robert Battle. + * lib/csv/csv.rb: Improved the parser to fail faster when fed some forms + of invalid CSV that can be detected without reading ahead. + * lib/csv/csv.rb: Added a :field_size_limit option to control CSV's + lookahead and prevent the parser from biting off more data than + it can chew. + * lib/csv/csv.rb: Added readers for CSV attributes: col_sep(), row_sep(), + quote_char(), field_size_limit(), converters(), unconverted_fields?(), + headers(), return_headers?(), write_headers?(), header_converters(), + skip_blanks?(), and force_quotes?(). + * lib/csv/csv.rb: Cleaned up code syntax to be more inline with + Ruby 1.9 than 1.8. + +Sun Sep 21 07:43:16 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c: an instance method image has been removed and + uses "imag" instead of "image". + + * complex.c: two instance method re and im are removed. + + * rational.c: follows the above changes. + + * include/ruby/ruby.h: ditto. + + * gc.c: ditto. + + * lib/cmath.rb: ditto. + + * lib/mathn.rb: ditto. + + * lib/complex.rb: ditto. and provides some obsolate methods. + +Sun Sep 21 02:48:45 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * ext/json/ext/parser/parse.c: use ruby_xfree(). + + * ext/json/ext/parser/parse.rl: ditto. + + * ext/json/ext/parser/unicode.c: ditto. + +Sun Sep 21 02:40:20 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * ext/json: import JSON v 1.1.3. + +Sat Sep 20 11:43:08 2008 Yusuke Endoh <mame@tsg.ne.jp> + + * lib/optparse.rb (summarize): separator "" should output new line. + +Sat Sep 20 08:07:34 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * parse.y: strings which contain only US-ASCII don't force to have + US-ASCII encoding. [ruby-dev:36400] + +Sat Sep 20 07:59:31 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * re.c (rb_reg_desc): Regexps of ASCII Compatible encoding may + contain non-ASCII characters. So in that case its encoding + must keep original encoding. + +Sat Sep 20 07:44:56 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * common.mk: prec.c is removed. + +Fri Sep 19 22:37:25 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c: uses f_(in)?exact_p macro. + + * rational.c: ditto. + + * bignum.c (rb_big_pow): bignum**bignum - should calculate without + rational. + + * lib/complex.rb: should override Math module at most once. + + * lib/mathn.rb: requires 'cmath' directly. + +Fri Sep 19 20:48:06 2008 Yuki Sonoda <yugui@yugui.jp> + + * prec.c: removed. Precision will be redesigned and be back again. + c.f. [ruby-dev:36352]. + + * common.mk (COMMON_OBJS): removed prec.o. + + * inits.c (rb_call_inits): removed Init_Precision. + + * numeric.c (Init_Numeric): removed inclusion of Precision. + removed #induced_from from each class. + + * rational.c: ditto. + + * ext/bigdecimal/bigdecimal.c: ditto. + + * lib/rdoc/knwon_classes.rb: removed the entry for Precision. + + * test/ruby/test_prec.rb: removed. + + * test/ruby/test_integer.rb: removed tests for Precision. + + * test/ruby/test_fixnum.rb: ditto. + + * test/ruby/test_float.rb: ditto. + + * test/ruby/test_rational.rb: ditto. + + * test/ruby/test_complex.rb: ditto. + + * test/bigdecimal/test_bigdecimal.rb: ditto. + +Fri Sep 19 19:43:40 2008 Yuki Sonoda <yugui@yugui.jp> + + * common.mk : Reverts the changeset 18994. + Uses the official repository of rubyspec again. + +Fri Sep 19 17:41:56 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * configure.in: applied OS/2 support patch from Brendan Oakley + <gentux2@gmail.com> in [ruby-core:18707]. + +Fri Sep 19 09:29:26 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * dln.c: newer BeOS support. a patch from Pete Goodeve + <pete.goodeve at computer.org> in [ruby-core:18712]. + +Fri Sep 19 03:41:25 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * ext/nkf/nkf-utf8/nkf.c: fix memory violation. mentioned by mame [ruby-dev:36373] + +Fri Sep 19 01:07:36 2008 Tanaka Akira <akr@fsij.org> + + * regexec.c (string_cmp_ic): add text_end argument. + (slow_search): call enclen with real string end. + (map_search): add text_end argument. + +Thu Sep 18 22:54:39 2008 Yusuke Endoh <mame@tsg.ne.jp> + + * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_to_string): comment out + fragments of unused code. + +Thu Sep 18 22:35:03 2008 Yusuke Endoh <mame@tsg.ne.jp> + + * ext/bigdecimal/bigdecimal.c (VpCtoV): 1E1000...000 is interpreted as + Infinity. [ruby-dev:36159] + + * ext/bigdecimal/bigdecimal.c (VpPower): Infinity ** 1 returns + Infinity instead of NaN. [ruby-dev:36159] + + * test/bigdecimal/test_bigdecimal.rb: add tests for above. + +Thu Sep 18 21:57:32 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (rb_str_comparable): make ascii8bit string to be + compatible with any other encoding. + + * string.c (rb_str_cmp): use rb_str_comparable() instead of + rb_enc_compatible() since <=> is a comparison anyway. + +Thu Sep 18 21:37:14 2008 Tanaka Akira <akr@fsij.org> + + * grapheme cluster implementation reverted. [ruby-dev:36375] + +Thu Sep 18 20:50:36 2008 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * lib/rake.rb (Rake::Application#standard_exception_handling): + replaced magic numbers for exit status. + +Thu Sep 18 20:37:59 2008 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * lib/optparse.rb (OptionParser::ParseError#set_backtrace): omits + OptionParser internal backtraces unless debug flag is set. + +Thu Sep 18 20:02:48 2008 Yusuke Endoh <mame@tsg.ne.jp> + + * lib/uri/common.rb (unescape): skip '%' to make String#hex work + correctly. + +Thu Sep 18 19:51:11 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * bignum.c (big2str_karatsuba): free internal buffer eagerly. + a patch from TOYOFUKU Chikanobu <nobu_toyofuku at nifty.com> + in [ruby-dev:36217]. + + * bignum.c (rb_big2str0): ditto. + +Thu Sep 18 19:43:04 2008 Yusuke Endoh <mame@tsg.ne.jp> + + * st.c (new_size): raise RuntimeError when st_table is too big. + [ruby-dev:36354] + +Thu Sep 18 18:23:23 2008 Tanaka Akira <akr@fsij.org> + + * transcode.c (enc_arg): must take pointer argument to avoid GC + problem. StringValueCStr modifies the argument and it should be + preserved while the string StringValueCStr returns is used. + Since the string is used by caller, the modified argument should be + hold by caller. Actually + GC.stress = true + def (o=Object.new).to_str() + "universal"+"_newline" + end + "\u3042".encode(o, "") + causes curious warning: + rb_define_const: invalid name `' for constant + +Thu Sep 18 17:32:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * transcode.c: add "Error" suffix for Encoding exception classes. + a patch from Tadashi Saito <shiba at mail2.accsnet.ne.jp> in + [ruby-dev:36346]. + + * encoding.c (Init_Encoding): rename EncodingCompatibilityError to + Encoding::CompatibilityError. [ruby-dev:36366] + +Thu Sep 18 17:18:35 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * transcode.c (enc_arg): revert last change. too early exception + raising. + + * transcode.c (enc_arg): need not to take pointer argument. + +Sun Sep 18 02:22:15 2008 Yusuke Endoh <mame@tsg.ne.jp> + + * test/bigdecimal/test_bigdecimal.rb: add tests to achieve over 90% + test coverage of bigdecimal. + +Wed Sep 17 21:50:14 2008 Tanaka Akira <akr@fsij.org> + + * string.c (rb_str_casecmp): don't use rb_enc_codepoint. + +Wed Sep 17 19:55:33 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c (nucomp_s_convert): accepts complex + value (Complex(a,b) as a+bi). + +Wed Sep 17 19:16:47 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com> + + * test/ruby/test_io.rb (TestIO#test_dup): avoid infinite loop. + [ruby-dev:36326] + + * test/ruby/test_io.rb (TestIO#test_dup): remove needless open. + [ruby-dev:35957] + +Wed Sep 17 17:44:59 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * io.c (rb_io_extract_modeenc): process option mode: and perm: as + well. + + * io.c (open_key_args): move mode: and perm: related code to + rb_io_extract_modeenc(). + +Wed Sep 17 13:42:59 2008 Takeyuki Fujioka <xibbar@ruby-lang.org> + + * lib/cgi/html.rb (checkbox_group,radio_group): bug fix + use size instead of bytesize. + + * test/cgi/test_cgi_tag_helper.rb: test for checkbox_group,radio_group. + +Wed Sep 17 06:58:31 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * numeric.c: provides predicate real? instead of scalar?. + + * complex.c: follows the above change. + + * lib/cmath.rb: ditto. + +Wed Sep 17 01:56:27 2008 Tanaka Akira <akr@fsij.org> + + * test/ruby/test_io_m17n.rb: use __FILE__ instead of /dev/null. + [ruby-dev:36327] + +Wed Sep 17 01:33:11 2008 Tanaka Akira <akr@fsij.org> + + * include/ruby/oniguruma.h (OnigEncodingTypeST): add precise_ret + argument for mbc_to_code. + (ONIGENC_MBC_TO_CODE): provide NULL for precise_ret. + (ONIGENC_MBC_PRECISE_CODEPOINT): defined. + + * include/ruby/encoding.h (rb_enc_mbc_precise_codepoint): defined. + + * regenc.h (onigenc_single_byte_mbc_to_code): precise_ret argument + added. + (onigenc_mbn_mbc_to_code): ditto. + + * regenc.c (onigenc_single_byte_mbc_to_code): precise_ret argument + added. + (onigenc_mbn_mbc_to_code): ditto. + + * string.c (count_utf8_lead_bytes_with_word): removed. + (str_utf8_nth): removed. + (str_utf8_offset): removed. + (str_strlen): UTF-8 codepoint oriented optimization removed. + (rb_str_substr): ditto. + (enc_succ_char): use rb_enc_mbc_precise_codepoint. + (enc_pred_char): ditto. + (rb_str_succ): ditto. + + * encoding.c (rb_enc_ascget): check length with + rb_enc_mbc_precise_codepoint. + (rb_enc_codepoint): use rb_enc_mbc_precise_codepoint. + + * regexec.c (string_cmp_ic): add text_end argument. + (match_at): check end of character after exact string matches. + + * enc/utf_8.c (grapheme_table): defined for extended grapheme cluster + boundary. + (grapheme_cmp): defined. + (get_grapheme_properties): defined. + (grapheme_boundary_p): defined. + (MAX_BYTES_LENGTH): defined. + (comb_char_enc_len): defined. + (mbc_to_code0): extracted from mbc_to_code. + (mbc_to_code): use mbc_to_code0. + (left_adjust_combchar_head): defined. + (utf_8): use a extended grapheme cluster as a unit. + + * enc/unicode.c (onigenc_unicode_mbc_case_fold): use + ONIGENC_MBC_PRECISE_CODEPOINT to extract codepoints. + (onigenc_unicode_get_case_fold_codes_by_str): ditto. + + * enc/euc_jp.c (mbc_to_code): follow mbc_to_code field change. + use onigenc_mbn_mbc_to_code. + + * enc/shift_jis.c (mbc_to_code): ditto. + + * enc/emacs_mule.c (mbc_to_code): ditto. + + * enc/gbk.c (gbk_mbc_to_code): follow mbc_to_code field and + onigenc_mbn_mbc_to_code change. + + * enc/cp949.c (cp949_mbc_to_code): ditto. + + * enc/big5.c (big5_mbc_to_code): ditto. + + * enc/euc_tw.c (euctw_mbc_to_code): ditto. + + * enc/euc_kr.c (euckr_mbc_to_code): ditto. + + * enc/gb18030.c (gb18030_mbc_to_code): ditto. + + * enc/utf_32be.c (utf32be_mbc_to_code): follow mbc_to_code field + change. + + * enc/utf_16be.c (utf16be_mbc_to_code): ditto. + + * enc/utf_32le.c (utf32le_mbc_to_code): ditto. + + * enc/utf_16le.c (utf16le_mbc_to_code): ditto. + +Wed Sep 17 01:17:12 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * transcode.c (enc_arg): raise exception when unknown encoding is + given. + +Tue Sep 16 22:23:24 2008 Takeyuki Fujioka <xibbar@ruby-lang.org> + + * lib/cgi/core.rb (CGI#header): performance improvement. + From CGIAlt http://cgialt.rubyforge.org/ + + * test/cgi/test_cgi_header.rb: exception class fixed. + +Tue Sep 16 22:21:33 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * string.c (rb_str_concat): fix rdoc. (codepoint is integer) + + * string.c (rb_str_each_codepoint): use UINT2NUM. + +Tue Sep 16 21:48:55 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * re.c (rb_reg_desc): Regexp#inspect should be US-ASCII. + +Tue Sep 16 21:33:22 2008 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * string.c (rb_str_crypt): orthodox crypt() sees only first two bytes + of salt. + +Tue Sep 16 19:18:40 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c (nucomp_marshal_{dump,load}): preserve instance + variables. + + * rational.c (nurat_marshal_{dump,load}): ditto. + +Tue Sep 16 18:28:52 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * io.c (rb_io_gets_m): rdoc updated. limit counts in bytes. + [ruby-core:18617] + + * io.c (rb_io_readlines, rb_f_gets): ditto. + + * io.c (rb_io_readbyte): rdoc updated. [ruby-core:18617] + +Tue Sep 16 11:55:16 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (rb_str_each_codepoint): add new methods, #codepoints + and #each_codepoint. a patch from Michael Selig + <michael.selig at fs.com.au> in [ruby-core:18532]. + +Tue Sep 16 11:24:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * ext/socket/mkconstants.rb: add new constants. a patch from + IWAMURO Motonori <deenheart+ruby at gmail.com> in [ruby-dev:36309]. + +Tue Sep 16 09:20:42 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * test/ruby/test_io.rb (TestIO#test_dup): exception should be + raised from IO#dup. + +Tue Sep 16 08:35:29 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * test/ruby/test_io.rb (TestIO#test_dup): this test might fail if + there are any garbage IO objects. + +Tue Sep 16 02:02:56 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * string.c (rb_str_buf_cat_ascii): codepoint is unsigned int. + + * string.c (rb_str_concat): ditto. + + * string.c (str_cat_char): ditto. + + * string.c (prefix_escape): ditto. + +Tue Sep 16 01:47:07 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (single_byte_optimizable): make function inline. based + on a patch from Michael Selig <michael.selig at fs.com.au> in + [ruby-core:18532]. + + * string.c (str_modify_keep_cr): new function act as + rb_str_modify(), but don't clear coderange + + * string.c (rb_str_casecmp): specialized for single byte strings. + + * string.c (rb_str_splice): preserve coderange. + + * string.c (rb_str_slice_bang, rb_str_reverse_bang, + rb_str_upcase_bang, rb_str_downcase_bang, tr_trans, + rb_str_capitalize_bang, rb_str_swapcase_bang, + rb_str_delete_bang, rb_str_chop_bang, rb_str_chomp_bang, + rb_str_lstrip_bang, rb_str_rstrip_bang): ditto. + + * string.c (rb_str_clear): preset coderange. + + * string.c (rb_str_split_m): specialized for splitting with a + string. + +Tue Sep 16 00:57:56 2008 Tanaka Akira <akr@fsij.org> + + * re.c (rb_reg_quote): use rb_enc_mbcput to generate ASCII + incompatible characters properly. + +Tue Sep 16 00:51:59 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * encoding.c (Encoding#base_encoding): removed. [ruby-dev:36270] + +Tue Sep 16 00:40:56 2008 Tanaka Akira <akr@fsij.org> + + * transcode_data.h (STR1_LENGTH): defined. + (makeSTR1LEN): defined. + + * tool/transcode-tblgen.rb: use makeSTR1LEN. generate STR1 for 4 to + 259 bytes. + + * transcode.c (rb_transcoding): new field: output_index. + (transcode_restartable0): use STR1_LENGTH. + +Mon Sep 15 23:52:45 2008 Koichi Sasada <ko1@atdot.net> + + * gc.c, include/ruby/ruby.h: rename rb_register_mark_object() + to rb_gc_register_mark_object(). + + * eval.c, vm.c: initialize vm->mark_object_ary at + Init_top_self(). + + * bignum.c, complex.c, encoding.c, ext/win32ole/win32ole.c, + io.c, load.c, marshal.c, rational.c, ruby.c, vm.c: + use rb_gc_register_mark_object() instead of + rb_global_variable() or rb_gc_register_address(). + +Mon Sep 15 23:37:15 2008 Tanaka Akira <akr@fsij.org> + + * transcode.c (econv_opts): don't use to_sym. + +Mon Sep 15 23:28:28 2008 Tanaka Akira <akr@fsij.org> + + * encoding.c (rb_enc_get_index): don't return -1. + + * io.c (rb_scan_open_args): call FilePathValue before encoding + conversion. + +Mon Sep 15 22:11:07 2008 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (rb_str_squeeze_bang): specialized for 7bit characters in + ASCII compatible strings. + + * string.c (rb_str_count): ditto. + + * string.c (tr_trans): preserve 7bit/valid coderange flag. + + * string.c (rb_str_squeeze_bang): preserve previous coderange value. + + * string.c (rb_str_lstrip_bang): ditto. + + * string.c (rb_str_rstrip_bang): ditto. + + * encoding.c (rb_default_external_encoding): preserve + default_external_encoding in a static variable. + + * string.c (single_byte_optimizable): check coderange first, to + reduce number of calling rb_enc_from_index(). + +Mon Sep 15 20:57:00 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp> + + * lib/matrix.rb (Matrix#eql?): fixed [ruby-dev:36298]. + Reported by an anonymous user. + + * lib/matrix.rb (Vector#eql?): ditto. + + * (Matrix#compare_by_row_vectors): takes comparison + strategy as an optional parameter. + + * (Vector#compare_by): ditto. + +Mon Sep 15 14:34:32 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * encoding.c (RUBY_MAX_CHAR_LEN): defined. + + * encoding.c (str_cat_char): use RUBY_MAX_CHAR_LEN. + +Mon Sep 15 13:53:33 2008 NARUSE, Yui <naruse@ruby-lang.org> + + * encoding.c (rb_enc_compatible): accept other than strings and + regexps. [ruby-core:18595] + + * encoding.c (rb_enc_get_index): works files and encodings. + +Mon Sep 15 13:17:21 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c (nucomp_eql_p): new. + + * complex.c (nucomp_hash): should use hash values of the elements. + + * rational.c (nurat_hash): ditto. + + * hash.c (rb_any_cmp): removed an unused variable. + +Mon Sep 15 11:11:04 2008 Tanaka Akira <akr@fsij.org> + + * transcode_data.h (rb_transcoder): resetsize_func and resetstate_func + also returns ssize_t. + + * enc/trans/iso2022.trans: follow the type change. + +Mon Sep 15 10:28:10 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp> + + * test/matrix/test_matrix.rb (setup): typo. + (test_equality): misdefinition of the expected working. + Reported by an anonymous user. + (test_hash): added. + + * test/matrix/test_vector.rb: ditto. + +Mon Sep 15 03:33:10 2008 Tanaka Akira <akr@fsij.org> + + * transcode_data.h: return output functions ssize_t. + + * transcode.c (transcode_restartable0): don't need to cast the result + of output functions. + + * enc/trans/newline.trans: follow the type change. + + * enc/trans/escape.trans: ditto. + + * enc/trans/utf_16_32.trans: ditto. + + * enc/trans/iso2022.trans: ditto. + + * enc/trans/japanese.trans: ditto. + +Mon Sep 15 03:04:29 2008 Tanaka Akira <akr@fsij.org> + + * transcode_data.h: output function takes output buffer size. + + * transcode.c: give output buffer size for output functions. + + * enc/trans/newline.trans: follow the type change. + + * enc/trans/escape.trans: ditto. + + * enc/trans/utf_16_32.trans: ditto. + + * enc/trans/iso2022.trans: ditto. + + * enc/trans/japanese.trans: ditto. + +Mon Sep 15 02:37:19 2008 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * transcode.c (str_encode): returns duplicated string if nothing + changed. [ruby-core:18578] + +Sun Sep 14 22:09:01 2008 Takeyuki Fujioka <xibbar@ruby-lang.org> + + * lib/cgi/core.rb (CGI::parse): performance improvement + +Sun Sep 14 18:33:32 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c: trivial changes. + +Sun Sep 14 16:15:22 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp> + + * lib/matrix.rb (Vector#eql?): typo of the method name as "eqn?". + (Vector#eqn?): removed. Defined by mistake. + Fixes [ruby-dev:36294]. Reported by weda <weda AT + issp.u-tokyo.ac.jp> and an anonymous user. + + * test/matrix/test_matrix.rb: added. + + * test/matrix/test_vector.rb: added. + +Sun Sep 14 16:07:04 2008 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * ruby.c (process_options): associates the locale encoding with $0 as + well as ARGV. + +Sun Sep 14 13:48:03 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp> + + * object.c (Init_Object): added metameta-class initialization for + BasicObject, Object, and Module. + The metameta-classes of them are now the metaclass of Class, as the + metameta-class of Class is. + + * object.c (boot_defmetametaclass): added. + +Sun Sep 14 10:10:43 2008 Tadayoshi Funaba <tadf@dotrb.org> + + * complex.c (f_{add,mul,sub}): omitted some shortcuts for preserving + signed zero anyway. + + * complex.c (nucomp_negate): new. + +Sun Sep 14 04:15:16 2008 Tanaka Akira <akr@fsij.org> + + * include/ruby/oniguruma.h (OnigEncodingTypeST): add end argument for + left_adjust_char_head. + (ONIGENC_LEFT_ADJUST_CHAR_HEAD): add end argument. + (onigenc_get_left_adjust_char_head): ditto. + + * include/ruby/encoding.h (rb_enc_left_char_head): add end argument. + + * regenc.h (onigenc_single_byte_left_adjust_char_head): ditto. + + * regenc.c (onigenc_get_right_adjust_char_head): follow the interface + change. + (onigenc_get_right_adjust_char_head_with_prev): ditto. + (onigenc_get_prev_char_head): ditto. + (onigenc_step_back): ditto. + (onigenc_get_left_adjust_char_head): ditto. + (onigenc_single_byte_code_to_mbc): ditto. + + * re.c: ditto. + + * string.c: ditto. + + * io.c: ditto. + + * regexec.c: ditto. + + * enc/euc_jp.c: ditto. + + * enc/cp949.c: ditto. + + * enc/shift_jis.c: ditto. + + * enc/gbk.c: ditto. + + * enc/big5.c: ditto. + + * enc/euc_tw.c: ditto. + + * enc/euc_kr.c: ditto. + + * enc/emacs_mule.c: ditto. + + * enc/gb18030.c: ditto. + + * enc/utf_8.c: ditto. + + * enc/utf_16le.c: ditto. + + * enc/utf_16be.c: ditto. + + * enc/utf_32le.c: ditto. + + * enc/utf_32be.c: ditto. + +Sun Sep 14 03:43:27 2008 Tanaka Akira <akr@fsij.org> + + * include/ruby/oniguruma.h (ONIGENC_STEP_BACK): add end argument. + (onigenc_step_back): ditto. + + * regenc.c (onigenc_step_back): add end argument. + + * regexec.c: follow the interface change. + +Sun Sep 14 03:20:03 2008 Tanaka Akira <akr@fsij.org> + + * include/ruby/oniguruma.h (onigenc_get_prev_char_head): add end + argument. + + * include/ruby/encoding.h (rb_enc_prev_char): ditto. + + * regenc.c (onigenc_get_prev_char_head): add end argument. + + * regparse.c: follow the interface change. + + * regexec.c: ditto. + + * string.c: ditto. + + * parse.y: ditto. + +Sun Sep 14 02:04:28 2008 Tanaka Akira <akr@fsij.org> + + * include/ruby/oniguruma.h + (onigenc_get_right_adjust_char_head_with_prev): add end argument. + + * regenc.c (onigenc_get_right_adjust_char_head_with_prev): use end + argument. + + * regexec.c (forward_search_range): follow the interface change. + +Sun Sep 14 01:38:26 2008 Tanaka Akira <akr@fsij.org> + + * include/ruby/oniguruma.h (onigenc_get_right_adjust_char_head): add + end argument. + + * include/ruby/encoding.h (rb_enc_right_char_head): add end argument. + + * regenc.c (onigenc_get_right_adjust_char_head): use end argument. + + * re.c (rb_reg_adjust_startpos): follow the interface change. + + * string.c (rb_str_index): ditto. + + * regexec.c (backward_search_range): ditto. + (onig_search): ditto. + Sun Sep 14 00:43:28 2008 Tanaka Akira <akr@fsij.org> * ext/ripper/depend (ripper.o): it depends on ruby headers. @@ -962,7 +1746,8 @@ Thu Sep 4 19:10:27 2008 Tanaka Akira <akr@fsij.org> * include/ruby/encoding.h (ECONV_INVALID_IGNORE): removed because it tend to cause security problem. If the behaviour is really required, ECONV_INVALID_REPLACE with empty string can be used. - For example, CVE-2006-2313, CVE-2008-1036, [ruby-core:15645] + For example, CVE-2006-2313, CVE-2008-1036, [ruby-core:15645], + http://unicode.org/reports/tr36/ (ECONV_UNDEF_IGNORE): ditto. * transcode.c (rb_econv_convert): follow the above change. @@ -774,7 +774,7 @@ power_cache_get_power0(int base, int 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]); + rb_gc_register_mark_object(big2str_power_cache[base - 2][i]); } return big2str_power_cache[base - 2][i]; } @@ -909,8 +909,10 @@ big2str_karatsuba(VALUE x, int base, char* ptr, bigdivmod(x, b, &q, &r); lh = big2str_karatsuba(q, base, ptr, (len - m1)/2, len - m1, hbase, trim); + rb_big_resize(q, 0); ll = big2str_karatsuba(r, base, ptr + lh, m1/2, m1, hbase, !lh && trim); + rb_big_resize(r, 0); return lh + ll; } @@ -953,6 +955,7 @@ rb_big2str0(VALUE x, int base, int trim) len = off + big2str_karatsuba(xx, base, ptr + off, n1, n2, hbase, trim); } + rb_big_resize(xx, 0); ptr[len] = '\0'; rb_str_resize(ss, len); @@ -2099,9 +2102,6 @@ rb_big_pow(VALUE x, VALUE y) 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; @@ -2110,7 +2110,7 @@ rb_big_pow(VALUE x, VALUE y) yy = FIX2LONG(y); if (yy < 0) - return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); + return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); else { VALUE z = 0; SIGNED_VALUE mask; @@ -9,7 +9,7 @@ RUBYOPT = - SPEC_GIT_BASE = git://github.com/rubyspec MSPEC_GIT_URL = $(SPEC_GIT_BASE)/mspec.git -RUBYSPEC_GIT_URL = git://github.com/yugui/rubyspec.git +RUBYSPEC_GIT_URL = $(SPEC_GIT_BASE)/rubyspec.git STATIC_RUBY = static-ruby @@ -49,7 +49,6 @@ COMMONOBJS = array.$(OBJEXT) \ pack.$(OBJEXT) \ parse.$(OBJEXT) \ process.$(OBJEXT) \ - prec.$(OBJEXT) \ random.$(OBJEXT) \ range.$(OBJEXT) \ rational.$(OBJEXT) \ @@ -520,7 +519,6 @@ parse.$(OBJEXT): {$(VPATH)}parse.c {$(VPATH)}parse.y $(RUBY_H_INCLUDES) \ {$(VPATH)}oniguruma.h $(ID_H_INCLUDES) {$(VPATH)}regenc.h \ {$(VPATH)}regex.h {$(VPATH)}util.h {$(VPATH)}lex.c {$(VPATH)}keywords \ {$(VPATH)}debug.h {$(VPATH)}id.c -prec.$(OBJEXT): {$(VPATH)}prec.c $(RUBY_H_INCLUDES) {$(VPATH)}st.h proc.$(OBJEXT): {$(VPATH)}proc.c {$(VPATH)}eval_intern.h \ $(RUBY_H_INCLUDES) {$(VPATH)}st.h {$(VPATH)}node.h {$(VPATH)}util.h \ {$(VPATH)}vm_core.h {$(VPATH)}debug.h \ @@ -21,11 +21,10 @@ VALUE rb_cComplex; -static ID id_Unify, id_abs, id_abs2, id_arg, id_cmp, id_conjugate, - id_convert, id_denominator, id_divmod, id_equal_p, id_exact_p, id_expt, - id_floor, id_format, id_idiv, id_inspect, id_negate, id_new, id_new_bang, - id_numerator, id_polar, id_quo, id_scalar_p, id_to_f, id_to_i, id_to_r, - id_to_s, id_truncate; +static ID id_Unify, id_abs, id_abs2, id_arg, id_cmp, id_conj, id_convert, + id_denominator, id_divmod, id_equal_p, id_expt, id_floor, id_hash, + id_idiv, id_inspect, id_negate, id_numerator, id_polar, id_quo, + id_real_p, id_to_f, id_to_i, id_to_r, id_to_s; #define f_boolcast(x) ((x) ? Qtrue : Qfalse) @@ -64,13 +63,17 @@ m_##n(VALUE x, VALUE y)\ return rb_funcall(rb_mMath, id_##n, 2, x, y);\ } +#define PRESERVE_SIGNEDZERO + inline static VALUE f_add(VALUE x, VALUE y) { +#ifndef PRESERVE_SIGNEDZERO if (FIXNUM_P(y) && FIX2LONG(y) == 0) return x; else if (FIXNUM_P(x) && FIX2LONG(x) == 0) return y; +#endif return rb_funcall(x, '+', 1, y); } @@ -117,6 +120,7 @@ binop(mod, '%') inline static VALUE f_mul(VALUE x, VALUE y) { +#ifndef PRESERVE_SIGNEDZERO if (FIXNUM_P(y)) { long iy = FIX2LONG(y); if (iy == 0) { @@ -135,14 +139,17 @@ f_mul(VALUE x, VALUE y) else if (ix == 1) return y; } +#endif return rb_funcall(x, '*', 1, y); } inline static VALUE f_sub(VALUE x, VALUE y) { +#ifndef PRESERVE_SIGNEDZERO if (FIXNUM_P(y) && FIX2LONG(y) == 0) return x; +#endif return rb_funcall(x, '-', 1, y); } @@ -151,23 +158,20 @@ binop(xor, '^') fun1(abs) fun1(abs2) fun1(arg) -fun1(conjugate) +fun1(conj) fun1(denominator) -fun1(exact_p) fun1(floor) +fun1(hash) fun1(inspect) fun1(negate) fun1(numerator) fun1(polar) -fun1(scalar_p) - -#define f_real_p f_scalar_p +fun1(real_p) fun1(to_f) fun1(to_i) fun1(to_r) fun1(to_s) -fun1(truncate) fun2(divmod) @@ -191,6 +195,8 @@ f_negative_p(VALUE x) return rb_funcall(x, '<', 1, ZERO); } +#define f_positive_p(x) (!f_negative_p(x)) + inline static VALUE f_zero_p(VALUE x) { @@ -199,6 +205,8 @@ f_zero_p(VALUE x) return rb_funcall(x, id_equal_p, 1, ZERO); } +#define f_nonzero_p(x) (!f_zero_p(x)) + inline static VALUE f_one_p(VALUE x) { @@ -243,6 +251,9 @@ k_complex_p(VALUE x) return f_kind_of_p(x, rb_cComplex); } +#define k_exact_p(x) (!k_float_p(x)) +#define k_inexact_p(x) k_float_p(x) + #define get_dat1(x) \ struct RComplex *dat;\ dat = ((struct RComplex *)(x)) @@ -253,13 +264,13 @@ k_complex_p(VALUE x) bdat = ((struct RComplex *)(y)) inline static VALUE -nucomp_s_new_internal(VALUE klass, VALUE real, VALUE image) +nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag) { NEWOBJ(obj, struct RComplex); OBJSETUP(obj, klass, T_COMPLEX); obj->real = real; - obj->image = image; + obj->imag = imag; return (VALUE)obj; } @@ -273,23 +284,23 @@ nucomp_s_alloc(VALUE klass) static VALUE nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass) { - VALUE real, image; + VALUE real, imag; - switch (rb_scan_args(argc, argv, "11", &real, &image)) { + switch (rb_scan_args(argc, argv, "11", &real, &imag)) { case 1: if (!k_numeric_p(real)) real = f_to_i(real); - image = ZERO; + imag = ZERO; break; default: if (!k_numeric_p(real)) real = f_to_i(real); - if (!k_numeric_p(image)) - image = f_to_i(image); + if (!k_numeric_p(imag)) + imag = f_to_i(imag); break; } - return nucomp_s_new_internal(klass, real, image); + return nucomp_s_new_internal(klass, real, imag); } inline static VALUE @@ -325,39 +336,38 @@ nucomp_real_check(VALUE num) } inline static VALUE -nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE image) +nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag) { #define CL_CANON #ifdef CL_CANON - if (f_zero_p(image) && f_unify_p(klass) && - !k_float_p(real) && !k_float_p(image)) + if (f_zero_p(imag) && k_exact_p(imag) && f_unify_p(klass)) return real; #else - if (f_zero_p(image) && f_unify_p(klass)) + if (f_zero_p(imag) && f_unify_p(klass)) return real; #endif - else if (f_real_p(real) && f_real_p(image)) - return nucomp_s_new_internal(klass, real, image); + else if (f_real_p(real) && f_real_p(imag)) + return nucomp_s_new_internal(klass, real, imag); else if (f_real_p(real)) { - get_dat1(image); + get_dat1(imag); return nucomp_s_new_internal(klass, - f_sub(real, dat->image), + f_sub(real, dat->imag), f_add(ZERO, dat->real)); } - else if (f_real_p(image)) { + else if (f_real_p(imag)) { get_dat1(real); return nucomp_s_new_internal(klass, dat->real, - f_add(dat->image, image)); + f_add(dat->imag, imag)); } else { - get_dat2(real, image); + get_dat2(real, imag); return nucomp_s_new_internal(klass, - f_sub(adat->real, bdat->image), - f_add(adat->image, bdat->real)); + f_sub(adat->real, bdat->imag), + f_add(adat->imag, bdat->real)); } } @@ -365,36 +375,40 @@ nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE image) static VALUE nucomp_s_canonicalize(int argc, VALUE *argv, VALUE klass) { - VALUE real, image; + VALUE real, imag; - switch (rb_scan_args(argc, argv, "11", &real, &image)) { + switch (rb_scan_args(argc, argv, "11", &real, &imag)) { case 1: - image = ZERO; + nucomp_real_check(real); + imag = ZERO; + break; + default: + nucomp_real_check(real); + nucomp_real_check(imag); break; } - nucomp_real_check(real); - nucomp_real_check(image); - - return nucomp_s_canonicalize_internal(klass, real, image); + return nucomp_s_canonicalize_internal(klass, real, imag); } #endif static VALUE nucomp_s_new(int argc, VALUE *argv, VALUE klass) { - VALUE real, image; + VALUE real, imag; - switch (rb_scan_args(argc, argv, "11", &real, &image)) { + switch (rb_scan_args(argc, argv, "11", &real, &imag)) { case 1: - image = ZERO; + nucomp_real_check(real); + imag = ZERO; + break; + default: + nucomp_real_check(real); + nucomp_real_check(imag); break; } - nucomp_real_check(real); - nucomp_real_check(image); - - return nucomp_s_canonicalize_internal(klass, real, image); + return nucomp_s_canonicalize_internal(klass, real, imag); } inline static VALUE @@ -446,44 +460,46 @@ m_log_bang(VALUE x) static VALUE m_cos(VALUE x) { - get_dat1(x); - if (f_real_p(x)) return m_cos_bang(x); - 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))); + { + get_dat1(x); + return f_complex_new2(rb_cComplex, + f_mul(m_cos_bang(dat->real), + m_cosh_bang(dat->imag)), + f_mul(f_negate(m_sin_bang(dat->real)), + m_sinh_bang(dat->imag))); + } } static VALUE m_sin(VALUE x) { - get_dat1(x); - if (f_real_p(x)) return m_sin_bang(x); - 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))); + { + get_dat1(x); + return f_complex_new2(rb_cComplex, + f_mul(m_sin_bang(dat->real), + m_cosh_bang(dat->imag)), + f_mul(m_cos_bang(dat->real), + m_sinh_bang(dat->imag))); + } } static VALUE m_sqrt(VALUE x) { if (f_real_p(x)) { - if (!f_negative_p(x)) + if (f_positive_p(x)) return m_sqrt_bang(x); 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))); + if (f_negative_p(dat->imag)) + return f_conj(m_sqrt(f_conj(x))); else { VALUE a = f_abs(x); return f_complex_new2(rb_cComplex, @@ -517,30 +533,38 @@ nucomp_real(VALUE self) } static VALUE -nucomp_image(VALUE self) +nucomp_imag(VALUE self) { get_dat1(self); - return dat->image; + return dat->imag; +} + +static VALUE +nucomp_negate(VALUE self) +{ + get_dat1(self); + return f_complex_new2(CLASS_OF(self), + f_negate(dat->real), f_negate(dat->imag)); } static VALUE nucomp_add(VALUE self, VALUE other) { if (k_complex_p(other)) { - VALUE real, image; + VALUE real, imag; get_dat2(self, other); real = f_add(adat->real, bdat->real); - image = f_add(adat->image, bdat->image); + imag = f_add(adat->imag, bdat->imag); - return f_complex_new2(CLASS_OF(self), real, image); + return f_complex_new2(CLASS_OF(self), real, imag); } if (k_numeric_p(other) && f_real_p(other)) { get_dat1(self); return f_complex_new2(CLASS_OF(self), - f_add(dat->real, other), dat->image); + f_add(dat->real, other), dat->imag); } return rb_num_coerce_bin(self, other, '+'); } @@ -549,20 +573,20 @@ static VALUE nucomp_sub(VALUE self, VALUE other) { if (k_complex_p(other)) { - VALUE real, image; + VALUE real, imag; get_dat2(self, other); real = f_sub(adat->real, bdat->real); - image = f_sub(adat->image, bdat->image); + imag = f_sub(adat->imag, bdat->imag); - return f_complex_new2(CLASS_OF(self), real, image); + return f_complex_new2(CLASS_OF(self), real, imag); } if (k_numeric_p(other) && f_real_p(other)) { get_dat1(self); return f_complex_new2(CLASS_OF(self), - f_sub(dat->real, other), dat->image); + f_sub(dat->real, other), dat->imag); } return rb_num_coerce_bin(self, other, '-'); } @@ -571,23 +595,23 @@ static VALUE nucomp_mul(VALUE self, VALUE other) { if (k_complex_p(other)) { - VALUE real, image; + VALUE real, imag; 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)); + f_mul(adat->imag, bdat->imag)); + imag = f_add(f_mul(adat->real, bdat->imag), + f_mul(adat->imag, bdat->real)); - return f_complex_new2(CLASS_OF(self), real, image); + return f_complex_new2(CLASS_OF(self), real, imag); } if (k_numeric_p(other) && f_real_p(other)) { get_dat1(self); return f_complex_new2(CLASS_OF(self), f_mul(dat->real, other), - f_mul(dat->image, other)); + f_mul(dat->imag, other)); } return rb_num_coerce_bin(self, other, '*'); } @@ -601,23 +625,23 @@ nucomp_div(VALUE self, VALUE other) get_dat2(self, other); if (TYPE(adat->real) == T_FLOAT || - TYPE(adat->image) == T_FLOAT || + TYPE(adat->imag) == T_FLOAT || TYPE(bdat->real) == T_FLOAT || - TYPE(bdat->image) == T_FLOAT) { - VALUE magn = m_hypot(bdat->real, bdat->image); + TYPE(bdat->imag) == T_FLOAT) { + VALUE magn = m_hypot(bdat->real, bdat->imag); 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); + f_div(bdat->imag, magn)); + return f_div(f_mul(self, f_conj(tmp)), magn); } - return f_div(f_mul(self, f_conjugate(other)), f_abs2(other)); + return f_div(f_mul(self, f_conj(other)), f_abs2(other)); } if (k_numeric_p(other) && f_real_p(other)) { get_dat1(self); return f_complex_new2(CLASS_OF(self), f_div(dat->real, other), - f_div(dat->image, other)); + f_div(dat->imag, other)); } return rb_num_coerce_bin(self, other, '/'); } @@ -632,13 +656,13 @@ nucomp_fdiv(VALUE self, VALUE other) return f_div(f_complex_new2(CLASS_OF(self), f_to_f(dat->real), - f_to_f(dat->image)), other); + f_to_f(dat->imag)), other); } static VALUE nucomp_expt(VALUE self, VALUE other) { - if (f_zero_p(other)) + if (k_exact_p(other) && f_zero_p(other)) return f_complex_new_bang1(CLASS_OF(self), ONE); if (k_rational_p(other) && f_one_p(f_denominator(other))) @@ -654,7 +678,7 @@ nucomp_expt(VALUE self, VALUE other) theta = RARRAY_PTR(a)[1]; ore = dat->real; - oim = dat->image; + oim = dat->imag; 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))); @@ -668,7 +692,7 @@ nucomp_expt(VALUE self, VALUE other) z = x; n = f_sub(other, ONE); - while (!f_zero_p(n)) { + while (f_nonzero_p(n)) { VALUE a; while (a = f_divmod(n, TWO), @@ -677,8 +701,8 @@ nucomp_expt(VALUE self, VALUE other) 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)); + f_mul(dat->imag, dat->imag)), + f_mul(f_mul(TWO, dat->real), dat->imag)); n = RARRAY_PTR(a)[0]; } z = f_mul(z, x); @@ -707,12 +731,12 @@ nucomp_equal_p(VALUE self, VALUE other) get_dat2(self, other); return f_boolcast(f_equal_p(adat->real, bdat->real) && - f_equal_p(adat->image, bdat->image)); + f_equal_p(adat->imag, bdat->imag)); } if (k_numeric_p(other) && f_real_p(other)) { get_dat1(self); - return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->image)); + return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->imag)); } return f_equal_p(other, self); } @@ -732,7 +756,7 @@ static VALUE nucomp_abs(VALUE self) { get_dat1(self); - return m_hypot(dat->real, dat->image); + return m_hypot(dat->real, dat->imag); } static VALUE @@ -740,21 +764,21 @@ nucomp_abs2(VALUE self) { get_dat1(self); return f_add(f_mul(dat->real, dat->real), - f_mul(dat->image, dat->image)); + f_mul(dat->imag, dat->imag)); } static VALUE nucomp_arg(VALUE self) { get_dat1(self); - return m_atan2_bang(dat->image, dat->real); + return m_atan2_bang(dat->imag, dat->real); } static VALUE nucomp_rect(VALUE self) { get_dat1(self); - return rb_assoc_new(dat->real, dat->image); + return rb_assoc_new(dat->real, dat->imag); } static VALUE @@ -764,10 +788,10 @@ nucomp_polar(VALUE self) } static VALUE -nucomp_conjugate(VALUE self) +nucomp_conj(VALUE self) { get_dat1(self); - return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->image)); + return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag)); } #if 0 @@ -789,7 +813,7 @@ static VALUE nucomp_exact_p(VALUE self) { get_dat1(self); - return f_boolcast(f_exact_p(dat->real) && f_exact_p(dat->image)); + return f_boolcast(f_exact_p(dat->real) && f_exact_p(dat->imag)); } static VALUE @@ -805,7 +829,7 @@ static VALUE nucomp_denominator(VALUE self) { get_dat1(self); - return rb_lcm(f_denominator(dat->real), f_denominator(dat->image)); + return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag)); } static VALUE @@ -819,15 +843,29 @@ nucomp_numerator(VALUE 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)))); + f_mul(f_numerator(dat->imag), + f_div(cd, f_denominator(dat->imag)))); } static VALUE nucomp_hash(VALUE self) { get_dat1(self); - return f_xor(dat->real, dat->image); + return f_xor(f_hash(dat->real), f_hash(dat->imag)); +} + +static VALUE +nucomp_eql_p(VALUE self, VALUE other) +{ + if (k_complex_p(other)) { + get_dat2(self, other); + + return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) && + (CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) && + f_equal_p(self, other)); + + } + return Qfalse; } #ifndef HAVE_SIGNBIT @@ -869,12 +907,12 @@ nucomp_to_s(VALUE self) get_dat1(self); - impos = f_tpositive_p(dat->image); + impos = f_tpositive_p(dat->imag); s = f_to_s(dat->real); rb_str_cat2(s, !impos ? "-" : "+"); - rb_str_concat(s, f_to_s(f_abs(dat->image))); + rb_str_concat(s, f_to_s(f_abs(dat->imag))); rb_str_cat2(s, "i"); return s; @@ -887,13 +925,13 @@ nucomp_inspect(VALUE self) get_dat1(self); - impos = f_tpositive_p(dat->image); + impos = f_tpositive_p(dat->imag); s = rb_str_new2("("); rb_str_concat(s, f_inspect(dat->real)); rb_str_cat2(s, !impos ? "-" : "+"); - rb_str_concat(s, f_inspect(f_abs(dat->image))); + rb_str_concat(s, f_inspect(f_abs(dat->imag))); rb_str_cat2(s, "i)"); return s; @@ -902,8 +940,12 @@ nucomp_inspect(VALUE self) static VALUE nucomp_marshal_dump(VALUE self) { + VALUE a; get_dat1(self); - return rb_assoc_new(dat->real, dat->image); + + a = rb_assoc_new(dat->real, dat->imag); + rb_copy_generic_ivar(a, self); + return a; } static VALUE @@ -911,7 +953,8 @@ nucomp_marshal_load(VALUE self, VALUE a) { get_dat1(self); dat->real = RARRAY_PTR(a)[0]; - dat->image = RARRAY_PTR(a)[1]; + dat->imag = RARRAY_PTR(a)[1]; + rb_copy_generic_ivar(self, a); return self; } @@ -951,7 +994,7 @@ nucomp_to_i(VALUE self) { get_dat1(self); - if (k_float_p(dat->image) || !f_zero_p(dat->image)) { + if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) { VALUE s = f_to_s(self); rb_raise(rb_eRangeError, "can't convert %s into Integer", StringValuePtr(s)); @@ -964,7 +1007,7 @@ nucomp_to_f(VALUE self) { get_dat1(self); - if (k_float_p(dat->image) || !f_zero_p(dat->image)) { + if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) { VALUE s = f_to_s(self); rb_raise(rb_eRangeError, "can't convert %s into Float", StringValuePtr(s)); @@ -977,7 +1020,7 @@ nucomp_to_r(VALUE self) { get_dat1(self); - if (k_float_p(dat->image) || !f_zero_p(dat->image)) { + if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) { VALUE s = f_to_s(self); rb_raise(rb_eRangeError, "can't convert %s into Rational", StringValuePtr(s)); @@ -1021,29 +1064,29 @@ make_patterns(void) if (comp_pat0) return; comp_pat0 = rb_reg_new(comp_pat0_source, sizeof comp_pat0_source - 1, 0); - rb_global_variable(&comp_pat0); + rb_gc_register_mark_object(comp_pat0); comp_pat1 = rb_reg_new(comp_pat1_source, sizeof comp_pat1_source - 1, 0); - rb_global_variable(&comp_pat1); + rb_gc_register_mark_object(comp_pat1); comp_pat2 = rb_reg_new(comp_pat2_source, sizeof comp_pat2_source - 1, 0); - rb_global_variable(&comp_pat2); + rb_gc_register_mark_object(comp_pat2); a_slash = rb_str_new2("/"); - rb_global_variable(&a_slash); + rb_gc_register_mark_object(a_slash); a_dot_and_an_e = rb_str_new2(".eE"); - rb_global_variable(&a_dot_and_an_e); + rb_gc_register_mark_object(a_dot_and_an_e); null_string = rb_str_new2(""); - rb_global_variable(&null_string); + rb_gc_register_mark_object(null_string); underscores_pat = rb_reg_new(underscores_pat_source, sizeof underscores_pat_source - 1, 0); - rb_global_variable(&underscores_pat); + rb_gc_register_mark_object(underscores_pat); an_underscore = rb_str_new2("_"); - rb_global_variable(&an_underscore); + rb_gc_register_mark_object(an_underscore); } #define id_match rb_intern("match") @@ -1109,9 +1152,8 @@ string_to_c_internal(VALUE self) } if (NIL_P(m)) { m = f_match(comp_pat2, s); - if (NIL_P(m)) { + if (NIL_P(m)) return rb_assoc_new(Qnil, self); - } sr = f_aref(m, INT2FIX(1)); if (NIL_P(f_aref(m, INT2FIX(2)))) si = Qnil; @@ -1149,7 +1191,6 @@ string_to_c_internal(VALUE self) return rb_assoc_new(rb_complex_polar(r, i), re); else return rb_assoc_new(rb_complex_new2(r, i), re); - } } @@ -1191,7 +1232,7 @@ nucomp_s_convert(int argc, VALUE *argv, VALUE klass) { VALUE a1, a2, backref; - rb_scan_args(argc, argv, "02", &a1, &a2); + rb_scan_args(argc, argv, "11", &a1, &a2); backref = rb_backref_get(); rb_match_busy(backref); @@ -1223,7 +1264,7 @@ nucomp_s_convert(int argc, VALUE *argv, VALUE klass) { get_dat1(a1); - if (!k_float_p(dat->image) && f_zero_p(dat->image)) + if (k_exact_p(dat->imag) && f_zero_p(dat->imag)) a1 = dat->real; } } @@ -1233,17 +1274,29 @@ nucomp_s_convert(int argc, VALUE *argv, VALUE klass) { get_dat1(a2); - if (!k_float_p(dat->image) && f_zero_p(dat->image)) + if (k_exact_p(dat->imag) && f_zero_p(dat->imag)) a2 = dat->real; } } switch (TYPE(a1)) { case T_COMPLEX: - if (NIL_P(a2) || f_zero_p(a2)) + if (argc == 1 || (k_exact_p(a2) && f_zero_p(a2))) return a1; } + if (argc == 1) { + if (k_numeric_p(a1) && !f_real_p(a1)) + return a1; + } + else { + if ((k_numeric_p(a1) && k_numeric_p(a2)) && + (!f_real_p(a1) || !f_real_p(a2))) + return f_add(a1, + f_mul(a2, + f_complex_new_bang2(rb_cComplex, ZERO, ONE))); + } + { VALUE argv2[2]; argv2[0] = a1; @@ -1254,20 +1307,6 @@ nucomp_s_convert(int argc, VALUE *argv, VALUE 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) { @@ -1275,7 +1314,7 @@ numeric_real(VALUE self) } static VALUE -numeric_image(VALUE self) +numeric_imag(VALUE self) { return INT2FIX(0); } @@ -1291,7 +1330,7 @@ numeric_abs2(VALUE self) static VALUE numeric_arg(VALUE self) { - if (!f_negative_p(self)) + if (f_positive_p(self)) return INT2FIX(0); return rb_const_get(rb_mMath, id_PI); } @@ -1299,7 +1338,7 @@ numeric_arg(VALUE self) static VALUE numeric_rect(VALUE self) { - return rb_assoc_new(self, ZERO); + return rb_assoc_new(self, INT2FIX(0)); } static VALUE @@ -1309,7 +1348,7 @@ numeric_polar(VALUE self) } static VALUE -numeric_conjugate(VALUE self) +numeric_conj(VALUE self) { return self; } @@ -1327,29 +1366,25 @@ Init_Complex(void) id_abs2 = rb_intern("abs2"); id_arg = rb_intern("arg"); id_cmp = rb_intern("<=>"); - id_conjugate = rb_intern("conjugate"); + id_conj = rb_intern("conj"); id_convert = rb_intern("convert"); id_denominator = rb_intern("denominator"); id_divmod = rb_intern("divmod"); id_equal_p = rb_intern("=="); - id_exact_p = rb_intern("exact?"); id_expt = rb_intern("**"); id_floor = rb_intern("floor"); - id_format = rb_intern("format"); + id_hash = rb_intern("hash"); 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_numerator = rb_intern("numerator"); id_polar = rb_intern("polar"); id_quo = rb_intern("quo"); - id_scalar_p = rb_intern("scalar?"); + id_real_p = rb_intern("real?"); 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); @@ -1390,9 +1425,10 @@ Init_Complex(void) #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, "imaginary", nucomp_imag, 0); + rb_define_method(rb_cComplex, "imag", nucomp_imag, 0); + rb_define_method(rb_cComplex, "-@", nucomp_negate, 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); @@ -1413,24 +1449,24 @@ Init_Complex(void) rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0); rb_define_method(rb_cComplex, "rect", nucomp_rect, 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); + rb_define_method(rb_cComplex, "conjugate", nucomp_conj, 0); + rb_define_method(rb_cComplex, "conj", nucomp_conj, 0); #if 0 - rb_define_method(rb_cComplex, "~", nucomp_conjugate, 0); /* gcc */ + rb_define_method(rb_cComplex, "~", nucomp_conj, 0); /* gcc */ #endif -#if 0 rb_define_method(rb_cComplex, "real?", nucomp_false, 0); +#if 0 rb_define_method(rb_cComplex, "complex?", nucomp_true, 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, "scalar?", nucomp_false, 0); 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, "eql?", nucomp_eql_p, 1); rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0); rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0); @@ -1456,11 +1492,9 @@ Init_Complex(void) /* --- */ - 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, "imaginary", numeric_imag, 0); + rb_define_method(rb_cNumeric, "imag", numeric_imag, 0); rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0); rb_define_method(rb_cNumeric, "arg", numeric_arg, 0); rb_define_method(rb_cNumeric, "angle", numeric_arg, 0); @@ -1468,9 +1502,15 @@ Init_Complex(void) rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0); rb_define_method(rb_cNumeric, "rect", numeric_rect, 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_method(rb_cNumeric, "conjugate", numeric_conj, 0); + rb_define_method(rb_cNumeric, "conj", numeric_conj, 0); rb_define_const(rb_cComplex, "I", f_complex_new_bang2(rb_cComplex, ZERO, ONE)); } + +/* +Local variables: +c-file-style: "ruby" +End: +*/ diff --git a/configure.in b/configure.in index 327abb24eb..6783b82994 100644 --- a/configure.in +++ b/configure.in @@ -1423,10 +1423,12 @@ if test "$with_dln_a_out" != yes; then powerpc*) : ${LDSHARED="ld -xms"} DLDFLAGS="$DLDFLAGS "'-export Init_$(TARGET) -lbe -lroot glue-noinit.a init_term_dyn.o start_dyn.o' - ;; + LDFLAGS="$LDFLAGS -L/boot/home/config/lib -lbe -lroot" + ;; i586*) : ${LDSHARED="ld -shared"} - DLDFLAGS="$DLDFLAGS -L/boot/develop/lib/x86 -lbe -lroot" + DLDFLAGS="$DLDFLAGS -L/boot/develop/lib/x86 -L/boot/home/config/lib \$(topdir)/_APP_ -lbe -lroot" + LDFLAGS="$LDFLAGS -L/boot/develop/lib/x86 -L/boot/home/config/lib -lbe -lroot" ;; esac : ${LIBPATHENV=LIBRARY_PATH} @@ -1455,7 +1457,7 @@ if test "$with_dln_a_out" != yes; then hiuxmpp) : ${LDSHARED='ld -r'} ;; atheos*) : ${LDSHARED="$CC -shared"} rb_cv_dlopen=yes ;; - os2-emx*) LDFLAGS="$LDFLAGS -Zbsd-signals" + os2-emx*) LDFLAGS="$LDFLAGS -Zomf" ;; *) : ${LDSHARED='ld'} ;; esac @@ -1799,7 +1801,7 @@ case "$target_os" in MINIDLNOBJ=dmydln.o ;; os2-emx) - CFLAGS="$CFLAGS -DOS2 -Zmts" + CFLAGS="$CFLAGS -DOS2" LIBRUBY_A=`echo $LIBRUBY_A | sed 's/^lib//'` LIBRUBY_SO=`echo $LIBRUBY_SO | sed 's/^lib//'` LIBRUBY_ALIASES=`for i in $LIBRUBY_ALIASES; do echo "$i"; done | sed 's/^lib//'` @@ -1826,6 +1828,7 @@ case "$target_os" in CFLAGS="$CFLAGS -relax_pointers" ;; esac + CPPFLAGS="$CPPFLAGS -I/boot/home/config/include" ;; cygwin*|mingw*) LIBRUBY_DLDFLAGS="${DLDFLAGS}"' -Wl,--out-implib=$(LIBRUBY)' @@ -1442,7 +1442,8 @@ dln_load(const char *file) /* load extention module */ img_id = load_add_on(file); if (img_id <= 0) { - rb_loaderror("Failed to load %.200s", file); + rb_loaderror("Failed to load add_on %.200s error_code=%x", + file, img_id); } /* find symbol for module initialize function. */ diff --git a/enc/big5.c b/enc/big5.c index 70a316ea2c..9993f472e1 100644 --- a/enc/big5.c +++ b/enc/big5.c @@ -165,7 +165,7 @@ static const char BIG5_CAN_BE_TRAIL_TABLE[256] = { #define BIG5_ISMB_TRAIL(byte) BIG5_CAN_BE_TRAIL_TABLE[(byte)] static UChar* -big5_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +big5_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { const UChar *p; int len; @@ -181,7 +181,7 @@ big5_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) } } } - len = enclen(enc, p, s); + len = enclen(enc, p, end); if (p + len > s) return (UChar* )p; p += len; return (UChar* )(p + ((s - p) & ~1)); diff --git a/enc/cp949.c b/enc/cp949.c index 0046460625..009443aed4 100644 --- a/enc/cp949.c +++ b/enc/cp949.c @@ -165,7 +165,7 @@ cp949_is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc) } static UChar* -cp949_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +cp949_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { const UChar *p; int len; @@ -181,7 +181,7 @@ cp949_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc } } } - len = enclen(enc, p, s); + len = enclen(enc, p, end); if (p + len > s) return (UChar* )p; p += len; return (UChar* )(p + ((s - p) & ~1)); diff --git a/enc/euc_jp.c b/enc/euc_jp.c index fb8bf41c25..21f30ad2f3 100644 --- a/enc/euc_jp.c +++ b/enc/euc_jp.c @@ -222,7 +222,7 @@ mbc_case_fold(OnigCaseFoldType flag, } static UChar* -left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { /* In this encoding mb-trail bytes doesn't mix with single bytes. @@ -234,7 +234,7 @@ left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) p = s; while (!eucjp_islead(*p) && p > start) p--; - len = enclen(enc, p, s); + len = enclen(enc, p, end); if (p + len > s) return (UChar* )p; p += len; return (UChar* )(p + ((s - p) & ~1)); diff --git a/enc/euc_kr.c b/enc/euc_kr.c index 1b5ec893c1..f20a57e69a 100644 --- a/enc/euc_kr.c +++ b/enc/euc_kr.c @@ -145,7 +145,7 @@ euckr_is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc) #define euckr_islead(c) ((c) < 0xa1 || (c) == 0xff) static UChar* -euckr_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +euckr_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { /* Assumed in this encoding, mb-trail bytes don't mix with single bytes. @@ -157,7 +157,7 @@ euckr_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc p = s; while (!euckr_islead(*p) && p > start) p--; - len = enclen(enc, p, s); + len = enclen(enc, p, end); if (p + len > s) return (UChar* )p; p += len; return (UChar* )(p + ((s - p) & ~1)); diff --git a/enc/euc_tw.c b/enc/euc_tw.c index ca38983d53..d025a0dd45 100644 --- a/enc/euc_tw.c +++ b/enc/euc_tw.c @@ -187,7 +187,7 @@ euctw_is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc) #define euctw_islead(c) ((UChar )((c) - 0xa1) > 0xfe - 0xa1) static UChar* -euctw_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +euctw_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { /* Assumed in this encoding, mb-trail bytes don't mix with single bytes. @@ -199,7 +199,7 @@ euctw_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc p = s; while (!euctw_islead(*p) && p > start) p--; - len = enclen(enc, p, s); + len = enclen(enc, p, end); if (p + len > s) return (UChar* )p; p += len; return (UChar* )(p + ((s - p) & ~1)); diff --git a/enc/gb18030.c b/enc/gb18030.c index 2b707d4a7d..16c8c1c17f 100644 --- a/enc/gb18030.c +++ b/enc/gb18030.c @@ -245,7 +245,7 @@ enum state { }; static UChar* -gb18030_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +gb18030_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { const UChar *p; enum state state = S_START; @@ -165,7 +165,7 @@ gbk_is_code_ctype(OnigCodePoint code, unsigned int ctype, OnigEncoding enc) } static UChar* -gbk_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +gbk_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { const UChar *p; int len; @@ -181,7 +181,7 @@ gbk_left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) } } } - len = enclen(enc, p, s); + len = enclen(enc, p, end); if (p + len > s) return (UChar* )p; p += len; return (UChar* )(p + ((s - p) & ~1)); diff --git a/enc/shift_jis.c b/enc/shift_jis.c index f74afffa92..b4d8592a27 100644 --- a/enc/shift_jis.c +++ b/enc/shift_jis.c @@ -229,7 +229,7 @@ is_code_ctype(OnigCodePoint code, unsigned int ctype) #endif static UChar* -left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) +left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc) { const UChar *p; int len; @@ -245,7 +245,7 @@ left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc) } } } - len = enclen(enc, p, s); + len = enclen(enc, p, end); if (p + len > s) return (UChar* )p; p += len; return (UChar* )(p + ((s - p) & ~1)); diff --git a/enc/utf_16be.c b/enc/utf_16be.c index ccae9397bb..8d7c8e9b11 100644 --- a/enc/utf_16be.c +++ b/enc/utf_16be.c @@ -212,7 +212,7 @@ utf16be_is_mbc_ambiguous(OnigCaseFoldType flag, const UChar** pp, const UChar* e #endif static UChar* -utf16be_left_adjust_char_head(const UChar* start, const UChar* s, +utf16be_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc ARG_UNUSED) { if (s <= start) return (UChar* )s; diff --git a/enc/utf_16le.c b/enc/utf_16le.c index c3712f4e18..c8a1e7a10a 100644 --- a/enc/utf_16le.c +++ b/enc/utf_16le.c @@ -204,7 +204,7 @@ utf16le_is_mbc_ambiguous(OnigCaseFoldType flag, const UChar** pp, #endif static UChar* -utf16le_left_adjust_char_head(const UChar* start, const UChar* s, +utf16le_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc ARG_UNUSED) { if (s <= start) return (UChar* )s; diff --git a/enc/utf_32be.c b/enc/utf_32be.c index ed6c9b7f3b..61e7d0f1b5 100644 --- a/enc/utf_32be.c +++ b/enc/utf_32be.c @@ -152,7 +152,7 @@ utf32be_is_mbc_ambiguous(OnigCaseFoldType flag, const UChar** pp, const UChar* e #endif static UChar* -utf32be_left_adjust_char_head(const UChar* start, const UChar* s, +utf32be_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc ARG_UNUSED) { int rem; diff --git a/enc/utf_32le.c b/enc/utf_32le.c index 53e3522070..3a0a41bba7 100644 --- a/enc/utf_32le.c +++ b/enc/utf_32le.c @@ -152,7 +152,7 @@ utf32le_is_mbc_ambiguous(OnigCaseFoldType flag, const UChar** pp, const UChar* e #endif static UChar* -utf32le_left_adjust_char_head(const UChar* start, const UChar* s, +utf32le_left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc ARG_UNUSED) { int rem; diff --git a/enc/utf_8.c b/enc/utf_8.c index b8ee92feb4..3b9387c613 100644 --- a/enc/utf_8.c +++ b/enc/utf_8.c @@ -405,7 +405,7 @@ get_ctype_code_range(OnigCtype ctype, OnigCodePoint *sb_out, static UChar* -left_adjust_char_head(const UChar* start, const UChar* s, OnigEncoding enc ARG_UNUSED) +left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc ARG_UNUSED) { const UChar *p; diff --git a/encoding.c b/encoding.c index 3752d1c73a..78887de730 100644 --- a/encoding.c +++ b/encoding.c @@ -18,7 +18,7 @@ #endif #include "ruby/util.h" -static ID id_encoding, id_base_encoding; +static ID id_encoding; VALUE rb_cEncoding; static VALUE rb_encoding_list; @@ -42,7 +42,6 @@ void rb_enc_init(void); #define enc_autoload_p(enc) (!rb_enc_mbmaxlen(enc)) static int load_encoding(const char *name); -static VALUE enc_base_encoding(VALUE self); static void enc_mark(void *ptr) @@ -545,14 +544,31 @@ rb_id_encoding(void) int rb_enc_get_index(VALUE obj) { - int i; - - i = ENCODING_GET_INLINED(obj); - if (i == ENCODING_INLINE_MAX) { - VALUE iv; + int i = -1; + VALUE tmp; - iv = rb_ivar_get(obj, rb_id_encoding()); - i = NUM2INT(iv); + switch (BUILTIN_TYPE(obj)) { + default: + case T_STRING: + case T_REGEXP: + i = ENCODING_GET_INLINED(obj); + if (i == ENCODING_INLINE_MAX) { + VALUE iv; + + iv = rb_ivar_get(obj, rb_id_encoding()); + i = NUM2INT(iv); + } + break; + case T_FILE: + tmp = rb_funcall(obj, rb_intern("internal_encoding"), 0, 0); + if (NIL_P(tmp)) obj = rb_funcall(obj, rb_intern("external_encoding"), 0, 0); + else obj = tmp; + if (NIL_P(obj)) break; + case T_DATA: + if (RDATA(obj)->dmark == enc_mark) { + i = enc_check_encoding(obj); + } + break; } return i; } @@ -631,9 +647,11 @@ rb_enc_compatible(VALUE str1, VALUE str2) if (!rb_enc_asciicompat(enc1) || !rb_enc_asciicompat(enc2)) { return 0; } - if (BUILTIN_TYPE(str2) == T_REGEXP && idx2 == ENCINDEX_US_ASCII) + + /* objects whose encoding is the same of contents */ + if (BUILTIN_TYPE(str2) != T_STRING && idx2 == ENCINDEX_US_ASCII) return enc1; - if (BUILTIN_TYPE(str1) == T_REGEXP && idx1 == ENCINDEX_US_ASCII) + if (BUILTIN_TYPE(str1) != T_STRING && idx1 == ENCINDEX_US_ASCII) return enc2; if (BUILTIN_TYPE(str1) != T_STRING) { @@ -805,14 +823,6 @@ enc_name(VALUE self) return rb_usascii_str_new2(rb_enc_name((rb_encoding*)DATA_PTR(self))); } -static VALUE -enc_base_encoding(VALUE self) -{ - rb_encoding *base = enc_table.list[must_encoding(self)].base; - if (!base) return Qnil; - return ENC_FROM_ENCODING(base); -} - /* * call-seq: * Encoding.list => [enc1, enc2, ...] @@ -880,14 +890,6 @@ enc_compatible_p(VALUE klass, VALUE str1, VALUE str2) { rb_encoding *enc; - if (SPECIAL_CONST_P(str1) || TYPE(str1) != T_STRING && TYPE(str1) != T_REGEXP) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Regexp)", - rb_obj_classname(str1)); - } - if (SPECIAL_CONST_P(str2) || TYPE(str2) != T_STRING && TYPE(str2) != T_REGEXP) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Regexp)", - rb_obj_classname(str2)); - } if (!enc_capable(str1)) return Qnil; if (!enc_capable(str2)) return Qnil; enc = rb_enc_compatible(str1, str2); @@ -986,11 +988,15 @@ rb_filesystem_encoding(void) } static int default_external_index; +static rb_encoding *default_external; rb_encoding * rb_default_external_encoding(void) { - return rb_enc_from_index(default_external_index); + if (!default_external) { + default_external = rb_enc_from_index(default_external_index); + } + return default_external; } VALUE @@ -1017,6 +1023,7 @@ void rb_enc_set_default_external(VALUE encoding) { default_external_index = rb_enc_to_index(rb_to_encoding(encoding)); + default_external = 0; } /* @@ -1188,14 +1195,11 @@ Init_Encoding(void) VALUE list; int i; - id_base_encoding = rb_intern("#base_encoding"); - rb_cEncoding = rb_define_class("Encoding", rb_cObject); rb_undef_alloc_func(rb_cEncoding); rb_define_method(rb_cEncoding, "to_s", enc_name, 0); rb_define_method(rb_cEncoding, "inspect", enc_inspect, 0); rb_define_method(rb_cEncoding, "name", enc_name, 0); - rb_define_method(rb_cEncoding, "base_encoding", enc_base_encoding, 0); rb_define_method(rb_cEncoding, "dummy?", enc_dummy_p, 0); rb_define_singleton_method(rb_cEncoding, "list", enc_list, 0); rb_define_singleton_method(rb_cEncoding, "name_list", rb_enc_name_list, 0); @@ -1209,10 +1213,11 @@ Init_Encoding(void) rb_define_singleton_method(rb_cEncoding, "default_external", get_default_external, 0); rb_define_singleton_method(rb_cEncoding, "locale_charmap", rb_locale_charmap, 0); - rb_gc_register_address(&rb_encoding_list); list = rb_ary_new2(enc_table.count); RBASIC(list)->klass = 0; rb_encoding_list = list; + rb_gc_register_mark_object(list); + for (i = 0; i < enc_table.count; ++i) { rb_ary_push(list, enc_new(enc_table.list[i].enc)); } @@ -323,12 +323,12 @@ VALUE rb_eIndexError; VALUE rb_eKeyError; VALUE rb_eRangeError; VALUE rb_eNameError; +VALUE rb_eEncCompatError; VALUE rb_eNoMethodError; VALUE rb_eSecurityError; VALUE rb_eNotImpError; VALUE rb_eNoMemError; VALUE rb_cNameErrorMesg; -VALUE rb_eEncCompatError; VALUE rb_eScriptError; VALUE rb_eSyntaxError; @@ -1033,7 +1033,6 @@ Init_Exception(void) rb_eIndexError = rb_define_class("IndexError", rb_eStandardError); rb_eKeyError = rb_define_class("KeyError", rb_eIndexError); rb_eRangeError = rb_define_class("RangeError", rb_eStandardError); - rb_eEncCompatError = rb_define_class("EncodingCompatibilityError", rb_eStandardError); rb_eScriptError = rb_define_class("ScriptError", rb_eException); rb_eSyntaxError = rb_define_class("SyntaxError", rb_eScriptError); @@ -1057,6 +1056,7 @@ Init_Exception(void) rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError); rb_eSecurityError = rb_define_class("SecurityError", rb_eException); rb_eNoMemError = rb_define_class("NoMemoryError", rb_eException); + rb_eEncCompatError = rb_define_class_under(rb_cEncoding, "CompatibilityError", rb_eStandardError); syserr_tbl = st_init_numtable(); rb_eSystemCallError = rb_define_class("SystemCallError", rb_eStandardError); @@ -1129,9 +1129,6 @@ rb_f_method_name(void) void Init_eval(void) { - /* TODO: fix position */ - GET_THREAD()->vm->mark_object_ary = rb_ary_new(); - rb_define_virtual_variable("$@", errat_getter, errat_setter); rb_define_virtual_variable("$!", errinfo_getter, 0); diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 754c319991..fbc2474edf 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -579,13 +579,6 @@ BigDecimal_to_i(VALUE self) return rb_cstr2inum(psz,10); } -static VALUE -BigDecimal_induced_from(VALUE self, VALUE x) -{ - Real *p = GetVpValue(x,1); - return p->obj; -} - /* Returns a new Float object having approximately the same value as the * BigDecimal number. Normal accuracy limits and built-in errors of binary * Float arithmetic apply. @@ -1807,7 +1800,6 @@ Init_bigdecimal(void) rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1); rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1); rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0); - rb_define_singleton_method(rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1); rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1); rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0); @@ -3944,7 +3936,12 @@ VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, con es = e*((S_INT)BASE_FIG); e = e * 10 + exp_chr[i] - '0'; if(es>e*((S_INT)BASE_FIG)) { - return VpException(VP_EXCEPTION_INFINITY,"exponent overflow",0); + VpException(VP_EXCEPTION_INFINITY,"exponent overflow",0); + sign = 1; + if(int_chr[0] == '-') sign = -1; + if(signe > 0) VpSetInf(a, sign); + else VpSetZero(a, sign); + return 1; } ++i; } @@ -4633,8 +4630,20 @@ VpPower(Real *y, Real *x, S_INT n) } goto Exit; } - if(!VpIsDef(x)) { - VpSetNaN(y); /* Not sure !!! */ + if(VpIsNaN(x)) { + VpSetNaN(y); + goto Exit; + } + if(VpIsInf(x)) { + if(n==0) { + VpSetOne(y); + goto Exit; + } + if(n>0) { + VpSetInf(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1); + goto Exit; + } + VpSetZero(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1); goto Exit; } diff --git a/ext/json/ext/generator/extconf.rb b/ext/json/ext/generator/extconf.rb index 86ed7e6367..88aaf40d70 100644 --- a/ext/json/ext/generator/extconf.rb +++ b/ext/json/ext/generator/extconf.rb @@ -2,9 +2,8 @@ require 'mkmf' require 'rbconfig' if CONFIG['CC'] =~ /gcc/ - #$CFLAGS += ' -Wall -ggdb' $CFLAGS += ' -Wall' + #$CFLAGS += ' -O0 -ggdb' end -have_header 'st.h' -create_makefile 'json/ext/generator' +create_makefile 'generator' diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index b8a1ea16d1..1f48d3c780 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -1,15 +1,8 @@ -/* vim: set cin et sw=4 ts=4: */ - +#include <string.h> #include "ruby.h" -#include "ruby/st.h" #include "unicode.h" -#include <string.h> #include <math.h> -#ifdef HAVE_IEEEFP_H -#include <ieeefp.h> -#endif - #define check_max_nesting(state, depth) do { \ long current_nesting = 1 + depth; \ if (state->max_nesting != 0 && current_nesting > state->max_nesting) \ @@ -297,14 +290,14 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self) return rb_funcall(self, i_to_s, 0); } else { tmp = rb_funcall(self, i_to_s, 0); - rb_raise(eGeneratorError, "%s not allowed in JSON", StringValueCStr(tmp)); + rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp)); } } else if (isnan(value)) { if (!state || state->allow_nan) { return rb_funcall(self, i_to_s, 0); } else { tmp = rb_funcall(self, i_to_s, 0); - rb_raise(eGeneratorError, "%s not allowed in JSON", StringValueCStr(tmp)); + rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp)); } } else { return rb_funcall(self, i_to_s, 0); diff --git a/ext/json/ext/generator/unicode.c b/ext/json/ext/generator/unicode.c index 44e1f41f98..76834eadc5 100644 --- a/ext/json/ext/generator/unicode.c +++ b/ext/json/ext/generator/unicode.c @@ -1,5 +1,3 @@ -/* vim: set cin et sw=4 ts=4: */ - #include "unicode.h" #define unicode_escape(buffer, character) \ diff --git a/ext/json/ext/parser/extconf.rb b/ext/json/ext/parser/extconf.rb index b2e7b051a4..f511bf07da 100644 --- a/ext/json/ext/parser/extconf.rb +++ b/ext/json/ext/parser/extconf.rb @@ -2,9 +2,8 @@ require 'mkmf' require 'rbconfig' if CONFIG['CC'] =~ /gcc/ - #$CFLAGS += ' -Wall -ggdb' $CFLAGS += ' -Wall' + #$CFLAGS += ' -O0 -ggdb' end -have_header 'st.h' -create_makefile 'json/ext/parser' +create_makefile 'parser' diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 8734de2f5b..fe85b26cee 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -1,10 +1,5 @@ #line 1 "parser.rl" -/* vim: set cin et sw=4 ts=4: */ - #include "ruby.h" -#include "ruby/re.h" -#include "ruby/st.h" -#include "ruby/encoding.h" #include "unicode.h" #define EVIL 0x666 @@ -39,18 +34,18 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul JSON_Parser *json; \ Data_Get_Struct(self, JSON_Parser, json); -#line 67 "parser.rl" +#line 64 "parser.rl" -#line 47 "parser.c" +#line 44 "parser.c" static const int JSON_object_start = 1; static const int JSON_object_first_final = 27; static const int JSON_object_error = 0; static const int JSON_object_en_main = 1; -#line 100 "parser.rl" +#line 97 "parser.rl" static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -65,16 +60,16 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu *result = rb_hash_new(); -#line 69 "parser.c" +#line 66 "parser.c" { cs = JSON_object_start; } -#line 114 "parser.rl" +#line 111 "parser.rl" -#line 75 "parser.c" +#line 72 "parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { case 1: @@ -82,10 +77,11 @@ case 1: goto st2; goto st0; st0: - goto _out0; +cs = 0; + goto _out; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: switch( (*p) ) { case 13: goto st2; @@ -98,17 +94,17 @@ case 2: goto st2; goto st0; tr2: -#line 86 "parser.rl" +#line 83 "parser.rl" { char *np = JSON_parse_string(json, p, pe, &last_name); - if (np == NULL) goto _out3; else {p = (( np))-1;} + if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else {p = (( np))-1;} } goto st3; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: -#line 112 "parser.c" +#line 110 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -120,7 +116,7 @@ case 3: goto st0; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: switch( (*p) ) { case 42: goto st5; @@ -129,14 +125,14 @@ case 4: goto st0; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: if ( (*p) == 42 ) goto st6; goto st5; st6: if ( ++p == pe ) - goto _out6; + goto _test_eof6; case 6: switch( (*p) ) { case 42: goto st6; @@ -145,14 +141,14 @@ case 6: goto st5; st7: if ( ++p == pe ) - goto _out7; + goto _test_eof7; case 7: if ( (*p) == 10 ) goto st3; goto st7; st8: if ( ++p == pe ) - goto _out8; + goto _test_eof8; case 8: switch( (*p) ) { case 13: goto st8; @@ -175,12 +171,12 @@ case 8: goto st8; goto st0; tr11: -#line 75 "parser.rl" +#line 72 "parser.rl" { VALUE v = Qnil; char *np = JSON_parse_value(json, p, pe, &v); if (np == NULL) { - goto _out9; + p--; {p++; cs = 9; goto _out;} } else { rb_hash_aset(*result, last_name, v); {p = (( np))-1;} @@ -189,9 +185,9 @@ tr11: goto st9; st9: if ( ++p == pe ) - goto _out9; + goto _test_eof9; case 9: -#line 195 "parser.c" +#line 193 "parser.c" switch( (*p) ) { case 13: goto st9; case 32: goto st9; @@ -204,7 +200,7 @@ case 9: goto st0; st10: if ( ++p == pe ) - goto _out10; + goto _test_eof10; case 10: switch( (*p) ) { case 13: goto st10; @@ -217,7 +213,7 @@ case 10: goto st0; st11: if ( ++p == pe ) - goto _out11; + goto _test_eof11; case 11: switch( (*p) ) { case 42: goto st12; @@ -226,14 +222,14 @@ case 11: goto st0; st12: if ( ++p == pe ) - goto _out12; + goto _test_eof12; case 12: if ( (*p) == 42 ) goto st13; goto st12; st13: if ( ++p == pe ) - goto _out13; + goto _test_eof13; case 13: switch( (*p) ) { case 42: goto st13; @@ -242,14 +238,14 @@ case 13: goto st12; st14: if ( ++p == pe ) - goto _out14; + goto _test_eof14; case 14: if ( (*p) == 10 ) goto st10; goto st14; st15: if ( ++p == pe ) - goto _out15; + goto _test_eof15; case 15: switch( (*p) ) { case 42: goto st16; @@ -258,14 +254,14 @@ case 15: goto st0; st16: if ( ++p == pe ) - goto _out16; + goto _test_eof16; case 16: if ( (*p) == 42 ) goto st17; goto st16; st17: if ( ++p == pe ) - goto _out17; + goto _test_eof17; case 17: switch( (*p) ) { case 42: goto st17; @@ -274,24 +270,24 @@ case 17: goto st16; st18: if ( ++p == pe ) - goto _out18; + goto _test_eof18; case 18: if ( (*p) == 10 ) goto st9; goto st18; tr4: -#line 91 "parser.rl" - { goto _out27; } +#line 88 "parser.rl" + { p--; {p++; cs = 27; goto _out;} } goto st27; st27: if ( ++p == pe ) - goto _out27; + goto _test_eof27; case 27: -#line 291 "parser.c" +#line 289 "parser.c" goto st0; st19: if ( ++p == pe ) - goto _out19; + goto _test_eof19; case 19: switch( (*p) ) { case 42: goto st20; @@ -300,14 +296,14 @@ case 19: goto st0; st20: if ( ++p == pe ) - goto _out20; + goto _test_eof20; case 20: if ( (*p) == 42 ) goto st21; goto st20; st21: if ( ++p == pe ) - goto _out21; + goto _test_eof21; case 21: switch( (*p) ) { case 42: goto st21; @@ -316,14 +312,14 @@ case 21: goto st20; st22: if ( ++p == pe ) - goto _out22; + goto _test_eof22; case 22: if ( (*p) == 10 ) goto st8; goto st22; st23: if ( ++p == pe ) - goto _out23; + goto _test_eof23; case 23: switch( (*p) ) { case 42: goto st24; @@ -332,14 +328,14 @@ case 23: goto st0; st24: if ( ++p == pe ) - goto _out24; + goto _test_eof24; case 24: if ( (*p) == 42 ) goto st25; goto st24; st25: if ( ++p == pe ) - goto _out25; + goto _test_eof25; case 25: switch( (*p) ) { case 42: goto st25; @@ -348,43 +344,43 @@ case 25: goto st24; st26: if ( ++p == pe ) - goto _out26; + goto _test_eof26; case 26: if ( (*p) == 10 ) goto st2; goto st26; } - _out0: cs = 0; goto _out; - _out2: cs = 2; goto _out; - _out3: cs = 3; goto _out; - _out4: cs = 4; goto _out; - _out5: cs = 5; goto _out; - _out6: cs = 6; goto _out; - _out7: cs = 7; goto _out; - _out8: cs = 8; goto _out; - _out9: cs = 9; goto _out; - _out10: cs = 10; goto _out; - _out11: cs = 11; goto _out; - _out12: cs = 12; goto _out; - _out13: cs = 13; goto _out; - _out14: cs = 14; goto _out; - _out15: cs = 15; goto _out; - _out16: cs = 16; goto _out; - _out17: cs = 17; goto _out; - _out18: cs = 18; goto _out; - _out27: cs = 27; goto _out; - _out19: cs = 19; goto _out; - _out20: cs = 20; goto _out; - _out21: cs = 21; goto _out; - _out22: cs = 22; goto _out; - _out23: cs = 23; goto _out; - _out24: cs = 24; goto _out; - _out25: cs = 25; goto _out; - _out26: cs = 26; goto _out; - + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof9: cs = 9; goto _test_eof; + _test_eof10: cs = 10; goto _test_eof; + _test_eof11: cs = 11; goto _test_eof; + _test_eof12: cs = 12; goto _test_eof; + _test_eof13: cs = 13; goto _test_eof; + _test_eof14: cs = 14; goto _test_eof; + _test_eof15: cs = 15; goto _test_eof; + _test_eof16: cs = 16; goto _test_eof; + _test_eof17: cs = 17; goto _test_eof; + _test_eof18: cs = 18; goto _test_eof; + _test_eof27: cs = 27; goto _test_eof; + _test_eof19: cs = 19; goto _test_eof; + _test_eof20: cs = 20; goto _test_eof; + _test_eof21: cs = 21; goto _test_eof; + _test_eof22: cs = 22; goto _test_eof; + _test_eof23: cs = 23; goto _test_eof; + _test_eof24: cs = 24; goto _test_eof; + _test_eof25: cs = 25; goto _test_eof; + _test_eof26: cs = 26; goto _test_eof; + + _test_eof: {} _out: {} } -#line 115 "parser.rl" +#line 112 "parser.rl" if (cs >= JSON_object_first_final) { if (RTEST(json->create_id)) { @@ -403,14 +399,14 @@ case 26: } -#line 407 "parser.c" +#line 405 "parser.c" static const int JSON_value_start = 1; static const int JSON_value_first_final = 21; static const int JSON_value_error = 0; static const int JSON_value_en_main = 1; -#line 213 "parser.rl" +#line 210 "parser.rl" static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -418,16 +414,16 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 422 "parser.c" +#line 420 "parser.c" { cs = JSON_value_start; } -#line 220 "parser.rl" +#line 217 "parser.rl" -#line 428 "parser.c" +#line 426 "parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { case 1: @@ -446,259 +442,260 @@ case 1: goto tr2; goto st0; st0: - goto _out0; +cs = 0; + goto _out; tr0: -#line 161 "parser.rl" +#line 158 "parser.rl" { char *np = JSON_parse_string(json, p, pe, result); - if (np == NULL) goto _out21; else {p = (( np))-1;} + if (np == NULL) { p--; {p++; cs = 21; goto _out;} } else {p = (( np))-1;} } goto st21; tr2: -#line 166 "parser.rl" +#line 163 "parser.rl" { char *np; if(pe > p + 9 && !strncmp(MinusInfinity, p, 9)) { if (json->allow_nan) { *result = CMinusInfinity; {p = (( p + 10))-1;} - goto _out21; + p--; {p++; cs = 21; goto _out;} } else { - rb_raise(eParserError, "unexpected token at '%s'", p); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p); } } np = JSON_parse_float(json, p, pe, result); if (np != NULL) {p = (( np))-1;} np = JSON_parse_integer(json, p, pe, result); if (np != NULL) {p = (( np))-1;} - goto _out21; + p--; {p++; cs = 21; goto _out;} } goto st21; tr5: -#line 184 "parser.rl" +#line 181 "parser.rl" { char *np; - json->current_nesting += 1; + json->current_nesting++; np = JSON_parse_array(json, p, pe, result); - json->current_nesting -= 1; - if (np == NULL) goto _out21; else {p = (( np))-1;} + json->current_nesting--; + if (np == NULL) { p--; {p++; cs = 21; goto _out;} } else {p = (( np))-1;} } goto st21; tr9: -#line 192 "parser.rl" +#line 189 "parser.rl" { char *np; - json->current_nesting += 1; + json->current_nesting++; np = JSON_parse_object(json, p, pe, result); - json->current_nesting -= 1; - if (np == NULL) goto _out21; else {p = (( np))-1;} + json->current_nesting--; + if (np == NULL) { p--; {p++; cs = 21; goto _out;} } else {p = (( np))-1;} } goto st21; tr16: -#line 154 "parser.rl" +#line 151 "parser.rl" { if (json->allow_nan) { *result = CInfinity; } else { - rb_raise(eParserError, "unexpected token at '%s'", p - 8); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8); } } goto st21; tr18: -#line 147 "parser.rl" +#line 144 "parser.rl" { if (json->allow_nan) { *result = CNaN; } else { - rb_raise(eParserError, "unexpected token at '%s'", p - 2); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2); } } goto st21; tr22: -#line 141 "parser.rl" +#line 138 "parser.rl" { *result = Qfalse; } goto st21; tr25: -#line 138 "parser.rl" +#line 135 "parser.rl" { *result = Qnil; } goto st21; tr28: -#line 144 "parser.rl" +#line 141 "parser.rl" { *result = Qtrue; } goto st21; st21: if ( ++p == pe ) - goto _out21; + goto _test_eof21; case 21: -#line 200 "parser.rl" - { goto _out21; } -#line 542 "parser.c" +#line 197 "parser.rl" + { p--; {p++; cs = 21; goto _out;} } +#line 541 "parser.c" goto st0; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: if ( (*p) == 110 ) goto st3; goto st0; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: if ( (*p) == 102 ) goto st4; goto st0; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: if ( (*p) == 105 ) goto st5; goto st0; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: if ( (*p) == 110 ) goto st6; goto st0; st6: if ( ++p == pe ) - goto _out6; + goto _test_eof6; case 6: if ( (*p) == 105 ) goto st7; goto st0; st7: if ( ++p == pe ) - goto _out7; + goto _test_eof7; case 7: if ( (*p) == 116 ) goto st8; goto st0; st8: if ( ++p == pe ) - goto _out8; + goto _test_eof8; case 8: if ( (*p) == 121 ) goto tr16; goto st0; st9: if ( ++p == pe ) - goto _out9; + goto _test_eof9; case 9: if ( (*p) == 97 ) goto st10; goto st0; st10: if ( ++p == pe ) - goto _out10; + goto _test_eof10; case 10: if ( (*p) == 78 ) goto tr18; goto st0; st11: if ( ++p == pe ) - goto _out11; + goto _test_eof11; case 11: if ( (*p) == 97 ) goto st12; goto st0; st12: if ( ++p == pe ) - goto _out12; + goto _test_eof12; case 12: if ( (*p) == 108 ) goto st13; goto st0; st13: if ( ++p == pe ) - goto _out13; + goto _test_eof13; case 13: if ( (*p) == 115 ) goto st14; goto st0; st14: if ( ++p == pe ) - goto _out14; + goto _test_eof14; case 14: if ( (*p) == 101 ) goto tr22; goto st0; st15: if ( ++p == pe ) - goto _out15; + goto _test_eof15; case 15: if ( (*p) == 117 ) goto st16; goto st0; st16: if ( ++p == pe ) - goto _out16; + goto _test_eof16; case 16: if ( (*p) == 108 ) goto st17; goto st0; st17: if ( ++p == pe ) - goto _out17; + goto _test_eof17; case 17: if ( (*p) == 108 ) goto tr25; goto st0; st18: if ( ++p == pe ) - goto _out18; + goto _test_eof18; case 18: if ( (*p) == 114 ) goto st19; goto st0; st19: if ( ++p == pe ) - goto _out19; + goto _test_eof19; case 19: if ( (*p) == 117 ) goto st20; goto st0; st20: if ( ++p == pe ) - goto _out20; + goto _test_eof20; case 20: if ( (*p) == 101 ) goto tr28; goto st0; } - _out0: cs = 0; goto _out; - _out21: cs = 21; goto _out; - _out2: cs = 2; goto _out; - _out3: cs = 3; goto _out; - _out4: cs = 4; goto _out; - _out5: cs = 5; goto _out; - _out6: cs = 6; goto _out; - _out7: cs = 7; goto _out; - _out8: cs = 8; goto _out; - _out9: cs = 9; goto _out; - _out10: cs = 10; goto _out; - _out11: cs = 11; goto _out; - _out12: cs = 12; goto _out; - _out13: cs = 13; goto _out; - _out14: cs = 14; goto _out; - _out15: cs = 15; goto _out; - _out16: cs = 16; goto _out; - _out17: cs = 17; goto _out; - _out18: cs = 18; goto _out; - _out19: cs = 19; goto _out; - _out20: cs = 20; goto _out; - + _test_eof21: cs = 21; goto _test_eof; + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof9: cs = 9; goto _test_eof; + _test_eof10: cs = 10; goto _test_eof; + _test_eof11: cs = 11; goto _test_eof; + _test_eof12: cs = 12; goto _test_eof; + _test_eof13: cs = 13; goto _test_eof; + _test_eof14: cs = 14; goto _test_eof; + _test_eof15: cs = 15; goto _test_eof; + _test_eof16: cs = 16; goto _test_eof; + _test_eof17: cs = 17; goto _test_eof; + _test_eof18: cs = 18; goto _test_eof; + _test_eof19: cs = 19; goto _test_eof; + _test_eof20: cs = 20; goto _test_eof; + + _test_eof: {} _out: {} } -#line 221 "parser.rl" +#line 218 "parser.rl" if (cs >= JSON_value_first_final) { return p; @@ -708,14 +705,14 @@ case 20: } -#line 712 "parser.c" +#line 711 "parser.c" static const int JSON_integer_start = 1; static const int JSON_integer_first_final = 5; static const int JSON_integer_error = 0; static const int JSON_integer_en_main = 1; -#line 237 "parser.rl" +#line 234 "parser.rl" static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -723,17 +720,17 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res int cs = EVIL; -#line 727 "parser.c" +#line 726 "parser.c" { cs = JSON_integer_start; } -#line 244 "parser.rl" +#line 241 "parser.rl" json->memo = p; -#line 734 "parser.c" +#line 733 "parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { case 1: @@ -745,10 +742,11 @@ case 1: goto st4; goto st0; st0: - goto _out0; +cs = 0; + goto _out; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: if ( (*p) == 48 ) goto st3; @@ -757,38 +755,38 @@ case 2: goto st0; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: if ( 48 <= (*p) && (*p) <= 57 ) goto st0; goto tr4; tr4: -#line 234 "parser.rl" - { goto _out5; } +#line 231 "parser.rl" + { p--; {p++; cs = 5; goto _out;} } goto st5; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: #line 774 "parser.c" goto st0; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: if ( 48 <= (*p) && (*p) <= 57 ) goto st4; goto tr4; } - _out0: cs = 0; goto _out; - _out2: cs = 2; goto _out; - _out3: cs = 3; goto _out; - _out5: cs = 5; goto _out; - _out4: cs = 4; goto _out; + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof: {} _out: {} } -#line 246 "parser.rl" +#line 243 "parser.rl" if (cs >= JSON_integer_first_final) { long len = p - json->memo; @@ -807,7 +805,7 @@ static const int JSON_float_error = 0; static const int JSON_float_en_main = 1; -#line 268 "parser.rl" +#line 265 "parser.rl" static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -819,13 +817,13 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul { cs = JSON_float_start; } -#line 275 "parser.rl" +#line 272 "parser.rl" json->memo = p; #line 826 "parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { case 1: @@ -837,10 +835,11 @@ case 1: goto st9; goto st0; st0: - goto _out0; +cs = 0; + goto _out; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: if ( (*p) == 48 ) goto st3; @@ -849,7 +848,7 @@ case 2: goto st0; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: switch( (*p) ) { case 46: goto st4; @@ -859,14 +858,14 @@ case 3: goto st0; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: if ( 48 <= (*p) && (*p) <= 57 ) goto st5; goto st0; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: switch( (*p) ) { case 69: goto st6; @@ -879,18 +878,18 @@ case 5: goto st0; goto tr7; tr7: -#line 262 "parser.rl" - { goto _out10; } +#line 259 "parser.rl" + { p--; {p++; cs = 10; goto _out;} } goto st10; st10: if ( ++p == pe ) - goto _out10; + goto _test_eof10; case 10: -#line 890 "parser.c" +#line 891 "parser.c" goto st0; st6: if ( ++p == pe ) - goto _out6; + goto _test_eof6; case 6: switch( (*p) ) { case 43: goto st7; @@ -901,14 +900,14 @@ case 6: goto st0; st7: if ( ++p == pe ) - goto _out7; + goto _test_eof7; case 7: if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; st8: if ( ++p == pe ) - goto _out8; + goto _test_eof8; case 8: switch( (*p) ) { case 69: goto st0; @@ -922,7 +921,7 @@ case 8: goto tr7; st9: if ( ++p == pe ) - goto _out9; + goto _test_eof9; case 9: switch( (*p) ) { case 46: goto st4; @@ -933,20 +932,20 @@ case 9: goto st9; goto st0; } - _out0: cs = 0; goto _out; - _out2: cs = 2; goto _out; - _out3: cs = 3; goto _out; - _out4: cs = 4; goto _out; - _out5: cs = 5; goto _out; - _out10: cs = 10; goto _out; - _out6: cs = 6; goto _out; - _out7: cs = 7; goto _out; - _out8: cs = 8; goto _out; - _out9: cs = 9; goto _out; - + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof10: cs = 10; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof9: cs = 9; goto _test_eof; + + _test_eof: {} _out: {} } -#line 277 "parser.rl" +#line 274 "parser.rl" if (cs >= JSON_float_first_final) { long len = p - json->memo; @@ -959,14 +958,14 @@ case 9: -#line 963 "parser.c" +#line 964 "parser.c" static const int JSON_array_start = 1; static const int JSON_array_first_final = 17; static const int JSON_array_error = 0; static const int JSON_array_en_main = 1; -#line 313 "parser.rl" +#line 310 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -979,16 +978,16 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul *result = rb_ary_new(); -#line 983 "parser.c" +#line 984 "parser.c" { cs = JSON_array_start; } -#line 325 "parser.rl" +#line 322 "parser.rl" -#line 989 "parser.c" +#line 990 "parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { case 1: @@ -996,10 +995,11 @@ case 1: goto st2; goto st0; st0: - goto _out0; +cs = 0; + goto _out; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: switch( (*p) ) { case 13: goto st2; @@ -1023,12 +1023,12 @@ case 2: goto st2; goto st0; tr2: -#line 294 "parser.rl" +#line 291 "parser.rl" { VALUE v = Qnil; char *np = JSON_parse_value(json, p, pe, &v); if (np == NULL) { - goto _out3; + p--; {p++; cs = 3; goto _out;} } else { rb_ary_push(*result, v); {p = (( np))-1;} @@ -1037,9 +1037,9 @@ tr2: goto st3; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: -#line 1043 "parser.c" +#line 1045 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -1052,7 +1052,7 @@ case 3: goto st0; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: switch( (*p) ) { case 13: goto st4; @@ -1076,7 +1076,7 @@ case 4: goto st0; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: switch( (*p) ) { case 42: goto st6; @@ -1085,14 +1085,14 @@ case 5: goto st0; st6: if ( ++p == pe ) - goto _out6; + goto _test_eof6; case 6: if ( (*p) == 42 ) goto st7; goto st6; st7: if ( ++p == pe ) - goto _out7; + goto _test_eof7; case 7: switch( (*p) ) { case 42: goto st7; @@ -1101,14 +1101,14 @@ case 7: goto st6; st8: if ( ++p == pe ) - goto _out8; + goto _test_eof8; case 8: if ( (*p) == 10 ) goto st4; goto st8; st9: if ( ++p == pe ) - goto _out9; + goto _test_eof9; case 9: switch( (*p) ) { case 42: goto st10; @@ -1117,14 +1117,14 @@ case 9: goto st0; st10: if ( ++p == pe ) - goto _out10; + goto _test_eof10; case 10: if ( (*p) == 42 ) goto st11; goto st10; st11: if ( ++p == pe ) - goto _out11; + goto _test_eof11; case 11: switch( (*p) ) { case 42: goto st11; @@ -1133,24 +1133,24 @@ case 11: goto st10; st12: if ( ++p == pe ) - goto _out12; + goto _test_eof12; case 12: if ( (*p) == 10 ) goto st3; goto st12; tr4: -#line 305 "parser.rl" - { goto _out17; } +#line 302 "parser.rl" + { p--; {p++; cs = 17; goto _out;} } goto st17; st17: if ( ++p == pe ) - goto _out17; + goto _test_eof17; case 17: -#line 1150 "parser.c" +#line 1152 "parser.c" goto st0; st13: if ( ++p == pe ) - goto _out13; + goto _test_eof13; case 13: switch( (*p) ) { case 42: goto st14; @@ -1159,14 +1159,14 @@ case 13: goto st0; st14: if ( ++p == pe ) - goto _out14; + goto _test_eof14; case 14: if ( (*p) == 42 ) goto st15; goto st14; st15: if ( ++p == pe ) - goto _out15; + goto _test_eof15; case 15: switch( (*p) ) { case 42: goto st15; @@ -1175,44 +1175,44 @@ case 15: goto st14; st16: if ( ++p == pe ) - goto _out16; + goto _test_eof16; case 16: if ( (*p) == 10 ) goto st2; goto st16; } - _out0: cs = 0; goto _out; - _out2: cs = 2; goto _out; - _out3: cs = 3; goto _out; - _out4: cs = 4; goto _out; - _out5: cs = 5; goto _out; - _out6: cs = 6; goto _out; - _out7: cs = 7; goto _out; - _out8: cs = 8; goto _out; - _out9: cs = 9; goto _out; - _out10: cs = 10; goto _out; - _out11: cs = 11; goto _out; - _out12: cs = 12; goto _out; - _out17: cs = 17; goto _out; - _out13: cs = 13; goto _out; - _out14: cs = 14; goto _out; - _out15: cs = 15; goto _out; - _out16: cs = 16; goto _out; - + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof9: cs = 9; goto _test_eof; + _test_eof10: cs = 10; goto _test_eof; + _test_eof11: cs = 11; goto _test_eof; + _test_eof12: cs = 12; goto _test_eof; + _test_eof17: cs = 17; goto _test_eof; + _test_eof13: cs = 13; goto _test_eof; + _test_eof14: cs = 14; goto _test_eof; + _test_eof15: cs = 15; goto _test_eof; + _test_eof16: cs = 16; goto _test_eof; + + _test_eof: {} _out: {} } -#line 326 "parser.rl" +#line 323 "parser.rl" if(cs >= JSON_array_first_final) { return p + 1; } else { - rb_raise(eParserError, "unexpected token at '%s'", p); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p); } } static VALUE json_string_unescape(char *p, char *pe) { - VALUE result = rb_enc_str_new("", 0, rb_utf8_encoding()); + VALUE result = rb_str_buf_new(pe - p + 1); while (p < pe) { if (*p == '\\') { @@ -1267,33 +1267,33 @@ static VALUE json_string_unescape(char *p, char *pe) } -#line 1271 "parser.c" +#line 1273 "parser.c" static const int JSON_string_start = 1; static const int JSON_string_first_final = 8; static const int JSON_string_error = 0; static const int JSON_string_en_main = 1; -#line 404 "parser.rl" +#line 401 "parser.rl" static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result) { int cs = EVIL; - *result = rb_enc_str_new("", 0, rb_utf8_encoding()); + *result = rb_str_new("", 0); -#line 1287 "parser.c" +#line 1289 "parser.c" { cs = JSON_string_start; } -#line 412 "parser.rl" +#line 409 "parser.rl" json->memo = p; -#line 1294 "parser.c" +#line 1296 "parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { case 1: @@ -1301,10 +1301,11 @@ case 1: goto st2; goto st0; st0: - goto _out0; +cs = 0; + goto _out; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: switch( (*p) ) { case 34: goto tr2; @@ -1314,23 +1315,23 @@ case 2: goto st0; goto st2; tr2: -#line 396 "parser.rl" +#line 393 "parser.rl" { *result = json_string_unescape(json->memo + 1, p); - if (NIL_P(*result)) goto _out8; else {p = (( p + 1))-1;} + if (NIL_P(*result)) { p--; {p++; cs = 8; goto _out;} } else {p = (( p + 1))-1;} } -#line 401 "parser.rl" - { goto _out8; } +#line 398 "parser.rl" + { p--; {p++; cs = 8; goto _out;} } goto st8; st8: if ( ++p == pe ) - goto _out8; + goto _test_eof8; case 8: -#line 1330 "parser.c" +#line 1333 "parser.c" goto st0; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: if ( (*p) == 117 ) goto st4; @@ -1339,7 +1340,7 @@ case 3: goto st2; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -1352,7 +1353,7 @@ case 4: goto st0; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -1365,7 +1366,7 @@ case 5: goto st0; st6: if ( ++p == pe ) - goto _out6; + goto _test_eof6; case 6: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -1378,7 +1379,7 @@ case 6: goto st0; st7: if ( ++p == pe ) - goto _out7; + goto _test_eof7; case 7: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -1390,18 +1391,18 @@ case 7: goto st2; goto st0; } - _out0: cs = 0; goto _out; - _out2: cs = 2; goto _out; - _out8: cs = 8; goto _out; - _out3: cs = 3; goto _out; - _out4: cs = 4; goto _out; - _out5: cs = 5; goto _out; - _out6: cs = 6; goto _out; - _out7: cs = 7; goto _out; - + _test_eof2: cs = 2; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + + _test_eof: {} _out: {} } -#line 414 "parser.rl" +#line 411 "parser.rl" if (cs >= JSON_string_first_final) { return p + 1; @@ -1412,14 +1413,14 @@ case 7: -#line 1416 "parser.c" +#line 1419 "parser.c" static const int JSON_start = 1; static const int JSON_first_final = 10; static const int JSON_error = 0; static const int JSON_en_main = 1; -#line 448 "parser.rl" +#line 445 "parser.rl" /* @@ -1542,23 +1543,23 @@ static VALUE cParser_parse(VALUE self) GET_STRUCT; -#line 1546 "parser.c" +#line 1549 "parser.c" { cs = JSON_start; } -#line 570 "parser.rl" +#line 567 "parser.rl" p = json->source; pe = p + json->len; -#line 1554 "parser.c" +#line 1557 "parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { st1: if ( ++p == pe ) - goto _out1; + goto _test_eof1; case 1: switch( (*p) ) { case 13: goto st1; @@ -1571,10 +1572,11 @@ case 1: goto st1; goto st0; st0: - goto _out0; +cs = 0; + goto _out; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: switch( (*p) ) { case 42: goto st3; @@ -1583,14 +1585,14 @@ case 2: goto st0; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: if ( (*p) == 42 ) goto st4; goto st3; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: switch( (*p) ) { case 42: goto st4; @@ -1599,34 +1601,34 @@ case 4: goto st3; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: if ( (*p) == 10 ) goto st1; goto st5; tr3: -#line 437 "parser.rl" +#line 434 "parser.rl" { char *np; json->current_nesting = 1; np = JSON_parse_array(json, p, pe, &result); - if (np == NULL) goto _out10; else {p = (( np))-1;} + if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; tr4: -#line 430 "parser.rl" +#line 427 "parser.rl" { char *np; json->current_nesting = 1; np = JSON_parse_object(json, p, pe, &result); - if (np == NULL) goto _out10; else {p = (( np))-1;} + if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; st10: if ( ++p == pe ) - goto _out10; + goto _test_eof10; case 10: -#line 1630 "parser.c" +#line 1634 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -1637,7 +1639,7 @@ case 10: goto st0; st6: if ( ++p == pe ) - goto _out6; + goto _test_eof6; case 6: switch( (*p) ) { case 42: goto st7; @@ -1646,14 +1648,14 @@ case 6: goto st0; st7: if ( ++p == pe ) - goto _out7; + goto _test_eof7; case 7: if ( (*p) == 42 ) goto st8; goto st7; st8: if ( ++p == pe ) - goto _out8; + goto _test_eof8; case 8: switch( (*p) ) { case 42: goto st8; @@ -1662,32 +1664,32 @@ case 8: goto st7; st9: if ( ++p == pe ) - goto _out9; + goto _test_eof9; case 9: if ( (*p) == 10 ) goto st10; goto st9; } - _out1: cs = 1; goto _out; - _out0: cs = 0; goto _out; - _out2: cs = 2; goto _out; - _out3: cs = 3; goto _out; - _out4: cs = 4; goto _out; - _out5: cs = 5; goto _out; - _out10: cs = 10; goto _out; - _out6: cs = 6; goto _out; - _out7: cs = 7; goto _out; - _out8: cs = 8; goto _out; - _out9: cs = 9; goto _out; - + _test_eof1: cs = 1; goto _test_eof; + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof10: cs = 10; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof9: cs = 9; goto _test_eof; + + _test_eof: {} _out: {} } -#line 573 "parser.rl" +#line 570 "parser.rl" if (cs >= JSON_first_final && p == pe) { return result; } else { - rb_raise(eParserError, "unexpected token at '%s'", p); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p); } } @@ -1729,6 +1731,7 @@ static VALUE cParser_source(VALUE self) void Init_parser() { + rb_require("json/common"); mJSON = rb_define_module("JSON"); mExt = rb_define_module_under(mJSON, "Ext"); cParser = rb_define_class_under(mExt, "Parser", rb_cObject); diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index c25b1278f7..8325a93795 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -1,9 +1,4 @@ -/* vim: set cin et sw=4 ts=4: */ - #include "ruby.h" -#include "ruby/re.h" -#include "ruby/st.h" -#include "ruby/encoding.h" #include "unicode.h" #define EVIL 0x666 @@ -76,7 +71,7 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul VALUE v = Qnil; char *np = JSON_parse_value(json, fpc, pe, &v); if (np == NULL) { - fbreak; + fhold; fbreak; } else { rb_hash_aset(*result, last_name, v); fexec np; @@ -85,10 +80,10 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul action parse_name { char *np = JSON_parse_string(json, fpc, pe, &last_name); - if (np == NULL) fbreak; else fexec np; + if (np == NULL) { fhold; fbreak; } else fexec np; } - action exit { fbreak; } + action exit { fhold; fbreak; } a_pair = ignore* begin_name >parse_name ignore* name_separator ignore* @@ -148,19 +143,19 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu if (json->allow_nan) { *result = CNaN; } else { - rb_raise(eParserError, "unexpected token at '%s'", p - 2); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2); } } action parse_infinity { if (json->allow_nan) { *result = CInfinity; } else { - rb_raise(eParserError, "unexpected token at '%s'", p - 8); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8); } } action parse_string { char *np = JSON_parse_string(json, fpc, pe, result); - if (np == NULL) fbreak; else fexec np; + if (np == NULL) { fhold; fbreak; } else fexec np; } action parse_number { @@ -169,35 +164,35 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu if (json->allow_nan) { *result = CMinusInfinity; fexec p + 10; - fbreak; + fhold; fbreak; } else { - rb_raise(eParserError, "unexpected token at '%s'", p); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p); } } np = JSON_parse_float(json, fpc, pe, result); if (np != NULL) fexec np; np = JSON_parse_integer(json, fpc, pe, result); if (np != NULL) fexec np; - fbreak; + fhold; fbreak; } action parse_array { char *np; - json->current_nesting += 1; + json->current_nesting++; np = JSON_parse_array(json, fpc, pe, result); - json->current_nesting -= 1; - if (np == NULL) fbreak; else fexec np; + json->current_nesting--; + if (np == NULL) { fhold; fbreak; } else fexec np; } action parse_object { char *np; - json->current_nesting += 1; + json->current_nesting++; np = JSON_parse_object(json, fpc, pe, result); - json->current_nesting -= 1; - if (np == NULL) fbreak; else fexec np; + json->current_nesting--; + if (np == NULL) { fhold; fbreak; } else fexec np; } - action exit { fbreak; } + action exit { fhold; fbreak; } main := ( Vnull @parse_null | @@ -231,7 +226,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul write data; - action exit { fbreak; } + action exit { fhold; fbreak; } main := '-'? ('0' | [1-9][0-9]*) (^[0-9] @exit); }%% @@ -259,7 +254,7 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res write data; - action exit { fbreak; } + action exit { fhold; fbreak; } main := '-'? ( (('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?) @@ -295,14 +290,14 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul VALUE v = Qnil; char *np = JSON_parse_value(json, fpc, pe, &v); if (np == NULL) { - fbreak; + fhold; fbreak; } else { rb_ary_push(*result, v); fexec np; } } - action exit { fbreak; } + action exit { fhold; fbreak; } next_element = value_separator ignore* begin_value >parse_value; @@ -327,13 +322,13 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if(cs >= JSON_array_first_final) { return p + 1; } else { - rb_raise(eParserError, "unexpected token at '%s'", p); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p); } } static VALUE json_string_unescape(char *p, char *pe) { - VALUE result = rb_enc_str_new(0, pe - p + 1, rb_utf8_encoding()); + VALUE result = rb_str_buf_new(pe - p + 1); while (p < pe) { if (*p == '\\') { @@ -395,10 +390,10 @@ static VALUE json_string_unescape(char *p, char *pe) action parse_string { *result = json_string_unescape(json->memo + 1, p); - if (NIL_P(*result)) fbreak; else fexec p + 1; + if (NIL_P(*result)) { fhold; fbreak; } else fexec p + 1; } - action exit { fbreak; } + action exit { fhold; fbreak; } main := '"' ((^(["\\] | 0..0x1f) | '\\'["\\/bfnrt] | '\\u'[0-9a-fA-F]{4} | '\\'^(["\\/bfnrtu]|0..0x1f))* %parse_string) '"' @exit; }%% @@ -407,7 +402,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu { int cs = EVIL; - *result = rb_enc_str_new("", 0, rb_utf8_encoding()); + *result = rb_str_new("", 0); %% write init; json->memo = p; %% write exec; @@ -431,14 +426,14 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu char *np; json->current_nesting = 1; np = JSON_parse_object(json, fpc, pe, &result); - if (np == NULL) fbreak; else fexec np; + if (np == NULL) { fhold; fbreak; } else fexec np; } action parse_array { char *np; json->current_nesting = 1; np = JSON_parse_array(json, fpc, pe, &result); - if (np == NULL) fbreak; else fexec np; + if (np == NULL) { fhold; fbreak; } else fexec np; } main := ignore* ( @@ -574,7 +569,7 @@ static VALUE cParser_parse(VALUE self) if (cs >= JSON_first_final && p == pe) { return result; } else { - rb_raise(eParserError, "unexpected token at '%s'", p); + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p); } } @@ -616,6 +611,7 @@ static VALUE cParser_source(VALUE self) void Init_parser() { + rb_require("json/common"); mJSON = rb_define_module("JSON"); mExt = rb_define_module_under(mJSON, "Ext"); cParser = rb_define_class_under(mExt, "Parser", rb_cObject); diff --git a/ext/json/ext/parser/unicode.c b/ext/json/ext/parser/unicode.c index f196727354..b2f1e58676 100644 --- a/ext/json/ext/parser/unicode.c +++ b/ext/json/ext/parser/unicode.c @@ -1,5 +1,3 @@ -/* vim: set cin et sw=4 ts=4: */ - #include "unicode.h" /* @@ -105,7 +103,7 @@ char *JSON_convert_UTF16_to_UTF8 ( + (ch2 - UNI_SUR_LOW_START) + halfBase; ++tmpPtr; } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - ruby_xfree(tmp); + ruby_xfree(tmp); rb_raise(rb_path2class("JSON::ParserError"), "source sequence is illegal/malformed near %s", source); } diff --git a/ext/json/lib/json/add/core.rb b/ext/json/lib/json/add/core.rb index 630ed6e4b7..7121a77ff1 100644 --- a/ext/json/lib/json/add/core.rb +++ b/ext/json/lib/json/add/core.rb @@ -9,14 +9,21 @@ require 'date' class Time def self.json_create(object) - at(*object.values_at('s', 'u')) + if usec = object.delete('u') # used to be tv_usec -> tv_nsec + object['n'] = usec * 1000 + end + if respond_to?(:tv_nsec) + at(*object.values_at('s', 'n')) + else + at(object['s'], object['n'] / 1000) + end end def to_json(*args) { - 'json_class' => self.class.name.to_s, + 'json_class' => self.class.name, 's' => tv_sec, - 'u' => tv_usec, + 'n' => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000 }.to_json(*args) end end @@ -26,13 +33,15 @@ class Date civil(*object.values_at('y', 'm', 'd', 'sg')) end + alias start sg unless method_defined?(:start) + def to_json(*args) { - 'json_class' => self.class.name.to_s, + 'json_class' => self.class.name, 'y' => year, 'm' => month, 'd' => day, - 'sg' => @sg, + 'sg' => start, }.to_json(*args) end end @@ -41,14 +50,20 @@ class DateTime def self.json_create(object) args = object.values_at('y', 'm', 'd', 'H', 'M', 'S') of_a, of_b = object['of'].split('/') - args << Rational(of_a.to_i, of_b.to_i) + if of_b and of_b != '0' + args << Rational(of_a.to_i, of_b.to_i) + else + args << of_a + end args << object['sg'] civil(*args) end + alias start sg unless method_defined?(:start) + def to_json(*args) { - 'json_class' => self.class.name.to_s, + 'json_class' => self.class.name, 'y' => year, 'm' => month, 'd' => day, @@ -56,7 +71,7 @@ class DateTime 'M' => min, 'S' => sec, 'of' => offset.to_s, - 'sg' => @sg, + 'sg' => start, }.to_json(*args) end end @@ -68,7 +83,7 @@ class Range def to_json(*args) { - 'json_class' => self.class.name.to_s, + 'json_class' => self.class.name, 'a' => [ first, last, exclude_end? ] }.to_json(*args) end @@ -80,8 +95,8 @@ class Struct end def to_json(*args) - klass = self.class.name.to_s - klass.empty? and raise JSON::JSONError, "Only named structs are supported!" + klass = self.class.name + klass.nil? and raise JSON::JSONError, "Only named structs are supported!" { 'json_class' => klass, 'v' => values, @@ -98,7 +113,7 @@ class Exception def to_json(*args) { - 'json_class' => self.class.name.to_s, + 'json_class' => self.class.name, 'm' => message, 'b' => backtrace, }.to_json(*args) @@ -112,7 +127,7 @@ class Regexp def to_json(*) { - 'json_class' => self.class.name.to_s, + 'json_class' => self.class.name, 'o' => options, 's' => source, }.to_json diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb index 7bc5ae0656..499fcc0dae 100644 --- a/ext/json/lib/json/common.rb +++ b/ext/json/lib/json/common.rb @@ -2,7 +2,7 @@ require 'json/version' module JSON class << self - # If _object_ is string like parse the string and return the parsed result + # If _object_ is string-like parse the string and return the parsed result # as a Ruby data structure. Otherwise generate a JSON text from the Ruby # data structure object and return it. # @@ -184,7 +184,8 @@ module JSON end # :stopdoc: - # I want to deprecate these later, so I'll first be silent about them, and later delete them. + # I want to deprecate these later, so I'll first be silent about them, and + # later delete them. alias unparse generate module_function :unparse # :startdoc: @@ -238,7 +239,7 @@ module JSON # :startdoc: # Load a ruby data structure from a JSON _source_ and return it. A source can - # either be a string like object, an IO like object, or an object responding + # either be a string-like object, an IO like object, or an object responding # to the read method. If _proc_ was given, it will be called with any nested # Ruby object as an argument recursively in depth first order. # @@ -327,7 +328,7 @@ module ::Kernel nil end - # If _object_ is string like parse the string and return the parsed result as + # If _object_ is string-like parse the string and return the parsed result as # a Ruby data structure. Otherwise generate a JSON text from the Ruby data # structure object and return it. # @@ -351,4 +352,3 @@ class ::Class respond_to?(:json_create) end end - # vim: set et sw=2 ts=2: diff --git a/ext/json/lib/json/editor.rb b/ext/json/lib/json/editor.rb index 9a65400622..12a7f94591 100644 --- a/ext/json/lib/json/editor.rb +++ b/ext/json/lib/json/editor.rb @@ -1360,4 +1360,3 @@ module JSON end end end - # vim: set et sw=2 ts=2: diff --git a/ext/json/lib/json/pure/parser.rb b/ext/json/lib/json/pure/parser.rb index 39bee54269..9b30f15c07 100644 --- a/ext/json/lib/json/pure/parser.rb +++ b/ext/json/lib/json/pure/parser.rb @@ -122,9 +122,8 @@ module JSON def parse_string if scan(STRING) return '' if self[1].empty? - self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do - c = $& - if u = UNESCAPE_MAP[c[1]] + self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c| + if u = UNESCAPE_MAP[$&[1]] u else # \uXXXX bytes = '' diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb index 3d674ac44f..acf8217048 100644 --- a/ext/json/lib/json/version.rb +++ b/ext/json/lib/json/version.rb @@ -1,6 +1,6 @@ module JSON # JSON version - VERSION = '1.1.2' + VERSION = '1.1.3' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: diff --git a/ext/nkf/nkf-utf8/nkf.c b/ext/nkf/nkf-utf8/nkf.c index a4ad15dcfb..3d690dcb37 100644 --- a/ext/nkf/nkf-utf8/nkf.c +++ b/ext/nkf/nkf-utf8/nkf.c @@ -318,7 +318,7 @@ extern POINT _BufferSize; #endif struct input_code{ - const char *name; + char *name; nkf_char stat; nkf_char score; nkf_char index; @@ -328,11 +328,10 @@ struct input_code{ int _file_stat; }; -static const char *input_codename = NULL; /* NULL: unestablished, "": BINARY */ +static char *input_codename = NULL; /* NULL: unestablished, "": BINARY */ static nkf_encoding *input_encoding = NULL; static nkf_encoding *output_encoding = NULL; -static int kanji_convert(FILE *f); #if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE) /* UCS Mapping * 0: Shift_JIS, eucJP-ascii @@ -439,7 +438,7 @@ static nkf_char (*iconv_for_check)(nkf_char c2,nkf_char c1,nkf_char c0) = 0; #endif static int guess_f = 0; /* 0: OFF, 1: ON, 2: VERBOSE */ -static void set_input_codename(const char *codename); +static void set_input_codename(char *codename); #ifdef EXEC_IO static int exec_f = 0; @@ -915,7 +914,8 @@ get_backup_filename(const char *suffix, const char *filename) } backup_filename[j] = '\0'; }else{ - backup_filename = malloc(filename_length + strlen(suffix) + 1); + j = filename_length + strlen(suffix); + backup_filename = malloc(j + 1); strcpy(backup_filename, filename); strcat(backup_filename, suffix); backup_filename[j] = '\0'; @@ -1472,6 +1472,7 @@ s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1) nkf_char val; #endif static const char shift_jisx0213_s1a3_table[5][2] ={ { 1, 8}, { 3, 4}, { 5,12}, {13,14}, {15, 0} }; + if (0xFC < c1) return 1; #ifdef SHIFTJIS_CP932 if (!cp932inv_f && is_ibmext_in_sjis(c2)){ val = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40]; @@ -1482,10 +1483,10 @@ s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1) } if (cp932inv_f && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){ - nkf_char c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40]; - if (c){ - c2 = c >> 8; - c1 = c & 0xff; + val = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40]; + if (val){ + c2 = val >> 8; + c1 = val & 0xff; } } #endif /* SHIFTJIS_CP932 */ @@ -2501,6 +2502,7 @@ w_oconv16(nkf_char c2, nkf_char c1) c1 = val & 0xff; if (!val) return; } + if (output_endian == ENDIAN_LITTLE){ (*o_putc)(c1); (*o_putc)(c2); @@ -3499,7 +3501,7 @@ z_conv(nkf_char c2, nkf_char c1) if (alpha_f&8 && c2 == 0) { /* HTML Entity */ - const char *entity = 0; + char *entity = 0; switch (c1){ case '>': entity = ">"; break; case '<': entity = "<"; break; @@ -3982,7 +3984,7 @@ debug(const char *str) #endif static void -set_input_codename(const char *codename) +set_input_codename(char *codename) { if (!input_codename) { input_codename = codename; @@ -3991,7 +3993,7 @@ set_input_codename(const char *codename) } } -static const char* +static char* get_guessed_code(void) { if (input_codename && !*input_codename) { @@ -5251,7 +5253,7 @@ kanji_convert(FILE *f) { nkf_char c1=0, c2=0, c3=0, c4=0; int shift_mode = 0; /* 0, 1, 2, 3 */ - char g2 = 0; + int g2 = 0; int is_8bit = FALSE; if (input_encoding && !nkf_enc_asciicompat(input_encoding)) { @@ -6085,9 +6087,9 @@ options(unsigned char *cp) cp++; input_endian = ENDIAN_BIG; } - enc_idx = enc_idx == UTF_16 + enc_idx = (enc_idx == UTF_16 ? (input_endian == ENDIAN_LITTLE ? UTF_16LE : UTF_16BE) - : (input_endian == ENDIAN_LITTLE ? UTF_32LE : UTF_32BE); + : (input_endian == ENDIAN_LITTLE ? UTF_32LE : UTF_32BE)); input_encoding = nkf_enc_from_index(enc_idx); } continue; diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index d4285f2069..caa140dc4b 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -463,8 +463,10 @@ static VALUE ossl_ec_key_to_string(VALUE self, int format) BIO *out; int i = -1; int private = 0; +#if 0 /* unused now */ EVP_CIPHER *cipher = NULL; char *password = NULL; +#endif VALUE str; Require_EC_KEY(self, ec); @@ -484,13 +486,18 @@ static VALUE ossl_ec_key_to_string(VALUE self, int format) switch(format) { case EXPORT_PEM: if (private) { +#if 0 /* unused now */ if (cipher || password) /* BUG: finish cipher/password key export */ rb_notimplement(); i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password); +#endif + i = PEM_write_bio_ECPrivateKey(out, ec, NULL, NULL, 0, NULL, NULL); } else { +#if 0 /* unused now */ if (cipher || password) rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); +#endif i = PEM_write_bio_EC_PUBKEY(out, ec); } @@ -498,13 +505,17 @@ static VALUE ossl_ec_key_to_string(VALUE self, int format) break; case EXPORT_DER: if (private) { +#if 0 /* unused now */ if (cipher || password) rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); +#endif i = i2d_ECPrivateKey_bio(out, ec); } else { +#if 0 /* unused now */ if (cipher || password) rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); +#endif i = i2d_EC_PUBKEY_bio(out, ec); } diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c index e99c4e462b..837a506a72 100644 --- a/ext/socket/getaddrinfo.c +++ b/ext/socket/getaddrinfo.c @@ -42,7 +42,7 @@ #include <sys/types.h> #ifndef _WIN32 #include <sys/param.h> -#if defined(__BEOS__) && !defined(__HAIKU__) +#if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE) # include <net/socket.h> #else # include <sys/socket.h> diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c index 37f60fc83f..aee81b5356 100644 --- a/ext/socket/getnameinfo.c +++ b/ext/socket/getnameinfo.c @@ -38,7 +38,7 @@ #include <stdio.h> #include <sys/types.h> #ifndef _WIN32 -#if defined(__BEOS__) && !defined(__HAIKU__) +#if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE) # include <net/socket.h> #else # include <sys/socket.h> diff --git a/ext/socket/mkconstants.rb b/ext/socket/mkconstants.rb index 46a6655bfc..bb05250805 100644 --- a/ext/socket/mkconstants.rb +++ b/ext/socket/mkconstants.rb @@ -143,6 +143,16 @@ IPPROTO_TP IPPROTO_XTP IPPROTO_EON IPPROTO_BIP +IPPROTO_AH +IPPROTO_DSTOPTS +IPPROTO_ESP +IPPROTO_FRAGMENT +IPPROTO_HOPOPTS +IPPROTO_ICMPV6 +IPPROTO_IPV6 +IPPROTO_NONE +IPPROTO_ROUTING + IPPROTO_RAW 255 IPPROTO_MAX @@ -232,6 +242,7 @@ EAI_FAMILY EAI_MEMORY EAI_NODATA EAI_NONAME +EAI_OVERFLOW EAI_SERVICE EAI_SOCKTYPE EAI_SYSTEM @@ -242,6 +253,7 @@ EAI_MAX AI_PASSIVE AI_CANONNAME AI_NUMERICHOST +AI_NUMERICSERV AI_MASK AI_ALL AI_V4MAPPED_CFG @@ -288,3 +300,6 @@ IPV6_RTHDR_TYPE_0 IPV6_RECVPATHMTU IPV6_TCLASS IPV6_USE_MIN_MTU + +INET_ADDRSTRLEN +INET6_ADDRSTRLEN diff --git a/ext/socket/socket.c b/ext/socket/socket.c index c753f19de3..698bc60996 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -28,7 +28,7 @@ #endif #ifndef _WIN32 -#if defined(__BEOS__) && !defined(__HAIKU__) +#if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE) # include <net/socket.h> #else # include <sys/socket.h> diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index 8b20e62b0c..7cffda2aed 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -8797,7 +8797,7 @@ void Init_win32ole() { ary_ole_event = rb_ary_new(); - rb_register_mark_object(ary_ole_event); + rb_gc_register_mark_object(ary_ole_event); id_events = rb_intern("events"); com_vtbl.QueryInterface = QueryInterface; @@ -8816,7 +8816,7 @@ Init_win32ole() message_filter.MessagePending = mf_MessagePending; com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable()); - rb_register_mark_object(com_hash); + rb_gc_register_mark_object(com_hash); cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject); @@ -722,7 +722,7 @@ rb_gc_disable(void) VALUE rb_mGC; void -rb_register_mark_object(VALUE obj) +rb_gc_register_mark_object(VALUE obj) { VALUE ary = GET_THREAD()->vm->mark_object_ary; rb_ary_push(ary, obj); @@ -1539,7 +1539,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) case T_COMPLEX: gc_mark(objspace, obj->as.complex.real, lev); - gc_mark(objspace, obj->as.complex.image, lev); + gc_mark(objspace, obj->as.complex.imag, lev); break; case T_STRUCT: @@ -39,8 +39,6 @@ static ID id_hash, id_yield, id_default; static int rb_any_cmp(VALUE a, VALUE b) { - VALUE args[2]; - if (a == b) return 0; if (FIXNUM_P(a) && FIXNUM_P(b)) { return a != b; @@ -54,8 +52,6 @@ rb_any_cmp(VALUE a, VALUE b) return a != b; } - args[0] = a; - args[1] = b; return !rb_eql(a, b); } diff --git a/include/ruby/defines.h b/include/ruby/defines.h index 1a0274ec81..d580135233 100644 --- a/include/ruby/defines.h +++ b/include/ruby/defines.h @@ -198,7 +198,7 @@ void xfree(void*); #include "vms/vms.h" #endif -#if defined(__BEOS__) && !defined(__HAIKU__) +#if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE) #include <net/socket.h> /* intern.h needs fd_set definition */ #endif diff --git a/include/ruby/encoding.h b/include/ruby/encoding.h index a69940e267..f2f7ba19b5 100644 --- a/include/ruby/encoding.h +++ b/include/ruby/encoding.h @@ -129,11 +129,11 @@ int rb_enc_codelen(int code, rb_encoding *enc); /* code,ptr,encoding -> write buf */ #define rb_enc_mbcput(c,buf,enc) ONIGENC_CODE_TO_MBC(enc,c,(UChar*)(buf)) -/* ptr, ptr, encoding -> prev_char */ -#define rb_enc_prev_char(s,p,enc) (char *)onigenc_get_prev_char_head(enc,(UChar*)(s),(UChar*)(p)) -/* ptr, ptr, encoding -> next_char */ -#define rb_enc_left_char_head(s,p,enc) (char *)onigenc_get_left_adjust_char_head(enc,(UChar*)(s),(UChar*)(p)) -#define rb_enc_right_char_head(s,p,enc) (char *)onigenc_get_right_adjust_char_head(enc,(UChar*)(s),(UChar*)(p)) +/* start, ptr, end, encoding -> prev_char */ +#define rb_enc_prev_char(s,p,e,enc) (char *)onigenc_get_prev_char_head(enc,(UChar*)(s),(UChar*)(p),(UChar*)(e)) +/* start, ptr, end, encoding -> next_char */ +#define rb_enc_left_char_head(s,p,e,enc) (char *)onigenc_get_left_adjust_char_head(enc,(UChar*)(s),(UChar*)(p),(UChar*)(e)) +#define rb_enc_right_char_head(s,p,e,enc) (char *)onigenc_get_right_adjust_char_head(enc,(UChar*)(s),(UChar*)(p),(UChar*)(e)) /* ptr, ptr, encoding -> newline_or_not */ #define rb_enc_is_newline(p,end,enc) ONIGENC_IS_MBC_NEWLINE(enc,(UChar*)(p),(UChar*)(end)) diff --git a/include/ruby/oniguruma.h b/include/ruby/oniguruma.h index 2e3b2bf293..bc6905edaa 100644 --- a/include/ruby/oniguruma.h +++ b/include/ruby/oniguruma.h @@ -164,7 +164,7 @@ typedef struct OnigEncodingTypeST { int (*property_name_to_ctype)(struct OnigEncodingTypeST* enc, OnigUChar* p, OnigUChar* end); int (*is_code_ctype)(OnigCodePoint code, OnigCtype ctype, struct OnigEncodingTypeST* enc); int (*get_ctype_code_range)(OnigCtype ctype, OnigCodePoint* sb_out, const OnigCodePoint* ranges[], struct OnigEncodingTypeST* enc); - OnigUChar* (*left_adjust_char_head)(const OnigUChar* start, const OnigUChar* p, struct OnigEncodingTypeST* enc); + OnigUChar* (*left_adjust_char_head)(const OnigUChar* start, const OnigUChar* p, const OnigUChar* end, struct OnigEncodingTypeST* enc); int (*is_allowed_reverse_match)(const OnigUChar* p, const OnigUChar* end, struct OnigEncodingTypeST* enc); int ruby_encoding_index; } OnigEncodingType; @@ -219,14 +219,14 @@ ONIG_EXTERN OnigEncodingType OnigEncodingASCII; (enc)->mbc_case_fold(flag,(const OnigUChar** )pp,end,buf,enc) #define ONIGENC_IS_ALLOWED_REVERSE_MATCH(enc,s,end) \ (enc)->is_allowed_reverse_match(s,end,enc) -#define ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc,start,s) \ - (enc)->left_adjust_char_head(start, s, enc) +#define ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc,start,s,end) \ + (enc)->left_adjust_char_head(start, s, end, enc) #define ONIGENC_APPLY_ALL_CASE_FOLD(enc,case_fold_flag,f,arg) \ (enc)->apply_all_case_fold(case_fold_flag,f,arg,enc) #define ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc,case_fold_flag,p,end,acs) \ (enc)->get_case_fold_codes_by_str(case_fold_flag,p,end,acs,enc) -#define ONIGENC_STEP_BACK(enc,start,s,n) \ - onigenc_step_back((enc),(start),(s),(n)) +#define ONIGENC_STEP_BACK(enc,start,s,end,n) \ + onigenc_step_back((enc),(start),(s),(end),(n)) #define ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(n) (n) #define ONIGENC_MBCLEN_CHARFOUND_P(r) (0 < (r)) @@ -290,7 +290,7 @@ int onigenc_mbclen_approximate P_((const OnigUChar* p,const OnigUChar* e, struct (enc)->get_ctype_code_range(ctype,sbout,ranges,enc) ONIG_EXTERN -OnigUChar* onigenc_step_back P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, int n)); +OnigUChar* onigenc_step_back P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, const OnigUChar* end, int n)); /* encoding API */ @@ -303,13 +303,13 @@ OnigEncoding onigenc_get_default_encoding P_((void)); ONIG_EXTERN void onigenc_set_default_caseconv_table P_((const OnigUChar* table)); ONIG_EXTERN -OnigUChar* onigenc_get_right_adjust_char_head_with_prev P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, const OnigUChar** prev)); +OnigUChar* onigenc_get_right_adjust_char_head_with_prev P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, const OnigUChar* end, const OnigUChar** prev)); ONIG_EXTERN -OnigUChar* onigenc_get_prev_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s)); +OnigUChar* onigenc_get_prev_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, const OnigUChar* end)); ONIG_EXTERN -OnigUChar* onigenc_get_left_adjust_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s)); +OnigUChar* onigenc_get_left_adjust_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, const OnigUChar* end)); ONIG_EXTERN -OnigUChar* onigenc_get_right_adjust_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s)); +OnigUChar* onigenc_get_right_adjust_char_head P_((OnigEncoding enc, const OnigUChar* start, const OnigUChar* s, const OnigUChar* end)); ONIG_EXTERN int onigenc_strlen P_((OnigEncoding enc, const OnigUChar* p, const OnigUChar* end)); ONIG_EXTERN diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index d8ae11b204..eb80bce4c2 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -650,7 +650,7 @@ struct RRational { struct RComplex { struct RBasic basic; VALUE real; - VALUE image; + VALUE imag; }; struct RData { @@ -851,7 +851,7 @@ void rb_define_alias(VALUE,const char*,const char*); void rb_define_attr(VALUE,const char*,int,int); void rb_global_variable(VALUE*); -void rb_register_mark_object(VALUE); +void rb_gc_register_mark_object(VALUE); void rb_gc_register_address(VALUE*); void rb_gc_unregister_address(VALUE*); @@ -982,6 +982,7 @@ RUBY_EXTERN VALUE rb_cCont; RUBY_EXTERN VALUE rb_cDir; RUBY_EXTERN VALUE rb_cData; RUBY_EXTERN VALUE rb_cFalseClass; +RUBY_EXTERN VALUE rb_cEncoding; RUBY_EXTERN VALUE rb_cEnumerator; RUBY_EXTERN VALUE rb_cFile; RUBY_EXTERN VALUE rb_cFixnum; @@ -34,7 +34,6 @@ void Init_marshal(void); void Init_Numeric(void); void Init_Object(void); void Init_pack(void); -void Init_Precision(void); void Init_sym(void); void Init_process(void); void Init_RandomSeed(void); @@ -66,7 +65,6 @@ rb_call_inits() Init_Encoding(); Init_Comparable(); Init_Enumerable(); - Init_Precision(); Init_String(); Init_Exception(); Init_eval(); @@ -2177,13 +2177,14 @@ rb_io_getline_1(VALUE rs, long limit, VALUE io) else enc = io_input_encoding(fptr); while ((c = appendline(fptr, newline, &str, &limit)) != EOF) { - const char *s, *p, *pp; + const char *s, *p, *pp, *e; if (c == newline) { if (RSTRING_LEN(str) < rslen) continue; s = RSTRING_PTR(str); - p = s + RSTRING_LEN(str) - rslen; - pp = rb_enc_left_char_head(s, p, enc); + e = s + RSTRING_LEN(str); + p = e - rslen; + pp = rb_enc_left_char_head(s, p, e, enc); if (pp != p) continue; if (!rspara) rscheck(rsptr, rslen, rs); if (memcmp(p, rsptr, rslen) == 0) break; @@ -2191,7 +2192,7 @@ rb_io_getline_1(VALUE rs, long limit, VALUE io) if (limit == 0) { s = RSTRING_PTR(str); p = s + RSTRING_LEN(str); - pp = rb_enc_left_char_head(s, p-1, enc); + pp = rb_enc_left_char_head(s, p-1, p, enc); if (extra_limit && MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) { /* relax the limit while incomplete character. @@ -2256,7 +2257,7 @@ rb_io_gets(VALUE io) * to <code>$_</code>. Returns <code>nil</code> if called at end of * file. If the first argument is an integer, or optional second * argument is given, the returning string would not be longer than the - * given value. + * given value in bytes. * * File.new("testfile").gets #=> "This is line one\n" * $_ #=> "This is line one\n" @@ -2362,8 +2363,8 @@ rb_io_readline(int argc, VALUE *argv, VALUE io) * <i>sep</i> is <code>nil</code>, the rest of the stream is returned * as a single record. If the first argument is an integer, or * optional second argument is given, the returning string would not be - * longer than the given value. The stream must be opened for reading - * or an <code>IOError</code> will be raised. + * longer than the given value in bytes. The stream must be opened for + * reading or an <code>IOError</code> will be raised. * * f = File.new("testfile") * f.readlines[0] #=> "This is line one\n" @@ -2747,7 +2748,7 @@ rb_io_getbyte(VALUE io) * call-seq: * ios.readbyte => fixnum * - * Reads a character as with <code>IO#getc</code>, but raises an + * Reads a byte as with <code>IO#getbyte</code>, but raises an * <code>EOFError</code> on end of file. */ @@ -3863,7 +3864,7 @@ validate_enc_binmode(int fmode, rb_encoding *enc, rb_encoding *enc2) } static void -rb_io_extract_modeenc(VALUE *vmode_p, VALUE opthash, +rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, convconfig_t *convconfig_p) { VALUE vmode; @@ -3871,7 +3872,7 @@ rb_io_extract_modeenc(VALUE *vmode_p, VALUE opthash, rb_encoding *enc, *enc2; int ecflags; VALUE ecopts; - int has_enc = 0; + int has_enc = 0, has_vmode = 0; VALUE intmode; vmode = *vmode_p; @@ -3890,6 +3891,8 @@ rb_io_extract_modeenc(VALUE *vmode_p, VALUE opthash, } else { const char *p; + + vmode_handle: SafeStringValue(vmode); p = StringValueCStr(vmode); fmode = rb_io_modestr_fmode(p); @@ -3908,15 +3911,38 @@ rb_io_extract_modeenc(VALUE *vmode_p, VALUE opthash, else { VALUE v; v = rb_hash_aref(opthash, sym_textmode); - if (RTEST(v)) + if (!NIL_P(v)) fmode |= FMODE_TEXTMODE; v = rb_hash_aref(opthash, sym_binmode); - if (RTEST(v)) { + if (!NIL_P(v)) { fmode |= FMODE_BINMODE; #ifdef O_BINARY oflags |= O_BINARY; #endif } + if (!has_vmode) { + v = rb_hash_aref(opthash, sym_mode); + if (!NIL_P(v)) { + if (!NIL_P(vmode)) { + rb_raise(rb_eArgError, "mode specified twice"); + } + has_vmode = 1; + vmode = v; + goto vmode_handle; + } + } + v = rb_hash_aref(opthash, sym_perm); + if (!NIL_P(v)) { + if (vperm_p) { + if (!NIL_P(*vperm_p)) { + rb_raise(rb_eArgError, "perm specified twice"); + } + *vperm_p = v; + } + else { + /* perm no use, just ignore */ + } + } ecflags = rb_econv_prepare_opts(opthash, &ecopts); if (io_extract_encoding_option(opthash, &enc, &enc2)) { @@ -4587,7 +4613,7 @@ rb_io_s_popen(int argc, VALUE *argv, VALUE klass) opt = pop_last_hash(&argc, &argv); rb_scan_args(argc, argv, "11", &pname, &pmode); - rb_io_extract_modeenc(&pmode, opt, &oflags, &fmode, &convconfig); + rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig); modestr = rb_io_oflags_modestr(oflags); tmp = rb_check_array_type(pname); @@ -4630,6 +4656,7 @@ rb_scan_open_args(int argc, VALUE *argv, opt = pop_last_hash(&argc, &argv); rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm); + FilePathValue(fname); #if defined _WIN32 || defined __APPLE__ { static rb_encoding *fs_encoding; @@ -4649,9 +4676,8 @@ rb_scan_open_args(int argc, VALUE *argv, } } #endif - FilePathValue(fname); - rb_io_extract_modeenc(&vmode, opt, &oflags, &fmode, convconfig_p); + rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p); perm = NIL_P(vperm) ? 0666 : NUM2UINT(vperm); @@ -4908,7 +4934,7 @@ rb_io_open(VALUE filename, VALUE vmode, VALUE vperm, VALUE opt) convconfig_t convconfig; mode_t perm; - rb_io_extract_modeenc(&vmode, opt, &oflags, &fmode, &convconfig); + rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig); perm = NIL_P(vperm) ? 0666 : NUM2UINT(vperm); if (!NIL_P(cmd = check_pipe_command(filename))) { @@ -5595,7 +5621,7 @@ rb_io_initialize(int argc, VALUE *argv, VALUE io) opt = pop_last_hash(&argc, &argv); rb_scan_args(argc, argv, "11", &fnum, &vmode); - rb_io_extract_modeenc(&vmode, opt, &oflags, &fmode, &convconfig); + rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig); fd = NUM2INT(fnum); UPDATE_MAXFD(fd); @@ -5993,9 +6019,9 @@ static VALUE argf_gets(int, VALUE *, VALUE); * reads the input one paragraph at a time, where paragraphs are * divided by two consecutive newlines. If the first argument is an * integer, or optional second argument is given, the returning string - * would not be longer than the given value. If multiple filenames are - * present in +ARGV+, +gets(nil)+ will read the contents one file at a - * time. + * would not be longer than the given value in bytes. If multiple + * filenames are present in +ARGV+, +gets(nil)+ will read the contents + * one file at a time. * * ARGV << "testfile" * print while gets @@ -6773,7 +6799,6 @@ static void open_key_args(int argc, VALUE *argv, struct foreach_arg *arg) { VALUE opt, v; - VALUE vmode, vperm; FilePathValue(argv[0]); arg->io = 0; @@ -6800,15 +6825,7 @@ open_key_args(int argc, VALUE *argv, struct foreach_arg *arg) arg->io = rb_io_open_with_args(RARRAY_LEN(args), RARRAY_PTR(args)); return; } - vmode = Qnil; - vperm = INT2NUM(O_RDONLY); - v = rb_hash_aref(opt, sym_mode); - if (!NIL_P(v)) - vmode = v; - v = rb_hash_aref(opt, sym_perm); - if (!NIL_P(v)) - vperm = v; - arg->io = rb_io_open(argv[0], vmode, vperm, opt); + arg->io = rb_io_open(argv[0], Qnil, INT2NUM(O_RDONLY), opt); } static VALUE @@ -8179,8 +8196,8 @@ Init_IO(void) rb_output_fs = Qnil; rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_str_setter); - rb_global_variable(&rb_default_rs); rb_rs = rb_default_rs = rb_str_new2("\n"); + rb_gc_register_mark_object(rb_default_rs); rb_output_rs = Qnil; OBJ_FREEZE(rb_default_rs); /* avoid modifying RS_default */ rb_define_hooked_variable("$/", &rb_rs, 0, rb_str_setter); diff --git a/lib/cmath.rb b/lib/cmath.rb index 55995879e6..d293401804 100644 --- a/lib/cmath.rb +++ b/lib/cmath.rb @@ -25,17 +25,17 @@ module CMath alias atanh! atanh def exp(z) - if z.scalar? + if z.real? exp!(z) else - Complex(exp!(z.real) * cos!(z.image), - exp!(z.real) * sin!(z.image)) + Complex(exp!(z.real) * cos!(z.imag), + exp!(z.real) * sin!(z.imag)) end end def log(*args) z, b = args - if z.scalar? and z >= 0 and (b.nil? or b >= 0) + if z.real? and z >= 0 and (b.nil? or b >= 0) log!(*args) else r, theta = z.polar @@ -48,7 +48,7 @@ module CMath end def log10(z) - if z.scalar? + if z.real? log10!(z) else log(z) / log!(10) @@ -56,14 +56,14 @@ module CMath end def sqrt(z) - if z.scalar? + if z.real? if z >= 0 sqrt!(z) else - Complex(0,sqrt!(-z)) + Complex(0, sqrt!(-z)) end else - if z.image < 0 + if z.imag < 0 sqrt(z.conjugate).conjugate else r = z.abs @@ -74,25 +74,25 @@ module CMath end def sin(z) - if z.scalar? + if z.real? sin!(z) else - Complex(sin!(z.real) * cosh!(z.image), - cos!(z.real) * sinh!(z.image)) + Complex(sin!(z.real) * cosh!(z.imag), + cos!(z.real) * sinh!(z.imag)) end end def cos(z) - if z.scalar? + if z.real? cos!(z) else - Complex(cos!(z.real) * cosh!(z.image), - -sin!(z.real) * sinh!(z.image)) + Complex(cos!(z.real) * cosh!(z.imag), + -sin!(z.real) * sinh!(z.imag)) end end def tan(z) - if z.scalar? + if z.real? tan!(z) else sin(z)/cos(z) @@ -100,25 +100,25 @@ module CMath end def sinh(z) - if z.scalar? + if z.real? sinh!(z) else - Complex(sinh!(z.real) * cos!(z.image), - cosh!(z.real) * sin!(z.image)) + Complex(sinh!(z.real) * cos!(z.imag), + cosh!(z.real) * sin!(z.imag)) end end def cosh(z) - if z.scalar? + if z.real? cosh!(z) else - Complex(cosh!(z.real) * cos!(z.image), - sinh!(z.real) * sin!(z.image)) + Complex(cosh!(z.real) * cos!(z.imag), + sinh!(z.real) * sin!(z.imag)) end end def tanh(z) - if z.scalar? + if z.real? tanh!(z) else sinh(z) / cosh(z) @@ -126,39 +126,39 @@ module CMath end def asin(z) - if z.scalar? and z >= -1 and z <= 1 + if z.real? and z >= -1 and z <= 1 asin!(z) else - -1.0.im * log(1.0.im * z + sqrt(1.0 - z * z)) + Complex(0, -1.0) * log(Complex(0, 1.0) * z + sqrt(1.0 - z * z)) end end def acos(z) - if z.scalar? and z >= -1 and z <= 1 + if z.real? and z >= -1 and z <= 1 acos!(z) else - -1.0.im * log(z + 1.0.im * sqrt(1.0 - z * z)) + Complex(0, -1.0) * log(z + Complex(0, 1.0) * sqrt(1.0 - z * z)) end end def atan(z) - if z.scalar? + if z.real? atan!(z) else - 1.0.im * log((1.0.im + z) / (1.0.im - z)) / 2.0 + Complex(0, 1.0) * log((Complex(0, 1.0) + z) / (Complex(0, 1.0) - z)) / 2.0 end end def atan2(y,x) - if y.scalar? and x.scalar? + if y.real? and x.real? atan2!(y,x) else - -1.0.im * log((x + 1.0.im * y) / sqrt(x * x + y * y)) + Complex(0, -1.0) * log((x + Complex(0, 1.0) * y) / sqrt(x * x + y * y)) end end def acosh(z) - if z.scalar? and z >= 1 + if z.real? and z >= 1 acosh!(z) else log(z + sqrt(z * z - 1.0)) @@ -166,7 +166,7 @@ module CMath end def asinh(z) - if z.scalar? + if z.real? asinh!(z) else log(z + sqrt(1.0 + z * z)) @@ -174,7 +174,7 @@ module CMath end def atanh(z) - if z.scalar? and z >= -1 and z <= 1 + if z.real? and z >= -1 and z <= 1 atanh!(z) else log((1.0 + z) / (1.0 - z)) / 2.0 diff --git a/lib/complex.rb b/lib/complex.rb index 1845f30b1f..301879143f 100644 --- a/lib/complex.rb +++ b/lib/complex.rb @@ -1,10 +1,24 @@ require 'cmath' -Object.instance_eval{remove_const :Math} -Math = CMath +unless defined?(Math.exp!) + Object.instance_eval{remove_const :Math} + Math = CMath +end def Complex.generic? (other) other.kind_of?(Integer) || other.kind_of?(Float) || other.kind_of?(Rational) end + +class Complex + + alias image imag + +end + +class Numeric + + def im() Complex(0, self) end + +end diff --git a/lib/csv.rb b/lib/csv.rb index f60d5b1cb0..dccee6cbe8 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1,5 +1,5 @@ -#!/usr/local/bin/ruby -w - +#!/usr/bin/env ruby -w +# encoding: UTF-8 # = csv.rb -- CSV Reading and Writing # # Created by James Edward Gray II on 2005-10-31. @@ -37,6 +37,7 @@ # # === CSV Parsing # +# * This parser is m17n aware. See CSV for full details. # * This library has a stricter parser and will throw MalformedCSVErrors on # problematic data. # * This library has a less liberal idea of a line ending than CSV. What you @@ -91,7 +92,6 @@ require "forwardable" require "English" -require "enumerator" require "date" require "stringio" @@ -130,7 +130,7 @@ require "stringio" # # === To a File # -# CSV.open("path/to/file.csv", "w") do |csv| +# CSV.open("path/to/file.csv", "wb") do |csv| # csv << ["row", "of", "CSV", "data"] # csv << ["another", "row"] # # ... @@ -155,9 +155,51 @@ require "stringio" # CSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String # CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr # +# == CSV and Character Encodings (M17n or Multilingualization) +# +# This new CSV parser is m17n savvy. The parser works in the Encoding of the IO +# or String object being read from or written to. Your data is never transcoded +# (unless you ask Ruby to transcode it for you) and will literally be parsed in +# the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the +# Encoding of your data. This is accomplished by transcoding the parser itself +# into your Encoding. +# +# Some transcoding must take place, of course, to accomplish this multiencoding +# support. For example, <tt>:col_sep</tt>, <tt>:row_sep</tt>, and +# <tt>:quote_char</tt> must be transcoded to match your data. Hopefully this +# makes the entire process feel transparent, since CSV's defaults should just +# magically work for you data. However, you can set these values manually in +# the target Encoding to avoid the translation. +# +# It's also important to note that while all of CSV's core parser is now +# Encoding agnostic, some features are not. For example, the built-in +# converters will try to transcode data to UTF-8 before making conversions. +# Again, you can provide custom converters that are aware of your Encodings to +# avoid this translation. It's just too hard for me to support native +# conversions in all of Ruby's Encodings. +# +# Anyway, the practical side of this is simple: make sure IO and String objects +# passed into CSV have the proper Encoding set and everything should just work. +# CSV methods that allow you to open IO objects (CSV::foreach(), CSV::open(), +# CSV::read(), and CSV::readlines()) do allow you to specify the Encoding. +# +# One minor exception comes when generating CSV into a String with an Encoding +# that is not ASCII compatible. There's no existing data for CSV to use to +# prepare itself and thus you will probably need to manually specify the desired +# Encoding for most of those cases. It will try to guess using the fields in a +# row of output though, when using CSV::generate_line() or Array#to_csv(). +# +# I try to point out any other Encoding issues in the documentation of methods +# as they come up. +# +# This has been tested to the best of my ability with all non-"dummy" Encodings +# Ruby ships with. However, it is brave new code and may have some bugs. +# Please feel free to {report}[mailto:james@grayproductions.net] any issues you +# find with it. +# class CSV # The version of the installed library. - VERSION = "2.0.0".freeze + VERSION = "2.4.0".freeze # # A CSV::Row is part Array and part Hash. It retains an order for the fields @@ -188,9 +230,9 @@ class CSV # handle extra headers or fields @row = if headers.size > fields.size - headers.each_with_index.map { |header, i| [header, fields[i]] } + headers.zip(fields) else - fields.each_with_index.map { |field, i| [headers[i], field] } + fields.zip(headers).map { |pair| pair.reverse } end end @@ -444,6 +486,17 @@ class CSV fields.to_csv(options) end alias_method :to_s, :to_csv + + # A summary of fields, by header, in an ASCII-8BIT String. + def inspect + str = ["#<", self.class.to_s] + each do |header, field| + str << " " << (header.is_a?(Symbol) ? header.to_s : header.inspect) << + ":" << field.inspect + end + str << ">" + str.map { |s| s.encode("ASCII-8BIT") }.join + end end # @@ -775,6 +828,11 @@ class CSV end.join end alias_method :to_s, :to_csv + + # Shows the mode and size of this table in a US-ASCII String. + def inspect + "#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>" + end end # The error thrown when the parser encounters illegal CSV formatting. @@ -799,6 +857,10 @@ class CSV DateTimeMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} | \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2} )\z /x + + # The encoding used by all converters. + ConverterEncoding = Encoding.find("UTF-8") + # # This Hash holds the built-in converters of CSV that can be accessed by name. # You can select Converters with CSV.convert() or through the +options+ Hash @@ -813,20 +875,38 @@ class CSV # <b><tt>:all</tt></b>:: All built-in converters. A combination of # <tt>:date_time</tt> and <tt>:numeric</tt>. # + # All built-in converters transcode field data to UTF-8 before attempting a + # conversion. If your data cannot be transcoded to UTF-8 the conversion will + # fail and the field will remain unchanged. + # # This Hash is intentionally left unfrozen and users should feel free to add # values to it that can be accessed by all CSV objects. # # To add a combo field, the value should be an Array of names. Combo fields # can be nested with other combo fields. # - Converters = { :integer => lambda { |f| Integer(f) rescue f }, - :float => lambda { |f| Float(f) rescue f }, + Converters = { :integer => lambda { |f| + Integer(f.encode(ConverterEncoding)) rescue f + }, + :float => lambda { |f| + Float(f.encode(ConverterEncoding)) rescue f + }, :numeric => [:integer, :float], :date => lambda { |f| - f =~ DateMatcher ? (Date.parse(f) rescue f) : f + begin + e = f.encode(ConverterEncoding) + e =~ DateMatcher ? Date.parse(e) : f + rescue # encoding conversion or date parse errors + f + end }, :date_time => lambda { |f| - f =~ DateTimeMatcher ? (DateTime.parse(f) rescue f) : f + begin + e = f.encode(ConverterEncoding) + e =~ DateTimeMatcher ? DateTime.parse(e) : f + rescue # encoding conversion or date parse errors + f + end }, :all => [:date_time, :numeric] } @@ -840,6 +920,10 @@ class CSV # replaced with underscores, non-word characters # are dropped, and finally to_sym() is called. # + # All built-in header converters transcode header data to UTF-8 before + # attempting a conversion. If your data cannot be transcoded to UTF-8 the + # conversion will fail and the header will remain unchanged. + # # This Hash is intetionally left unfrozen and users should feel free to add # values to it that can be accessed by all CSV objects. # @@ -847,9 +931,10 @@ class CSV # can be nested with other combo fields. # HeaderConverters = { - :downcase => lambda { |h| h.downcase }, + :downcase => lambda { |h| h.encode(ConverterEncoding).downcase }, :symbol => lambda { |h| - h.downcase.tr(" ", "_").delete("^a-z0-9_").to_sym + h.encode(ConverterEncoding). + downcase.tr(" ", "_").delete("^a-z0-9_").to_sym } } @@ -859,6 +944,7 @@ class CSV # <b><tt>:col_sep</tt></b>:: <tt>","</tt> # <b><tt>:row_sep</tt></b>:: <tt>:auto</tt> # <b><tt>:quote_char</tt></b>:: <tt>'"'</tt> + # <b><tt>:field_size_limit</tt></b>:: +nil+ # <b><tt>:converters</tt></b>:: +nil+ # <b><tt>:unconverted_fields</tt></b>:: +nil+ # <b><tt>:headers</tt></b>:: +false+ @@ -870,6 +956,7 @@ class CSV DEFAULT_OPTIONS = { :col_sep => ",", :row_sep => :auto, :quote_char => '"', + :field_size_limit => nil, :converters => nil, :unconverted_fields => nil, :headers => false, @@ -879,6 +966,31 @@ class CSV :force_quotes => false }.freeze # + # This method will return a CSV instance, just like CSV::new(), but the + # instance will be cached and returned for all future calls to this method for + # the same +data+ object (tested by Object#object_id()) with the same + # +options+. + # + # If a block is given, the instance is passed to the block and the return + # value becomes the return value of the block. + # + def self.instance(data = $stdout, options = Hash.new) + # create a _signature_ for this method call, data object and options + sig = [data.object_id] + + options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s }) + + # fetch or create the instance for this signature + @@instances ||= Hash.new + instance = (@@instances[sig] ||= new(data, options)) + + if block_given? + yield instance # run block, if given, returning result + else + instance # or return the instance + end + end + + # # This method allows you to serialize an Array of Ruby objects to a String or # File of CSV data. This is not as powerful as Marshal or YAML, but perhaps # useful for spreadsheet and database interaction. @@ -959,6 +1071,53 @@ class CSV end # + # This method is the reading counterpart to CSV::dump(). See that method for + # a detailed description of the process. + # + # You can customize loading by adding a class method called csv_load() which + # will be passed a Hash of meta information, an Array of headers, and an Array + # of fields for the object the method is expected to return. + # + # Remember that all fields will be Strings after this load. If you need + # something else, use +options+ to setup converters or provide a custom + # csv_load() implementation. + # + def self.load(io_or_str, options = Hash.new) + csv = new(io_or_str, options) + + # load meta information + meta = Hash[*csv.shift] + cls = meta["class".encode(csv.encoding)].split("::".encode(csv.encoding)). + inject(Object) do |c, const| + c.const_get(const) + end + + # load headers + headers = csv.shift + + # unserialize each object stored in the file + results = csv.inject(Array.new) do |all, row| + begin + obj = cls.csv_load(meta, headers, row) + rescue NoMethodError + obj = cls.allocate + headers.zip(row) do |name, value| + if name[0] == ?@ + obj.instance_variable_set(name, value) + else + obj.send(name, value) + end + end + end + all << obj + end + + csv.close unless io_or_str.is_a? String + + results + end + + # # :call-seq: # filter( options = Hash.new ) { |row| ... } # filter( input, options = Hash.new ) { |row| ... } @@ -1014,10 +1173,20 @@ class CSV # pass a +path+ and any +options+ you wish to set for the read. Each row of # file will be passed to the provided +block+ in turn. # - # The +options+ parameter can be anything CSV::new() understands. + # The +options+ parameter can be anything CSV::new() understands. This method + # also understands an additional <tt>:encoding</tt> parameter that you can use + # to specify the Encoding of the data in the file to be read. You must provide + # this unless your data is in Encoding::default_external(). CSV will use this + # to deterime how to parse the data. You may provide a second Encoding to + # have the data transcoded as it is read. For example, + # <tt>:encoding => "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the + # file but transcode it to UTF-8 before CSV parses it. # def self.foreach(path, options = Hash.new, &block) - open(path, options) do |csv| + encoding = options.delete(:encoding) + mode = "rb" + mode << ":#{encoding}" if encoding + open(path, mode, options) do |csv| csv.each(&block) end end @@ -1035,7 +1204,10 @@ class CSV # Note that a passed String *is* modfied by this method. Call dup() before # passing if you need a new String. # - # The +options+ parameter can be anthing CSV::new() understands. + # The +options+ parameter can be anthing CSV::new() understands. This method + # understands an additional <tt>:encoding</tt> parameter when not passed a + # String to set the base Encoding for the output. CSV needs this hint if you + # plan to output non-ASCII compatible data. # def self.generate(*args) # add a default empty String, if none was given @@ -1044,7 +1216,10 @@ class CSV io.seek(0, IO::SEEK_END) args.unshift(io) else - args.unshift("") + encoding = args.last.is_a?(Hash) ? args.last.delete(:encoding) : nil + str = "" + str.encode!(encoding) if encoding + args.unshift(str) end csv = new(*args) # wrap yield csv # yield for appending @@ -1055,97 +1230,40 @@ class CSV # This method is a shortcut for converting a single row (Array) into a CSV # String. # - # The +options+ parameter can be anthing CSV::new() understands. + # The +options+ parameter can be anthing CSV::new() understands. This method + # understands an additional <tt>:encoding</tt> parameter to set the base + # Encoding for the output. This method will try to guess your Encoding from + # the first non-+nil+ field in +row+, if possible, but you may need to use + # this parameter as a backup plan. # # The <tt>:row_sep</tt> +option+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt> # (<tt>$/</tt>) when calling this method. # def self.generate_line(row, options = Hash.new) - options = {:row_sep => $INPUT_RECORD_SEPARATOR}.merge(options) - (new("", options) << row).string - end - - # - # This method will return a CSV instance, just like CSV::new(), but the - # instance will be cached and returned for all future calls to this method for - # the same +data+ object (tested by Object#object_id()) with the same - # +options+. - # - # If a block is given, the instance is passed to the block and the return - # value becomes the return value of the block. - # - def self.instance(data = $stdout, options = Hash.new) - # create a _signature_ for this method call, data object and options - sig = [data.object_id] + - options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s }) - - # fetch or create the instance for this signature - @@instances ||= Hash.new - instance = (@@instances[sig] ||= new(data, options)) - - if block_given? - yield instance # run block, if given, returning result - else - instance # or return the instance - end - end - - # - # This method is the reading counterpart to CSV::dump(). See that method for - # a detailed description of the process. - # - # You can customize loading by adding a class method called csv_load() which - # will be passed a Hash of meta information, an Array of headers, and an Array - # of fields for the object the method is expected to return. - # - # Remember that all fields will be Strings after this load. If you need - # something else, use +options+ to setup converters or provide a custom - # csv_load() implementation. - # - def self.load(io_or_str, options = Hash.new) - csv = new(io_or_str, options) - - # load meta information - meta = Hash[*csv.shift] - cls = meta["class"].split("::").inject(Object) do |c, const| - c.const_get(const) - end - - # load headers - headers = csv.shift - - # unserialize each object stored in the file - results = csv.inject(Array.new) do |all, row| - begin - obj = cls.csv_load(meta, headers, row) - rescue NoMethodError - obj = cls.allocate - headers.zip(row) do |name, value| - if name[0] == ?@ - obj.instance_variable_set(name, value) - else - obj.send(name, value) - end - end - end - all << obj - end - - csv.close unless io_or_str.is_a? String - - results + options = {:row_sep => $INPUT_RECORD_SEPARATOR}.merge(options) + encoding = options.delete(:encoding) + str = "" + if encoding + str.encode!(encoding) + elsif field = row.find { |f| not f.nil? } + str.encode!(String(field).encoding) + end + (new(str, options) << row).string end # # :call-seq: - # open( filename, mode="r", options = Hash.new ) { |csv| ... } - # open( filename, mode="r", options = Hash.new ) + # open( filename, mode = "rb", options = Hash.new ) { |faster_csv| ... } + # open( filename, options = Hash.new ) { |faster_csv| ... } + # open( filename, mode = "rb", options = Hash.new ) + # open( filename, options = Hash.new ) # # This method opens an IO object, and wraps that with CSV. This is intended # as the primary interface for writing a CSV file. # - # You may pass any +args+ Ruby's open() understands followed by an optional - # Hash containing any +options+ CSV::new() understands. + # You must pass a +filename+ and may optionally add a +mode+ for Ruby's + # open(). You may also pass an optional Hash containing any +options+ + # CSV::new() understands as the final argument. # # This method works like Ruby's open() call, in that it will pass a CSV object # to a provided block and close it when the block terminates, or it will @@ -1153,24 +1271,38 @@ class CSV # from the Ruby 1.8 CSV library which passed rows to the block. Use # CSV::foreach() for that behavior.) # - # An opened CSV object will delegate to many IO methods, for convenience. You + # You must provide a +mode+ with an embedded Encoding designator unless your + # data is in Encoding::default_external(). CSV will check the Encoding of the + # underlying IO object (set by the +mode+ you pass) to deterime how to parse + # the data. You may provide a second Encoding to have the data transcoded as + # it is read just as you can with a normal call to IO::open(). For example, + # <tt>"rb:UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file but + # transcode it to UTF-8 before CSV parses it. + # + # An opened CSV object will delegate to many IO methods for convenience. You # may call: # # * binmode() + # * binmode?() # * close() # * close_read() # * close_write() # * closed?() # * eof() # * eof?() + # * external_encoding() # * fcntl() # * fileno() + # * flock() # * flush() # * fsync() + # * internal_encoding() # * ioctl() # * isatty() + # * path() # * pid() # * pos() + # * pos=() # * reopen() # * seek() # * stat() @@ -1179,11 +1311,14 @@ class CSV # * tell() # * to_i() # * to_io() + # * truncate() # * tty?() # def self.open(*args) # find the +options+ Hash options = if args.last.is_a? Hash then args.pop else Hash.new end + # default to a binary open mode + args << "rb" if args.size == 1 # wrap a File opened with the remaining +args+ csv = new(File.open(*args), options) @@ -1237,10 +1372,20 @@ class CSV # # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the - # file and any +options+ CSV::new() understands. + # file and any +options+ CSV::new() understands. This method also understands + # an additional <tt>:encoding</tt> parameter that you can use to specify the + # Encoding of the data in the file to be read. You must provide this unless + # your data is in Encoding::default_external(). CSV will use this to deterime + # how to parse the data. You may provide a second Encoding to have the data + # transcoded as it is read. For example, + # <tt>:encoding => "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the + # file but transcode it to UTF-8 before CSV parses it. # def self.read(path, options = Hash.new) - open(path, options) { |csv| csv.read } + encoding = options.delete(:encoding) + mode = "rb" + mode << ":#{encoding}" if encoding + open(path, mode, options) { |csv| csv.read } end # Alias for CSV::read(). @@ -1276,6 +1421,8 @@ class CSV # Available options are: # # <b><tt>:col_sep</tt></b>:: The String placed between each field. + # This String will be transcoded into + # the data's Encoding before parsing. # <b><tt>:row_sep</tt></b>:: The String appended to the end of each # row. This can be set to the special # <tt>:auto</tt> setting, which requests @@ -1295,7 +1442,16 @@ class CSV # <tt>$INPUT_RECORD_SEPARATOR</tt> # (<tt>$/</tt>) is used. Obviously, # discovery takes a little time. Set - # manually if speed is important. + # manually if speed is important. Also + # note that IO objects should be opened + # in binary mode on Windows if this + # feature will be used as the + # line-ending translation can cause + # problems with resetting the document + # position to where it was before the + # read ahead. This String will be + # transcoded into the data's Encoding + # before parsing. # <b><tt>:quote_char</tt></b>:: The character used to quote fields. # This has to be a single character # String. This is useful for @@ -1304,11 +1460,31 @@ class CSV # instead of the correct <tt>"</tt>. # CSV will always consider a double # sequence this character to be an - # escaped quote. + # escaped quote. This String will be + # transcoded into the data's Encoding + # before parsing. + # <b><tt>:field_size_limit</tt></b>:: This is a maximum size CSV will read + # ahead looking for the closing quote + # for a field. (In truth, it reads to + # the first line ending beyond this + # size.) If a quote cannot be found + # within the limit CSV will raise a + # MalformedCSVError, assuming the data + # is faulty. You can use this limit to + # prevent what are effectively DoS + # attacks on the parser. However, this + # limit can cause a legitimate parse to + # fail and thus is set to +nil+, or off, + # by default. # <b><tt>:converters</tt></b>:: An Array of names from the Converters # Hash and/or lambdas that handle custom # conversion. A single converter - # doesn't have to be in an Array. + # doesn't have to be in an Array. All + # built-in converters try to transcode + # fields to UTF-8 before converting. + # The conversion will fail if the data + # cannot be transcoded, leaving the + # field unchanged. # <b><tt>:unconverted_fields</tt></b>:: If set to +true+, an # unconverted_fields() method will be # added to all returned rows (Array or @@ -1324,11 +1500,14 @@ class CSV # headers. If set to an Array, the # contents will be used as the headers. # If set to a String, the String is run - # through a call of CSV::parse_line() to - # produce an Array of headers. This - # setting causes CSV.shift() to return + # through a call of CSV::parse_line() + # with the same <tt>:col_sep</tt>, + # <tt>:row_sep</tt>, and + # <tt>:quote_char</tt> as this instance + # to produce an Array of headers. This + # setting causes CSV#shift() to return # rows as CSV::Row objects instead of - # Arrays and CSV.read() to return + # Arrays and CSV#read() to return # CSV::Table objects instead of an Array # of Arrays. # <b><tt>:return_headers</tt></b>:: When +false+, header rows are silently @@ -1337,10 +1516,17 @@ class CSV # with identical headers and # fields (save that the fields do not go # through the converters). + # <b><tt>:write_headers</tt></b>:: When +true+ and <tt>:headers</tt> is + # set, a header row will be added to the + # output. # <b><tt>:header_converters</tt></b>:: Identical in functionality to # <tt>:converters</tt> save that the # conversions are only made to header - # rows. + # rows. All built-in converters try to + # transcode headers to UTF-8 before + # converting. The conversion will fail + # if the data cannot be transcoded, + # leaving the header unchanged. # <b><tt>:skip_blanks</tt></b>:: When set to a +true+ value, CSV will # skip over any rows with no content. # <b><tt>:force_quotes</tt></b>:: When set to a +true+ value, CSV will @@ -1356,8 +1542,24 @@ class CSV options = DEFAULT_OPTIONS.merge(options) # create the IO object we will read from - @io = if data.is_a? String then StringIO.new(data) else data end - + @io = if data.is_a? String then StringIO.new(data) else data end + # honor the IO encoding if we can, otherwise default to ASCII-8BIT + @encoding = if @io.respond_to? :internal_encoding + @io.internal_encoding || @io.external_encoding + elsif @io.is_a? StringIO + @io.string.encoding + end + @encoding ||= Encoding.default_external + # + # prepare for build safe regular expressions in the target encoding, + # if we can transcode the needed characters + # + @re_esc = "\\".encode(@encoding) rescue "" + @re_chars = %w[ \\ . [ ] - ^ $ ? + * + { } ( ) | # + \ \r \n \t \f \v ]. + map { |s| s.encode(@encoding) rescue nil }.compact + init_separators(options) init_parsers(options) init_converters(options) @@ -1372,6 +1574,79 @@ class CSV end # + # The encoded <tt>:col_sep</tt> used in parsing and writing. See CSV::new + # for details. + # + attr_reader :col_sep + # + # The encoded <tt>:row_sep</tt> used in parsing and writing. See CSV::new + # for details. + # + attr_reader :row_sep + # + # The encoded <tt>:quote_char</tt> used in parsing and writing. See CSV::new + # for details. + # + attr_reader :quote_char + # The limit for field size, if any. See CSV::new for details. + attr_reader :field_size_limit + # + # Returns the current list of converters in effect. See CSV::new for details. + # Built-in converters will be returned by name, while others will be returned + # as is. + # + def converters + @converters.map do |converter| + name = Converters.rassoc(converter) + name ? name.first : converter + end + end + # + # Returns +true+ if unconverted_fields() to parsed results. See CSV::new + # for details. + # + def unconverted_fields?() @unconverted_fields end + # + # Returns +nil+ if headers will not be used, +true+ if they will but have not + # yet been read, or the actual headers after they have been read. See + # CSV::new for details. + # + def headers + @headers || true if @use_headers + end + # + # Returns +true+ if headers will be returned as a row of results. + # See CSV::new for details. + # + def return_headers?() @return_headers end + # Returns +true+ if headers are written in output. See CSV::new for details. + def write_headers?() @write_headers end + # + # Returns the current list of converters in effect for headers. See CSV::new + # for details. Built-in converters will be returned by name, while others + # will be returned as is. + # + def header_converters + @header_converters.map do |converter| + name = HeaderConverters.rassoc(converter) + name ? name.first : converter + end + end + # + # Returns +true+ blank lines are skipped by the parser. See CSV::new + # for details. + # + def skip_blanks?() @skip_blanks end + # Returns +true+ if all output fields are quoted. See CSV::new for details. + def force_quotes?() @force_quotes end + + # + # The Encoding CSV is parsing or writing in. This will be the Encoding you + # receive parsed data in and/or the Encoding data will be written in. + # + attr_reader :encoding + + # # The line number of the last row read from this file. Fields with nested # line-end characters will not affect this count. # @@ -1380,10 +1655,12 @@ class CSV ### IO and StringIO Delegation ### extend Forwardable - def_delegators :@io, :binmode, :close, :close_read, :close_write, :closed?, - :eof, :eof?, :fcntl, :fileno, :flush, :fsync, :ioctl, - :isatty, :pid, :pos, :reopen, :seek, :stat, :string, - :sync, :sync=, :tell, :to_i, :to_io, :tty? + def_delegators :@io, :binmode, :binmode?, :close, :close_read, :close_write, + :closed?, :eof, :eof?, :external_encoding, :fcntl, + :fileno, :flock, :flush, :fsync, :internal_encoding, + :ioctl, :isatty, :path, :pid, :pos, :pos=, :reopen, + :seek, :stat, :string, :sync, :sync=, :tell, :to_i, + :to_io, :truncate, :tty? # Rewinds the underlying IO object and resets CSV's lineno() counter. def rewind @@ -1403,12 +1680,18 @@ class CSV # The data source must be open for writing. # def <<(row) + # make sure headers have been assigned + if header_row? and [Array, String].include? @use_headers.class + parse_headers # won't read data for Array or String + self << @headers if @write_headers + end + # handle CSV::Row objects and Hashes row = case row - when self.class::Row then row.fields - when Hash then @headers.map { |header| row[header] } - else row - end + when self.class::Row then row.fields + when Hash then @headers.map { |header| row[header] } + else row + end @headers = row if header_row? @lineno += 1 @@ -1431,7 +1714,7 @@ class CSV # # If you provide a block that takes one argument, it will be passed the field # and is expected to return the converted value or the field itself. If your - # block takes two arguments, it will also be passed a FieldInfo Struct, + # block takes two arguments, it will also be passed a CSV::FieldInfo Struct, # containing details about the field. Again, the block should return a # converted field or the field itself. # @@ -1445,7 +1728,7 @@ class CSV # header_convert { |field| ... } # header_convert { |field, field_info| ... } # - # Identical to CSV.convert(), but for header rows. + # Identical to CSV#convert(), but for header rows. # # Note that this method must be called before header rows are read to have any # effect. @@ -1526,7 +1809,7 @@ class CSV # add another read to the line (line += @io.gets(@row_sep)) rescue return nil # copy the line so we can chop it up in parsing - parse = line.dup + parse = line.dup parse.sub!(@parsers[:line_end], "") # @@ -1566,7 +1849,7 @@ class CSV nil # for Ruby 1.8 CSV compatibility else # I decided to take a strict approach to CSV parsing... - if $2.count("\r\n").zero? # verify correctness of field... + if $2.count(@parsers[:return_newline]).zero? # verify correctness $2 else # or throw an Exception @@ -1603,6 +1886,10 @@ class CSV # if we're not empty?() but at eof?(), a quoted field wasn't closed... if @io.eof? raise MalformedCSVError, "Unclosed quoted field on line #{lineno + 1}." + elsif parse =~ @parsers[:bad_field] + raise MalformedCSVError, "Illegal quoting on line #{lineno + 1}." + elsif @field_size_limit and parse.length >= @field_size_limit + raise MalformedCSVError, "Field size exceeded on line #{lineno + 1}." end # otherwise, we need to loop and pull some more data to complete the row end @@ -1610,6 +1897,38 @@ class CSV alias_method :gets, :shift alias_method :readline, :shift + # + # Returns a simplified description of the key FasterCSV attributes in an + # ASCII-8BIT String. + # + def inspect + str = ["<#", self.class.to_s, " io_type:"] + # show type of wrapped IO + if @io == $stdout then str << "$stdout" + elsif @io == $stdin then str << "$stdin" + elsif @io == $stderr then str << "$stderr" + else str << @io.class.to_s + end + # show IO.path(), if available + if @io.respond_to?(:path) and (p = @io.path) + str << " io_path:" << p.inspect + end + # show encoding + str << " encoding:" << @encoding.name + # show other attributes + %w[ lineno col_sep row_sep + quote_char skip_blanks ].each do |attr_name| + if a = instance_variable_get("@#{attr_name}") + str << " " << attr_name << ":" << a.inspect + end + end + if @use_headers + str << " headers:" << headers.inspect + end + str << ">" + str.map { |s| s.encode("ASCII-8BIT") }.join + end + private # @@ -1624,15 +1943,18 @@ class CSV # def init_separators(options) # store the selected separators - @col_sep = options.delete(:col_sep) - @row_sep = options.delete(:row_sep) - @quote_char = options.delete(:quote_char) + @col_sep = options.delete(:col_sep).to_s.encode(@encoding) + @row_sep = options.delete(:row_sep) # encode after resolving :auto + @quote_char = options.delete(:quote_char).to_s.encode(@encoding) if @quote_char.length != 1 raise ArgumentError, ":quote_char has to be a single character String" end + # # automatically discover row separator when requested + # (not fully encoding safe) + # if @row_sep == :auto if [ARGF, STDIN, STDOUT, STDERR].include?(@io) or (defined?(Zlib) and @io.class == Zlib::GzipWriter) @@ -1651,11 +1973,12 @@ class CSV end # read ahead a bit - sample = @io.read(1024) - sample += @io.read(1) if sample[-1..-1] == "\r" and not @io.eof? + sample = read_to_char(1024) + sample += read_to_char(1) if sample[-1..-1] == encode_str("\r") and + not @io.eof? # try to find a standard separator - if sample =~ /\r\n?|\n/ + if sample =~ encode_re("\r\n?|\n") @row_sep = $& break end @@ -1673,14 +1996,17 @@ class CSV end end end + @row_sep = @row_sep.to_s.encode(@encoding) # establish quoting rules - do_quote = lambda do |field| + @force_quotes = options.delete(:force_quotes) + do_quote = lambda do |field| @quote_char + String(field).gsub(@quote_char, @quote_char * 2) + @quote_char end - @quote = if options.delete(:force_quotes) + quotable_chars = encode_str("\r\n", @col_sep, @quote_char) + @quote = if @force_quotes do_quote else lambda do |field| @@ -1690,7 +2016,7 @@ class CSV field = String(field) # Stringify fields # represent empty fields as empty quoted fields if field.empty? or - field.count("\r\n#{@col_sep}#{@quote_char}").nonzero? + field.count(quotable_chars).nonzero? do_quote.call(field) else field # unquoted field @@ -1703,27 +2029,45 @@ class CSV # Pre-compiles parsers and stores them by name for access during reads. def init_parsers(options) # store the parser behaviors - @skip_blanks = options.delete(:skip_blanks) + @skip_blanks = options.delete(:skip_blanks) + @field_size_limit = options.delete(:field_size_limit) # prebuild Regexps for faster parsing - esc_col_sep = Regexp.escape(@col_sep) - esc_row_sep = Regexp.escape(@row_sep) - esc_quote = Regexp.escape(@quote_char) + esc_col_sep = escape_re(@col_sep) + esc_row_sep = escape_re(@row_sep) + esc_quote = escape_re(@quote_char) @parsers = { - :leading_fields => - /\A(?:#{esc_col_sep})+/, # for empty leading fields - :csv_row => - ### The Primary Parser ### - / \G(?:^|#{esc_col_sep}) # anchor the match - (?: #{esc_quote}( (?>[^#{esc_quote}]*) # find quoted fields - (?> #{esc_quote*2} - [^#{esc_quote}]* )* )#{esc_quote} - | # ... or ... - ([^#{esc_quote}#{esc_col_sep}]*) # unquoted fields - )/x, - ### End Primary Parser ### - :line_end => - /#{esc_row_sep}\z/ # safer than chomp!() + # for empty leading fields + :leading_fields => encode_re("\\A(?:", esc_col_sep, ")+"), + # The Primary Parser + :csv_row => encode_re( + "\\G(?:\\A|", esc_col_sep, ")", # anchor the match + "(?:", esc_quote, # find quoted fields + "((?>[^", esc_quote, "]*)", # "unrolling the loop" + "(?>", esc_quote * 2, # double for escaping + "[^", esc_quote, "]*)*)", + esc_quote, + "|", # ... or ... + "([^", esc_quote, esc_col_sep, "]*))", # unquoted fields + "(?=", esc_col_sep, "|\\z)" # ensure field is ended + ), + # a test for unescaped quotes + :bad_field => encode_re( + "\\A", esc_col_sep, "?", # an optional comma + "(?:", esc_quote, # a quoted field + "(?>[^", esc_quote, "]*)", # "unrolling the loop" + "(?>", esc_quote * 2, # double for escaping + "[^", esc_quote, "]*)*", + esc_quote, # the closing quote + "[^", esc_quote, "]", # an extra character + "|", # ... or ... + "[^", esc_quote, esc_col_sep, "]+", # an unquoted field + esc_quote, ")" # an extra quote + ), + # safer than chomp!() + :line_end => encode_re(esc_row_sep, "\\z"), + # illegal unquoted characters + :return_newline => encode_str("\r\n") } end @@ -1770,6 +2114,7 @@ class CSV def init_headers(options) @use_headers = options.delete(:headers) @return_headers = options.delete(:return_headers) + @write_headers = options.delete(:write_headers) # headers must be delayed until shift(), in case they need a row of content @headers = nil @@ -1812,7 +2157,7 @@ class CSV # see if we are converting headers or fields converters = headers ? @header_converters : @converters - fields.each_with_index.map do |field, index| # map_with_index + fields.map.with_index do |field, index| converters.each do |converter| field = if converter.arity == 1 # straight field converter converter[field] @@ -1839,10 +2184,17 @@ class CSV def parse_headers(row = nil) if @headers.nil? # header row @headers = case @use_headers # save headers - when Array then @use_headers # Array of headers - when String then self.class.parse_line(@use_headers) # CSV header String - else row # first row headers - end + # Array of headers + when Array then @use_headers + # CSV header String + when String + self.class.parse_line( @use_headers, + :col_sep => @col_sep, + :row_sep => @row_sep, + :quote_char => @quote_char ) + # first row is headers + else row + end # prepare converted and unconverted copies row = @headers if row.nil? @@ -1870,6 +2222,56 @@ class CSV row.instance_eval { @unconverted_fields = fields } row end + + # + # This method is an encoding safe version of Regexp::escape(). I will escape + # any characters that would change the meaning of a regular expression in the + # encoding of +str+. Regular expression characters that cannot be transcoded + # to the target encodign will be skipped and no escaping will be performed if + # a backslash cannot be transcoded. + # + def escape_re(str) + str.chars.map { |c| @re_chars.include?(c) ? @re_esc + c : c }.join + end + + # + # Builds a regular expression in <tt>@encoding</tt>. All +chunks+ will be + # transcoded to that encoding. + # + def encode_re(*chunks) + Regexp.new(encode_str(*chunks)) + end + + # + # Builds a String in <tt>@encoding</tt>. All +chunks+ will be transcoded to + # that encoding. + # + def encode_str(*chunks) + chunks.map { |chunk| chunk.encode(@encoding.name) }.join + end + + # + # Reads at least +bytes+ from <tt>@io</tt>, but will read on until the data + # read is valid in the ecoding of that data. This should ensure that it is + # safe to use regular expressions on the read data. The read data will be + # returned in <tt>@encoding</tt>. + # + def read_to_char(bytes) + return "" if @io.eof? + data = @io.read(bytes) + begin + encoded = encode_str(data) + raise unless encoded.valid_encoding? + return encoded + rescue # encoding error or my invalid data raise + if @io.eof? + return data + else + data += @io.read(1) until data.valid_encoding? or @io.eof? + retry + end + end + end end # Another name for CSV::instance(). diff --git a/lib/mathn.rb b/lib/mathn.rb index 2af2b83da3..e918608b0d 100644 --- a/lib/mathn.rb +++ b/lib/mathn.rb @@ -9,11 +9,15 @@ # # -require "complex.rb" -require "rational.rb" +require "cmath.rb" require "matrix.rb" require "prime.rb" +unless defined?(Math.exp!) + Object.instance_eval{remove_const :Math} + Math = CMath +end + class Fixnum remove_method :/ alias / quo @@ -33,7 +37,7 @@ class Rational if other.kind_of?(Rational) other2 = other if self < 0 - return Complex.__send__(:new!, self, 0) ** other + return Complex(self, 0.0) ** other elsif other == 0 return Rational(1,1) elsif self == 0 @@ -95,7 +99,7 @@ module Math remove_method(:sqrt) def sqrt(a) if a.kind_of?(Complex) - abs = sqrt(a.real*a.real + a.image*a.image) + abs = sqrt(a.real*a.real + a.imag*a.imag) # if not abs.kind_of?(Rational) # return a**Rational(1,2) # end @@ -104,7 +108,7 @@ module Math # if !(x.kind_of?(Rational) and y.kind_of?(Rational)) # return a**Rational(1,2) # end - if a.image >= 0 + if a.imag >= 0 Complex(x, y) else Complex(x, -y) diff --git a/lib/matrix.rb b/lib/matrix.rb index d31fcc5464..c672ee5198 100644 --- a/lib/matrix.rb +++ b/lib/matrix.rb @@ -410,17 +410,21 @@ class Matrix other.compare_by_row_vectors(@rows) end - alias eql? == + def eql?(other) + return false unless Matrix === other + + other.compare_by_row_vectors(@rows, :eql?) + end # # Not really intended for general consumption. # - def compare_by_row_vectors(rows) + def compare_by_row_vectors(rows, comparison = :==) return false unless @rows.size == rows.size 0.upto(@rows.size - 1) do |i| - return false unless @rows[i] == rows[i] + return false unless @rows[i].send(comparison, rows[i]) end true end @@ -1200,13 +1204,17 @@ class Vector other.compare_by(@elements) end - alias eqn? == + def eql?(other) + return false unless Vector === other + + other.compare_by(@elements, :eql?) + end # # For internal use. # - def compare_by(elements) - @elements == elements + def compare_by(elements, comparison = :==) + @elements.send(comparison, elements) end # diff --git a/lib/open-uri.rb b/lib/open-uri.rb index 238d759d5f..c68aee6e97 100644 --- a/lib/open-uri.rb +++ b/lib/open-uri.rb @@ -542,7 +542,7 @@ module OpenURI # :proxy => true # :proxy => false # :proxy => nil - # + # # If :proxy option is specified, the value should be String, URI, # boolean or nil. # When String or URI is given, it is treated as proxy URI. @@ -556,7 +556,7 @@ module OpenURI # Synopsis: # :proxy_http_basic_authentication => ["http://proxy.foo.com:8000/", "proxy-user", "proxy-password"] # :proxy_http_basic_authentication => [URI.parse("http://proxy.foo.com:8000/"), "proxy-user", "proxy-password"] - # + # # If :proxy option is specified, the value should be an Array with 3 elements. # It should contain a proxy URI, a proxy user name and a proxy password. # The proxy URI should be a String, an URI or nil. @@ -564,7 +564,7 @@ module OpenURI # # If nil is given for the proxy URI, this option is just ignored. # - # If :proxy and :proxy_http_basic_authentication is specified, + # If :proxy and :proxy_http_basic_authentication is specified, # ArgumentError is raised. # # [:http_basic_authentication] @@ -579,14 +579,14 @@ module OpenURI # [:content_length_proc] # Synopsis: # :content_length_proc => lambda {|content_length| ... } - # + # # If :content_length_proc option is specified, the option value procedure # is called before actual transfer is started. # It takes one argument which is expected content length in bytes. - # + # # If two or more transfer is done by HTTP redirection, the procedure # is called only one for a last transfer. - # + # # When expected content length is unknown, the procedure is called with # nil. # It is happen when HTTP response has no Content-Length header. diff --git a/lib/optparse.rb b/lib/optparse.rb index 86681235a0..f457b072a9 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -632,7 +632,7 @@ class OptionParser list.each do |opt| if opt.respond_to?(:summarize) # perhaps OptionParser::Switch opt.summarize(*args, &block) - elsif !opt + elsif !opt or opt.empty? yield("") elsif opt.respond_to?(:each_line) opt.each_line(&block) @@ -1605,6 +1605,13 @@ class OptionParser argv end + def set_backtrace(array) + unless $DEBUG + array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~)) + end + super(array) + end + def set_option(opt, eq) if eq @args[0] = opt diff --git a/lib/pathname.rb b/lib/pathname.rb index 7bee22b58f..45974545a6 100644 --- a/lib/pathname.rb +++ b/lib/pathname.rb @@ -43,7 +43,7 @@ # base = p.basename # Pathname:ruby # dir, base = p.split # [Pathname:/usr/bin, Pathname:ruby] # data = p.read -# p.open { |f| _ } +# p.open { |f| _ } # p.each_line { |line| _ } # # === Example 2: Using standard Ruby @@ -55,7 +55,7 @@ # base = File.basename(p) # "ruby" # dir, base = File.split(p) # ["/usr/bin", "ruby"] # data = File.read(p) -# File.open(p) { |f| _ } +# File.open(p) { |f| _ } # File.foreach(p) { |line| _ } # # === Example 3: Special features @@ -71,7 +71,7 @@ # p5.cleanpath # Pathname:articles # p5.realpath # Pathname:/home/gavin/articles # p5.children # [Pathname:/home/gavin/articles/linux, ...] -# +# # == Breakdown of functionality # # === Core methods @@ -452,7 +452,7 @@ class Pathname # Returns a real (absolute) pathname of +self+ in the actual filesystem. # The real pathname doesn't contain symlinks or useless dots. # - # No arguments should be given; the old behaviour is *obsoleted*. + # No arguments should be given; the old behaviour is *obsoleted*. # def realpath path = @path @@ -587,7 +587,7 @@ class Pathname # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd # - # This method doesn't access the file system; it is pure string manipulation. + # This method doesn't access the file system; it is pure string manipulation. # def +(other) other = Pathname.new(other) unless Pathname === other @@ -1,10 +1,10 @@ # == Pretty-printer for Ruby objects. -# +# # = Which seems better? -# +# # non-pretty-printed output by #p is: # #<PP:0x81fedf0 @genspace=#<Proc:0x81feda0>, @group_queue=#<PrettyPrint::GroupQueue:0x81fed3c @queue=[[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], []]>, @buffer=[], @newline="\n", @group_stack=[#<PrettyPrint::Group:0x81fed78 @breakables=[], @depth=0, @break=false>], @buffer_width=0, @indent=0, @maxwidth=79, @output_width=2, @output=#<IO:0x8114ee4>> -# +# # pretty-printed output by #pp is: # #<PP:0x81fedf0 # @buffer=[], @@ -22,17 +22,17 @@ # @newline="\n", # @output=#<IO:0x8114ee4>, # @output_width=2> -# +# # I like the latter. If you do too, this library is for you. -# +# # = Usage -# +# # pp(obj) # # output +obj+ to +$>+ in pretty printed format. -# +# # It returns +nil+. -# +# # = Output Customization # To define your customized pretty printing function for your classes, # redefine a method #pretty_print(+pp+) in the class. @@ -67,10 +67,10 @@ end class PP < PrettyPrint # Outputs +obj+ to +out+ in pretty printed format of # +width+ columns in width. - # + # # If +out+ is omitted, +$>+ is assumed. # If +width+ is omitted, 79 is assumed. - # + # # PP.pp returns +out+. def PP.pp(obj, out=$>, width=79) q = PP.new(out, width) @@ -82,7 +82,7 @@ class PP < PrettyPrint # Outputs +obj+ to +out+ like PP.pp but with no indent and # newline. - # + # # PP.singleline_pp returns +out+. def PP.singleline_pp(obj, out=$>) q = SingleLine.new(out) @@ -138,12 +138,12 @@ class PP < PrettyPrint # Adds +obj+ to the pretty printing buffer # using Object#pretty_print or Object#pretty_print_cycle. - # + # # Object#pretty_print_cycle is used when +obj+ is already # printed, a.k.a the object reference chain has a cycle. def pp(obj) id = obj.object_id - + if check_inspect_key(id) group {obj.pretty_print_cycle self} return @@ -158,7 +158,7 @@ class PP < PrettyPrint end # A convenience method which is same as follows: - # + # # group(1, '#<' + obj.class.name, '>') { ... } def object_group(obj, &block) # :yield: group(1, '#<' + obj.class.name, '>', &block) @@ -185,7 +185,7 @@ class PP < PrettyPrint end # A convenience method which is same as follows: - # + # # text ',' # breakable def comma_breakable @@ -195,23 +195,23 @@ class PP < PrettyPrint # Adds a separated list. # The list is separated by comma with breakable space, by default. - # + # # #seplist iterates the +list+ using +iter_method+. # It yields each object to the block given for #seplist. # The procedure +separator_proc+ is called between each yields. - # + # # If the iteration is zero times, +separator_proc+ is not called at all. - # + # # If +separator_proc+ is nil or not given, # +lambda { comma_breakable }+ is used. # If +iter_method+ is not given, :each is used. - # + # # For example, following 3 code fragments has similar effect. - # + # # q.seplist([1,2,3]) {|v| xxx v } - # + # # q.seplist([1,2,3], lambda { q.comma_breakable }, :each) {|v| xxx v } - # + # # xxx 1 # q.comma_breakable # xxx 2 @@ -275,11 +275,11 @@ class PP < PrettyPrint # A default pretty printing method for general objects. # It calls #pretty_print_instance_variables to list instance variables. - # + # # If +self+ has a customized (redefined) #inspect method, # the result of self.inspect is used but it obviously has no # line break hints. - # + # # This module provides predefined #pretty_print methods for some of # the most commonly used built-in classes for convenience. def pretty_print(q) @@ -302,7 +302,7 @@ class PP < PrettyPrint end # Returns a sorted array of instance variable names. - # + # # This method should return an array of names of instance variables as symbols or strings as: # +[:@a, :@b]+. def pretty_print_instance_variables @@ -311,7 +311,7 @@ class PP < PrettyPrint # Is #inspect implementation using #pretty_print. # If you implement #pretty_print, it can be used as follows. - # + # # alias inspect pretty_print_inspect # # However, doing this requires that every class that #inspect is called on @@ -629,7 +629,7 @@ if __FILE__ == $0 result = PP.pp(a, '') assert_equal("#{a.inspect}\n", result) end - + def test_to_s_without_iv a = Object.new def a.to_s() "aaa" end diff --git a/lib/prettyprint.rb b/lib/prettyprint.rb index 315c422e9e..48f2ebf1e4 100644 --- a/lib/prettyprint.rb +++ b/lib/prettyprint.rb @@ -2,7 +2,7 @@ # This class implements a pretty printing algorithm. It finds line breaks and # nice indentations for grouped structure. -# +# # By default, the class assumes that primitive elements are strings and each # byte in the strings have single column in width. But it can be used for # other situations by giving suitable arguments for some methods: @@ -18,28 +18,28 @@ # == Bugs # * Box based formatting? # * Other (better) model/algorithm? -# +# # == References # Christian Lindig, Strictly Pretty, March 2000, # http://www.st.cs.uni-sb.de/~lindig/papers/#pretty -# +# # Philip Wadler, A prettier printer, March 1998, # http://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier -# +# # == Author # Tanaka Akira <akr@m17n.org> -# +# class PrettyPrint # This is a convenience method which is same as follows: - # + # # begin # q = PrettyPrint.new(output, maxwidth, newline, &genspace) # ... # q.flush # output # end - # + # def PrettyPrint.format(output='', maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n}) q = PrettyPrint.new(output, maxwidth, newline, &genspace) yield q diff --git a/lib/rake.rb b/lib/rake.rb index 0b21eb7350..caafa5caf0 100755 --- a/lib/rake.rb +++ b/lib/rake.rb @@ -29,13 +29,13 @@ # as a library via a require statement, but it can be distributed # independently as an application. -RAKEVERSION = '0.8.0' +RAKEVERSION = '0.8.2' require 'rbconfig' -require 'getoptlong' require 'fileutils' require 'singleton' -require 'thread' +require 'monitor' +require 'optparse' require 'ostruct' ###################################################################### @@ -239,6 +239,33 @@ end # class String ############################################################################## module Rake + # Errors ----------------------------------------------------------- + + # Error indicating an ill-formed task declaration. + class TaskArgumentError < ArgumentError + end + + # Error indicating a recursion overflow error in task selection. + class RuleRecursionOverflowError < StandardError + def initialize(*args) + super + @targets = [] + end + + def add_target(target) + @targets << target + end + + def message + super + ": [" + @targets.reverse.join(' => ') + "]" + end + end + + # Error indicating a problem in locating the home directory on a + # Win32 system. + class Win32HomeError < RuntimeError + end + # -------------------------------------------------------------------------- # Rake module singleton methods. # @@ -266,16 +293,22 @@ module Rake module Cloneable # Clone an object by making a new object and setting all the instance # variables to the same values. - def clone + def dup sibling = self.class.new instance_variables.each do |ivar| value = self.instance_variable_get(ivar) new_value = value.clone rescue value sibling.instance_variable_set(ivar, new_value) end + sibling.taint if tainted? + sibling + end + + def clone + sibling = dup + sibling.freeze if frozen? sibling end - alias dup clone end #################################################################### @@ -286,12 +319,15 @@ module Rake attr_reader :names + # Create a TaskArgument object with a list of named arguments + # (given by :names) and a set of associated values (given by + # :values). :parent is the parent argument object. def initialize(names, values, parent=nil) @names = names @parent = parent @hash = {} names.each_with_index { |name, i| - @hash[name.to_sym] = values[i] + @hash[name.to_sym] = values[i] unless values[i].nil? } end @@ -307,6 +343,13 @@ module Rake lookup(index.to_sym) end + # Specify a hash of default values for task arguments. Use the + # defaults only if there is no specific value for the given + # argument. + def with_defaults(defaults) + @hash = defaults.merge(@hash) + end + def each(&block) @hash.each(&block) end @@ -342,6 +385,8 @@ module Rake end end + EMPTY_TASK_ARGS = TaskArguments.new([], []) + #################################################################### # InvocationChain tracks the chain of task invocations to detect # circular dependencies. @@ -409,6 +454,9 @@ module Rake # List of prerequisites for a task. attr_reader :prerequisites + # List of actions attached to a task. + attr_reader :actions + # Application owning this task. attr_accessor :application @@ -446,12 +494,12 @@ module Rake # +enhance+ to add actions and prerequisites. def initialize(task_name, app) @name = task_name.to_s - @prerequisites = FileList[] + @prerequisites = [] @actions = [] @already_invoked = false @full_comment = nil @comment = nil - @lock = Mutex.new + @lock = Monitor.new @application = app @scope = app.current_scope @arg_names = nil @@ -488,6 +536,31 @@ module Rake @arg_names || [] end + # Reenable the task, allowing its tasks to be executed if the task + # is invoked again. + def reenable + @already_invoked = false + end + + # Clear the existing prerequisites and actions of a rake task. + def clear + clear_prerequisites + clear_actions + self + end + + # Clear the existing prerequisites of a rake task. + def clear_prerequisites + prerequisites.clear + self + end + + # Clear the existing actions on a rake task. + def clear_actions + actions.clear + self + end + # Invoke the task if it is needed. Prerequites are invoked first. def invoke(*args) task_args = TaskArguments.new(arg_names, args) @@ -496,7 +569,7 @@ module Rake # Same as invoke, but explicitly pass a call chain to detect # circular dependencies. - def invoke_with_call_chain(task_args, invocation_chain) + def invoke_with_call_chain(task_args, invocation_chain) # :nodoc: new_chain = InvocationChain.append(self, invocation_chain) @lock.synchronize do if application.options.trace @@ -511,7 +584,7 @@ module Rake protected :invoke_with_call_chain # Invoke all the prerequisites of a task. - def invoke_prerequisites(task_args, invocation_chain) + def invoke_prerequisites(task_args, invocation_chain) # :nodoc: @prerequisites.each { |n| prereq = application[n, @scope] prereq_args = task_args.new_scope(prereq.arg_names) @@ -529,7 +602,8 @@ module Rake private :format_trace_flags # Execute the actions associated with this task. - def execute(args) + def execute(args=nil) + args ||= EMPTY_TASK_ARGS if application.options.dryrun puts "** Execute (dry run) #{name}" return @@ -772,8 +846,8 @@ end # end # end # -def file(args, &block) - Rake::FileTask.define_task(args, &block) +def file(*args, &block) + Rake::FileTask.define_task(*args, &block) end # Declare a file creation task. @@ -899,14 +973,38 @@ module FileUtils ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]" } end + if RakeFileUtils.verbose_flag == :default + options[:verbose] = false + else + options[:verbose] ||= RakeFileUtils.verbose_flag + end + options[:noop] ||= RakeFileUtils.nowrite_flag rake_check_options options, :noop, :verbose rake_output_message cmd.join(" ") if options[:verbose] unless options[:noop] - res = system(*cmd) + res = rake_system(*cmd) block.call(res, $?) end end + def rake_system(*cmd) + if Rake.application.windows? + rake_win32_system(*cmd) + else + system(*cmd) + end + end + private :rake_system + + def rake_win32_system(*cmd) + if cmd.size == 1 + system("call #{cmd}") + else + system(*cmd) + end + end + private :rake_win32_system + # Run a Ruby interpreter with the given arguments. # # Example: @@ -917,7 +1015,7 @@ module FileUtils if args.length > 1 then sh(*([RUBY] + args + [options]), &block) else - sh("#{RUBY.sub(/.*\s.*/m, '"\&"')} #{args.first}", options, &block) + sh("#{RUBY} #{args.first}", options, &block) end end @@ -961,7 +1059,7 @@ module RakeFileUtils class << self attr_accessor :verbose_flag, :nowrite_flag end - RakeFileUtils.verbose_flag = true + RakeFileUtils.verbose_flag = :default RakeFileUtils.nowrite_flag = false $fileutils_verbose = true @@ -969,10 +1067,10 @@ module RakeFileUtils FileUtils::OPT_TABLE.each do |name, opts| default_options = [] - if opts.include?('verbose') + if opts.include?(:verbose) || opts.include?("verbose") default_options << ':verbose => RakeFileUtils.verbose_flag' end - if opts.include?('noop') + if opts.include?(:noop) || opts.include?("noop") default_options << ':noop => RakeFileUtils.nowrite_flag' end @@ -1029,7 +1127,7 @@ module RakeFileUtils oldvalue end - # Use this function to prevent potentially destructive ruby code from + # Use this function to prevent protentially destructive ruby code from # running when the :nowrite flag is set. # # Example: @@ -1094,21 +1192,6 @@ private(*RakeFileUtils.instance_methods(false)) ###################################################################### module Rake - class RuleRecursionOverflowError < StandardError - def initialize(*args) - super - @targets = [] - end - - def add_target(target) - @targets << target - end - - def message - super + ": [" + @targets.reverse.join(' => ') + "]" - end - end - # ######################################################################### # A FileList is essentially an array with a few helper methods defined to # make file manipulation a bit easier. @@ -1352,7 +1435,7 @@ module Rake private :resolve_exclude # Return a new FileList with the results of running +sub+ against each - # element of the original list. + # element of the oringal list. # # Example: # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o'] @@ -1503,7 +1586,7 @@ module Rake class << self # Yield each file or directory component. - def each_dir_parent(dir) + def each_dir_parent(dir) # :nodoc: old_length = nil while dir != '.' && dir.length != old_length yield(dir) @@ -1642,23 +1725,65 @@ module Rake # Resolve the arguments for a task/rule. Returns a triplet of # [task_name, arg_name_list, prerequisites]. def resolve_args(args) + if args.last.is_a?(Hash) + deps = args.pop + resolve_args_with_dependencies(args, deps) + else + resolve_args_without_dependencies(args) + end + end + + # Resolve task arguments for a task or rule when there are no + # dependencies declared. + # + # The patterns recognized by this argument resolving function are: + # + # task :t + # task :t, [:a] + # task :t, :a (deprecated) + # + def resolve_args_without_dependencies(args) task_name = args.shift - arg_names = args #.map { |a| a.to_sym } - needs = [] - if task_name.is_a?(Hash) - hash = task_name - task_name = hash.keys[0] - needs = hash[task_name] + if args.size == 1 && args.first.respond_to?(:to_ary) + arg_names = args.first.to_ary + else + arg_names = args end - if arg_names.last.is_a?(Hash) - hash = arg_names.pop - needs = hash[:needs] - fail "Unrecognized keys in task hash: #{hash.keys.inspect}" if hash.size > 1 + [task_name, arg_names, []] + end + private :resolve_args_without_dependencies + + # Resolve task arguments for a task or rule when there are + # dependencies declared. + # + # The patterns recognized by this argument resolving function are: + # + # task :t => [:d] + # task :t, [a] => [:d] + # task :t, :needs => [:d] (deprecated) + # task :t, :a, :needs => [:d] (deprecated) + # + def resolve_args_with_dependencies(args, hash) # :nodoc: + fail "Task Argument Error" if hash.size != 1 + key, value = hash.map { |k, v| [k,v] }.first + if args.empty? + task_name = key + arg_names = [] + deps = value + elsif key == :needs + task_name = args.shift + arg_names = args + deps = value + else + task_name = args.shift + arg_names = key + deps = value end - needs = [needs] unless needs.respond_to?(:to_ary) - [task_name, arg_names, needs] + deps = [deps] unless deps.respond_to?(:to_ary) + [task_name, arg_names, deps] end - + private :resolve_args_with_dependencies + # If a rule can be found that matches the task name, enhance the # task with the prerequisites and actions from the rule. Set the # source attribute of the task appropriately for the rule. Return @@ -1749,15 +1874,23 @@ module Rake "_anon_#{@seed}" end + def trace_rule(level, message) + puts "#{" "*level}#{message}" if Rake.application.options.trace_rules + end + # Attempt to create a rule given the list of prerequisites. def attempt_rule(task_name, extensions, block, level) sources = make_sources(task_name, extensions) prereqs = sources.collect { |source| + trace_rule level, "Attempting Rule #{task_name} => #{source}" if File.exist?(source) || Rake::Task.task_defined?(source) + trace_rule level, "(#{task_name} => #{source} ... EXIST)" source - elsif parent = enhance_with_matching_rule(sources.first, level+1) + elsif parent = enhance_with_matching_rule(source, level+1) + trace_rule level, "(#{task_name} => #{source} ... ENHANCE)" parent.name else + trace_rule level, "(#{task_name} => #{source} ... FAIL)" return nil end } @@ -1814,41 +1947,6 @@ module Rake DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze - OPTIONS = [ # :nodoc: - ['--classic-namespace', '-C', GetoptLong::NO_ARGUMENT, - "Put Task and FileTask in the top level namespace"], - ['--describe', '-D', GetoptLong::OPTIONAL_ARGUMENT, - "Describe the tasks (matching optional PATTERN), then exit."], - ['--rakefile', '-f', GetoptLong::OPTIONAL_ARGUMENT, - "Use FILE as the rakefile."], - ['--help', '-h', '-H', GetoptLong::NO_ARGUMENT, - "Display this help message."], - ['--libdir', '-I', GetoptLong::REQUIRED_ARGUMENT, - "Include LIBDIR in the search path for required modules."], - ['--dry-run', '-n', GetoptLong::NO_ARGUMENT, - "Do a dry run without executing actions."], - ['--nosearch', '-N', GetoptLong::NO_ARGUMENT, - "Do not search parent directories for the Rakefile."], - ['--prereqs', '-P', GetoptLong::NO_ARGUMENT, - "Display the tasks and dependencies, then exit."], - ['--quiet', '-q', GetoptLong::NO_ARGUMENT, - "Do not log messages to standard output."], - ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT, - "Require MODULE before executing rakefile."], - ['--rakelibdir', '-R', GetoptLong::REQUIRED_ARGUMENT, - "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')"], - ['--silent', '-s', GetoptLong::NO_ARGUMENT, - "Like --quiet, but also suppresses the 'in directory' announcement."], - ['--tasks', '-T', GetoptLong::OPTIONAL_ARGUMENT, - "Display the tasks (matching optional PATTERN) with descriptions, then exit."], - ['--trace', '-t', GetoptLong::NO_ARGUMENT, - "Turn on invoke/execute tracing, enable full backtrace."], - ['--verbose', '-v', GetoptLong::NO_ARGUMENT, - "Log message to standard output (default)."], - ['--version', '-V', GetoptLong::NO_ARGUMENT, - "Display the program version."], - ] - # Initialize a Rake::Application object. def initialize super @@ -1861,8 +1959,10 @@ module Rake @default_loader = Rake::DefaultLoader.new @original_dir = Dir.pwd @top_level_tasks = [] + add_loader('rb', DefaultLoader.new) add_loader('rf', DefaultLoader.new) add_loader('rake', DefaultLoader.new) + @tty_output = STDOUT.tty? end # Run the Rake application. The run method performs the following three steps: @@ -1886,8 +1986,7 @@ module Rake def init(app_name='rake') standard_exception_handling do @name = app_name - handle_options - collect_tasks + collect_tasks handle_options end end @@ -1942,16 +2041,16 @@ module Rake [name, args] end - # Provide standard exception handling for the given block. + # Provide standard execption handling for the given block. def standard_exception_handling begin yield rescue SystemExit => ex # Exit silently with current status - exit(ex.status) - rescue SystemExit, GetoptLong::InvalidOption => ex + raise + rescue OptionParser::InvalidOption => ex # Exit silently - exit(1) + exit(false) rescue Exception => ex # Exit with error message $stderr.puts "rake aborted!" @@ -1962,7 +2061,7 @@ module Rake $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || "" $stderr.puts "(See full trace by running task with --trace)" end - exit(1) + exit(false) end end @@ -1971,33 +2070,26 @@ module Rake def have_rakefile @rakefiles.each do |fn| if File.exist?(fn) || fn == '' - @rakefile = fn - return true + return fn end end - return false + return nil end - # Display the rake command line help. - def help - puts "rake [-f rakefile] {options} targets..." - puts - puts "Options are ..." - puts - OPTIONS.sort.each do |long, *short, mode, desc| - case mode - when GetoptLong::REQUIRED_ARGUMENT - if desc =~ /\b([A-Z]{2,})\b/ - long = long + "=#{$1}" - end - when GetoptLong::OPTIONAL_ARGUMENT - if desc =~ /\b([A-Z]{2,})\b/ - long = long + "[=#{$1}]" - end - end - printf " %-20s (%s)\n", long, short.join(", ") - printf " %s\n", desc - end + # True if we are outputting to TTY, false otherwise + def tty_output? + @tty_output + end + + # Override the detected TTY output state (mostly for testing) + def tty_output=( tty_output_state ) + @tty_output = tty_output_state + end + + # We will truncate output if we are outputting to a TTY or if we've been + # given an explicit column width to honor + def truncate_output? + tty_output? || ENV['RAKE_COLUMNS'] end # Display the tasks and dependencies. @@ -2015,19 +2107,51 @@ module Rake end else width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10 - max_column = 80 - name.size - width - 7 + max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil displayable_tasks.each do |t| printf "#{name} %-#{width}s # %s\n", - t.name_with_args, truncate(t.comment, max_column) + t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment end end end + def terminal_width + if ENV['RAKE_COLUMNS'] + result = ENV['RAKE_COLUMNS'].to_i + else + result = unix? ? dynamic_width : 80 + end + (result < 10) ? 80 : result + rescue + 80 + end + + # Calculate the dynamic width of the + def dynamic_width + @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput) + end + + def dynamic_width_stty + %x{stty size 2>/dev/null}.split[1].to_i + end + + def dynamic_width_tput + %x{tput cols 2>/dev/null}.to_i + end + + def unix? + RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i + end + + def windows? + Config::CONFIG['host_os'] =~ /mswin/ + end + def truncate(string, width) if string.length <= width string else - string[0, width-3] + "..." + ( string[0, width-3] || "" ) + "..." end end @@ -2039,77 +2163,141 @@ module Rake end end - # Return a list of the command line options supported by the - # program. - def command_line_options - OPTIONS.collect { |lst| lst[0..-2] } - end - - # Do the option defined by +opt+ and +value+. - def do_option(opt, value) - case opt - when '--describe' - options.show_tasks = true - options.show_task_pattern = Regexp.new(value || '.') - options.full_description = true - when '--dry-run' - verbose(true) - nowrite(true) - options.dryrun = true - options.trace = true - when '--help' - help - exit - when '--libdir' - $:.push(value) - when '--nosearch' - options.nosearch = true - when '--prereqs' - options.show_prereqs = true - when '--quiet' - verbose(false) - when '--rakefile' - @rakefiles.clear - @rakefiles << value - when '--rakelibdir' - options.rakelib = value.split(':') - when '--require' - begin - require value - rescue LoadError => ex - begin - rake_require value - rescue LoadError => ex2 - raise ex - end - end - when '--silent' - verbose(false) - options.silent = true - when '--tasks' - options.show_tasks = true - options.show_task_pattern = Regexp.new(value || '.') - options.full_description = false - when '--trace' - options.trace = true - verbose(true) - when '--verbose' - verbose(true) - when '--version' - puts "rake, version #{RAKEVERSION}" - exit - when '--classic-namespace' - require 'rake/classic_namespace' - options.classic_namespace = true - end + # A list of all the standard options used in rake, suitable for + # passing to OptionParser. + def standard_rake_options + [ + ['--classic-namespace', '-C', "Put Task and FileTask in the top level namespace", + lambda { |value| + require 'rake/classic_namespace' + options.classic_namespace = true + } + ], + ['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.", + lambda { |value| + options.show_tasks = true + options.full_description = true + options.show_task_pattern = Regexp.new(value || '') + } + ], + ['--dry-run', '-n', "Do a dry run without executing actions.", + lambda { |value| + verbose(true) + nowrite(true) + options.dryrun = true + options.trace = true + } + ], + ['--execute', '-e CODE', "Execute some Ruby code and exit.", + lambda { |value| + eval(value) + exit + } + ], + ['--execute-print', '-p CODE', "Execute some Ruby code, print the result, then exit.", + lambda { |value| + puts eval(value) + exit + } + ], + ['--execute-continue', '-E CODE', + "Execute some Ruby code, then continue with normal task processing.", + lambda { |value| eval(value) } + ], + ['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.", + lambda { |value| $:.push(value) } + ], + ['--prereqs', '-P', "Display the tasks and dependencies, then exit.", + lambda { |value| options.show_prereqs = true } + ], + ['--quiet', '-q', "Do not log messages to standard output.", + lambda { |value| verbose(false) } + ], + ['--rakefile', '-f [FILE]', "Use FILE as the rakefile.", + lambda { |value| + value ||= '' + @rakefiles.clear + @rakefiles << value + } + ], + ['--rakelibdir', '--rakelib', '-R RAKELIBDIR', + "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')", + lambda { |value| options.rakelib = value.split(':') } + ], + ['--require', '-r MODULE', "Require MODULE before executing rakefile.", + lambda { |value| + begin + require value + rescue LoadError => ex + begin + rake_require value + rescue LoadError => ex2 + raise ex + end + end + } + ], + ['--rules', "Trace the rules resolution.", + lambda { |value| options.trace_rules = true } + ], + ['--no-search', '--nosearch', '-N', "Do not search parent directories for the Rakefile.", + lambda { |value| options.nosearch = true } + ], + ['--silent', '-s', "Like --quiet, but also suppresses the 'in directory' announcement.", + lambda { |value| + verbose(false) + options.silent = true + } + ], + ['--system', '-g', + "Using system wide (global) rakefiles (usually '~/.rake/*.rake').", + lambda { |value| options.load_system = true } + ], + ['--no-system', '--nosystem', '-G', + "Use standard project Rakefile search paths, ignore system wide rakefiles.", + lambda { |value| options.ignore_system = true } + ], + ['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.", + lambda { |value| + options.show_tasks = true + options.show_task_pattern = Regexp.new(value || '') + options.full_description = false + } + ], + ['--trace', '-t', "Turn on invoke/execute tracing, enable full backtrace.", + lambda { |value| + options.trace = true + verbose(true) + } + ], + ['--verbose', '-v', "Log message to standard output (default).", + lambda { |value| verbose(true) } + ], + ['--version', '-V', "Display the program version.", + lambda { |value| + puts "rake, version #{RAKEVERSION}" + exit + } + ] + ] end # Read and handle the command line options. def handle_options options.rakelib = ['rakelib'] - opts = GetoptLong.new(*command_line_options) - opts.each { |opt, value| do_option(opt, value) } + opts = OptionParser.new + opts.banner = "rake [-f rakefile] {options} targets..." + opts.separator "" + opts.separator "Options are ..." + + opts.on_tail("-h", "--help", "-H", "Display this help message.") do + puts opts + exit + end + + standard_rake_options.each { |args| opts.on(*args) } + parsed_argv = opts.parse(ARGV) # If class namespaces are requested, set the global options # according to the values in the options structure. @@ -2120,12 +2308,11 @@ module Rake $dryrun = options.dryrun $silent = options.silent end - rescue NoMethodError => ex - raise GetoptLong::InvalidOption, "While parsing options, error = #{ex.class}:#{ex.message}" + parsed_argv end # Similar to the regular Ruby +require+ command, but will check - # for .rake files in addition to .rb files. + # for *.rake files in addition to *.rb files. def rake_require(file_name, paths=$LOAD_PATH, loaded=$") return false if loaded.include?(file_name) paths.each do |path| @@ -2140,34 +2327,95 @@ module Rake fail LoadError, "Can't find #{file_name}" end - def raw_load_rakefile # :nodoc: + def find_rakefile_location here = Dir.pwd - while ! have_rakefile + while ! (fn = have_rakefile) Dir.chdir("..") if Dir.pwd == here || options.nosearch - fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" + return nil end here = Dir.pwd end - puts "(in #{Dir.pwd})" unless options.silent - $rakefile = @rakefile - load File.expand_path(@rakefile) if @rakefile != '' - options.rakelib.each do |rlib| - Dir["#{rlib}/*.rake"].each do |name| add_import name end + [fn, here] + ensure + Dir.chdir(Rake.original_dir) + end + + def raw_load_rakefile # :nodoc: + rakefile, location = find_rakefile_location + if (! options.ignore_system) && + (options.load_system || rakefile.nil?) && + directory?(system_dir) + puts "(in #{Dir.pwd})" unless options.silent + glob("#{system_dir}/*.rake") do |name| + add_import name + end + else + fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})" if + rakefile.nil? + @rakefile = rakefile + Dir.chdir(location) + puts "(in #{Dir.pwd})" unless options.silent + $rakefile = @rakefile if options.classic_namespace + load File.expand_path(@rakefile) if @rakefile && @rakefile != '' + options.rakelib.each do |rlib| + glob("#{rlib}/*.rake") do |name| + add_import name + end + end end load_imports end + def glob(path, &block) + Dir[path.gsub("\\", '/')].each(&block) + end + private :glob + + # The directory path containing the system wide rakefiles. + def system_dir + if ENV['RAKE_SYSTEM'] + ENV['RAKE_SYSTEM'] + elsif windows? + win32_system_dir + else + standard_system_dir + end + end + + # The standard directory containing system wide rake files. + def standard_system_dir #:nodoc: + File.join(File.expand_path('~'), '.rake') + end + private :standard_system_dir + + # The standard directory containing system wide rake files on Win + # 32 systems. + def win32_system_dir #:nodoc: + win32home = File.join(ENV['APPDATA'], 'Rake') + unless directory?(win32home) + raise Win32HomeError, "Unable to determine home path environment variable." + else + win32home + end + end + private :win32_system_dir + + def directory?(path) + File.directory?(path) + end + private :directory? + # Collect the list of tasks on the command line. If no tasks are # given, return a list containing only the default task. # Environmental assignments are processed at this time as well. - def collect_tasks + def collect_tasks(argv) @top_level_tasks = [] - ARGV.each do |arg| + argv.each do |arg| if arg =~ /^(\w+)=(.*)$/ ENV[$1] = $2 else - @top_level_tasks << arg + @top_level_tasks << arg unless arg =~ /^-/ end end @top_level_tasks.push("default") if @top_level_tasks.size == 0 diff --git a/lib/rake/loaders/makefile.rb b/lib/rake/loaders/makefile.rb index f66eb3b35f..9ade098a1b 100644 --- a/lib/rake/loaders/makefile.rb +++ b/lib/rake/loaders/makefile.rb @@ -7,31 +7,26 @@ module Rake # Load the makefile dependencies in +fn+. def load(fn) - buffer = '' open(fn) do |mf| - mf.each do |line| - next if line =~ /^\s*#/ - buffer << line - if buffer =~ /\\$/ - buffer.sub!(/\\\n/, ' ') - state = :append - else - process_line(buffer) - buffer = '' - end + lines = mf.read + lines.gsub!(/#[^\n]*\n/m, "") + lines.gsub!(/\\\n/, ' ') + lines.split("\n").each do |line| + process_line(line) end end - process_line(buffer) if buffer != '' end private # Process one logical line of makefile data. def process_line(line) - file_task, args = line.split(':') + file_tasks, args = line.split(':') return if args.nil? dependents = args.split - file file_task => dependents + file_tasks.strip.split.each do |file_task| + file file_task => dependents + end end end diff --git a/lib/rake/packagetask.rb b/lib/rake/packagetask.rb index 71b66a6481..4b0775d09c 100644 --- a/lib/rake/packagetask.rb +++ b/lib/rake/packagetask.rb @@ -122,6 +122,7 @@ module Rake task :package => ["#{package_dir}/#{file}"] file "#{package_dir}/#{file}" => [package_dir_path] + package_files do chdir(package_dir) do + sh %{env} sh %{#{@tar_command} #{flag}cvf #{file} #{package_name}} end end diff --git a/lib/rake/rdoctask.rb b/lib/rake/rdoctask.rb index 54adc6feb5..6cfbda1d6a 100644 --- a/lib/rake/rdoctask.rb +++ b/lib/rake/rdoctask.rb @@ -55,7 +55,7 @@ module Rake # RDoc. (default is none) attr_accessor :main - # Name of template to be used by rdoc. (default is 'html') + # Name of template to be used by rdoc. (defaults to rdoc's default) attr_accessor :template # List of files to be included in the rdoc generation. (default is []) @@ -74,7 +74,7 @@ module Rake @rdoc_dir = 'html' @main = nil @title = nil - @template = 'html' + @template = nil @external = false @options = [] yield self if block_given? @@ -91,18 +91,18 @@ module Rake task name desc "Force a rebuild of the RDOC files" - task paste("re", name) => [paste("clobber_", name), name] + task "re#{name}" => ["clobber_#{name}", name] desc "Remove rdoc products" - task paste("clobber_", name) do + task "clobber_#{name}" do rm_r rdoc_dir rescue nil end - - task :clobber => [paste("clobber_", name)] + + task :clobber => ["clobber_#{name}"] directory @rdoc_dir task name => [rdoc_target] - file rdoc_target => @rdoc_files + [$rakefile] do + file rdoc_target => @rdoc_files + [Rake.application.rakefile] do rm_r @rdoc_dir rescue nil args = option_list + @rdoc_files if @external diff --git a/lib/rake/tasklib.rb b/lib/rake/tasklib.rb index 465a58a0c7..c7fd98133c 100644 --- a/lib/rake/tasklib.rb +++ b/lib/rake/tasklib.rb @@ -6,11 +6,16 @@ module Rake # Base class for Task Libraries. class TaskLib - include Cloneable - # Make a symbol by pasting two strings together. - def paste(a,b) + # Make a symbol by pasting two strings together. + # + # NOTE: DEPRECATED! This method is kinda stupid. I don't know why + # I didn't just use string interpolation. But now other task + # libraries depend on this so I can't remove it without breaking + # other people's code. So for now it stays for backwards + # compatibility. BUT DON'T USE IT. + def paste(a,b) # :nodoc: (a.to_s + b.to_s).intern end end diff --git a/lib/rake/testtask.rb b/lib/rake/testtask.rb index f5b77e5957..79154e422b 100644 --- a/lib/rake/testtask.rb +++ b/lib/rake/testtask.rb @@ -136,7 +136,12 @@ module Rake end def fix # :nodoc: - '' + case RUBY_VERSION + when '1.8.2' + find_file 'rake/ruby182_test_unit_fix' + else + nil + end || '' end def rake_loader # :nodoc: diff --git a/lib/resolv.rb b/lib/resolv.rb index d1494b46c9..fc3c78215b 100644 --- a/lib/resolv.rb +++ b/lib/resolv.rb @@ -13,24 +13,24 @@ end # interpreter. # # See also resolv-replace.rb to replace the libc resolver with # Resolv. -# +# # Resolv can look up various DNS resources using the DNS module directly. -# +# # Examples: -# +# # p Resolv.getaddress "www.ruby-lang.org" # p Resolv.getname "210.251.121.214" -# +# # Resolv::DNS.open do |dns| # ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A # p ress.map { |r| r.address } # ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX # p ress.map { |r| [r.exchange.to_s, r.preference] } # end -# -# +# +# # == Bugs -# +# # * NIS is not supported. # * /etc/nsswitch.conf is not supported. @@ -38,14 +38,14 @@ class Resolv ## # Looks up the first IP address for +name+. - + def self.getaddress(name) DefaultResolver.getaddress(name) end ## # Looks up all IP address for +name+. - + def self.getaddresses(name) DefaultResolver.getaddresses(name) end @@ -87,7 +87,7 @@ class Resolv ## # Looks up the first IP address for +name+. - + def getaddress(name) each_address(name) {|address| return address} raise ResolvError.new("no address for #{name}") @@ -95,7 +95,7 @@ class Resolv ## # Looks up all IP address for +name+. - + def getaddresses(name) ret = [] each_address(name) {|address| ret << address} @@ -309,7 +309,7 @@ class Resolv # Creates a new DNS resolver. # # +config_info+ can be: - # + # # nil:: Uses /etc/resolv.conf. # String:: Path to a file using /etc/resolv.conf's format. # Hash:: Must contain :nameserver, :search and :ndots keys. @@ -457,7 +457,7 @@ class Resolv ## # Looks up all +typeclass+ DNS resources for +name+. See #getresource for # argument details. - + def getresources(name, typeclass) ret = [] each_resource(name, typeclass) {|resource| ret << resource} @@ -467,7 +467,7 @@ class Resolv ## # Iterates over all +typeclass+ DNS resources for +name+. See # #getresource for argument details. - + def each_resource(name, typeclass, &proc) lazy_initialize requester = make_requester @@ -569,7 +569,7 @@ class Resolv h = (RequestID[[host, port]] ||= {}) begin id = rangerand(0x0000..0xffff) - end while h[id] + end while h[id] h[id] = true } id @@ -1037,7 +1037,7 @@ class Resolv # A representation of a DNS name. class Name - + ## # Creates a new DNS name from +arg+. +arg+ can be: # @@ -1460,11 +1460,11 @@ class Resolv class Query def encode_rdata(msg) # :nodoc: - raise EncodeError.new("#{self.class} is query.") + raise EncodeError.new("#{self.class} is query.") end def self.decode_rdata(msg) # :nodoc: - raise DecodeError.new("#{self.class} is query.") + raise DecodeError.new("#{self.class} is query.") end end @@ -1939,7 +1939,7 @@ class Resolv def initialize(address) @address = IPv6.create(address) end - + ## # The Resolv::IPv6 address for this AAAA. @@ -1956,7 +1956,7 @@ class Resolv ## # SRV resource record defined in RFC 2782 - # + # # These records identify the hostname and port that a service is # available at. diff --git a/lib/time.rb b/lib/time.rb index 96f3945320..85c715b80b 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -1,37 +1,37 @@ # # == Introduction -# +# # This library extends the Time class: # * conversion between date string and time object. # * date-time defined by RFC 2822 # * HTTP-date defined by RFC 2616 # * dateTime defined by XML Schema Part 2: Datatypes (ISO 8601) # * various formats handled by Date._parse (string to time only) -# +# # == Design Issues -# +# # === Specialized interface -# +# # This library provides methods dedicated to special purposes: # * RFC 2822, RFC 2616 and XML Schema. # * They makes usual life easier. -# +# # === Doesn't depend on strftime -# +# # This library doesn't use +strftime+. Especially #rfc2822 doesn't depend # on +strftime+ because: -# +# # * %a and %b are locale sensitive -# +# # Since they are locale sensitive, they may be replaced to # invalid weekday/month name in some locales. # Since ruby-1.6 doesn't invoke setlocale by default, # the problem doesn't arise until some external library invokes setlocale. # Ruby/GTK is the example of such library. -# +# # * %z is not portable -# +# # %z is required to generate zone in date-time of RFC 2822 # but it is not portable. # @@ -61,9 +61,9 @@ class Time 'PST' => -8, 'PDT' => -7, # Following definition of military zones is original one. # See RFC 1123 and RFC 2822 for the error in RFC 822. - 'A' => +1, 'B' => +2, 'C' => +3, 'D' => +4, 'E' => +5, 'F' => +6, + 'A' => +1, 'B' => +2, 'C' => +3, 'D' => +4, 'E' => +5, 'F' => +6, 'G' => +7, 'H' => +8, 'I' => +9, 'K' => +10, 'L' => +11, 'M' => +12, - 'N' => -1, 'O' => -2, 'P' => -3, 'Q' => -4, 'R' => -5, 'S' => -6, + 'N' => -1, 'O' => -2, 'P' => -3, 'Q' => -4, 'R' => -5, 'S' => -6, 'T' => -7, 'U' => -8, 'V' => -9, 'W' => -10, 'X' => -11, 'Y' => -12, } def zone_offset(zone, year=self.now.year) @@ -436,8 +436,8 @@ class Time # # Returns a string which represents the time as rfc1123-date of HTTP-date - # defined by RFC 2616: - # + # defined by RFC 2616: + # # day-of-week, DD month-name CCYY hh:mm:ss GMT # # Note that the result is always UTC (GMT). @@ -768,21 +768,21 @@ if __FILE__ == $0 def test_rfc2822_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:59 UTC")) - assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 -0000"));t.localtime + assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:59 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:59 +0100")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:59 +0000")) - assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:59 -0100"));t.utc + assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:59 -0100"));t.utc t += 1 assert_equal(t, Time.rfc2822("Thu, 31 Dec 1998 23:59:60 UTC")) - assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 -0000"));t.localtime + assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 08:59:60 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:59:60 +0100")) assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 23:59:60 +0000")) - assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:60 -0100"));t.utc + assert_equal(t, Time.rfc2822("Fri, 31 Dec 1998 22:59:60 -0100"));t.utc t += 1 if t.sec == 60 assert_equal(t, Time.rfc2822("Thu, 1 Jan 1999 00:00:00 UTC")) - assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 -0000"));t.localtime + assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 -0000"));t.localtime assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 09:00:00 +0900")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 01:00:00 +0100")) assert_equal(t, Time.rfc2822("Fri, 1 Jan 1999 00:00:00 +0000")) diff --git a/lib/tsort.rb b/lib/tsort.rb index a014e7f6c2..9fc4feadcd 100644 --- a/lib/tsort.rb +++ b/lib/tsort.rb @@ -32,7 +32,7 @@ # array using the user-supplied block. # # require 'tsort' -# +# # class Hash # include TSort # alias tsort_each_node each_key @@ -40,10 +40,10 @@ # fetch(node).each(&block) # end # end -# +# # {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort # #=> [3, 2, 1, 4] -# +# # {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components # #=> [[4], [2, 3], [1]] # @@ -52,19 +52,19 @@ # A very simple `make' like tool can be implemented as follows: # # require 'tsort' -# +# # class Make # def initialize # @dep = {} # @dep.default = [] # end -# +# # def rule(outputs, inputs=[], &block) # triple = [outputs, inputs, block] # outputs.each {|f| @dep[f] = [triple]} # @dep[triple] = inputs # end -# +# # def build(target) # each_strongly_connected_component_from(target) {|ns| # if ns.length != 1 @@ -88,18 +88,18 @@ # end # } # end -# +# # def tsort_each_child(node, &block) # @dep[node].each(&block) # end # include TSort # end -# +# # def command(arg) # print arg, "\n" # system arg # end -# +# # m = Make.new # m.rule(%w[t1]) { command 'date > t1' } # m.rule(%w[t2]) { command 'date > t2' } @@ -189,7 +189,7 @@ module TSort end # - # Iterates over strongly connected component in the subgraph reachable from + # Iterates over strongly connected component in the subgraph reachable from # _node_. # # Return value is unspecified. diff --git a/lib/uri/common.rb b/lib/uri/common.rb index 98dda2a350..9a6a06894a 100644 --- a/lib/uri/common.rb +++ b/lib/uri/common.rb @@ -227,7 +227,7 @@ module URI end def unescape(str, escaped = @regexp[:ESCAPED]) - str.gsub(escaped) { [$&.hex].pack('U') } + str.gsub(escaped) { [$&[1, 2].hex].pack('U') } end @@to_s = Kernel.instance_method(:to_s) @@ -698,5 +698,5 @@ Init_load() rb_define_global_function("autoload?", rb_f_autoload_p, 1); ruby_dln_librefs = rb_ary_new(); - rb_register_mark_object(ruby_dln_librefs); + rb_gc_register_mark_object(ruby_dln_librefs); } @@ -1723,9 +1723,9 @@ Init_marshal(void) rb_define_const(rb_mMarshal, "MINOR_VERSION", INT2FIX(MARSHAL_MINOR)); compat_allocator_tbl = st_init_numtable(); - rb_gc_register_address(&compat_allocator_tbl_wrapper); compat_allocator_tbl_wrapper = Data_Wrap_Struct(rb_cData, mark_marshal_compat_t, 0, compat_allocator_tbl); + rb_gc_register_mark_object(compat_allocator_tbl_wrapper); } VALUE @@ -353,7 +353,7 @@ math_log(int argc, VALUE *argv) Need_Float(x); errno = 0; d = log(RFLOAT_VALUE(x)); - if (!NIL_P(base)) { + if (argc == 2) { Need_Float(base); d /= log(RFLOAT_VALUE(base)); } @@ -78,6 +78,9 @@ round(double x) } return x; } +#elif defined(__BEOS__) +/* appears to be a bug in the BeOS headers */ +double round(double x); #endif static ID id_coerce, id_to_i, id_eq; @@ -385,14 +388,14 @@ num_remainder(VALUE x, VALUE y) /* * call-seq: - * num.scalar? -> true or false + * num.real? -> true or false * - * Returns <code>true</code> if <i>num</i> is an <code>Scalar</code> + * Returns <code>true</code> if <i>num</i> is a <code>Real</code> * (i.e. non <code>Complex</code>). */ static VALUE -num_scalar_p(VALUE num) +num_real_p(VALUE num) { return Qtrue; } @@ -1948,66 +1951,6 @@ int_denominator(VALUE num) /* * call-seq: - * Fixnum.induced_from(obj) => fixnum - * - * Convert <code>obj</code> to a Fixnum. Works with numeric parameters. - * Also works with Symbols, but this is deprecated. - */ - -static VALUE -rb_fix_induced_from(VALUE klass, VALUE x) -{ - return rb_num2fix(x); -} - -/* - * call-seq: - * Integer.induced_from(obj) => fixnum, bignum - * - * Convert <code>obj</code> to an Integer. - */ - -static VALUE -rb_int_induced_from(VALUE klass, VALUE x) -{ - switch (TYPE(x)) { - case T_FIXNUM: - 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", - rb_obj_classname(x)); - } -} - -/* - * call-seq: - * Float.induced_from(obj) => float - * - * Convert <code>obj</code> to a float. - */ - -static VALUE -rb_flo_induced_from(VALUE klass, VALUE x) -{ - 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; - default: - rb_raise(rb_eTypeError, "failed to convert %s into Float", - rb_obj_classname(x)); - } -} - -/* - * call-seq: * -fix => integer * * Negates <code>fix</code> (which might return a Bignum). @@ -2447,7 +2390,7 @@ fix_pow(VALUE x, VALUE y) long b = FIX2LONG(y); if (b < 0) - return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); + return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); if (b == 0) return INT2FIX(1); if (b == 1) return x; @@ -2468,7 +2411,7 @@ fix_pow(VALUE x, VALUE y) case T_BIGNUM: if (rb_funcall(y, '<', 1, INT2FIX(0))) - return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); + return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); if (a == 0) return INT2FIX(0); if (a == 1) return INT2FIX(1); @@ -3145,7 +3088,7 @@ Init_Numeric(void) rb_define_method(rb_cNumeric, "magnitude", num_abs, 0); rb_define_method(rb_cNumeric, "to_int", num_to_int, 0); - rb_define_method(rb_cNumeric, "scalar?", num_scalar_p, 0); + rb_define_method(rb_cNumeric, "real?", num_real_p, 0); rb_define_method(rb_cNumeric, "integer?", num_int_p, 0); rb_define_method(rb_cNumeric, "zero?", num_zero_p, 0); rb_define_method(rb_cNumeric, "nonzero?", num_nonzero_p, 0); @@ -3169,7 +3112,6 @@ Init_Numeric(void) rb_define_method(rb_cInteger, "upto", int_upto, 1); rb_define_method(rb_cInteger, "downto", int_downto, 1); rb_define_method(rb_cInteger, "times", int_dotimes, 0); - rb_include_module(rb_cInteger, rb_mPrecision); rb_define_method(rb_cInteger, "succ", int_succ, 0); rb_define_method(rb_cInteger, "next", int_succ, 0); rb_define_method(rb_cInteger, "pred", int_pred, 0); @@ -3182,9 +3124,6 @@ Init_Numeric(void) rb_define_method(rb_cInteger, "round", int_round, -1); rb_cFixnum = rb_define_class("Fixnum", rb_cInteger); - rb_include_module(rb_cFixnum, rb_mPrecision); - 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); @@ -3234,9 +3173,6 @@ Init_Numeric(void) rb_undef_alloc_func(rb_cFloat); rb_undef_method(CLASS_OF(rb_cFloat), "new"); - rb_define_singleton_method(rb_cFloat, "induced_from", rb_flo_induced_from, 1); - rb_include_module(rb_cFloat, rb_mPrecision); - rb_define_const(rb_cFloat, "ROUNDS", INT2FIX(FLT_ROUNDS)); rb_define_const(rb_cFloat, "RADIX", INT2FIX(FLT_RADIX)); rb_define_const(rb_cFloat, "MANT_DIG", INT2FIX(DBL_MANT_DIG)); @@ -2369,6 +2369,12 @@ boot_defclass(const char *name, VALUE super) return obj; } +static void +boot_defmetametaclass(VALUE klass, VALUE metametaclass) +{ + RBASIC(RBASIC(klass)->klass)->klass = metametaclass; +} + /* * Document-class: Class * @@ -2467,6 +2473,9 @@ Init_Object(void) metaclass = rb_make_metaclass(rb_cObject, metaclass); metaclass = rb_make_metaclass(rb_cModule, metaclass); metaclass = rb_make_metaclass(rb_cClass, metaclass); + boot_defmetametaclass(rb_cModule, metaclass); + boot_defmetametaclass(rb_cObject, metaclass); + boot_defmetametaclass(rb_cBasicObject, metaclass); rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0); rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance); @@ -264,12 +264,11 @@ struct parser_params { #define UTF8_ENC() (parser->utf8 ? parser->utf8 : \ (parser->utf8 = rb_utf8_encoding())) #define STR_NEW(p,n) rb_enc_str_new((p),(n),parser->enc) -#define STR_NEW0() rb_usascii_str_new(0,0) +#define STR_NEW0() rb_enc_str_new(0,0,parser->enc) #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) -#define TOK_INTERN(mb) rb_intern3(tok(), toklen(), STR_ENC(mb)) +#define TOK_INTERN(mb) rb_intern3(tok(), toklen(), parser->enc) #ifdef YYMALLOC void *rb_parser_malloc(struct parser_params *, size_t); @@ -4877,11 +4876,11 @@ parser_yyerror(struct parser_params *parser, const char *msg) if (len > max_line_margin * 2 + 10) { if (lex_p - p > max_line_margin) { - p = rb_enc_prev_char(p, lex_p - max_line_margin, rb_enc_get(lex_lastline)); + p = rb_enc_prev_char(p, lex_p - max_line_margin, pe, rb_enc_get(lex_lastline)); pre = "..."; } if (pe - lex_p > max_line_margin) { - pe = rb_enc_prev_char(lex_p, lex_p + max_line_margin, rb_enc_get(lex_lastline)); + pe = rb_enc_prev_char(lex_p, lex_p + max_line_margin, pe, rb_enc_get(lex_lastline)); post = "..."; } len = pe - p; @@ -5150,7 +5149,6 @@ parser_str_new(const char *p, long n, rb_encoding *enc, int func, rb_encoding *e str = rb_enc_str_new(p, n, enc); 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()); } else if (enc0 == rb_usascii_encoding() && enc != rb_utf8_encoding()) { rb_enc_associate(str, rb_ascii8bit_encoding()); diff --git a/prec.c b/prec.c deleted file mode 100644 index 84de958be8..0000000000 --- a/prec.c +++ /dev/null @@ -1,138 +0,0 @@ -/********************************************************************** - - prec.c - - - $Author$ - created at: Tue Jan 26 02:40:41 2000 - - Copyright (C) 1993-2007 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby/ruby.h" - -VALUE rb_mPrecision; - -static ID prc_pr, prc_if; - - -/* - * call-seq: - * num.prec(klass) => a_class - * - * Converts _self_ into an instance of _klass_. By default, - * +prec+ invokes - * - * klass.induced_from(num) - * - * and returns its value. So, if <code>klass.induced_from</code> - * doesn't return an instance of _klass_, it will be necessary - * to reimplement +prec+. - */ - -static VALUE -prec_prec(VALUE x, VALUE klass) -{ - return rb_funcall(klass, prc_if, 1, x); -} - -/* - * call-seq: - * num.prec_i => Integer - * - * Returns an +Integer+ converted from _num_. It is equivalent - * to <code>prec(Integer)</code>. - */ - -static VALUE -prec_prec_i(VALUE x) -{ - VALUE klass = rb_cInteger; - - return rb_funcall(x, prc_pr, 1, klass); -} - -/* - * call-seq: - * num.prec_f => Float - * - * Returns a +Float+ converted from _num_. It is equivalent - * to <code>prec(Float)</code>. - */ - -static VALUE -prec_prec_f(VALUE x) -{ - VALUE klass = rb_cFloat; - - return rb_funcall(x, prc_pr, 1, klass); -} - -/* - * call-seq: - * Mod.induced_from(number) => a_mod - * - * Creates an instance of mod from. This method is overridden - * by concrete +Numeric+ classes, so that (for example) - * - * Fixnum.induced_from(9.9) #=> 9 - * - * Note that a use of +prec+ in a redefinition may cause - * an infinite loop. - */ - -static VALUE -prec_induced_from(VALUE module, VALUE x) -{ - rb_raise(rb_eTypeError, "undefined conversion from %s into %s", - rb_obj_classname(x), rb_class2name(module)); - return Qnil; /* not reached */ -} - -/* - * call_seq: - * included - * - * When the +Precision+ module is mixed-in to a class, this +included+ - * method is used to add our default +induced_from+ implementation - * to the host class. - */ - -static VALUE -prec_included(VALUE module, VALUE include) -{ - switch (TYPE(include)) { - case T_CLASS: - case T_MODULE: - break; - default: - Check_Type(include, T_CLASS); - break; - } - rb_define_singleton_method(include, "induced_from", prec_induced_from, 1); - return module; -} - -/* - * Precision is a mixin for concrete numeric classes with - * precision. Here, `precision' means the fineness of approximation - * of a real number, so, this module should not be included into - * anything which is not a subset of Real (so it should not be - * included in classes such as +Complex+ or +Matrix+). -*/ - -void -Init_Precision(void) -{ -#undef rb_intern -#define rb_intern(str) rb_intern_const(str) - - rb_mPrecision = rb_define_module("Precision"); - rb_define_singleton_method(rb_mPrecision, "included", prec_included, 1); - rb_define_method(rb_mPrecision, "prec", prec_prec, 1); - rb_define_method(rb_mPrecision, "prec_i", prec_prec_i, 0); - rb_define_method(rb_mPrecision, "prec_f", prec_prec_f, 0); - - prc_pr = rb_intern("prec"); - prc_if = rb_intern("induced_from"); -} diff --git a/rational.c b/rational.c index 7274ace1ff..3b352ea9da 100644 --- a/rational.c +++ b/rational.c @@ -27,8 +27,8 @@ 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_integer_p, id_negate, - id_new, id_new_bang, id_to_f, id_to_i, id_to_s, id_truncate; + id_floor, id_format, id_hash, id_idiv, id_inspect, id_integer_p, + id_negate, id_to_f, id_to_i, id_to_s, id_truncate; #define f_boolcast(x) ((x) ? Qtrue : Qfalse) @@ -139,6 +139,7 @@ binop(xor, '^') fun1(abs) fun1(floor) +fun1(hash) fun1(inspect) fun1(integer_p) fun1(negate) @@ -166,6 +167,8 @@ f_negative_p(VALUE x) return rb_funcall(x, '<', 1, ZERO); } +#define f_positive_p(x) (!f_negative_p(x)) + inline static VALUE f_zero_p(VALUE x) { @@ -174,6 +177,8 @@ f_zero_p(VALUE x) return rb_funcall(x, id_equal_p, 1, ZERO); } +#define f_nonzero_p(x) (!f_zero_p(x)) + inline static VALUE f_one_p(VALUE x) { @@ -212,6 +217,9 @@ k_rational_p(VALUE x) return f_kind_of_p(x, rb_cRational); } +#define k_exact_p(x) (!k_float_p(x)) +#define k_inexact_p(x) k_float_p(x) + #ifndef NDEBUG #define f_gcd f_gcd_orig #endif @@ -276,7 +284,7 @@ inline static VALUE f_gcd(VALUE x, VALUE y) { VALUE r = f_gcd_orig(x, y); - if (!f_zero_p(r)) { + if (f_nonzero_p(r)) { assert(f_zero_p(f_mod(x, r))); assert(f_zero_p(f_mod(y, r))); } @@ -362,8 +370,8 @@ f_rational_new_bang1(VALUE klass, VALUE x) inline static VALUE f_rational_new_bang2(VALUE klass, VALUE x, VALUE y) { - assert(!f_negative_p(y)); - assert(!f_zero_p(y)); + assert(f_positive_p(y)); + assert(f_nonzero_p(y)); return nurat_s_new_internal(klass, x, y); } @@ -772,7 +780,7 @@ nurat_fdiv(VALUE self, VALUE other) static VALUE nurat_expt(VALUE self, VALUE other) { - if (f_zero_p(other)) + if (k_exact_p(other) && f_zero_p(other)) return f_rational_new_bang1(CLASS_OF(self), ONE); if (k_rational_p(other)) { @@ -951,7 +959,7 @@ nurat_quotrem(VALUE self, VALUE other) static VALUE nurat_abs(VALUE self) { - if (!f_negative_p(self)) + if (f_positive_p(self)) return self; return f_negate(self); } @@ -1102,7 +1110,7 @@ static VALUE nurat_hash(VALUE self) { get_dat1(self); - return f_xor(dat->num, dat->den); + return f_xor(f_hash(dat->num), f_hash(dat->den)); } static VALUE @@ -1124,8 +1132,12 @@ nurat_inspect(VALUE self) static VALUE nurat_marshal_dump(VALUE self) { + VALUE a; get_dat1(self); - return rb_assoc_new(dat->num, dat->den); + + a = rb_assoc_new(dat->num, dat->den); + rb_copy_generic_ivar(a, self); + return a; } static VALUE @@ -1134,6 +1146,7 @@ nurat_marshal_load(VALUE self, VALUE a) get_dat1(self); dat->num = RARRAY_PTR(a)[0]; dat->den = RARRAY_PTR(a)[1]; + rb_copy_generic_ivar(self, a); if (f_zero_p(dat->den)) rb_raise_zerodiv(); @@ -1251,20 +1264,20 @@ make_patterns(void) if (rat_pat) return; rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0); - rb_global_variable(&rat_pat); + rb_gc_register_mark_object(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); + rb_gc_register_mark_object(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); + rb_gc_register_mark_object(a_dot_pat); underscores_pat = rb_reg_new(underscores_pat_source, sizeof underscores_pat_source - 1, 0); - rb_global_variable(&underscores_pat); + rb_gc_register_mark_object(underscores_pat); an_underscore = rb_str_new2("_"); - rb_global_variable(&an_underscore); + rb_gc_register_mark_object(an_underscore); } #define id_match rb_intern("match") @@ -1393,26 +1406,18 @@ nurat_s_convert(int argc, VALUE *argv, VALUE klass) { VALUE a1, a2, backref; - rb_scan_args(argc, argv, "02", &a1, &a2); + rb_scan_args(argc, argv, "11", &a1, &a2); 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; + if (k_exact_p(RCOMPLEX(a1)->imag) && f_zero_p(RCOMPLEX(a1)->imag)) + 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; + if (k_exact_p(RCOMPLEX(a2)->imag) && f_zero_p(RCOMPLEX(a2)->imag)) + a2 = RCOMPLEX(a2)->real; } backref = rb_backref_get(); @@ -1446,14 +1451,18 @@ nurat_s_convert(int argc, VALUE *argv, VALUE klass) switch (TYPE(a1)) { case T_RATIONAL: - if (NIL_P(a2) || f_zero_p(a2)) + if (argc == 1 || (k_exact_p(a2) && f_one_p(a2))) return a1; - return f_div(a1, a2); } - switch (TYPE(a2)) { - case T_RATIONAL: - return f_div(a1, a2); + if (argc == 1) { + if (k_numeric_p(a1) && !f_integer_p(a1)) + return a1; + } + else { + if ((k_numeric_p(a1) && k_numeric_p(a2)) && + (!f_integer_p(a1) || !f_integer_p(a2))) + return f_div(a1, a2); } { @@ -1464,12 +1473,6 @@ nurat_s_convert(int argc, VALUE *argv, VALUE klass) } } -static VALUE -nurat_s_induced_from(VALUE klass, VALUE n) -{ - return f_to_r(n); -} - void Init_Rational(void) { @@ -1486,12 +1489,11 @@ Init_Rational(void) id_expt = rb_intern("**"); id_floor = rb_intern("floor"); id_format = rb_intern("format"); + id_hash = rb_intern("hash"); id_idiv = rb_intern("div"); id_inspect = rb_intern("inspect"); id_integer_p = rb_intern("integer?"); 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"); @@ -1587,8 +1589,10 @@ Init_Rational(void) 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); } + +/* +Local variables: +c-file-style: "ruby" +End: +*/ @@ -380,8 +380,12 @@ static VALUE rb_reg_desc(const char *s, long len, VALUE re) { VALUE str = rb_str_buf_new2("/"); - - rb_enc_copy(str, re); + if (rb_enc_asciicompat(rb_enc_get(re))) { + rb_enc_copy(str, re); + } + else { + rb_enc_associate(str, rb_usascii_encoding()); + } rb_reg_expr_str(str, s, len); rb_str_buf_cat2(str, "/"); if (re) { @@ -1264,10 +1268,10 @@ rb_reg_adjust_startpos(VALUE re, VALUE str, int pos, int reverse) string = (UChar*)RSTRING_PTR(str); if (range > 0) { - p = onigenc_get_right_adjust_char_head(enc, string, string + pos); + p = onigenc_get_right_adjust_char_head(enc, string, string + pos, string + RSTRING_LEN(str)); } else { - p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, string, string + pos); + p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, string, string + pos, string + RSTRING_LEN(str)); } return p - string; } @@ -2860,34 +2864,34 @@ rb_reg_quote(VALUE str) case '*': case '.': case '\\': case '?': case '+': case '^': case '$': case '#': - *t++ = '\\'; + t += rb_enc_mbcput('\\', t, enc); break; case ' ': - *t++ = '\\'; - *t++ = ' '; + t += rb_enc_mbcput('\\', t, enc); + t += rb_enc_mbcput(' ', t, enc); continue; case '\t': - *t++ = '\\'; - *t++ = 't'; + t += rb_enc_mbcput('\\', t, enc); + t += rb_enc_mbcput('t', t, enc); continue; case '\n': - *t++ = '\\'; - *t++ = 'n'; + t += rb_enc_mbcput('\\', t, enc); + t += rb_enc_mbcput('n', t, enc); continue; case '\r': - *t++ = '\\'; - *t++ = 'r'; + t += rb_enc_mbcput('\\', t, enc); + t += rb_enc_mbcput('r', t, enc); continue; case '\f': - *t++ = '\\'; - *t++ = 'f'; + t += rb_enc_mbcput('\\', t, enc); + t += rb_enc_mbcput('f', t, enc); continue; case '\v': - *t++ = '\\'; - *t++ = 'v'; + t += rb_enc_mbcput('\\', t, enc); + t += rb_enc_mbcput('v', t, enc); continue; } - *t++ = c; + t += rb_enc_mbcput(c, t, enc); } rb_str_resize(tmp, t - RSTRING_PTR(tmp)); OBJ_INFECT(tmp, str); @@ -62,24 +62,24 @@ onigenc_mbclen_approximate(const OnigUChar* p,const OnigUChar* e, struct OnigEnc } extern UChar* -onigenc_get_right_adjust_char_head(OnigEncoding enc, const UChar* start, const UChar* s) +onigenc_get_right_adjust_char_head(OnigEncoding enc, const UChar* start, const UChar* s, const UChar* end) { - UChar* p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s); + UChar* p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s, end); if (p < s) { - p += enclen(enc, p, s); + p += enclen(enc, p, end); } return p; } extern UChar* onigenc_get_right_adjust_char_head_with_prev(OnigEncoding enc, - const UChar* start, const UChar* s, const UChar** prev) + const UChar* start, const UChar* s, const UChar* end, const UChar** prev) { - UChar* p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s); + UChar* p = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s, end); if (p < s) { if (prev) *prev = (const UChar* )p; - p += enclen(enc, p, s); + p += enclen(enc, p, end); } else { if (prev) *prev = (const UChar* )NULL; /* Sorry */ @@ -88,22 +88,22 @@ onigenc_get_right_adjust_char_head_with_prev(OnigEncoding enc, } extern UChar* -onigenc_get_prev_char_head(OnigEncoding enc, const UChar* start, const UChar* s) +onigenc_get_prev_char_head(OnigEncoding enc, const UChar* start, const UChar* s, const UChar* end) { if (s <= start) return (UChar* )NULL; - return ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s - 1); + return ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s - 1, end); } extern UChar* -onigenc_step_back(OnigEncoding enc, const UChar* start, const UChar* s, int n) +onigenc_step_back(OnigEncoding enc, const UChar* start, const UChar* s, const UChar* end, int n) { while (ONIG_IS_NOT_NULL(s) && n-- > 0) { if (s <= start) return (UChar* )NULL; - s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s - 1); + s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s - 1, end); } return (UChar* )s; } @@ -369,9 +369,9 @@ onigenc_set_default_caseconv_table(const UChar* table ARG_UNUSED) } extern UChar* -onigenc_get_left_adjust_char_head(OnigEncoding enc, const UChar* start, const UChar* s) +onigenc_get_left_adjust_char_head(OnigEncoding enc, const UChar* start, const UChar* s, const UChar* end) { - return ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s); + return ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, start, s, end); } const OnigPairCaseFoldCodes OnigAsciiLowerMap[] = { @@ -637,6 +637,7 @@ onigenc_single_byte_code_to_mbc(OnigCodePoint code, UChar *buf, OnigEncoding enc extern UChar* onigenc_single_byte_left_adjust_char_head(const UChar* start ARG_UNUSED, const UChar* s, + const UChar* end, OnigEncoding enc ARG_UNUSED) { return (UChar* )s; @@ -125,7 +125,7 @@ ONIG_EXTERN int onigenc_single_byte_mbc_enc_len P_((const UChar* p, const UChar* ONIG_EXTERN OnigCodePoint onigenc_single_byte_mbc_to_code P_((const UChar* p, const UChar* end, OnigEncoding enc)); ONIG_EXTERN int onigenc_single_byte_code_to_mbclen P_((OnigCodePoint code, OnigEncoding enc)); ONIG_EXTERN int onigenc_single_byte_code_to_mbc P_((OnigCodePoint code, UChar *buf, OnigEncoding enc)); -ONIG_EXTERN UChar* onigenc_single_byte_left_adjust_char_head P_((const UChar* start, const UChar* s, OnigEncoding enc)); +ONIG_EXTERN UChar* onigenc_single_byte_left_adjust_char_head P_((const UChar* start, const UChar* s, const OnigUChar* end, OnigEncoding enc)); ONIG_EXTERN int onigenc_always_true_is_allowed_reverse_match P_((const UChar* s, const UChar* end, OnigEncoding enc)); ONIG_EXTERN int onigenc_always_false_is_allowed_reverse_match P_((const UChar* s, const UChar* end, OnigEncoding enc)); ONIG_EXTERN int onigenc_ascii_is_code_ctype P_((OnigCodePoint code, unsigned int ctype, OnigEncoding enc)); @@ -977,25 +977,24 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end, }\ } while(0) -#define STRING_CMP_IC(case_fold_flag,s1,ps2,len) do {\ - if (string_cmp_ic(encode, case_fold_flag, s1, ps2, len) == 0) \ +#define STRING_CMP_IC(case_fold_flag,s1,ps2,len,text_end) do {\ + if (string_cmp_ic(encode, case_fold_flag, s1, ps2, len, text_end) == 0) \ goto fail; \ } while(0) static int string_cmp_ic(OnigEncoding enc, int case_fold_flag, - UChar* s1, UChar** ps2, int mblen) + UChar* s1, UChar** ps2, int mblen, const UChar* text_end) { UChar buf1[ONIGENC_MBC_CASE_FOLD_MAXLEN]; UChar buf2[ONIGENC_MBC_CASE_FOLD_MAXLEN]; - UChar *p1, *p2, *end1, *s2, *end2; + UChar *p1, *p2, *end1, *s2; int len1, len2; s2 = *ps2; end1 = s1 + mblen; - end2 = s2 + mblen; while (s1 < end1) { - len1 = ONIGENC_MBC_CASE_FOLD(enc, case_fold_flag, &s1, end1, buf1); - len2 = ONIGENC_MBC_CASE_FOLD(enc, case_fold_flag, &s2, end2, buf2); + len1 = ONIGENC_MBC_CASE_FOLD(enc, case_fold_flag, &s1, text_end, buf1); + len2 = ONIGENC_MBC_CASE_FOLD(enc, case_fold_flag, &s2, text_end, buf2); if (len1 != len2) return 0; p1 = buf1; p2 = buf2; @@ -1019,8 +1018,8 @@ static int string_cmp_ic(OnigEncoding enc, int case_fold_flag, }\ } while(0) -#define STRING_CMP_VALUE_IC(case_fold_flag,s1,ps2,len,is_fail) do {\ - if (string_cmp_ic(encode, case_fold_flag, s1, ps2, len) == 0) \ +#define STRING_CMP_VALUE_IC(case_fold_flag,s1,ps2,len,text_end,is_fail) do {\ + if (string_cmp_ic(encode, case_fold_flag, s1, ps2, len, text_end) == 0) \ is_fail = 1; \ else \ is_fail = 0; \ @@ -1126,7 +1125,7 @@ static int backref_match_at_nested_level(regex_t* reg if (ignore_case != 0) { if (string_cmp_ic(reg->enc, case_fold_flag, - pstart, &ss, (int )(pend - pstart)) == 0) + pstart, &ss, (int )(pend - pstart), send) == 0) return 0; /* or goto next_mem; */ } else { @@ -2199,7 +2198,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, n = pend - pstart; DATA_ENSURE(n); sprev = s; - STRING_CMP_IC(case_fold_flag, pstart, &s, n); + STRING_CMP_IC(case_fold_flag, pstart, &s, n, end); while (sprev + (len = enclen(encode, sprev, end)) < s) sprev += len; @@ -2271,7 +2270,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, DATA_ENSURE(n); sprev = s; swork = s; - STRING_CMP_VALUE_IC(case_fold_flag, pstart, &swork, n, is_fail); + STRING_CMP_VALUE_IC(case_fold_flag, pstart, &swork, n, end, is_fail); if (is_fail) continue; s = swork; while (sprev + (len = enclen(encode, sprev, end)) < s) @@ -2647,9 +2646,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, case OP_LOOK_BEHIND: MOP_IN(OP_LOOK_BEHIND); GET_LENGTH_INC(tlen, p); - s = (UChar* )ONIGENC_STEP_BACK(encode, str, s, (int )tlen); + s = (UChar* )ONIGENC_STEP_BACK(encode, str, s, end, (int )tlen); if (IS_NULL(s)) goto fail; - sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s); + sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s, end); MOP_OUT; continue; break; @@ -2657,7 +2656,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, case OP_PUSH_LOOK_BEHIND_NOT: MOP_IN(OP_PUSH_LOOK_BEHIND_NOT); GET_RELADDR_INC(addr, p); GET_LENGTH_INC(tlen, p); - q = (UChar* )ONIGENC_STEP_BACK(encode, str, s, (int )tlen); + q = (UChar* )ONIGENC_STEP_BACK(encode, str, s, end, (int )tlen); if (IS_NULL(q)) { /* too short case -> success. ex. /(?<!XXX)a/.match("a") If you want to change to fail, replace following line. */ @@ -2667,7 +2666,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, else { STACK_PUSH_LOOK_BEHIND_NOT(p + addr, s, sprev); s = q; - sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s); + sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s, end); } MOP_OUT; continue; @@ -2780,7 +2779,7 @@ slow_search(OnigEncoding enc, UChar* target, UChar* target_end, if (target_end == t || memcmp(t, p, target_end - t) == 0) return s; } - s += enclen(enc, s, end); + s += enclen(enc, s, text_end); } return (UChar* )NULL; @@ -2843,7 +2842,7 @@ slow_search_backward(OnigEncoding enc, UChar* target, UChar* target_end, if (s > text_start) s = (UChar* )text_start; else - s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, adjust_text, s); + s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, adjust_text, s, text_end); while (s >= text) { if (*s == *target) { @@ -2857,7 +2856,7 @@ slow_search_backward(OnigEncoding enc, UChar* target, UChar* target_end, if (t == target_end) return s; } - s = (UChar* )onigenc_get_prev_char_head(enc, adjust_text, s); + s = (UChar* )onigenc_get_prev_char_head(enc, adjust_text, s, text_end); } return (UChar* )NULL; @@ -2876,14 +2875,14 @@ slow_search_backward_ic(OnigEncoding enc, int case_fold_flag, if (s > text_start) s = (UChar* )text_start; else - s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, adjust_text, s); + s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(enc, adjust_text, s, text_end); while (s >= text) { if (str_lower_case_match(enc, case_fold_flag, target, target_end, s, text_end)) return s; - s = (UChar* )onigenc_get_prev_char_head(enc, adjust_text, s); + s = (UChar* )onigenc_get_prev_char_head(enc, adjust_text, s, text_end); } return (UChar* )NULL; @@ -3018,7 +3017,7 @@ bm_search_backward(regex_t* reg, const UChar* target, const UChar* target_end, if (text_start < s) s = text_start; else - s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s); + s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s, text_end); while (s >= text) { p = s; @@ -3030,7 +3029,7 @@ bm_search_backward(regex_t* reg, const UChar* target, const UChar* target_end, return (UChar* )s; s -= reg->int_map_backward[*s]; - s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s); + s = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, adjust_text, s, text_end); } return (UChar* )NULL; @@ -3038,14 +3037,14 @@ bm_search_backward(regex_t* reg, const UChar* target, const UChar* target_end, static UChar* map_search(OnigEncoding enc, UChar map[], - const UChar* text, const UChar* text_range) + const UChar* text, const UChar* text_range, const UChar* text_end) { const UChar *s = text; while (s < text_range) { if (map[*s]) return (UChar* )s; - s += enclen(enc, s, text_range); + s += enclen(enc, s, text_end); } return (UChar* )NULL; } @@ -3053,14 +3052,14 @@ map_search(OnigEncoding enc, UChar map[], static UChar* map_search_backward(OnigEncoding enc, UChar map[], const UChar* text, const UChar* adjust_text, - const UChar* text_start) + const UChar* text_start, const UChar* text_end) { const UChar *s = text_start; while (s >= text) { if (map[*s]) return (UChar* )s; - s = onigenc_get_prev_char_head(enc, adjust_text, s); + s = onigenc_get_prev_char_head(enc, adjust_text, s, text_end); } return (UChar* )NULL; } @@ -3117,7 +3116,7 @@ onig_match(regex_t* reg, const UChar* str, const UChar* end, const UChar* at, On r = 0; if (r == 0) { - prev = (UChar* )onigenc_get_prev_char_head(reg->enc, str, at); + prev = (UChar* )onigenc_get_prev_char_head(reg->enc, str, at, end); r = match_at(reg, str, end, #ifdef USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE end, @@ -3171,7 +3170,7 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s, break; case ONIG_OPTIMIZE_MAP: - p = map_search(reg->enc, reg->map, p, range); + p = map_search(reg->enc, reg->map, p, range, end); break; } @@ -3190,7 +3189,7 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s, case ANCHOR_BEGIN_LINE: if (!ON_STR_BEGIN(p)) { prev = onigenc_get_prev_char_head(reg->enc, - (pprev ? pprev : str), p); + (pprev ? pprev : str), p, end); if (!ONIGENC_IS_MBC_NEWLINE(reg->enc, prev, end)) goto retry_gate; } @@ -3219,10 +3218,10 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s, *low = p; if (low_prev) { if (*low > s) - *low_prev = onigenc_get_prev_char_head(reg->enc, s, p); + *low_prev = onigenc_get_prev_char_head(reg->enc, s, p, end); else *low_prev = onigenc_get_prev_char_head(reg->enc, - (pprev ? pprev : str), p); + (pprev ? pprev : str), p, end); } } else { @@ -3230,15 +3229,15 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s, *low = p - reg->dmax; if (*low > s) { *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, s, - *low, (const UChar** )low_prev); + *low, end, (const UChar** )low_prev); if (low_prev && IS_NULL(*low_prev)) *low_prev = onigenc_get_prev_char_head(reg->enc, - (pprev ? pprev : s), *low); + (pprev ? pprev : s), *low, end); } else { if (low_prev) *low_prev = onigenc_get_prev_char_head(reg->enc, - (pprev ? pprev : str), *low); + (pprev ? pprev : str), *low, end); } } } @@ -3301,7 +3300,7 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end, break; case ONIG_OPTIMIZE_MAP: - p = map_search_backward(reg->enc, reg->map, range, adjrange, p); + p = map_search_backward(reg->enc, reg->map, range, adjrange, p, end); break; } @@ -3312,7 +3311,7 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end, switch (reg->sub_anchor) { case ANCHOR_BEGIN_LINE: if (!ON_STR_BEGIN(p)) { - prev = onigenc_get_prev_char_head(reg->enc, str, p); + prev = onigenc_get_prev_char_head(reg->enc, str, p, end); if (!ONIGENC_IS_MBC_NEWLINE(reg->enc, prev, end)) { p = prev; goto retry; @@ -3336,7 +3335,7 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end, && ! ONIGENC_IS_MBC_CRNL(reg->enc, p, end) #endif ) { - p = onigenc_get_prev_char_head(reg->enc, adjrange, p); + p = onigenc_get_prev_char_head(reg->enc, adjrange, p, end); if (IS_NULL(p)) goto fail; goto retry; } @@ -3348,7 +3347,7 @@ backward_search_range(regex_t* reg, const UChar* str, const UChar* end, if (reg->dmax != ONIG_INFINITE_DISTANCE) { *low = p - reg->dmax; *high = p - reg->dmin; - *high = onigenc_get_right_adjust_char_head(reg->enc, adjrange, *high); + *high = onigenc_get_right_adjust_char_head(reg->enc, adjrange, *high, end); } #ifdef ONIG_DEBUG_SEARCH @@ -3506,9 +3505,9 @@ onig_search(regex_t* reg, const UChar* str, const UChar* end, if ((OnigDistance )(min_semi_end - start) > reg->anchor_dmax) { start = min_semi_end - reg->anchor_dmax; if (start < end) - start = onigenc_get_right_adjust_char_head(reg->enc, str, start); + start = onigenc_get_right_adjust_char_head(reg->enc, str, start, end); else { /* match with empty at end */ - start = onigenc_get_prev_char_head(reg->enc, str, end); + start = onigenc_get_prev_char_head(reg->enc, str, end, end); } } if ((OnigDistance )(max_semi_end - (range - 1)) < reg->anchor_dmin) { @@ -3523,20 +3522,20 @@ onig_search(regex_t* reg, const UChar* str, const UChar* end, } if ((OnigDistance )(max_semi_end - start) < reg->anchor_dmin) { start = max_semi_end - reg->anchor_dmin; - start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, start); + start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, start, end); } if (range > start) goto mismatch_no_msa; } } else if (reg->anchor & ANCHOR_SEMI_END_BUF) { - UChar* pre_end = ONIGENC_STEP_BACK(reg->enc, str, end, 1); + UChar* pre_end = ONIGENC_STEP_BACK(reg->enc, str, end, end, 1); max_semi_end = (UChar* )end; if (ONIGENC_IS_MBC_NEWLINE(reg->enc, pre_end, end)) { min_semi_end = pre_end; #ifdef USE_CRNL_AS_LINE_TERMINATOR - pre_end = ONIGENC_STEP_BACK(reg->enc, str, pre_end, 1); + pre_end = ONIGENC_STEP_BACK(reg->enc, str, pre_end, end, 1); if (IS_NOT_NULL(pre_end) && ONIGENC_IS_MBC_CRNL(reg->enc, pre_end, end)) { min_semi_end = pre_end; @@ -3594,7 +3593,7 @@ onig_search(regex_t* reg, const UChar* str, const UChar* end, s = (UChar* )start; if (range > start) { /* forward search */ if (s > str) - prev = onigenc_get_prev_char_head(reg->enc, str, s); + prev = onigenc_get_prev_char_head(reg->enc, str, s, end); else prev = (UChar* )NULL; @@ -3670,7 +3669,7 @@ onig_search(regex_t* reg, const UChar* str, const UChar* end, UChar *low, *high, *adjrange, *sch_start; if (range < end) - adjrange = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, range); + adjrange = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, str, range, end); else adjrange = (UChar* )end; @@ -3687,7 +3686,7 @@ onig_search(regex_t* reg, const UChar* str, const UChar* end, s = high; while (s >= low) { - prev = onigenc_get_prev_char_head(reg->enc, str, s); + prev = onigenc_get_prev_char_head(reg->enc, str, s, end); MATCH_AND_RETURN_CHECK(orig_start); s = prev; } @@ -3706,7 +3705,7 @@ onig_search(regex_t* reg, const UChar* str, const UChar* end, if (sch_start > end) sch_start = (UChar* )end; else sch_start = ONIGENC_LEFT_ADJUST_CHAR_HEAD(reg->enc, - start, sch_start); + start, sch_start, end); } } if (backward_search_range(reg, str, end, sch_start, range, adjrange, @@ -3715,7 +3714,7 @@ onig_search(regex_t* reg, const UChar* str, const UChar* end, } do { - prev = onigenc_get_prev_char_head(reg->enc, str, s); + prev = onigenc_get_prev_char_head(reg->enc, str, s, end); MATCH_AND_RETURN_CHECK(orig_start); s = prev; } while (s >= range); diff --git a/regparse.c b/regparse.c index 168b175758..0bd898b771 100644 --- a/regparse.c +++ b/regparse.c @@ -1540,7 +1540,7 @@ str_node_split_last_char(StrNode* sn, OnigEncoding enc) Node* n = NULL_NODE; if (sn->end > sn->s) { - p = onigenc_get_prev_char_head(enc, sn->s, sn->end); + p = onigenc_get_prev_char_head(enc, sn->s, sn->end, sn->end); if (p && p > sn->s) { /* can be splitted. */ n = node_new_str(p, sn->end); if ((sn->flag & NSTR_RAW) != 0) @@ -967,6 +967,7 @@ process_options(VALUE arg) NODE *tree = 0; VALUE parser; VALUE iseq; + VALUE args; rb_encoding *enc, *lenc; const char *s; char fbuf[MAXPATHLEN]; @@ -1067,7 +1068,7 @@ process_options(VALUE arg) #if defined DOSISH || defined __CYGWIN__ translate_char(RSTRING_PTR(rb_progname), '\\', '/'); #endif - opt->script_name = rb_str_new4(rb_progname); + opt->script_name = rb_progname; opt->script = RSTRING_PTR(opt->script_name); safe = rb_safe_level(); rb_set_safe_level_force(0); @@ -1077,8 +1078,10 @@ process_options(VALUE arg) ruby_init_loadpath(); ruby_init_gems(!(opt->disable & DISABLE_BIT(gems))); lenc = rb_locale_encoding(); - for (i = 0; i < RARRAY_LEN(rb_argv); i++) { - rb_enc_associate(RARRAY_PTR(rb_argv)[i], lenc); + rb_enc_associate(rb_progname, lenc); + opt->script_name = rb_str_new4(rb_progname); + for (i = 0, args = rb_argv; i < RARRAY_LEN(args); i++) { + rb_enc_associate(RARRAY_PTR(args)[i], lenc); } parser = rb_parser_new(); if (opt->yydebug) rb_parser_set_yydebug(parser, Qtrue); @@ -1475,7 +1478,6 @@ ruby_prog_init(void) rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0); rb_define_global_const("ARGV", rb_argv); - rb_global_variable(&rb_argv0); #ifdef MSDOS /* @@ -1532,6 +1534,7 @@ ruby_process_options(int argc, char **argv) ruby_script(argv[0]); /* for the time being */ rb_argv0 = rb_str_new4(rb_progname); + rb_gc_register_mark_object(rb_argv0); args.argc = argc; args.argv = argv; args.opt = cmdline_options_init(&opt); @@ -6,9 +6,7 @@ #include "regint.h" #include "st.h" #else -#include "ruby/config.h" -#include "ruby/defines.h" -#include "ruby/st.h" +#include "ruby/ruby.h" #endif #include <stdio.h> @@ -135,6 +133,9 @@ new_size(int size) if (newsize > size) return primes[i]; } /* Ran out of polynomials */ +#ifndef NOT_RUBY + rb_raise(rb_eRuntimeError, "st_table too big"); +#endif return -1; /* should raise exception */ #endif } @@ -43,6 +43,7 @@ VALUE rb_cString; VALUE rb_cSymbol; +#define RUBY_MAX_CHAR_LEN 16 #define STR_TMPLOCK FL_USER7 #define STR_NOEMBED FL_USER1 #define STR_SHARED FL_USER2 /* = ELTS_SHARED */ @@ -111,18 +112,19 @@ VALUE rb_cSymbol; #define STR_ENC_GET(str) rb_enc_from_index(ENCODING_GET(str)) -static int +static inline int single_byte_optimizable(VALUE str) { - rb_encoding *enc = STR_ENC_GET(str); - - if (rb_enc_mbmaxlen(enc) == 1) - return 1; + rb_encoding *enc; /* Conservative. It may be ENC_CODERANGE_UNKNOWN. */ if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) return 1; + enc = STR_ENC_GET(str); + if (rb_enc_mbmaxlen(enc) == 1) + return 1; + /* Conservative. Possibly single byte. * "\xa1" in Shift_JIS for example. */ return 0; @@ -1057,6 +1059,17 @@ rb_str_modify(VALUE str) ENC_CODERANGE_CLEAR(str); } +/* As rb_str_modify(), but don't clear coderange */ +static void +str_modify_keep_cr(VALUE str) +{ + if (!str_independent(str)) + str_make_independent(str); + if (ENC_CODERANGE(str) == ENC_CODERANGE_BROKEN) + /* Force re-scan later */ + ENC_CODERANGE_CLEAR(str); +} + void rb_str_associate(VALUE str, VALUE add) { @@ -1281,20 +1294,35 @@ rb_str_substr(VALUE str, long beg, long len) rb_encoding *enc = STR_ENC_GET(str); VALUE str2; char *p, *s = RSTRING_PTR(str), *e = s + RSTRING_LEN(str); - int singlebyte; if (len < 0) return Qnil; if (!RSTRING_LEN(str)) { len = 0; } + if (single_byte_optimizable(str)) { + if (beg > RSTRING_LEN(str)) return Qnil; + if (beg < 0) { + beg += RSTRING_LEN(str); + if (beg < 0) return Qnil; + } + if (beg + len > RSTRING_LEN(str)) + len = RSTRING_LEN(str) - beg; + if (len <= 0) { + len = 0; + p = 0; + } + else + p = s + beg; + goto sub; + } if (beg < 0) { if (len > -beg) len = -beg; if (-beg * rb_enc_mbmaxlen(enc) < RSTRING_LEN(str) / 8) { beg = -beg; - while (beg-- > len && (e = rb_enc_prev_char(s, e, enc)) != 0); + while (beg-- > len && (e = rb_enc_prev_char(s, e, e, enc)) != 0); p = e; if (!p) return Qnil; - while (len-- > 0 && (p = rb_enc_prev_char(s, p, enc)) != 0); + while (len-- > 0 && (p = rb_enc_prev_char(s, p, e, enc)) != 0); if (!p) return Qnil; len = e - p; goto sub; @@ -1307,7 +1335,6 @@ rb_str_substr(VALUE str, long beg, long len) else if (beg > 0 && beg > str_strlen(str, enc)) { return Qnil; } - singlebyte = single_byte_optimizable(str); if (len == 0) { p = 0; } @@ -1318,17 +1345,24 @@ rb_str_substr(VALUE str, long beg, long len) len = str_utf8_offset(p, e, len); } #endif - else if ((p = str_nth(s, e, beg, enc, singlebyte)) == e) { - len = 0; - } else if (rb_enc_mbmaxlen(enc) == rb_enc_mbminlen(enc)) { - if (len * rb_enc_mbmaxlen(enc) > e - p) + int char_sz = rb_enc_mbmaxlen(enc); + + p = s + beg * char_sz; + if (p > e) { + p = e; + len = 0; + } + else if (len * char_sz > e - p) len = e - p; else - len *= rb_enc_mbmaxlen(enc); + len *= char_sz; + } + else if ((p = str_nth(s, e, beg, enc, 0)) == e) { + len = 0; } else { - len = str_offset(p, e, len, enc, singlebyte); + len = str_offset(p, e, len, enc, 0); } sub: if (len > RSTRING_EMBED_LEN_MAX && beg + len == RSTRING_LEN(str)) { @@ -1623,7 +1657,7 @@ rb_str_buf_cat_ascii(VALUE str, const char *ptr) else { char *buf = ALLOCA_N(char, rb_enc_mbmaxlen(enc)); while (*ptr) { - int c = (unsigned char)*ptr; + unsigned int c = (unsigned char)*ptr; int len = rb_enc_codelen(c, enc); rb_enc_mbcput(c, buf, enc); rb_enc_cr_str_buf_cat(str, buf, len, @@ -1678,13 +1712,13 @@ rb_str_append(VALUE str, VALUE str2) /* * call-seq: - * str << fixnum => str - * str.concat(fixnum) => str + * str << integer => str + * str.concat(integer) => str * str << obj => str * str.concat(obj) => str * * Append---Concatenates the given object to <i>str</i>. If the object is a - * <code>Fixnum</code>, it is considered as a codepoint, and is converted + * <code>Integer</code>, it is considered as a codepoint, and is converted * to a character before concatenation. * * a = "hello " @@ -1695,9 +1729,9 @@ rb_str_append(VALUE str, VALUE str2) VALUE rb_str_concat(VALUE str1, VALUE str2) { - if (FIXNUM_P(str2)) { + if (FIXNUM_P(str2) || TYPE(str2) == T_BIGNUM) { rb_encoding *enc = STR_ENC_GET(str1); - int c = FIX2INT(str2); + unsigned int c = NUM2UINT(str2); int pos = RSTRING_LEN(str1); int len = rb_enc_codelen(c, enc); int cr = ENC_CODERANGE(str1); @@ -1892,6 +1926,7 @@ rb_str_comparable(VALUE str1, VALUE str2) { int idx1, idx2; int rc1, rc2; + int a8; if (RSTRING_LEN(str1) == 0) return Qtrue; if (RSTRING_LEN(str2) == 0) return Qtrue; @@ -1909,6 +1944,8 @@ rb_str_comparable(VALUE str1, VALUE str2) if (rb_enc_asciicompat(rb_enc_from_index(idx1))) return Qtrue; } + a8 = rb_ascii8bit_encindex(); + if (idx1 == a8 || idx2 == a8) return Qtrue; return Qfalse; } @@ -1922,7 +1959,7 @@ rb_str_cmp(VALUE str1, VALUE str2) retval = memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2), len); if (retval == 0) { if (RSTRING_LEN(str1) == RSTRING_LEN(str2)) { - if (!rb_enc_compatible(str1, str2)) { + if (!rb_str_comparable(str1, str2)) { if (ENCODING_GET(str1) - ENCODING_GET(str2) > 0) return 1; return -1; @@ -2065,19 +2102,33 @@ rb_str_casecmp(VALUE str1, VALUE str2) p1 = RSTRING_PTR(str1); p1end = RSTRING_END(str1); p2 = RSTRING_PTR(str2); p2end = RSTRING_END(str2); - while (p1 < p1end && p2 < p2end) { - unsigned int c1 = rb_enc_codepoint(p1, p1end, enc); - unsigned int c2 = rb_enc_codepoint(p2, p2end, enc); - - if (c1 != c2) { - c1 = rb_enc_toupper(c1, enc); - c2 = rb_enc_toupper(c2, enc); - if (c1 > c2) return INT2FIX(1); - if (c1 < c2) return INT2FIX(-1); + if (single_byte_optimizable(str1) && single_byte_optimizable(str2)) { + while (p1 < p1end && p2 < p2end) { + if (*p1 != *p2) { + unsigned int c1 = rb_enc_toupper(*p1 & 0xff, enc); + unsigned int c2 = rb_enc_toupper(*p2 & 0xff, enc); + if (c1 > c2) return INT2FIX(1); + if (c1 < c2) return INT2FIX(-1); + } + p1++; + p2++; + } + } + else { + while (p1 < p1end && p2 < p2end) { + unsigned int c1 = rb_enc_codepoint(p1, p1end, enc); + unsigned int c2 = rb_enc_codepoint(p2, p2end, enc); + + if (c1 != c2) { + c1 = rb_enc_toupper(c1, enc); + c2 = rb_enc_toupper(c2, enc); + if (c1 > c2) return INT2FIX(1); + if (c1 < c2) return INT2FIX(-1); + } + len = rb_enc_codelen(c1, enc); + p1 += len; + p2 += len; } - len = rb_enc_codelen(c1, enc); - p1 += len; - p2 += len; } if (RSTRING_LEN(str1) == RSTRING_LEN(str2)) return INT2FIX(0); if (RSTRING_LEN(str1) > RSTRING_LEN(str2)) return INT2FIX(1); @@ -2088,7 +2139,7 @@ static long rb_str_index(VALUE str, VALUE sub, long offset) { long pos; - char *s, *sptr; + char *s, *sptr, *e; long len, slen; rb_encoding *enc; @@ -2104,6 +2155,7 @@ rb_str_index(VALUE str, VALUE sub, long offset) } if (len - offset < slen) return -1; s = RSTRING_PTR(str); + e = s + RSTRING_LEN(str); if (offset) { offset = str_offset(s, RSTRING_END(str), offset, enc, single_byte_optimizable(str)); s += offset; @@ -2117,7 +2169,7 @@ rb_str_index(VALUE str, VALUE sub, long offset) char *t; pos = rb_memsearch(sptr, slen, s, len, enc); if (pos < 0) return pos; - t = rb_enc_right_char_head(s, s+pos, enc); + t = rb_enc_right_char_head(s, s+pos, e, enc); if (t == s + pos) break; if ((len -= t - s) <= 0) return -1; offset += t - s; @@ -2571,7 +2623,7 @@ rb_str_succ(VALUE orig) sbeg = RSTRING_PTR(str); s = e = sbeg + RSTRING_LEN(str); - while ((s = rb_enc_prev_char(sbeg, s, enc)) != 0) { + while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) { if (neighbor == NEIGHBOR_NOT_CHAR && last_alnum) { if (ISALPHA(*last_alnum) ? ISDIGIT(*s) : ISDIGIT(*last_alnum) ? ISALPHA(*s) : 0) { @@ -2596,7 +2648,7 @@ rb_str_succ(VALUE orig) } if (c == -1) { /* str contains no alnum */ s = e; - while ((s = rb_enc_prev_char(sbeg, s, enc)) != 0) { + while ((s = rb_enc_prev_char(sbeg, s, e, enc)) != 0) { enum neighbor_char neighbor; if ((l = rb_enc_precise_mbclen(s, e, enc)) <= 0) continue; neighbor = enc_succ_char(s, l, enc); @@ -2894,11 +2946,11 @@ rb_str_splice(VALUE str, long beg, long len, VALUE val) char *p, *e; rb_encoding *enc; int singlebyte = single_byte_optimizable(str); + int cr; if (len < 0) rb_raise(rb_eIndexError, "negative length %ld", len); StringValue(val); - rb_str_modify(str); enc = rb_enc_check(str, val); slen = str_strlen(str, enc); @@ -2915,6 +2967,7 @@ rb_str_splice(VALUE str, long beg, long len, VALUE val) if (slen < len || slen < beg + len) { len = slen - beg; } + str_modify_keep_cr(str); 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); @@ -2924,6 +2977,9 @@ rb_str_splice(VALUE str, long beg, long len, VALUE val) len = e - p; /* physical length */ rb_str_splice_0(str, beg, len, val); rb_enc_associate(str, enc); + cr = ENC_CODERANGE_AND(ENC_CODERANGE(str), ENC_CODERANGE(val)); + if (cr != ENC_CODERANGE_BROKEN) + ENC_CODERANGE_SET(str, cr); } void @@ -3114,7 +3170,7 @@ rb_str_slice_bang(int argc, VALUE *argv, VALUE str) for (i=0; i<argc; i++) { buf[i] = argv[i]; } - rb_str_modify(str); + str_modify_keep_cr(str); buf[i] = rb_str_new(0,0); result = rb_str_aref_m(argc, buf, str); if (!NIL_P(result)) { @@ -3524,7 +3580,10 @@ rb_str_clear(VALUE str) STR_SET_EMBED(str); STR_SET_EMBED_LEN(str, 0); RSTRING_PTR(str)[0] = 0; - ENC_CODERANGE_CLEAR(str); + if (rb_enc_asciicompat(STR_ENC_GET(str))) + ENC_CODERANGE_SET(str, ENC_CODERANGE_7BIT); + else + ENC_CODERANGE_SET(str, ENC_CODERANGE_VALID); return str; } @@ -3656,22 +3715,15 @@ rb_str_reverse_bang(VALUE str) if (RSTRING_LEN(str) > 1) { if (single_byte_optimizable(str)) { char *s, *e, c; - int cr = ENC_CODERANGE(str); - int single = 1; - rb_str_modify(str); + str_modify_keep_cr(str); s = RSTRING_PTR(str); e = RSTRING_END(str) - 1; while (s < e) { c = *s; - if (*s & 0x80) single = 0; *s++ = *e; *e-- = c; } - if (cr == ENC_CODERANGE_UNKNOWN && single) { - cr = ENC_CODERANGE_7BIT; - } - ENC_CODERANGE_SET(str, cr); } else { rb_str_shared_replace(str, rb_str_reverse(str)); @@ -3787,9 +3839,9 @@ rb_str_to_s(VALUE str) } static void -str_cat_char(VALUE str, int c, rb_encoding *enc) +str_cat_char(VALUE str, unsigned int c, rb_encoding *enc) { - char s[16]; + char s[RUBY_MAX_CHAR_LEN]; int n = rb_enc_codelen(c, enc); rb_enc_mbcput(c, s, enc); @@ -3797,7 +3849,7 @@ str_cat_char(VALUE str, int c, rb_encoding *enc) } static void -prefix_escape(VALUE str, int c, rb_encoding *enc) +prefix_escape(VALUE str, unsigned int c, rb_encoding *enc) { str_cat_char(str, '\\', enc); str_cat_char(str, c, enc); @@ -4033,23 +4085,46 @@ rb_str_upcase_bang(VALUE str) rb_encoding *enc; char *s, *send; int modify = 0; - int cr = ENC_CODERANGE(str); - rb_str_modify(str); + str_modify_keep_cr(str); enc = STR_ENC_GET(str); s = RSTRING_PTR(str); send = RSTRING_END(str); - while (s < send) { - unsigned int c = rb_enc_codepoint(s, send, enc); + if (single_byte_optimizable(str)) { + while (s < send) { + unsigned int c = *(unsigned char*)s; - if (rb_enc_islower(c, enc)) { - /* assuming toupper returns codepoint with same size */ - rb_enc_mbcput(rb_enc_toupper(c, enc), s, enc); - modify = 1; + if (rb_enc_isascii(c, enc) && 'a' <= c && c <= 'z') { + *s = 'A' + (c - 'a'); + modify = 1; + } + s++; + } + } + else { + int ascompat = rb_enc_asciicompat(enc); + + while (s < send) { + unsigned int c; + + if (ascompat && (c = *(unsigned char*)s) < 0x80) { + if (rb_enc_isascii(c, enc) && 'a' <= c && c <= 'z') { + *s = 'A' + (c - 'a'); + modify = 1; + } + s++; + } + else { + c = rb_enc_codepoint(s, send, enc); + if (rb_enc_islower(c, enc)) { + /* assuming toupper returns codepoint with same size */ + rb_enc_mbcput(rb_enc_toupper(c, enc), s, enc); + modify = 1; + } + s += rb_enc_codelen(c, enc); + } } - s += rb_enc_codelen(c, enc); } - ENC_CODERANGE_SET(str, cr); if (modify) return str; return Qnil; } @@ -4091,23 +4166,46 @@ rb_str_downcase_bang(VALUE str) rb_encoding *enc; char *s, *send; int modify = 0; - int cr = ENC_CODERANGE(str); - rb_str_modify(str); + str_modify_keep_cr(str); enc = STR_ENC_GET(str); s = RSTRING_PTR(str); send = RSTRING_END(str); - while (s < send) { - unsigned int c = rb_enc_codepoint(s, send, enc); + if (single_byte_optimizable(str)) { + while (s < send) { + unsigned int c = *(unsigned char*)s; - if (rb_enc_isupper(c, enc)) { - /* assuming toupper returns codepoint with same size */ - rb_enc_mbcput(rb_enc_tolower(c, enc), s, enc); - modify = 1; + if (rb_enc_isascii(c, enc) && 'A' <= c && c <= 'Z') { + *s = 'a' + (c - 'A'); + modify = 1; + } + s++; + } + } + else { + int ascompat = rb_enc_asciicompat(enc); + + while (s < send) { + unsigned int c; + + if (ascompat && (c = *(unsigned char*)s) < 0x80) { + if (rb_enc_isascii(c, enc) && 'A' <= c && c <= 'Z') { + *s = 'a' + (c - 'A'); + modify = 1; + } + s++; + } + else { + c = rb_enc_codepoint(s, send, enc); + if (rb_enc_isupper(c, enc)) { + /* assuming toupper returns codepoint with same size */ + rb_enc_mbcput(rb_enc_tolower(c, enc), s, enc); + modify = 1; + } + s += rb_enc_codelen(c, enc); + } } - s += rb_enc_codelen(c, enc); } - ENC_CODERANGE_SET(str, cr); if (modify) return str; return Qnil; } @@ -4155,9 +4253,8 @@ rb_str_capitalize_bang(VALUE str) char *s, *send; int modify = 0; unsigned int c; - int cr = ENC_CODERANGE(str); - rb_str_modify(str); + str_modify_keep_cr(str); enc = STR_ENC_GET(str); if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil; s = RSTRING_PTR(str); send = RSTRING_END(str); @@ -4177,7 +4274,6 @@ rb_str_capitalize_bang(VALUE str) s += rb_enc_codelen(c, enc); } - ENC_CODERANGE_SET(str, cr); if (modify) return str; return Qnil; } @@ -4220,9 +4316,8 @@ rb_str_swapcase_bang(VALUE str) rb_encoding *enc; char *s, *send; int modify = 0; - int cr = ENC_CODERANGE(str); - rb_str_modify(str); + str_modify_keep_cr(str); enc = STR_ENC_GET(str); s = RSTRING_PTR(str); send = RSTRING_END(str); while (s < send) { @@ -4234,14 +4329,13 @@ rb_str_swapcase_bang(VALUE str) modify = 1; } else if (rb_enc_islower(c, enc)) { - /* assuming toupper returns codepoint with same size */ + /* assuming tolower returns codepoint with same size */ rb_enc_mbcput(rb_enc_toupper(c, enc), s, enc); modify = 1; } - s += rb_enc_codelen(c, enc); + s += rb_enc_mbclen(s, send, enc); } - ENC_CODERANGE_SET(str, cr); if (modify) return str; return Qnil; } @@ -4323,6 +4417,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag) char *s, *send; VALUE hash = 0; int singlebyte = single_byte_optimizable(str); + int cr; StringValue(src); StringValue(repl); @@ -4331,6 +4426,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag) return rb_str_delete_bang(1, &src, str); } + cr = ENC_CODERANGE(str); e1 = rb_enc_check(str, src); e2 = rb_enc_check(str, repl); if (e1 == e2) { @@ -4394,7 +4490,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag) } } - rb_str_modify(str); + str_modify_keep_cr(str); s = RSTRING_PTR(str); send = RSTRING_END(str); if (sflag) { int clen, tlen, max = RSTRING_LEN(str); @@ -4516,6 +4612,9 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag) } if (modify) { + cr = ENC_CODERANGE_AND(cr, ENC_CODERANGE(repl)); + if (cr != ENC_CODERANGE_BROKEN) + ENC_CODERANGE_SET(str, cr); rb_enc_associate(str, enc); return str; } @@ -4654,11 +4753,9 @@ rb_str_delete_bang(int argc, VALUE *argv, VALUE str) char *s, *send, *t; VALUE del = 0, nodel = 0; int modify = 0; - int i; - int cr; + int i, ascompat; if (RSTRING_LEN(str) == 0 || !RSTRING_PTR(str)) return Qnil; - cr = ENC_CODERANGE(str); if (argc < 1) { rb_raise(rb_eArgError, "wrong number of arguments"); } @@ -4670,27 +4767,41 @@ rb_str_delete_bang(int argc, VALUE *argv, VALUE str) tr_setup_table(s, squeez, i==0, &del, &nodel, enc); } - rb_str_modify(str); + str_modify_keep_cr(str); + ascompat = rb_enc_asciicompat(enc); s = t = RSTRING_PTR(str); - if (!s || RSTRING_LEN(str) == 0) return Qnil; send = RSTRING_END(str); while (s < send) { - unsigned int c = rb_enc_codepoint(s, send, enc); - int clen = rb_enc_codelen(c, enc); + unsigned int c; + int clen; - if (tr_find(c, squeez, del, nodel)) { - modify = 1; + if (ascompat && (c = *(unsigned char*)s) < 0x80) { + if (squeez[c]) { + modify = 1; + } + else { + if (t != s) *t = c; + t++; + } + s++; } else { - if (t != s) rb_enc_mbcput(c, t, enc); - t += clen; + c = rb_enc_codepoint(s, send, enc); + clen = rb_enc_codelen(c, enc); + + if (tr_find(c, squeez, del, nodel)) { + modify = 1; + } + else { + if (t != s) rb_enc_mbcput(c, t, enc); + t += clen; + } + s += clen; } - s += clen; } *t = '\0'; STR_SET_LEN(str, t - RSTRING_PTR(str)); - ENC_CODERANGE_SET(str, cr); if (modify) return str; return Qnil; } @@ -4736,6 +4847,7 @@ rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str) char *s, *send, *t; int save, modify = 0; int i; + int ascompat, singlebyte = single_byte_optimizable(str); if (argc == 0) { enc = STR_ENC_GET(str); @@ -4746,26 +4858,51 @@ rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str) StringValue(s); enc = rb_enc_check(str, s); + if (singlebyte && !single_byte_optimizable(s)) + singlebyte = 0; tr_setup_table(s, squeez, i==0, &del, &nodel, enc); } } - rb_str_modify(str); + str_modify_keep_cr(str); s = t = RSTRING_PTR(str); if (!s || RSTRING_LEN(str) == 0) return Qnil; send = RSTRING_END(str); save = -1; - while (s < send) { - unsigned int c = rb_enc_codepoint(s, send, enc); - int clen = rb_enc_codelen(c, enc); + ascompat = rb_enc_asciicompat(enc); - if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) { - if (t != s) rb_enc_mbcput(c, t, enc); - save = c; - t += clen; + if (singlebyte) { + while (s < send) { + unsigned int c = *(unsigned char*)s++; + if (c != save || (argc > 0 && !squeez[c])) { + *t++ = save = c; + } + } + } else { + while (s < send) { + unsigned int c; + int clen; + + if (ascompat && (c = *(unsigned char*)s) < 0x80) { + if (c != save || (argc > 0 && !squeez[c])) { + *t++ = save = c; + } + s++; + } + else { + c = rb_enc_codepoint(s, send, enc); + clen = rb_enc_codelen(c, enc); + + if (c != save || (argc > 0 && !tr_find(c, squeez, del, nodel))) { + if (t != s) rb_enc_mbcput(c, t, enc); + save = c; + t += clen; + } + s += clen; + } } - s += clen; } + *t = '\0'; if (t - RSTRING_PTR(str) != RSTRING_LEN(str)) { STR_SET_LEN(str, t - RSTRING_PTR(str)); @@ -4777,7 +4914,7 @@ rb_str_squeeze_bang(int argc, VALUE *argv, VALUE str) } -/* +/* * call-seq: * str.squeeze([other_str]*) => new_str * @@ -4862,6 +4999,7 @@ rb_str_count(int argc, VALUE *argv, VALUE str) VALUE del = 0, nodel = 0; char *s, *send; int i; + int ascompat; if (argc < 1) { rb_raise(rb_eArgError, "wrong number of arguments"); @@ -4871,22 +5009,36 @@ rb_str_count(int argc, VALUE *argv, VALUE str) StringValue(s); enc = rb_enc_check(str, s); - tr_setup_table(s, table,i==0, &del, &nodel, enc); + tr_setup_table(s, table, i==0, &del, &nodel, enc); } s = RSTRING_PTR(str); if (!s || RSTRING_LEN(str) == 0) return INT2FIX(0); send = RSTRING_END(str); i = 0; + ascompat = rb_enc_asciicompat(enc); + while (s < send) { - unsigned int c = rb_enc_codepoint(s, send, enc); - int clen = rb_enc_codelen(c, enc); + unsigned int c; + int clen; - if (tr_find(c, table, del, nodel)) { - i++; + if (ascompat && (c = *(unsigned char*)s) < 0x80) { + clen = 1; + if (table[c]) { + i++; + } + s++; + } + else { + c = rb_enc_codepoint(s, send, enc); + clen = rb_enc_codelen(c, enc); + if (tr_find(c, table, del, nodel)) { + i++; + } + s += clen; } - s += clen; } + return INT2NUM(i); } @@ -4939,7 +5091,7 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str) rb_encoding *enc; VALUE spat; VALUE limit; - int awk_split = Qfalse; + enum {awk, string, regexp} split_type; long beg, end, i = 0; int lim = 0; VALUE result, tmp; @@ -4961,37 +5113,41 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str) spat = rb_fs; goto fs_set; } - awk_split = Qtrue; + split_type = awk; } else { fs_set: if (TYPE(spat) == T_STRING) { rb_encoding *enc2 = STR_ENC_GET(spat); - if (rb_enc_mbminlen(enc2) == 1) { + split_type = string; + if (RSTRING_LEN(spat) == 0) { + /* Special case - split into chars */ + spat = rb_reg_regcomp(spat); + split_type = regexp; + } + else if (rb_enc_mbminlen(enc2) == 1) { if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' '){ - awk_split = Qtrue; + split_type = awk; } } else { int l; if (rb_enc_ascget(RSTRING_PTR(spat), RSTRING_END(spat), &l, enc2) == ' ' && RSTRING_LEN(spat) == l) { - awk_split = Qtrue; + split_type = awk; } } - if (!awk_split) { - spat = rb_reg_regcomp(rb_reg_quote(spat)); - } } else { spat = get_pat(spat, 1); + split_type = regexp; } } result = rb_ary_new(); beg = 0; - if (awk_split) { + if (split_type == awk) { char *ptr = RSTRING_PTR(str); char *eptr = RSTRING_END(str); char *bptr = ptr; @@ -5025,6 +5181,33 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str) } } } + else if (split_type == string) { + char *ptr = RSTRING_PTR(str); + char *eptr = RSTRING_END(str); + char *sptr = RSTRING_PTR(spat); + int slen = RSTRING_LEN(spat); + + if (is_broken_string(str)) { + rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str))); + } + if (is_broken_string(spat)) { + rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(spat))); + } + enc = rb_enc_check(str, spat); + while (ptr < eptr && + (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) { + /* Check we are at the start of a char */ + char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc); + if (t != ptr + end) { + ptr = t; + continue; + } + rb_ary_push(result, rb_str_substr(str, ptr - RSTRING_PTR(str), end)); + ptr += end + slen; + if (!NIL_P(limit) && lim <= ++i) break; + } + beg = ptr - RSTRING_PTR(str); + } else { long start = beg; long idx; @@ -5178,7 +5361,7 @@ rb_str_each_line(int argc, VALUE *argv, VALUE str) p = memchr(p, '\n', pend - p); if (!p) break; - p0 = rb_enc_left_char_head(s, p, enc); + p0 = rb_enc_left_char_head(s, p, pend, enc); if (!rb_enc_is_newline(p0, pend, enc)) { p++; continue; @@ -5326,6 +5509,59 @@ rb_str_each_char(VALUE str) return str; } +/* + * Document-method: codepoints + * call-seq: + * str.codepoints => anEnumerator + * str.codepoints {|fixnum| block } => str + * + * Returns an enumerator that gives the <code>Integer</code> ordinal + * of each character in the string, also known as a <i>codepoint</i> + * when applied to Unicode strings. If a block is given, it iterates + * over each character in the string. + * + * "foo\u0635".chars.to_a #=> [102, 111, 111, 1589] + */ + +/* + * Document-method: each_codepoint + * call-seq: + * str.each_codepoint {|integer| block } => str + * + * Passes the <code>Integer</code> ordinal of each character in <i>str</i>, + * also known as a <i>codepoint</i> when applied to Unicode strings to the + * given block. + * + * "hello\u0639".each_codepoint {|c| print c, ' ' } + * + * <em>produces:</em> + * + * 104 101 108 108 111 1593 + */ + +static VALUE +rb_str_each_codepoint(VALUE str) +{ + int len, n; + unsigned int c; + const char *ptr, *end; + rb_encoding *enc; + + if (single_byte_optimizable(str)) return rb_str_each_byte(str); + RETURN_ENUMERATOR(str, 0, 0); + ptr = RSTRING_PTR(str); + len = RSTRING_LEN(str); + end = RSTRING_END(str); + enc = STR_ENC_GET(str); + while (ptr < end) { + c = rb_enc_codepoint(ptr, end, enc); + n = rb_enc_codelen(c, enc); + rb_yield(UINT2NUM(c)); + ptr += n; + } + return str; +} + static long chopped_length(VALUE str) { @@ -5335,10 +5571,10 @@ chopped_length(VALUE str) beg = RSTRING_PTR(str); end = beg + RSTRING_LEN(str); if (beg > end) return 0; - p = rb_enc_prev_char(beg, end, enc); + p = rb_enc_prev_char(beg, end, end, enc); if (!p) return 0; if (p > beg && rb_enc_codepoint(p, end, enc) == '\n') { - p2 = rb_enc_prev_char(beg, p, enc); + p2 = rb_enc_prev_char(beg, p, end, enc); if (p2 && rb_enc_codepoint(p2, end, enc) == '\r') p = p2; } return p - beg; @@ -5358,7 +5594,7 @@ rb_str_chop_bang(VALUE str) { if (RSTRING_LEN(str) > 0) { long len; - rb_str_modify(str); + str_modify_keep_cr(str); len = chopped_length(str); STR_SET_LEN(str, len); RSTRING_PTR(str)[len] = '\0'; @@ -5420,16 +5656,16 @@ rb_str_chomp_bang(int argc, VALUE *argv, VALUE str) rs = rb_rs; if (rs == rb_default_rs) { smart_chomp: - rb_str_modify(str); + str_modify_keep_cr(str); enc = rb_enc_get(str); if (rb_enc_mbminlen(enc) > 1) { - pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), enc); + pp = rb_enc_left_char_head(p, e-rb_enc_mbminlen(enc), e, enc); if (rb_enc_is_newline(pp, e, enc)) { e = pp; } pp = e - rb_enc_mbminlen(enc); if (pp >= p) { - pp = rb_enc_left_char_head(p, pp, enc); + pp = rb_enc_left_char_head(p, pp, e, enc); if (rb_enc_ascget(pp, e, 0, enc) == '\r') { e = pp; } @@ -5472,7 +5708,7 @@ rb_str_chomp_bang(int argc, VALUE *argv, VALUE str) len--; } if (len < RSTRING_LEN(str)) { - rb_str_modify(str); + str_modify_keep_cr(str); STR_SET_LEN(str, len); RSTRING_PTR(str)[len] = '\0'; return str; @@ -5492,9 +5728,9 @@ rb_str_chomp_bang(int argc, VALUE *argv, VALUE str) if (p[len-1] == newline && (rslen <= 1 || memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) { - if (rb_enc_left_char_head(p, pp, enc) != pp) + if (rb_enc_left_char_head(p, pp, e, enc) != pp) return Qnil; - rb_str_modify(str); + str_modify_keep_cr(str); STR_SET_LEN(str, RSTRING_LEN(str) - rslen); RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0'; return str; @@ -5548,7 +5784,7 @@ rb_str_lstrip_bang(VALUE str) rb_encoding *enc; char *s, *t, *e; - rb_str_modify(str); + str_modify_keep_cr(str); enc = STR_ENC_GET(str); s = RSTRING_PTR(str); if (!s || RSTRING_LEN(str) == 0) return Qnil; @@ -5562,7 +5798,6 @@ rb_str_lstrip_bang(VALUE str) } if (s > RSTRING_PTR(str)) { - rb_str_modify(str); STR_SET_LEN(str, t-s); memmove(RSTRING_PTR(str), s, RSTRING_LEN(str)); RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0'; @@ -5609,30 +5844,33 @@ rb_str_rstrip_bang(VALUE str) { rb_encoding *enc; char *s, *t, *e; - int space_seen = Qfalse; - rb_str_modify(str); enc = STR_ENC_GET(str); s = RSTRING_PTR(str); if (!s || RSTRING_LEN(str) == 0) return Qnil; t = e = RSTRING_END(str); - while (s < e) { - unsigned int cc = rb_enc_codepoint(s, e, enc); - if (!cc || rb_enc_isspace(cc, enc)) { - if (!space_seen) t = s; - space_seen = Qtrue; - } - else { - space_seen = Qfalse; + if (single_byte_optimizable(str)) { + /* remove trailing '\0's */ + while (s < t && t[-1] == '\0') t--; + + /* remove trailing spaces */ + while (s < t && rb_enc_isspace(*(t-1), enc)) t--; + } + else { + char *tp; + + while ((tp = rb_enc_prev_char(s, t, e, enc)) != NULL) { + if (!rb_enc_isspace(rb_enc_codepoint(tp, e, enc), enc)) break; + t = tp; } - s += rb_enc_codelen(cc, enc); } - if (!space_seen) t = s; if (t < e) { - rb_str_modify(str); - STR_SET_LEN(str, t-RSTRING_PTR(str)); - RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0'; + int len = t-RSTRING_PTR(str); + + str_modify_keep_cr(str); + STR_SET_LEN(str, len); + RSTRING_PTR(str)[len] = '\0'; return str; } return Qnil; @@ -5864,30 +6102,27 @@ rb_str_crypt(VALUE str, VALUE salt) { extern char *crypt(const char *, const char *); VALUE result; - const char *s; + const char *s, *saltp; #ifdef BROKEN_CRYPT - VALUE salt_8bit_clean; - rb_encoding *enc; + char salt_8bit_clean[3]; #endif StringValue(salt); 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) s = ""; + saltp = RSTRING_PTR(salt); #ifdef BROKEN_CRYPT - salt_8bit_clean = rb_str_dup(salt); - enc = rb_ascii8bit_encoding(); - str_modifiable(salt_8bit_clean); - rb_enc_associate(salt_8bit_clean, enc); - salt_8bit_clean = rb_str_tr(salt_8bit_clean, - rb_enc_str_new("\x80-\xFF", 3, enc), - rb_usascii_str_new("\x00-\x7F", 3)); - result = rb_str_new2(crypt(s, RSTRING_PTR(salt_8bit_clean))); -#else - result = rb_str_new2(crypt(s, RSTRING_PTR(salt))); + if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned char)saltp[1])) { + salt_8bit_clean[0] = saltp[0] & 0x7f; + salt_8bit_clean[1] = saltp[1] & 0x7f; + salt_8bit_clean[2] = '\0'; + saltp = salt_8bit_clean; + } #endif + result = rb_str_new2(crypt(s, saltp)); OBJ_INFECT(result, str); OBJ_INFECT(result, salt); return result; @@ -6029,7 +6264,7 @@ rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag) const char *f = " "; long n, llen, rlen; volatile VALUE pad; - int singlebyte = 1; + int singlebyte = 1, cr; rb_scan_args(argc, argv, "11", &w, &pad); enc = STR_ENC_GET(str); @@ -6050,6 +6285,7 @@ rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag) n = width - len; llen = (jflag == 'l') ? 0 : ((jflag == 'r') ? n : n/2); rlen = n - llen; + cr = ENC_CODERANGE(str); res = rb_str_new5(str, 0, RSTRING_LEN(str)+n*flen/fclen+2); p = RSTRING_PTR(res); while (llen) { @@ -6095,6 +6331,10 @@ rb_str_justify(int argc, VALUE *argv, VALUE str, char jflag) OBJ_INFECT(res, str); if (!NIL_P(pad)) OBJ_INFECT(res, pad); rb_enc_associate(res, enc); + if (argc == 2) + cr = ENC_CODERANGE_AND(cr, ENC_CODERANGE(pad)); + if (cr != ENC_CODERANGE_BROKEN) + ENC_CODERANGE_SET(res, cr); return res; } @@ -6283,7 +6523,7 @@ static VALUE rb_str_end_with(int argc, VALUE *argv, VALUE str) { int i; - char *p, *s; + char *p, *s, *e; rb_encoding *enc; for (i=0; i<argc; i++) { @@ -6292,8 +6532,9 @@ rb_str_end_with(int argc, VALUE *argv, VALUE str) enc = rb_enc_check(str, tmp); if (RSTRING_LEN(str) < RSTRING_LEN(tmp)) continue; p = RSTRING_PTR(str); - s = p + RSTRING_LEN(str) - RSTRING_LEN(tmp); - if (rb_enc_left_char_head(p, s, enc) != s) + e = p + RSTRING_LEN(str); + s = e - RSTRING_LEN(tmp); + if (rb_enc_left_char_head(p, s, e, enc) != s) continue; if (memcmp(s, RSTRING_PTR(tmp), RSTRING_LEN(tmp)) == 0) return Qtrue; @@ -6695,6 +6936,7 @@ Init_String(void) rb_define_method(rb_cString, "lines", rb_str_each_line, -1); rb_define_method(rb_cString, "bytes", rb_str_each_byte, 0); rb_define_method(rb_cString, "chars", rb_str_each_char, 0); + rb_define_method(rb_cString, "codepoints", rb_str_each_codepoint, 0); rb_define_method(rb_cString, "reverse", rb_str_reverse, 0); rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0); rb_define_method(rb_cString, "concat", rb_str_concat, 1); @@ -6744,6 +6986,7 @@ Init_String(void) rb_define_method(rb_cString, "each_line", rb_str_each_line, -1); rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0); rb_define_method(rb_cString, "each_char", rb_str_each_char, 0); + rb_define_method(rb_cString, "each_codepoint", rb_str_each_codepoint, 0); rb_define_method(rb_cString, "sum", rb_str_sum, -1); diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb new file mode 100644 index 0000000000..99ce108458 --- /dev/null +++ b/test/bigdecimal/test_bigdecimal.rb @@ -0,0 +1,689 @@ +require "test/unit" +require "bigdecimal" + +class TestBigDecimal < Test::Unit::TestCase + def setup + BigDecimal.mode(BigDecimal::EXCEPTION_ALL, true) + BigDecimal.mode(BigDecimal::EXCEPTION_UNDERFLOW, true) + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true) + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_UP) + BigDecimal.limit(0) + end + + def test_version + assert_equal("1.0.1", BigDecimal.ver) + end + + def test_global_new + assert_equal(1, BigDecimal("1")) + assert_equal(1, BigDecimal("1", 1)) + assert_raise(ArgumentError) { BigDecimal("1", -1) } + end + + def test_new + assert_equal(1, BigDecimal.new("1")) + assert_equal(1, BigDecimal.new("1", 1)) + assert_equal(1, BigDecimal.new(" 1 ")) + assert_equal(111, BigDecimal.new("1_1_1_")) + assert_equal(0, BigDecimal.new("_1_1_1")) + + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + assert_equal( 1, BigDecimal.new("Infinity").infinite?) + assert_equal(-1, BigDecimal.new("-Infinity").infinite?) + assert_equal(true, BigDecimal.new("NaN").nan?) + end + + def _test_mode(type) + BigDecimal.mode(type, true) + assert_raise(FloatDomainError) { yield } + + BigDecimal.mode(type, false) + assert_nothing_raised { yield } + end + + def test_mode + assert_raise(TypeError) { BigDecimal.mode(BigDecimal::EXCEPTION_ALL, 1) } + assert_raise(TypeError) { BigDecimal.mode(BigDecimal::ROUND_MODE, 256) } + assert_raise(TypeError) { BigDecimal.mode(0xf000, true) } + end + + def test_exception_nan + _test_mode(BigDecimal::EXCEPTION_NaN) { BigDecimal.new("NaN") } + end + + def test_exception_infinity + _test_mode(BigDecimal::EXCEPTION_INFINITY) { BigDecimal.new("Infinity") } + end + + def test_exception_underflow + _test_mode(BigDecimal::EXCEPTION_UNDERFLOW) do + x = BigDecimal.new("0.1") + 100.times do + x *= x + break if x == false + end + end + end + + def test_exception_overflow + _test_mode(BigDecimal::EXCEPTION_OVERFLOW) do + x = BigDecimal.new("10") + 100.times do + x *= x + break if x == false + end + end + end + + def test_exception_zerodivide + _test_mode(BigDecimal::EXCEPTION_ZERODIVIDE) { 1 / BigDecimal.new("0") } + _test_mode(BigDecimal::EXCEPTION_ZERODIVIDE) { -1 / BigDecimal.new("0") } + end + + def test_round_up + n4 = BigDecimal.new("4") # n4 / 9 = 0.44444... + n5 = BigDecimal.new("5") # n5 / 9 = 0.55555... + n6 = BigDecimal.new("6") # n6 / 9 = 0.66666... + m4, m5, m6 = -n4, -n5, -n6 + n2h = BigDecimal.new("2.5") + n3h = BigDecimal.new("3.5") + m2h, m3h = -n2h, -n3h + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_UP) + assert_operator(n4, :<, n4 / 9 * 9) + assert_operator(n5, :<, n5 / 9 * 9) + assert_operator(n6, :<, n6 / 9 * 9) + assert_operator(m4, :>, m4 / 9 * 9) + assert_operator(m5, :>, m5 / 9 * 9) + assert_operator(m6, :>, m6 / 9 * 9) + assert_equal(3, n2h.round) + assert_equal(4, n3h.round) + assert_equal(-3, m2h.round) + assert_equal(-4, m3h.round) + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_DOWN) + assert_operator(n4, :>, n4 / 9 * 9) + assert_operator(n5, :>, n5 / 9 * 9) + assert_operator(n6, :>, n6 / 9 * 9) + assert_operator(m4, :<, m4 / 9 * 9) + assert_operator(m5, :<, m5 / 9 * 9) + assert_operator(m6, :<, m6 / 9 * 9) + assert_equal(2, n2h.round) + assert_equal(3, n3h.round) + assert_equal(-2, m2h.round) + assert_equal(-3, m3h.round) + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_UP) + assert_operator(n4, :>, n4 / 9 * 9) + assert_operator(n5, :<, n5 / 9 * 9) + assert_operator(n6, :<, n6 / 9 * 9) + assert_operator(m4, :<, m4 / 9 * 9) + assert_operator(m5, :>, m5 / 9 * 9) + assert_operator(m6, :>, m6 / 9 * 9) + assert_equal(3, n2h.round) + assert_equal(4, n3h.round) + assert_equal(-3, m2h.round) + assert_equal(-4, m3h.round) + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_DOWN) + assert_operator(n4, :>, n4 / 9 * 9) + assert_operator(n5, :>, n5 / 9 * 9) + assert_operator(n6, :<, n6 / 9 * 9) + assert_operator(m4, :<, m4 / 9 * 9) + assert_operator(m5, :<, m5 / 9 * 9) + assert_operator(m6, :>, m6 / 9 * 9) + assert_equal(2, n2h.round) + assert_equal(3, n3h.round) + assert_equal(-2, m2h.round) + assert_equal(-3, m3h.round) + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_EVEN) + assert_operator(n4, :>, n4 / 9 * 9) + assert_operator(n5, :<, n5 / 9 * 9) + assert_operator(n6, :<, n6 / 9 * 9) + assert_operator(m4, :<, m4 / 9 * 9) + assert_operator(m5, :>, m5 / 9 * 9) + assert_operator(m6, :>, m6 / 9 * 9) + assert_equal(2, n2h.round) + assert_equal(4, n3h.round) + assert_equal(-2, m2h.round) + assert_equal(-4, m3h.round) + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_CEILING) + assert_operator(n4, :<, n4 / 9 * 9) + assert_operator(n5, :<, n5 / 9 * 9) + assert_operator(n6, :<, n6 / 9 * 9) + assert_operator(m4, :<, m4 / 9 * 9) + assert_operator(m5, :<, m5 / 9 * 9) + assert_operator(m6, :<, m6 / 9 * 9) + assert_equal(3, n2h.round) + assert_equal(4, n3h.round) + assert_equal(-2, m2h.round) + assert_equal(-3, m3h.round) + + BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_FLOOR) + assert_operator(n4, :>, n4 / 9 * 9) + assert_operator(n5, :>, n5 / 9 * 9) + assert_operator(n6, :>, n6 / 9 * 9) + assert_operator(m4, :>, m4 / 9 * 9) + assert_operator(m5, :>, m5 / 9 * 9) + assert_operator(m6, :>, m6 / 9 * 9) + assert_equal(2, n2h.round) + assert_equal(3, n3h.round) + assert_equal(-3, m2h.round) + assert_equal(-4, m3h.round) + end + + def test_zero_p + assert_equal(true, BigDecimal.new("0").zero?) + assert_equal(false, BigDecimal.new("1").zero?) + end + + def test_nonzero_p + assert_equal(nil, BigDecimal.new("0").nonzero?) + assert_equal(BigDecimal.new("1"), BigDecimal.new("1").nonzero?) + end + + def test_double_fig + assert_kind_of(Integer, BigDecimal.double_fig) + end + + def test_cmp + n1 = BigDecimal.new("1") + n2 = BigDecimal.new("2") + assert_equal( 0, n1 <=> n1) + assert_equal( 1, n2 <=> n1) + assert_equal(-1, n1 <=> n2) + assert_operator(n1, :==, n1) + assert_operator(n1, :!=, n2) + assert_operator(n1, :<, n2) + assert_operator(n1, :<=, n1) + assert_operator(n1, :<=, n2) + assert_operator(n2, :>, n1) + assert_operator(n2, :>=, n1) + assert_operator(n1, :>=, n1) + + assert_operator(BigDecimal.new("-0"), :==, BigDecimal.new("0")) + assert_operator(BigDecimal.new("0"), :<, BigDecimal.new("1")) + assert_operator(BigDecimal.new("1"), :>, BigDecimal.new("0")) + assert_operator(BigDecimal.new("1"), :>, BigDecimal.new("-1")) + assert_operator(BigDecimal.new("-1"), :<, BigDecimal.new("1")) + assert_operator(BigDecimal.new((2**100).to_s), :>, BigDecimal.new("1")) + assert_operator(BigDecimal.new("1"), :<, BigDecimal.new((2**100).to_s)) + + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + inf = BigDecimal.new("Infinity") + assert_operator(inf, :>, 1) + assert_operator(1, :<, inf) + end + + def test_cmp_corece + n1 = BigDecimal.new("1") + n2 = BigDecimal.new("2") + o1 = Object.new; def o1.coerce(x); [x, BigDecimal.new("1")]; end + o2 = Object.new; def o2.coerce(x); [x, BigDecimal.new("2")]; end + assert_equal( 0, n1 <=> o1) + assert_equal( 1, n2 <=> o1) + assert_equal(-1, n1 <=> o2) + assert_operator(n1, :==, o1) + assert_operator(n1, :!=, o2) + assert_operator(n1, :<, o2) + assert_operator(n1, :<=, o1) + assert_operator(n1, :<=, o2) + assert_operator(n2, :>, o1) + assert_operator(n2, :>=, o1) + assert_operator(n1, :>=, 1) + end + + def test_cmp_bignum + assert_operator(BigDecimal.new((2**100).to_s), :==, 2**100) + end + + def test_cmp_data + d = Time.now; def d.coerce(x); [x, x]; end + assert_operator(BigDecimal.new((2**100).to_s), :==, d) + end + + def test_precs + a = BigDecimal.new("1").precs + assert_instance_of(Array, a) + assert_equal(2, a.size) + assert_kind_of(Integer, a[0]) + assert_kind_of(Integer, a[1]) + end + + def test_hash + a = [] + x = BigDecimal.new("1") + 10.times { a << x *= 10 } + h = {} + a.each_with_index {|x, i| h[x] = i } + a.each_with_index do |x, i| + assert_equal(i, h[x]) + end + end + + def test_marshal + s = Marshal.dump(BigDecimal("1", 1)) + assert_equal(BigDecimal("1", 1), Marshal.load(s)) + + # corrupt data + s = s.gsub(/BigDecimal.*\z/m) {|x| x.gsub(/\d/m, "-") } + assert_raise(TypeError) { Marshal.load(s) } + end + + def test_finite_infinite_nan + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + + x = BigDecimal.new("0") + assert_equal(true, x.finite?) + assert_equal(nil, x.infinite?) + assert_equal(false, x.nan?) + y = 1 / x + assert_equal(false, y.finite?) + assert_equal(1, y.infinite?) + assert_equal(false, y.nan?) + y = -1 / x + assert_equal(false, y.finite?) + assert_equal(-1, y.infinite?) + assert_equal(false, y.nan?) + + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + y = 0 / x + assert_equal(false, y.finite?) + assert_equal(nil, y.infinite?) + assert_equal(true, y.nan?) + end + + def test_to_i + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + + x = BigDecimal.new("0") + assert_kind_of(Integer, x.to_i) + assert_equal(0, x.to_i) + assert_nil(( 1 / x).to_i) + assert_nil((-1 / x).to_i) + assert_nil(( 0 / x).to_i) + x = BigDecimal.new("1") + assert_equal(1, x.to_i) + x = BigDecimal.new((2**100).to_s) + assert_equal(2**100, x.to_i) + end + + def test_to_f + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + + x = BigDecimal.new("0") + assert_instance_of(Float, x.to_f) + assert_equal(0.0, x.to_f) + assert_equal( 1.0 / 0.0, ( 1 / x).to_f) + assert_equal(-1.0 / 0.0, (-1 / x).to_f) + assert_equal(true, ( 0 / x).to_f.nan?) + x = BigDecimal.new("1") + assert_equal(1.0, x.to_f) + x = BigDecimal.new((2**100).to_s) + assert_equal((2**100).to_f, x.to_f) + x = BigDecimal.new("1" + "0" * 10000) + assert_equal(0, BigDecimal.new("-0").to_f) + + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true) + assert_raise(FloatDomainError) { x.to_f } + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + assert_kind_of(Float, x .to_f) + assert_kind_of(Float, (-x).to_f) + end + + def test_coerce + a, b = BigDecimal.new("1").coerce(1.0) + assert_instance_of(Float, a) + assert_instance_of(Float, b) + end + + def test_uplus + x = BigDecimal.new("1") + assert_equal(x, x.send(:+@)) + end + + def test_add + x = BigDecimal.new("1") + assert_equal(BigDecimal.new("2"), x + x) + assert_equal(1, BigDecimal.new("0") + 1) + assert_equal(1, x + 0) + + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("0") + 0).sign) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("-0") + 0).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, (BigDecimal.new("-0") + BigDecimal.new("-0")).sign) + + x = BigDecimal.new((2**100).to_s) + assert_equal(BigDecimal.new((2**100+1).to_s), x + 1) + end + + def test_sub + x = BigDecimal.new("1") + assert_equal(BigDecimal.new("0"), x - x) + assert_equal(-1, BigDecimal.new("0") - 1) + assert_equal(1, x - 0) + + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("0") - 0).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, (BigDecimal.new("-0") - 0).sign) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("-0") - BigDecimal.new("-0")).sign) + + x = BigDecimal.new((2**100).to_s) + assert_equal(BigDecimal.new((2**100-1).to_s), x - 1) + end + + def test_mult + x = BigDecimal.new((2**100).to_s) + assert_equal(BigDecimal.new((2**100 * 3).to_s), (x * 3).to_i) + assert_equal(x, (x * 1).to_i) + assert_equal(x, (BigDecimal("1") * x).to_i) + assert_equal(BigDecimal.new((2**200).to_s), (x * x).to_i) + end + + def test_div + x = BigDecimal.new((2**100).to_s) + assert_equal(BigDecimal.new((2**100 / 3).to_s), (x / 3).to_i) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("0") / 1).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, (BigDecimal.new("-0") / 1).sign) + assert_equal(2, BigDecimal.new("2") / 1) + assert_equal(-2, BigDecimal.new("2") / -1) + end + + def test_mod + x = BigDecimal.new((2**100).to_s) + assert_equal(1, x % 3) + assert_equal(2, (-x) % 3) + assert_equal(-2, x % -3) + assert_equal(-1, (-x) % -3) + end + + def test_remainder + x = BigDecimal.new((2**100).to_s) + assert_equal(1, x.remainder(3)) + assert_equal(-1, (-x).remainder(3)) + assert_equal(1, x.remainder(-3)) + assert_equal(-1, (-x).remainder(-3)) + end + + def test_divmod + x = BigDecimal.new((2**100).to_s) + assert_equal([(x / 3).floor, 1], x.divmod(3)) + assert_equal([(-x / 3).floor, 2], (-x).divmod(3)) + + assert_equal([0, 0], BigDecimal.new("0").divmod(2)) + + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + a, b = BigDecimal.new("0").divmod(0) + assert_equal(true, a.nan?) + assert_equal(true, b.nan?) + end + + def test_add_bigdecimal + x = BigDecimal.new((2**100).to_s) + assert_equal(3000000000000000000000000000000, x.add(x, 1)) + assert_equal(2500000000000000000000000000000, x.add(x, 2)) + assert_equal(2540000000000000000000000000000, x.add(x, 3)) + end + + def test_sub_bigdecimal + x = BigDecimal.new((2**100).to_s) + assert_equal(1000000000000000000000000000000, x.sub(1, 1)) + assert_equal(1300000000000000000000000000000, x.sub(1, 2)) + assert_equal(1270000000000000000000000000000, x.sub(1, 3)) + end + + def test_mult_bigdecimal + x = BigDecimal.new((2**100).to_s) + assert_equal(4000000000000000000000000000000, x.mult(3, 1)) + assert_equal(3800000000000000000000000000000, x.mult(3, 2)) + assert_equal(3800000000000000000000000000000, x.mult(3, 3)) + end + + def test_div_bigdecimal + x = BigDecimal.new((2**100).to_s) + assert_equal(422550200076076467165567735125, x.div(3)) + assert_equal(400000000000000000000000000000, x.div(3, 1)) + assert_equal(420000000000000000000000000000, x.div(3, 2)) + assert_equal(423000000000000000000000000000, x.div(3, 3)) + end + + def test_abs_bigdecimal + x = BigDecimal.new((2**100).to_s) + assert_equal(1267650600228229401496703205376, x.abs) + x = BigDecimal.new("-" + (2**100).to_s) + assert_equal(1267650600228229401496703205376, x.abs) + x = BigDecimal.new("0") + assert_equal(0, x.abs) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + x = BigDecimal.new("NaN") + assert_equal(true, x.abs.nan?) + end + + def test_sqrt_bigdecimal + x = BigDecimal.new("0.09") + assert_in_delta(0.3, x.sqrt(1), 0.001) + x = BigDecimal.new((2**100).to_s) + assert_equal(1125899906842624, x.sqrt(1)) + assert_equal(1125899906842624, x.sqrt(2)) + assert_equal(1125899906842624, x.sqrt(3)) # I don't understand the meaning of argument... + x = BigDecimal.new("-" + (2**100).to_s) + assert_raise(FloatDomainError) { x.sqrt(1) } + x = BigDecimal.new((2**200).to_s) + assert_equal(2**100, x.sqrt(1)) + + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + assert_raise(FloatDomainError) { BigDecimal.new("NaN").sqrt(1) } + + assert_equal(0, BigDecimal.new("0").sqrt(1)) + assert_equal(1, BigDecimal.new("1").sqrt(1)) + end + + def test_fix + x = BigDecimal.new("1.1") + assert_equal(1, x.fix) + end + + def test_frac + x = BigDecimal.new("1.1") + assert_equal(0.1, x.frac) + assert_equal(0.1, BigDecimal.new("0.1").frac) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + assert_equal(true, BigDecimal.new("NaN").frac.nan?) + end + + def test_round + assert_equal(3, BigDecimal.new("3.14159").round) + assert_equal(9, BigDecimal.new("8.7").round) + assert_equal(3.142, BigDecimal.new("3.14159").round(3)) + assert_equal(13300.0, BigDecimal.new("13345.234").round(-2)) + + x = BigDecimal.new("111.111") + assert_equal(111 , x.round) + assert_equal(111.1 , x.round(1)) + assert_equal(111.11 , x.round(2)) + assert_equal(111.111, x.round(3)) + assert_equal(111.111, x.round(4)) + assert_equal(110 , x.round(-1)) + assert_equal(100 , x.round(-2)) + assert_equal( 0 , x.round(-3)) + assert_equal( 0 , x.round(-4)) + + x = BigDecimal.new("2.5") + assert_equal(3, x.round(0, BigDecimal::ROUND_UP)) + assert_equal(2, x.round(0, BigDecimal::ROUND_DOWN)) + assert_equal(3, x.round(0, BigDecimal::ROUND_HALF_UP)) + assert_equal(2, x.round(0, BigDecimal::ROUND_HALF_DOWN)) + assert_equal(2, x.round(0, BigDecimal::ROUND_HALF_EVEN)) + assert_equal(3, x.round(0, BigDecimal::ROUND_CEILING)) + assert_equal(2, x.round(0, BigDecimal::ROUND_FLOOR)) + assert_raise(TypeError) { x.round(0, 256) } + end + + def test_truncate + assert_equal(3, BigDecimal.new("3.14159").truncate) + assert_equal(8, BigDecimal.new("8.7").truncate) + assert_equal(3.141, BigDecimal.new("3.14159").truncate(3)) + assert_equal(13300.0, BigDecimal.new("13345.234").truncate(-2)) + end + + def test_floor + assert_equal(3, BigDecimal.new("3.14159").floor) + assert_equal(-10, BigDecimal.new("-9.1").floor) + assert_equal(3.141, BigDecimal.new("3.14159").floor(3)) + assert_equal(13300.0, BigDecimal.new("13345.234").floor(-2)) + end + + def test_ceil + assert_equal(4, BigDecimal.new("3.14159").ceil) + assert_equal(-9, BigDecimal.new("-9.1").ceil) + assert_equal(3.142, BigDecimal.new("3.14159").ceil(3)) + assert_equal(13400.0, BigDecimal.new("13345.234").ceil(-2)) + end + + def test_to_s + assert_equal('-123.45678 90123 45678 9', BigDecimal.new('-123.45678901234567890').to_s('5F')) + assert_equal('+123.45678901 23456789', BigDecimal.new('123.45678901234567890').to_s('+8F')) + assert_equal(' 123.4567890123456789', BigDecimal.new('123.45678901234567890').to_s(' F')) + assert_equal('0.1234567890123456789E3', BigDecimal.new('123.45678901234567890').to_s) + assert_equal('0.12345 67890 12345 6789E3', BigDecimal.new('123.45678901234567890').to_s(5)) + end + + def test_split + x = BigDecimal.new('-123.45678901234567890') + assert_equal([-1, "1234567890123456789", 10, 3], x.split) + assert_equal([1, "0", 10, 0], BigDecimal.new("0").split) + assert_equal([-1, "0", 10, 0], BigDecimal.new("-0").split) + + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + assert_equal([0, "NaN", 10, 0], BigDecimal.new("NaN").split) + assert_equal([1, "Infinity", 10, 0], BigDecimal.new("Infinity").split) + assert_equal([-1, "Infinity", 10, 0], BigDecimal.new("-Infinity").split) + end + + def test_exponent + x = BigDecimal.new('-123.45678901234567890') + assert_equal(3, x.exponent) + end + + def test_inspect + x = BigDecimal.new("1234.5678") + assert_match(/^#<BigDecimal:[0-9a-f]+,'0.12345678E4',8\(12\)>$/, x.inspect) + end + + def test_power + x = BigDecimal.new("3") + assert_equal(81, x ** 4) + assert_equal(1.0/81, x ** -4) + assert_equal(1, x ** 0) + assert_raise(TypeError) { x ** x } + assert_equal(0, BigDecimal.new("0") ** 4) + assert_equal(1, BigDecimal.new("0") ** 0) + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + assert_equal(BigDecimal.new("Infinity"), BigDecimal.new("0") ** -1) + assert_equal(BigDecimal.new("-Infinity"), BigDecimal.new("-0") ** -1) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + assert_equal(true, (BigDecimal.new("NaN") ** 1).nan?) + + assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, (BigDecimal.new("Infinity") ** 2).sign) + assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, (BigDecimal.new("Infinity") ** 1).sign) + assert_equal(1, BigDecimal.new("Infinity") ** 0) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("Infinity") ** -1).sign) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("Infinity") ** -2).sign) + + assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, (BigDecimal.new("-Infinity") ** 2).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_INFINITE, (BigDecimal.new("-Infinity") ** 1).sign) + assert_equal(1, BigDecimal.new("-Infinity") ** 0) + assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, (BigDecimal.new("-Infinity") ** -1).sign) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (BigDecimal.new("-Infinity") ** -2).sign) + end + + def test_limit + BigDecimal.limit(1) + x = BigDecimal.new("3") + assert_equal(90, x ** 4) # OK? must it be 80? + # 3 * 3 * 3 * 3 = 10 * 3 * 3 = 30 * 3 = 90 ??? + assert_raise(ArgumentError) { BigDecimal.limit(-1) } + end + + def test_sign + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, BigDecimal.new("0").sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, BigDecimal.new("-0").sign) + assert_equal(BigDecimal::SIGN_POSITIVE_FINITE, BigDecimal.new("1").sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_FINITE, BigDecimal.new("-1").sign) + assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, (BigDecimal.new("1") / 0).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_INFINITE, (BigDecimal.new("-1") / 0).sign) + assert_equal(BigDecimal::SIGN_NaN, (BigDecimal.new("0") / 0).sign) + end + + def test_inf + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + inf = BigDecimal.new("Infinity") + + assert_equal(inf, inf + inf) + assert_equal(true, (inf + (-inf)).nan?) + assert_equal(true, (inf - inf).nan?) + assert_equal(inf, inf - (-inf)) + assert_equal(inf, inf * inf) + assert_equal(true, (inf / inf).nan?) + + assert_equal(inf, inf + 1) + assert_equal(inf, inf - 1) + assert_equal(inf, inf * 1) + assert_equal(true, (inf * 0).nan?) + assert_equal(inf, inf / 1) + + assert_equal(inf, 1 + inf) + assert_equal(-inf, 1 - inf) + assert_equal(inf, 1 * inf) + assert_equal(-inf, -1 * inf) + assert_equal(true, (0 * inf).nan?) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, (1 / inf).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, (-1 / inf).sign) + end + + def test_to_special_string + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + nan = BigDecimal.new("NaN") + assert_equal("NaN", nan.to_s) + inf = BigDecimal.new("Infinity") + assert_equal("Infinity", inf.to_s) + assert_equal(" Infinity", inf.to_s(" ")) + assert_equal("+Infinity", inf.to_s("+")) + assert_equal("-Infinity", (-inf).to_s) + pzero = BigDecimal.new("0") + assert_equal("0.0", pzero.to_s) + assert_equal(" 0.0", pzero.to_s(" ")) + assert_equal("+0.0", pzero.to_s("+")) + assert_equal("-0.0", (-pzero).to_s) + end + + def test_to_string + assert_equal("0.01", BigDecimal("0.01").to_s("F")) + s = "0." + "0" * 100 + "1" + assert_equal(s, BigDecimal(s).to_s("F")) + s = "1" + "0" * 100 + ".0" + assert_equal(s, BigDecimal(s).to_s("F")) + end + + def test_ctov + assert_equal(0.1, BigDecimal.new("1E-1")) + assert_equal(10, BigDecimal.new("1E+1")) + assert_equal(1, BigDecimal.new("+1")) + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + + assert_equal(BigDecimal::SIGN_POSITIVE_INFINITE, BigDecimal.new("1E1" + "0" * 10000).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_INFINITE, BigDecimal.new("-1E1" + "0" * 10000).sign) + assert_equal(BigDecimal::SIGN_POSITIVE_ZERO, BigDecimal.new("1E-1" + "0" * 10000).sign) + assert_equal(BigDecimal::SIGN_NEGATIVE_ZERO, BigDecimal.new("-1E-1" + "0" * 10000).sign) + end +end diff --git a/test/csv/tc_csv_parsing.rb b/test/csv/tc_csv_parsing.rb index 965af929f3..635ae90531 100644 --- a/test/csv/tc_csv_parsing.rb +++ b/test/csv/tc_csv_parsing.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_csv_parsing.rb # @@ -7,6 +8,7 @@ # under the terms of Ruby's license. require "test/unit" +require "timeout" require "csv" @@ -17,6 +19,8 @@ require "csv" # separator <tt>$/</tt>. # class TestCSVParsing < Test::Unit::TestCase + BIG_DATA = "123456789\n" * 1024 + def test_mastering_regex_example ex = %Q{Ten Thousand,10000, 2710 ,,"10,000","It's ""10 Grand"", baby",10K} assert_equal( [ "Ten Thousand", "10000", " 2710 ", nil, "10,000", @@ -158,7 +162,31 @@ class TestCSVParsing < Test::Unit::TestCase assert_send([csv.lineno, :<, 4]) end rescue CSV::MalformedCSVError - assert_equal("Unclosed quoted field on line 4.", $!.message) + assert_equal("Illegal quoting on line 4.", $!.message) + end + end + + def test_the_parse_fails_fast_when_it_can_for_unquoted_fields + assert_parse_errors_out('valid,fields,bad start"' + BIG_DATA) + end + + def test_the_parse_fails_fast_when_it_can_for_unescaped_quotes + assert_parse_errors_out('valid,fields,"bad start"unescaped' + BIG_DATA) + end + + def test_field_size_limit_controls_lookahead + assert_parse_errors_out( 'valid,fields,"' + BIG_DATA + '"', + :field_size_limit => 2048 ) + end + + private + + def assert_parse_errors_out(*args) + assert_raise(CSV::MalformedCSVError) do + Timeout.timeout(0.2) do + CSV.parse(*args) + fail("Parse didn't error out") + end end end end diff --git a/test/csv/tc_csv_writing.rb b/test/csv/tc_csv_writing.rb index 4677284306..a1ce4de97e 100644 --- a/test/csv/tc_csv_writing.rb +++ b/test/csv/tc_csv_writing.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_csv_writing.rb # diff --git a/test/csv/tc_data_converters.rb b/test/csv/tc_data_converters.rb index 24c6b6b76f..acf27a6669 100644 --- a/test/csv/tc_data_converters.rb +++ b/test/csv/tc_data_converters.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_data_converters.rb # diff --git a/test/csv/tc_features.rb b/test/csv/tc_features.rb index ae5a8a451b..ad6732a1ec 100644 --- a/test/csv/tc_features.rb +++ b/test/csv/tc_features.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_features.rb # @@ -67,18 +68,25 @@ class TestCSVFeatures < Test::Unit::TestCase end end + def test_csv_char_readers + %w[col_sep row_sep quote_char].each do |reader| + csv = CSV.new("abc,def", reader.to_sym => "|") + assert_equal("|", csv.send(reader)) + end + end + def test_row_sep_auto_discovery ["\r\n", "\n", "\r"].each do |line_end| data = "1,2,3#{line_end}4,5#{line_end}" - discovered = CSV.new(data).instance_eval { @row_sep } + discovered = CSV.new(data).row_sep assert_equal(line_end, discovered) end - assert_equal("\n", CSV.new("\n\r\n\r").instance_eval { @row_sep }) + assert_equal("\n", CSV.new("\n\r\n\r").row_sep) - assert_equal($/, CSV.new("").instance_eval { @row_sep }) + assert_equal($/, CSV.new("").row_sep) - assert_equal($/, CSV.new(STDERR).instance_eval { @row_sep }) + assert_equal($/, CSV.new(STDERR).row_sep) end def test_lineno @@ -117,6 +125,51 @@ class TestCSVFeatures < Test::Unit::TestCase assert_equal(3, count) end + def test_csv_behavior_readers + %w[ unconverted_fields return_headers write_headers + skip_blanks force_quotes ].each do |behavior| + assert( !CSV.new("abc,def").send("#{behavior}?"), + "Behavior defaulted to on." ) + csv = CSV.new("abc,def", behavior.to_sym => true) + assert(csv.send("#{behavior}?"), "Behavior change now registered.") + end + end + + def test_converters_reader + # no change + assert_equal( [:integer], + CSV.new("abc,def", :converters => [:integer]).converters ) + + # just one + assert_equal( [:integer], + CSV.new("abc,def", :converters => :integer).converters ) + + # expanded + assert_equal( [:integer, :float], + CSV.new("abc,def", :converters => :numeric).converters ) + + # custom + csv = CSV.new("abc,def", :converters => [:integer, lambda { }]) + assert_equal(2, csv.converters.size) + assert_equal(:integer, csv.converters.first) + assert_instance_of(Proc, csv.converters.last) + end + + def test_header_converters_reader + # no change + hc = :header_converters + assert_equal([:downcase], CSV.new("abc,def", hc => [:downcase]).send(hc)) + + # just one + assert_equal([:downcase], CSV.new("abc,def", hc => :downcase).send(hc)) + + # custom + csv = CSV.new("abc,def", hc => [:symbol, lambda { }]) + assert_equal(2, csv.send(hc).size) + assert_equal(:symbol, csv.send(hc).first) + assert_instance_of(Proc, csv.send(hc).last) + end + # reported by Kev Jackson def test_failing_to_escape_col_sep_bug_fix assert_nothing_raised(Exception) { CSV.new(String.new, :col_sep => "|") } @@ -149,7 +202,7 @@ class TestCSVFeatures < Test::Unit::TestCase ) ) end - assert_equal("\r\n", zipped.instance_eval { @row_sep }) + assert_equal("\r\n", zipped.row_sep) end def test_gzip_writer_bug_fix @@ -168,6 +221,41 @@ class TestCSVFeatures < Test::Unit::TestCase File.unlink(file) end + def test_inspect_is_smart_about_io_types + str = CSV.new("string,data").inspect + assert(str.include?("io_type:StringIO"), "IO type not detected.") + + str = CSV.new($stderr).inspect + assert(str.include?("io_type:$stderr"), "IO type not detected.") + + path = File.join(File.dirname(__FILE__), "temp.csv") + File.open(path, "w") { |csv| csv << "one,two,three\n1,2,3\n" } + str = CSV.open(path) { |csv| csv.inspect } + assert(str.include?("io_type:File"), "IO type not detected.") + File.unlink(path) + end + + def test_inspect_shows_key_attributes + str = @csv.inspect + %w[lineno col_sep row_sep quote_char].each do |attr_name| + assert_match(/\b#{attr_name}:[^\s>]+/, str) + end + end + + def test_inspect_shows_headers_when_available + CSV.new("one,two,three\n1,2,3\n", :headers => true) do |csv| + assert(csv.inspect.include?("headers:true"), "Header hint not shown.") + csv.shift # load headers + assert_match(/headers:\[[^\]]+\]/, csv.inspect) + end + end + + def test_inspect_is_ascii_8bit_encoded + CSV.new("one,two,three\n1,2,3\n".encode("UTF-16BE")) do |csv| + assert_equal("ASCII-8BIT", csv.inspect.encoding.name) + end + end + def test_version assert_not_nil(CSV::VERSION) assert_instance_of(String, CSV::VERSION) diff --git a/test/csv/tc_headers.rb b/test/csv/tc_headers.rb index 74e2f54ad4..e0f544dadf 100644 --- a/test/csv/tc_headers.rb +++ b/test/csv/tc_headers.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_headers.rb # @@ -129,6 +130,21 @@ class TestCSVHeaders < Test::Unit::TestCase assert(!row.field_row?) end + def test_csv_header_string_inherits_separators + # parse with custom col_sep + csv = nil + assert_nothing_raised(Exception) do + csv = CSV.parse( @data.tr(",", "|"), :col_sep => "|", + :headers => "my|new|headers" ) + end + + # verify headers were recognized + row = csv[0] + assert_not_nil(row) + assert_instance_of(CSV::Row, row) + assert_equal([%w{my first}, %w{new second}, %w{headers third}], row.to_a) + end + def test_return_headers # activate headers and request they are returned csv = nil @@ -250,6 +266,17 @@ class TestCSVHeaders < Test::Unit::TestCase end end + def test_headers_reader + # no headers + assert_nil(CSV.new(@data).headers) + + # headers + csv = CSV.new(@data, :headers => true) + assert_equal(true, csv.headers) # before headers are read + csv.shift # set headers + assert_equal(%w[first second third], csv.headers) # after headers are read + end + def test_blank_row_bug_fix @data += "\n#{@data}" # add a blank row diff --git a/test/csv/tc_interface.rb b/test/csv/tc_interface.rb index e8cc920f9d..9cacc28b0a 100644 --- a/test/csv/tc_interface.rb +++ b/test/csv/tc_interface.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_interface.rb # @@ -42,8 +43,9 @@ class TestCSVInterface < Test::Unit::TestCase csv.close assert(csv.closed?) - ret = CSV.open(@path) do |csv| - assert_instance_of(CSV, csv) + ret = CSV.open(@path) do |new_csv| + csv = new_csv + assert_instance_of(CSV, new_csv) "Return value." end assert(csv.closed?) @@ -161,7 +163,6 @@ class TestCSVInterface < Test::Unit::TestCase lines = [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}] CSV.open( @path, "w", :headers => true, - :converters => :all, :header_converters => :symbol ) do |csv| csv << lines.first.keys lines.each { |line| csv << line } @@ -173,6 +174,74 @@ class TestCSVInterface < Test::Unit::TestCase end end + def test_write_hash_with_headers_array + File.unlink(@path) + + lines = [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}] + CSV.open(@path, "w", :headers => [:b, :a, :c]) do |csv| + lines.each { |line| csv << line } + end + + # test writing fields in the correct order + File.open(@path, "r") do |f| + assert_equal("2,1,3", f.gets.strip) + assert_equal("5,4,6", f.gets.strip) + end + + # test reading CSV with headers + CSV.open( @path, "r", :headers => [:b, :a, :c], + :converters => :all ) do |csv| + csv.each { |line| assert_equal(lines.shift, line.to_hash) } + end + end + + def test_write_hash_with_headers_string + File.unlink(@path) + + lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}] + CSV.open(@path, "w", :headers => "b|a|c", :col_sep => "|") do |csv| + lines.each { |line| csv << line } + end + + # test writing fields in the correct order + File.open(@path, "r") do |f| + assert_equal("2|1|3", f.gets.strip) + assert_equal("5|4|6", f.gets.strip) + end + + # test reading CSV with headers + CSV.open( @path, "r", :headers => "b|a|c", + :col_sep => "|", + :converters => :all ) do |csv| + csv.each { |line| assert_equal(lines.shift, line.to_hash) } + end + end + + def test_write_headers + File.unlink(@path) + + lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}] + CSV.open( @path, "w", :headers => "b|a|c", + :write_headers => true, + :col_sep => "|" ) do |csv| + lines.each { |line| csv << line } + end + + # test writing fields in the correct order + File.open(@path, "r") do |f| + assert_equal("b|a|c", f.gets.strip) + assert_equal("2|1|3", f.gets.strip) + assert_equal("5|4|6", f.gets.strip) + end + + # test reading CSV with headers + CSV.open( @path, "r", :headers => true, + :col_sep => "|", + :converters => :all ) do |csv| + csv.each { |line| assert_equal(lines.shift, line.to_hash) } + end + end + def test_append # aliased add_row() and puts() File.unlink(@path) @@ -230,6 +299,6 @@ class TestCSVInterface < Test::Unit::TestCase # shortcuts assert_equal(STDOUT, CSV.instance.instance_eval { @io }) - assert_equal(STDOUT, CSV { |csv| csv.instance_eval { @io } }) + assert_equal(STDOUT, CSV { |new_csv| new_csv.instance_eval { @io } }) end end diff --git a/test/csv/tc_row.rb b/test/csv/tc_row.rb index a9b7f042b2..3fa3784bba 100644 --- a/test/csv/tc_row.rb +++ b/test/csv/tc_row.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_row.rb # @@ -286,4 +287,24 @@ class TestCSVRow < Test::Unit::TestCase assert_equal([@row.headers.size, @row.fields.size].max, @row.size) end + + def test_inspect_shows_header_field_pairs + str = @row.inspect + @row.each do |header, field| + assert( str.include?("#{header.inspect}:#{field.inspect}"), + "Header field pair not found." ) + end + end + + def test_inspect_is_ascii_8bit_encoded + assert_equal("ASCII-8BIT", @row.inspect.encoding.name) + end + + def test_inspect_shows_symbol_headers_as_bare_attributes + str = CSV::Row.new(@row.headers.map { |h| h.to_sym }, @row.fields).inspect + @row.each do |header, field| + assert( str.include?("#{header}:#{field.inspect}"), + "Header field pair not found." ) + end + end end diff --git a/test/csv/tc_serialization.rb b/test/csv/tc_serialization.rb index d9c37fde21..c8273bdb3c 100644 --- a/test/csv/tc_serialization.rb +++ b/test/csv/tc_serialization.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_serialization.rb # diff --git a/test/csv/tc_table.rb b/test/csv/tc_table.rb index 028274d97f..1e572d979c 100644 --- a/test/csv/tc_table.rb +++ b/test/csv/tc_table.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # tc_table.rb # @@ -389,4 +390,17 @@ class TestCSVTable < Test::Unit::TestCase assert_equal(@rows.size, @table.size) end + + def test_inspect_shows_current_mode + str = @table.inspect + assert(str.include?("mode:#{@table.mode}"), "Mode not shown.") + + @table.by_col! + str = @table.inspect + assert(str.include?("mode:#{@table.mode}"), "Mode not shown.") + end + + def test_inspect_is_us_ascii_encoded + assert_equal("US-ASCII", @table.inspect.encoding.name) + end end diff --git a/test/csv/ts_all.rb b/test/csv/ts_all.rb index c930523757..d380ab5318 100644 --- a/test/csv/ts_all.rb +++ b/test/csv/ts_all.rb @@ -1,4 +1,5 @@ -#!/usr/local/bin/ruby -w +#!/usr/bin/env ruby -w +# encoding: UTF-8 # ts_all.rb # @@ -17,3 +18,4 @@ require "tc_row" require "tc_table" require "tc_headers" require "tc_serialization" +require "tc_encodings" diff --git a/test/json/fixtures/fail18.json b/test/json/fixtures/fail18.json index d61a345465..e2d130c6eb 100644 --- a/test/json/fixtures/fail18.json +++ b/test/json/fixtures/fail18.json @@ -1 +1 @@ -[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] // No, we don't limit our depth: Moved to pass... +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] diff --git a/test/json/runner.rb b/test/json/runner.rb index 91bc12a594..9ad04485bf 100755 --- a/test/json/runner.rb +++ b/test/json/runner.rb @@ -23,4 +23,3 @@ class TS_AllTests end end Test::Unit::UI::Console::TestRunner.run(TS_AllTests) - # vim: set et sw=2 ts=2: diff --git a/test/json/test_json.rb b/test/json/test_json.rb index 257b8e0f63..0ee993eb88 100755 --- a/test/json/test_json.rb +++ b/test/json/test_json.rb @@ -3,6 +3,7 @@ require 'test/unit' require 'json' +require 'stringio' class TC_JSON < Test::Unit::TestCase include JSON @@ -61,6 +62,12 @@ class TC_JSON < Test::Unit::TestCase assert_equal_float [3.141], parse('[3141.0E-3]') assert_equal_float [-3.141], parse('[-3141.0e-3]') assert_equal_float [-3.141], parse('[-3141e-3]') + assert_raises(ParserError) { parse('[NaN]') } + assert parse('[NaN]', :allow_nan => true).first.nan? + assert_raises(ParserError) { parse('[Infinity]') } + assert_equal [1.0/0], parse('[Infinity]', :allow_nan => true) + assert_raises(ParserError) { parse('[-Infinity]') } + assert_equal [-1.0/0], parse('[-Infinity]', :allow_nan => true) assert_equal([""], parse('[""]')) assert_equal(["foobar"], parse('["foobar"]')) assert_equal([{}], parse('[{}]')) @@ -238,18 +245,49 @@ EOT end def test_nesting - to_deep = '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]' - assert_raises(JSON::NestingError) { JSON.parse to_deep } - assert_raises(JSON::NestingError) { JSON.parser.new(to_deep).parse } - assert_raises(JSON::NestingError) { JSON.parse to_deep, :max_nesting => 19 } - ok = JSON.parse to_deep, :max_nesting => 20 - assert_kind_of Array, ok - ok = JSON.parse to_deep, :max_nesting => nil - assert_kind_of Array, ok - ok = JSON.parse to_deep, :max_nesting => false - assert_kind_of Array, ok - ok = JSON.parse to_deep, :max_nesting => 0 - assert_kind_of Array, ok + assert_raises(JSON::NestingError) { JSON.parse '[[]]', :max_nesting => 1 } + assert_raises(JSON::NestingError) { JSON.parser.new('[[]]', :max_nesting => 1).parse } + assert_equal [[]], JSON.parse('[[]]', :max_nesting => 2) + too_deep = '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]' + too_deep_ary = eval too_deep + assert_raises(JSON::NestingError) { JSON.parse too_deep } + assert_raises(JSON::NestingError) { JSON.parser.new(too_deep).parse } + assert_raises(JSON::NestingError) { JSON.parse too_deep, :max_nesting => 19 } + ok = JSON.parse too_deep, :max_nesting => 20 + assert_equal too_deep_ary, ok + ok = JSON.parse too_deep, :max_nesting => nil + assert_equal too_deep_ary, ok + ok = JSON.parse too_deep, :max_nesting => false + assert_equal too_deep_ary, ok + ok = JSON.parse too_deep, :max_nesting => 0 + assert_equal too_deep_ary, ok + assert_raises(JSON::NestingError) { JSON.generate [[]], :max_nesting => 1 } + assert_equal '[[]]', JSON.generate([[]], :max_nesting => 2) + assert_raises(JSON::NestingError) { JSON.generate too_deep_ary } + assert_raises(JSON::NestingError) { JSON.generate too_deep_ary, :max_nesting => 19 } + ok = JSON.generate too_deep_ary, :max_nesting => 20 + assert_equal too_deep, ok + ok = JSON.generate too_deep_ary, :max_nesting => nil + assert_equal too_deep, ok + ok = JSON.generate too_deep_ary, :max_nesting => false + assert_equal too_deep, ok + ok = JSON.generate too_deep_ary, :max_nesting => 0 + assert_equal too_deep, ok + end + + def test_load_dump + too_deep = '[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]' + assert_equal too_deep, JSON.dump(eval(too_deep)) + assert_kind_of String, Marshal.dump(eval(too_deep)) + assert_raises(ArgumentError) { JSON.dump(eval(too_deep), 19) } + assert_raises(ArgumentError) { Marshal.dump(eval(too_deep), 19) } + assert_equal too_deep, JSON.dump(eval(too_deep), 20) + assert_kind_of String, Marshal.dump(eval(too_deep), 20) + output = StringIO.new + JSON.dump(eval(too_deep), output) + assert_equal too_deep, output.string + output = StringIO.new + JSON.dump(eval(too_deep), output, 20) + assert_equal too_deep, output.string end end - # vim: set et sw=2 ts=2: diff --git a/test/json/test_json_addition.rb b/test/json/test_json_addition.rb index 04c690ce31..cf8a92ae10 100755 --- a/test/json/test_json_addition.rb +++ b/test/json/test_json_addition.rb @@ -31,6 +31,10 @@ class TC_JSONAddition < Test::Unit::TestCase end class B + def self.json_creatable? + false + end + def to_json(*args) { 'json_class' => self.class.name, @@ -50,9 +54,6 @@ class TC_JSONAddition < Test::Unit::TestCase end end - def setup - end - def test_extended_json a = A.new(666) assert A.json_creatable? @@ -77,14 +78,14 @@ class TC_JSONAddition < Test::Unit::TestCase ) end - def test_extended_json_fail + def test_extended_json_fail1 b = B.new assert !B.json_creatable? json = generate(b) - assert_equal({ 'json_class' => B.name }, JSON.parse(json)) + assert_equal({ "json_class"=>"TC_JSONAddition::B" }, JSON.parse(json)) end - def test_extended_json_fail + def test_extended_json_fail2 c = C.new assert !C.json_creatable? json = generate(c) @@ -111,9 +112,11 @@ EOT assert_equal raw, raw_again end + MyJsonStruct = Struct.new 'MyJsonStruct', :foo, :bar + def test_core - t = Time.at(1198254128, 895990) - assert_equal t, JSON(JSON(t)) + t = Time.now + assert_equal t.inspect, JSON(JSON(t)).inspect d = Date.today assert_equal d, JSON(JSON(d)) d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161) @@ -122,8 +125,7 @@ EOT assert_equal 1...10, JSON(JSON(1...10)) assert_equal "a".."c", JSON(JSON("a".."c")) assert_equal "a"..."c", JSON(JSON("a"..."c")) - struct = Struct.new 'MyJsonStruct', :foo, :bar - s = struct.new 4711, 'foot' + s = MyJsonStruct.new 4711, 'foot' assert_equal s, JSON(JSON(s)) struct = Struct.new :foo, :bar s = struct.new 4711, 'foot' @@ -137,7 +139,19 @@ EOT assert_equal e.message, e_again.message assert_equal e.backtrace, e_again.backtrace end - assert_equal /foo/, JSON(JSON(/foo/)) - assert_equal /foo/i, JSON(JSON(/foo/i)) + assert_equal(/foo/, JSON(JSON(/foo/))) + assert_equal(/foo/i, JSON(JSON(/foo/i))) + end + + def test_utc_datetime + now = Time.now + d = DateTime.parse(now.to_s) # usual case + assert d, JSON.parse(d.to_json) + d = DateTime.parse(now.utc.to_s) # of = 0 + assert d, JSON.parse(d.to_json) + d = DateTime.civil(2008, 6, 17, 11, 48, 32, 1) # of = 1 / 12 => 1/12 + assert d, JSON.parse(d.to_json) + d = DateTime.civil(2008, 6, 17, 11, 48, 32, 12) # of = 12 / 12 => 12 + assert d, JSON.parse(d.to_json) end end diff --git a/test/json/test_json_generate.rb b/test/json/test_json_generate.rb index e720b2d862..b7e0bc22c6 100644 --- a/test/json/test_json_generate.rb +++ b/test/json/test_json_generate.rb @@ -70,6 +70,7 @@ EOT #assert s.check_circular h = { 1=>2 } h[3] = h + assert_raises(JSON::CircularDatastructure) { generate(h) } assert_raises(JSON::CircularDatastructure) { generate(h, s) } s = JSON.state.new(:check_circular => true) #assert s.check_circular @@ -77,4 +78,22 @@ EOT a << a assert_raises(JSON::CircularDatastructure) { generate(a, s) } end + + def test_allow_nan + assert_raises(GeneratorError) { generate([JSON::NaN]) } + assert_equal '[NaN]', generate([JSON::NaN], :allow_nan => true) + assert_equal '[NaN]', fast_generate([JSON::NaN]) + assert_raises(GeneratorError) { pretty_generate([JSON::NaN]) } + assert_equal "[\n NaN\n]", pretty_generate([JSON::NaN], :allow_nan => true) + assert_raises(GeneratorError) { generate([JSON::Infinity]) } + assert_equal '[Infinity]', generate([JSON::Infinity], :allow_nan => true) + assert_equal '[Infinity]', fast_generate([JSON::Infinity]) + assert_raises(GeneratorError) { pretty_generate([JSON::Infinity]) } + assert_equal "[\n Infinity\n]", pretty_generate([JSON::Infinity], :allow_nan => true) + assert_raises(GeneratorError) { generate([JSON::MinusInfinity]) } + assert_equal '[-Infinity]', generate([JSON::MinusInfinity], :allow_nan => true) + assert_equal '[-Infinity]', fast_generate([JSON::MinusInfinity]) + assert_raises(GeneratorError) { pretty_generate([JSON::MinusInfinity]) } + assert_equal "[\n -Infinity\n]", pretty_generate([JSON::MinusInfinity], :allow_nan => true) + end end diff --git a/test/json/test_json_rails.rb b/test/json/test_json_rails.rb index e44ea606e3..c0447ddaba 100644 --- a/test/json/test_json_rails.rb +++ b/test/json/test_json_rails.rb @@ -31,6 +31,10 @@ class TC_JSONRails < Test::Unit::TestCase end class B + def self.json_creatable? + false + end + def to_json(*args) { 'json_class' => self.class.name, @@ -46,9 +50,6 @@ class TC_JSONRails < Test::Unit::TestCase end end - def setup - end - def test_extended_json a = A.new(666) assert A.json_creatable? @@ -73,14 +74,14 @@ class TC_JSONRails < Test::Unit::TestCase ) end - def test_extended_json_fail + def test_extended_json_fail1 b = B.new assert !B.json_creatable? json = generate(b) assert_equal({ 'json_class' => B.name }, JSON.parse(json)) end - def test_extended_json_fail + def test_extended_json_fail2 c = C.new # with rails addition all objects are theoretically creatable assert C.json_creatable? json = generate(c) diff --git a/test/json/test_json_unicode.rb b/test/json/test_json_unicode.rb index cad93846b5..862c6ea1e0 100755 --- a/test/json/test_json_unicode.rb +++ b/test/json/test_json_unicode.rb @@ -7,9 +7,6 @@ require 'json' class TC_JSONUnicode < Test::Unit::TestCase include JSON - def setup - end - def test_unicode assert_equal '""', ''.to_json assert_equal '"\\b"', "\b".to_json @@ -54,7 +51,7 @@ class TC_JSONUnicode < Test::Unit::TestCase end end assert_raises(JSON::GeneratorError) do - JSON.generate(["" << 0x80]) + JSON.generate(["\x80"]) end assert_equal "\302\200", JSON.parse('["\u0080"]').first end diff --git a/test/matrix/test_matrix.rb b/test/matrix/test_matrix.rb new file mode 100644 index 0000000000..0850117b86 --- /dev/null +++ b/test/matrix/test_matrix.rb @@ -0,0 +1,49 @@ +require 'test/unit' +require 'matrix' + +class TestMatrix < Test::Unit::TestCase + def setup + @m1 = Matrix[[1,2,3], [4,5,6]] + @m2 = Matrix[[1,2,3], [4,5,6]] + @m3 = @m1.clone + @m4 = Matrix[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]] + @n1 = Matrix[[2,3,4], [5,6,7]] + end + + def test_identity + assert_same @m1, @m1 + assert_not_same @m1, @m2 + assert_not_same @m1, @m3 + assert_not_same @m1, @m4 + assert_not_same @m1, @n1 + end + + def test_equality + assert_equal @m1, @m1 + assert_equal @m1, @m2 + assert_equal @m1, @m3 + assert_equal @m1, @m4 + assert_not_equal @m1, @n1 + end + + def test_hash_equality + assert @m1.eql?(@m1) + assert @m1.eql?(@m2) + assert @m1.eql?(@m3) + assert !@m1.eql?(@m4) + assert !@m1.eql?(@n1) + + hash = { @m1 => :value } + assert hash.key?(@m1) + assert hash.key?(@m2) + assert hash.key?(@m3) + assert !hash.key?(@m4) + assert !hash.key?(@n1) + end + + def test_hash + assert_equal @m1.hash, @m1.hash + assert_equal @m1.hash, @m2.hash + assert_equal @m1.hash, @m3.hash + end +end diff --git a/test/matrix/test_vector.rb b/test/matrix/test_vector.rb new file mode 100644 index 0000000000..95a39693fc --- /dev/null +++ b/test/matrix/test_vector.rb @@ -0,0 +1,49 @@ +require 'test/unit' +require 'matrix' + +class TestVector < Test::Unit::TestCase + def setup + @v1 = Vector[1,2,3] + @v2 = Vector[1,2,3] + @v3 = @v1.clone + @v4 = Vector[1.0, 2.0, 3.0] + @w1 = Vector[2,3,4] + end + + def test_identity + assert_same @v1, @v1 + assert_not_same @v1, @v2 + assert_not_same @v1, @v3 + assert_not_same @v1, @v4 + assert_not_same @v1, @w1 + end + + def test_equality + assert_equal @v1, @v1 + assert_equal @v1, @v2 + assert_equal @v1, @v3 + assert_equal @v1, @v4 + assert_not_equal @v1, @w1 + end + + def test_hash_equality + assert @v1.eql?(@v1) + assert @v1.eql?(@v2) + assert @v1.eql?(@v3) + assert !@v1.eql?(@v4) + assert !@v1.eql?(@w1) + + hash = { @v1 => :value } + assert hash.key?(@v1) + assert hash.key?(@v2) + assert hash.key?(@v3) + assert !hash.key?(@v4) + assert !hash.key?(@w1) + end + + def test_hash + assert_equal @v1.hash, @v1.hash + assert_equal @v1.hash, @v2.hash + assert_equal @v1.hash, @v3.hash + end +end diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb index ef612e2279..e2417fe14d 100644 --- a/test/ruby/test_complex.rb +++ b/test/ruby/test_complex.rb @@ -4,6 +4,14 @@ class ComplexSub < Complex; end class Complex_Test < Test::Unit::TestCase + def setup + @rational = defined?(Rational) + if @rational + @keiju = Rational.instance_variable_get('@RCS_ID') + end + @unify = defined?(Complex::Unify) + end + def test_compsub c = ComplexSub.__send__(:new, 1) cc = ComplexSub.__send__(:convert, 1) @@ -11,7 +19,7 @@ class Complex_Test < Test::Unit::TestCase assert_kind_of(Numeric, c) assert_kind_of(Numeric, cc) - if defined?(ComplexSub::Unify) + if @unify assert_instance_of(Fixnum, c) assert_instance_of(Fixnum, cc) else @@ -42,7 +50,7 @@ class Complex_Test < Test::Unit::TestCase assert_equal(true, c.eql?(c2)) assert_equal(false, c.eql?(c3)) - if defined?(Complex::Unify) + if @unify assert_equal(true, c.eql?(0)) else assert_equal(false, c.eql?(0)) @@ -51,6 +59,7 @@ class Complex_Test < Test::Unit::TestCase def test_hash assert_instance_of(Fixnum, Complex(1,2).hash) + assert_instance_of(Fixnum, Complex(1.0,2.0).hash) h = {} h[Complex(0)] = 0 @@ -63,12 +72,15 @@ class Complex_Test < Test::Unit::TestCase h[Complex(0,0)] = 9 assert_equal(4, h.size) + + h[Complex(0.0,0.0)] = 9.0 + assert_equal(5, h.size) end def test_freeze c = Complex(1) c.freeze - unless defined?(Complex::Unify) + unless @unify assert_equal(true, c.frozen?) end assert_instance_of(String, c.to_s) @@ -77,45 +89,45 @@ class Complex_Test < Test::Unit::TestCase 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]}) + instance_eval{[real, imag]}) assert_equal([2,4], Complex.__send__(:new!, 2,4). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([-2,4], Complex.__send__(:new!, -2,4). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([2,-4], Complex.__send__(:new!, 2,-4). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([-2,-4], Complex.__send__(:new!, -2,-4). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([2,0], Complex.__send__(:new!, Complex(2)). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([2,3], Complex.__send__(:new!, Complex(2), Complex(3)). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([2,3], Complex.__send__(:new!, 2, Complex(3)). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([1.1,0], Complex.__send__(:new!, 1.1). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([-1.1,0], Complex.__send__(:new!, -1.1). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([1,0], Complex.__send__(:new!, '1'). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) assert_equal([0,0], Complex.__send__(:new!, nil). - instance_eval{[real, image]}) + instance_eval{[real, imag]}) end def test_new assert_instance_of(Complex, Complex.__send__(:new, 2,0.0)) - if defined?(Complex::Unify) + if @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]}) + assert_equal([2,0], Complex.__send__(:new, 2,0). instance_eval{[real, imag]}) 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_equal([2,4], Complex.__send__(:new, 2,4).instance_eval{[real, imag]}) + assert_equal([-2,4], Complex.__send__(:new, -2,4).instance_eval{[real, imag]}) + assert_equal([2,-4], Complex.__send__(:new, 2,-4).instance_eval{[real, imag]}) + assert_equal([-2,-4], Complex.__send__(:new, -2,-4).instance_eval{[real, imag]}) assert_raise(ArgumentError){Complex.__send__(:new, Complex(1,2),2)} assert_raise(ArgumentError){Complex.__send__(:new, 2,Complex(1,2))} @@ -134,44 +146,38 @@ class Complex_Test < Test::Unit::TestCase 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]) + assert_equal([2**32,2**32], [c.real,c.imag]) 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]) + assert_equal([-2**32,2**32], [c.real,c.imag]) 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]) + assert_equal([2**32,-2**32], [c.real,c.imag]) 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]) + assert_equal([-2**32,-2**32], [c.real,c.imag]) - c = Complex(Complex(1),0) - assert_equal(Complex.__send__(:new, 1,0), c) + c = Complex(Complex(1,2),2) + assert_equal(Complex.__send__(:new, 1,4), c) - c = Complex(0,Complex(1)) + c = Complex(2,Complex(1,2)) 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(Complex(1,2),Complex(1,2)) + assert_equal(Complex.__send__(:new, -1,3), c) 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_equal(Complex.__send__(:new, 3.0,3.0),Complex('3.0','3.0')) + if @rational && !@keiju + assert_equal(Complex.__send__(:new, 1,1),Complex('3/3','3/3')) + end assert_raise(ArgumentError){Complex(nil)} assert_raise(ArgumentError){Complex(Object.new)} assert_raise(ArgumentError){Complex()} @@ -182,64 +188,63 @@ class Complex_Test < Test::Unit::TestCase c = Complex(4) assert_equal(4, c.real) - assert_equal(0, c.image) + assert_equal(0, c.imag) c = Complex(4,5) assert_equal(4, c.real) - assert_equal(5, c.image) + assert_equal(5, c.imag) if -0.0.to_s == '-0.0' c = Complex(-0.0,-0.0) assert_equal('-0.0', c.real.to_s) - assert_equal('-0.0', c.image.to_s) + assert_equal('-0.0', c.imag.to_s) end c = Complex.__send__(:new, 4) assert_equal(4, c.real) - assert_equal(0, c.image) - assert_equal(c.imag, c.image) + assert_equal(0, c.imag) + assert_equal(c.imag, c.imaginary) c = Complex.__send__(:new, 4,5) assert_equal(4, c.real) - assert_equal(5, c.image) - assert_equal(c.imag, c.image) + assert_equal(5, c.imag) + assert_equal(c.imag, c.imaginary) if -0.0.to_s == '-0.0' 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) + assert_equal('-0.0', c.imag.to_s) + assert_equal(c.imag.to_s, c.imaginary.to_s) end c = Complex.__send__(:new!, 4) assert_equal(4, c.real) - assert_equal(c.imag, c.image) - assert_equal(0, c.image) + assert_equal(c.imag, c.imaginary) + assert_equal(0, c.imag) c = Complex.__send__(:new!, 4,5) assert_equal(4, c.real) - assert_equal(5, c.image) - assert_equal(c.imag, c.image) + assert_equal(5, c.imag) + assert_equal(c.imag, c.imaginary) 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) + assert_equal('-0.0', c.imag.to_s) + assert_equal(c.imag.to_s, c.imaginary.to_s) end def test_attr2 c = Complex(1) - if defined?(Complex::Unify) - assert_equal(true, c.scalar?) + if @unify =begin assert_equal(true, c.finite?) assert_equal(false, c.infinite?) @@ -247,13 +252,14 @@ class Complex_Test < Test::Unit::TestCase assert_equal(true, c.integer?) assert_equal(false, c.float?) assert_equal(true, c.rational?) +=end assert_equal(true, c.real?) +=begin 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?) @@ -261,7 +267,9 @@ class Complex_Test < Test::Unit::TestCase assert_equal(false, c.integer?) assert_equal(false, c.float?) assert_equal(false, c.rational?) +=end assert_equal(false, c.real?) +=begin assert_equal(true, c.complex?) assert_equal(true, c.exact?) assert_equal(false, c.inexact?) @@ -303,6 +311,16 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(-1,1), +Complex(-1,1)) assert_equal(Complex(1,-1), +Complex(1,-1)) assert_equal(Complex(-1,-1), +Complex(-1,-1)) + + if -0.0.to_s == '-0.0' + c = +Complex(0.0,0.0) + assert_equal('0.0', c.real.to_s) + assert_equal('0.0', c.imag.to_s) + + c = +Complex(-0.0,-0.0) + assert_equal('-0.0', c.real.to_s) + assert_equal('-0.0', c.imag.to_s) + end end def test_negate @@ -313,6 +331,16 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(-1,1), -Complex(1,-1)) assert_equal(Complex(1,1), -Complex(-1,-1)) + if -0.0.to_s == '-0.0' + c = -Complex(0.0,0.0) + assert_equal('-0.0', c.real.to_s) + assert_equal('-0.0', c.imag.to_s) + + c = -Complex(-0.0,-0.0) + assert_equal('0.0', c.real.to_s) + assert_equal('0.0', c.imag.to_s) + end + =begin assert_equal(0, Complex(0).negate) assert_equal(-2, Complex(2).negate) @@ -329,7 +357,7 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(3,2), c + 2) assert_equal(Complex(3.0,2), c + 2.0) - if defined?(Rational) + if @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 @@ -344,7 +372,7 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(-1,2), c - 2) assert_equal(Complex(-1.0,2), c - 2.0) - if defined?(Rational) + if @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 @@ -359,7 +387,7 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(2,4), c * 2) assert_equal(Complex(2.0,4.0), c * 2.0) - if defined?(Rational) + if @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 @@ -370,12 +398,12 @@ class Complex_Test < Test::Unit::TestCase c = Complex(1,2) c2 = Complex(2,3) - if defined?(Rational) + if @rational assert_equal(Complex(Rational(8,13),Rational(1,13)), c / c2) else r = c / c2 assert_in_delta(0.615, r.real, 0.001) - assert_in_delta(0.076, r.image, 0.001) + assert_in_delta(0.076, r.imag, 0.001) end c = Complex(1.0,2.0) @@ -383,19 +411,19 @@ class Complex_Test < Test::Unit::TestCase r = c / c2 assert_in_delta(0.615, r.real, 0.001) - assert_in_delta(0.076, r.image, 0.001) + assert_in_delta(0.076, r.imag, 0.001) c = Complex(1,2) c2 = Complex(2,3) - if defined?(Rational) + if @rational assert_equal(Complex(Rational(1,2),1), c / 2) else assert_equal(Complex(0.5,1.0), c / 2) end assert_equal(Complex(0.5,1.0), c / 2.0) - if defined?(Rational) + if @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 @@ -405,12 +433,12 @@ class Complex_Test < Test::Unit::TestCase c = Complex(1,2) c2 = Complex(2,3) - if defined?(Rational) + if @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) + assert_in_delta(0.076, r.imag, 0.001) end c = Complex(1.0,2.0) @@ -418,19 +446,19 @@ class Complex_Test < Test::Unit::TestCase r = c.quo(c2) assert_in_delta(0.615, r.real, 0.001) - assert_in_delta(0.076, r.image, 0.001) + assert_in_delta(0.076, r.imag, 0.001) c = Complex(1,2) c2 = Complex(2,3) - if defined?(Rational) + if @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) + if @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 @@ -442,14 +470,14 @@ class Complex_Test < Test::Unit::TestCase r = c.fdiv(c2) assert_in_delta(0.615, r.real, 0.001) - assert_in_delta(0.076, r.image, 0.001) + assert_in_delta(0.076, r.imag, 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) + assert_in_delta(0.076, r.imag, 0.001) c = Complex(1,2) c2 = Complex(2,3) @@ -464,25 +492,25 @@ class Complex_Test < Test::Unit::TestCase r = c ** c2 assert_in_delta(-0.015, r.real, 0.001) - assert_in_delta(-0.179, r.image, 0.001) + assert_in_delta(-0.179, r.imag, 0.001) assert_equal(Complex(-3,4), c ** 2) - if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID') + if @rational && !@keiju 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) + assert_in_delta(-0.16, r.imag, 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) + assert_in_delta(4.0, r.imag, 0.001) r = c ** -2.0 assert_in_delta(-0.12, r.real, 0.001) - assert_in_delta(-0.16, r.image, 0.001) + assert_in_delta(-0.16, r.imag, 0.001) - if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID') + if @rational && !@keiju assert_equal(Complex(-3,4), c ** Rational(2)) #=begin assert_equal(Complex(Rational(-3,25),Rational(-4,25)), @@ -491,11 +519,11 @@ class Complex_Test < Test::Unit::TestCase r = c ** Rational(2,3) assert_in_delta(1.264, r.real, 0.001) - assert_in_delta(1.150, r.image, 0.001) + assert_in_delta(1.150, r.imag, 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) + assert_in_delta(-0.393, r.imag, 0.001) end end @@ -525,7 +553,7 @@ class Complex_Test < Test::Unit::TestCase end def test_unify - if defined?(Complex::Unify) + if @unify assert_instance_of(Fixnum, Complex(1,2) + Complex(-1,-2)) assert_instance_of(Fixnum, Complex(1,2) - Complex(1,2)) assert_instance_of(Fixnum, Complex(1,2) * 0) @@ -544,9 +572,9 @@ class Complex_Test < Test::Unit::TestCase 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.abs, Math.sqrt(c.real**2 + c.imag**2)) assert_equal(c.abs2, c * c.conj) - assert_equal(c.abs2, c.real**2 + c.image**2) + assert_equal(c.abs2, c.real**2 + c.imag**2) assert_in_delta(1.107, c.arg, 0.001) assert_in_delta(1.107, c.angle, 0.001) @@ -586,7 +614,7 @@ class Complex_Test < Test::Unit::TestCase 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) && !defined?(Complex::Unify) && !Rational.instance_variable_get('@RCS_ID') + if @rational && !@unify && !@keiju assert_equal('0+2/1i', Complex(0,Rational(2)).to_s) assert_equal('0-2/1i', Complex(0,Rational(-2)).to_s) assert_equal('1+2/1i', Complex(1,Rational(2)).to_s) @@ -614,13 +642,15 @@ class Complex_Test < Test::Unit::TestCase def test_marshal c = Complex(1,2) + c.instance_eval{@ivar = 9} s = Marshal.dump(c) c2 = Marshal.load(s) assert_equal(c, c2) + assert_equal(9, c2.instance_variable_get(:@ivar)) assert_instance_of(Complex, c2) - if defined?(Rational) + if @rational c = Complex(Rational(1,2),Rational(2,3)) s = Marshal.dump(c) @@ -755,7 +785,7 @@ class Complex_Test < Test::Unit::TestCase assert_raise(ArgumentError){ Complex('5+3i_')} assert_raise(ArgumentError){ Complex('5+3ix')} - if defined?(Rational) && defined?(''.to_r) + if @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) @@ -821,51 +851,47 @@ class Complex_Test < Test::Unit::TestCase end def test_to_r - if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID') + if @rational && !@keiju 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))} +# 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]) + assert_equal([0,0] , [c.real, c.imag]) c = 0.to_c - assert_equal([0,0] , [c.real, c.image]) + assert_equal([0,0] , [c.real, c.imag]) c = 1.to_c - assert_equal([1,0] , [c.real, c.image]) + assert_equal([1,0] , [c.real, c.imag]) c = 1.1.to_c - assert_equal([1.1, 0], [c.real, c.image]) + assert_equal([1.1, 0], [c.real, c.imag]) - if defined?(Rational) + if @rational c = Rational(1,2).to_c - assert_equal([Rational(1,2), 0], [c.real, c.image]) + assert_equal([Rational(1,2), 0], [c.real, c.imag]) end c = Complex(1,2).to_c - assert_equal([1, 2], [c.real, c.image]) - end - - def test_prec - assert_equal(nil, Complex < Precision) + assert_equal([1, 2], [c.real, c.imag]) end def test_supp - assert_equal(true, 1.scalar?) - assert_equal(true, 1.1.scalar?) + assert_equal(true, 1.real?) + assert_equal(true, 1.1.real?) assert_equal(1, 1.real) - assert_equal(0, 1.image) assert_equal(0, 1.imag) + assert_equal(0, 1.imaginary) assert_equal(1.1, 1.1.real) - assert_equal(0, 1.1.image) assert_equal(0, 1.1.imag) + assert_equal(0, 1.1.imaginary) assert_equal(1, 1.magnitude) assert_equal(1, -1.magnitude) @@ -919,14 +945,14 @@ class Complex_Test < Test::Unit::TestCase assert_equal(1.1, 1.1.conj) assert_equal(-1.1, -1.1.conj) - if defined?(Rational) + if @rational assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2)) else assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2)) end =begin - if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID') + if @rational && !@keiju assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2)) end =end @@ -934,7 +960,7 @@ class Complex_Test < Test::Unit::TestCase 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) + if @rational assert_equal(0.25, Rational(1,2).fdiv(2)) end assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2)) @@ -944,7 +970,7 @@ class Complex_Test < Test::Unit::TestCase # 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) + if @rational assert_equal(Complex(0,2), Math.sqrt(Rational(-4))) # assert_equal(true, Math.sqrt(Rational(-4)).exact?) end @@ -953,98 +979,98 @@ class Complex_Test < Test::Unit::TestCase # 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) + if @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) + assert_in_delta(0.786, c.imag, 0.001) c = Math.sqrt(-9) assert_in_delta(0.0, c.real, 0.001) - assert_in_delta(3.0, c.image, 0.001) + assert_in_delta(3.0, c.imag, 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) + assert_in_delta(2.471, c.imag, 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) + assert_in_delta(1.959, c.imag, 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) + assert_in_delta(-3.051, c.imag, 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) + assert_in_delta(1.014, c.imag, 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) + assert_in_delta(1.403, c.imag, 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) + assert_in_delta(1.068, c.imag, 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) + assert_in_delta(-0.243, c.imag, 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) + assert_in_delta(1.107, c.imag, 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) + assert_in_delta(1.107, c.imag, 0.001) c = Math.log(-1) assert_in_delta(0.0, c.real, 0.001) - assert_in_delta(Math::PI, c.image, 0.001) + assert_in_delta(Math::PI, c.imag, 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) + assert_in_delta(0.0, c.imag, 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) + assert_in_delta(-0.420, c.imag, 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) + assert_in_delta(0.480, c.imag, 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) + assert_in_delta(1.528, c.imag, 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) + assert_in_delta(-1.528, c.imag, 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) + assert_in_delta(0.402, c.imag, 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) + assert_in_delta(0.402, c.imag, 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) + assert_in_delta(1.063, c.imag, 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) + assert_in_delta(1.143, c.imag, 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) + assert_in_delta(1.178, c.imag, 0.001) end end @@ -1056,7 +1082,7 @@ class Complex_Test < Test::Unit::TestCase end def test_fixed_bug - if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID') + if @rational && !@keiju assert_equal(Complex(1), 1 ** Complex(1)) end assert_equal('-1.0-0.0i', Complex(-1.0, -0.0).to_s) diff --git a/test/ruby/test_fixnum.rb b/test/ruby/test_fixnum.rb index 8fa751ba98..e55e324bd1 100644 --- a/test/ruby/test_fixnum.rb +++ b/test/ruby/test_fixnum.rb @@ -119,15 +119,6 @@ class TestFixnum < Test::Unit::TestCase assert_equal(0x4000000000000000, (-0x4000000000000000).abs) end - def test_induced_from - assert_equal(1, Fixnum.induced_from(1)) - assert_raise(RangeError) do - Fixnum.induced_from(2**31-1) - Fixnum.induced_from(2**63-1) - end - assert_equal(1, Fixnum.induced_from((2**32).coerce(1).first)) - end - def test_to_s assert_equal("1010", 10.to_s(2)) assert_equal("a", 10.to_s(36)) diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index d4bbd688d2..5d7bbb178b 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -275,13 +275,6 @@ class TestFloat < Test::Unit::TestCase assert_equal(11100.0, 11111.1.round(-2)) end - def test_induced_from - assert_equal(1.0, Float.induced_from(1)) - assert_equal(1.0, Float.induced_from(1.0)) - assert_raise(TypeError) { Float.induced_from(nil) } - end - - VS = [ 18446744073709551617.0, 18446744073709551616.0, diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index e31fb1880d..232a7fae30 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -122,12 +122,6 @@ class TestInteger < Test::Unit::TestCase assert_raise(RangeError) { 0x100.chr } end - def test_induced_from - assert_equal(1, Integer.induced_from(1)) - assert_equal(1, Integer.induced_from(1.0)) - assert_raise(TypeError) { Integer.induced_from(nil) } - end - def test_upto a = [] 1.upto(3) {|x| a << x } diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 35f575aa13..4d9bb51fe3 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -578,18 +578,6 @@ class TestIO < Test::Unit::TestCase (wt.kill; wt.join) if wt end - def pipe2(&b) - a = [] - a << IO.pipe while true - rescue Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM - yield(*a.last) - ensure - a.each do |r, w| - r.close unless !r || r.closed? - w.close unless !w || w.closed? - end - end - def ruby(*args) args = ['-e', '$>.write($<.read)'] if args.empty? ruby = EnvUtil.rubybin @@ -636,14 +624,16 @@ class TestIO < Test::Unit::TestCase assert_equal("", f2.read) end - proc do - open(__FILE__) # see Bug #493 [ruby-dev:35957] - end.call - - pipe2 do |r, w| - assert_raise(Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM) do - r2, w2 = r.dup, w.dup - end + a = [] + assert_raise(Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM) do + loop {a << IO.pipe} + end + assert_raise(Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM) do + loop {a << [a[-1][0].dup, a[-1][1].dup]} + end + a.each do |r, w| + r.close unless !r || r.closed? + w.close unless !w || w.closed? end end diff --git a/test/ruby/test_io_m17n.rb b/test/ruby/test_io_m17n.rb index 237698b868..3f21ee088e 100644 --- a/test/ruby/test_io_m17n.rb +++ b/test/ruby/test_io_m17n.rb @@ -374,7 +374,7 @@ EOT with_pipe("euc-jp:utf-8") {|r, w| w << "\xa1xyz" w.close - err = assert_raise(Encoding::InvalidByteSequence) { r.getc } + err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc } assert_equal("\xA1".force_encoding("ascii-8bit"), err.error_bytes) assert_equal("xyz", r.read(10)) } @@ -652,7 +652,7 @@ EOT after = "\u{3046}\u{3048}" w << before + invalid + after w.close - err = assert_raise(Encoding::InvalidByteSequence) { r.gets } + err = assert_raise(Encoding::InvalidByteSequenceError) { r.gets } assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) assert_equal(after.encode("euc-jp"), r.gets) } @@ -669,7 +669,7 @@ EOT w.close assert_equal(before1.encode("euc-jp"), r.getc) assert_equal(before2.encode("euc-jp"), r.getc) - err = assert_raise(Encoding::InvalidByteSequence) { r.getc } + err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc } assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) assert_equal(after1.encode("euc-jp"), r.getc) assert_equal(after2.encode("euc-jp"), r.getc) @@ -688,7 +688,7 @@ EOT w.close assert_equal(before1.encode("euc-jp"), r.getc) assert_equal(before2.encode("euc-jp"), r.getc) - err = assert_raise(Encoding::InvalidByteSequence) { r.getc } + err = assert_raise(Encoding::InvalidByteSequenceError) { r.getc } assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) assert_equal(after1.encode("euc-jp"), r.getc) assert_equal(after2.encode("euc-jp"), r.getc) @@ -711,7 +711,7 @@ EOT after = "\u{3046}\u{3048}" w << before + invalid + after w.close - err = assert_raise(Encoding::InvalidByteSequence) { r.read } + err = assert_raise(Encoding::InvalidByteSequenceError) { r.read } assert_equal(invalid.force_encoding("ascii-8bit"), err.error_bytes) assert_equal(after.encode("euc-jp"), r.read) } @@ -809,28 +809,28 @@ EOT def test_set_encoding_binmode assert_raise(ArgumentError) { - open("/dev/null", "rt") {|f| + open(__FILE__, "rt") {|f| f.set_encoding("iso-2022-jp") } } assert_raise(ArgumentError) { - open("/dev/null", "r") {|f| + open(__FILE__, "r") {|f| f.set_encoding("iso-2022-jp") } } assert_nothing_raised { - open("/dev/null", "rb") {|f| + open(__FILE__, "rb") {|f| f.set_encoding("iso-2022-jp") } } assert_nothing_raised { - open("/dev/null", "r") {|f| + open(__FILE__, "r") {|f| f.binmode f.set_encoding("iso-2022-jp") } } assert_nothing_raised { - open("/dev/null", "rt") {|f| + open(__FILE__, "rt") {|f| f.binmode f.set_encoding("iso-2022-jp") } @@ -1549,11 +1549,11 @@ EOT assert_equal("ab", f.read) } open("t.txt", "r:utf-8:euc-jp", :undef => :replace) {|f| - assert_raise(Encoding::InvalidByteSequence) { f.read } + assert_raise(Encoding::InvalidByteSequenceError) { f.read } assert_equal("b", f.read) } open("t.txt", "r:utf-8:euc-jp", :undef => :replace, :replace => "") {|f| - assert_raise(Encoding::InvalidByteSequence) { f.read } + assert_raise(Encoding::InvalidByteSequenceError) { f.read } assert_equal("b", f.read) } } @@ -1569,11 +1569,11 @@ EOT assert_equal("ab", f.read) } open("t.txt", "r:utf-8:euc-jp", :invalid => :replace) {|f| - assert_raise(Encoding::ConversionUndefined) { f.read } + assert_raise(Encoding::ConversionUndefinedError) { f.read } assert_equal("b", f.read) } open("t.txt", "r:utf-8:euc-jp", :invalid => :replace, :replace => "") {|f| - assert_raise(Encoding::ConversionUndefined) { f.read } + assert_raise(Encoding::ConversionUndefinedError) { f.read } assert_equal("b", f.read) } } @@ -1593,10 +1593,10 @@ EOT assert_equal("ab", File.read("t.txt")) open("t.txt", "w:euc-jp", :undef => :replace) {|f| - assert_raise(Encoding::InvalidByteSequence) { f.write invalid_utf8 } + assert_raise(Encoding::InvalidByteSequenceError) { f.write invalid_utf8 } } open("t.txt", "w:euc-jp", :undef => :replace, :replace => "") {|f| - assert_raise(Encoding::InvalidByteSequence) { f.write invalid_utf8 } + assert_raise(Encoding::InvalidByteSequenceError) { f.write invalid_utf8 } } } end @@ -1613,10 +1613,10 @@ EOT } assert_equal("ab", File.read("t.txt")) open("t.txt", "w:euc-jp:utf-8", :invalid => :replace) {|f| - assert_raise(Encoding::ConversionUndefined) { f.write "a\uFFFDb" } + assert_raise(Encoding::ConversionUndefinedError) { f.write "a\uFFFDb" } } open("t.txt", "w:euc-jp:utf-8", :invalid => :replace, :replace => "") {|f| - assert_raise(Encoding::ConversionUndefined) { f.write "a\uFFFDb" } + assert_raise(Encoding::ConversionUndefinedError) { f.write "a\uFFFDb" } } } end @@ -1633,10 +1633,10 @@ EOT } assert_equal("ab", File.read("t.txt")) open("t.txt", "w:iso-2022-jp:utf-8", :invalid => :replace) {|f| - assert_raise(Encoding::ConversionUndefined) { f.write "a\uFFFDb" } + assert_raise(Encoding::ConversionUndefinedError) { f.write "a\uFFFDb" } } open("t.txt", "w:iso-2022-jp:utf-8", :invalid => :replace, :replace => "") {|f| - assert_raise(Encoding::ConversionUndefined) { f.write "a\uFFFDb" } + assert_raise(Encoding::ConversionUndefinedError) { f.write "a\uFFFDb" } } } end diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb index a878227534..a1772f6408 100644 --- a/test/ruby/test_m17n.rb +++ b/test/ruby/test_m17n.rb @@ -146,17 +146,17 @@ class TestM17N < Test::Unit::TestCase # tests start def test_string_ascii_literal - assert_encoding("US-ASCII", eval(a(%{""})).encoding) - assert_encoding("US-ASCII", eval(a(%{"a"})).encoding) + assert_encoding("ASCII-8BIT", eval(a(%{""})).encoding) + assert_encoding("ASCII-8BIT", eval(a(%{"a"})).encoding) end def test_string_eucjp_literal - assert_encoding("US-ASCII", eval(e(%{""})).encoding) - assert_encoding("US-ASCII", eval(e(%{"a"})).encoding) + assert_encoding("EUC-JP", eval(e(%{""})).encoding) + assert_encoding("EUC-JP", eval(e(%{"a"})).encoding) assert_encoding("EUC-JP", eval(e(%{"\xa1\xa1"})).encoding) assert_encoding("EUC-JP", eval(e(%{"\\xa1\\xa1"})).encoding) - assert_encoding("US-ASCII", eval(e(%{"\\x20"})).encoding) - assert_encoding("US-ASCII", eval(e(%{"\\n"})).encoding) + assert_encoding("EUC-JP", eval(e(%{"\\x20"})).encoding) + assert_encoding("EUC-JP", eval(e(%{"\\n"})).encoding) assert_encoding("EUC-JP", eval(e(%{"\\x80"})).encoding) end @@ -746,7 +746,7 @@ class TestM17N < Test::Unit::TestCase #assert_raise(ArgumentError) { s("%c") % 0xc2a1 } assert_strenc("\u{c2a1}", 'UTF-8', u("%c") % 0xc2a1) assert_strenc("\u{c2}", 'UTF-8', u("%c") % 0xc2) - assert_raise(EncodingCompatibilityError) { + assert_raise(Encoding::CompatibilityError) { "%s%s" % [s("\xc2\xa1"), e("\xc2\xa1")] } end @@ -866,22 +866,22 @@ class TestM17N < Test::Unit::TestCase def test_str_aref_substr assert_equal(a("\xa1\xc2"), a("\xc2\xa1\xc2\xa2\xc2\xa3")[a("\xa1\xc2")]) - assert_raise(EncodingCompatibilityError) { a("\xc2\xa1\xc2\xa2\xc2\xa3")[e("\xa1\xc2")] } + assert_raise(Encoding::CompatibilityError) { a("\xc2\xa1\xc2\xa2\xc2\xa3")[e("\xa1\xc2")] } assert_equal(nil, e("\xc2\xa1\xc2\xa2\xc2\xa3")[e("\xa1\xc2")]) - assert_raise(EncodingCompatibilityError) { e("\xc2\xa1\xc2\xa2\xc2\xa3")[s("\xa1\xc2")] } + assert_raise(Encoding::CompatibilityError) { e("\xc2\xa1\xc2\xa2\xc2\xa3")[s("\xa1\xc2")] } assert_equal(s("\xa1\xc2"), s("\xc2\xa1\xc2\xa2\xc2\xa3")[s("\xa1\xc2")]) - assert_raise(EncodingCompatibilityError) { s("\xc2\xa1\xc2\xa2\xc2\xa3")[u("\xa1\xc2")] } + assert_raise(Encoding::CompatibilityError) { s("\xc2\xa1\xc2\xa2\xc2\xa3")[u("\xa1\xc2")] } assert_equal(nil, u("\xc2\xa1\xc2\xa2\xc2\xa3")[u("\xa1\xc2")]) - assert_raise(EncodingCompatibilityError) { u("\xc2\xa1\xc2\xa2\xc2\xa3")[a("\xa1\xc2")] } + assert_raise(Encoding::CompatibilityError) { u("\xc2\xa1\xc2\xa2\xc2\xa3")[a("\xa1\xc2")] } assert_nil(e("\xa1\xa2\xa3\xa4")[e("\xa2\xa3")]) end def test_aset s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") - assert_raise(EncodingCompatibilityError){s["\xb0\xa3"] = "foo"} + assert_raise(Encoding::CompatibilityError){s["\xb0\xa3"] = "foo"} end def test_str_center @@ -917,13 +917,13 @@ class TestM17N < Test::Unit::TestCase def test_count assert_equal(0, e("\xa1\xa2").count("z")) s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") - assert_raise(EncodingCompatibilityError){s.count(a("\xa3\xb0"))} + assert_raise(Encoding::CompatibilityError){s.count(a("\xa3\xb0"))} end def test_delete assert_equal(1, e("\xa1\xa2").delete("z").length) s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") - assert_raise(EncodingCompatibilityError){s.delete(a("\xa3\xb2"))} + assert_raise(Encoding::CompatibilityError){s.delete(a("\xa3\xb2"))} a = "\u3042\u3044\u3046\u3042\u3044\u3046" a.delete!("\u3042\u3044", "^\u3044") @@ -942,7 +942,7 @@ class TestM17N < Test::Unit::TestCase assert_nil(e("\xa1\xa2\xa3\xa4").index(e("\xa3"))) assert_nil(e("\xa1\xa2\xa3\xa4").rindex(e("\xa3"))) s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") - assert_raise(EncodingCompatibilityError){s.rindex(a("\xb1\xa3"))} + assert_raise(Encoding::CompatibilityError){s.rindex(a("\xb1\xa3"))} end def test_next @@ -985,7 +985,7 @@ class TestM17N < Test::Unit::TestCase def test_upto s1 = e("\xa1\xa2") s2 = s("\xa1\xa2") - assert_raise(EncodingCompatibilityError){s1.upto(s2) {|x| break }} + assert_raise(Encoding::CompatibilityError){s1.upto(s2) {|x| break }} end def test_casecmp @@ -1005,12 +1005,12 @@ class TestM17N < Test::Unit::TestCase end def test_plus - assert_raise(EncodingCompatibilityError){u("\xe3\x81\x82") + a("\xa1")} + assert_raise(Encoding::CompatibilityError){u("\xe3\x81\x82") + a("\xa1")} end def test_chomp s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") - assert_raise(EncodingCompatibilityError){s.chomp(s("\xa3\xb4"))} + assert_raise(Encoding::CompatibilityError){s.chomp(s("\xa3\xb4"))} end def test_gsub @@ -1023,7 +1023,7 @@ class TestM17N < Test::Unit::TestCase t = s.gsub(/b/, "\xa1\xa1".force_encoding("euc-jp")) assert_equal(Encoding::ASCII_8BIT, s.encoding) - assert_raise(EncodingCompatibilityError) { + assert_raise(Encoding::CompatibilityError) { "abc".gsub(/[ac]/) { $& == "a" ? "\xc2\xa1".force_encoding("euc-jp") : "\xc2\xa1".force_encoding("utf-8") @@ -1044,7 +1044,7 @@ class TestM17N < Test::Unit::TestCase def test_each_line s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") - assert_raise(EncodingCompatibilityError){s.each_line(a("\xa3\xb1")) {|l| }} + assert_raise(Encoding::CompatibilityError){s.each_line(a("\xa3\xb1")) {|l| }} s = e("\xa4\xa2\nfoo") actual = [] @@ -1280,11 +1280,20 @@ class TestM17N < Test::Unit::TestCase end def test_compatible - assert_raise(TypeError) {Encoding.compatible?("",0)} + assert_nil Encoding.compatible?("",0) + assert_equal(Encoding::UTF_8, Encoding.compatible?(Encoding::UTF_8, Encoding::UTF_8)) + assert_equal(Encoding::UTF_8, Encoding.compatible?(Encoding::UTF_8, Encoding::US_ASCII)) + assert_equal(Encoding::ASCII_8BIT, + Encoding.compatible?(Encoding::ASCII_8BIT, Encoding::US_ASCII)) + assert_nil Encoding.compatible?(Encoding::UTF_8, Encoding::ASCII_8BIT) end def test_force_encoding assert(("".center(1, "\x80".force_encoding("utf-8")); true), "moved from btest/knownbug, [ruby-dev:33807]") end + + def test_combchar_codepoint + assert_equal([0x30BB, 0x309A], "\u30BB\u309A".codepoints.to_a) + end end diff --git a/test/ruby/test_m17n_comb.rb b/test/ruby/test_m17n_comb.rb index 37b1a687a2..50fe8c2233 100644 --- a/test/ruby/test_m17n_comb.rb +++ b/test/ruby/test_m17n_comb.rb @@ -261,7 +261,7 @@ class TestM17NComb < Test::Unit::TestCase def test_str_plus combination(STRINGS, STRINGS) {|s1, s2| if s1.encoding != s2.encoding && !s1.ascii_only? && !s2.ascii_only? - assert_raise(EncodingCompatibilityError) { s1 + s2 } + assert_raise(Encoding::CompatibilityError) { s1 + s2 } else t = enccall(s1, :+, s2) assert(t.valid_encoding?) if s1.valid_encoding? && s2.valid_encoding? @@ -318,10 +318,11 @@ class TestM17NComb < Test::Unit::TestCase def test_str_eq combination(STRINGS, STRINGS) {|s1, s2| desc_eq = "#{encdump s1} == #{encdump s2}" - if s1.ascii_only? && s2.ascii_only? && a(s1) == a(s2) - assert(s1 == s2, desc_eq) - assert(s1.eql?(s2), desc_eq) - elsif s1.encoding == s2.encoding && a(s1) == a(s2) + if a(s1) == a(s2) and + (s1.ascii_only? && s2.ascii_only? or + s1.encoding == s2.encoding or + s1.encoding == (enc = Encoding.find("ASCII-8BIT")) or + s2.encoding == enc) then assert(s1 == s2, desc_eq) assert(!(s1 != s2)) assert_equal(0, s1 <=> s2) @@ -344,7 +345,7 @@ class TestM17NComb < Test::Unit::TestCase assert_equal(a(s), a(s1) + a(s2)) assert_str_enc_propagation(s, s1, s2) else - assert_raise(EncodingCompatibilityError) { s << s2 } + assert_raise(Encoding::CompatibilityError) { s << s2 } end } end @@ -396,7 +397,7 @@ class TestM17NComb < Test::Unit::TestCase end end else - assert_raise(EncodingCompatibilityError) { s1[s2] } + assert_raise(Encoding::CompatibilityError) { s1[s2] } end } end @@ -481,7 +482,7 @@ class TestM17NComb < Test::Unit::TestCase end end else - assert_raise(EncodingCompatibilityError) { t[i] = s2 } + assert_raise(Encoding::CompatibilityError) { t[i] = s2 } end } } @@ -513,7 +514,7 @@ class TestM17NComb < Test::Unit::TestCase end end else - assert_raise(EncodingCompatibilityError) { t[i,len] = s2 } + assert_raise(Encoding::CompatibilityError) { t[i,len] = s2 } end } end @@ -526,7 +527,7 @@ class TestM17NComb < Test::Unit::TestCase !s2.ascii_only? ? s2.encoding : nil, !s3.ascii_only? ? s3.encoding : nil].uniq.compact if 1 < encs.length - assert_raise(EncodingCompatibilityError, IndexError) { t[s2] = s3 } + assert_raise(Encoding::CompatibilityError, IndexError) { t[s2] = s3 } else if encs.empty? encs = [ @@ -565,7 +566,7 @@ class TestM17NComb < Test::Unit::TestCase end end else - assert_raise(EncodingCompatibilityError, RangeError, + assert_raise(Encoding::CompatibilityError, RangeError, "t=#{encdump(s1)};t[#{first}..#{last}]=#{encdump(s2)}") { t[first..last] = s2 } @@ -592,7 +593,7 @@ class TestM17NComb < Test::Unit::TestCase end end else - assert_raise(EncodingCompatibilityError, RangeError, + assert_raise(Encoding::CompatibilityError, RangeError, "t=#{encdump(s1)};t[#{first}...#{last}]=#{encdump(s2)}") { t[first...last] = s2 } @@ -655,7 +656,7 @@ class TestM17NComb < Test::Unit::TestCase next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.center(width, s2) } + assert_raise(Encoding::CompatibilityError) { s1.center(width, s2) } next end t = enccall(s1, :center, width, s2) @@ -676,7 +677,7 @@ class TestM17NComb < Test::Unit::TestCase next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.ljust(width, s2) } + assert_raise(Encoding::CompatibilityError) { s1.ljust(width, s2) } next end t = enccall(s1, :ljust, width, s2) @@ -697,7 +698,7 @@ class TestM17NComb < Test::Unit::TestCase next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.rjust(width, s2) } + assert_raise(Encoding::CompatibilityError) { s1.rjust(width, s2) } next end t = enccall(s1, :rjust, width, s2) @@ -711,7 +712,7 @@ class TestM17NComb < Test::Unit::TestCase combination(STRINGS, STRINGS) {|s1, s2| if !s1.ascii_only? && !s2.ascii_only? && !Encoding.compatible?(s1,s2) if s1.bytesize > s2.bytesize - assert_raise(EncodingCompatibilityError) { s1.chomp(s2) } + assert_raise(Encoding::CompatibilityError) { s1.chomp(s2) } end next end @@ -777,11 +778,11 @@ class TestM17NComb < Test::Unit::TestCase def test_str_count combination(STRINGS, STRINGS) {|s1, s2| if !s1.valid_encoding? || !s2.valid_encoding? - assert_raise(ArgumentError, EncodingCompatibilityError) { s1.count(s2) } + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.count(s2) } next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.count(s2) } + assert_raise(Encoding::CompatibilityError) { s1.count(s2) } next end n = enccall(s1, :count, s2) @@ -809,11 +810,11 @@ class TestM17NComb < Test::Unit::TestCase next end if !s1.valid_encoding? || !s2.valid_encoding? - assert_raise(ArgumentError, EncodingCompatibilityError) { s1.delete(s2) } + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.delete(s2) } next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.delete(s2) } + assert_raise(Encoding::CompatibilityError) { s1.delete(s2) } next end t = enccall(s1, :delete, s2) @@ -855,11 +856,11 @@ class TestM17NComb < Test::Unit::TestCase def test_str_each_line combination(STRINGS, STRINGS) {|s1, s2| if !s1.valid_encoding? || !s2.valid_encoding? - assert_raise(ArgumentError, EncodingCompatibilityError) { s1.each_line(s2) {} } + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.each_line(s2) {} } next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.each_line(s2) {} } + assert_raise(Encoding::CompatibilityError) { s1.each_line(s2) {} } next end lines = [] @@ -908,9 +909,9 @@ class TestM17NComb < Test::Unit::TestCase def test_str_include? combination(STRINGS, STRINGS) {|s1, s2| if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.include?(s2) } - assert_raise(EncodingCompatibilityError) { s1.index(s2) } - assert_raise(EncodingCompatibilityError) { s1.rindex(s2) } + assert_raise(Encoding::CompatibilityError) { s1.include?(s2) } + assert_raise(Encoding::CompatibilityError) { s1.index(s2) } + assert_raise(Encoding::CompatibilityError) { s1.rindex(s2) } next end t = enccall(s1, :include?, s2) @@ -941,7 +942,7 @@ class TestM17NComb < Test::Unit::TestCase def test_str_index combination(STRINGS, STRINGS, -2..2) {|s1, s2, pos| if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.index(s2) } + assert_raise(Encoding::CompatibilityError) { s1.index(s2) } next end t = enccall(s1, :index, s2, pos) @@ -974,7 +975,7 @@ class TestM17NComb < Test::Unit::TestCase def test_str_rindex combination(STRINGS, STRINGS, -2..2) {|s1, s2, pos| if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.rindex(s2) } + assert_raise(Encoding::CompatibilityError) { s1.rindex(s2) } next end t = enccall(s1, :rindex, s2, pos) @@ -1023,11 +1024,11 @@ class TestM17NComb < Test::Unit::TestCase t2 = s1.dup begin t1[nth, 0] = s2 - rescue EncodingCompatibilityError, IndexError => e1 + rescue Encoding::CompatibilityError, IndexError => e1 end begin t2.insert(nth, s2) - rescue EncodingCompatibilityError, IndexError => e2 + rescue Encoding::CompatibilityError, IndexError => e2 end assert_equal(t1, t2, "t=#{encdump s1}; t.insert(#{nth},#{encdump s2}); t") assert_equal(e1.class, e2.class, "begin #{encdump s1}.insert(#{nth},#{encdump s2}); rescue ArgumentError, IndexError => e; e end") @@ -1041,7 +1042,7 @@ class TestM17NComb < Test::Unit::TestCase t1.insert(nth, s2) slen = s2.length assert_equal(t1[nth-slen+1,slen], s2, "t=#{encdump s1}; t.insert(#{nth},#{encdump s2}); t") - rescue EncodingCompatibilityError, IndexError => e + rescue Encoding::CompatibilityError, IndexError => e end } end @@ -1158,11 +1159,11 @@ class TestM17NComb < Test::Unit::TestCase def test_str_split combination(STRINGS, STRINGS) {|s1, s2| if !s2.valid_encoding? - assert_raise(RegexpError) { s1.split(s2) } + assert_raise(ArgumentError, RegexpError) { s1.split(s2) } next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(ArgumentError) { s1.split(s2) } + assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.split(s2) } next end if !s1.valid_encoding? @@ -1186,11 +1187,11 @@ class TestM17NComb < Test::Unit::TestCase def test_str_squeeze combination(STRINGS, STRINGS) {|s1, s2| if !s1.valid_encoding? || !s2.valid_encoding? - assert_raise(ArgumentError, EncodingCompatibilityError, "#{encdump s1}.squeeze(#{encdump s2})") { s1.squeeze(s2) } + assert_raise(ArgumentError, Encoding::CompatibilityError, "#{encdump s1}.squeeze(#{encdump s2})") { s1.squeeze(s2) } next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(EncodingCompatibilityError) { s1.squeeze(s2) } + assert_raise(Encoding::CompatibilityError) { s1.squeeze(s2) } next end t = enccall(s1, :squeeze, s2) @@ -1280,7 +1281,7 @@ class TestM17NComb < Test::Unit::TestCase next end if !str_enc_compatible?(s1, s2, s3) - assert_raise(EncodingCompatibilityError, desc) { s1.tr(s2, s3) } + assert_raise(Encoding::CompatibilityError, desc) { s1.tr(s2, s3) } next end if !s1.valid_encoding? @@ -1309,11 +1310,11 @@ class TestM17NComb < Test::Unit::TestCase next end if !s1.valid_encoding? - assert_raise(ArgumentError, EncodingCompatibilityError, desc) { s1.tr_s(s2, s3) } + assert_raise(ArgumentError, Encoding::CompatibilityError, desc) { s1.tr_s(s2, s3) } next end if !str_enc_compatible?(s1, s2, s3) - assert_raise(EncodingCompatibilityError, desc) { s1.tr(s2, s3) } + assert_raise(Encoding::CompatibilityError, desc) { s1.tr(s2, s3) } next end if s2.empty? @@ -1423,7 +1424,7 @@ class TestM17NComb < Test::Unit::TestCase next end if !str_enc_compatible?(s1.gsub(r2, ''), s3) - assert_raise(EncodingCompatibilityError, desc) { doit.call } + assert_raise(Encoding::CompatibilityError, desc) { doit.call } next end t = nil @@ -1477,7 +1478,7 @@ class TestM17NComb < Test::Unit::TestCase next end if !str_enc_compatible?(s1.gsub(r2, ''), s3) - assert_raise(EncodingCompatibilityError, desc) { doit.call } + assert_raise(Encoding::CompatibilityError, desc) { doit.call } next end t = ret = nil @@ -1538,7 +1539,7 @@ class TestM17NComb < Test::Unit::TestCase combination(STRINGS, STRINGS) {|s1, s2| desc = "#{encdump s1}.end_with?(#{encdump s2})" if !str_enc_compatible?(s1, s2) - assert_raise(EncodingCompatibilityError, desc) { s1.end_with?(s2) } + assert_raise(Encoding::CompatibilityError, desc) { s1.end_with?(s2) } next end if s1.length < s2.length @@ -1557,7 +1558,7 @@ class TestM17NComb < Test::Unit::TestCase combination(STRINGS, STRINGS) {|s1, s2| desc = "#{encdump s1}.start_with?(#{encdump s2})" if !str_enc_compatible?(s1, s2) - assert_raise(EncodingCompatibilityError, desc) { s1.start_with?(s2) } + assert_raise(Encoding::CompatibilityError, desc) { s1.start_with?(s2) } next end s1 = s1.dup.force_encoding("ASCII-8BIT") @@ -1592,7 +1593,7 @@ class TestM17NComb < Test::Unit::TestCase combination(STRINGS, STRINGS) {|s1, s2| desc = "#{encdump s1}.partition(#{encdump s2})" if !str_enc_compatible?(s1, s2) - assert_raise(EncodingCompatibilityError, desc) { s1.partition(s2) } + assert_raise(Encoding::CompatibilityError, desc) { s1.partition(s2) } next end i = enccall(s1, :index, s2) @@ -1608,7 +1609,7 @@ class TestM17NComb < Test::Unit::TestCase combination(STRINGS, STRINGS) {|s1, s2| desc = "#{encdump s1}.rpartition(#{encdump s2})" if !str_enc_compatible?(s1, s2) - assert_raise(EncodingCompatibilityError, desc) { s1.rpartition(s2) } + assert_raise(Encoding::CompatibilityError, desc) { s1.rpartition(s2) } next end i = enccall(s1, :rindex, s2) diff --git a/test/ruby/test_math.rb b/test/ruby/test_math.rb index 55f354664c..d4dbf9dbf0 100644 --- a/test/ruby/test_math.rb +++ b/test/ruby/test_math.rb @@ -113,6 +113,7 @@ class TestMath < Test::Unit::TestCase assert_equal(1.0/0, Math.log(1.0/0)) assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log(0) } assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log(-1) } + assert_raise(TypeError) { Math.log(1,nil) } end def test_log2 diff --git a/test/ruby/test_mixed_unicode_escapes.rb b/test/ruby/test_mixed_unicode_escapes.rb index f274ae7090..982b57e286 100644 --- a/test/ruby/test_mixed_unicode_escapes.rb +++ b/test/ruby/test_mixed_unicode_escapes.rb @@ -1,4 +1,4 @@ -# -*- coding: sjis -*- +# -*- coding: cp932 -*- # This test is in a differnt file than TestUnicodeEscapes # So that we can have a different coding comment above @@ -18,8 +18,8 @@ class TestMixedUnicodeEscape < Test::Unit::TestCase # String interpolation turns into an expression and we get # a different kind of error, but we still can't mix these - assert_raise(EncodingCompatibilityError) { eval %q("\u{1234}#{nil}")} - assert_raise(EncodingCompatibilityError) { eval %q("#{nil}\u1234")} + assert_raise(Encoding::CompatibilityError) { eval %q("\u{1234}#{nil}")} + assert_raise(Encoding::CompatibilityError) { eval %q("#{nil}\u1234")} end end diff --git a/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb index 3db054fdae..0dd7b2e99c 100644 --- a/test/ruby/test_numeric.rb +++ b/test/ruby/test_numeric.rb @@ -72,8 +72,8 @@ class TestNumeric < Test::Unit::TestCase end end - def test_scalar_p - assert(Numeric.new.scalar?) + def test_real_p + assert(Numeric.new.real?) end def test_integer_p diff --git a/test/ruby/test_prec.rb b/test/ruby/test_prec.rb deleted file mode 100644 index d872242c11..0000000000 --- a/test/ruby/test_prec.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'test/unit' - -class TestPrecision < Test::Unit::TestCase - def test_prec_i - assert_same(1, 1.0.prec(Integer)) - assert_same(1, 1.0.prec_i) - assert_same(1, Integer.induced_from(1.0)) - end - - def test_prec_f - assert_equal(1.0, 1.prec(Float)) - assert_equal(1.0, 1.prec_f) - assert_equal(1.0, Float.induced_from(1)) - end - - def test_induced_from - m = Module.new - m.instance_eval { include(Precision) } - assert_raise(TypeError) { m.induced_from(0) } - end -end diff --git a/test/ruby/test_rational.rb b/test/ruby/test_rational.rb index 1d280e4361..7f75584e0e 100644 --- a/test/ruby/test_rational.rb +++ b/test/ruby/test_rational.rb @@ -4,6 +4,14 @@ class RationalSub < Rational; end class Rational_Test < Test::Unit::TestCase + def setup + @complex = defined?(Complex) + if @complex + @keiju = Complex.instance_variable_get('@RCS_ID') + end + @unify = defined?(Rational::Unify) + end + def test_ratsub c = RationalSub.__send__(:new, 1) cc = RationalSub.__send__(:convert, 1) @@ -11,7 +19,7 @@ class Rational_Test < Test::Unit::TestCase assert_kind_of(Numeric, c) assert_kind_of(Numeric, cc) - if defined?(RationalSub::Unify) + if @unify assert_instance_of(Fixnum, c) assert_instance_of(Fixnum, cc) else @@ -41,7 +49,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(true, c.eql?(c2)) assert_equal(false, c.eql?(c3)) - if defined?(Rational::Unify) + if @unify assert_equal(true, c.eql?(0)) else assert_equal(false, c.eql?(0)) @@ -67,7 +75,7 @@ class Rational_Test < Test::Unit::TestCase def test_freeze c = Rational(1) c.freeze - unless defined?(Rational::Unify) + unless @unify assert_equal(true, c.frozen?) end assert_instance_of(String, c.to_s) @@ -108,7 +116,7 @@ class Rational_Test < Test::Unit::TestCase =begin def test_reduce - if defined?(Rational::Unify) + if @unify assert_instance_of(Fixnum, Rational.__send__(:reduce, 2,1)) else assert_instance_of(Rational, Rational.__send__(:reduce, 2,1)) @@ -138,7 +146,7 @@ class Rational_Test < Test::Unit::TestCase =end def test_new - if defined?(Rational::Unify) + if @unify assert_instance_of(Fixnum, Rational.__send__(:new, 2,1)) else assert_instance_of(Rational, Rational.__send__(:new, 2,1)) @@ -164,7 +172,7 @@ class Rational_Test < Test::Unit::TestCase assert_raise(ArgumentError){Rational.__send__(:new, nil)} =begin assert_raise(ArgumentError){Rational.__send__(:new, Rational(1))} - if defined?(Complex) + if @complex assert_raise(ArgumentError){Rational.__send__(:new, Complex(1))} end =end @@ -199,6 +207,17 @@ class Rational_Test < Test::Unit::TestCase c = Rational(Rational(1,2),Rational(1,2)) assert_equal(Rational.__send__(:new, 1), c) + if @complex && !@keiju + c = Rational(Complex(1,2),2) + assert_equal(Complex.__send__(:new, Rational(1,2),1), c) + + c = Rational(2,Complex(1,2)) + assert_equal(Complex.__send__(:new, Rational(2,5),Rational(-4,5)), c) + + c = Rational(Complex(1,2),Complex(1,2)) + assert_equal(Rational.__send__(:new, 1), c) + end + assert_equal(Rational.__send__(:new, 3),Rational(3)) assert_equal(Rational.__send__(:new, 1),Rational(3,3)) assert_equal(3.3.to_r,Rational(3.3)) @@ -248,8 +267,7 @@ class Rational_Test < Test::Unit::TestCase def test_attr2 c = Rational(1) - if defined?(Rational::Unify) - assert_equal(true, c.scalar?) + if @unify =begin assert_equal(true, c.finite?) assert_equal(false, c.infinite?) @@ -257,13 +275,14 @@ class Rational_Test < Test::Unit::TestCase assert_equal(true, c.integer?) assert_equal(false, c.float?) assert_equal(true, c.rational?) +=end assert_equal(true, c.real?) +=begin 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?) @@ -271,7 +290,9 @@ class Rational_Test < Test::Unit::TestCase assert_equal(false, c.integer?) assert_equal(false, c.float?) assert_equal(true, c.rational?) +=end assert_equal(true, c.real?) +=begin assert_equal(false, c.complex?) assert_equal(true, c.exact?) assert_equal(false, c.inexact?) @@ -406,7 +427,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(-2, (-c).div(c2)) assert_equal(1, (-c).div(-c2)) - unless defined?(Rational::Unify) + unless @unify c = Rational(11) c2 = Rational(3) @@ -441,7 +462,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(Rational(99,100), (-c).modulo(c2)) assert_equal(Rational(-101,100), (-c).modulo(-c2)) - unless defined?(Rational::Unify) + unless @unify c = Rational(11) c2 = Rational(3) @@ -476,7 +497,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal([-2, Rational(99,100)], (-c).divmod(c2)) assert_equal([1, Rational(-101,100)], (-c).divmod(-c2)) - unless defined?(Rational::Unify) + unless @unify c = Rational(11) c2 = Rational(3) @@ -512,7 +533,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(-1, (-c).quot(c2)) assert_equal(1, (-c).quot(-c2)) - unless defined?(Rational::Unify) + unless @unify c = Rational(11) c2 = Rational(3) @@ -548,7 +569,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(Rational(-101,100), (-c).remainder(c2)) assert_equal(Rational(-101,100), (-c).remainder(-c2)) - unless defined?(Rational::Unify) + unless @unify c = Rational(11) c2 = Rational(3) @@ -584,7 +605,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal([-1, Rational(-101,100)], (-c).quotrem(c2)) assert_equal([1, Rational(-101,100)], (-c).quotrem(-c2)) - unless defined?(Rational::Unify) + unless @unify c = Rational(11) c2 = Rational(3) @@ -641,7 +662,7 @@ class Rational_Test < Test::Unit::TestCase # p ** p x = 2 ** Rational(2) assert_equal(Rational(4), x) - unless defined?(Rational::Unify) + unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) @@ -649,7 +670,7 @@ class Rational_Test < Test::Unit::TestCase x = Rational(2) ** 2 assert_equal(Rational(4), x) - unless defined?(Rational::Unify) + unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) @@ -657,7 +678,7 @@ class Rational_Test < Test::Unit::TestCase x = Rational(2) ** Rational(2) assert_equal(Rational(4), x) - unless defined?(Rational::Unify) + unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) @@ -666,7 +687,7 @@ class Rational_Test < Test::Unit::TestCase # -p ** p x = (-2) ** Rational(2) assert_equal(Rational(4), x) - unless defined?(Rational::Unify) + unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) @@ -674,7 +695,7 @@ class Rational_Test < Test::Unit::TestCase x = Rational(-2) ** 2 assert_equal(Rational(4), x) - unless defined?(Rational::Unify) + unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) @@ -682,7 +703,7 @@ class Rational_Test < Test::Unit::TestCase x = Rational(-2) ** Rational(2) assert_equal(Rational(4), x) - unless defined?(Rational::Unify) + unless @unify assert_instance_of(Rational, x) end assert_equal(4, x.numerator) @@ -726,7 +747,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(1, x.numerator) assert_equal(4, x.denominator) - unless defined?(Rational::Unify) # maybe bug mathn + unless @unify # maybe bug mathn assert_raise(ZeroDivisionError){0 ** -1} end end @@ -787,7 +808,7 @@ class Rational_Test < Test::Unit::TestCase end def test_unify - if defined?(Rational::Unify) + if @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) @@ -801,7 +822,7 @@ class Rational_Test < Test::Unit::TestCase def test_math assert_equal(Rational(1,2), Rational(1,2).abs) assert_equal(Rational(1,2), Rational(-1,2).abs) - if defined?(Complex) && !Complex.instance_variable_get('@RCS_ID') + if @complex && !@keiju assert_equal(Rational(1,2), Rational(1,2).magnitude) assert_equal(Rational(1,2), Rational(-1,2).magnitude) end @@ -831,7 +852,7 @@ class Rational_Test < Test::Unit::TestCase assert_instance_of(String, c.to_s) assert_equal('1/2', c.to_s) - if defined?(Rational::Unify) + if @unify assert_equal('0', Rational(0,2).to_s) assert_equal('0', Rational(0,-2).to_s) else @@ -854,10 +875,12 @@ class Rational_Test < Test::Unit::TestCase def test_marshal c = Rational(1,2) + c.instance_eval{@ivar = 9} s = Marshal.dump(c) c2 = Marshal.load(s) assert_equal(c, c2) + assert_equal(9, c2.instance_variable_get(:@ivar)) assert_instance_of(Rational, c2) assert_raise(ZeroDivisionError){ @@ -987,8 +1010,8 @@ class Rational_Test < Test::Unit::TestCase end def test_to_c - if defined?(Complex) && !Complex.instance_variable_get('@RCS_ID') - if defined?(Rational::Unify) + if @complex && !@keiju + if @unify assert_equal(Rational(3,2), Rational(3,2).to_c) assert_equal(Rational(3,2), Complex(Rational(3,2))) else @@ -1015,8 +1038,8 @@ class Rational_Test < Test::Unit::TestCase c = Rational(1,2).to_r assert_equal([1,2] , [c.numerator, c.denominator]) - if defined?(Complex) - if Complex.instance_variable_get('@RCS_ID') + if @complex + if @keiju assert_raise(NoMethodError){Complex(1,2).to_r} else assert_raise(RangeError){Complex(1,2).to_r} @@ -1024,16 +1047,6 @@ class Rational_Test < Test::Unit::TestCase 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_gcdlcm assert_equal(7, 91.gcd(-49)) assert_equal(5, 5.gcd(0)) @@ -1052,8 +1065,8 @@ class Rational_Test < Test::Unit::TestCase end def test_supp - assert_equal(true, 1.scalar?) - assert_equal(true, 1.1.scalar?) + assert_equal(true, 1.real?) + assert_equal(true, 1.1.real?) assert_equal(1, 1.numerator) assert_equal(9, 9.numerator) @@ -1089,7 +1102,7 @@ class Rational_Test < Test::Unit::TestCase end def test_fixed_bug - if defined?(Rational::Unify) + if @unify assert_instance_of(Fixnum, Rational(1,2) ** 0) # mathn's bug end diff --git a/test/ruby/test_transcode.rb b/test/ruby/test_transcode.rb index 5abeed88ee..389deb48b1 100644 --- a/test/ruby/test_transcode.rb +++ b/test/ruby/test_transcode.rb @@ -21,13 +21,13 @@ class TestTranscode < Test::Unit::TestCase def test_errors assert_raise(ArgumentError) { 'abc'.encode } assert_raise(ArgumentError) { 'abc'.encode! } - assert_raise(Encoding::NoConverter) { 'abc'.encode('foo', 'bar') } - assert_raise(Encoding::NoConverter) { 'abc'.encode!('foo', 'bar') } - assert_raise(Encoding::NoConverter) { 'abc'.force_encoding('utf-8').encode('foo') } - assert_raise(Encoding::NoConverter) { 'abc'.force_encoding('utf-8').encode!('foo') } - assert_raise(Encoding::ConversionUndefined) { "\x80".encode('utf-8','ASCII-8BIT') } - assert_raise(Encoding::InvalidByteSequence) { "\x80".encode('utf-8','US-ASCII') } - assert_raise(Encoding::ConversionUndefined) { "\xA5".encode('utf-8','iso-8859-3') } + assert_raise(Encoding::NoConverterError) { 'abc'.encode('foo', 'bar') } + assert_raise(Encoding::NoConverterError) { 'abc'.encode!('foo', 'bar') } + assert_raise(Encoding::NoConverterError) { 'abc'.force_encoding('utf-8').encode('foo') } + assert_raise(Encoding::NoConverterError) { 'abc'.force_encoding('utf-8').encode!('foo') } + assert_raise(Encoding::ConversionUndefinedError) { "\x80".encode('utf-8','ASCII-8BIT') } + assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode('utf-8','US-ASCII') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA5".encode('utf-8','iso-8859-3') } end def test_arguments @@ -355,24 +355,24 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u71FC", "\xE0\x9E", 'shift_jis') # 燼 check_both_ways("\u71F9", "\xE0\x9F", 'shift_jis') # 燹 check_both_ways("\u73F1", "\xE0\xFC", 'shift_jis') # 珱 - assert_raise(Encoding::ConversionUndefined) { "\xEF\x40".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xEF\x7E".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xEF\x80".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xEF\x9E".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xEF\x9F".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xEF\xFC".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xF0\x40".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xF0\x7E".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xF0\x80".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xF0\x9E".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xF0\x9F".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xF0\xFC".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xEF\x40".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xEF\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xEF\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xEF\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xEF\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xEF\xFC".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xF0\x40".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xF0\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xF0\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xF0\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xF0\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xF0\xFC".encode("utf-8", 'shift_jis') } #check_both_ways("\u9ADC", "\xFC\x40", 'shift_jis') # 髜 (IBM extended) - assert_raise(Encoding::ConversionUndefined) { "\xFC\x7E".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xFC\x80".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xFC\x9E".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xFC\x9F".encode("utf-8", 'shift_jis') } - assert_raise(Encoding::ConversionUndefined) { "\xFC\xFC".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xFC\x7E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xFC\x80".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xFC\x9E".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xFC\x9F".encode("utf-8", 'shift_jis') } + assert_raise(Encoding::ConversionUndefinedError) { "\xFC\xFC".encode("utf-8", 'shift_jis') } check_both_ways("\u677E\u672C\u884C\u5F18", "\x8f\xbc\x96\x7b\x8d\x73\x8d\x4f", 'shift_jis') # 松本行弘 check_both_ways("\u9752\u5C71\u5B66\u9662\u5927\u5B66", "\x90\xC2\x8E\x52\x8A\x77\x89\x40\x91\xE5\x8A\x77", 'shift_jis') # 青山学院大学 check_both_ways("\u795E\u6797\u7FA9\u535A", "\x90\x5F\x97\xD1\x8B\x60\x94\x8E", 'shift_jis') # 神林義博 @@ -392,34 +392,34 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u00F7", "\xA1\xE0", 'euc-jp') # ÷ check_both_ways("\u25C7", "\xA1\xFE", 'euc-jp') # ◇ check_both_ways("\u25C6", "\xA2\xA1", 'euc-jp') # ◆ - assert_raise(Encoding::ConversionUndefined) { "\xA2\xAF".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xB9".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xC2".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xC9".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xD1".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xDB".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xEB".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xF1".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xFA".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA2\xFD".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xAF".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xB9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xC2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xC9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xD1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xDB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xEB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xF1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xFA".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA2\xFD".encode("utf-8", 'euc-jp') } check_both_ways("\u25EF", "\xA2\xFE", 'euc-jp') # ◯ - assert_raise(Encoding::ConversionUndefined) { "\xA3\xAF".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA3\xBA".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA3\xC0".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA3\xDB".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA3\xE0".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA3\xFB".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA4\xF4".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA5\xF7".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA6\xB9".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA6\xC0".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA6\xD9".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA7\xC2".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA7\xD0".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA7\xF2".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xA8\xC1".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xCF\xD4".encode("utf-8", 'euc-jp') } - assert_raise(Encoding::ConversionUndefined) { "\xCF\xFE".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA3\xAF".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA3\xBA".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA3\xC0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA3\xDB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA3\xE0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA3\xFB".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA4\xF4".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA5\xF7".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA6\xB9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA6\xC0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA6\xD9".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA7\xC2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA7\xD0".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA7\xF2".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xA8\xC1".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xCF\xD4".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xCF\xFE".encode("utf-8", 'euc-jp') } check_both_ways("\u6A97", "\xDD\xA1", 'euc-jp') # 檗 check_both_ways("\u6BEF", "\xDD\xDF", 'euc-jp') # 毯 check_both_ways("\u9EBE", "\xDD\xE0", 'euc-jp') # 麾 @@ -432,7 +432,7 @@ class TestTranscode < Test::Unit::TestCase check_both_ways("\u71FC", "\xDF\xFE", 'euc-jp') # 燼 check_both_ways("\u71F9", "\xE0\xA1", 'euc-jp') # 燹 check_both_ways("\u73F1", "\xE0\xFE", 'euc-jp') # 珱 - assert_raise(Encoding::ConversionUndefined) { "\xF4\xA7".encode("utf-8", 'euc-jp') } + assert_raise(Encoding::ConversionUndefinedError) { "\xF4\xA7".encode("utf-8", 'euc-jp') } #check_both_ways("\u9ADC", "\xFC\xE3", 'euc-jp') # 髜 (IBM extended) check_both_ways("\u677E\u672C\u884C\u5F18", "\xBE\xBE\xCB\xDC\xB9\xD4\xB9\xB0", 'euc-jp') # 松本行弘 @@ -491,33 +491,33 @@ class TestTranscode < Test::Unit::TestCase end def test_eucjp_sjis_undef - assert_raise(Encoding::ConversionUndefined) { "\x8e\xe0".encode("Shift_JIS", "EUC-JP") } - assert_raise(Encoding::ConversionUndefined) { "\x8e\xfe".encode("Shift_JIS", "EUC-JP") } - assert_raise(Encoding::ConversionUndefined) { "\x8f\xa1\xa1".encode("Shift_JIS", "EUC-JP") } - assert_raise(Encoding::ConversionUndefined) { "\x8f\xa1\xfe".encode("Shift_JIS", "EUC-JP") } - assert_raise(Encoding::ConversionUndefined) { "\x8f\xfe\xa1".encode("Shift_JIS", "EUC-JP") } - assert_raise(Encoding::ConversionUndefined) { "\x8f\xfe\xfe".encode("Shift_JIS", "EUC-JP") } - - assert_raise(Encoding::ConversionUndefined) { "\xf0\x40".encode("EUC-JP", "Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\xf0\x7e".encode("EUC-JP", "Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\xf0\x80".encode("EUC-JP", "Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\xf0\xfc".encode("EUC-JP", "Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\xfc\x40".encode("EUC-JP", "Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\xfc\x7e".encode("EUC-JP", "Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\xfc\x80".encode("EUC-JP", "Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\xfc\xfc".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\x8e\xe0".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::ConversionUndefinedError) { "\x8e\xfe".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::ConversionUndefinedError) { "\x8f\xa1\xa1".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::ConversionUndefinedError) { "\x8f\xa1\xfe".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::ConversionUndefinedError) { "\x8f\xfe\xa1".encode("Shift_JIS", "EUC-JP") } + assert_raise(Encoding::ConversionUndefinedError) { "\x8f\xfe\xfe".encode("Shift_JIS", "EUC-JP") } + + assert_raise(Encoding::ConversionUndefinedError) { "\xf0\x40".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\xf0\x7e".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\xf0\x80".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\xf0\xfc".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\xfc\x40".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\xfc\x7e".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\xfc\x80".encode("EUC-JP", "Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\xfc\xfc".encode("EUC-JP", "Shift_JIS") } end def test_iso_2022_jp - assert_raise(Encoding::InvalidByteSequence) { "\x1b(A".encode("utf-8", "iso-2022-jp") } - assert_raise(Encoding::InvalidByteSequence) { "\x1b$(A".encode("utf-8", "iso-2022-jp") } - assert_raise(Encoding::InvalidByteSequence) { "\x1b$C".encode("utf-8", "iso-2022-jp") } - assert_raise(Encoding::InvalidByteSequence) { "\x0e".encode("utf-8", "iso-2022-jp") } - assert_raise(Encoding::InvalidByteSequence) { "\x80".encode("utf-8", "iso-2022-jp") } - assert_raise(Encoding::InvalidByteSequence) { "\x1b$(Dd!\x1b(B".encode("utf-8", "iso-2022-jp") } - assert_raise(Encoding::ConversionUndefined) { "\u9299".encode("iso-2022-jp") } - assert_raise(Encoding::ConversionUndefined) { "\uff71\uff72\uff73\uff74\uff75".encode("iso-2022-jp") } - assert_raise(Encoding::InvalidByteSequence) { "\x1b(I12345\x1b(B".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(A".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(A".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$C".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x0e".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x80".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b$(Dd!\x1b(B".encode("utf-8", "iso-2022-jp") } + assert_raise(Encoding::ConversionUndefinedError) { "\u9299".encode("iso-2022-jp") } + assert_raise(Encoding::ConversionUndefinedError) { "\uff71\uff72\uff73\uff74\uff75".encode("iso-2022-jp") } + assert_raise(Encoding::InvalidByteSequenceError) { "\x1b(I12345\x1b(B".encode("utf-8", "iso-2022-jp") } assert_equal("\xA1\xA1".force_encoding("euc-jp"), "\e$B!!\e(B".encode("EUC-JP", "ISO-2022-JP")) assert_equal("\e$B!!\e(B".force_encoding("ISO-2022-JP"), @@ -550,11 +550,11 @@ class TestTranscode < Test::Unit::TestCase assert_equal("\u005C", "\e(J\x5C\e(B".encode("UTF-8", "ISO-2022-JP")) assert_equal("\u005C", "\x5C".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) assert_equal("\u005C", "\e(J\x5C\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) - assert_raise(Encoding::ConversionUndefined) { "\u00A5".encode("Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\u00A5".encode("Windows-31J") } - assert_raise(Encoding::ConversionUndefined) { "\u00A5".encode("EUC-JP") } - assert_raise(Encoding::ConversionUndefined) { "\u00A5".encode("eucJP-ms") } - assert_raise(Encoding::ConversionUndefined) { "\u00A5".encode("CP51932") } + assert_raise(Encoding::ConversionUndefinedError) { "\u00A5".encode("Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\u00A5".encode("Windows-31J") } + assert_raise(Encoding::ConversionUndefinedError) { "\u00A5".encode("EUC-JP") } + assert_raise(Encoding::ConversionUndefinedError) { "\u00A5".encode("eucJP-ms") } + assert_raise(Encoding::ConversionUndefinedError) { "\u00A5".encode("CP51932") } # FULLWIDTH REVERSE SOLIDUS check_both_ways("\uFF3C", "\x81\x5F", "Shift_JIS") @@ -575,11 +575,17 @@ class TestTranscode < Test::Unit::TestCase assert_equal("\u007E", "\e(J\x7E\e(B".encode("UTF-8", "ISO-2022-JP")) assert_equal("\u007E", "\x7E".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) assert_equal("\u007E", "\e(J\x7E\e(B".encode("stateless-ISO-2022-JP", "ISO-2022-JP")) - assert_raise(Encoding::ConversionUndefined) { "\u203E".encode("Shift_JIS") } - assert_raise(Encoding::ConversionUndefined) { "\u203E".encode("Windows-31J") } - assert_raise(Encoding::ConversionUndefined) { "\u203E".encode("EUC-JP") } - assert_raise(Encoding::ConversionUndefined) { "\u203E".encode("eucJP-ms") } - assert_raise(Encoding::ConversionUndefined) { "\u203E".encode("CP51932") } + assert_raise(Encoding::ConversionUndefinedError) { "\u203E".encode("Shift_JIS") } + assert_raise(Encoding::ConversionUndefinedError) { "\u203E".encode("Windows-31J") } + assert_raise(Encoding::ConversionUndefinedError) { "\u203E".encode("EUC-JP") } + assert_raise(Encoding::ConversionUndefinedError) { "\u203E".encode("eucJP-ms") } + assert_raise(Encoding::ConversionUndefinedError) { "\u203E".encode("CP51932") } end + def test_nothing_changed + a = "James".force_encoding("US-ASCII") + b = a.encode("Shift_JIS") + assert_equal(Encoding::US_ASCII, a.encoding) + assert_equal(Encoding::Shift_JIS, b.encoding) + end end diff --git a/transcode.c b/transcode.c index 4d1107ddc4..b82729cb5b 100644 --- a/transcode.c +++ b/transcode.c @@ -14,9 +14,9 @@ #include "transcode_data.h" #include <ctype.h> -VALUE rb_eConversionUndefined; -VALUE rb_eInvalidByteSequence; -VALUE rb_eNoConverter; +VALUE rb_eConversionUndefinedError; +VALUE rb_eInvalidByteSequenceError; +VALUE rb_eNoConverterError; VALUE rb_cEncodingConverter; @@ -52,6 +52,7 @@ typedef struct rb_transcoding { unsigned int next_table; VALUE next_info; unsigned char next_byte; + unsigned int output_index; int recognized_len; /* already interpreted */ int readagain_len; /* not yet interpreted */ @@ -80,6 +81,10 @@ typedef struct rb_transcoding { ((tc)->transcoder->max_output <= sizeof((tc)->writebuf.ary) ? \ (tc)->writebuf.ary : \ (tc)->writebuf.ptr) +#define TRANSCODING_WRITEBUF_SIZE(tc) \ + ((tc)->transcoder->max_output <= sizeof((tc)->writebuf.ary) ? \ + sizeof((tc)->writebuf.ary) : \ + (tc)->transcoder->max_output) #define TRANSCODING_STATE_EMBED_MAX sizeof(union rb_transcoding_state_t) #define TRANSCODING_STATE(tc) \ ((tc)->transcoder->state_size <= sizeof((tc)->state) ? \ @@ -580,10 +585,10 @@ transcode_restartable0(const unsigned char **in_pos, unsigned char **out_pos, SUSPEND_OBUF(19); *out_p++ = getBT3(next_info); continue; case STR1: - next_byte = 0; /* index */ - while (next_byte < BYTE_ADDR(STR1_BYTEINDEX(next_info))[0]) { - SUSPEND_OBUF(28); *out_p++ = BYTE_ADDR(STR1_BYTEINDEX(next_info))[1+next_byte]; - next_byte++; + tc->output_index = 0; + while (tc->output_index < STR1_LENGTH(BYTE_ADDR(STR1_BYTEINDEX(next_info)))) { + SUSPEND_OBUF(28); *out_p++ = BYTE_ADDR(STR1_BYTEINDEX(next_info))[1+tc->output_index]; + tc->output_index++; } continue; case FUNii: @@ -600,9 +605,12 @@ transcode_restartable0(const unsigned char **in_pos, unsigned char **out_pos, case FUNio: SUSPEND_OBUF(13); if (tr->max_output <= out_stop - out_p) - out_p += (VALUE)(*tr->func_io)(TRANSCODING_STATE(tc), next_info, out_p); + out_p += tr->func_io(TRANSCODING_STATE(tc), + next_info, out_p, out_stop - out_p); else { - writebuf_len = (VALUE)(*tr->func_io)(TRANSCODING_STATE(tc), next_info, TRANSCODING_WRITEBUF(tc)); + writebuf_len = tr->func_io(TRANSCODING_STATE(tc), + next_info, + TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc)); writebuf_off = 0; while (writebuf_off < writebuf_len) { SUSPEND_OBUF(20); @@ -617,11 +625,15 @@ transcode_restartable0(const unsigned char **in_pos, unsigned char **out_pos, SUSPEND_OBUF(14); if (tr->max_output <= out_stop - out_p) { char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len); - out_p += (VALUE)(*tr->func_so)(TRANSCODING_STATE(tc), char_start, (size_t)char_len, out_p); + out_p += tr->func_so(TRANSCODING_STATE(tc), + char_start, (size_t)char_len, + out_p, out_stop - out_p); } else { char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len); - writebuf_len = (VALUE)(*tr->func_so)(TRANSCODING_STATE(tc), char_start, (size_t)char_len, TRANSCODING_WRITEBUF(tc)); + writebuf_len = tr->func_so(TRANSCODING_STATE(tc), + char_start, (size_t)char_len, + TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc)); writebuf_off = 0; while (writebuf_off < writebuf_len) { SUSPEND_OBUF(22); @@ -675,10 +687,12 @@ transcode_restartable0(const unsigned char **in_pos, unsigned char **out_pos, if (tr->finish_func) { SUSPEND_OBUF(4); if (tr->max_output <= out_stop - out_p) { - out_p += tr->finish_func(TRANSCODING_STATE(tc), out_p); + out_p += tr->finish_func(TRANSCODING_STATE(tc), + out_p, out_stop - out_p); } else { - writebuf_len = tr->finish_func(TRANSCODING_STATE(tc), TRANSCODING_WRITEBUF(tc)); + writebuf_len = tr->finish_func(TRANSCODING_STATE(tc), + TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc)); writebuf_off = 0; while (writebuf_off < writebuf_len) { SUSPEND_OBUF(23); @@ -1946,7 +1960,7 @@ rb_econv_open_exc(const char *sname, const char *dname, int ecflags) mesg = rb_str_new_cstr("code converter not found ("); econv_description(sname, dname, ecflags, mesg); rb_str_cat2(mesg, ")"); - exc = rb_exc_new3(rb_eNoConverter, mesg); + exc = rb_exc_new3(rb_eNoConverterError, mesg); return exc; } @@ -1983,7 +1997,7 @@ make_econv_exception(rb_econv_t *ec) ec->last_error.source_encoding); } - exc = rb_exc_new3(rb_eInvalidByteSequence, mesg); + exc = rb_exc_new3(rb_eInvalidByteSequenceError, mesg); rb_ivar_set(exc, rb_intern("error_bytes"), bytes); rb_ivar_set(exc, rb_intern("readagain_bytes"), bytes2); rb_ivar_set(exc, rb_intern("incomplete_input"), ec->last_error.result == econv_incomplete_input ? Qtrue : Qfalse); @@ -2009,7 +2023,7 @@ make_econv_exception(rb_econv_t *ec) StringValueCStr(dumped), ec->last_error.source_encoding, ec->last_error.destination_encoding); - exc = rb_exc_new3(rb_eConversionUndefined, mesg); + exc = rb_exc_new3(rb_eConversionUndefinedError, mesg); idx = rb_enc_find_index(ec->last_error.source_encoding); if (0 <= idx) rb_enc_associate_index(bytes, idx); @@ -2274,16 +2288,18 @@ econv_opts(VALUE opt) v = rb_hash_aref(opt, sym_xml); if (!NIL_P(v)) { - v = rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym"); if (v==sym_text) { ecflags |= ECONV_XML_TEXT_DECORATOR|ECONV_UNDEF_HEX_CHARREF; } else if (v==sym_attr) { ecflags |= ECONV_XML_ATTR_CONTENT_DECORATOR|ECONV_XML_ATTR_QUOTE_DECORATOR|ECONV_UNDEF_HEX_CHARREF; } - else { + else if (TYPE(v) == T_SYMBOL) { rb_raise(rb_eArgError, "unexpected value for xml option: %s", rb_id2name(SYM2ID(v))); } + else { + rb_raise(rb_eArgError, "unexpected value for xml option"); + } } v = rb_hash_aref(opt, sym_universal_newline); @@ -2570,7 +2586,12 @@ str_encode(int argc, VALUE *argv, VALUE str) int encidx = str_transcode(argc, argv, &newstr); if (encidx < 0) return rb_str_dup(str); - RBASIC(newstr)->klass = rb_obj_class(str); + if (newstr == str) { + newstr = rb_str_dup(str); + } + else { + RBASIC(newstr)->klass = rb_obj_class(str); + } return str_encode_associate(newstr, encidx); } @@ -3361,8 +3382,8 @@ econv_primitive_convert(int argc, VALUE *argv, VALUE self) * puts ec.finish.dump #=> "\e(B".force_encoding("ISO-2022-JP") * * If a conversion error occur, - * Encoding::ConversionUndefined or - * Encoding::InvalidByteSequence is raised. + * Encoding::ConversionUndefinedError or + * Encoding::InvalidByteSequenceError is raised. * */ static VALUE @@ -3614,7 +3635,7 @@ econv_insert_output(VALUE self, VALUE string) * some bytes are buffered to be converted later. * The latter bytes can be put back. * It can be observed by - * Encoding::InvalidByteSequence#readagain_bytes and + * Encoding::InvalidByteSequenceError#readagain_bytes and * Encoding::Converter#primitive_errinfo. * * ec = Encoding::Converter.new("utf-16le", "iso-8859-1") @@ -3663,14 +3684,14 @@ econv_putback(int argc, VALUE *argv, VALUE self) * It returns nil if the last conversion is not an error. * * "error" means that - * Encoding::InvalidByteSequence and Encoding::ConversionUndefined for + * Encoding::InvalidByteSequenceError and Encoding::ConversionUndefinedError for * Encoding::Converter#convert and * :invalid_byte_sequence, :incomplete_input and :undefined_conversion for * Encoding::Converter#primitive_convert. * * ec = Encoding::Converter.new("utf-8", "iso-8859-1") * p ec.primitive_convert(src="\xf1abcd", dst="") #=> :invalid_byte_sequence - * p ec.last_error #=> #<Encoding::InvalidByteSequence: "\xF1" followed by "a" on UTF-8> + * p ec.last_error #=> #<Encoding::InvalidByteSequenceError: "\xF1" followed by "a" on UTF-8> * p ec.primitive_convert(src, dst, nil, 1) #=> :destination_buffer_full * p ec.last_error #=> nil * @@ -3708,7 +3729,7 @@ econv_get_replacement(VALUE self) ret = make_replacement(ec); if (ret == -1) { - rb_raise(rb_eConversionUndefined, "replacement character setup failed"); + rb_raise(rb_eConversionUndefinedError, "replacement character setup failed"); } enc = rb_enc_find(ec->replacement_enc); @@ -3742,8 +3763,8 @@ econv_set_replacement(VALUE self, VALUE arg) rb_enc_name(enc)); if (ret == -1) { - /* xxx: rb_eInvalidByteSequence? */ - rb_raise(rb_eConversionUndefined, "replacement character setup failed"); + /* xxx: rb_eInvalidByteSequenceError? */ + rb_raise(rb_eConversionUndefinedError, "replacement character setup failed"); } return arg; @@ -3784,7 +3805,7 @@ ecerr_source_encoding_name(VALUE self) * ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP") # ISO-8859-1 -> UTF-8 -> EUC-JP * begin * ec.convert("\xa0") # NO-BREAK SPACE, which is available in UTF-8 but not in EUC-JP. - * rescue Encoding::ConversionUndefined + * rescue Encoding::ConversionUndefinedError * p $!.source_encoding #=> #<Encoding:UTF-8> * p $!.destination_encoding #=> #<Encoding:EUC-JP> * p $!.source_encoding_name #=> "UTF-8" @@ -3826,12 +3847,12 @@ ecerr_destination_encoding(VALUE self) * call-seq: * ecerr.error_char -> string * - * returns the one-character string which cause Encoding::ConversionUndefined. + * returns the one-character string which cause Encoding::ConversionUndefinedError. * * ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP") * begin * ec.convert("\xa0") - * rescue Encoding::ConversionUndefined + * rescue Encoding::ConversionUndefinedError * puts $!.error_char.dump #=> "\xC2\xA0" * p $!.error_char.encoding #=> #<Encoding:UTF-8> * end @@ -3847,13 +3868,13 @@ ecerr_error_char(VALUE self) * call-seq: * ecerr.error_bytes -> string * - * returns the discarded bytes when Encoding::InvalidByteSequence occur. + * returns the discarded bytes when Encoding::InvalidByteSequenceError occur. * * ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1") * begin * ec.convert("abc\xA1\xFFdef") - * rescue Encoding::InvalidByteSequence - * p $! #=> #<Encoding::InvalidByteSequence: "\xA1" followed by "\xFF" on EUC-JP> + * rescue Encoding::InvalidByteSequenceError + * p $! #=> #<Encoding::InvalidByteSequenceError: "\xA1" followed by "\xFF" on EUC-JP> * puts $!.error_bytes.dump #=> "\xA1" * puts $!.readagain_bytes.dump #=> "\xFF" * end @@ -3868,7 +3889,7 @@ ecerr_error_bytes(VALUE self) * call-seq: * ecerr.readagain_bytes -> string * - * returns the bytes to be read again when Encoding::InvalidByteSequence occur. + * returns the bytes to be read again when Encoding::InvalidByteSequenceError occur. */ static VALUE ecerr_readagain_bytes(VALUE self) @@ -3887,16 +3908,16 @@ ecerr_readagain_bytes(VALUE self) * * begin * ec.convert("abc\xA1z") - * rescue Encoding::InvalidByteSequence - * p $! #=> #<Encoding::InvalidByteSequence: "\xA1" followed by "z" on EUC-JP> + * rescue Encoding::InvalidByteSequenceError + * p $! #=> #<Encoding::InvalidByteSequenceError: "\xA1" followed by "z" on EUC-JP> * p $!.incomplete_input? #=> false * end * * begin * ec.convert("abc\xA1") * ec.finish - * rescue Encoding::InvalidByteSequence - * p $! #=> #<Encoding::InvalidByteSequence: incomplete "\xA1" on EUC-JP> + * rescue Encoding::InvalidByteSequenceError + * p $! #=> #<Encoding::InvalidByteSequenceError: incomplete "\xA1" on EUC-JP> * p $!.incomplete_input? #=> true * end */ @@ -3911,9 +3932,9 @@ extern void Init_newline(void); void Init_transcode(void) { - rb_eConversionUndefined = rb_define_class_under(rb_cEncoding, "ConversionUndefined", rb_eStandardError); - rb_eInvalidByteSequence = rb_define_class_under(rb_cEncoding, "InvalidByteSequence", rb_eStandardError); - rb_eNoConverter = rb_define_class_under(rb_cEncoding, "NoConverter", rb_eStandardError); + rb_eConversionUndefinedError = rb_define_class_under(rb_cEncoding, "ConversionUndefinedError", rb_eStandardError); + rb_eInvalidByteSequenceError = rb_define_class_under(rb_cEncoding, "InvalidByteSequenceError", rb_eStandardError); + rb_eNoConverterError = rb_define_class_under(rb_cEncoding, "NoConverterError", rb_eStandardError); transcoder_table = st_init_strcasetable(); @@ -3973,19 +3994,19 @@ Init_transcode(void) rb_define_const(rb_cEncodingConverter, "XML_ATTR_CONTENT_DECORATOR", INT2FIX(ECONV_XML_ATTR_CONTENT_DECORATOR)); rb_define_const(rb_cEncodingConverter, "XML_ATTR_QUOTE_DECORATOR", INT2FIX(ECONV_XML_ATTR_QUOTE_DECORATOR)); - rb_define_method(rb_eConversionUndefined, "source_encoding_name", ecerr_source_encoding_name, 0); - rb_define_method(rb_eConversionUndefined, "destination_encoding_name", ecerr_destination_encoding_name, 0); - rb_define_method(rb_eConversionUndefined, "source_encoding", ecerr_source_encoding, 0); - rb_define_method(rb_eConversionUndefined, "destination_encoding", ecerr_destination_encoding, 0); - rb_define_method(rb_eConversionUndefined, "error_char", ecerr_error_char, 0); - - rb_define_method(rb_eInvalidByteSequence, "source_encoding_name", ecerr_source_encoding_name, 0); - rb_define_method(rb_eInvalidByteSequence, "destination_encoding_name", ecerr_destination_encoding_name, 0); - rb_define_method(rb_eInvalidByteSequence, "source_encoding", ecerr_source_encoding, 0); - rb_define_method(rb_eInvalidByteSequence, "destination_encoding", ecerr_destination_encoding, 0); - rb_define_method(rb_eInvalidByteSequence, "error_bytes", ecerr_error_bytes, 0); - rb_define_method(rb_eInvalidByteSequence, "readagain_bytes", ecerr_readagain_bytes, 0); - rb_define_method(rb_eInvalidByteSequence, "incomplete_input?", ecerr_incomplete_input, 0); + rb_define_method(rb_eConversionUndefinedError, "source_encoding_name", ecerr_source_encoding_name, 0); + rb_define_method(rb_eConversionUndefinedError, "destination_encoding_name", ecerr_destination_encoding_name, 0); + rb_define_method(rb_eConversionUndefinedError, "source_encoding", ecerr_source_encoding, 0); + rb_define_method(rb_eConversionUndefinedError, "destination_encoding", ecerr_destination_encoding, 0); + rb_define_method(rb_eConversionUndefinedError, "error_char", ecerr_error_char, 0); + + rb_define_method(rb_eInvalidByteSequenceError, "source_encoding_name", ecerr_source_encoding_name, 0); + rb_define_method(rb_eInvalidByteSequenceError, "destination_encoding_name", ecerr_destination_encoding_name, 0); + rb_define_method(rb_eInvalidByteSequenceError, "source_encoding", ecerr_source_encoding, 0); + rb_define_method(rb_eInvalidByteSequenceError, "destination_encoding", ecerr_destination_encoding, 0); + rb_define_method(rb_eInvalidByteSequenceError, "error_bytes", ecerr_error_bytes, 0); + rb_define_method(rb_eInvalidByteSequenceError, "readagain_bytes", ecerr_readagain_bytes, 0); + rb_define_method(rb_eInvalidByteSequenceError, "incomplete_input?", ecerr_incomplete_input, 0); Init_newline(); } diff --git a/transcode_data.h b/transcode_data.h index 98f48a4de9..497eb3c51b 100644 --- a/transcode_data.h +++ b/transcode_data.h @@ -34,10 +34,12 @@ #define FUNsi (PType 0x0D) /* function from start to info */ #define FUNio (PType 0x0E) /* function from info to output */ #define FUNso (PType 0x0F) /* function from start to output */ -#define STR1 (PType 0x11) /* string up to 255 bytes: 1byte length + content */ +#define STR1 (PType 0x11) /* string 4 <= len <= 259 bytes: 1byte length + content */ +#define STR1_LENGTH(byte_addr) (*(byte_addr) + 4) #define STR1_BYTEINDEX(w) ((w) >> 6) #define makeSTR1(bi) (((bi) << 6) | STR1) +#define makeSTR1LEN(len) ((len)-4) #define o1(b1) (PType((((unsigned char)(b1))<<8)|ONEbt)) #define o2(b1,b2) (PType((((unsigned char)(b1))<<8)|(((unsigned char)(b2))<<16)|TWObt)) @@ -84,11 +86,11 @@ struct rb_transcoder { int (*state_fini_func)(void*); /* ret==0:success ret!=0:failure(errno) */ VALUE (*func_ii)(void*, VALUE); /* info -> info */ VALUE (*func_si)(void*, const unsigned char*, size_t); /* start -> info */ - int (*func_io)(void*, VALUE, const unsigned char*); /* info -> output */ - int (*func_so)(void*, const unsigned char*, size_t, unsigned char*); /* start -> output */ - int (*finish_func)(void*, unsigned char*); /* -> output */ - int (*resetsize_func)(void*); /* -> len */ - int (*resetstate_func)(void*, unsigned char*); /* -> output */ + ssize_t (*func_io)(void*, VALUE, const unsigned char*, size_t); /* info -> output */ + ssize_t (*func_so)(void*, const unsigned char*, size_t, unsigned char*, size_t); /* start -> output */ + ssize_t (*finish_func)(void*, unsigned char*, size_t); /* -> output */ + ssize_t (*resetsize_func)(void*); /* -> len */ + ssize_t (*resetstate_func)(void*, unsigned char*, size_t); /* -> output */ }; void rb_declare_transcoder(const char *enc1, const char *enc2, const char *lib); @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.9.0" -#define RUBY_RELEASE_DATE "2008-09-14" +#define RUBY_RELEASE_DATE "2008-09-21" #define RUBY_VERSION_CODE 190 -#define RUBY_RELEASE_CODE 20080914 +#define RUBY_RELEASE_CODE 20080921 #define RUBY_PATCHLEVEL 0 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_YEAR 2008 #define RUBY_RELEASE_MONTH 9 -#define RUBY_RELEASE_DAY 14 +#define RUBY_RELEASE_DAY 21 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; @@ -1820,7 +1820,7 @@ Init_VM(void) rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3); rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1); rb_obj_freeze(fcore); - rb_global_variable(&rb_mRubyVMFrozenCore); + rb_gc_register_mark_object(fcore); rb_mRubyVMFrozenCore = fcore; /* ::VM::Env */ @@ -1901,7 +1901,7 @@ Init_VM(void) vm->living_threads = st_init_numtable(); st_insert(vm->living_threads, th_self, (st_data_t) th->thread_id); - rb_register_mark_object(iseqval); + rb_gc_register_mark_object(iseqval); GetISeqPtr(iseqval, iseq); th->cfp->iseq = iseq; th->cfp->pc = iseq->iseq_encoded; @@ -1960,6 +1960,9 @@ Init_top_self(void) vm->top_self = rb_obj_alloc(rb_cObject); rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0); + + /* initialize mark object array */ + vm->mark_object_ary = rb_ary_new(); } VALUE * |