summaryrefslogtreecommitdiff
path: root/ext/java/org/jruby/ext/psych/PsychEmitter.java
diff options
context:
space:
mode:
Diffstat (limited to 'ext/java/org/jruby/ext/psych/PsychEmitter.java')
-rw-r--r--ext/java/org/jruby/ext/psych/PsychEmitter.java214
1 files changed, 112 insertions, 102 deletions
diff --git a/ext/java/org/jruby/ext/psych/PsychEmitter.java b/ext/java/org/jruby/ext/psych/PsychEmitter.java
index f2e6498..4df7989 100644
--- a/ext/java/org/jruby/ext/psych/PsychEmitter.java
+++ b/ext/java/org/jruby/ext/psych/PsychEmitter.java
@@ -27,48 +27,54 @@
***** END LICENSE BLOCK *****/
package org.jruby.ext.psych;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-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.RubyBoolean;
import org.jruby.RubyClass;
-import org.jruby.RubyFixnum;
+import org.jruby.RubyEncoding;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.RubyString;
import org.jruby.anno.JRubyMethod;
-import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.util.ByteList;
import org.jruby.util.IOOutputStream;
import org.jruby.util.TypeConverter;
import org.jruby.util.io.EncodingUtils;
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.emitter.Emitter;
-import org.yaml.snakeyaml.emitter.EmitterException;
-import org.yaml.snakeyaml.error.Mark;
-import org.yaml.snakeyaml.events.AliasEvent;
-import org.yaml.snakeyaml.events.DocumentEndEvent;
-import org.yaml.snakeyaml.events.DocumentStartEvent;
-import org.yaml.snakeyaml.events.Event;
-import org.yaml.snakeyaml.events.ImplicitTuple;
-import org.yaml.snakeyaml.events.MappingEndEvent;
-import org.yaml.snakeyaml.events.MappingStartEvent;
-import org.yaml.snakeyaml.events.ScalarEvent;
-import org.yaml.snakeyaml.events.SequenceEndEvent;
-import org.yaml.snakeyaml.events.SequenceStartEvent;
-import org.yaml.snakeyaml.events.StreamEndEvent;
-import org.yaml.snakeyaml.events.StreamStartEvent;
-
-import static org.jruby.runtime.Visibility.*;
+import org.snakeyaml.engine.v2.api.DumpSettings;
+import org.snakeyaml.engine.v2.api.DumpSettingsBuilder;
+import org.snakeyaml.engine.v2.api.StreamDataWriter;
+import org.snakeyaml.engine.v2.api.YamlOutputStreamWriter;
+import org.snakeyaml.engine.v2.common.Anchor;
+import org.snakeyaml.engine.v2.common.FlowStyle;
+import org.snakeyaml.engine.v2.common.ScalarStyle;
+import org.snakeyaml.engine.v2.common.SpecVersion;
+import org.snakeyaml.engine.v2.emitter.Emitter;
+import org.snakeyaml.engine.v2.events.AliasEvent;
+import org.snakeyaml.engine.v2.events.DocumentEndEvent;
+import org.snakeyaml.engine.v2.events.DocumentStartEvent;
+import org.snakeyaml.engine.v2.events.Event;
+import org.snakeyaml.engine.v2.events.ImplicitTuple;
+import org.snakeyaml.engine.v2.events.MappingEndEvent;
+import org.snakeyaml.engine.v2.events.MappingStartEvent;
+import org.snakeyaml.engine.v2.events.ScalarEvent;
+import org.snakeyaml.engine.v2.events.SequenceEndEvent;
+import org.snakeyaml.engine.v2.events.SequenceStartEvent;
+import org.snakeyaml.engine.v2.events.StreamEndEvent;
+import org.snakeyaml.engine.v2.events.StreamStartEvent;
+import org.snakeyaml.engine.v2.exceptions.EmitterException;
+import org.snakeyaml.engine.v2.exceptions.Mark;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.jruby.runtime.Visibility.PRIVATE;
public class PsychEmitter extends RubyObject {
public static void initPsychEmitter(Ruby runtime, RubyModule psych) {
@@ -84,8 +90,7 @@ public class PsychEmitter extends RubyObject {
@JRubyMethod(visibility = PRIVATE)
public IRubyObject initialize(ThreadContext context, IRubyObject io) {
- options = new DumperOptions();
- options.setIndent(2);
+ dumpSettingsBuilder.setIndent(2);
this.io = io;
@@ -98,10 +103,8 @@ public class PsychEmitter extends RubyObject {
IRubyObject canonical = rbOptions.callMethod(context, "canonical");
IRubyObject level = rbOptions.callMethod(context, "indentation");
- options = new DumperOptions();
-
- options.setCanonical(canonical.isTrue());
- options.setIndent((int)level.convertToInteger().getLongValue());
+ dumpSettingsBuilder.setCanonical(canonical.isTrue());
+ dumpSettingsBuilder.setIndent((int)level.convertToInteger().getLongValue());
line_width_set(context, width);
this.io = io;
@@ -115,17 +118,14 @@ public class PsychEmitter extends RubyObject {
initEmitter(context, encoding);
- StreamStartEvent event = new StreamStartEvent(NULL_MARK, NULL_MARK);
-
- emit(context, event);
+ emit(context, NULL_STREAM_START_EVENT);
return this;
}
@JRubyMethod
public IRubyObject end_stream(ThreadContext context) {
- StreamEndEvent event = new StreamEndEvent(NULL_MARK, NULL_MARK);
- emit(context, event);
+ emit(context, NULL_STREAM_START_EVENT);
return this;
}
@@ -133,30 +133,28 @@ public class PsychEmitter extends RubyObject {
public IRubyObject start_document(ThreadContext context, IRubyObject _version, IRubyObject tags, IRubyObject implicit) {
Ruby runtime = context.runtime;
- DumperOptions.Version version = null;
boolean implicitBool = implicit.isTrue();
- Map<String, String> tagsMap = null;
RubyClass arrayClass = runtime.getArray();
TypeConverter.checkType(context, _version, arrayClass);
RubyArray versionAry = _version.convertToArray();
+ Optional<SpecVersion> specVersion;
if (versionAry.size() == 2) {
int versionInt0 = versionAry.eltInternal(0).convertToInteger().getIntValue();
int versionInt1 = versionAry.eltInternal(1).convertToInteger().getIntValue();
- if (versionInt0 == 1) {
- if (versionInt1 == 0) {
- version = DumperOptions.Version.V1_0;
- } else if (versionInt1 == 1) {
- version = DumperOptions.Version.V1_1;
- }
- }
- if (version == null) {
+ if (versionInt0 != 1) {
throw runtime.newArgumentError("invalid YAML version: " + versionAry);
}
+
+ specVersion = Optional.of(new SpecVersion(versionInt0, versionInt1));
+ } else {
+ specVersion = Optional.empty();
}
+ Map<String, String> tagsMap = new HashMap<>();
+
if (!tags.isNil()) {
TypeConverter.checkType(context, tags, arrayClass);
@@ -177,14 +175,14 @@ public class PsychEmitter extends RubyObject {
}
}
- DocumentStartEvent event = new DocumentStartEvent(NULL_MARK, NULL_MARK, !implicitBool, version, tagsMap);
+ DocumentStartEvent event = new DocumentStartEvent(!implicitBool, specVersion, tagsMap, NULL_MARK, NULL_MARK);
emit(context, event);
return this;
}
@JRubyMethod
public IRubyObject end_document(ThreadContext context, IRubyObject implicit) {
- DocumentEndEvent event = new DocumentEndEvent(NULL_MARK, NULL_MARK, !implicit.isTrue());
+ DocumentEndEvent event = new DocumentEndEvent(!implicit.isTrue(), NULL_MARK, NULL_MARK);
emit(context, event);
return this;
}
@@ -206,17 +204,17 @@ public class PsychEmitter extends RubyObject {
valueStr = EncodingUtils.strConvEnc(context, valueStr, valueStr.getEncoding(), UTF8Encoding.INSTANCE);
- RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
- RubyString tagStr = exportToUTF8(context, tag, stringClass);
+ String anchorStr = exportToUTF8(context, anchor, stringClass);
+ String tagStr = exportToUTF8(context, tag, stringClass);
ScalarEvent event = new ScalarEvent(
- anchorStr == null ? null : anchorStr.asJavaString(),
- tagStr == null ? null : tagStr.asJavaString(),
+ Optional.ofNullable(anchorStr == null ? null : new Anchor(anchorStr)),
+ Optional.ofNullable(tagStr),
new ImplicitTuple(plain.isTrue(), quoted.isTrue()),
valueStr.asJavaString(),
+ SCALAR_STYLES[style.convertToInteger().getIntValue()],
NULL_MARK,
- NULL_MARK,
- SCALAR_STYLES[style.convertToInteger().getIntValue()]);
+ NULL_MARK);
emit(context, event);
@@ -232,16 +230,16 @@ public class PsychEmitter extends RubyObject {
RubyClass stringClass = context.runtime.getString();
- RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
- RubyString tagStr = exportToUTF8(context, tag, stringClass);
+ String anchorStr = exportToUTF8(context, anchor, stringClass);
+ String tagStr = exportToUTF8(context, tag, stringClass);
SequenceStartEvent event = new SequenceStartEvent(
- anchorStr == null ? null : anchorStr.asJavaString(),
- tagStr == null ? null : tagStr.asJavaString(),
+ Optional.ofNullable(anchorStr == null ? null : new Anchor(anchorStr)),
+ Optional.ofNullable(tagStr),
implicit.isTrue(),
+ FLOW_STYLES[style.convertToInteger().getIntValue()],
NULL_MARK,
- NULL_MARK,
- FLOW_STYLES[style.convertToInteger().getIntValue()]);
+ NULL_MARK);
emit(context, event);
return this;
}
@@ -262,16 +260,16 @@ public class PsychEmitter extends RubyObject {
RubyClass stringClass = context.runtime.getString();
- RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
- RubyString tagStr = exportToUTF8(context, tag, stringClass);
+ String anchorStr = exportToUTF8(context, anchor, stringClass);
+ String tagStr = exportToUTF8(context, tag, stringClass);
MappingStartEvent event = new MappingStartEvent(
- anchorStr == null ? null : anchorStr.asJavaString(),
- tagStr == null ? null : tagStr.asJavaString(),
+ Optional.ofNullable(anchorStr == null ? null : new Anchor(anchorStr)),
+ Optional.ofNullable(tagStr),
implicit.isTrue(),
+ FLOW_STYLES[style.convertToInteger().getIntValue()],
NULL_MARK,
- NULL_MARK,
- FLOW_STYLES[style.convertToInteger().getIntValue()]);
+ NULL_MARK);
emit(context, event);
@@ -289,9 +287,9 @@ public class PsychEmitter extends RubyObject {
public IRubyObject alias(ThreadContext context, IRubyObject anchor) {
RubyClass stringClass = context.runtime.getString();
- RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
+ String anchorStr = exportToUTF8(context, anchor, stringClass);
- AliasEvent event = new AliasEvent(anchorStr.asJavaString(), NULL_MARK, NULL_MARK);
+ AliasEvent event = new AliasEvent(Optional.of(new Anchor(anchorStr)), NULL_MARK, NULL_MARK);
emit(context, event);
return this;
}
@@ -299,40 +297,40 @@ public class PsychEmitter extends RubyObject {
@JRubyMethod(name = "canonical=")
public IRubyObject canonical_set(ThreadContext context, IRubyObject canonical) {
// TODO: unclear if this affects a running emitter
- options.setCanonical(canonical.isTrue());
+ dumpSettingsBuilder.setCanonical(canonical.isTrue());
return canonical;
}
@JRubyMethod
public IRubyObject canonical(ThreadContext context) {
// TODO: unclear if this affects a running emitter
- return RubyBoolean.newBoolean(context, options.isCanonical());
+ return RubyBoolean.newBoolean(context, buildDumpSettings().isCanonical());
}
@JRubyMethod(name = "indentation=")
public IRubyObject indentation_set(ThreadContext context, IRubyObject level) {
// TODO: unclear if this affects a running emitter
- options.setIndent((int)level.convertToInteger().getLongValue());
+ dumpSettingsBuilder.setIndent(level.convertToInteger().getIntValue());
return level;
}
@JRubyMethod
public IRubyObject indentation(ThreadContext context) {
// TODO: unclear if this affects a running emitter
- return context.runtime.newFixnum(options.getIndent());
+ return context.runtime.newFixnum(buildDumpSettings().getIndent());
}
@JRubyMethod(name = "line_width=")
public IRubyObject line_width_set(ThreadContext context, IRubyObject width) {
- int newWidth = (int)width.convertToInteger().getLongValue();
+ int newWidth = width.convertToInteger().getIntValue();
if (newWidth <= 0) newWidth = Integer.MAX_VALUE;
- options.setWidth(newWidth);
+ dumpSettingsBuilder.setWidth(newWidth);
return width;
}
@JRubyMethod
public IRubyObject line_width(ThreadContext context) {
- return context.runtime.newFixnum(options.getWidth());
+ return context.runtime.newFixnum(buildDumpSettings().getWidth());
}
private void emit(ThreadContext context, Event event) {
@@ -343,8 +341,6 @@ public class PsychEmitter extends RubyObject {
// flush writer after each emit
writer.flush();
- } catch (IOException ioe) {
- throw context.runtime.newIOErrorFromException(ioe);
} catch (EmitterException ee) {
throw context.runtime.newRuntimeError(ee.toString());
}
@@ -356,41 +352,55 @@ public class PsychEmitter extends RubyObject {
Encoding encoding = PsychLibrary.YAMLEncoding.values()[(int)_encoding.convertToInteger().getLongValue()].encoding;
Charset charset = context.runtime.getEncodingService().charsetForEncoding(encoding);
- writer = new OutputStreamWriter(new IOOutputStream(io, encoding), charset);
- emitter = new Emitter(writer, options);
+ writer = new YamlOutputStreamWriter(new IOOutputStream(io, encoding), charset) {
+ @Override
+ public void processIOException(IOException ioe) {
+ throw context.runtime.newIOErrorFromException(ioe);
+ }
+ };
+ emitter = new Emitter(buildDumpSettings(), writer);
+ }
+
+ private DumpSettings buildDumpSettings() {
+ return dumpSettingsBuilder.build();
}
- private RubyString exportToUTF8(ThreadContext context, IRubyObject tag, RubyClass stringClass) {
- RubyString tagStr = null;
- if (!tag.isNil()) {
- TypeConverter.checkType(context, tag, stringClass);
- tagStr = (RubyString) tag;
- tagStr = EncodingUtils.strConvEnc(context, tagStr, tagStr.getEncoding(), UTF8Encoding.INSTANCE);
+ private String exportToUTF8(ThreadContext context, IRubyObject maybeString, RubyClass stringClass) {
+ if (maybeString.isNil()) {
+ return null;
}
- return tagStr;
+
+ RubyString string;
+
+ TypeConverter.checkType(context, maybeString, stringClass);
+ string = (RubyString) maybeString;
+ ByteList bytes = string.getByteList();
+
+ return RubyEncoding.decodeUTF8(bytes.unsafeBytes(), bytes.begin(), bytes.realSize());
}
Emitter emitter;
- Writer writer;
- DumperOptions options = new DumperOptions();
+ StreamDataWriter writer;
+ final DumpSettingsBuilder dumpSettingsBuilder = DumpSettings.builder();
IRubyObject io;
- private static final Mark NULL_MARK = new Mark("", 0, 0, 0, new int[0], 0);
+ private static final Optional<Mark> NULL_MARK = Optional.empty();
+ private static final StreamStartEvent NULL_STREAM_START_EVENT = new StreamStartEvent(NULL_MARK, NULL_MARK);
// Map style constants from Psych values (ANY = 0 ... FOLDED = 5)
// to SnakeYaml values; see psych/nodes/scalar.rb.
- private static final DumperOptions.ScalarStyle[] SCALAR_STYLES = {
- DumperOptions.ScalarStyle.PLAIN, // ANY
- DumperOptions.ScalarStyle.PLAIN,
- DumperOptions.ScalarStyle.SINGLE_QUOTED,
- DumperOptions.ScalarStyle.DOUBLE_QUOTED,
- DumperOptions.ScalarStyle.LITERAL,
- DumperOptions.ScalarStyle.FOLDED
+ private static final ScalarStyle[] SCALAR_STYLES = {
+ ScalarStyle.PLAIN, // ANY
+ ScalarStyle.PLAIN,
+ ScalarStyle.SINGLE_QUOTED,
+ ScalarStyle.DOUBLE_QUOTED,
+ ScalarStyle.LITERAL,
+ ScalarStyle.FOLDED
};
- private static final DumperOptions.FlowStyle[] FLOW_STYLES = {
- DumperOptions.FlowStyle.AUTO,
- DumperOptions.FlowStyle.BLOCK,
- DumperOptions.FlowStyle.FLOW
+ private static final FlowStyle[] FLOW_STYLES = {
+ FlowStyle.AUTO,
+ FlowStyle.BLOCK,
+ FlowStyle.FLOW
};
}