psych 4.0.0-java → 4.0.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/java/org/jruby/ext/psych/PsychEmitter.java +77 -33
- data/ext/java/org/jruby/ext/psych/PsychParser.java +65 -19
- data/lib/psych.rb +86 -3
- data/lib/psych/class_loader.rb +2 -2
- data/lib/psych/exception.rb +2 -2
- data/lib/psych/versions.rb +1 -1
- data/lib/psych/visitors/yaml_tree.rb +46 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23dccf627759f7113d2058885273d84aa92edc9a162a7a620510d27ba4c80fff
|
4
|
+
data.tar.gz: 50bd2d6eb02c3ea703bbb1064493c62ba7f579fdefa8b98cdb7a417438c5fd09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4bf4b8036cc63a7dffa4a0e0858a3eb327f1812d422c60c22852458f4a163dad53688c8bbef8300059c25ba61be455a470d5ca5918308648c450bde29231a5a
|
7
|
+
data.tar.gz: eba85f35d6f01299dd169c9c5e97f63ab795f041fa8e333a1dc26bfea125dbe14cb094b68535c687663210fc4dca88516babcd89f9235af68b493c42408f8a7d
|
@@ -29,13 +29,16 @@ package org.jruby.ext.psych;
|
|
29
29
|
|
30
30
|
import java.io.IOException;
|
31
31
|
import java.io.OutputStreamWriter;
|
32
|
+
import java.io.Writer;
|
32
33
|
import java.nio.charset.Charset;
|
33
34
|
import java.util.HashMap;
|
34
35
|
import java.util.Map;
|
35
36
|
|
36
37
|
import org.jcodings.Encoding;
|
38
|
+
import org.jcodings.specific.UTF8Encoding;
|
37
39
|
import org.jruby.Ruby;
|
38
40
|
import org.jruby.RubyArray;
|
41
|
+
import org.jruby.RubyBoolean;
|
39
42
|
import org.jruby.RubyClass;
|
40
43
|
import org.jruby.RubyFixnum;
|
41
44
|
import org.jruby.RubyModule;
|
@@ -46,6 +49,8 @@ import org.jruby.runtime.ObjectAllocator;
|
|
46
49
|
import org.jruby.runtime.ThreadContext;
|
47
50
|
import org.jruby.runtime.builtin.IRubyObject;
|
48
51
|
import org.jruby.util.IOOutputStream;
|
52
|
+
import org.jruby.util.TypeConverter;
|
53
|
+
import org.jruby.util.io.EncodingUtils;
|
49
54
|
import org.yaml.snakeyaml.DumperOptions;
|
50
55
|
import org.yaml.snakeyaml.emitter.Emitter;
|
51
56
|
import org.yaml.snakeyaml.emitter.EmitterException;
|
@@ -110,9 +115,7 @@ public class PsychEmitter extends RubyObject {
|
|
110
115
|
|
111
116
|
@JRubyMethod
|
112
117
|
public IRubyObject start_stream(ThreadContext context, IRubyObject encoding) {
|
113
|
-
|
114
|
-
throw context.runtime.newTypeError(encoding, context.runtime.getFixnum());
|
115
|
-
}
|
118
|
+
TypeConverter.checkType(context, encoding, context.runtime.getFixnum());
|
116
119
|
|
117
120
|
initEmitter(context, encoding);
|
118
121
|
|
@@ -136,6 +139,8 @@ public class PsychEmitter extends RubyObject {
|
|
136
139
|
boolean implicitBool = implicit.isTrue();
|
137
140
|
Map<String, String> tagsMap = null;
|
138
141
|
|
142
|
+
TypeConverter.checkType(context, _version, context.runtime.getArray());
|
143
|
+
|
139
144
|
RubyArray versionAry = _version.convertToArray();
|
140
145
|
if (versionAry.size() == 2) {
|
141
146
|
int versionInt0 = (int)versionAry.eltInternal(0).convertToInteger().getLongValue();
|
@@ -153,19 +158,23 @@ public class PsychEmitter extends RubyObject {
|
|
153
158
|
}
|
154
159
|
}
|
155
160
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
161
|
+
if (!tags.isNil()) {
|
162
|
+
TypeConverter.checkType(context, tags, context.runtime.getArray());
|
163
|
+
|
164
|
+
RubyArray tagsAry = tags.convertToArray();
|
165
|
+
if (tagsAry.size() > 0) {
|
166
|
+
tagsMap = new HashMap<>(tagsAry.size());
|
167
|
+
for (int i = 0; i < tagsAry.size(); i++) {
|
168
|
+
RubyArray tagsTuple = tagsAry.eltInternal(i).convertToArray();
|
169
|
+
if (tagsTuple.size() != 2) {
|
170
|
+
throw context.runtime.newRuntimeError("tags tuple must be of length 2");
|
171
|
+
}
|
172
|
+
IRubyObject key = tagsTuple.eltInternal(0);
|
173
|
+
IRubyObject value = tagsTuple.eltInternal(1);
|
174
|
+
tagsMap.put(
|
175
|
+
key.asJavaString(),
|
176
|
+
value.asJavaString());
|
163
177
|
}
|
164
|
-
IRubyObject key = tagsTuple.eltInternal(0);
|
165
|
-
IRubyObject value = tagsTuple.eltInternal(1);
|
166
|
-
tagsMap.put(
|
167
|
-
key.asJavaString(),
|
168
|
-
value.asJavaString());
|
169
178
|
}
|
170
179
|
}
|
171
180
|
|
@@ -189,21 +198,29 @@ public class PsychEmitter extends RubyObject {
|
|
189
198
|
IRubyObject plain = args[3];
|
190
199
|
IRubyObject quoted = args[4];
|
191
200
|
IRubyObject style = args[5];
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
201
|
+
|
202
|
+
RubyClass stringClass = context.runtime.getString();
|
203
|
+
|
204
|
+
TypeConverter.checkType(context, value, stringClass);
|
205
|
+
|
206
|
+
RubyString valueStr = (RubyString) value;
|
207
|
+
|
208
|
+
valueStr = EncodingUtils.strConvEnc(context, valueStr, valueStr.getEncoding(), UTF8Encoding.INSTANCE);
|
209
|
+
|
210
|
+
RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
|
211
|
+
RubyString tagStr = exportToUTF8(context, tag, stringClass);
|
196
212
|
|
197
213
|
ScalarEvent event = new ScalarEvent(
|
198
|
-
|
199
|
-
|
200
|
-
new ImplicitTuple(plain.isTrue(),
|
201
|
-
|
202
|
-
value.asJavaString(),
|
214
|
+
anchorStr == null ? null : anchorStr.asJavaString(),
|
215
|
+
tagStr == null ? null : tagStr.asJavaString(),
|
216
|
+
new ImplicitTuple(plain.isTrue(), quoted.isTrue()),
|
217
|
+
valueStr.asJavaString(),
|
203
218
|
NULL_MARK,
|
204
219
|
NULL_MARK,
|
205
220
|
SCALAR_STYLES[style.convertToInteger().getIntValue()]);
|
221
|
+
|
206
222
|
emit(context, event);
|
223
|
+
|
207
224
|
return this;
|
208
225
|
}
|
209
226
|
|
@@ -214,11 +231,14 @@ public class PsychEmitter extends RubyObject {
|
|
214
231
|
IRubyObject implicit = args[2];
|
215
232
|
IRubyObject style = args[3];
|
216
233
|
|
217
|
-
|
234
|
+
RubyClass stringClass = context.runtime.getString();
|
235
|
+
|
236
|
+
RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
|
237
|
+
RubyString tagStr = exportToUTF8(context, tag, stringClass);
|
218
238
|
|
219
239
|
SequenceStartEvent event = new SequenceStartEvent(
|
220
|
-
|
221
|
-
|
240
|
+
anchorStr == null ? null : anchorStr.asJavaString(),
|
241
|
+
tagStr == null ? null : tagStr.asJavaString(),
|
222
242
|
implicit.isTrue(),
|
223
243
|
NULL_MARK,
|
224
244
|
NULL_MARK,
|
@@ -241,16 +261,21 @@ public class PsychEmitter extends RubyObject {
|
|
241
261
|
IRubyObject implicit = args[2];
|
242
262
|
IRubyObject style = args[3];
|
243
263
|
|
244
|
-
|
264
|
+
RubyClass stringClass = context.runtime.getString();
|
265
|
+
|
266
|
+
RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
|
267
|
+
RubyString tagStr = exportToUTF8(context, tag, stringClass);
|
245
268
|
|
246
269
|
MappingStartEvent event = new MappingStartEvent(
|
247
|
-
|
248
|
-
|
270
|
+
anchorStr == null ? null : anchorStr.asJavaString(),
|
271
|
+
tagStr == null ? null : tagStr.asJavaString(),
|
249
272
|
implicit.isTrue(),
|
250
273
|
NULL_MARK,
|
251
274
|
NULL_MARK,
|
252
275
|
FLOW_STYLES[style.convertToInteger().getIntValue()]);
|
276
|
+
|
253
277
|
emit(context, event);
|
278
|
+
|
254
279
|
return this;
|
255
280
|
}
|
256
281
|
|
@@ -263,7 +288,11 @@ public class PsychEmitter extends RubyObject {
|
|
263
288
|
|
264
289
|
@JRubyMethod
|
265
290
|
public IRubyObject alias(ThreadContext context, IRubyObject anchor) {
|
266
|
-
|
291
|
+
RubyClass stringClass = context.runtime.getString();
|
292
|
+
|
293
|
+
RubyString anchorStr = exportToUTF8(context, anchor, stringClass);
|
294
|
+
|
295
|
+
AliasEvent event = new AliasEvent(anchorStr.asJavaString(), NULL_MARK, NULL_MARK);
|
267
296
|
emit(context, event);
|
268
297
|
return this;
|
269
298
|
}
|
@@ -278,7 +307,7 @@ public class PsychEmitter extends RubyObject {
|
|
278
307
|
@JRubyMethod
|
279
308
|
public IRubyObject canonical(ThreadContext context) {
|
280
309
|
// TODO: unclear if this affects a running emitter
|
281
|
-
return
|
310
|
+
return RubyBoolean.newBoolean(context, options.isCanonical());
|
282
311
|
}
|
283
312
|
|
284
313
|
@JRubyMethod(name = "indentation=")
|
@@ -312,6 +341,9 @@ public class PsychEmitter extends RubyObject {
|
|
312
341
|
if (emitter == null) throw context.runtime.newRuntimeError("uninitialized emitter");
|
313
342
|
|
314
343
|
emitter.emit(event);
|
344
|
+
|
345
|
+
// flush writer after each emit
|
346
|
+
writer.flush();
|
315
347
|
} catch (IOException ioe) {
|
316
348
|
throw context.runtime.newIOErrorFromException(ioe);
|
317
349
|
} catch (EmitterException ee) {
|
@@ -325,10 +357,22 @@ public class PsychEmitter extends RubyObject {
|
|
325
357
|
Encoding encoding = PsychLibrary.YAMLEncoding.values()[(int)_encoding.convertToInteger().getLongValue()].encoding;
|
326
358
|
Charset charset = context.runtime.getEncodingService().charsetForEncoding(encoding);
|
327
359
|
|
328
|
-
|
360
|
+
writer = new OutputStreamWriter(new IOOutputStream(io, encoding), charset);
|
361
|
+
emitter = new Emitter(writer, options);
|
362
|
+
}
|
363
|
+
|
364
|
+
private RubyString exportToUTF8(ThreadContext context, IRubyObject tag, RubyClass stringClass) {
|
365
|
+
RubyString tagStr = null;
|
366
|
+
if (!tag.isNil()) {
|
367
|
+
TypeConverter.checkType(context, tag, stringClass);
|
368
|
+
tagStr = (RubyString) tag;
|
369
|
+
tagStr = EncodingUtils.strConvEnc(context, tagStr, tagStr.getEncoding(), UTF8Encoding.INSTANCE);
|
370
|
+
}
|
371
|
+
return tagStr;
|
329
372
|
}
|
330
373
|
|
331
374
|
Emitter emitter;
|
375
|
+
Writer writer;
|
332
376
|
DumperOptions options = new DumperOptions();
|
333
377
|
IRubyObject io;
|
334
378
|
|
@@ -30,6 +30,9 @@ package org.jruby.ext.psych;
|
|
30
30
|
import java.io.ByteArrayInputStream;
|
31
31
|
import java.io.InputStreamReader;
|
32
32
|
import java.nio.charset.Charset;
|
33
|
+
import java.nio.charset.CharsetDecoder;
|
34
|
+
import java.nio.charset.CodingErrorAction;
|
35
|
+
import java.nio.charset.MalformedInputException;
|
33
36
|
import java.util.Map;
|
34
37
|
|
35
38
|
import org.jcodings.Encoding;
|
@@ -61,6 +64,7 @@ import org.jruby.util.log.LoggerFactory;
|
|
61
64
|
import org.yaml.snakeyaml.DumperOptions;
|
62
65
|
import org.yaml.snakeyaml.error.Mark;
|
63
66
|
import org.yaml.snakeyaml.error.MarkedYAMLException;
|
67
|
+
import org.yaml.snakeyaml.error.YAMLException;
|
64
68
|
import org.yaml.snakeyaml.events.AliasEvent;
|
65
69
|
import org.yaml.snakeyaml.events.DocumentEndEvent;
|
66
70
|
import org.yaml.snakeyaml.events.DocumentStartEvent;
|
@@ -75,6 +79,8 @@ import org.yaml.snakeyaml.parser.ParserImpl;
|
|
75
79
|
import org.yaml.snakeyaml.reader.ReaderException;
|
76
80
|
import org.yaml.snakeyaml.reader.StreamReader;
|
77
81
|
import org.yaml.snakeyaml.scanner.ScannerException;
|
82
|
+
|
83
|
+
import static org.jruby.runtime.Helpers.arrayOf;
|
78
84
|
import static org.jruby.runtime.Helpers.invoke;
|
79
85
|
import org.jruby.util.ByteList;
|
80
86
|
|
@@ -89,8 +95,7 @@ public class PsychParser extends RubyObject {
|
|
89
95
|
}
|
90
96
|
}, psych);
|
91
97
|
|
92
|
-
|
93
|
-
runtime.newString("psych/syntax_error"), Block.NULL_BLOCK);
|
98
|
+
runtime.getLoadService().require("psych/syntax_error");
|
94
99
|
psychParser.defineConstant("ANY", runtime.newFixnum(YAML_ANY_ENCODING.ordinal()));
|
95
100
|
psychParser.defineConstant("UTF8", runtime.newFixnum(YAML_UTF8_ENCODING.ordinal()));
|
96
101
|
psychParser.defineConstant("UTF16LE", runtime.newFixnum(YAML_UTF16LE_ENCODING.ordinal()));
|
@@ -110,13 +115,15 @@ public class PsychParser extends RubyObject {
|
|
110
115
|
return parse(context, yaml, runtime.getNil());
|
111
116
|
}
|
112
117
|
|
113
|
-
private IRubyObject stringOrNilFor(
|
114
|
-
if (value == null) return
|
118
|
+
private IRubyObject stringOrNilFor(ThreadContext context, String value, boolean tainted) {
|
119
|
+
if (value == null) return context.nil;
|
115
120
|
|
116
|
-
return stringFor(
|
121
|
+
return stringFor(context, value, tainted);
|
117
122
|
}
|
118
123
|
|
119
|
-
private RubyString stringFor(
|
124
|
+
private RubyString stringFor(ThreadContext context, String value, boolean tainted) {
|
125
|
+
Ruby runtime = context.runtime;
|
126
|
+
|
120
127
|
Encoding encoding = runtime.getDefaultInternalEncoding();
|
121
128
|
if (encoding == null) {
|
122
129
|
encoding = UTF8Encoding.INSTANCE;
|
@@ -136,8 +143,6 @@ public class PsychParser extends RubyObject {
|
|
136
143
|
}
|
137
144
|
|
138
145
|
private StreamReader readerFor(ThreadContext context, IRubyObject yaml) {
|
139
|
-
Ruby runtime = context.runtime;
|
140
|
-
|
141
146
|
if (yaml instanceof RubyString) {
|
142
147
|
ByteList byteList = ((RubyString)yaml).getByteList();
|
143
148
|
Encoding enc = byteList.getEncoding();
|
@@ -175,8 +180,14 @@ public class PsychParser extends RubyObject {
|
|
175
180
|
// If we can't get it from the IO or it doesn't have a charset, fall back on UTF-8
|
176
181
|
charset = UTF8Encoding.INSTANCE.getCharset();
|
177
182
|
}
|
178
|
-
|
183
|
+
CharsetDecoder decoder = charset.newDecoder();
|
184
|
+
decoder.onMalformedInput(CodingErrorAction.REPORT);
|
185
|
+
decoder.onMalformedInput(CodingErrorAction.REPORT);
|
186
|
+
|
187
|
+
return new StreamReader(new InputStreamReader(new IOInputStream(yaml), decoder));
|
179
188
|
} else {
|
189
|
+
Ruby runtime = context.runtime;
|
190
|
+
|
180
191
|
throw runtime.newTypeError(yaml, runtime.getIO());
|
181
192
|
}
|
182
193
|
}
|
@@ -214,7 +225,7 @@ public class PsychParser extends RubyObject {
|
|
214
225
|
|
215
226
|
invoke(context, handler, "end_document", notExplicit);
|
216
227
|
} else if (event.is(ID.Alias)) {
|
217
|
-
IRubyObject alias = stringOrNilFor(
|
228
|
+
IRubyObject alias = stringOrNilFor(context, ((AliasEvent)event).getAnchor(), tainted);
|
218
229
|
|
219
230
|
invoke(context, handler, "alias", alias);
|
220
231
|
} else if (event.is(ID.Scalar)) {
|
@@ -249,6 +260,16 @@ public class PsychParser extends RubyObject {
|
|
249
260
|
parser = null;
|
250
261
|
raiseParserException(context, yaml, re, path);
|
251
262
|
|
263
|
+
} catch (YAMLException ye) {
|
264
|
+
Throwable cause = ye.getCause();
|
265
|
+
|
266
|
+
if (cause instanceof MalformedInputException) {
|
267
|
+
// failure due to improperly encoded input
|
268
|
+
raiseParserException(context, yaml, (MalformedInputException) cause, path);
|
269
|
+
}
|
270
|
+
|
271
|
+
throw ye;
|
272
|
+
|
252
273
|
} catch (Throwable t) {
|
253
274
|
Helpers.throwException(t);
|
254
275
|
return this;
|
@@ -268,8 +289,8 @@ public class PsychParser extends RubyObject {
|
|
268
289
|
RubyArray tags = RubyArray.newArray(runtime);
|
269
290
|
if (tagsMap != null && tagsMap.size() > 0) {
|
270
291
|
for (Map.Entry<String, String> tag : tagsMap.entrySet()) {
|
271
|
-
IRubyObject key = stringFor(
|
272
|
-
IRubyObject value = stringFor(
|
292
|
+
IRubyObject key = stringFor(context, tag.getKey(), tainted);
|
293
|
+
IRubyObject value = stringFor(context, tag.getValue(), tainted);
|
273
294
|
|
274
295
|
tags.append(RubyArray.newArray(runtime, key, value));
|
275
296
|
}
|
@@ -281,8 +302,8 @@ public class PsychParser extends RubyObject {
|
|
281
302
|
|
282
303
|
private void handleMappingStart(ThreadContext context, MappingStartEvent mse, boolean tainted, IRubyObject handler) {
|
283
304
|
Ruby runtime = context.runtime;
|
284
|
-
IRubyObject anchor = stringOrNilFor(
|
285
|
-
IRubyObject tag = stringOrNilFor(
|
305
|
+
IRubyObject anchor = stringOrNilFor(context, mse.getAnchor(), tainted);
|
306
|
+
IRubyObject tag = stringOrNilFor(context, mse.getTag(), tainted);
|
286
307
|
IRubyObject implicit = runtime.newBoolean(mse.getImplicit());
|
287
308
|
IRubyObject style = runtime.newFixnum(translateFlowStyle(mse.getFlowStyle()));
|
288
309
|
|
@@ -292,12 +313,12 @@ public class PsychParser extends RubyObject {
|
|
292
313
|
private void handleScalar(ThreadContext context, ScalarEvent se, boolean tainted, IRubyObject handler) {
|
293
314
|
Ruby runtime = context.runtime;
|
294
315
|
|
295
|
-
IRubyObject anchor = stringOrNilFor(
|
296
|
-
IRubyObject tag = stringOrNilFor(
|
316
|
+
IRubyObject anchor = stringOrNilFor(context, se.getAnchor(), tainted);
|
317
|
+
IRubyObject tag = stringOrNilFor(context, se.getTag(), tainted);
|
297
318
|
IRubyObject plain_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInPlainScalar());
|
298
319
|
IRubyObject quoted_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInNonPlainScalar());
|
299
320
|
IRubyObject style = runtime.newFixnum(translateStyle(se.getScalarStyle()));
|
300
|
-
IRubyObject val = stringFor(
|
321
|
+
IRubyObject val = stringFor(context, se.getValue(), tainted);
|
301
322
|
|
302
323
|
invoke(context, handler, "scalar", val, anchor, tag, plain_implicit,
|
303
324
|
quoted_implicit, style);
|
@@ -305,8 +326,8 @@ public class PsychParser extends RubyObject {
|
|
305
326
|
|
306
327
|
private void handleSequenceStart(ThreadContext context, SequenceStartEvent sse, boolean tainted, IRubyObject handler) {
|
307
328
|
Ruby runtime = context.runtime;
|
308
|
-
IRubyObject anchor = stringOrNilFor(
|
309
|
-
IRubyObject tag = stringOrNilFor(
|
329
|
+
IRubyObject anchor = stringOrNilFor(context, sse.getAnchor(), tainted);
|
330
|
+
IRubyObject tag = stringOrNilFor(context, sse.getTag(), tainted);
|
310
331
|
IRubyObject implicit = runtime.newBoolean(sse.getImplicit());
|
311
332
|
IRubyObject style = runtime.newFixnum(translateFlowStyle(sse.getFlowStyle()));
|
312
333
|
|
@@ -360,6 +381,31 @@ public class PsychParser extends RubyObject {
|
|
360
381
|
RubyKernel.raise(context, runtime.getKernel(), new IRubyObject[] { exception }, Block.NULL_BLOCK);
|
361
382
|
}
|
362
383
|
|
384
|
+
private static void raiseParserException(ThreadContext context, IRubyObject yaml, MalformedInputException mie, IRubyObject rbPath) {
|
385
|
+
Ruby runtime;
|
386
|
+
Mark mark;
|
387
|
+
RubyClass se;
|
388
|
+
IRubyObject exception;
|
389
|
+
|
390
|
+
runtime = context.runtime;
|
391
|
+
se = (RubyClass)runtime.getModule("Psych").getConstant("SyntaxError");
|
392
|
+
|
393
|
+
mie.getInputLength();
|
394
|
+
|
395
|
+
exception = se.newInstance(context,
|
396
|
+
arrayOf(
|
397
|
+
rbPath,
|
398
|
+
runtime.newFixnum(-1),
|
399
|
+
runtime.newFixnum(-1),
|
400
|
+
runtime.newFixnum(mie.getInputLength()),
|
401
|
+
runtime.getNil(),
|
402
|
+
runtime.getNil()
|
403
|
+
),
|
404
|
+
Block.NULL_BLOCK);
|
405
|
+
|
406
|
+
RubyKernel.raise(context, runtime.getKernel(), new IRubyObject[] { exception }, Block.NULL_BLOCK);
|
407
|
+
}
|
408
|
+
|
363
409
|
private static int translateStyle(DumperOptions.ScalarStyle style) {
|
364
410
|
if (style == null) return 0; // any
|
365
411
|
|
data/lib/psych.rb
CHANGED
@@ -282,7 +282,8 @@ module Psych
|
|
282
282
|
# * TrueClass
|
283
283
|
# * FalseClass
|
284
284
|
# * NilClass
|
285
|
-
# *
|
285
|
+
# * Integer
|
286
|
+
# * Float
|
286
287
|
# * String
|
287
288
|
# * Array
|
288
289
|
# * Hash
|
@@ -512,6 +513,79 @@ module Psych
|
|
512
513
|
visitor.tree.yaml io, options
|
513
514
|
end
|
514
515
|
|
516
|
+
###
|
517
|
+
# call-seq:
|
518
|
+
# Psych.safe_dump(o) -> string of yaml
|
519
|
+
# Psych.safe_dump(o, options) -> string of yaml
|
520
|
+
# Psych.safe_dump(o, io) -> io object passed in
|
521
|
+
# Psych.safe_dump(o, io, options) -> io object passed in
|
522
|
+
#
|
523
|
+
# Safely dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in
|
524
|
+
# to control the output format. If an IO object is passed in, the YAML will
|
525
|
+
# be dumped to that IO object. By default, only the following
|
526
|
+
# classes are allowed to be serialized:
|
527
|
+
#
|
528
|
+
# * TrueClass
|
529
|
+
# * FalseClass
|
530
|
+
# * NilClass
|
531
|
+
# * Integer
|
532
|
+
# * Float
|
533
|
+
# * String
|
534
|
+
# * Array
|
535
|
+
# * Hash
|
536
|
+
#
|
537
|
+
# Arbitrary classes can be allowed by adding those classes to the +permitted_classes+
|
538
|
+
# keyword argument. They are additive. For example, to allow Date serialization:
|
539
|
+
#
|
540
|
+
# Psych.safe_dump(yaml, permitted_classes: [Date])
|
541
|
+
#
|
542
|
+
# Now the Date class can be dumped in addition to the classes listed above.
|
543
|
+
#
|
544
|
+
# A Psych::DisallowedClass exception will be raised if the object contains a
|
545
|
+
# class that isn't in the +permitted_classes+ list.
|
546
|
+
#
|
547
|
+
# Currently supported options are:
|
548
|
+
#
|
549
|
+
# [<tt>:indentation</tt>] Number of space characters used to indent.
|
550
|
+
# Acceptable value should be in <tt>0..9</tt> range,
|
551
|
+
# otherwise option is ignored.
|
552
|
+
#
|
553
|
+
# Default: <tt>2</tt>.
|
554
|
+
# [<tt>:line_width</tt>] Max character to wrap line at.
|
555
|
+
#
|
556
|
+
# Default: <tt>0</tt> (meaning "wrap at 81").
|
557
|
+
# [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
|
558
|
+
# strictly formal).
|
559
|
+
#
|
560
|
+
# Default: <tt>false</tt>.
|
561
|
+
# [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document.
|
562
|
+
#
|
563
|
+
# Default: <tt>false</tt>.
|
564
|
+
#
|
565
|
+
# Example:
|
566
|
+
#
|
567
|
+
# # Dump an array, get back a YAML string
|
568
|
+
# Psych.safe_dump(['a', 'b']) # => "---\n- a\n- b\n"
|
569
|
+
#
|
570
|
+
# # Dump an array to an IO object
|
571
|
+
# Psych.safe_dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
|
572
|
+
#
|
573
|
+
# # Dump an array with indentation set
|
574
|
+
# Psych.safe_dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n"
|
575
|
+
#
|
576
|
+
# # Dump an array to an IO with indentation set
|
577
|
+
# Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3)
|
578
|
+
def self.safe_dump o, io = nil, options = {}
|
579
|
+
if Hash === io
|
580
|
+
options = io
|
581
|
+
io = nil
|
582
|
+
end
|
583
|
+
|
584
|
+
visitor = Psych::Visitors::RestrictedYAMLTree.create options
|
585
|
+
visitor << o
|
586
|
+
visitor.tree.yaml io, options
|
587
|
+
end
|
588
|
+
|
515
589
|
###
|
516
590
|
# Dump a list of objects as separate documents to a document stream.
|
517
591
|
#
|
@@ -575,7 +649,6 @@ module Psych
|
|
575
649
|
self.unsafe_load f, filename: filename, **kwargs
|
576
650
|
}
|
577
651
|
end
|
578
|
-
class << self; alias :load_file :unsafe_load_file; end
|
579
652
|
|
580
653
|
###
|
581
654
|
# Safely loads the document contained in +filename+. Returns the yaml contained in
|
@@ -587,7 +660,17 @@ module Psych
|
|
587
660
|
self.safe_load f, filename: filename, **kwargs
|
588
661
|
}
|
589
662
|
end
|
590
|
-
|
663
|
+
|
664
|
+
###
|
665
|
+
# Loads the document contained in +filename+. Returns the yaml contained in
|
666
|
+
# +filename+ as a Ruby object, or if the file is empty, it returns
|
667
|
+
# the specified +fallback+ return value, which defaults to +false+.
|
668
|
+
# See load for options.
|
669
|
+
def self.load_file filename, **kwargs
|
670
|
+
File.open(filename, 'r:bom|utf-8') { |f|
|
671
|
+
self.load f, filename: filename, **kwargs
|
672
|
+
}
|
673
|
+
end
|
591
674
|
|
592
675
|
# :stopdoc:
|
593
676
|
def self.add_domain_type domain, type_tag, &block
|
data/lib/psych/class_loader.rb
CHANGED
@@ -86,7 +86,7 @@ module Psych
|
|
86
86
|
if @symbols.include? sym
|
87
87
|
super
|
88
88
|
else
|
89
|
-
raise DisallowedClass, 'Symbol'
|
89
|
+
raise DisallowedClass.new('load', 'Symbol')
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -96,7 +96,7 @@ module Psych
|
|
96
96
|
if @classes.include? klassname
|
97
97
|
super
|
98
98
|
else
|
99
|
-
raise DisallowedClass, klassname
|
99
|
+
raise DisallowedClass.new('load', klassname)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
data/lib/psych/exception.rb
CHANGED
@@ -7,8 +7,8 @@ module Psych
|
|
7
7
|
end
|
8
8
|
|
9
9
|
class DisallowedClass < Exception
|
10
|
-
def initialize klass_name
|
11
|
-
super "Tried to
|
10
|
+
def initialize action, klass_name
|
11
|
+
super "Tried to #{action} unspecified class: #{klass_name}"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
data/lib/psych/versions.rb
CHANGED
@@ -535,5 +535,51 @@ module Psych
|
|
535
535
|
end
|
536
536
|
end
|
537
537
|
end
|
538
|
+
|
539
|
+
class RestrictedYAMLTree < YAMLTree
|
540
|
+
DEFAULT_PERMITTED_CLASSES = {
|
541
|
+
TrueClass => true,
|
542
|
+
FalseClass => true,
|
543
|
+
NilClass => true,
|
544
|
+
Integer => true,
|
545
|
+
Float => true,
|
546
|
+
String => true,
|
547
|
+
Array => true,
|
548
|
+
Hash => true,
|
549
|
+
}.compare_by_identity.freeze
|
550
|
+
|
551
|
+
def initialize emitter, ss, options
|
552
|
+
super
|
553
|
+
@permitted_classes = DEFAULT_PERMITTED_CLASSES.dup
|
554
|
+
Array(options[:permitted_classes]).each do |klass|
|
555
|
+
@permitted_classes[klass] = true
|
556
|
+
end
|
557
|
+
@permitted_symbols = {}.compare_by_identity
|
558
|
+
Array(options[:permitted_symbols]).each do |symbol|
|
559
|
+
@permitted_symbols[symbol] = true
|
560
|
+
end
|
561
|
+
@aliases = options.fetch(:aliases, false)
|
562
|
+
end
|
563
|
+
|
564
|
+
def accept target
|
565
|
+
if !@aliases && @st.key?(target)
|
566
|
+
raise BadAlias, "Tried to dump an aliased object"
|
567
|
+
end
|
568
|
+
|
569
|
+
unless @permitted_classes[target.class]
|
570
|
+
raise DisallowedClass.new('dump', target.class.name || target.class.inspect)
|
571
|
+
end
|
572
|
+
|
573
|
+
super
|
574
|
+
end
|
575
|
+
|
576
|
+
def visit_Symbol sym
|
577
|
+
unless @permitted_symbols[sym]
|
578
|
+
raise DisallowedClass.new('dump', "Symbol(#{sym.inspect})")
|
579
|
+
end
|
580
|
+
|
581
|
+
super
|
582
|
+
end
|
583
|
+
end
|
538
584
|
end
|
539
585
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: psych
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.1
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Aaron Patterson
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-06-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
@@ -19,8 +19,8 @@ dependencies:
|
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: 0.1.7
|
21
21
|
name: jar-dependencies
|
22
|
-
type: :runtime
|
23
22
|
prerelease: false
|
23
|
+
type: :runtime
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - ">="
|
@@ -138,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
138
|
version: '0'
|
139
139
|
requirements:
|
140
140
|
- jar org.yaml:snakeyaml, 1.28
|
141
|
-
rubygems_version: 3.
|
141
|
+
rubygems_version: 3.1.6
|
142
142
|
signing_key:
|
143
143
|
specification_version: 4
|
144
144
|
summary: Psych is a YAML parser and emitter
|