psych icon indicating copy to clipboard operation
psych copied to clipboard

Need port to Java of fix for excessive quoting fix for line width -1

Open headius opened this issue 9 years ago • 0 comments

See #254. This code was not ported to the Java stuff.

Here's my attempt at a patch, but it causes out-of-memory errors for some reason (i.e. it's broken in a non-obvious way I can't fix right now):

diff --git a/ext/java/PsychEmitter.java b/ext/java/PsychEmitter.java
index d9f3231..c0be111 100644
--- a/ext/java/PsychEmitter.java
+++ b/ext/java/PsychEmitter.java
@@ -29,23 +29,36 @@ package org.jruby.ext.psych;

 import java.io.IOException;
 import java.io.OutputStreamWriter;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channel;
+import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Map;

 import org.jcodings.Encoding;
+import org.jcodings.specific.UTF8Encoding;
 import org.jruby.Ruby;
 import org.jruby.RubyArray;
 import org.jruby.RubyClass;
+import org.jruby.RubyEncoding;
 import org.jruby.RubyFixnum;
+import org.jruby.RubyIO;
 import org.jruby.RubyModule;
 import org.jruby.RubyObject;
 import org.jruby.RubyString;
 import org.jruby.anno.JRubyMethod;
+import org.jruby.exceptions.RaiseException;
+import org.jruby.java.addons.IOJavaAddons;
 import org.jruby.runtime.ObjectAllocator;
 import org.jruby.runtime.ThreadContext;
 import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.runtime.callsite.NormalCachingCallSite;
+import org.jruby.util.ByteList;
 import org.jruby.util.IOOutputStream;
+import org.jruby.util.StringSupport;
+import org.jruby.util.io.ChannelHelper;
 import org.yaml.snakeyaml.DumperOptions;
 import org.yaml.snakeyaml.emitter.Emitter;
 import org.yaml.snakeyaml.emitter.EmitterException;
@@ -317,13 +330,45 @@ public class PsychEmitter extends RubyObject {
         }
     }

-    private void initEmitter(ThreadContext context, IRubyObject _encoding) {
+    private void initEmitter(final ThreadContext context, IRubyObject _encoding) {
         if (emitter != null) throw context.runtime.newRuntimeError("already initialized emitter");

-        Encoding encoding = PsychLibrary.YAMLEncoding.values()[(int)_encoding.convertToInteger().getLongValue()].encoding;
-        Charset charset = context.runtime.getEncodingService().charsetForEncoding(encoding);
+        WritableByteChannel out = new WritableByteChannel() {
+            NormalCachingCallSite adapter = new NormalCachingCallSite("write");
+            RubyString tmpStr;
+            ByteList tmpBL;
+            @Override
+            public synchronized int write(ByteBuffer src) throws IOException {
+                if (tmpStr == null) {
+                    tmpBL = new ByteList(src.array(), src.position(), src.remaining(), UTF8Encoding.INSTANCE, false);
+                    tmpStr = RubyString.newString(context.runtime, tmpBL, StringSupport.CR_UNKNOWN);
+                } else {
+                    tmpBL.setUnsafeBytes(src.array());
+                    tmpBL.setBegin(src.position());
+                    tmpBL.setRealSize(src.remaining());
+                }
+                try {
+                    return adapter.call(context, PsychEmitter.this, io, tmpStr).convertToInteger().getIntValue();
+                } catch (RaiseException re) {
+                    throw new IOException("error in dynamic write: " + re.getMessage(), re);
+                }
+            }

-        emitter = new Emitter(new OutputStreamWriter(new IOOutputStream(io, encoding), charset), options);
+            @Override
+            public boolean isOpen() {
+                return !io.callMethod(context, "closed?").isTrue();
+            }
+
+            @Override
+            public void close() throws IOException {
+                try {
+                    io.callMethod(context, "close");
+                } catch (RaiseException re) {
+                    throw new IOException("error in dynamic close: " + re.getMessage(), re);
+                }
+            }
+        };
+        emitter = new Emitter(new OutputStreamWriter(Channels.newOutputStream(out), RubyEncoding.UTF8), options);
     }

     Emitter emitter;

headius avatar Feb 22 '16 17:02 headius