diff options
Diffstat (limited to 'ext/psych')
51 files changed, 6004 insertions, 0 deletions
diff --git a/ext/psych/.gitignore b/ext/psych/.gitignore new file mode 100644 index 0000000000..92946455b0 --- /dev/null +++ b/ext/psych/.gitignore @@ -0,0 +1 @@ +/yaml-[0-9]*.*.* diff --git a/ext/psych/depend b/ext/psych/depend new file mode 100644 index 0000000000..95175841a2 --- /dev/null +++ b/ext/psych/depend @@ -0,0 +1,906 @@ +$(TARGET_SO): $(LIBYAML) + +libyaml $(LIBYAML): + cd libyaml && $(MAKE) + $(AR) $(ARFLAGS) $(LIBYAML) $(LIBYAML_OBJDIR)/*.$(OBJEXT) + $(RANLIB) $(LIBYAML) + +clean-so:: + -cd libyaml && $(MAKE) clean + +distclean-so:: + -cd libyaml && $(MAKE) distclean + -$(Q)$(RMDIRS) libyaml/* libyaml + +# AUTOGENERATED DEPENDENCIES START +psych.o: $(RUBY_EXTCONF_H) +psych.o: $(arch_hdrdir)/ruby/config.h +psych.o: $(hdrdir)/ruby.h +psych.o: $(hdrdir)/ruby/assert.h +psych.o: $(hdrdir)/ruby/backward.h +psych.o: $(hdrdir)/ruby/backward/2/assume.h +psych.o: $(hdrdir)/ruby/backward/2/attributes.h +psych.o: $(hdrdir)/ruby/backward/2/bool.h +psych.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych.o: $(hdrdir)/ruby/backward/2/limits.h +psych.o: $(hdrdir)/ruby/backward/2/long_long.h +psych.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych.o: $(hdrdir)/ruby/defines.h +psych.o: $(hdrdir)/ruby/encoding.h +psych.o: $(hdrdir)/ruby/intern.h +psych.o: $(hdrdir)/ruby/internal/abi.h +psych.o: $(hdrdir)/ruby/internal/anyargs.h +psych.o: $(hdrdir)/ruby/internal/arithmetic.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych.o: $(hdrdir)/ruby/internal/assume.h +psych.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych.o: $(hdrdir)/ruby/internal/attr/cold.h +psych.o: $(hdrdir)/ruby/internal/attr/const.h +psych.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych.o: $(hdrdir)/ruby/internal/attr/error.h +psych.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych.o: $(hdrdir)/ruby/internal/attr/format.h +psych.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych.o: $(hdrdir)/ruby/internal/attr/pure.h +psych.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych.o: $(hdrdir)/ruby/internal/attr/warning.h +psych.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych.o: $(hdrdir)/ruby/internal/cast.h +psych.o: $(hdrdir)/ruby/internal/compiler_is.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych.o: $(hdrdir)/ruby/internal/compiler_since.h +psych.o: $(hdrdir)/ruby/internal/config.h +psych.o: $(hdrdir)/ruby/internal/constant_p.h +psych.o: $(hdrdir)/ruby/internal/core.h +psych.o: $(hdrdir)/ruby/internal/core/rarray.h +psych.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych.o: $(hdrdir)/ruby/internal/core/rclass.h +psych.o: $(hdrdir)/ruby/internal/core/rdata.h +psych.o: $(hdrdir)/ruby/internal/core/rfile.h +psych.o: $(hdrdir)/ruby/internal/core/rhash.h +psych.o: $(hdrdir)/ruby/internal/core/robject.h +psych.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych.o: $(hdrdir)/ruby/internal/core/rstring.h +psych.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych.o: $(hdrdir)/ruby/internal/ctype.h +psych.o: $(hdrdir)/ruby/internal/dllexport.h +psych.o: $(hdrdir)/ruby/internal/dosish.h +psych.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych.o: $(hdrdir)/ruby/internal/encoding/re.h +psych.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych.o: $(hdrdir)/ruby/internal/encoding/string.h +psych.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych.o: $(hdrdir)/ruby/internal/error.h +psych.o: $(hdrdir)/ruby/internal/eval.h +psych.o: $(hdrdir)/ruby/internal/event.h +psych.o: $(hdrdir)/ruby/internal/fl_type.h +psych.o: $(hdrdir)/ruby/internal/gc.h +psych.o: $(hdrdir)/ruby/internal/glob.h +psych.o: $(hdrdir)/ruby/internal/globals.h +psych.o: $(hdrdir)/ruby/internal/has/attribute.h +psych.o: $(hdrdir)/ruby/internal/has/builtin.h +psych.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych.o: $(hdrdir)/ruby/internal/has/extension.h +psych.o: $(hdrdir)/ruby/internal/has/feature.h +psych.o: $(hdrdir)/ruby/internal/has/warning.h +psych.o: $(hdrdir)/ruby/internal/intern/array.h +psych.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych.o: $(hdrdir)/ruby/internal/intern/class.h +psych.o: $(hdrdir)/ruby/internal/intern/compar.h +psych.o: $(hdrdir)/ruby/internal/intern/complex.h +psych.o: $(hdrdir)/ruby/internal/intern/cont.h +psych.o: $(hdrdir)/ruby/internal/intern/dir.h +psych.o: $(hdrdir)/ruby/internal/intern/enum.h +psych.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych.o: $(hdrdir)/ruby/internal/intern/error.h +psych.o: $(hdrdir)/ruby/internal/intern/eval.h +psych.o: $(hdrdir)/ruby/internal/intern/file.h +psych.o: $(hdrdir)/ruby/internal/intern/hash.h +psych.o: $(hdrdir)/ruby/internal/intern/io.h +psych.o: $(hdrdir)/ruby/internal/intern/load.h +psych.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych.o: $(hdrdir)/ruby/internal/intern/object.h +psych.o: $(hdrdir)/ruby/internal/intern/parse.h +psych.o: $(hdrdir)/ruby/internal/intern/proc.h +psych.o: $(hdrdir)/ruby/internal/intern/process.h +psych.o: $(hdrdir)/ruby/internal/intern/random.h +psych.o: $(hdrdir)/ruby/internal/intern/range.h +psych.o: $(hdrdir)/ruby/internal/intern/rational.h +psych.o: $(hdrdir)/ruby/internal/intern/re.h +psych.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych.o: $(hdrdir)/ruby/internal/intern/select.h +psych.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych.o: $(hdrdir)/ruby/internal/intern/set.h +psych.o: $(hdrdir)/ruby/internal/intern/signal.h +psych.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych.o: $(hdrdir)/ruby/internal/intern/string.h +psych.o: $(hdrdir)/ruby/internal/intern/struct.h +psych.o: $(hdrdir)/ruby/internal/intern/thread.h +psych.o: $(hdrdir)/ruby/internal/intern/time.h +psych.o: $(hdrdir)/ruby/internal/intern/variable.h +psych.o: $(hdrdir)/ruby/internal/intern/vm.h +psych.o: $(hdrdir)/ruby/internal/interpreter.h +psych.o: $(hdrdir)/ruby/internal/iterator.h +psych.o: $(hdrdir)/ruby/internal/memory.h +psych.o: $(hdrdir)/ruby/internal/method.h +psych.o: $(hdrdir)/ruby/internal/module.h +psych.o: $(hdrdir)/ruby/internal/newobj.h +psych.o: $(hdrdir)/ruby/internal/scan_args.h +psych.o: $(hdrdir)/ruby/internal/special_consts.h +psych.o: $(hdrdir)/ruby/internal/static_assert.h +psych.o: $(hdrdir)/ruby/internal/stdalign.h +psych.o: $(hdrdir)/ruby/internal/stdbool.h +psych.o: $(hdrdir)/ruby/internal/stdckdint.h +psych.o: $(hdrdir)/ruby/internal/symbol.h +psych.o: $(hdrdir)/ruby/internal/value.h +psych.o: $(hdrdir)/ruby/internal/value_type.h +psych.o: $(hdrdir)/ruby/internal/variable.h +psych.o: $(hdrdir)/ruby/internal/warning_push.h +psych.o: $(hdrdir)/ruby/internal/xmalloc.h +psych.o: $(hdrdir)/ruby/missing.h +psych.o: $(hdrdir)/ruby/onigmo.h +psych.o: $(hdrdir)/ruby/oniguruma.h +psych.o: $(hdrdir)/ruby/ruby.h +psych.o: $(hdrdir)/ruby/st.h +psych.o: $(hdrdir)/ruby/subst.h +psych.o: psych.c +psych.o: psych.h +psych.o: psych_emitter.h +psych.o: psych_parser.h +psych.o: psych_to_ruby.h +psych.o: psych_yaml_tree.h +psych_emitter.o: $(RUBY_EXTCONF_H) +psych_emitter.o: $(arch_hdrdir)/ruby/config.h +psych_emitter.o: $(hdrdir)/ruby.h +psych_emitter.o: $(hdrdir)/ruby/assert.h +psych_emitter.o: $(hdrdir)/ruby/backward.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/assume.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/bool.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/limits.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_emitter.o: $(hdrdir)/ruby/defines.h +psych_emitter.o: $(hdrdir)/ruby/encoding.h +psych_emitter.o: $(hdrdir)/ruby/intern.h +psych_emitter.o: $(hdrdir)/ruby/internal/abi.h +psych_emitter.o: $(hdrdir)/ruby/internal/anyargs.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/assume.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/const.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/error.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/format.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_emitter.o: $(hdrdir)/ruby/internal/cast.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_emitter.o: $(hdrdir)/ruby/internal/config.h +psych_emitter.o: $(hdrdir)/ruby/internal/constant_p.h +psych_emitter.o: $(hdrdir)/ruby/internal/core.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/robject.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_emitter.o: $(hdrdir)/ruby/internal/ctype.h +psych_emitter.o: $(hdrdir)/ruby/internal/dllexport.h +psych_emitter.o: $(hdrdir)/ruby/internal/dosish.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_emitter.o: $(hdrdir)/ruby/internal/error.h +psych_emitter.o: $(hdrdir)/ruby/internal/eval.h +psych_emitter.o: $(hdrdir)/ruby/internal/event.h +psych_emitter.o: $(hdrdir)/ruby/internal/fl_type.h +psych_emitter.o: $(hdrdir)/ruby/internal/gc.h +psych_emitter.o: $(hdrdir)/ruby/internal/glob.h +psych_emitter.o: $(hdrdir)/ruby/internal/globals.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/extension.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/feature.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/warning.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/array.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/class.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/error.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/file.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/io.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/load.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/object.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/process.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/random.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/range.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/re.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/select.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/set.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/string.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/time.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_emitter.o: $(hdrdir)/ruby/internal/interpreter.h +psych_emitter.o: $(hdrdir)/ruby/internal/iterator.h +psych_emitter.o: $(hdrdir)/ruby/internal/memory.h +psych_emitter.o: $(hdrdir)/ruby/internal/method.h +psych_emitter.o: $(hdrdir)/ruby/internal/module.h +psych_emitter.o: $(hdrdir)/ruby/internal/newobj.h +psych_emitter.o: $(hdrdir)/ruby/internal/scan_args.h +psych_emitter.o: $(hdrdir)/ruby/internal/special_consts.h +psych_emitter.o: $(hdrdir)/ruby/internal/static_assert.h +psych_emitter.o: $(hdrdir)/ruby/internal/stdalign.h +psych_emitter.o: $(hdrdir)/ruby/internal/stdbool.h +psych_emitter.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_emitter.o: $(hdrdir)/ruby/internal/symbol.h +psych_emitter.o: $(hdrdir)/ruby/internal/value.h +psych_emitter.o: $(hdrdir)/ruby/internal/value_type.h +psych_emitter.o: $(hdrdir)/ruby/internal/variable.h +psych_emitter.o: $(hdrdir)/ruby/internal/warning_push.h +psych_emitter.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_emitter.o: $(hdrdir)/ruby/missing.h +psych_emitter.o: $(hdrdir)/ruby/onigmo.h +psych_emitter.o: $(hdrdir)/ruby/oniguruma.h +psych_emitter.o: $(hdrdir)/ruby/ruby.h +psych_emitter.o: $(hdrdir)/ruby/st.h +psych_emitter.o: $(hdrdir)/ruby/subst.h +psych_emitter.o: psych.h +psych_emitter.o: psych_emitter.c +psych_emitter.o: psych_emitter.h +psych_emitter.o: psych_parser.h +psych_emitter.o: psych_to_ruby.h +psych_emitter.o: psych_yaml_tree.h +psych_parser.o: $(RUBY_EXTCONF_H) +psych_parser.o: $(arch_hdrdir)/ruby/config.h +psych_parser.o: $(hdrdir)/ruby.h +psych_parser.o: $(hdrdir)/ruby/assert.h +psych_parser.o: $(hdrdir)/ruby/backward.h +psych_parser.o: $(hdrdir)/ruby/backward/2/assume.h +psych_parser.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_parser.o: $(hdrdir)/ruby/backward/2/bool.h +psych_parser.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_parser.o: $(hdrdir)/ruby/backward/2/limits.h +psych_parser.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_parser.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_parser.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_parser.o: $(hdrdir)/ruby/defines.h +psych_parser.o: $(hdrdir)/ruby/encoding.h +psych_parser.o: $(hdrdir)/ruby/intern.h +psych_parser.o: $(hdrdir)/ruby/internal/abi.h +psych_parser.o: $(hdrdir)/ruby/internal/anyargs.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_parser.o: $(hdrdir)/ruby/internal/assume.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/const.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/error.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/format.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_parser.o: $(hdrdir)/ruby/internal/cast.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_parser.o: $(hdrdir)/ruby/internal/config.h +psych_parser.o: $(hdrdir)/ruby/internal/constant_p.h +psych_parser.o: $(hdrdir)/ruby/internal/core.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_parser.o: $(hdrdir)/ruby/internal/core/robject.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_parser.o: $(hdrdir)/ruby/internal/ctype.h +psych_parser.o: $(hdrdir)/ruby/internal/dllexport.h +psych_parser.o: $(hdrdir)/ruby/internal/dosish.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_parser.o: $(hdrdir)/ruby/internal/error.h +psych_parser.o: $(hdrdir)/ruby/internal/eval.h +psych_parser.o: $(hdrdir)/ruby/internal/event.h +psych_parser.o: $(hdrdir)/ruby/internal/fl_type.h +psych_parser.o: $(hdrdir)/ruby/internal/gc.h +psych_parser.o: $(hdrdir)/ruby/internal/glob.h +psych_parser.o: $(hdrdir)/ruby/internal/globals.h +psych_parser.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_parser.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/extension.h +psych_parser.o: $(hdrdir)/ruby/internal/has/feature.h +psych_parser.o: $(hdrdir)/ruby/internal/has/warning.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/array.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/class.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/error.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/file.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/io.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/load.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/object.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/process.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/random.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/range.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/re.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/select.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/set.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/string.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/time.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_parser.o: $(hdrdir)/ruby/internal/interpreter.h +psych_parser.o: $(hdrdir)/ruby/internal/iterator.h +psych_parser.o: $(hdrdir)/ruby/internal/memory.h +psych_parser.o: $(hdrdir)/ruby/internal/method.h +psych_parser.o: $(hdrdir)/ruby/internal/module.h +psych_parser.o: $(hdrdir)/ruby/internal/newobj.h +psych_parser.o: $(hdrdir)/ruby/internal/scan_args.h +psych_parser.o: $(hdrdir)/ruby/internal/special_consts.h +psych_parser.o: $(hdrdir)/ruby/internal/static_assert.h +psych_parser.o: $(hdrdir)/ruby/internal/stdalign.h +psych_parser.o: $(hdrdir)/ruby/internal/stdbool.h +psych_parser.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_parser.o: $(hdrdir)/ruby/internal/symbol.h +psych_parser.o: $(hdrdir)/ruby/internal/value.h +psych_parser.o: $(hdrdir)/ruby/internal/value_type.h +psych_parser.o: $(hdrdir)/ruby/internal/variable.h +psych_parser.o: $(hdrdir)/ruby/internal/warning_push.h +psych_parser.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_parser.o: $(hdrdir)/ruby/missing.h +psych_parser.o: $(hdrdir)/ruby/onigmo.h +psych_parser.o: $(hdrdir)/ruby/oniguruma.h +psych_parser.o: $(hdrdir)/ruby/ruby.h +psych_parser.o: $(hdrdir)/ruby/st.h +psych_parser.o: $(hdrdir)/ruby/subst.h +psych_parser.o: psych.h +psych_parser.o: psych_emitter.h +psych_parser.o: psych_parser.c +psych_parser.o: psych_parser.h +psych_parser.o: psych_to_ruby.h +psych_parser.o: psych_yaml_tree.h +psych_to_ruby.o: $(RUBY_EXTCONF_H) +psych_to_ruby.o: $(arch_hdrdir)/ruby/config.h +psych_to_ruby.o: $(hdrdir)/ruby.h +psych_to_ruby.o: $(hdrdir)/ruby/assert.h +psych_to_ruby.o: $(hdrdir)/ruby/backward.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/assume.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/bool.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/limits.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_to_ruby.o: $(hdrdir)/ruby/defines.h +psych_to_ruby.o: $(hdrdir)/ruby/encoding.h +psych_to_ruby.o: $(hdrdir)/ruby/intern.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/abi.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/anyargs.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/assume.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/const.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/error.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/format.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/cast.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/config.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/constant_p.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/robject.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/ctype.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/dllexport.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/dosish.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/error.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/eval.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/event.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/fl_type.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/gc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/glob.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/globals.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/extension.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/feature.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/warning.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/array.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/class.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/error.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/file.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/io.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/load.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/object.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/process.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/random.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/range.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/re.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/set.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/string.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/time.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/interpreter.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/iterator.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/memory.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/method.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/module.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/newobj.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/scan_args.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/special_consts.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/static_assert.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/stdalign.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/stdbool.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/symbol.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/value.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/value_type.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/variable.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/warning_push.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_to_ruby.o: $(hdrdir)/ruby/missing.h +psych_to_ruby.o: $(hdrdir)/ruby/onigmo.h +psych_to_ruby.o: $(hdrdir)/ruby/oniguruma.h +psych_to_ruby.o: $(hdrdir)/ruby/ruby.h +psych_to_ruby.o: $(hdrdir)/ruby/st.h +psych_to_ruby.o: $(hdrdir)/ruby/subst.h +psych_to_ruby.o: psych.h +psych_to_ruby.o: psych_emitter.h +psych_to_ruby.o: psych_parser.h +psych_to_ruby.o: psych_to_ruby.c +psych_to_ruby.o: psych_to_ruby.h +psych_to_ruby.o: psych_yaml_tree.h +psych_yaml_tree.o: $(RUBY_EXTCONF_H) +psych_yaml_tree.o: $(arch_hdrdir)/ruby/config.h +psych_yaml_tree.o: $(hdrdir)/ruby.h +psych_yaml_tree.o: $(hdrdir)/ruby/assert.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/assume.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/bool.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/limits.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_yaml_tree.o: $(hdrdir)/ruby/defines.h +psych_yaml_tree.o: $(hdrdir)/ruby/encoding.h +psych_yaml_tree.o: $(hdrdir)/ruby/intern.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/abi.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/anyargs.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/assume.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/const.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/error.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/format.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/cast.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/config.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/constant_p.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/robject.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/ctype.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/dllexport.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/dosish.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/error.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/eval.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/event.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/fl_type.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/gc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/glob.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/globals.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/extension.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/feature.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/warning.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/array.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/class.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/error.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/file.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/io.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/load.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/object.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/process.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/random.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/range.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/re.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/set.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/string.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/time.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/interpreter.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/iterator.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/memory.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/method.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/module.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/newobj.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/scan_args.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/special_consts.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/static_assert.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdalign.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdbool.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/symbol.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/value.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/value_type.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/variable.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/warning_push.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_yaml_tree.o: $(hdrdir)/ruby/missing.h +psych_yaml_tree.o: $(hdrdir)/ruby/onigmo.h +psych_yaml_tree.o: $(hdrdir)/ruby/oniguruma.h +psych_yaml_tree.o: $(hdrdir)/ruby/ruby.h +psych_yaml_tree.o: $(hdrdir)/ruby/st.h +psych_yaml_tree.o: $(hdrdir)/ruby/subst.h +psych_yaml_tree.o: psych.h +psych_yaml_tree.o: psych_emitter.h +psych_yaml_tree.o: psych_parser.h +psych_yaml_tree.o: psych_to_ruby.h +psych_yaml_tree.o: psych_yaml_tree.c +psych_yaml_tree.o: psych_yaml_tree.h +# AUTOGENERATED DEPENDENCIES END diff --git a/ext/psych/extconf.rb b/ext/psych/extconf.rb new file mode 100644 index 0000000000..589e201c1c --- /dev/null +++ b/ext/psych/extconf.rb @@ -0,0 +1,56 @@ +# -*- coding: us-ascii -*- +# frozen_string_literal: true +require 'mkmf' + +if $mswin or $mingw or $cygwin + $CPPFLAGS << " -DYAML_DECLARE_STATIC" +end + +yaml_source = with_config("libyaml-source-dir") +if yaml_source + yaml_source = yaml_source.gsub(/\$\((\w+)\)|\$\{(\w+)\}/) {ENV[$1||$2]} + yaml_source = yaml_source.chomp("/") + yaml_configure = "#{File.expand_path(yaml_source)}/configure" + unless File.exist?(yaml_configure) + raise "Configure script not found in #{yaml_source.quote}" + end + + puts("Configuring libyaml source in #{yaml_source.quote}") + yaml = "libyaml" + Dir.mkdir(yaml) unless File.directory?(yaml) + shared = $enable_shared || !$static + args = [ + yaml_configure, + "--enable-#{shared ? 'shared' : 'static'}", + "--host=#{RbConfig::CONFIG['host'].sub(/-unknown-/, '-').sub(/arm64/, 'arm')}", + "CC=#{RbConfig::CONFIG['CC']}", + *(["CFLAGS=-w"] if RbConfig::CONFIG["GCC"] == "yes"), + ] + puts(args.quote.join(' ')) + unless system(*args, chdir: yaml) + raise "failed to configure libyaml" + end + inc = yaml_source.start_with?("#$srcdir/") ? "$(srcdir)#{yaml_source[$srcdir.size..-1]}" : yaml_source + $INCFLAGS << " -I#{yaml}/include -I#{inc}/include" + puts("INCFLAGS=#$INCFLAGS") + libyaml = "libyaml.#$LIBEXT" + $cleanfiles << libyaml + $LOCAL_LIBS.prepend("$(LIBYAML) ") + + # default to pre-installed libyaml +elsif pkg_config('yaml-0.1') + # found with pkg-config +else + dir_config('libyaml') + find_header('yaml.h') or abort "yaml.h not found" + find_library('yaml', 'yaml_get_version') or abort "libyaml not found" +end + +create_makefile 'psych' do |mk| + mk << "LIBYAML = #{libyaml}".strip << "\n" + mk << "LIBYAML_OBJDIR = libyaml/src#{shared ? '/.libs' : ''}\n" + mk << "OBJEXT = #$OBJEXT" + mk << "RANLIB = #{config_string('RANLIB') || config_string('NULLCMD')}\n" +end + +# :startdoc: diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb new file mode 100644 index 0000000000..850a6d1937 --- /dev/null +++ b/ext/psych/lib/psych.rb @@ -0,0 +1,794 @@ +# frozen_string_literal: true +require 'date' + +require_relative 'psych/versions' +case RUBY_ENGINE +when 'jruby' + require_relative 'psych_jars' + if JRuby::Util.respond_to?(:load_ext) + JRuby::Util.load_ext('org.jruby.ext.psych.PsychLibrary') + else + require 'java'; require 'jruby' + org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false) + end +else + require 'psych.so' +end +require_relative 'psych/nodes' +require_relative 'psych/streaming' +require_relative 'psych/visitors' +require_relative 'psych/handler' +require_relative 'psych/tree_builder' +require_relative 'psych/parser' +require_relative 'psych/omap' +require_relative 'psych/set' +require_relative 'psych/coder' +require_relative 'psych/stream' +require_relative 'psych/json/tree_builder' +require_relative 'psych/json/stream' +require_relative 'psych/handlers/document_stream' +require_relative 'psych/class_loader' + +### +# = Overview +# +# Psych is a YAML parser and emitter. +# Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML] +# or [git repo: https://github.com/yaml/libyaml] for its YAML parsing +# and emitting capabilities. In addition to wrapping libyaml, Psych also +# knows how to serialize and de-serialize most Ruby objects to and from +# the YAML format. +# +# = I NEED TO PARSE OR EMIT YAML RIGHT NOW! +# +# # Parse some YAML +# Psych.load("--- foo") # => "foo" +# +# # Emit some YAML +# Psych.dump("foo") # => "--- foo\n...\n" +# { :a => 'b'}.to_yaml # => "---\n:a: b\n" +# +# Got more time on your hands? Keep on reading! +# +# == YAML Parsing +# +# Psych provides a range of interfaces for parsing a YAML document ranging from +# low level to high level, depending on your parsing needs. At the lowest +# level, is an event based parser. Mid level is access to the raw YAML AST, +# and at the highest level is the ability to unmarshal YAML to Ruby objects. +# +# == YAML Emitting +# +# Psych provides a range of interfaces ranging from low to high level for +# producing YAML documents. Very similar to the YAML parsing interfaces, Psych +# provides at the lowest level, an event based system, mid-level is building +# a YAML AST, and the highest level is converting a Ruby object straight to +# a YAML document. +# +# == High-level API +# +# === Parsing +# +# The high level YAML parser provided by Psych simply takes YAML as input and +# returns a Ruby data structure. For information on using the high level parser +# see Psych.load +# +# ==== Reading from a string +# +# Psych.safe_load("--- a") # => 'a' +# Psych.safe_load("---\n - a\n - b") # => ['a', 'b'] +# # From a trusted string: +# Psych.load("--- !ruby/range\nbegin: 0\nend: 42\nexcl: false\n") # => 0..42 +# +# ==== Reading from a file +# +# Psych.safe_load_file("data.yml", permitted_classes: [Date]) +# Psych.load_file("trusted_database.yml") +# +# ==== \Exception handling +# +# begin +# # The second argument changes only the exception contents +# Psych.parse("--- `", "file.txt") +# rescue Psych::SyntaxError => ex +# ex.file # => 'file.txt' +# ex.message # => "(file.txt): found character that cannot start any token" +# end +# +# === Emitting +# +# The high level emitter has the easiest interface. Psych simply takes a Ruby +# data structure and converts it to a YAML document. See Psych.dump for more +# information on dumping a Ruby data structure. +# +# ==== Writing to a string +# +# # Dump an array, get back a YAML string +# Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" +# +# # Dump an array to an IO object +# Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> +# +# # Dump an array with indentation set +# Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" +# +# # Dump an array to an IO with indentation set +# Psych.dump(['a', ['b']], StringIO.new, :indentation => 3) +# +# ==== Writing to a file +# +# Currently there is no direct API for dumping Ruby structure to file: +# +# File.open('database.yml', 'w') do |file| +# file.write(Psych.dump(['a', 'b'])) +# end +# +# == Mid-level API +# +# === Parsing +# +# Psych provides access to an AST produced from parsing a YAML document. This +# tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can +# be examined and manipulated freely. Please see Psych::parse_stream, +# Psych::Nodes, and Psych::Nodes::Node for more information on dealing with +# YAML syntax trees. +# +# ==== Reading from a string +# +# # Returns Psych::Nodes::Stream +# Psych.parse_stream("---\n - a\n - b") +# +# # Returns Psych::Nodes::Document +# Psych.parse("---\n - a\n - b") +# +# ==== Reading from a file +# +# # Returns Psych::Nodes::Stream +# Psych.parse_stream(File.read('database.yml')) +# +# # Returns Psych::Nodes::Document +# Psych.parse_file('database.yml') +# +# ==== \Exception handling +# +# begin +# # The second argument changes only the exception contents +# Psych.parse("--- `", "file.txt") +# rescue Psych::SyntaxError => ex +# ex.file # => 'file.txt' +# ex.message # => "(file.txt): found character that cannot start any token" +# end +# +# === Emitting +# +# At the mid level is building an AST. This AST is exactly the same as the AST +# used when parsing a YAML document. Users can build an AST by hand and the +# AST knows how to emit itself as a YAML document. See Psych::Nodes, +# Psych::Nodes::Node, and Psych::TreeBuilder for more information on building +# a YAML AST. +# +# ==== Writing to a string +# +# # We need Psych::Nodes::Stream (not Psych::Nodes::Document) +# stream = Psych.parse_stream("---\n - a\n - b") +# +# stream.to_yaml # => "---\n- a\n- b\n" +# +# ==== Writing to a file +# +# # We need Psych::Nodes::Stream (not Psych::Nodes::Document) +# stream = Psych.parse_stream(File.read('database.yml')) +# +# File.open('database.yml', 'w') do |file| +# file.write(stream.to_yaml) +# end +# +# == Low-level API +# +# === Parsing +# +# The lowest level parser should be used when the YAML input is already known, +# and the developer does not want to pay the price of building an AST or +# automatic detection and conversion to Ruby objects. See Psych::Parser for +# more information on using the event based parser. +# +# ==== Reading to Psych::Nodes::Stream structure +# +# parser = Psych::Parser.new(TreeBuilder.new) # => #<Psych::Parser> +# parser = Psych.parser # it's an alias for the above +# +# parser.parse("---\n - a\n - b") # => #<Psych::Parser> +# parser.handler # => #<Psych::TreeBuilder> +# parser.handler.root # => #<Psych::Nodes::Stream> +# +# ==== Receiving an events stream +# +# recorder = Psych::Handlers::Recorder.new +# parser = Psych::Parser.new(recorder) +# +# parser.parse("---\n - a\n - b") +# recorder.events # => [list of [event, args] lists] +# # event is one of: Psych::Handler::EVENTS +# # args are the arguments passed to the event +# +# === Emitting +# +# The lowest level emitter is an event based system. Events are sent to a +# Psych::Emitter object. That object knows how to convert the events to a YAML +# document. This interface should be used when document format is known in +# advance or speed is a concern. See Psych::Emitter for more information. +# +# ==== Writing to a Ruby structure +# +# Psych.parser.parse("--- a") # => #<Psych::Parser> +# +# parser.handler.first # => #<Psych::Nodes::Stream> +# parser.handler.first.to_ruby # => ["a"] +# +# parser.handler.root.first # => #<Psych::Nodes::Document> +# parser.handler.root.first.to_ruby # => "a" +# +# # You can instantiate an Emitter manually +# Psych::Visitors::ToRuby.new.accept(parser.handler.root.first) +# # => "a" + +module Psych + # The version of libyaml Psych is using + LIBYAML_VERSION = Psych.libyaml_version.join('.').freeze + + ### + # Load +yaml+ in to a Ruby data structure. If multiple documents are + # provided, the object contained in the first document will be returned. + # +filename+ will be used in the exception message if any exception + # is raised while parsing. If +yaml+ is empty, it returns + # the specified +fallback+ return value, which defaults to +false+. + # + # Raises a Psych::SyntaxError when a YAML syntax error is detected. + # + # Example: + # + # Psych.unsafe_load("--- a") # => 'a' + # Psych.unsafe_load("---\n - a\n - b") # => ['a', 'b'] + # + # begin + # Psych.unsafe_load("--- `", filename: "file.txt") + # rescue Psych::SyntaxError => ex + # ex.file # => 'file.txt' + # ex.message # => "(file.txt): found character that cannot start any token" + # end + # + # When the optional +symbolize_names+ keyword argument is set to a + # true value, returns symbols for keys in Hash objects (default: strings). + # + # Psych.unsafe_load("---\n foo: bar") # => {"foo"=>"bar"} + # Psych.unsafe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} + # + # Raises a TypeError when `yaml` parameter is NilClass + # + # NOTE: This method *should not* be used to parse untrusted documents, such as + # YAML documents that are supplied via user input. Instead, please use the + # load method or the safe_load method. + # + def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true + result = parse(yaml, filename: filename) + return fallback unless result + result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols) + end + + ### + # Safely load the yaml string in +yaml+. By default, only the following + # classes are allowed to be deserialized: + # + # * TrueClass + # * FalseClass + # * NilClass + # * Integer + # * Float + # * String + # * Array + # * Hash + # + # Recursive data structures are not allowed by default. Arbitrary classes + # can be allowed by adding those classes to the +permitted_classes+ keyword argument. They are + # additive. For example, to allow Date deserialization: + # + # Psych.safe_load(yaml, permitted_classes: [Date]) + # + # Now the Date class can be loaded in addition to the classes listed above. + # + # Aliases can be explicitly allowed by changing the +aliases+ keyword argument. + # For example: + # + # x = [] + # x << x + # yaml = Psych.dump x + # Psych.safe_load yaml # => raises an exception + # Psych.safe_load yaml, aliases: true # => loads the aliases + # + # A Psych::DisallowedClass exception will be raised if the yaml contains a + # class that isn't in the +permitted_classes+ list. + # + # A Psych::AliasesNotEnabled exception will be raised if the yaml contains aliases + # but the +aliases+ keyword argument is set to false. + # + # +filename+ will be used in the exception message if any exception is raised + # while parsing. + # + # When the optional +symbolize_names+ keyword argument is set to a + # true value, returns symbols for keys in Hash objects (default: strings). + # + # Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"} + # Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} + # + def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true + result = parse(yaml, filename: filename) + return fallback unless result + + class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s), + permitted_symbols.map(&:to_s)) + scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols + visitor = if aliases + Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze + else + Visitors::NoAliasRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze + end + result = visitor.accept result + result + end + + ### + # Load +yaml+ in to a Ruby data structure. If multiple documents are + # provided, the object contained in the first document will be returned. + # +filename+ will be used in the exception message if any exception + # is raised while parsing. If +yaml+ is empty, it returns + # the specified +fallback+ return value, which defaults to +nil+. + # + # Raises a Psych::SyntaxError when a YAML syntax error is detected. + # + # Example: + # + # Psych.load("--- a") # => 'a' + # Psych.load("---\n - a\n - b") # => ['a', 'b'] + # + # begin + # Psych.load("--- `", filename: "file.txt") + # rescue Psych::SyntaxError => ex + # ex.file # => 'file.txt' + # ex.message # => "(file.txt): found character that cannot start any token" + # end + # + # When the optional +symbolize_names+ keyword argument is set to a + # true value, returns symbols for keys in Hash objects (default: strings). + # + # Psych.load("---\n foo: bar") # => {"foo"=>"bar"} + # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} + # + # Raises a TypeError when `yaml` parameter is NilClass. This method is + # similar to `safe_load` except that `Symbol` objects are allowed by default. + # + def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true + safe_load yaml, permitted_classes: permitted_classes, + permitted_symbols: permitted_symbols, + aliases: aliases, + filename: filename, + fallback: fallback, + symbolize_names: symbolize_names, + freeze: freeze, + strict_integer: strict_integer, + parse_symbols: parse_symbols + end + + ### + # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Document. + # +filename+ is used in the exception message if a Psych::SyntaxError is + # raised. + # + # Raises a Psych::SyntaxError when a YAML syntax error is detected. + # + # Example: + # + # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00> + # + # begin + # Psych.parse("--- `", filename: "file.txt") + # rescue Psych::SyntaxError => ex + # ex.file # => 'file.txt' + # ex.message # => "(file.txt): found character that cannot start any token" + # end + # + # See Psych::Nodes for more information about YAML AST. + def self.parse yaml, filename: nil + parse_stream(yaml, filename: filename) do |node| + return node + end + + false + end + + ### + # Parse a file at +filename+. Returns the Psych::Nodes::Document. + # + # Raises a Psych::SyntaxError when a YAML syntax error is detected. + def self.parse_file filename, fallback: false + result = File.open filename, 'r:bom|utf-8' do |f| + parse f, filename: filename + end + result || fallback + end + + ### + # Returns a default parser + def self.parser + Psych::Parser.new(TreeBuilder.new) + end + + ### + # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Stream. + # This method can handle multiple YAML documents contained in +yaml+. + # +filename+ is used in the exception message if a Psych::SyntaxError is + # raised. + # + # If a block is given, a Psych::Nodes::Document node will be yielded to the + # block as it's being parsed. + # + # Raises a Psych::SyntaxError when a YAML syntax error is detected. + # + # Example: + # + # Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00> + # + # Psych.parse_stream("--- a\n--- b") do |node| + # node # => #<Psych::Nodes::Document:0x00> + # end + # + # begin + # Psych.parse_stream("--- `", filename: "file.txt") + # rescue Psych::SyntaxError => ex + # ex.file # => 'file.txt' + # ex.message # => "(file.txt): found character that cannot start any token" + # end + # + # Raises a TypeError when NilClass is passed. + # + # See Psych::Nodes for more information about YAML AST. + def self.parse_stream yaml, filename: nil, &block + if block_given? + parser = Psych::Parser.new(Handlers::DocumentStream.new(&block)) + parser.parse yaml, filename + else + parser = self.parser + parser.parse yaml, filename + parser.handler.root + end + end + + ### + # call-seq: + # Psych.dump(o) -> string of yaml + # Psych.dump(o, options) -> string of yaml + # Psych.dump(o, io) -> io object passed in + # Psych.dump(o, io, options) -> io object passed in + # + # Dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in + # to control the output format. If an IO object is passed in, the YAML will + # be dumped to that IO object. + # + # Currently supported options are: + # + # [<tt>:indentation</tt>] Number of space characters used to indent. + # Acceptable value should be in <tt>0..9</tt> range, + # otherwise option is ignored. + # + # Default: <tt>2</tt>. + # [<tt>:line_width</tt>] Max character to wrap line at. + # For unlimited line width use <tt>-1</tt>. + # + # Default: <tt>0</tt> (meaning "wrap at 81"). + # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet + # strictly formal). + # + # Default: <tt>false</tt>. + # [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document. + # + # Default: <tt>false</tt>. + # + # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string. + # + # Default: <tt>false</tt>. + # + # Example: + # + # # Dump an array, get back a YAML string + # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" + # + # # Dump an array to an IO object + # Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> + # + # # Dump an array with indentation set + # Psych.dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n" + # + # # Dump an array to an IO with indentation set + # Psych.dump(['a', ['b']], StringIO.new, indentation: 3) + # + # # Dump hash with symbol keys as string + # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n" + def self.dump o, io = nil, options = {} + if Hash === io + options = io + io = nil + end + + visitor = Psych::Visitors::YAMLTree.create options + visitor << o + visitor.tree.yaml io, options + end + + ### + # call-seq: + # Psych.safe_dump(o) -> string of yaml + # Psych.safe_dump(o, options) -> string of yaml + # Psych.safe_dump(o, io) -> io object passed in + # Psych.safe_dump(o, io, options) -> io object passed in + # + # Safely dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in + # to control the output format. If an IO object is passed in, the YAML will + # be dumped to that IO object. By default, only the following + # classes are allowed to be serialized: + # + # * TrueClass + # * FalseClass + # * NilClass + # * Integer + # * Float + # * String + # * Array + # * Hash + # + # Arbitrary classes can be allowed by adding those classes to the +permitted_classes+ + # keyword argument. They are additive. For example, to allow Date serialization: + # + # Psych.safe_dump(yaml, permitted_classes: [Date]) + # + # Now the Date class can be dumped in addition to the classes listed above. + # + # A Psych::DisallowedClass exception will be raised if the object contains a + # class that isn't in the +permitted_classes+ list. + # + # Currently supported options are: + # + # [<tt>:indentation</tt>] Number of space characters used to indent. + # Acceptable value should be in <tt>0..9</tt> range, + # otherwise option is ignored. + # + # Default: <tt>2</tt>. + # [<tt>:line_width</tt>] Max character to wrap line at. + # For unlimited line width use <tt>-1</tt>. + # + # Default: <tt>0</tt> (meaning "wrap at 81"). + # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet + # strictly formal). + # + # Default: <tt>false</tt>. + # [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document. + # + # Default: <tt>false</tt>. + # + # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string. + # + # Default: <tt>false</tt>. + # + # Example: + # + # # Dump an array, get back a YAML string + # Psych.safe_dump(['a', 'b']) # => "---\n- a\n- b\n" + # + # # Dump an array to an IO object + # Psych.safe_dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> + # + # # Dump an array with indentation set + # Psych.safe_dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n" + # + # # Dump an array to an IO with indentation set + # Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3) + # + # # Dump hash with symbol keys as string + # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n" + def self.safe_dump o, io = nil, options = {} + if Hash === io + options = io + io = nil + end + + visitor = Psych::Visitors::RestrictedYAMLTree.create options + visitor << o + visitor.tree.yaml io, options + end + + ### + # Dump a list of objects as separate documents to a document stream. + # + # Example: + # + # Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n" + def self.dump_stream *objects + visitor = Psych::Visitors::YAMLTree.create({}) + objects.each do |o| + visitor << o + end + visitor.tree.yaml + end + + ### + # Dump Ruby +object+ to a JSON string. + def self.to_json object + visitor = Psych::Visitors::JSONTree.create + visitor << object + visitor.tree.yaml + end + + ### + # Load multiple documents given in +yaml+. Returns the parsed documents + # as a list. If a block is given, each document will be converted to Ruby + # and passed to the block during parsing + # + # Example: + # + # Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] + # + # list = [] + # Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby| + # list << ruby + # end + # list # => ['foo', 'bar'] + # + def self.load_stream yaml, filename: nil, fallback: [], **kwargs + result = if block_given? + parse_stream(yaml, filename: filename) do |node| + yield node.to_ruby(**kwargs) + end + else + parse_stream(yaml, filename: filename).children.map { |node| node.to_ruby(**kwargs) } + end + + return fallback if result.is_a?(Array) && result.empty? + result + end + + ### + # Load multiple documents given in +yaml+. Returns the parsed documents + # as a list. + # + # Example: + # + # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] + # + # list = [] + # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") do |ruby| + # list << ruby + # end + # list # => ['foo', 'bar'] + # + def self.safe_load_stream yaml, filename: nil, permitted_classes: [], aliases: false + documents = parse_stream(yaml, filename: filename).children.map do |child| + stream = Psych::Nodes::Stream.new + stream.children << child + safe_load(stream.to_yaml, permitted_classes: permitted_classes, aliases: aliases) + end + + if block_given? + documents.each { |doc| yield doc } + nil + else + documents + end + end + + ### + # Load the document contained in +filename+. Returns the yaml contained in + # +filename+ as a Ruby object, or if the file is empty, it returns + # the specified +fallback+ return value, which defaults to +false+. + # + # NOTE: This method *should not* be used to parse untrusted documents, such as + # YAML documents that are supplied via user input. Instead, please use the + # safe_load_file method. + def self.unsafe_load_file filename, **kwargs + File.open(filename, 'r:bom|utf-8') { |f| + self.unsafe_load f, filename: filename, **kwargs + } + end + + ### + # Safely loads the document contained in +filename+. Returns the yaml contained in + # +filename+ as a Ruby object, or if the file is empty, it returns + # the specified +fallback+ return value, which defaults to +nil+. + # See safe_load for options. + def self.safe_load_file filename, **kwargs + File.open(filename, 'r:bom|utf-8') { |f| + self.safe_load f, filename: filename, **kwargs + } + end + + ### + # Loads the document contained in +filename+. Returns the yaml contained in + # +filename+ as a Ruby object, or if the file is empty, it returns + # the specified +fallback+ return value, which defaults to +nil+. + # See load for options. + def self.load_file filename, **kwargs + File.open(filename, 'r:bom|utf-8') { |f| + self.load f, filename: filename, **kwargs + } + end + + # :stopdoc: + def self.add_domain_type domain, type_tag, &block + key = ['tag', domain, type_tag].join ':' + domain_types[key] = [key, block] + domain_types["tag:#{type_tag}"] = [key, block] + end + + def self.add_builtin_type type_tag, &block + domain = 'yaml.org,2002' + key = ['tag', domain, type_tag].join ':' + domain_types[key] = [key, block] + end + + def self.remove_type type_tag + domain_types.delete type_tag + end + + def self.add_tag tag, klass + load_tags[tag] = klass.name + dump_tags[klass] = tag + end + + class << self + if defined?(Ractor) + class Config + attr_accessor :load_tags, :dump_tags, :domain_types + def initialize + @load_tags = {} + @dump_tags = {} + @domain_types = {} + end + end + + def config + Ractor.current[:PsychConfig] ||= Config.new + end + + def load_tags + config.load_tags + end + + def dump_tags + config.dump_tags + end + + def domain_types + config.domain_types + end + + def load_tags=(value) + config.load_tags = value + end + + def dump_tags=(value) + config.dump_tags = value + end + + def domain_types=(value) + config.domain_types = value + end + else + attr_accessor :load_tags + attr_accessor :dump_tags + attr_accessor :domain_types + end + end + self.load_tags = {} + self.dump_tags = {} + self.domain_types = {} + # :startdoc: +end + +require_relative 'psych/core_ext' diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb new file mode 100644 index 0000000000..c8f509720a --- /dev/null +++ b/ext/psych/lib/psych/class_loader.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true +require_relative 'omap' +require_relative 'set' + +module Psych + class ClassLoader # :nodoc: + BIG_DECIMAL = 'BigDecimal' + COMPLEX = 'Complex' + DATA = 'Data' unless RUBY_VERSION < "3.2" + DATE = 'Date' + DATE_TIME = 'DateTime' + EXCEPTION = 'Exception' + OBJECT = 'Object' + PSYCH_OMAP = 'Psych::Omap' + PSYCH_SET = 'Psych::Set' + RANGE = 'Range' + RATIONAL = 'Rational' + REGEXP = 'Regexp' + STRUCT = 'Struct' + SYMBOL = 'Symbol' + + def initialize + @cache = CACHE.dup + end + + def load klassname + return nil if !klassname || klassname.empty? + + find klassname + end + + def symbolize sym + symbol + sym.to_sym + end + + constants.each do |const| + konst = const_get const + class_eval <<~RUBY, __FILE__, __LINE__ + 1 + def #{const.to_s.downcase} + load #{konst.inspect} + end + RUBY + end + + private + + def find klassname + @cache[klassname] ||= resolve(klassname) + end + + def resolve klassname + name = klassname + retried = false + + begin + path2class(name) + rescue ArgumentError, NameError => ex + unless retried + name = "Struct::#{name}" + retried = ex + retry + end + raise retried + end + end + + CACHE = Hash[constants.map { |const| + val = const_get const + begin + [val, ::Object.const_get(val)] + rescue + nil + end + }.compact].freeze + + class Restricted < ClassLoader + def initialize classes, symbols + @classes = classes + @symbols = symbols + super() + end + + def symbolize sym + return super if @symbols.empty? + + if @symbols.include? sym + super + else + raise DisallowedClass.new('load', 'Symbol') + end + end + + private + + def find klassname + if @classes.include? klassname + super + else + raise DisallowedClass.new('load', klassname) + end + end + end + end +end diff --git a/ext/psych/lib/psych/coder.rb b/ext/psych/lib/psych/coder.rb new file mode 100644 index 0000000000..96a9c3fbad --- /dev/null +++ b/ext/psych/lib/psych/coder.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true +module Psych + ### + # If an object defines +encode_with+, then an instance of Psych::Coder will + # be passed to the method when the object is being serialized. The Coder + # automatically assumes a Psych::Nodes::Mapping is being emitted. Other + # objects like Sequence and Scalar may be emitted if +seq=+ or +scalar=+ are + # called, respectively. + class Coder + attr_accessor :tag, :style, :implicit, :object + attr_reader :type, :seq + + def initialize tag + @map = {} + @seq = [] + @implicit = false + @type = :map + @tag = tag + @style = Psych::Nodes::Mapping::BLOCK + @scalar = nil + @object = nil + end + + def scalar *args + if args.length > 0 + warn "#{caller[0]}: Coder#scalar(a,b,c) is deprecated" if $VERBOSE + @tag, @scalar, _ = args + @type = :scalar + end + @scalar + end + + # Emit a map. The coder will be yielded to the block. + def map tag = @tag, style = @style + @tag = tag + @style = style + yield self if block_given? + @map + end + + # Emit a scalar with +value+ and +tag+ + def represent_scalar tag, value + self.tag = tag + self.scalar = value + end + + # Emit a sequence with +list+ and +tag+ + def represent_seq tag, list + @tag = tag + self.seq = list + end + + # Emit a sequence with +map+ and +tag+ + def represent_map tag, map + @tag = tag + self.map = map + end + + # Emit an arbitrary object +obj+ and +tag+ + def represent_object tag, obj + @tag = tag + @type = :object + @object = obj + end + + # Emit a scalar with +value+ + def scalar= value + @type = :scalar + @scalar = value + end + + # Emit a map with +value+ + def map= map + @type = :map + @map = map + end + + def []= k, v + @type = :map + @map[k] = v + end + alias :add :[]= + + def [] k + @type = :map + @map[k] + end + + # Emit a sequence of +list+ + def seq= list + @type = :seq + @seq = list + end + end +end diff --git a/ext/psych/lib/psych/core_ext.rb b/ext/psych/lib/psych/core_ext.rb new file mode 100644 index 0000000000..6dfd0f1696 --- /dev/null +++ b/ext/psych/lib/psych/core_ext.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +class Object + def self.yaml_tag url + Psych.add_tag(url, self) + end + + ### + # call-seq: to_yaml(options = {}) + # + # Convert an object to YAML. See Psych.dump for more information on the + # available +options+. + def to_yaml options = {} + Psych.dump self, options + end +end + +# Up to Ruby 3.4, Set was a regular object and was dumped as such +# by Pysch. +# Starting from Ruby 4.0 it's a core class written in C, so we have to implement +# #encode_with / #init_with to preserve backward compatibility. +if defined?(::Set) && Set.new.instance_variables.empty? + class Set + def encode_with(coder) + hash = {} + each do |m| + hash[m] = true + end + coder["hash"] = hash + coder + end + + def init_with(coder) + replace(coder["hash"].keys) + end + end +end diff --git a/ext/psych/lib/psych/exception.rb b/ext/psych/lib/psych/exception.rb new file mode 100644 index 0000000000..d7469a4b30 --- /dev/null +++ b/ext/psych/lib/psych/exception.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +module Psych + class Exception < RuntimeError + end + + class BadAlias < Exception + end + + # Subclasses `BadAlias` for backwards compatibility + class AliasesNotEnabled < BadAlias + def initialize + super "Alias parsing was not enabled. To enable it, pass `aliases: true` to `Psych::load` or `Psych::safe_load`." + end + end + + # Subclasses `BadAlias` for backwards compatibility + class AnchorNotDefined < BadAlias + def initialize anchor_name + super "An alias referenced an unknown anchor: #{anchor_name}" + end + end + + class DisallowedClass < Exception + def initialize action, klass_name + super "Tried to #{action} unspecified class: #{klass_name}" + end + end +end diff --git a/ext/psych/lib/psych/handler.rb b/ext/psych/lib/psych/handler.rb new file mode 100644 index 0000000000..ad7249ff77 --- /dev/null +++ b/ext/psych/lib/psych/handler.rb @@ -0,0 +1,255 @@ +# frozen_string_literal: true +module Psych + ### + # Psych::Handler is an abstract base class that defines the events used + # when dealing with Psych::Parser. Clients who want to use Psych::Parser + # should implement a class that inherits from Psych::Handler and define + # events that they can handle. + # + # Psych::Handler defines all events that Psych::Parser can possibly send to + # event handlers. + # + # See Psych::Parser for more details + class Handler + ### + # Configuration options for dumping YAML. + class DumperOptions + attr_accessor :line_width, :indentation, :canonical + + def initialize + @line_width = 0 + @indentation = 2 + @canonical = false + end + end + + # Default dumping options + OPTIONS = DumperOptions.new + + # Events that a Handler should respond to. + EVENTS = [ :alias, + :empty, + :end_document, + :end_mapping, + :end_sequence, + :end_stream, + :scalar, + :start_document, + :start_mapping, + :start_sequence, + :start_stream ] + + ### + # Called with +encoding+ when the YAML stream starts. This method is + # called once per stream. A stream may contain multiple documents. + # + # See the constants in Psych::Parser for the possible values of +encoding+. + def start_stream encoding + end + + ### + # Called when the document starts with the declared +version+, + # +tag_directives+, if the document is +implicit+. + # + # +version+ will be an array of integers indicating the YAML version being + # dealt with, +tag_directives+ is a list of tuples indicating the prefix + # and suffix of each tag, and +implicit+ is a boolean indicating whether + # the document is started implicitly. + # + # === Example + # + # Given the following YAML: + # + # %YAML 1.1 + # %TAG ! tag:tenderlovemaking.com,2009: + # --- !squee + # + # The parameters for start_document must be this: + # + # version # => [1, 1] + # tag_directives # => [["!", "tag:tenderlovemaking.com,2009:"]] + # implicit # => false + def start_document version, tag_directives, implicit + end + + ### + # Called with the document ends. +implicit+ is a boolean value indicating + # whether or not the document has an implicit ending. + # + # === Example + # + # Given the following YAML: + # + # --- + # hello world + # + # +implicit+ will be true. Given this YAML: + # + # --- + # hello world + # ... + # + # +implicit+ will be false. + def end_document implicit + end + + ### + # Called when an alias is found to +anchor+. +anchor+ will be the name + # of the anchor found. + # + # === Example + # + # Here we have an example of an array that references itself in YAML: + # + # --- &ponies + # - first element + # - *ponies + # + # &ponies is the anchor, *ponies is the alias. In this case, alias is + # called with "ponies". + def alias anchor + end + + ### + # Called when a scalar +value+ is found. The scalar may have an + # +anchor+, a +tag+, be implicitly +plain+ or implicitly +quoted+ + # + # +value+ is the string value of the scalar + # +anchor+ is an associated anchor or nil + # +tag+ is an associated tag or nil + # +plain+ is a boolean value + # +quoted+ is a boolean value + # +style+ is an integer indicating the string style + # + # See the constants in Psych::Nodes::Scalar for the possible values of + # +style+ + # + # === Example + # + # Here is a YAML document that exercises most of the possible ways this + # method can be called: + # + # --- + # - !str "foo" + # - &anchor fun + # - many + # lines + # - | + # many + # newlines + # + # The above YAML document contains a list with four strings. Here are + # the parameters sent to this method in the same order: + # + # # value anchor tag plain quoted style + # ["foo", nil, "!str", false, false, 3 ] + # ["fun", "anchor", nil, true, false, 1 ] + # ["many lines", nil, nil, true, false, 1 ] + # ["many\nnewlines\n", nil, nil, false, true, 4 ] + # + def scalar value, anchor, tag, plain, quoted, style + end + + ### + # Called when a sequence is started. + # + # +anchor+ is the anchor associated with the sequence or nil. + # +tag+ is the tag associated with the sequence or nil. + # +implicit+ a boolean indicating whether or not the sequence was implicitly + # started. + # +style+ is an integer indicating the list style. + # + # See the constants in Psych::Nodes::Sequence for the possible values of + # +style+. + # + # === Example + # + # Here is a YAML document that exercises most of the possible ways this + # method can be called: + # + # --- + # - !!seq [ + # a + # ] + # - &pewpew + # - b + # + # The above YAML document consists of three lists, an outer list that + # contains two inner lists. Here is a matrix of the parameters sent + # to represent these lists: + # + # # anchor tag implicit style + # [nil, nil, true, 1 ] + # [nil, "tag:yaml.org,2002:seq", false, 2 ] + # ["pewpew", nil, true, 1 ] + + def start_sequence anchor, tag, implicit, style + end + + ### + # Called when a sequence ends. + def end_sequence + end + + ### + # Called when a map starts. + # + # +anchor+ is the anchor associated with the map or +nil+. + # +tag+ is the tag associated with the map or +nil+. + # +implicit+ is a boolean indicating whether or not the map was implicitly + # started. + # +style+ is an integer indicating the mapping style. + # + # See the constants in Psych::Nodes::Mapping for the possible values of + # +style+. + # + # === Example + # + # Here is a YAML document that exercises most of the possible ways this + # method can be called: + # + # --- + # k: !!map { hello: world } + # v: &pewpew + # hello: world + # + # The above YAML document consists of three maps, an outer map that contains + # two inner maps. Below is a matrix of the parameters sent in order to + # represent these three maps: + # + # # anchor tag implicit style + # [nil, nil, true, 1 ] + # [nil, "tag:yaml.org,2002:map", false, 2 ] + # ["pewpew", nil, true, 1 ] + + def start_mapping anchor, tag, implicit, style + end + + ### + # Called when a map ends + def end_mapping + end + + ### + # Called when an empty event happens. (Which, as far as I can tell, is + # never). + def empty + end + + ### + # Called when the YAML stream ends + def end_stream + end + + ### + # Called before each event with line/column information. + def event_location(start_line, start_column, end_line, end_column) + end + + ### + # Is this handler a streaming handler? + def streaming? + false + end + end +end diff --git a/ext/psych/lib/psych/handlers/document_stream.rb b/ext/psych/lib/psych/handlers/document_stream.rb new file mode 100644 index 0000000000..b77115d074 --- /dev/null +++ b/ext/psych/lib/psych/handlers/document_stream.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +require_relative '../tree_builder' + +module Psych + module Handlers + class DocumentStream < Psych::TreeBuilder # :nodoc: + def initialize &block + super + @block = block + end + + def start_document version, tag_directives, implicit + n = Nodes::Document.new version, tag_directives, implicit + push n + end + + def end_document implicit_end = !streaming? + @last.implicit_end = implicit_end + @block.call pop + end + end + end +end diff --git a/ext/psych/lib/psych/handlers/recorder.rb b/ext/psych/lib/psych/handlers/recorder.rb new file mode 100644 index 0000000000..c98724cb76 --- /dev/null +++ b/ext/psych/lib/psych/handlers/recorder.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +require_relative '../handler' + +module Psych + module Handlers + ### + # This handler will capture an event and record the event. Recorder events + # are available vial Psych::Handlers::Recorder#events. + # + # For example: + # + # recorder = Psych::Handlers::Recorder.new + # parser = Psych::Parser.new recorder + # parser.parse '--- foo' + # + # recorder.events # => [list of events] + # + # # Replay the events + # + # emitter = Psych::Emitter.new $stdout + # recorder.events.each do |m, args| + # emitter.send m, *args + # end + + class Recorder < Psych::Handler + attr_reader :events + + def initialize + @events = [] + super + end + + EVENTS.each do |event| + define_method event do |*args| + @events << [event, args] + end + end + end + end +end diff --git a/ext/psych/lib/psych/json/ruby_events.rb b/ext/psych/lib/psych/json/ruby_events.rb new file mode 100644 index 0000000000..17b7ddc386 --- /dev/null +++ b/ext/psych/lib/psych/json/ruby_events.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +module Psych + module JSON + module RubyEvents # :nodoc: + def visit_Time o + formatted = format_time o + @emitter.scalar formatted, nil, nil, false, true, Nodes::Scalar::DOUBLE_QUOTED + end + + def visit_DateTime o + visit_Time o.to_time + end + + def visit_String o + @emitter.scalar o.to_s, nil, nil, false, true, Nodes::Scalar::DOUBLE_QUOTED + end + alias :visit_Symbol :visit_String + end + end +end diff --git a/ext/psych/lib/psych/json/stream.rb b/ext/psych/lib/psych/json/stream.rb new file mode 100644 index 0000000000..24dd4b9baf --- /dev/null +++ b/ext/psych/lib/psych/json/stream.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +require_relative 'ruby_events' +require_relative 'yaml_events' + +module Psych + module JSON + class Stream < Psych::Visitors::JSONTree + include Psych::JSON::RubyEvents + include Psych::Streaming + extend Psych::Streaming::ClassMethods + + class Emitter < Psych::Stream::Emitter # :nodoc: + include Psych::JSON::YAMLEvents + end + end + end +end diff --git a/ext/psych/lib/psych/json/tree_builder.rb b/ext/psych/lib/psych/json/tree_builder.rb new file mode 100644 index 0000000000..9a45f6b94c --- /dev/null +++ b/ext/psych/lib/psych/json/tree_builder.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +require_relative 'yaml_events' + +module Psych + module JSON + ### + # Psych::JSON::TreeBuilder is an event based AST builder. Events are sent + # to an instance of Psych::JSON::TreeBuilder and a JSON AST is constructed. + class TreeBuilder < Psych::TreeBuilder + include Psych::JSON::YAMLEvents + end + end +end diff --git a/ext/psych/lib/psych/json/yaml_events.rb b/ext/psych/lib/psych/json/yaml_events.rb new file mode 100644 index 0000000000..eb973f5361 --- /dev/null +++ b/ext/psych/lib/psych/json/yaml_events.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +module Psych + module JSON + module YAMLEvents # :nodoc: + def start_document version, tag_directives, implicit + super(version, tag_directives, !streaming?) + end + + def end_document implicit_end = !streaming? + super(implicit_end) + end + + def start_mapping anchor, tag, implicit, style + super(anchor, nil, true, Nodes::Mapping::FLOW) + end + + def start_sequence anchor, tag, implicit, style + super(anchor, nil, true, Nodes::Sequence::FLOW) + end + + def scalar value, anchor, tag, plain, quoted, style + if "tag:yaml.org,2002:null" == tag + super('null', nil, nil, true, false, Nodes::Scalar::PLAIN) + else + super + end + end + end + end +end diff --git a/ext/psych/lib/psych/nodes.rb b/ext/psych/lib/psych/nodes.rb new file mode 100644 index 0000000000..2fa52e0055 --- /dev/null +++ b/ext/psych/lib/psych/nodes.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true +require_relative 'nodes/node' +require_relative 'nodes/stream' +require_relative 'nodes/document' +require_relative 'nodes/sequence' +require_relative 'nodes/scalar' +require_relative 'nodes/mapping' +require_relative 'nodes/alias' + +module Psych + ### + # = Overview + # + # When using Psych.load to deserialize a YAML document, the document is + # translated to an intermediary AST. That intermediary AST is then + # translated in to a Ruby object graph. + # + # In the opposite direction, when using Psych.dump, the Ruby object graph is + # translated to an intermediary AST which is then converted to a YAML + # document. + # + # Psych::Nodes contains all of the classes that make up the nodes of a YAML + # AST. You can manually build an AST and use one of the visitors (see + # Psych::Visitors) to convert that AST to either a YAML document or to a + # Ruby object graph. + # + # Here is an example of building an AST that represents a list with one + # scalar: + # + # # Create our nodes + # stream = Psych::Nodes::Stream.new + # doc = Psych::Nodes::Document.new + # seq = Psych::Nodes::Sequence.new + # scalar = Psych::Nodes::Scalar.new('foo') + # + # # Build up our tree + # stream.children << doc + # doc.children << seq + # seq.children << scalar + # + # The stream is the root of the tree. We can then convert the tree to YAML: + # + # stream.to_yaml => "---\n- foo\n" + # + # Or convert it to Ruby: + # + # stream.to_ruby => [["foo"]] + # + # == YAML AST Requirements + # + # A valid YAML AST *must* have one Psych::Nodes::Stream at the root. A + # Psych::Nodes::Stream node must have 1 or more Psych::Nodes::Document nodes + # as children. + # + # Psych::Nodes::Document nodes must have one and *only* one child. That child + # may be one of: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # + # Psych::Nodes::Sequence and Psych::Nodes::Mapping nodes may have many + # children, but Psych::Nodes::Mapping nodes should have an even number of + # children. + # + # All of these are valid children for Psych::Nodes::Sequence and + # Psych::Nodes::Mapping nodes: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # * Psych::Nodes::Alias + # + # Psych::Nodes::Scalar and Psych::Nodes::Alias are both terminal nodes and + # should not have any children. + module Nodes + end +end diff --git a/ext/psych/lib/psych/nodes/alias.rb b/ext/psych/lib/psych/nodes/alias.rb new file mode 100644 index 0000000000..6da655f0fd --- /dev/null +++ b/ext/psych/lib/psych/nodes/alias.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +module Psych + module Nodes + ### + # This class represents a {YAML Alias}[http://yaml.org/spec/1.1/#alias]. + # It points to an +anchor+. + # + # A Psych::Nodes::Alias is a terminal node and may have no children. + class Alias < Psych::Nodes::Node + # The anchor this alias links to + attr_accessor :anchor + + # Create a new Alias that points to an +anchor+ + def initialize anchor + @anchor = anchor + end + + def alias?; true; end + end + end +end diff --git a/ext/psych/lib/psych/nodes/document.rb b/ext/psych/lib/psych/nodes/document.rb new file mode 100644 index 0000000000..f57410d636 --- /dev/null +++ b/ext/psych/lib/psych/nodes/document.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true +module Psych + module Nodes + ### + # This represents a YAML Document. This node must be a child of + # Psych::Nodes::Stream. A Psych::Nodes::Document must have one child, + # and that child may be one of the following: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + class Document < Psych::Nodes::Node + # The version of the YAML document + attr_accessor :version + + # A list of tag directives for this document + attr_accessor :tag_directives + + # Was this document implicitly created? + attr_accessor :implicit + + # Is the end of the document implicit? + attr_accessor :implicit_end + + ### + # Create a new Psych::Nodes::Document object. + # + # +version+ is a list indicating the YAML version. + # +tags_directives+ is a list of tag directive declarations + # +implicit+ is a flag indicating whether the document will be implicitly + # started. + # + # == Example: + # This creates a YAML document object that represents a YAML 1.1 document + # with one tag directive, and has an implicit start: + # + # Psych::Nodes::Document.new( + # [1,1], + # [["!", "tag:tenderlovemaking.com,2009:"]], + # true + # ) + # + # == See Also + # See also Psych::Handler#start_document + def initialize version = [], tag_directives = [], implicit = false + super() + @version = version + @tag_directives = tag_directives + @implicit = implicit + @implicit_end = true + end + + ### + # Returns the root node. A Document may only have one root node: + # http://yaml.org/spec/1.1/#id898031 + def root + children.first + end + + def document?; true; end + end + end +end diff --git a/ext/psych/lib/psych/nodes/mapping.rb b/ext/psych/lib/psych/nodes/mapping.rb new file mode 100644 index 0000000000..d49678cb0e --- /dev/null +++ b/ext/psych/lib/psych/nodes/mapping.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true +module Psych + module Nodes + ### + # This class represents a {YAML Mapping}[http://yaml.org/spec/1.1/#mapping]. + # + # A Psych::Nodes::Mapping node may have 0 or more children, but must have + # an even number of children. Here are the valid children a + # Psych::Nodes::Mapping node may have: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # * Psych::Nodes::Alias + class Mapping < Psych::Nodes::Node + # Any Map Style + ANY = 0 + + # Block Map Style + BLOCK = 1 + + # Flow Map Style + FLOW = 2 + + # The optional anchor for this mapping + attr_accessor :anchor + + # The optional tag for this mapping + attr_accessor :tag + + # Is this an implicit mapping? + attr_accessor :implicit + + # The style of this mapping + attr_accessor :style + + ### + # Create a new Psych::Nodes::Mapping object. + # + # +anchor+ is the anchor associated with the map or +nil+. + # +tag+ is the tag associated with the map or +nil+. + # +implicit+ is a boolean indicating whether or not the map was implicitly + # started. + # +style+ is an integer indicating the mapping style. + # + # == See Also + # See also Psych::Handler#start_mapping + def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK + super() + @anchor = anchor + @tag = tag + @implicit = implicit + @style = style + end + + def mapping?; true; end + end + end +end diff --git a/ext/psych/lib/psych/nodes/node.rb b/ext/psych/lib/psych/nodes/node.rb new file mode 100644 index 0000000000..fc27448f2e --- /dev/null +++ b/ext/psych/lib/psych/nodes/node.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true +require_relative '../class_loader' +require_relative '../scalar_scanner' + +module Psych + module Nodes + ### + # The base class for any Node in a YAML parse tree. This class should + # never be instantiated. + class Node + include Enumerable + + # The children of this node + attr_reader :children + + # An associated tag + attr_reader :tag + + # The line number where this node start + attr_accessor :start_line + + # The column number where this node start + attr_accessor :start_column + + # The line number where this node ends + attr_accessor :end_line + + # The column number where this node ends + attr_accessor :end_column + + # Create a new Psych::Nodes::Node + def initialize + @children = [] + end + + ### + # Iterate over each node in the tree. Yields each node to +block+ depth + # first. + def each &block + return enum_for :each unless block_given? + Visitors::DepthFirst.new(block).accept self + end + + ### + # Convert this node to Ruby. + # + # See also Psych::Visitors::ToRuby + def to_ruby(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true) + Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols).accept(self) + end + alias :transform :to_ruby + + ### + # Convert this node to YAML. + # + # See also Psych::Visitors::Emitter + def yaml io = nil, options = {} + require "stringio" unless defined?(StringIO) + + real_io = io || StringIO.new(''.encode('utf-8')) + + Visitors::Emitter.new(real_io, options).accept self + return real_io.string unless io + io + end + alias :to_yaml :yaml + + def alias?; false; end + def document?; false; end + def mapping?; false; end + def scalar?; false; end + def sequence?; false; end + def stream?; false; end + end + end +end diff --git a/ext/psych/lib/psych/nodes/scalar.rb b/ext/psych/lib/psych/nodes/scalar.rb new file mode 100644 index 0000000000..5550b616a3 --- /dev/null +++ b/ext/psych/lib/psych/nodes/scalar.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true +module Psych + module Nodes + ### + # This class represents a {YAML Scalar}[http://yaml.org/spec/1.1/#id858081]. + # + # This node type is a terminal node and should not have any children. + class Scalar < Psych::Nodes::Node + # Any style scalar, the emitter chooses + ANY = 0 + + # Plain scalar style + PLAIN = 1 + + # Single quoted style + SINGLE_QUOTED = 2 + + # Double quoted style + DOUBLE_QUOTED = 3 + + # Literal style + LITERAL = 4 + + # Folded style + FOLDED = 5 + + # The scalar value + attr_accessor :value + + # The anchor value (if there is one) + attr_accessor :anchor + + # The tag value (if there is one) + attr_accessor :tag + + # Is this a plain scalar? + attr_accessor :plain + + # Is this scalar quoted? + attr_accessor :quoted + + # The style of this scalar + attr_accessor :style + + ### + # Create a new Psych::Nodes::Scalar object. + # + # +value+ is the string value of the scalar + # +anchor+ is an associated anchor or nil + # +tag+ is an associated tag or nil + # +plain+ is a boolean value + # +quoted+ is a boolean value + # +style+ is an integer indicating the string style + # + # == See Also + # + # See also Psych::Handler#scalar + def initialize value, anchor = nil, tag = nil, plain = true, quoted = false, style = ANY + @value = value + @anchor = anchor + @tag = tag + @plain = plain + @quoted = quoted + @style = style + end + + def scalar?; true; end + end + end +end diff --git a/ext/psych/lib/psych/nodes/sequence.rb b/ext/psych/lib/psych/nodes/sequence.rb new file mode 100644 index 0000000000..740f1938a4 --- /dev/null +++ b/ext/psych/lib/psych/nodes/sequence.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true +module Psych + module Nodes + ### + # This class represents a + # {YAML sequence}[http://yaml.org/spec/1.1/#sequence/syntax]. + # + # A YAML sequence is basically a list, and looks like this: + # + # %YAML 1.1 + # --- + # - I am + # - a Sequence + # + # A YAML sequence may have an anchor like this: + # + # %YAML 1.1 + # --- + # &A [ + # "This sequence", + # "has an anchor" + # ] + # + # A YAML sequence may also have a tag like this: + # + # %YAML 1.1 + # --- + # !!seq [ + # "This sequence", + # "has a tag" + # ] + # + # This class represents a sequence in a YAML document. A + # Psych::Nodes::Sequence node may have 0 or more children. Valid children + # for this node are: + # + # * Psych::Nodes::Sequence + # * Psych::Nodes::Mapping + # * Psych::Nodes::Scalar + # * Psych::Nodes::Alias + class Sequence < Psych::Nodes::Node + # Any Styles, emitter chooses + ANY = 0 + + # Block style sequence + BLOCK = 1 + + # Flow style sequence + FLOW = 2 + + # The anchor for this sequence (if any) + attr_accessor :anchor + + # The tag name for this sequence (if any) + attr_accessor :tag + + # Is this sequence started implicitly? + attr_accessor :implicit + + # The sequence style used + attr_accessor :style + + ### + # Create a new object representing a YAML sequence. + # + # +anchor+ is the anchor associated with the sequence or nil. + # +tag+ is the tag associated with the sequence or nil. + # +implicit+ a boolean indicating whether or not the sequence was + # implicitly started. + # +style+ is an integer indicating the list style. + # + # See Psych::Handler#start_sequence + def initialize anchor = nil, tag = nil, implicit = true, style = BLOCK + super() + @anchor = anchor + @tag = tag + @implicit = implicit + @style = style + end + + def sequence?; true; end + end + end +end diff --git a/ext/psych/lib/psych/nodes/stream.rb b/ext/psych/lib/psych/nodes/stream.rb new file mode 100644 index 0000000000..b525217821 --- /dev/null +++ b/ext/psych/lib/psych/nodes/stream.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +module Psych + module Nodes + ### + # Represents a YAML stream. This is the root node for any YAML parse + # tree. This node must have one or more child nodes. The only valid + # child node for a Psych::Nodes::Stream node is Psych::Nodes::Document. + class Stream < Psych::Nodes::Node + + # Encodings supported by Psych (and libyaml) + + # Any encoding + ANY = Psych::Parser::ANY + + # UTF-8 encoding + UTF8 = Psych::Parser::UTF8 + + # UTF-16LE encoding + UTF16LE = Psych::Parser::UTF16LE + + # UTF-16BE encoding + UTF16BE = Psych::Parser::UTF16BE + + # The encoding used for this stream + attr_accessor :encoding + + ### + # Create a new Psych::Nodes::Stream node with an +encoding+ that + # defaults to Psych::Nodes::Stream::UTF8. + # + # See also Psych::Handler#start_stream + def initialize encoding = UTF8 + super() + @encoding = encoding + end + + def stream?; true; end + end + end +end diff --git a/ext/psych/lib/psych/omap.rb b/ext/psych/lib/psych/omap.rb new file mode 100644 index 0000000000..29cde0be50 --- /dev/null +++ b/ext/psych/lib/psych/omap.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true +module Psych + class Omap < ::Hash + end +end diff --git a/ext/psych/lib/psych/parser.rb b/ext/psych/lib/psych/parser.rb new file mode 100644 index 0000000000..2181c730e5 --- /dev/null +++ b/ext/psych/lib/psych/parser.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true +module Psych + ### + # YAML event parser class. This class parses a YAML document and calls + # events on the handler that is passed to the constructor. The events can + # be used for things such as constructing a YAML AST or deserializing YAML + # documents. It can even be fed back to Psych::Emitter to emit the same + # document that was parsed. + # + # See Psych::Handler for documentation on the events that Psych::Parser emits. + # + # Here is an example that prints out ever scalar found in a YAML document: + # + # # Handler for detecting scalar values + # class ScalarHandler < Psych::Handler + # def scalar value, anchor, tag, plain, quoted, style + # puts value + # end + # end + # + # parser = Psych::Parser.new(ScalarHandler.new) + # parser.parse(yaml_document) + # + # Here is an example that feeds the parser back in to Psych::Emitter. The + # YAML document is read from STDIN and written back out to STDERR: + # + # parser = Psych::Parser.new(Psych::Emitter.new($stderr)) + # parser.parse($stdin) + # + # Psych uses Psych::Parser in combination with Psych::TreeBuilder to + # construct an AST of the parsed YAML document. + + class Parser + class Mark < Struct.new(:index, :line, :column) + end + + # The handler on which events will be called + attr_accessor :handler + + # Set the encoding for this parser to +encoding+ + attr_writer :external_encoding + + ### + # Creates a new Psych::Parser instance with +handler+. YAML events will + # be called on +handler+. See Psych::Parser for more details. + + def initialize handler = Handler.new + @handler = handler + @external_encoding = ANY + end + + ### + # call-seq: + # parser.parse(yaml) + # + # Parse the YAML document contained in +yaml+. Events will be called on + # the handler set on the parser instance. + # + # See Psych::Parser and Psych::Parser#handler + + def parse yaml, path = yaml.respond_to?(:path) ? yaml.path : "<unknown>" + _native_parse @handler, yaml, path + end + end +end diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb new file mode 100644 index 0000000000..6a556fb3b8 --- /dev/null +++ b/ext/psych/lib/psych/scalar_scanner.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +module Psych + ### + # Scan scalars for built in types + class ScalarScanner + # Taken from http://yaml.org/type/timestamp.html + TIME = /^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/ + + # Taken from http://yaml.org/type/float.html + # Base 60, [-+]inf and NaN are handled separately + FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10))$/x + + # Taken from http://yaml.org/type/int.html and modified to ensure at least one numerical symbol exists + INTEGER_STRICT = /^(?:[-+]?0b[_]*[0-1][0-1_]* (?# base 2) + |[-+]?0[_]*[0-7][0-7_]* (?# base 8) + |[-+]?(0|[1-9][0-9_]*) (?# base 10) + |[-+]?0x[_]*[0-9a-fA-F][0-9a-fA-F_]* (?# base 16))$/x + + # Same as above, but allows commas. + # Not to YML spec, but kept for backwards compatibility + INTEGER_LEGACY = /^(?:[-+]?0b[_,]*[0-1][0-1_,]* (?# base 2) + |[-+]?0[_,]*[0-7][0-7_,]* (?# base 8) + |[-+]?(?:0|[1-9](?:[0-9]|,[0-9]|_[0-9])*) (?# base 10) + |[-+]?0x[_,]*[0-9a-fA-F][0-9a-fA-F_,]* (?# base 16))$/x + + attr_reader :class_loader + + # Create a new scanner + def initialize class_loader, strict_integer: false, parse_symbols: true + @symbol_cache = {} + @class_loader = class_loader + @strict_integer = strict_integer + @parse_symbols = parse_symbols + end + + # Tokenize +string+ returning the Ruby object + def tokenize string + return nil if string.empty? + return @symbol_cache[string] if @symbol_cache.key?(string) + integer_regex = @strict_integer ? INTEGER_STRICT : INTEGER_LEGACY + # Check for a String type, being careful not to get caught by hash keys, hex values, and + # special floats (e.g., -.inf). + if string.match?(%r{^[^\d.:-]?[[:alpha:]_\s!@#$%\^&*(){}<>|/\\~;=]+}) || string.match?(/\n/) + return string if string.length > 5 + + if string.match?(/^[^ytonf~]/i) + string + elsif string == '~' || string.match?(/^null$/i) + nil + elsif string.match?(/^(yes|true|on)$/i) + true + elsif string.match?(/^(no|false|off)$/i) + false + else + string + end + elsif string.match?(TIME) + begin + parse_time string + rescue ArgumentError + string + end + elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/) + begin + class_loader.date.strptime(string, '%F', Date::GREGORIAN) + rescue ArgumentError + string + end + elsif string.match?(/^\+?\.inf$/i) + Float::INFINITY + elsif string.match?(/^-\.inf$/i) + -Float::INFINITY + elsif string.match?(/^\.nan$/i) + Float::NAN + elsif @parse_symbols && string.match?(/^:./) + if string =~ /^:(["'])(.*)\1/ + @symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, '')) + else + @symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, '')) + end + elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/) + i = 0 + string.split(':').each_with_index do |n,e| + i += (n.to_i * 60 ** (e - 2).abs) + end + i + elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/) + i = 0 + string.split(':').each_with_index do |n,e| + i += (n.to_f * 60 ** (e - 2).abs) + end + i + elsif string.match?(FLOAT) + if string.match?(/\A[-+]?\.\Z/) + string + else + Float(string.delete(',_').gsub(/\.([Ee]|$)/, '\1')) + end + elsif string.match?(integer_regex) + parse_int string + else + string + end + end + + ### + # Parse and return an int from +string+ + def parse_int string + Integer(string.delete(',_')) + end + + ### + # Parse and return a Time from +string+ + def parse_time string + klass = class_loader.load 'Time' + + date, time = *(string.split(/[ tT]/, 2)) + (yy, m, dd) = date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map { |x| x.to_i } + md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/) + + (hh, mm, ss) = md[1].split(':').map { |x| x.to_i } + us = (md[2] ? Rational("0.#{md[2]}") : 0) * 1000000 + + time = klass.utc(yy, m, dd, hh, mm, ss, us) + + return time if 'Z' == md[3] + return klass.at(time.to_i, us) unless md[3] + + tz = md[3].match(/^([+\-]?\d{1,2})\:?(\d{1,2})?$/)[1..-1].compact.map { |digit| Integer(digit, 10) } + offset = tz.first * 3600 + + if offset < 0 + offset -= ((tz[1] || 0) * 60) + else + offset += ((tz[1] || 0) * 60) + end + + klass.new(yy, m, dd, hh, mm, ss+us/(1_000_000r), offset) + end + end +end diff --git a/ext/psych/lib/psych/set.rb b/ext/psych/lib/psych/set.rb new file mode 100644 index 0000000000..760d217098 --- /dev/null +++ b/ext/psych/lib/psych/set.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true +module Psych + class Set < ::Hash + end +end diff --git a/ext/psych/lib/psych/stream.rb b/ext/psych/lib/psych/stream.rb new file mode 100644 index 0000000000..24e45afc3b --- /dev/null +++ b/ext/psych/lib/psych/stream.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +module Psych + ### + # Psych::Stream is a streaming YAML emitter. It will not buffer your YAML, + # but send it straight to an IO. + # + # Here is an example use: + # + # stream = Psych::Stream.new($stdout) + # stream.start + # stream.push({:foo => 'bar'}) + # stream.finish + # + # YAML will be immediately emitted to $stdout with no buffering. + # + # Psych::Stream#start will take a block and ensure that Psych::Stream#finish + # is called, so you can do this form: + # + # stream = Psych::Stream.new($stdout) + # stream.start do |em| + # em.push(:foo => 'bar') + # end + # + class Stream < Psych::Visitors::YAMLTree + class Emitter < Psych::Emitter # :nodoc: + def end_document implicit_end = !streaming? + super + end + + def streaming? + true + end + end + + include Psych::Streaming + extend Psych::Streaming::ClassMethods + end +end diff --git a/ext/psych/lib/psych/streaming.rb b/ext/psych/lib/psych/streaming.rb new file mode 100644 index 0000000000..eb19792ad0 --- /dev/null +++ b/ext/psych/lib/psych/streaming.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +module Psych + module Streaming + module ClassMethods + ### + # Create a new streaming emitter. Emitter will print to +io+. See + # Psych::Stream for an example. + def new io + emitter = const_get(:Emitter).new(io) + class_loader = ClassLoader.new + ss = ScalarScanner.new class_loader + super(emitter, ss, {}) + end + end + + ### + # Start streaming using +encoding+ + def start encoding = Nodes::Stream::UTF8 + super.tap { yield self if block_given? } + ensure + finish if block_given? + end + + private + def register target, obj + end + end +end diff --git a/ext/psych/lib/psych/syntax_error.rb b/ext/psych/lib/psych/syntax_error.rb new file mode 100644 index 0000000000..a4c9c4a376 --- /dev/null +++ b/ext/psych/lib/psych/syntax_error.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +require_relative 'exception' + +module Psych + class SyntaxError < Psych::Exception + attr_reader :file, :line, :column, :offset, :problem, :context + + def initialize file, line, col, offset, problem, context + err = [problem, context].compact.join ' ' + filename = file || '<unknown>' + message = "(%s): %s at line %d column %d" % [filename, err, line, col] + + @file = file + @line = line + @column = col + @offset = offset + @problem = problem + @context = context + super(message) + end + end +end diff --git a/ext/psych/lib/psych/tree_builder.rb b/ext/psych/lib/psych/tree_builder.rb new file mode 100644 index 0000000000..83115bd721 --- /dev/null +++ b/ext/psych/lib/psych/tree_builder.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true +require_relative 'handler' + +module Psych + ### + # This class works in conjunction with Psych::Parser to build an in-memory + # parse tree that represents a YAML document. + # + # == Example + # + # parser = Psych::Parser.new Psych::TreeBuilder.new + # parser.parse('--- foo') + # tree = parser.handler.root + # + # See Psych::Handler for documentation on the event methods used in this + # class. + class TreeBuilder < Psych::Handler + # Returns the root node for the built tree + attr_reader :root + + # Create a new TreeBuilder instance + def initialize + @stack = [] + @last = nil + @root = nil + + @start_line = nil + @start_column = nil + @end_line = nil + @end_column = nil + end + + def event_location(start_line, start_column, end_line, end_column) + @start_line = start_line + @start_column = start_column + @end_line = end_line + @end_column = end_column + end + + %w{ + Sequence + Mapping + }.each do |node| + class_eval <<~RUBY, __FILE__, __LINE__ + 1 + def start_#{node.downcase}(anchor, tag, implicit, style) + n = Nodes::#{node}.new(anchor, tag, implicit, style) + set_start_location(n) + @last.children << n + push n + end + + def end_#{node.downcase} + n = pop + set_end_location(n) + n + end + RUBY + end + + ### + # Handles start_document events with +version+, +tag_directives+, + # and +implicit+ styling. + # + # See Psych::Handler#start_document + def start_document version, tag_directives, implicit + n = Nodes::Document.new version, tag_directives, implicit + set_start_location(n) + @last.children << n + push n + end + + ### + # Handles end_document events with +version+, +tag_directives+, + # and +implicit+ styling. + # + # See Psych::Handler#start_document + def end_document implicit_end = !streaming? + @last.implicit_end = implicit_end + n = pop + set_end_location(n) + n + end + + def start_stream encoding + @root = Nodes::Stream.new(encoding) + set_start_location(@root) + push @root + end + + def end_stream + n = pop + set_end_location(n) + n + end + + def scalar value, anchor, tag, plain, quoted, style + s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style) + set_location(s) + @last.children << s + s + end + + def alias anchor + a = Nodes::Alias.new(anchor) + set_location(a) + @last.children << a + a + end + + private + def push value + @stack.push value + @last = value + end + + def pop + x = @stack.pop + @last = @stack.last + x + end + + def set_location(node) + set_start_location(node) + set_end_location(node) + end + + def set_start_location(node) + node.start_line = @start_line + node.start_column = @start_column + end + + def set_end_location(node) + node.end_line = @end_line + node.end_column = @end_column + end + end +end diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb new file mode 100644 index 0000000000..6c1679bf65 --- /dev/null +++ b/ext/psych/lib/psych/versions.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Psych + # The version of Psych you are using + VERSION = '5.4.0' + + if RUBY_ENGINE == 'jruby' + DEFAULT_SNAKEYAML_VERSION = '2.10'.freeze + end +end diff --git a/ext/psych/lib/psych/visitors.rb b/ext/psych/lib/psych/visitors.rb new file mode 100644 index 0000000000..508290d862 --- /dev/null +++ b/ext/psych/lib/psych/visitors.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +require_relative 'visitors/visitor' +require_relative 'visitors/to_ruby' +require_relative 'visitors/emitter' +require_relative 'visitors/yaml_tree' +require_relative 'visitors/json_tree' +require_relative 'visitors/depth_first' diff --git a/ext/psych/lib/psych/visitors/depth_first.rb b/ext/psych/lib/psych/visitors/depth_first.rb new file mode 100644 index 0000000000..b4ff9e40e7 --- /dev/null +++ b/ext/psych/lib/psych/visitors/depth_first.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +module Psych + module Visitors + class DepthFirst < Psych::Visitors::Visitor + def initialize block + @block = block + end + + private + + def nary o + o.children.each { |x| visit x } + @block.call o + end + alias :visit_Psych_Nodes_Stream :nary + alias :visit_Psych_Nodes_Document :nary + alias :visit_Psych_Nodes_Sequence :nary + alias :visit_Psych_Nodes_Mapping :nary + + def terminal o + @block.call o + end + alias :visit_Psych_Nodes_Scalar :terminal + alias :visit_Psych_Nodes_Alias :terminal + end + end +end diff --git a/ext/psych/lib/psych/visitors/emitter.rb b/ext/psych/lib/psych/visitors/emitter.rb new file mode 100644 index 0000000000..e3b92b7d03 --- /dev/null +++ b/ext/psych/lib/psych/visitors/emitter.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true +module Psych + module Visitors + class Emitter < Psych::Visitors::Visitor + def initialize io, options = {} + opts = [:indentation, :canonical, :line_width].find_all { |opt| + options.key?(opt) + } + + if opts.empty? + @handler = Psych::Emitter.new io + else + du = Handler::DumperOptions.new + opts.each { |option| du.send :"#{option}=", options[option] } + @handler = Psych::Emitter.new io, du + end + end + + def visit_Psych_Nodes_Stream o + @handler.start_stream o.encoding + o.children.each { |c| accept c } + @handler.end_stream + end + + def visit_Psych_Nodes_Document o + @handler.start_document o.version, o.tag_directives, o.implicit + o.children.each { |c| accept c } + @handler.end_document o.implicit_end + end + + def visit_Psych_Nodes_Scalar o + @handler.scalar o.value, o.anchor, o.tag, o.plain, o.quoted, o.style + end + + def visit_Psych_Nodes_Sequence o + @handler.start_sequence o.anchor, o.tag, o.implicit, o.style + o.children.each { |c| accept c } + @handler.end_sequence + end + + def visit_Psych_Nodes_Mapping o + @handler.start_mapping o.anchor, o.tag, o.implicit, o.style + o.children.each { |c| accept c } + @handler.end_mapping + end + + def visit_Psych_Nodes_Alias o + @handler.alias o.anchor + end + end + end +end diff --git a/ext/psych/lib/psych/visitors/json_tree.rb b/ext/psych/lib/psych/visitors/json_tree.rb new file mode 100644 index 0000000000..979fc100bd --- /dev/null +++ b/ext/psych/lib/psych/visitors/json_tree.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +require_relative '../json/ruby_events' + +module Psych + module Visitors + class JSONTree < YAMLTree + include Psych::JSON::RubyEvents + + def self.create options = {} + emitter = Psych::JSON::TreeBuilder.new + class_loader = ClassLoader.new + ss = ScalarScanner.new class_loader + new(emitter, ss, options) + end + + def accept target + if target.respond_to?(:encode_with) + dump_coder target + else + send(@dispatch_cache[target.class], target) + end + end + end + end +end diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb new file mode 100644 index 0000000000..475444e589 --- /dev/null +++ b/ext/psych/lib/psych/visitors/to_ruby.rb @@ -0,0 +1,479 @@ +# frozen_string_literal: true +require_relative '../scalar_scanner' +require_relative '../class_loader' +require_relative '../exception' + +unless defined?(Regexp::NOENCODING) + Regexp::NOENCODING = 32 +end + +module Psych + module Visitors + ### + # This class walks a YAML AST, converting each node to Ruby + class ToRuby < Psych::Visitors::Visitor + unless RUBY_VERSION < "3.2" + DATA_INITIALIZE = Data.instance_method(:initialize) + end + + def self.create(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true) + class_loader = ClassLoader.new + scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols + new(scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze) + end + + attr_reader :class_loader + + def initialize ss, class_loader, symbolize_names: false, freeze: false + super() + @st = {} + @ss = ss + @load_tags = Psych.load_tags + @domain_types = Psych.domain_types + @class_loader = class_loader + @symbolize_names = symbolize_names + @freeze = freeze + end + + def accept target + result = super + + unless @domain_types.empty? || !target.tag + key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:') + key = "tag:#{key}" unless key.match?(/^(?:tag:|x-private)/) + + if @domain_types.key? key + value, block = @domain_types[key] + result = block.call value, result + end + end + + result = deduplicate(result).freeze if @freeze + result + end + + def deserialize o + if klass = resolve_class(@load_tags[o.tag]) + instance = klass.allocate + + if instance.respond_to?(:init_with) + coder = Psych::Coder.new(o.tag) + coder.scalar = o.value + instance.init_with coder + end + + return instance + end + + return o.value if o.quoted + return @ss.tokenize(o.value) unless o.tag + + case o.tag + when '!binary', 'tag:yaml.org,2002:binary' + o.value.unpack('m').first + when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' + klass = resolve_class($1) + if klass + klass.allocate.replace o.value + else + o.value + end + when '!ruby/object:BigDecimal' + require 'bigdecimal' unless defined? BigDecimal + class_loader.big_decimal._load o.value + when "!ruby/object:DateTime" + class_loader.date_time + t = @ss.parse_time(o.value) + DateTime.civil(*t.to_a[0, 6].reverse, Rational(t.utc_offset, 86400)) + + (t.subsec/86400) + when '!ruby/encoding' + ::Encoding.find o.value + when "!ruby/object:Complex" + class_loader.complex + Complex(o.value) + when "!ruby/object:Rational" + class_loader.rational + Rational(o.value) + when "!ruby/class", "!ruby/module" + resolve_class o.value + when "tag:yaml.org,2002:float", "!float" + Float(@ss.tokenize(o.value)) + when "!ruby/regexp" + klass = class_loader.regexp + matches = /^\/(?<string>.*)\/(?<options>[mixn]*)$/m.match(o.value) + source = matches[:string].gsub('\/', '/') + options = 0 + lang = nil + matches[:options].each_char do |option| + case option + when 'x' then options |= Regexp::EXTENDED + when 'i' then options |= Regexp::IGNORECASE + when 'm' then options |= Regexp::MULTILINE + when 'n' then options |= Regexp::NOENCODING + else lang = option + end + end + klass.new(*[source, options, lang].compact) + when "!ruby/range" + klass = class_loader.range + args = o.value.split(/([.]{2,3})/, 2).map { |s| + accept Nodes::Scalar.new(s) + } + args.push(args.delete_at(1) == '...') + klass.new(*args) + when /^!ruby\/sym(bol)?:?(.*)?$/ + class_loader.symbolize o.value + else + @ss.tokenize o.value + end + end + private :deserialize + + def visit_Psych_Nodes_Scalar o + register o, deserialize(o) + end + + def visit_Psych_Nodes_Sequence o + if klass = resolve_class(@load_tags[o.tag]) + instance = klass.allocate + + if instance.respond_to?(:init_with) + coder = Psych::Coder.new(o.tag) + coder.seq = o.children.map { |c| accept c } + instance.init_with coder + end + + return instance + end + + case o.tag + when nil + register_empty(o) + when '!omap', 'tag:yaml.org,2002:omap' + map = register(o, Psych::Omap.new) + o.children.each { |a| + map[accept(a.children.first)] = accept a.children.last + } + map + when /^!(?:seq|ruby\/array):(.*)$/ + klass = resolve_class($1) + list = register(o, klass.allocate) + o.children.each { |c| list.push accept c } + list + else + register_empty(o) + end + end + + def visit_Psych_Nodes_Mapping o + if @load_tags[o.tag] + return revive(resolve_class(@load_tags[o.tag]), o) + end + return revive_hash(register(o, {}), o) unless o.tag + + case o.tag + when /^!ruby\/struct:?(.*)?$/ + klass = resolve_class($1) if $1 + + if klass + s = register(o, klass.allocate) + + members = {} + struct_members = s.members.map { |x| class_loader.symbolize x } + o.children.each_slice(2) do |k,v| + member = accept(k) + value = accept(v) + if struct_members.include?(class_loader.symbolize(member)) + s.send("#{member}=", value) + else + members[member.to_s.sub(/^@/, '')] = value + end + end + init_with(s, members, o) + else + klass = class_loader.struct + members = o.children.map { |c| accept c } + h = Hash[*members] + s = klass.new(*h.map { |k,v| + class_loader.symbolize k + }).new(*h.map { |k,v| v }) + register(o, s) + s + end + + when /^!ruby\/data(-with-ivars)?(?::(.*))?$/ + data = register(o, resolve_class($2).allocate) if $2 + members = {} + + if $1 # data-with-ivars + ivars = {} + o.children.each_slice(2) do |type, vars| + case accept(type) + when 'members' + revive_data_members(members, vars) + data ||= allocate_anon_data(o, members) + when 'ivars' + revive_hash(ivars, vars) + end + end + ivars.each do |ivar, v| + data.instance_variable_set ivar, v + end + else + revive_data_members(members, o) + end + data ||= allocate_anon_data(o, members) + DATA_INITIALIZE.bind_call(data, **members) + data.freeze + data + + when /^!ruby\/object:?(.*)?$/ + name = $1 || 'Object' + + if name == 'Complex' + class_loader.complex + h = Hash[*o.children.map { |c| accept c }] + register o, Complex(h['real'], h['image']) + elsif name == 'Rational' + class_loader.rational + h = Hash[*o.children.map { |c| accept c }] + register o, Rational(h['numerator'], h['denominator']) + elsif name == 'Hash' + revive_hash(register(o, {}), o) + else + obj = revive((resolve_class(name) || class_loader.object), o) + obj + end + + when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' + klass = resolve_class($1) + members = {} + string = nil + + o.children.each_slice(2) do |k,v| + key = accept k + value = accept v + + if key == 'str' + if klass + string = klass.allocate.replace value + else + string = value + end + register(o, string) + else + members[key] = value + end + end + init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) + when /^!ruby\/array:(.*)$/ + klass = resolve_class($1) + list = register(o, klass.allocate) + + members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a] + list.replace members['internal'] + + members['ivars'].each do |ivar, v| + list.instance_variable_set ivar, v + end + list + + when '!ruby/range' + klass = class_loader.range + h = Hash[*o.children.map { |c| accept c }] + register o, klass.new(h['begin'], h['end'], h['excl']) + + when /^!ruby\/exception:?(.*)?$/ + h = Hash[*o.children.map { |c| accept c }] + + e = build_exception((resolve_class($1) || class_loader.exception), + h.delete('message')) + + e.set_backtrace h.delete('backtrace') if h.key? 'backtrace' + init_with(e, h, o) + + when '!set', 'tag:yaml.org,2002:set' + set = class_loader.psych_set.new + @st[o.anchor] = set if o.anchor + o.children.each_slice(2) do |k,v| + set[accept(k)] = accept(v) + end + set + + when /^!ruby\/hash-with-ivars(?::(.*))?$/ + hash = $1 ? resolve_class($1).allocate : {} + register o, hash + o.children.each_slice(2) do |key, value| + case key.value + when 'elements' + revive_hash hash, value + when 'ivars' + value.children.each_slice(2) do |k,v| + hash.instance_variable_set accept(k), accept(v) + end + end + end + hash + + when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/ + revive_hash register(o, resolve_class($1).allocate), o + + when '!omap', 'tag:yaml.org,2002:omap' + map = register(o, class_loader.psych_omap.new) + o.children.each_slice(2) do |l,r| + map[accept(l)] = accept r + end + map + + when /^!ruby\/marshalable:(.*)$/ + name = $1 + klass = resolve_class(name) + obj = register(o, klass.allocate) + + if obj.respond_to?(:init_with) + init_with(obj, revive_hash({}, o), o) + elsif obj.respond_to?(:marshal_load) + marshal_data = o.children.map(&method(:accept)) + obj.marshal_load(marshal_data) + obj + else + raise ArgumentError, "Cannot deserialize #{name}" + end + + else + revive_hash(register(o, {}), o) + end + end + + def visit_Psych_Nodes_Document o + accept o.root + end + + def visit_Psych_Nodes_Stream o + o.children.map { |c| accept c } + end + + def visit_Psych_Nodes_Alias o + @st.fetch(o.anchor) { raise AnchorNotDefined, o.anchor } + end + + private + + def register node, object + @st[node.anchor] = object if node.anchor + object + end + + def register_empty object + list = register(object, []) + object.children.each { |c| list.push accept c } + list + end + + def allocate_anon_data node, members + klass = class_loader.data.define(*members.keys) + register(node, klass.allocate) + end + + def revive_data_members hash, o + o.children.each_slice(2) do |k,v| + name = accept(k) + value = accept(v) + hash[class_loader.symbolize(name)] = value + end + hash + end + + def revive_hash hash, o, tagged= false + o.children.each_slice(2) { |k,v| + key = accept(k) + val = accept(v) + + if key == '<<' && k.tag != "tag:yaml.org,2002:str" + case v + when Nodes::Alias, Nodes::Mapping + begin + hash.merge! val + rescue TypeError + hash[key] = val + end + when Nodes::Sequence + begin + h = {} + val.reverse_each do |value| + h.merge! value + end + hash.merge! h + rescue TypeError + hash[key] = val + end + else + hash[key] = val + end + else + if !tagged && @symbolize_names && key.is_a?(String) + key = key.to_sym + elsif !@freeze + key = deduplicate(key) + end + + hash[key] = val + end + + } + hash + end + + if RUBY_VERSION < '2.7' + def deduplicate key + if key.is_a?(String) + # It is important to untaint the string, otherwise it won't + # be deduplicated into an fstring, but simply frozen. + -(key.untaint) + else + key + end + end + else + def deduplicate key + if key.is_a?(String) + -key + else + key + end + end + end + + def merge_key hash, key, val + end + + def revive klass, node + s = register(node, klass.allocate) + init_with(s, revive_hash({}, node, true), node) + end + + def init_with o, h, node + c = Psych::Coder.new(node.tag) + c.map = h + + if o.respond_to?(:init_with) + o.init_with c + else + h.each { |k,v| o.instance_variable_set(:"@#{k}", v) } + end + o + end + + # Convert +klassname+ to a Class + def resolve_class klassname + class_loader.load klassname + end + end + + class NoAliasRuby < ToRuby + def visit_Psych_Nodes_Alias o + raise AliasesNotEnabled + end + end + end +end diff --git a/ext/psych/lib/psych/visitors/visitor.rb b/ext/psych/lib/psych/visitors/visitor.rb new file mode 100644 index 0000000000..21052aa66f --- /dev/null +++ b/ext/psych/lib/psych/visitors/visitor.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +module Psych + module Visitors + class Visitor + def accept target + visit target + end + + private + + # @api private + def self.dispatch_cache + Hash.new do |hash, klass| + hash[klass] = :"visit_#{klass.name.gsub('::', '_')}" + end.compare_by_identity + end + + if defined?(Ractor) + def dispatch + @dispatch_cache ||= (Ractor.current[:Psych_Visitors_Visitor] ||= Visitor.dispatch_cache) + end + else + DISPATCH = dispatch_cache + def dispatch + DISPATCH + end + end + + def visit target + send dispatch[target.class], target + end + end + end +end diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb new file mode 100644 index 0000000000..b6c86f4c94 --- /dev/null +++ b/ext/psych/lib/psych/visitors/yaml_tree.rb @@ -0,0 +1,626 @@ +# frozen_string_literal: true +require_relative '../tree_builder' +require_relative '../scalar_scanner' +require_relative '../class_loader' + +module Psych + module Visitors + ### + # YAMLTree builds a YAML ast given a Ruby object. For example: + # + # builder = Psych::Visitors::YAMLTree.new + # builder << { :foo => 'bar' } + # builder.tree # => #<Psych::Nodes::Stream .. } + # + class YAMLTree < Psych::Visitors::Visitor + class Registrar # :nodoc: + def initialize + @obj_to_id = {}.compare_by_identity + @obj_to_node = {}.compare_by_identity + @counter = 0 + end + + def register target, node + @obj_to_node[target] = node + end + + def key? target + @obj_to_node.key? target + end + + def id_for target + @obj_to_id[target] ||= (@counter += 1) + end + + def node_for target + @obj_to_node[target] + end + end + + attr_reader :started, :finished + alias :finished? :finished + alias :started? :started + + def self.create options = {}, emitter = nil + emitter ||= TreeBuilder.new + class_loader = ClassLoader.new + ss = ScalarScanner.new class_loader + new(emitter, ss, options) + end + + def initialize emitter, ss, options + super() + @started = false + @finished = false + @emitter = emitter + @st = Registrar.new + @ss = ss + @options = options + @line_width = options[:line_width] + if @line_width && @line_width < 0 + if @line_width == -1 + # Treat -1 as unlimited line-width, same as libyaml does. + @line_width = nil + else + fail(ArgumentError, "Invalid line_width #{@line_width}, must be non-negative or -1 for unlimited.") + end + end + @stringify_names = options[:stringify_names] + @coders = [] + + @dispatch_cache = Hash.new do |h,klass| + method = "visit_#{(klass.name || '').split('::').join('_')}" + + method = respond_to?(method) ? method : h[klass.superclass] + + raise(TypeError, "can't dump #{klass.name}") unless method + + h[klass] = method + end.compare_by_identity + end + + def start encoding = Nodes::Stream::UTF8 + @emitter.start_stream(encoding).tap do + @started = true + end + end + + def finish + @emitter.end_stream.tap do + @finished = true + end + end + + def tree + finish unless finished? + @emitter.root + end + + def push object + start unless started? + version = [] + version = [1,1] if @options[:header] + + case @options[:version] + when Array + version = @options[:version] + when String + version = @options[:version].split('.').map { |x| x.to_i } + else + version = [1,1] + end if @options.key? :version + + @emitter.start_document version, [], false + accept object + @emitter.end_document !@emitter.streaming? + end + alias :<< :push + + def accept target + # return any aliases we find + if @st.key? target + oid = @st.id_for target + node = @st.node_for target + anchor = oid.to_s + node.anchor = anchor + return @emitter.alias anchor + end + + if target.respond_to?(:encode_with) + dump_coder target + else + send(@dispatch_cache[target.class], target) + end + end + + def visit_Psych_Omap o + seq = @emitter.start_sequence(nil, 'tag:yaml.org,2002:omap', false, Nodes::Sequence::BLOCK) + register(o, seq) + + o.each { |k,v| visit_Hash k => v } + @emitter.end_sequence + end + + def visit_Encoding o + tag = "!ruby/encoding" + @emitter.scalar o.name, nil, tag, false, false, Nodes::Scalar::ANY + end + + def visit_Object o + tag = Psych.dump_tags[o.class] + unless tag + klass = o.class == Object ? nil : o.class.name + tag = ['!ruby/object', klass].compact.join(':') + end + + map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) + register(o, map) + + dump_ivars o + @emitter.end_mapping + end + + alias :visit_Delegator :visit_Object + + def visit_Data o + ivars = o.instance_variables + if ivars.empty? + tag = ['!ruby/data', o.class.name].compact.join(':') + register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) + o.members.each do |member| + @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY + accept o.send member + end + @emitter.end_mapping + + else + tag = ['!ruby/data-with-ivars', o.class.name].compact.join(':') + node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) + register(o, node) + + # Dump the members + accept 'members' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.members.each do |member| + @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY + accept o.send member + end + @emitter.end_mapping + + # Dump the ivars + accept 'ivars' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + ivars.each do |ivar| + accept ivar.to_s + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + @emitter.end_mapping + end + end unless RUBY_VERSION < "3.2" + + def visit_Struct o + tag = ['!ruby/struct', o.class.name].compact.join(':') + + register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) + o.members.each do |member| + @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY + accept o[member] + end + + dump_ivars o + + @emitter.end_mapping + end + + def visit_Exception o + dump_exception o, o.message.to_s + end + + def visit_NameError o + dump_exception o, o.message.to_s + end + + def visit_Regexp o + register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY) + end + + def visit_Date o + formatted = format_date o + register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY) + end + + def visit_DateTime o + t = o.italy + formatted = format_time t, t.offset.zero? + tag = '!ruby/object:DateTime' + register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY) + end + + def visit_Time o + formatted = format_time o + register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY) + end + + def visit_Rational o + register o, @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK) + + [ + 'denominator', o.denominator.to_s, + 'numerator', o.numerator.to_s + ].each do |m| + @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY + end + + @emitter.end_mapping + end + + def visit_Complex o + register o, @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK) + + ['real', o.real.to_s, 'image', o.imag.to_s].each do |m| + @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY + end + + @emitter.end_mapping + end + + def visit_Integer o + @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY + end + alias :visit_TrueClass :visit_Integer + alias :visit_FalseClass :visit_Integer + + def visit_Float o + if o.nan? + @emitter.scalar '.nan', nil, nil, true, false, Nodes::Scalar::ANY + elsif o.infinite? + @emitter.scalar((o.infinite? > 0 ? '.inf' : '-.inf'), + nil, nil, true, false, Nodes::Scalar::ANY) + else + @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY + end + end + + def visit_BigDecimal o + @emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY + end + + def visit_String o + plain = true + quote = true + style = Nodes::Scalar::PLAIN + tag = nil + + if binary?(o) + o = [o].pack('m0') + tag = '!binary' # FIXME: change to below when syck is removed + #tag = 'tag:yaml.org,2002:binary' + style = Nodes::Scalar::LITERAL + plain = false + quote = false + elsif o.match?(/\n(?!\Z)/) # match \n except blank line at the end of string + style = Nodes::Scalar::LITERAL + elsif o == '<<' + style = Nodes::Scalar::SINGLE_QUOTED + tag = 'tag:yaml.org,2002:str' + plain = false + quote = false + elsif o == 'y' || o == 'Y' || o == 'n' || o == 'N' + style = Nodes::Scalar::DOUBLE_QUOTED + elsif @line_width && o.length > @line_width + style = Nodes::Scalar::FOLDED + elsif o.match?(/^[^[:word:]][^"]*$/) + style = Nodes::Scalar::DOUBLE_QUOTED + elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/.match?(o) + style = Nodes::Scalar::SINGLE_QUOTED + end + + is_primitive = o.class == ::String + ivars = is_primitive ? [] : o.instance_variables + + if ivars.empty? + unless is_primitive + tag = "!ruby/string:#{o.class}" + plain = false + quote = false + end + @emitter.scalar o, nil, tag, plain, quote, style + else + maptag = '!ruby/string'.dup + maptag << ":#{o.class}" unless o.class == ::String + + register o, @emitter.start_mapping(nil, maptag, false, Nodes::Mapping::BLOCK) + @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY + @emitter.scalar o, nil, tag, plain, quote, style + + dump_ivars o + + @emitter.end_mapping + end + end + + def visit_Module o + raise TypeError, "can't dump anonymous module: #{o}" unless o.name + register o, @emitter.scalar(o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED) + end + + def visit_Class o + raise TypeError, "can't dump anonymous class: #{o}" unless o.name + register o, @emitter.scalar(o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED) + end + + def visit_Range o + register o, @emitter.start_mapping(nil, '!ruby/range', false, Nodes::Mapping::BLOCK) + ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m| + accept m + end + @emitter.end_mapping + end + + def visit_Hash o + if o.class == ::Hash + register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK)) + o.each do |k,v| + accept(@stringify_names && Symbol === k ? k.to_s : k) + accept v + end + @emitter.end_mapping + else + visit_hash_subclass o + end + end + + def visit_Psych_Set o + register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK)) + + o.each do |k,v| + accept(@stringify_names && Symbol === k ? k.to_s : k) + accept v + end + + @emitter.end_mapping + end + + def visit_Array o + if o.class == ::Array + visit_Enumerator o + else + visit_array_subclass o + end + end + + def visit_Enumerator o + register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) + o.each { |c| accept c } + @emitter.end_sequence + end + + def visit_NilClass o + @emitter.scalar('', nil, 'tag:yaml.org,2002:null', true, false, Nodes::Scalar::ANY) + end + + def visit_Symbol o + if o.empty? + @emitter.scalar "", nil, '!ruby/symbol', false, false, Nodes::Scalar::ANY + else + @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY + end + end + + def visit_BasicObject o + tag = Psych.dump_tags[o.class] + tag ||= "!ruby/marshalable:#{o.class.name}" + + map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) + register(o, map) + + o.marshal_dump.each(&method(:accept)) + + @emitter.end_mapping + end + + private + + def binary? string + string.encoding == Encoding::ASCII_8BIT && !string.ascii_only? + end + + def visit_array_subclass o + tag = "!ruby/array:#{o.class}" + ivars = o.instance_variables + if ivars.empty? + node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK) + register o, node + o.each { |c| accept c } + @emitter.end_sequence + else + node = @emitter.start_mapping(nil, tag, false, Nodes::Sequence::BLOCK) + register o, node + + # Dump the internal list + accept 'internal' + @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) + o.each { |c| accept c } + @emitter.end_sequence + + # Dump the ivars + accept 'ivars' + @emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK) + ivars.each do |ivar| + accept ivar + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + @emitter.end_mapping + end + end + + def visit_hash_subclass o + ivars = o.instance_variables + if ivars.any? + tag = "!ruby/hash-with-ivars:#{o.class}" + node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) + register(o, node) + + # Dump the ivars + accept 'ivars' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.instance_variables.each do |ivar| + accept ivar + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + # Dump the elements + accept 'elements' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.each do |k,v| + accept k + accept v + end + @emitter.end_mapping + + @emitter.end_mapping + else + tag = "!ruby/hash:#{o.class}" + node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) + register(o, node) + o.each do |k,v| + accept k + accept v + end + @emitter.end_mapping + end + end + + def dump_list o + end + + def dump_exception o, msg + tag = ['!ruby/exception', o.class.name].join ':' + + @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK + + if msg + @emitter.scalar 'message', nil, nil, true, false, Nodes::Scalar::ANY + accept msg + end + + @emitter.scalar 'backtrace', nil, nil, true, false, Nodes::Scalar::ANY + accept o.backtrace + + dump_ivars o + + @emitter.end_mapping + end + + def format_time time, utc = time.utc? + if utc + time.strftime("%Y-%m-%d %H:%M:%S.%9N Z") + else + time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z") + end + end + + def format_date date + date.strftime("%Y-%m-%d") + end + + def register target, yaml_obj + @st.register target, yaml_obj + yaml_obj + end + + def dump_coder o + @coders << o + tag = Psych.dump_tags[o.class] + unless tag + klass = o.class == Object ? nil : o.class.name + tag = ['!ruby/object', klass].compact.join(':') + end + + c = Psych::Coder.new(tag) + o.encode_with(c) + emit_coder c, o + end + + def emit_coder c, o + case c.type + when :scalar + @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, c.style + when :seq + @emitter.start_sequence nil, c.tag, c.tag.nil?, c.style + c.seq.each do |thing| + accept thing + end + @emitter.end_sequence + when :map + register o, @emitter.start_mapping(nil, c.tag, c.implicit, c.style) + c.map.each do |k,v| + accept k + accept v + end + @emitter.end_mapping + when :object + accept c.object + end + end + + def dump_ivars target + target.instance_variables.each do |iv| + @emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY) + accept target.instance_variable_get(iv) + end + end + end + + class RestrictedYAMLTree < YAMLTree + DEFAULT_PERMITTED_CLASSES = { + TrueClass => true, + FalseClass => true, + NilClass => true, + Integer => true, + Float => true, + String => true, + Array => true, + Hash => true, + }.compare_by_identity.freeze + + def initialize emitter, ss, options + super + @permitted_classes = DEFAULT_PERMITTED_CLASSES.dup + Array(options[:permitted_classes]).each do |klass| + @permitted_classes[klass] = true + end + @permitted_symbols = {}.compare_by_identity + Array(options[:permitted_symbols]).each do |symbol| + @permitted_symbols[symbol] = true + end + @aliases = options.fetch(:aliases, false) + end + + def accept target + if !@aliases && @st.key?(target) + raise BadAlias, "Tried to dump an aliased object" + end + + unless Symbol === target || @permitted_classes[target.class] + raise DisallowedClass.new('dump', target.class.name || target.class.inspect) + end + + super + end + + def visit_Symbol sym + unless @permitted_classes[Symbol] || @permitted_symbols[sym] + raise DisallowedClass.new('dump', "Symbol(#{sym.inspect})") + end + + super + end + end + end +end diff --git a/ext/psych/lib/psych/y.rb b/ext/psych/lib/psych/y.rb new file mode 100644 index 0000000000..e857953c04 --- /dev/null +++ b/ext/psych/lib/psych/y.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Kernel + ### + # An alias for Psych.dump_stream meant to be used with IRB. + def y *objects + puts Psych.dump_stream(*objects) + end + private :y +end + diff --git a/ext/psych/psych.c b/ext/psych/psych.c new file mode 100644 index 0000000000..afbd7a3571 --- /dev/null +++ b/ext/psych/psych.c @@ -0,0 +1,36 @@ +#include <psych.h> + +/* call-seq: Psych.libyaml_version + * + * Returns the version of libyaml being used + */ +static VALUE libyaml_version(VALUE module) +{ + int major, minor, patch; + VALUE list[3]; + + yaml_get_version(&major, &minor, &patch); + + list[0] = INT2NUM(major); + list[1] = INT2NUM(minor); + list[2] = INT2NUM(patch); + + return rb_ary_new4((long)3, list); +} + +VALUE mPsych; + +void Init_psych(void) +{ + #ifdef HAVE_RB_EXT_RACTOR_SAFE + RB_EXT_RACTOR_SAFE(true); + #endif + mPsych = rb_define_module("Psych"); + + rb_define_singleton_method(mPsych, "libyaml_version", libyaml_version, 0); + + Init_psych_parser(); + Init_psych_emitter(); + Init_psych_to_ruby(); + Init_psych_yaml_tree(); +} diff --git a/ext/psych/psych.gemspec b/ext/psych/psych.gemspec new file mode 100644 index 0000000000..a32f79bc16 --- /dev/null +++ b/ext/psych/psych.gemspec @@ -0,0 +1,82 @@ +# -*- encoding: utf-8 -*- +# frozen_string_literal: true + +version_module = Module.new do + version_rb = File.join(__dir__, "lib/psych/versions.rb") + module_eval(File.read(version_rb), version_rb) +end + +Gem::Specification.new do |s| + s.name = "psych" + s.version = version_module::Psych::VERSION + s.authors = ["Aaron Patterson", "SHIBATA Hiroshi", "Charles Oliver Nutter"] + s.email = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org", "headius@headius.com"] + s.summary = "Psych is a YAML parser and emitter" + s.description = <<-DESCRIPTION +Psych is a YAML parser and emitter. Psych leverages libyaml[https://pyyaml.org/wiki/LibYAML] +for its YAML parsing and emitting capabilities. In addition to wrapping libyaml, +Psych also knows how to serialize and de-serialize most Ruby objects to and from the YAML format. +DESCRIPTION + s.homepage = "https://github.com/ruby/psych" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + + # for ruby core repository. + # It was generated by + # `git ls-files -z`.split("\x0").reject { |f| + # f.match(%r{^\.git|^(test|spec|features|bin|tool)/|^[A-Z]\w+file$|/extlibs$|\.(gemspec|java)$|jar}) + # } + s.files = [ + "CONTRIBUTING.md", "LICENSE", "README.md", "ext/psych/depend", + "ext/psych/extconf.rb", "ext/psych/psych.c", "ext/psych/psych.h", + "ext/psych/psych_emitter.c", "ext/psych/psych_emitter.h", + "ext/psych/psych_parser.c", "ext/psych/psych_parser.h", + "ext/psych/psych_to_ruby.c", "ext/psych/psych_to_ruby.h", + "ext/psych/psych_yaml_tree.c", "ext/psych/psych_yaml_tree.h", + "lib/psych.rb", "lib/psych/class_loader.rb", "lib/psych/coder.rb", + "lib/psych/core_ext.rb", "lib/psych/exception.rb", "lib/psych/handler.rb", + "lib/psych/handlers/document_stream.rb", "lib/psych/handlers/recorder.rb", + "lib/psych/json/ruby_events.rb", "lib/psych/json/stream.rb", + "lib/psych/json/tree_builder.rb", "lib/psych/json/yaml_events.rb", + "lib/psych/nodes.rb", "lib/psych/nodes/alias.rb", + "lib/psych/nodes/document.rb", "lib/psych/nodes/mapping.rb", + "lib/psych/nodes/node.rb", "lib/psych/nodes/scalar.rb", + "lib/psych/nodes/sequence.rb", "lib/psych/nodes/stream.rb", + "lib/psych/omap.rb", "lib/psych/parser.rb", "lib/psych/scalar_scanner.rb", + "lib/psych/set.rb", "lib/psych/stream.rb", "lib/psych/streaming.rb", + "lib/psych/syntax_error.rb", "lib/psych/tree_builder.rb", + "lib/psych/versions.rb", "lib/psych/visitors.rb", + "lib/psych/visitors/depth_first.rb", "lib/psych/visitors/emitter.rb", + "lib/psych/visitors/json_tree.rb", "lib/psych/visitors/to_ruby.rb", + "lib/psych/visitors/visitor.rb", "lib/psych/visitors/yaml_tree.rb", + "lib/psych/y.rb" + ] + + s.rdoc_options = ["--main", "README.md"] + s.extra_rdoc_files = ["README.md"] + + s.required_ruby_version = Gem::Requirement.new(">= 2.5.0") + s.required_rubygems_version = Gem::Requirement.new(">= 0") + + if RUBY_ENGINE == 'jruby' + s.platform = 'java' + s.files.concat [ + "ext/java/org/jruby/ext/psych/PsychEmitter.java", + "ext/java/org/jruby/ext/psych/PsychLibrary.java", + "ext/java/org/jruby/ext/psych/PsychParser.java", + "ext/java/org/jruby/ext/psych/PsychToRuby.java", + "lib/psych_jars.rb", + "lib/psych.jar" + ] + s.requirements = "jar org.snakeyaml:snakeyaml-engine, #{version_module::Psych::DEFAULT_SNAKEYAML_VERSION}" + s.add_dependency 'jar-dependencies', '>= 0.1.7' + else + s.extensions = ["ext/psych/extconf.rb"] + s.add_dependency 'stringio' + end + + s.add_dependency 'date' + + s.metadata['msys2_mingw_dependencies'] = 'libyaml' + s.metadata['changelog_uri'] = s.homepage + '/releases' +end diff --git a/ext/psych/psych.h b/ext/psych/psych.h new file mode 100644 index 0000000000..6b3d63f246 --- /dev/null +++ b/ext/psych/psych.h @@ -0,0 +1,17 @@ +#ifndef PSYCH_H +#define PSYCH_H + +#include <ruby.h> +#include <ruby/encoding.h> + +#include <yaml.h> + +#include <psych_parser.h> +#include <psych_emitter.h> +#include <psych_to_ruby.h> +#include <psych_yaml_tree.h> + +extern VALUE mPsych; + + +#endif diff --git a/ext/psych/psych_emitter.c b/ext/psych/psych_emitter.c new file mode 100644 index 0000000000..624ab7c528 --- /dev/null +++ b/ext/psych/psych_emitter.c @@ -0,0 +1,589 @@ +#include <psych.h> + +#if !defined(RARRAY_CONST_PTR) +#define RARRAY_CONST_PTR(s) (const VALUE *)RARRAY_PTR(s) +#endif +#if !defined(RARRAY_AREF) +#define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i] +#endif + +VALUE cPsychEmitter; +static ID id_io; +static ID id_write; +static ID id_line_width; +static ID id_indentation; +static ID id_canonical; + +static void emit(yaml_emitter_t * emitter, yaml_event_t * event) +{ + if(!yaml_emitter_emit(emitter, event)) + rb_raise(rb_eRuntimeError, "%s", emitter->problem); +} + +static int writer(void *ctx, unsigned char *buffer, size_t size) +{ + VALUE self = (VALUE)ctx, io = rb_attr_get(self, id_io); + VALUE str = rb_enc_str_new((const char *)buffer, (long)size, rb_utf8_encoding()); + VALUE wrote = rb_funcall(io, id_write, 1, str); + return (int)NUM2INT(wrote); +} + +static void dealloc(void * ptr) +{ + yaml_emitter_t * emitter; + + emitter = (yaml_emitter_t *)ptr; + yaml_emitter_delete(emitter); + xfree(emitter); +} + +#if 0 +static size_t memsize(const void *ptr) +{ + const yaml_emitter_t *emitter = ptr; + /* TODO: calculate emitter's size */ + return 0; +} +#endif + +static const rb_data_type_t psych_emitter_type = { + "Psych/emitter", + {0, dealloc, 0,}, + 0, 0, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY, +#endif +}; + +static VALUE allocate(VALUE klass) +{ + yaml_emitter_t * emitter; + VALUE obj = TypedData_Make_Struct(klass, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_emitter_initialize(emitter); + yaml_emitter_set_unicode(emitter, 1); + yaml_emitter_set_indent(emitter, 2); + + return obj; +} + +/* call-seq: Psych::Emitter.new(io, options = Psych::Emitter::OPTIONS) + * + * Create a new Psych::Emitter that writes to +io+. + */ +static VALUE initialize(int argc, VALUE *argv, VALUE self) +{ + yaml_emitter_t * emitter; + VALUE io, options; + VALUE line_width; + VALUE indent; + VALUE canonical; + + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + if (rb_scan_args(argc, argv, "11", &io, &options) == 2) { + line_width = rb_funcall(options, id_line_width, 0); + indent = rb_funcall(options, id_indentation, 0); + canonical = rb_funcall(options, id_canonical, 0); + + yaml_emitter_set_width(emitter, NUM2INT(line_width)); + yaml_emitter_set_indent(emitter, NUM2INT(indent)); + yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0); + } + + rb_ivar_set(self, id_io, io); + yaml_emitter_set_output(emitter, writer, (void *)self); + + return self; +} + +/* call-seq: emitter.start_stream(encoding) + * + * Start a stream emission with +encoding+ + * + * See Psych::Handler#start_stream + */ +static VALUE start_stream(VALUE self, VALUE encoding) +{ + yaml_emitter_t * emitter; + yaml_event_t event; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + Check_Type(encoding, T_FIXNUM); + + yaml_stream_start_event_initialize(&event, (yaml_encoding_t)NUM2INT(encoding)); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.end_stream + * + * End a stream emission + * + * See Psych::Handler#end_stream + */ +static VALUE end_stream(VALUE self) +{ + yaml_emitter_t * emitter; + yaml_event_t event; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_stream_end_event_initialize(&event); + + emit(emitter, &event); + + return self; +} + +struct start_document_data { + VALUE self; + VALUE version; + VALUE tags; + VALUE imp; + + yaml_tag_directive_t * head; +}; + +static VALUE start_document_try(VALUE d) +{ + struct start_document_data * data = (struct start_document_data *)d; + VALUE self = data->self; + VALUE version = data->version; + VALUE tags = data->tags; + VALUE imp = data->imp; + + yaml_emitter_t * emitter; + yaml_tag_directive_t * tail = NULL; + yaml_event_t event; + yaml_version_directive_t version_directive; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + Check_Type(version, T_ARRAY); + + if(RARRAY_LEN(version) > 0) { + VALUE major = rb_ary_entry(version, (long)0); + VALUE minor = rb_ary_entry(version, (long)1); + + version_directive.major = NUM2INT(major); + version_directive.minor = NUM2INT(minor); + } + + if(RTEST(tags)) { + long i = 0; + long len; + rb_encoding * encoding = rb_utf8_encoding(); + + Check_Type(tags, T_ARRAY); + + len = RARRAY_LEN(tags); + data->head = xcalloc((size_t)len, sizeof(yaml_tag_directive_t)); + tail = data->head; + + for(i = 0; i < len && i < RARRAY_LEN(tags); i++) { + VALUE tuple = RARRAY_AREF(tags, i); + VALUE name; + VALUE value; + + Check_Type(tuple, T_ARRAY); + + if(RARRAY_LEN(tuple) < 2) { + rb_raise(rb_eRuntimeError, "tag tuple must be of length 2"); + } + + name = RARRAY_AREF(tuple, 0); + value = RARRAY_AREF(tuple, 1); + StringValue(name); + StringValue(value); + name = rb_str_export_to_enc(name, encoding); + value = rb_str_export_to_enc(value, encoding); + + tail->handle = (yaml_char_t *)StringValueCStr(name); + tail->prefix = (yaml_char_t *)StringValueCStr(value); + + tail++; + } + } + + yaml_document_start_event_initialize( + &event, + (RARRAY_LEN(version) > 0) ? &version_directive : NULL, + data->head, + tail, + imp ? 1 : 0 + ); + + emit(emitter, &event); + + return self; +} + +static VALUE start_document_ensure(VALUE d) +{ + struct start_document_data * data = (struct start_document_data *)d; + + xfree(data->head); + + return Qnil; +} + +/* call-seq: emitter.start_document(version, tags, implicit) + * + * Start a document emission with YAML +version+, +tags+, and an +implicit+ + * start. + * + * See Psych::Handler#start_document + */ +static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp) +{ + struct start_document_data data = { + .self = self, + .version = version, + .tags = tags, + .imp = imp, + + .head = NULL, + }; + + return rb_ensure(start_document_try, (VALUE)&data, start_document_ensure, (VALUE)&data); +} + +/* call-seq: emitter.end_document(implicit) + * + * End a document emission with an +implicit+ ending. + * + * See Psych::Handler#end_document + */ +static VALUE end_document(VALUE self, VALUE imp) +{ + yaml_emitter_t * emitter; + yaml_event_t event; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_document_end_event_initialize(&event, imp ? 1 : 0); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.scalar(value, anchor, tag, plain, quoted, style) + * + * Emit a scalar with +value+, +anchor+, +tag+, and a +plain+ or +quoted+ + * string type with +style+. + * + * See Psych::Handler#scalar + */ +static VALUE scalar( + VALUE self, + VALUE value, + VALUE anchor, + VALUE tag, + VALUE plain, + VALUE quoted, + VALUE style + ) { + yaml_emitter_t * emitter; + yaml_event_t event; + rb_encoding *encoding; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + Check_Type(value, T_STRING); + + encoding = rb_utf8_encoding(); + + value = rb_str_export_to_enc(value, encoding); + + if(!NIL_P(anchor)) { + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, encoding); + } + + if(!NIL_P(tag)) { + Check_Type(tag, T_STRING); + tag = rb_str_export_to_enc(tag, encoding); + } + + const char *value_ptr = StringValuePtr(value); + yaml_scalar_event_initialize( + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)), + (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)), + (yaml_char_t*)value_ptr, + (int)RSTRING_LEN(value), + plain ? 1 : 0, + quoted ? 1 : 0, + (yaml_scalar_style_t)NUM2INT(style) + ); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.start_sequence(anchor, tag, implicit, style) + * + * Start emitting a sequence with +anchor+, a +tag+, +implicit+ sequence + * start and end, along with +style+. + * + * See Psych::Handler#start_sequence + */ +static VALUE start_sequence( + VALUE self, + VALUE anchor, + VALUE tag, + VALUE implicit, + VALUE style + ) { + yaml_emitter_t * emitter; + yaml_event_t event; + + rb_encoding * encoding = rb_utf8_encoding(); + + if(!NIL_P(anchor)) { + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, encoding); + } + + if(!NIL_P(tag)) { + Check_Type(tag, T_STRING); + tag = rb_str_export_to_enc(tag, encoding); + } + + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_sequence_start_event_initialize( + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)), + (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)), + implicit ? 1 : 0, + (yaml_sequence_style_t)NUM2INT(style) + ); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.end_sequence + * + * End sequence emission. + * + * See Psych::Handler#end_sequence + */ +static VALUE end_sequence(VALUE self) +{ + yaml_emitter_t * emitter; + yaml_event_t event; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_sequence_end_event_initialize(&event); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.start_mapping(anchor, tag, implicit, style) + * + * Start emitting a YAML map with +anchor+, +tag+, an +implicit+ start + * and end, and +style+. + * + * See Psych::Handler#start_mapping + */ +static VALUE start_mapping( + VALUE self, + VALUE anchor, + VALUE tag, + VALUE implicit, + VALUE style + ) { + yaml_emitter_t * emitter; + yaml_event_t event; + rb_encoding *encoding; + + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + encoding = rb_utf8_encoding(); + + if(!NIL_P(anchor)) { + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, encoding); + } + + if(!NIL_P(tag)) { + Check_Type(tag, T_STRING); + tag = rb_str_export_to_enc(tag, encoding); + } + + yaml_mapping_start_event_initialize( + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)), + (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)), + implicit ? 1 : 0, + (yaml_mapping_style_t)NUM2INT(style) + ); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.end_mapping + * + * Emit the end of a mapping. + * + * See Psych::Handler#end_mapping + */ +static VALUE end_mapping(VALUE self) +{ + yaml_emitter_t * emitter; + yaml_event_t event; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_mapping_end_event_initialize(&event); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.alias(anchor) + * + * Emit an alias with +anchor+. + * + * See Psych::Handler#alias + */ +static VALUE alias(VALUE self, VALUE anchor) +{ + yaml_emitter_t * emitter; + yaml_event_t event; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + if(!NIL_P(anchor)) { + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, rb_utf8_encoding()); + } + + yaml_alias_event_initialize( + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)) + ); + + emit(emitter, &event); + + return self; +} + +/* call-seq: emitter.canonical = true + * + * Set the output style to canonical, or not. + */ +static VALUE set_canonical(VALUE self, VALUE style) +{ + yaml_emitter_t * emitter; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_emitter_set_canonical(emitter, Qtrue == style ? 1 : 0); + + return style; +} + +/* call-seq: emitter.canonical + * + * Get the output style, canonical or not. + */ +static VALUE canonical(VALUE self) +{ + yaml_emitter_t * emitter; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + return (emitter->canonical == 0) ? Qfalse : Qtrue; +} + +/* call-seq: emitter.indentation = level + * + * Set the indentation level to +level+. The level must be less than 10 and + * greater than 1. + */ +static VALUE set_indentation(VALUE self, VALUE level) +{ + yaml_emitter_t * emitter; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_emitter_set_indent(emitter, NUM2INT(level)); + + return level; +} + +/* call-seq: emitter.indentation + * + * Get the indentation level. + */ +static VALUE indentation(VALUE self) +{ + yaml_emitter_t * emitter; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + return INT2NUM(emitter->best_indent); +} + +/* call-seq: emitter.line_width + * + * Get the preferred line width. + */ +static VALUE line_width(VALUE self) +{ + yaml_emitter_t * emitter; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + return INT2NUM(emitter->best_width); +} + +/* call-seq: emitter.line_width = width + * + * Set the preferred line with to +width+. + */ +static VALUE set_line_width(VALUE self, VALUE width) +{ + yaml_emitter_t * emitter; + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + + yaml_emitter_set_width(emitter, NUM2INT(width)); + + return width; +} + +void Init_psych_emitter(void) +{ +#undef rb_intern + VALUE psych = rb_define_module("Psych"); + VALUE handler = rb_define_class_under(psych, "Handler", rb_cObject); + cPsychEmitter = rb_define_class_under(psych, "Emitter", handler); + + rb_define_alloc_func(cPsychEmitter, allocate); + + rb_define_method(cPsychEmitter, "initialize", initialize, -1); + rb_define_method(cPsychEmitter, "start_stream", start_stream, 1); + rb_define_method(cPsychEmitter, "end_stream", end_stream, 0); + rb_define_method(cPsychEmitter, "start_document", start_document, 3); + rb_define_method(cPsychEmitter, "end_document", end_document, 1); + rb_define_method(cPsychEmitter, "scalar", scalar, 6); + rb_define_method(cPsychEmitter, "start_sequence", start_sequence, 4); + rb_define_method(cPsychEmitter, "end_sequence", end_sequence, 0); + rb_define_method(cPsychEmitter, "start_mapping", start_mapping, 4); + rb_define_method(cPsychEmitter, "end_mapping", end_mapping, 0); + rb_define_method(cPsychEmitter, "alias", alias, 1); + rb_define_method(cPsychEmitter, "canonical", canonical, 0); + rb_define_method(cPsychEmitter, "canonical=", set_canonical, 1); + rb_define_method(cPsychEmitter, "indentation", indentation, 0); + rb_define_method(cPsychEmitter, "indentation=", set_indentation, 1); + rb_define_method(cPsychEmitter, "line_width", line_width, 0); + rb_define_method(cPsychEmitter, "line_width=", set_line_width, 1); + + id_io = rb_intern("io"); + id_write = rb_intern("write"); + id_line_width = rb_intern("line_width"); + id_indentation = rb_intern("indentation"); + id_canonical = rb_intern("canonical"); +} diff --git a/ext/psych/psych_emitter.h b/ext/psych/psych_emitter.h new file mode 100644 index 0000000000..4c1482a78b --- /dev/null +++ b/ext/psych/psych_emitter.h @@ -0,0 +1,8 @@ +#ifndef PSYCH_EMITTER_H +#define PSYCH_EMITTER_H + +#include <psych.h> + +void Init_psych_emitter(void); + +#endif diff --git a/ext/psych/psych_parser.c b/ext/psych/psych_parser.c new file mode 100644 index 0000000000..00a2207b58 --- /dev/null +++ b/ext/psych/psych_parser.c @@ -0,0 +1,575 @@ +#include <psych.h> + +VALUE cPsychParser; + +static ID id_read; +static ID id_path; +static ID id_empty; +static ID id_start_stream; +static ID id_end_stream; +static ID id_start_document; +static ID id_end_document; +static ID id_alias; +static ID id_scalar; +static ID id_start_sequence; +static ID id_end_sequence; +static ID id_start_mapping; +static ID id_end_mapping; +static ID id_event_location; + +#define PSYCH_TRANSCODE(_str, _yaml_enc, _internal_enc) \ + do { \ + rb_enc_associate_index((_str), (_yaml_enc)); \ + if(_internal_enc) \ + (_str) = rb_str_export_to_enc((_str), (_internal_enc)); \ + } while (0) + +static int io_reader(void * data, unsigned char *buf, size_t size, size_t *read) +{ + VALUE io = (VALUE)data; + VALUE string = rb_funcall(io, id_read, 1, SIZET2NUM(size)); + + *read = 0; + + if(! NIL_P(string)) { + char * str = StringValuePtr(string); + size_t len = (size_t)RSTRING_LEN(string); + + /* IO#read(size) is documented to return at most `size` bytes, but a + * misbehaving IO-like object may return more. Clamp the copy to the + * buffer libyaml gave us to avoid writing past its end, rounding down + * to a character boundary so a multibyte character is never split. */ + if(len > size) { + rb_encoding * enc = rb_enc_get(string); + len = (size_t)(rb_enc_left_char_head(str, str + size, str + len, enc) - str); + } + + *read = len; + memcpy(buf, str, len); + } + + return 1; +} + +static void dealloc(void * ptr) +{ + yaml_parser_t * parser; + + parser = (yaml_parser_t *)ptr; + yaml_parser_delete(parser); + xfree(parser); +} + +#if 0 +static size_t memsize(const void *ptr) +{ + const yaml_parser_t *parser = ptr; + /* TODO: calculate parser's size */ + return 0; +} +#endif + +static const rb_data_type_t psych_parser_type = { + "Psych/parser", + {0, dealloc, 0,}, + 0, 0, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY, +#endif +}; + +static VALUE allocate(VALUE klass) +{ + yaml_parser_t * parser; + VALUE obj = TypedData_Make_Struct(klass, yaml_parser_t, &psych_parser_type, parser); + + yaml_parser_initialize(parser); + + return obj; +} + +static VALUE make_exception(yaml_parser_t * parser, VALUE path) +{ + if (parser->error == YAML_MEMORY_ERROR) { + return rb_eNoMemError; + } else { + size_t line, column; + VALUE ePsychSyntaxError; + + line = parser->context_mark.line + 1; + column = parser->context_mark.column + 1; + + ePsychSyntaxError = rb_const_get(mPsych, rb_intern("SyntaxError")); + + return rb_funcall(ePsychSyntaxError, rb_intern("new"), 6, + path, + SIZET2NUM(line), + SIZET2NUM(column), + SIZET2NUM(parser->problem_offset), + parser->problem ? rb_usascii_str_new2(parser->problem) : Qnil, + parser->context ? rb_usascii_str_new2(parser->context) : Qnil); + } +} + +static VALUE transcode_string(VALUE src, int * parser_encoding) +{ + int utf8 = rb_utf8_encindex(); + int utf16le = rb_enc_find_index("UTF-16LE"); + int utf16be = rb_enc_find_index("UTF-16BE"); + int source_encoding = rb_enc_get_index(src); + + if (source_encoding == utf8) { + *parser_encoding = YAML_UTF8_ENCODING; + return src; + } + + if (source_encoding == utf16le) { + *parser_encoding = YAML_UTF16LE_ENCODING; + return src; + } + + if (source_encoding == utf16be) { + *parser_encoding = YAML_UTF16BE_ENCODING; + return src; + } + + src = rb_str_export_to_enc(src, rb_utf8_encoding()); + RB_GC_GUARD(src); + + *parser_encoding = YAML_UTF8_ENCODING; + return src; +} + +static VALUE transcode_io(VALUE src, int * parser_encoding) +{ + VALUE io_external_encoding; + int io_external_enc_index; + + io_external_encoding = rb_funcall(src, rb_intern("external_encoding"), 0); + + /* if no encoding is returned, assume ascii8bit. */ + if (NIL_P(io_external_encoding)) { + io_external_enc_index = rb_ascii8bit_encindex(); + } else { + io_external_enc_index = rb_to_encoding_index(io_external_encoding); + } + + /* Treat US-ASCII as utf_8 */ + if (io_external_enc_index == rb_usascii_encindex()) { + *parser_encoding = YAML_UTF8_ENCODING; + return src; + } + + if (io_external_enc_index == rb_utf8_encindex()) { + *parser_encoding = YAML_UTF8_ENCODING; + return src; + } + + if (io_external_enc_index == rb_enc_find_index("UTF-16LE")) { + *parser_encoding = YAML_UTF16LE_ENCODING; + return src; + } + + if (io_external_enc_index == rb_enc_find_index("UTF-16BE")) { + *parser_encoding = YAML_UTF16BE_ENCODING; + return src; + } + + /* Just guess on ASCII-8BIT */ + if (io_external_enc_index == rb_ascii8bit_encindex()) { + *parser_encoding = YAML_ANY_ENCODING; + return src; + } + + /* If the external encoding is something we don't know how to handle, + * fall back to YAML_ANY_ENCODING. */ + *parser_encoding = YAML_ANY_ENCODING; + + return src; +} + +static VALUE protected_start_stream(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall(args[0], id_start_stream, 1, args[1]); +} + +static VALUE protected_start_document(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_start_document, 3, args + 1); +} + +static VALUE protected_end_document(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall(args[0], id_end_document, 1, args[1]); +} + +static VALUE protected_alias(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall(args[0], id_alias, 1, args[1]); +} + +static VALUE protected_scalar(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_scalar, 6, args + 1); +} + +static VALUE protected_start_sequence(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_start_sequence, 4, args + 1); +} + +static VALUE protected_end_sequence(VALUE handler) +{ + return rb_funcall(handler, id_end_sequence, 0); +} + +static VALUE protected_start_mapping(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_start_mapping, 4, args + 1); +} + +static VALUE protected_end_mapping(VALUE handler) +{ + return rb_funcall(handler, id_end_mapping, 0); +} + +static VALUE protected_empty(VALUE handler) +{ + return rb_funcall(handler, id_empty, 0); +} + +static VALUE protected_end_stream(VALUE handler) +{ + return rb_funcall(handler, id_end_stream, 0); +} + +static VALUE protected_event_location(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_event_location, 4, args + 1); +} + +static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path) +{ + yaml_parser_t * parser; + yaml_event_t event; + int done = 0; + int state = 0; + int parser_encoding = YAML_ANY_ENCODING; + int encoding = rb_utf8_encindex(); + rb_encoding * internal_enc = rb_default_internal_encoding(); + + TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser); + + yaml_parser_delete(parser); + yaml_parser_initialize(parser); + + if (rb_respond_to(yaml, id_read)) { + yaml = transcode_io(yaml, &parser_encoding); + yaml_parser_set_encoding(parser, parser_encoding); + yaml_parser_set_input(parser, io_reader, (void *)yaml); + } else { + StringValue(yaml); + yaml = transcode_string(yaml, &parser_encoding); + yaml_parser_set_encoding(parser, parser_encoding); + yaml_parser_set_input_string( + parser, + (const unsigned char *)RSTRING_PTR(yaml), + (size_t)RSTRING_LEN(yaml) + ); + } + + while(!done) { + VALUE event_args[5]; + VALUE start_line, start_column, end_line, end_column; + + if(parser->error || !yaml_parser_parse(parser, &event)) { + VALUE exception; + + exception = make_exception(parser, path); + yaml_parser_delete(parser); + yaml_parser_initialize(parser); + + rb_exc_raise(exception); + } + + start_line = SIZET2NUM(event.start_mark.line); + start_column = SIZET2NUM(event.start_mark.column); + end_line = SIZET2NUM(event.end_mark.line); + end_column = SIZET2NUM(event.end_mark.column); + + event_args[0] = handler; + event_args[1] = start_line; + event_args[2] = start_column; + event_args[3] = end_line; + event_args[4] = end_column; + rb_protect(protected_event_location, (VALUE)event_args, &state); + + switch(event.type) { + case YAML_STREAM_START_EVENT: + { + VALUE args[2]; + + args[0] = handler; + args[1] = INT2NUM(event.data.stream_start.encoding); + rb_protect(protected_start_stream, (VALUE)args, &state); + } + break; + case YAML_DOCUMENT_START_EVENT: + { + VALUE args[4]; + /* Get a list of tag directives (if any) */ + VALUE tag_directives = rb_ary_new(); + /* Grab the document version */ + VALUE version = event.data.document_start.version_directive ? + rb_ary_new3( + (long)2, + INT2NUM(event.data.document_start.version_directive->major), + INT2NUM(event.data.document_start.version_directive->minor) + ) : rb_ary_new(); + + if(event.data.document_start.tag_directives.start) { + yaml_tag_directive_t *start = + event.data.document_start.tag_directives.start; + yaml_tag_directive_t *end = + event.data.document_start.tag_directives.end; + for(; start != end; start++) { + VALUE handle = Qnil; + VALUE prefix = Qnil; + if(start->handle) { + handle = rb_str_new2((const char *)start->handle); + PSYCH_TRANSCODE(handle, encoding, internal_enc); + } + + if(start->prefix) { + prefix = rb_str_new2((const char *)start->prefix); + PSYCH_TRANSCODE(prefix, encoding, internal_enc); + } + + rb_ary_push(tag_directives, rb_ary_new3((long)2, handle, prefix)); + } + } + args[0] = handler; + args[1] = version; + args[2] = tag_directives; + args[3] = event.data.document_start.implicit == 1 ? Qtrue : Qfalse; + rb_protect(protected_start_document, (VALUE)args, &state); + } + break; + case YAML_DOCUMENT_END_EVENT: + { + VALUE args[2]; + + args[0] = handler; + args[1] = event.data.document_end.implicit == 1 ? Qtrue : Qfalse; + rb_protect(protected_end_document, (VALUE)args, &state); + } + break; + case YAML_ALIAS_EVENT: + { + VALUE args[2]; + VALUE alias = Qnil; + if(event.data.alias.anchor) { + alias = rb_str_new2((const char *)event.data.alias.anchor); + PSYCH_TRANSCODE(alias, encoding, internal_enc); + } + + args[0] = handler; + args[1] = alias; + rb_protect(protected_alias, (VALUE)args, &state); + } + break; + case YAML_SCALAR_EVENT: + { + VALUE args[7]; + VALUE anchor = Qnil; + VALUE tag = Qnil; + VALUE plain_implicit, quoted_implicit, style; + VALUE val = rb_str_new( + (const char *)event.data.scalar.value, + (long)event.data.scalar.length + ); + + PSYCH_TRANSCODE(val, encoding, internal_enc); + + if(event.data.scalar.anchor) { + anchor = rb_str_new2((const char *)event.data.scalar.anchor); + PSYCH_TRANSCODE(anchor, encoding, internal_enc); + } + + if(event.data.scalar.tag) { + tag = rb_str_new2((const char *)event.data.scalar.tag); + PSYCH_TRANSCODE(tag, encoding, internal_enc); + } + + plain_implicit = + event.data.scalar.plain_implicit == 0 ? Qfalse : Qtrue; + + quoted_implicit = + event.data.scalar.quoted_implicit == 0 ? Qfalse : Qtrue; + + style = INT2NUM(event.data.scalar.style); + + args[0] = handler; + args[1] = val; + args[2] = anchor; + args[3] = tag; + args[4] = plain_implicit; + args[5] = quoted_implicit; + args[6] = style; + rb_protect(protected_scalar, (VALUE)args, &state); + } + break; + case YAML_SEQUENCE_START_EVENT: + { + VALUE args[5]; + VALUE anchor = Qnil; + VALUE tag = Qnil; + VALUE implicit, style; + if(event.data.sequence_start.anchor) { + anchor = rb_str_new2((const char *)event.data.sequence_start.anchor); + PSYCH_TRANSCODE(anchor, encoding, internal_enc); + } + + tag = Qnil; + if(event.data.sequence_start.tag) { + tag = rb_str_new2((const char *)event.data.sequence_start.tag); + PSYCH_TRANSCODE(tag, encoding, internal_enc); + } + + implicit = + event.data.sequence_start.implicit == 0 ? Qfalse : Qtrue; + + style = INT2NUM(event.data.sequence_start.style); + + args[0] = handler; + args[1] = anchor; + args[2] = tag; + args[3] = implicit; + args[4] = style; + + rb_protect(protected_start_sequence, (VALUE)args, &state); + } + break; + case YAML_SEQUENCE_END_EVENT: + rb_protect(protected_end_sequence, handler, &state); + break; + case YAML_MAPPING_START_EVENT: + { + VALUE args[5]; + VALUE anchor = Qnil; + VALUE tag = Qnil; + VALUE implicit, style; + if(event.data.mapping_start.anchor) { + anchor = rb_str_new2((const char *)event.data.mapping_start.anchor); + PSYCH_TRANSCODE(anchor, encoding, internal_enc); + } + + if(event.data.mapping_start.tag) { + tag = rb_str_new2((const char *)event.data.mapping_start.tag); + PSYCH_TRANSCODE(tag, encoding, internal_enc); + } + + implicit = + event.data.mapping_start.implicit == 0 ? Qfalse : Qtrue; + + style = INT2NUM(event.data.mapping_start.style); + + args[0] = handler; + args[1] = anchor; + args[2] = tag; + args[3] = implicit; + args[4] = style; + + rb_protect(protected_start_mapping, (VALUE)args, &state); + } + break; + case YAML_MAPPING_END_EVENT: + rb_protect(protected_end_mapping, handler, &state); + break; + case YAML_NO_EVENT: + rb_protect(protected_empty, handler, &state); + break; + case YAML_STREAM_END_EVENT: + rb_protect(protected_end_stream, handler, &state); + done = 1; + break; + } + yaml_event_delete(&event); + if (state) rb_jump_tag(state); + } + + return self; +} + +/* + * call-seq: + * parser.mark # => #<Psych::Parser::Mark> + * + * Returns a Psych::Parser::Mark object that contains line, column, and index + * information. + */ +static VALUE mark(VALUE self) +{ + VALUE mark_klass; + VALUE args[3]; + yaml_parser_t * parser; + + TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser); + mark_klass = rb_const_get_at(cPsychParser, rb_intern("Mark")); + args[0] = SIZET2NUM(parser->mark.index); + args[1] = SIZET2NUM(parser->mark.line); + args[2] = SIZET2NUM(parser->mark.column); + + return rb_class_new_instance(3, args, mark_klass); +} + +void Init_psych_parser(void) +{ +#undef rb_intern +#if 0 + mPsych = rb_define_module("Psych"); +#endif + + cPsychParser = rb_define_class_under(mPsych, "Parser", rb_cObject); + rb_define_alloc_func(cPsychParser, allocate); + + /* Any encoding: Let the parser choose the encoding */ + rb_define_const(cPsychParser, "ANY", INT2NUM(YAML_ANY_ENCODING)); + + /* UTF-8 Encoding */ + rb_define_const(cPsychParser, "UTF8", INT2NUM(YAML_UTF8_ENCODING)); + + /* UTF-16-LE Encoding with BOM */ + rb_define_const(cPsychParser, "UTF16LE", INT2NUM(YAML_UTF16LE_ENCODING)); + + /* UTF-16-BE Encoding with BOM */ + rb_define_const(cPsychParser, "UTF16BE", INT2NUM(YAML_UTF16BE_ENCODING)); + + rb_require("psych/syntax_error"); + + rb_define_private_method(cPsychParser, "_native_parse", parse, 3); + rb_define_method(cPsychParser, "mark", mark, 0); + + id_read = rb_intern("read"); + id_path = rb_intern("path"); + id_empty = rb_intern("empty"); + id_start_stream = rb_intern("start_stream"); + id_end_stream = rb_intern("end_stream"); + id_start_document = rb_intern("start_document"); + id_end_document = rb_intern("end_document"); + id_alias = rb_intern("alias"); + id_scalar = rb_intern("scalar"); + id_start_sequence = rb_intern("start_sequence"); + id_end_sequence = rb_intern("end_sequence"); + id_start_mapping = rb_intern("start_mapping"); + id_end_mapping = rb_intern("end_mapping"); + id_event_location = rb_intern("event_location"); +} diff --git a/ext/psych/psych_parser.h b/ext/psych/psych_parser.h new file mode 100644 index 0000000000..beb3dd0709 --- /dev/null +++ b/ext/psych/psych_parser.h @@ -0,0 +1,6 @@ +#ifndef PSYCH_PARSER_H +#define PSYCH_PARSER_H + +void Init_psych_parser(void); + +#endif diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c new file mode 100644 index 0000000000..3ab0138b52 --- /dev/null +++ b/ext/psych/psych_to_ruby.c @@ -0,0 +1,42 @@ +#include <psych.h> + +VALUE cPsychVisitorsToRuby; + +/* call-seq: vis.build_exception(klass, message) + * + * Create an exception with class +klass+ and +message+ + */ +static VALUE build_exception(VALUE self, VALUE klass, VALUE mesg) +{ + VALUE e = rb_obj_alloc(klass); + +#ifdef TRUFFLERUBY + rb_exc_set_message(e, mesg); +#else + rb_iv_set(e, "mesg", mesg); +#endif + + return e; +} + +/* call-seq: vis.path2class(path) + * + * Convert +path+ string to a class + */ +static VALUE path2class(VALUE self, VALUE path) +{ + return rb_path_to_class(path); +} + +void Init_psych_to_ruby(void) +{ + VALUE psych = rb_define_module("Psych"); + VALUE class_loader = rb_define_class_under(psych, "ClassLoader", rb_cObject); + + VALUE visitors = rb_define_module_under(psych, "Visitors"); + VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject); + cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor); + + rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2); + rb_define_private_method(class_loader, "path2class", path2class, 1); +} diff --git a/ext/psych/psych_to_ruby.h b/ext/psych/psych_to_ruby.h new file mode 100644 index 0000000000..7b8e757a45 --- /dev/null +++ b/ext/psych/psych_to_ruby.h @@ -0,0 +1,8 @@ +#ifndef PSYCH_TO_RUBY_H +#define PSYCH_TO_RUBY_H + +#include <psych.h> + +void Init_psych_to_ruby(void); + +#endif diff --git a/ext/psych/psych_yaml_tree.c b/ext/psych/psych_yaml_tree.c new file mode 100644 index 0000000000..bbd93f874d --- /dev/null +++ b/ext/psych/psych_yaml_tree.c @@ -0,0 +1,11 @@ +#include <psych.h> + +VALUE cPsychVisitorsYamlTree; + +void Init_psych_yaml_tree(void) +{ + VALUE psych = rb_define_module("Psych"); + VALUE visitors = rb_define_module_under(psych, "Visitors"); + VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject); + cPsychVisitorsYamlTree = rb_define_class_under(visitors, "YAMLTree", visitor); +} diff --git a/ext/psych/psych_yaml_tree.h b/ext/psych/psych_yaml_tree.h new file mode 100644 index 0000000000..4628a69d71 --- /dev/null +++ b/ext/psych/psych_yaml_tree.h @@ -0,0 +1,8 @@ +#ifndef PSYCH_YAML_TREE_H +#define PSYCH_YAML_TREE_H + +#include <psych.h> + +void Init_psych_yaml_tree(void); + +#endif |
