psych 2.1.0-java → 2.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/Gemfile +3 -0
  4. data/Mavenfile +7 -0
  5. data/bin/console +7 -0
  6. data/bin/setup +6 -0
  7. data/ext/java/PsychEmitter.java +345 -0
  8. data/ext/java/PsychLibrary.java +93 -0
  9. data/ext/java/PsychParser.java +399 -0
  10. data/ext/java/PsychToRuby.java +79 -0
  11. data/ext/java/PsychYamlTree.java +55 -0
  12. data/ext/psych/.gitignore +11 -0
  13. data/lib/psych.rb +2 -2
  14. data/lib/psych/visitors/to_ruby.rb +2 -2
  15. data/psych.gemspec +39 -0
  16. metadata +19 -53
  17. data/test/psych/handlers/test_recorder.rb +0 -26
  18. data/test/psych/helper.rb +0 -122
  19. data/test/psych/json/test_stream.rb +0 -110
  20. data/test/psych/nodes/test_enumerable.rb +0 -44
  21. data/test/psych/test_alias_and_anchor.rb +0 -97
  22. data/test/psych/test_array.rb +0 -58
  23. data/test/psych/test_boolean.rb +0 -37
  24. data/test/psych/test_class.rb +0 -37
  25. data/test/psych/test_coder.rb +0 -207
  26. data/test/psych/test_date_time.rb +0 -39
  27. data/test/psych/test_deprecated.rb +0 -215
  28. data/test/psych/test_document.rb +0 -47
  29. data/test/psych/test_emitter.rb +0 -112
  30. data/test/psych/test_encoding.rb +0 -269
  31. data/test/psych/test_exception.rb +0 -158
  32. data/test/psych/test_hash.rb +0 -95
  33. data/test/psych/test_json_tree.rb +0 -66
  34. data/test/psych/test_merge_keys.rb +0 -181
  35. data/test/psych/test_nil.rb +0 -19
  36. data/test/psych/test_null.rb +0 -20
  37. data/test/psych/test_numeric.rb +0 -46
  38. data/test/psych/test_object.rb +0 -45
  39. data/test/psych/test_object_references.rb +0 -72
  40. data/test/psych/test_omap.rb +0 -76
  41. data/test/psych/test_parser.rb +0 -340
  42. data/test/psych/test_psych.rb +0 -184
  43. data/test/psych/test_safe_load.rb +0 -98
  44. data/test/psych/test_scalar.rb +0 -12
  45. data/test/psych/test_scalar_scanner.rb +0 -111
  46. data/test/psych/test_serialize_subclasses.rb +0 -39
  47. data/test/psych/test_set.rb +0 -50
  48. data/test/psych/test_stream.rb +0 -94
  49. data/test/psych/test_string.rb +0 -231
  50. data/test/psych/test_struct.rb +0 -50
  51. data/test/psych/test_symbol.rb +0 -26
  52. data/test/psych/test_tainted.rb +0 -131
  53. data/test/psych/test_to_yaml_properties.rb +0 -64
  54. data/test/psych/test_tree_builder.rb +0 -80
  55. data/test/psych/test_yaml.rb +0 -1293
  56. data/test/psych/test_yamldbm.rb +0 -193
  57. data/test/psych/test_yamlstore.rb +0 -86
  58. data/test/psych/visitors/test_depth_first.rb +0 -50
  59. data/test/psych/visitors/test_emitter.rb +0 -145
  60. data/test/psych/visitors/test_to_ruby.rb +0 -332
  61. data/test/psych/visitors/test_yaml_tree.rb +0 -180
