ruby-changes:18097
From: nobu <ko1@a...>
Date: Tue, 7 Dec 2010 22:05:33 +0900 (JST)
Subject: [ruby-changes:18097] Ruby:r30118 (trunk): * transcode.c (transcode_loop): call default handler of the given
nobu 2010-12-07 22:05:26 +0900 (Tue, 07 Dec 2010) New Revision: 30118 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30118 Log: * transcode.c (transcode_loop): call default handler of the given hash, method, proc or [] method as fallback. [ruby-dev:42692] Modified files: trunk/ChangeLog trunk/include/ruby/intern.h trunk/proc.c trunk/test/ruby/test_transcode.rb trunk/transcode.c Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (revision 30117) +++ include/ruby/intern.h (revision 30118) @@ -340,6 +340,7 @@ VALUE rb_proc_lambda_p(VALUE); VALUE rb_binding_new(void); VALUE rb_obj_method(VALUE, VALUE); +VALUE rb_obj_is_method(VALUE); VALUE rb_method_call(int, VALUE*, VALUE); int rb_mod_method_arity(VALUE, ID); int rb_obj_method_arity(VALUE, ID); Index: ChangeLog =================================================================== --- ChangeLog (revision 30117) +++ ChangeLog (revision 30118) @@ -1,3 +1,8 @@ +Tue Dec 7 22:05:25 2010 Nobuyoshi Nakada <nobu@r...> + + * transcode.c (transcode_loop): call default handler of the given + hash, method, proc or [] method as fallback. [ruby-dev:42692] + Tue Dec 7 21:59:37 2010 Kouhei Sutou <kou@c...> * lib/rexml/light/node.rb: remove circular require. Index: proc.c =================================================================== --- proc.c (revision 30117) +++ proc.c (revision 30118) @@ -28,7 +28,6 @@ static VALUE bmcall(VALUE, VALUE); static int method_arity(VALUE); -static int rb_obj_is_method(VALUE m); rb_iseq_t *rb_method_get_iseq(VALUE method); /* Proc */ @@ -893,10 +892,15 @@ }, }; -static inline int +VALUE rb_obj_is_method(VALUE m) { - return rb_typeddata_is_kind_of(m, &method_data_type); + if (rb_typeddata_is_kind_of(m, &method_data_type)) { + return Qtrue; + } + else { + return Qfalse; + } } static VALUE Index: test/ruby/test_transcode.rb =================================================================== --- test/ruby/test_transcode.rb (revision 30117) +++ test/ruby/test_transcode.rb (revision 30118) @@ -1947,4 +1947,21 @@ assert_equal("[ISU]", "\u{1F4BA}".encode("SJIS-KDDI", fallback: {"\u{1F4BA}" => "[ISU]"})) end + + def test_fallback_hash_default + fallback = Hash.new {|h, x| "U+%.4X" % x.unpack("U")} + assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback)) + end + + def test_fallback_proc + fallback = proc {|x| "U+%.4X" % x.unpack("U")} + assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback)) + end + + def test_fallback_method + def (fallback = "U+%.4X").escape(x) + self % x.unpack("U") + end + assert_equal("U+3042", "\u{3042}".encode("US-ASCII", fallback: fallback.method(:escape))) + end end Index: transcode.c =================================================================== --- transcode.c (revision 30117) +++ transcode.c (revision 30118) @@ -21,7 +21,7 @@ VALUE rb_cEncodingConverter; -static VALUE sym_invalid, sym_undef, sym_replace, sym_fallback; +static VALUE sym_invalid, sym_undef, sym_replace, sym_fallback, sym_aref; static VALUE sym_xml, sym_text, sym_attr; static VALUE sym_universal_newline; static VALUE sym_crlf_newline; @@ -2240,6 +2240,26 @@ } #if 1 +#define hash_fallback rb_hash_aref + +static VALUE +proc_fallback(VALUE fallback, VALUE c) +{ + return rb_proc_call(fallback, rb_ary_new4(1, &c)); +} + +static VALUE +method_fallback(VALUE fallback, VALUE c) +{ + return rb_method_call(1, &c, fallback); +} + +static VALUE +aref_fallback(VALUE fallback, VALUE c) +{ + return rb_funcall3(fallback, sym_aref, 1, &c); +} + static void transcode_loop(const unsigned char **in_pos, unsigned char **out_pos, const unsigned char *in_stop, unsigned char *out_stop, @@ -2257,13 +2277,27 @@ int max_output; VALUE exc; VALUE fallback = Qnil; + VALUE (*fallback_func)(VALUE, VALUE) = 0; ec = rb_econv_open_opts(src_encoding, dst_encoding, ecflags, ecopts); if (!ec) rb_exc_raise(rb_econv_open_exc(src_encoding, dst_encoding, ecflags)); - if (!NIL_P(ecopts) && TYPE(ecopts) == T_HASH) + if (!NIL_P(ecopts) && TYPE(ecopts) == T_HASH) { fallback = rb_hash_aref(ecopts, sym_fallback); + if (RB_TYPE_P(fallback, T_HASH)) { + fallback_func = hash_fallback; + } + else if (rb_obj_is_proc(fallback)) { + fallback_func = proc_fallback; + } + else if (rb_obj_is_method(fallback)) { + fallback_func = method_fallback; + } + else { + fallback_func = aref_fallback; + } + } last_tc = ec->last_tc; max_output = last_tc ? last_tc->transcoder->max_output : 1; @@ -2275,8 +2309,8 @@ (const char *)ec->last_error.error_bytes_start, ec->last_error.error_bytes_len, rb_enc_find(ec->last_error.source_encoding)); - rep = rb_hash_lookup2(fallback, rep, Qundef); - if (rep != Qundef) { + rep = (*fallback_func)(fallback, rep); + if (rep != Qundef && !NIL_P(rep)) { StringValue(rep); ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(rep), RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep))); @@ -2479,8 +2513,10 @@ v = rb_hash_aref(opthash, sym_fallback); if (!NIL_P(v)) { - v = rb_convert_type(v, T_HASH, "Hash", "to_hash"); - if (!NIL_P(v)) { + VALUE h = rb_check_hash_type(v); + if (NIL_P(h) + ? (rb_obj_is_proc(v) || rb_obj_is_method(v) || rb_respond_to(v, sym_aref)) + : (v = h, 1)) { if (NIL_P(newhash)) newhash = rb_hash_new(); rb_hash_aset(newhash, sym_fallback, v); @@ -4258,6 +4294,7 @@ sym_undef = ID2SYM(rb_intern("undef")); sym_replace = ID2SYM(rb_intern("replace")); sym_fallback = ID2SYM(rb_intern("fallback")); + sym_aref = ID2SYM(rb_intern("[]")); sym_xml = ID2SYM(rb_intern("xml")); sym_text = ID2SYM(rb_intern("text")); sym_attr = ID2SYM(rb_intern("attr")); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/