[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]