@@ -0,0 +1,399 @@
1
+ /***** BEGIN LICENSE BLOCK *****
2
+ * Version: EPL 1.0/GPL 2.0/LGPL 2.1
3
+ *
4
+ * The contents of this file are subject to the Eclipse Public
5
+ * License Version 1.0 (the "License"); you may not use this file
6
+ * except in compliance with the License. You may obtain a copy of
7
+ * the License at http://www.eclipse.org/legal/epl-v10.html
8
+ *
9
+ * Software distributed under the License is distributed on an "AS
10
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
+ * implied. See the License for the specific language governing
12
+ * rights and limitations under the License.
13
+ *
14
+ * Copyright (C) 2010 Charles O Nutter <headius@headius.com>
15
+ *
16
+ * Alternatively, the contents of this file may be used under the terms of
17
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
18
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19
+ * in which case the provisions of the GPL or the LGPL are applicable instead
20
+ * of those above. If you wish to allow use of your version of this file only
21
+ * under the terms of either the GPL or the LGPL, and not to allow others to
22
+ * use your version of this file under the terms of the EPL, indicate your
23
+ * decision by deleting the provisions above and replace them with the notice
24
+ * and other provisions required by the GPL or the LGPL. If you do not delete
25
+ * the provisions above, a recipient may use your version of this file under
26
+ * the terms of any one of the EPL, the GPL or the LGPL.
27
+ ***** END LICENSE BLOCK *****/
28
+ package org.jruby.ext.psych;
29
+
30
+ import java.io.ByteArrayInputStream;
31
+ import java.io.InputStreamReader;
32
+ import java.nio.charset.Charset;
33
+ import java.util.Map;
34
+
35
+ import org.jcodings.Encoding;
36
+ import org.jcodings.specific.UTF8Encoding;
37
+ import org.jcodings.unicode.UnicodeEncoding;
38
+ import org.jruby.Ruby;
39
+ import org.jruby.RubyArray;
40
+ import org.jruby.RubyClass;
41
+ import org.jruby.RubyEncoding;
42
+ import org.jruby.RubyIO;
43
+ import org.jruby.RubyKernel;
44
+ import org.jruby.RubyModule;
45
+ import org.jruby.RubyObject;
46
+ import org.jruby.RubyString;
47
+ import org.jruby.anno.JRubyMethod;
48
+ import static org.jruby.ext.psych.PsychLibrary.YAMLEncoding.*;
49
+ import org.jruby.runtime.Block;
50
+ import org.jruby.runtime.Helpers;
51
+ import org.jruby.runtime.ObjectAllocator;
52
+ import org.jruby.runtime.ThreadContext;
53
+ import org.jruby.runtime.builtin.IRubyObject;
54
+ import org.jruby.util.IOInputStream;
55
+ import org.jruby.util.io.EncodingUtils;
56
+ import org.jruby.util.log.Logger;
57
+ import org.jruby.util.log.LoggerFactory;
58
+ import org.yaml.snakeyaml.DumperOptions;
59
+ import org.yaml.snakeyaml.error.Mark;
60
+ import org.yaml.snakeyaml.error.MarkedYAMLException;
61
+ import org.yaml.snakeyaml.events.AliasEvent;
62
+ import org.yaml.snakeyaml.events.DocumentEndEvent;
63
+ import org.yaml.snakeyaml.events.DocumentStartEvent;
64
+ import org.yaml.snakeyaml.events.Event;
65
+ import org.yaml.snakeyaml.events.Event.ID;
66
+ import org.yaml.snakeyaml.events.MappingStartEvent;
67
+ import org.yaml.snakeyaml.events.ScalarEvent;
68
+ import org.yaml.snakeyaml.events.SequenceStartEvent;
69
+ import org.yaml.snakeyaml.parser.Parser;
70
+ import org.yaml.snakeyaml.parser.ParserException;
71
+ import org.yaml.snakeyaml.parser.ParserImpl;
72
+ import org.yaml.snakeyaml.reader.ReaderException;
73
+ import org.yaml.snakeyaml.reader.StreamReader;
74
+ import org.yaml.snakeyaml.scanner.ScannerException;
75
+ import static org.jruby.runtime.Helpers.invoke;
76
+ import org.jruby.util.ByteList;
77
+
78
+ public class PsychParser extends RubyObject {
79
+
80
+ private static final Logger LOG = LoggerFactory.getLogger("PsychParser");
81
+
82
+ public static void initPsychParser(Ruby runtime, RubyModule psych) {
83
+ RubyClass psychParser = runtime.defineClassUnder("Parser", runtime.getObject(), new ObjectAllocator() {
84
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
85
+ return new PsychParser(runtime, klazz);
86
+ }
87
+ }, psych);
88
+
89
+ RubyKernel.require(runtime.getNil(),
90
+ runtime.newString("psych/syntax_error"), Block.NULL_BLOCK);
91
+ psychParser.defineConstant("ANY", runtime.newFixnum(YAML_ANY_ENCODING.ordinal()));
92
+ psychParser.defineConstant("UTF8", runtime.newFixnum(YAML_UTF8_ENCODING.ordinal()));
93
+ psychParser.defineConstant("UTF16LE", runtime.newFixnum(YAML_UTF16LE_ENCODING.ordinal()));
94
+ psychParser.defineConstant("UTF16BE", runtime.newFixnum(YAML_UTF16BE_ENCODING.ordinal()));
95
+
96
+ psychParser.defineAnnotatedMethods(PsychParser.class);
97
+ }
98
+
99
+ public PsychParser(Ruby runtime, RubyClass klass) {
100
+ super(runtime, klass);
101
+ }
102
+
103
+ @JRubyMethod
104
+ public IRubyObject parse(ThreadContext context, IRubyObject yaml) {
105
+ Ruby runtime = context.runtime;
106
+
107
+ return parse(context, yaml, runtime.getNil());
108
+ }
109
+
110
+ private IRubyObject stringOrNilFor(Ruby runtime, String value, boolean tainted) {
111
+ if (value == null) return runtime.getNil(); // No need to taint nil
112
+
113
+ return stringFor(runtime, value, tainted);
114
+ }
115
+
116
+ private RubyString stringFor(Ruby runtime, String value, boolean tainted) {
117
+ Encoding encoding = runtime.getDefaultInternalEncoding();
118
+ if (encoding == null) {
119
+ encoding = UTF8Encoding.INSTANCE;
120
+ }
121
+
122
+ Charset charset = RubyEncoding.UTF8;
123
+ if (encoding.getCharset() != null) {
124
+ charset = encoding.getCharset();
125
+ }
126
+
127
+ ByteList bytes = new ByteList(value.getBytes(charset), encoding);
128
+ RubyString string = RubyString.newString(runtime, bytes);
129
+
130
+ string.setTaint(tainted);
131
+
132
+ return string;
133
+ }
134
+
135
+ private StreamReader readerFor(ThreadContext context, IRubyObject yaml) {
136
+ Ruby runtime = context.runtime;
137
+
138
+ if (yaml instanceof RubyString) {
139
+ ByteList byteList = ((RubyString)yaml).getByteList();
140
+ Encoding enc = byteList.getEncoding();
141
+
142
+ // if not unicode, transcode to UTF8
143
+ if (!(enc instanceof UnicodeEncoding)) {
144
+ byteList = EncodingUtils.strConvEnc(context, byteList, enc, UTF8Encoding.INSTANCE);
145
+ enc = UTF8Encoding.INSTANCE;
146
+ }
147
+
148
+ ByteArrayInputStream bais = new ByteArrayInputStream(byteList.getUnsafeBytes(), byteList.getBegin(), byteList.getRealSize());
149
+
150
+ Charset charset = enc.getCharset();
151
+
152
+ assert charset != null : "charset for encoding " + enc + " should not be null";
153
+
154
+ InputStreamReader isr = new InputStreamReader(bais, charset);
155
+
156
+ return new StreamReader(isr);
157
+ }
158
+
159
+ // fall back on IOInputStream, using default charset
160
+ if (yaml.respondsTo("read")) {
161
+ Encoding enc = (yaml instanceof RubyIO)
162
+ ? ((RubyIO)yaml).getReadEncoding()
163
+ : UTF8Encoding.INSTANCE;
164
+ Charset charset = enc.getCharset();
165
+ return new StreamReader(new InputStreamReader(new IOInputStream(yaml), charset));
166
+ } else {
167
+ throw runtime.newTypeError(yaml, runtime.getIO());
168
+ }
169
+ }
170
+
171
+ @JRubyMethod
172
+ public IRubyObject parse(ThreadContext context, IRubyObject yaml, IRubyObject path) {
173
+ Ruby runtime = context.runtime;
174
+ boolean tainted = yaml.isTaint() || yaml instanceof RubyIO;
175
+
176
+ try {
177
+ parser = new ParserImpl(readerFor(context, yaml));
178
+
179
+ if (path.isNil() && yaml.respondsTo("path")) {
180
+ path = yaml.callMethod(context, "path");
181
+ }
182
+
183
+ IRubyObject handler = getInstanceVariable("@handler");
184
+
185
+ while (true) {
186
+ event = parser.getEvent();
187
+
188
+ // FIXME: Event should expose a getID, so it can be switched
189
+ if (event.is(ID.StreamStart)) {
190
+ invoke(context, handler, "start_stream", runtime.newFixnum(YAML_ANY_ENCODING.ordinal()));
191
+ } else if (event.is(ID.DocumentStart)) {
192
+ handleDocumentStart(context, (DocumentStartEvent) event, tainted, handler);
193
+ } else if (event.is(ID.DocumentEnd)) {
194
+ IRubyObject notExplicit = runtime.newBoolean(!((DocumentEndEvent) event).getExplicit());
195
+
196
+ invoke(context, handler, "end_document", notExplicit);
197
+ } else if (event.is(ID.Alias)) {
198
+ IRubyObject alias = stringOrNilFor(runtime, ((AliasEvent)event).getAnchor(), tainted);
199
+
200
+ invoke(context, handler, "alias", alias);
201
+ } else if (event.is(ID.Scalar)) {
202
+ handleScalar(context, (ScalarEvent) event, tainted, handler);
203
+ } else if (event.is(ID.SequenceStart)) {
204
+ handleSequenceStart(context,(SequenceStartEvent) event, tainted, handler);
205
+ } else if (event.is(ID.SequenceEnd)) {
206
+ invoke(context, handler, "end_sequence");
207
+ } else if (event.is(ID.MappingStart)) {
208
+ handleMappingStart(context, (MappingStartEvent) event, tainted, handler);
209
+ } else if (event.is(ID.MappingEnd)) {
210
+ invoke(context, handler, "end_mapping");
211
+ } else if (event.is(ID.StreamEnd)) {
212
+ invoke(context, handler, "end_stream");
213
+
214
+ break;
215
+ }
216
+ }
217
+ } catch (ParserException pe) {
218
+ parser = null;
219
+ raiseParserException(context, yaml, pe, path);
220
+
221
+ } catch (ScannerException se) {
222
+ parser = null;
223
+ StringBuilder message = new StringBuilder("syntax error");
224
+ if (se.getProblemMark() != null) {
225
+ message.append(se.getProblemMark().toString());
226
+ }
227
+ raiseParserException(context, yaml, se, path);
228
+
229
+ } catch (ReaderException re) {
230
+ parser = null;
231
+ raiseParserException(context, yaml, re, path);
232
+
233
+ } catch (Throwable t) {
234
+ Helpers.throwException(t);
235
+ return this;
236
+ }
237
+
238
+ return this;
239
+ }
240
+
241
+ private void handleDocumentStart(ThreadContext context, DocumentStartEvent dse, boolean tainted, IRubyObject handler) {
242
+ Ruby runtime = context.runtime;
243
+ DumperOptions.Version _version = dse.getVersion();
244
+ Integer[] versionInts = _version == null ? null : _version.getArray();
245
+ IRubyObject version = versionInts == null ?
246
+ RubyArray.newArray(runtime) :
247
+ RubyArray.newArray(runtime, runtime.newFixnum(versionInts[0]), runtime.newFixnum(versionInts[1]));
248
+
249
+ Map<String, String> tagsMap = dse.getTags();
250
+ RubyArray tags = RubyArray.newArray(runtime);
251
+ if (tagsMap != null && tagsMap.size() > 0) {
252
+ for (Map.Entry<String, String> tag : tagsMap.entrySet()) {
253
+ IRubyObject key = stringFor(runtime, tag.getKey(), tainted);
254
+ IRubyObject value = stringFor(runtime, tag.getValue(), tainted);
255
+
256
+ tags.append(RubyArray.newArray(runtime, key, value));
257
+ }
258
+ }
259
+ IRubyObject notExplicit = runtime.newBoolean(!dse.getExplicit());
260
+
261
+ invoke(context, handler, "start_document", version, tags, notExplicit);
262
+ }
263
+
264
+ private void handleMappingStart(ThreadContext context, MappingStartEvent mse, boolean tainted, IRubyObject handler) {
265
+ Ruby runtime = context.runtime;
266
+ IRubyObject anchor = stringOrNilFor(runtime, mse.getAnchor(), tainted);
267
+ IRubyObject tag = stringOrNilFor(runtime, mse.getTag(), tainted);
268
+ IRubyObject implicit = runtime.newBoolean(mse.getImplicit());
269
+ IRubyObject style = runtime.newFixnum(translateFlowStyle(mse.getFlowStyle()));
270
+
271
+ invoke(context, handler, "start_mapping", anchor, tag, implicit, style);
272
+ }
273
+
274
+ private void handleScalar(ThreadContext context, ScalarEvent se, boolean tainted, IRubyObject handler) {
275
+ Ruby runtime = context.runtime;
276
+ IRubyObject anchor = stringOrNilFor(runtime, se.getAnchor(), tainted);
277
+ IRubyObject tag = stringOrNilFor(runtime, se.getTag(), tainted);
278
+ IRubyObject plain_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInPlainScalar());
279
+ IRubyObject quoted_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInNonPlainScalar());
280
+ IRubyObject style = runtime.newFixnum(translateStyle(se.getStyle()));
281
+ IRubyObject val = stringFor(runtime, se.getValue(), tainted);
282
+
283
+ invoke(context, handler, "scalar", val, anchor, tag, plain_implicit,
284
+ quoted_implicit, style);
285
+ }
286
+
287
+ private void handleSequenceStart(ThreadContext context, SequenceStartEvent sse, boolean tainted, IRubyObject handler) {
288
+ Ruby runtime = context.runtime;
289
+ IRubyObject anchor = stringOrNilFor(runtime, sse.getAnchor(), tainted);
290
+ IRubyObject tag = stringOrNilFor(runtime, sse.getTag(), tainted);
291
+ IRubyObject implicit = runtime.newBoolean(sse.getImplicit());
292
+ IRubyObject style = runtime.newFixnum(translateFlowStyle(sse.getFlowStyle()));
293
+
294
+ invoke(context, handler, "start_sequence", anchor, tag, implicit, style);
295
+ }
296
+
297
+ private static void raiseParserException(ThreadContext context, IRubyObject yaml, ReaderException re, IRubyObject rbPath) {
298
+ Ruby runtime;
299
+ RubyClass se;
300
+ IRubyObject exception;
301
+
302
+ runtime = context.runtime;
303
+ se = (RubyClass)runtime.getModule("Psych").getConstant("SyntaxError");
304
+
305
+ exception = se.newInstance(context,
306
+ new IRubyObject[] {
307
+ rbPath,
308
+ runtime.newFixnum(0),
309
+ runtime.newFixnum(0),
310
+ runtime.newFixnum(re.getPosition()),
311
+ (null == re.getName() ? runtime.getNil() : runtime.newString(re.getName())),
312
+ (null == re.toString() ? runtime.getNil() : runtime.newString(re.toString()))
313
+ },
314
+ Block.NULL_BLOCK);
315
+
316
+ RubyKernel.raise(context, runtime.getKernel(), new IRubyObject[] { exception }, Block.NULL_BLOCK);
317
+ }
318
+
319
+ private static void raiseParserException(ThreadContext context, IRubyObject yaml, MarkedYAMLException mye, IRubyObject rbPath) {
320
+ Ruby runtime;
321
+ Mark mark;
322
+ RubyClass se;
323
+ IRubyObject exception;
324
+
325
+ runtime = context.runtime;
326
+ se = (RubyClass)runtime.getModule("Psych").getConstant("SyntaxError");
327
+
328
+ mark = mye.getProblemMark();
329
+
330
+ exception = se.newInstance(context,
331
+ new IRubyObject[] {
332
+ rbPath,
333
+ runtime.newFixnum(mark.getLine() + 1),
334
+ runtime.newFixnum(mark.getColumn() + 1),
335
+ runtime.newFixnum(mark.getIndex()),
336
+ (null == mye.getProblem() ? runtime.getNil() : runtime.newString(mye.getProblem())),
337
+ (null == mye.getContext() ? runtime.getNil() : runtime.newString(mye.getContext()))
338
+ },
339
+ Block.NULL_BLOCK);
340
+
341
+ RubyKernel.raise(context, runtime.getKernel(), new IRubyObject[] { exception }, Block.NULL_BLOCK);
342
+ }
343
+
344
+ private static int translateStyle(Character style) {
345
+ if (style == null) return 0; // any
346
+
347
+ switch (style) {
348
+ case 0: return 1; // plain
349
+ case '\'': return 2; // single-quoted
350
+ case '"': return 3; // double-quoted
351
+ case '|': return 4; // literal
352
+ case '>': return 5; // folded
353
+ default: return 0; // any
354
+ }
355
+ }
356
+
357
+ private static int translateFlowStyle(Boolean flowStyle) {
358
+ if (flowStyle == null) return 0; // any
359
+
360
+ if (flowStyle) return 2;
361
+ return 1;
362
+ }
363
+
364
+ @JRubyMethod
365
+ public IRubyObject mark(ThreadContext context) {
366
+ Ruby runtime = context.runtime;
367
+
368
+ Event event = null;
369
+
370
+ if (parser != null) {
371
+ event = parser.peekEvent();
372
+
373
+ if (event == null) event = this.event;
374
+ }
375
+
376
+ if (event == null) {
377
+ return ((RubyClass)context.runtime.getClassFromPath("Psych::Parser::Mark")).newInstance(
378
+ context,
379
+ runtime.newFixnum(0),
380
+ runtime.newFixnum(0),
381
+ runtime.newFixnum(0),
382
+ Block.NULL_BLOCK
383
+ );
384
+ }
385
+
386
+ Mark mark = event.getStartMark();
387
+
388
+ return ((RubyClass)context.runtime.getClassFromPath("Psych::Parser::Mark")).newInstance(
389
+ context,
390
+ runtime.newFixnum(mark.getIndex()),
391
+ runtime.newFixnum(mark.getLine()),
392
+ runtime.newFixnum(mark.getColumn()),
393
+ Block.NULL_BLOCK
394
+ );
395
+ }
396
+
397
+ private Parser parser;
398
+ private Event event;
399
+ }
@@ -0,0 +1,79 @@
1
+ /***** BEGIN LICENSE BLOCK *****
2
+ * Version: EPL 1.0/GPL 2.0/LGPL 2.1
3
+ *
4
+ * The contents of this file are subject to the Eclipse Public
5
+ * License Version 1.0 (the "License"); you may not use this file
6
+ * except in compliance with the License. You may obtain a copy of
7
+ * the License at http://www.eclipse.org/legal/epl-v10.html
8
+ *
9
+ * Software distributed under the License is distributed on an "AS
10
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
+ * implied. See the License for the specific language governing
12
+ * rights and limitations under the License.
13
+ *
14
+ * Copyright (C) 2010 Charles O Nutter <headius@headius.com>
15
+ *
16
+ * Alternatively, the contents of this file may be used under the terms of
17
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
18
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19
+ * in which case the provisions of the GPL or the LGPL are applicable instead
20
+ * of those above. If you wish to allow use of your version of this file only
21
+ * under the terms of either the GPL or the LGPL, and not to allow others to
22
+ * use your version of this file under the terms of the EPL, indicate your
23
+ * decision by deleting the provisions above and replace them with the notice
24
+ * and other provisions required by the GPL or the LGPL. If you do not delete
25
+ * the provisions above, a recipient may use your version of this file under
26
+ * the terms of any one of the EPL, the GPL or the LGPL.
27
+ ***** END LICENSE BLOCK *****/
28
+ package org.jruby.ext.psych;
29
+
30
+ import org.jruby.Ruby;
31
+ import org.jruby.RubyClass;
32
+ import org.jruby.RubyModule;
33
+ import org.jruby.RubyObject;
34
+ import org.jruby.RubyException;
35
+ import org.jruby.anno.JRubyMethod;
36
+ import org.jruby.exceptions.RaiseException;
37
+ import org.jruby.runtime.ThreadContext;
38
+ import org.jruby.runtime.builtin.IRubyObject;
39
+ import static org.jruby.runtime.Visibility.*;
40
+
41
+ public class PsychToRuby {
42
+ public static void initPsychToRuby(Ruby runtime, RubyModule psych) {
43
+ RubyClass classLoader = runtime.defineClassUnder("ClassLoader", runtime.getObject(), RubyObject.OBJECT_ALLOCATOR, psych);
44
+
45
+ RubyModule visitors = runtime.defineModuleUnder("Visitors", psych);
46
+ RubyClass visitor = runtime.defineClassUnder("Visitor", runtime.getObject(), runtime.getObject().getAllocator(), visitors);
47
+ RubyClass psychToRuby = runtime.defineClassUnder("ToRuby", visitor, RubyObject.OBJECT_ALLOCATOR, visitors);
48
+
49
+ psychToRuby.defineAnnotatedMethods(ToRuby.class);
50
+ classLoader.defineAnnotatedMethods(ClassLoader.class);
51
+ }
52
+
53
+ public static class ToRuby {
54
+ @JRubyMethod(visibility = PRIVATE)
55
+ public static IRubyObject build_exception(ThreadContext context, IRubyObject self, IRubyObject klass, IRubyObject message) {
56
+ if (klass instanceof RubyClass) {
57
+ IRubyObject exception = ((RubyClass)klass).allocate();
58
+ ((RubyException)exception).message = message;
59
+ return exception;
60
+ } else {
61
+ throw context.runtime.newTypeError(klass, context.runtime.getClassClass());
62
+ }
63
+ }
64
+ }
65
+
66
+ public static class ClassLoader {
67
+ @JRubyMethod(visibility = PRIVATE)
68
+ public static IRubyObject path2class(ThreadContext context, IRubyObject self, IRubyObject path) {
69
+ try {
70
+ return context.runtime.getClassFromPath(path.asJavaString());
71
+ } catch (RaiseException re) {
72
+ if (re.getException().getMetaClass() == context.runtime.getNameError()) {
73
+ throw context.runtime.newArgumentError("undefined class/module " + path);
74
+ }
75
+ throw re;
76
+ }
77
+ }
78
+ }
79
+ }