From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001
From: Jari Vetoniemi <jari.vetoniemi@indooratlas.com>
Date: Mon, 16 Mar 2020 18:49:26 +0900
Subject: Fresh start

---
 jni/ruby/ext/psych/lib/psych.rb                    | 498 ++++++++++++++++++
 jni/ruby/ext/psych/lib/psych/class_loader.rb       | 101 ++++
 jni/ruby/ext/psych/lib/psych/coder.rb              |  94 ++++
 jni/ruby/ext/psych/lib/psych/core_ext.rb           |  35 ++
 jni/ruby/ext/psych/lib/psych/deprecated.rb         |  85 ++++
 jni/ruby/ext/psych/lib/psych/exception.rb          |  13 +
 jni/ruby/ext/psych/lib/psych/handler.rb            | 249 +++++++++
 .../psych/lib/psych/handlers/document_stream.rb    |  22 +
 jni/ruby/ext/psych/lib/psych/handlers/recorder.rb  |  39 ++
 jni/ruby/ext/psych/lib/psych/json/ruby_events.rb   |  19 +
 jni/ruby/ext/psych/lib/psych/json/stream.rb        |  16 +
 jni/ruby/ext/psych/lib/psych/json/tree_builder.rb  |  12 +
 jni/ruby/ext/psych/lib/psych/json/yaml_events.rb   |  29 ++
 jni/ruby/ext/psych/lib/psych/nodes.rb              |  77 +++
 jni/ruby/ext/psych/lib/psych/nodes/alias.rb        |  18 +
 jni/ruby/ext/psych/lib/psych/nodes/document.rb     |  60 +++
 jni/ruby/ext/psych/lib/psych/nodes/mapping.rb      |  56 ++
 jni/ruby/ext/psych/lib/psych/nodes/node.rb         |  55 ++
 jni/ruby/ext/psych/lib/psych/nodes/scalar.rb       |  67 +++
 jni/ruby/ext/psych/lib/psych/nodes/sequence.rb     |  81 +++
 jni/ruby/ext/psych/lib/psych/nodes/stream.rb       |  37 ++
 jni/ruby/ext/psych/lib/psych/omap.rb               |   4 +
 jni/ruby/ext/psych/lib/psych/parser.rb             |  51 ++
 jni/ruby/ext/psych/lib/psych/scalar_scanner.rb     | 149 ++++++
 jni/ruby/ext/psych/lib/psych/set.rb                |   4 +
 jni/ruby/ext/psych/lib/psych/stream.rb             |  37 ++
 jni/ruby/ext/psych/lib/psych/streaming.rb          |  27 +
 jni/ruby/ext/psych/lib/psych/syntax_error.rb       |  21 +
 jni/ruby/ext/psych/lib/psych/tree_builder.rb       |  96 ++++
 jni/ruby/ext/psych/lib/psych/visitors.rb           |   6 +
 .../ext/psych/lib/psych/visitors/depth_first.rb    |  26 +
 jni/ruby/ext/psych/lib/psych/visitors/emitter.rb   |  51 ++
 jni/ruby/ext/psych/lib/psych/visitors/json_tree.rb |  24 +
 jni/ruby/ext/psych/lib/psych/visitors/to_ruby.rb   | 389 ++++++++++++++
 jni/ruby/ext/psych/lib/psych/visitors/visitor.rb   |  19 +
 jni/ruby/ext/psych/lib/psych/visitors/yaml_tree.rb | 565 +++++++++++++++++++++
 jni/ruby/ext/psych/lib/psych/y.rb                  |   9 +
 37 files changed, 3141 insertions(+)
 create mode 100644 jni/ruby/ext/psych/lib/psych.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/class_loader.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/coder.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/core_ext.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/deprecated.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/exception.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/handler.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/handlers/document_stream.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/handlers/recorder.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/json/ruby_events.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/json/stream.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/json/tree_builder.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/json/yaml_events.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes/alias.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes/document.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes/mapping.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes/node.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes/scalar.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes/sequence.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/nodes/stream.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/omap.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/parser.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/scalar_scanner.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/set.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/stream.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/streaming.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/syntax_error.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/tree_builder.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/visitors.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/visitors/depth_first.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/visitors/emitter.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/visitors/json_tree.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/visitors/to_ruby.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/visitors/visitor.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/visitors/yaml_tree.rb
 create mode 100644 jni/ruby/ext/psych/lib/psych/y.rb

(limited to 'jni/ruby/ext/psych/lib')

diff --git a/jni/ruby/ext/psych/lib/psych.rb b/jni/ruby/ext/psych/lib/psych.rb
new file mode 100644
index 0000000..1933437
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych.rb
@@ -0,0 +1,498 @@
+require 'psych.so'
+require 'psych/nodes'
+require 'psych/streaming'
+require 'psych/visitors'
+require 'psych/handler'
+require 'psych/tree_builder'
+require 'psych/parser'
+require 'psych/omap'
+require 'psych/set'
+require 'psych/coder'
+require 'psych/core_ext'
+require 'psych/deprecated'
+require 'psych/stream'
+require 'psych/json/tree_builder'
+require 'psych/json/stream'
+require 'psych/handlers/document_stream'
+require 'psych/class_loader'
+
+###
+# = Overview
+#
+# Psych is a YAML parser and emitter.
+# Psych leverages libyaml [Home page: http://pyyaml.org/wiki/LibYAML]
+# or [HG repo: https://bitbucket.org/xi/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.load("--- a")             # => 'a'
+#   Psych.load("---\n - a\n - b")   # => ['a', 'b']
+#
+# ==== Reading from a file
+#
+#   Psych.load_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
+#
+# 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
+#
+#   parser = Psych::Parser.new(Psych::Handlers::Recorder.new)
+#
+#   parser.parse("---\n - a\n - b")
+#   parser.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 is Psych you're using
+  VERSION         = '2.0.8'
+
+  # The version of libyaml Psych is using
+  LIBYAML_VERSION = Psych.libyaml_version.join '.'
+
+  ###
+  # 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.
+  #
+  # 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("--- `", "file.txt")
+  #   rescue Psych::SyntaxError => ex
+  #     ex.file    # => 'file.txt'
+  #     ex.message # => "(file.txt): found character that cannot start any token"
+  #   end
+  def self.load yaml, filename = nil
+    result = parse(yaml, filename)
+    result ? result.to_ruby : result
+  end
+
+  ###
+  # Safely load the yaml string in +yaml+.  By default, only the following
+  # classes are allowed to be deserialized:
+  #
+  # * TrueClass
+  # * FalseClass
+  # * NilClass
+  # * Numeric
+  # * String
+  # * Array
+  # * Hash
+  #
+  # Recursive data structures are not allowed by default.  Arbitrary classes
+  # can be allowed by adding those classes to the +whitelist+.  They are
+  # additive.  For example, to allow Date deserialization:
+  #
+  #   Psych.safe_load(yaml, [Date])
+  #
+  # Now the Date class can be loaded in addition to the classes listed above.
+  #
+  # Aliases can be explicitly allowed by changing the +aliases+ parameter.
+  # For example:
+  #
+  #   x = []
+  #   x << x
+  #   yaml = Psych.dump x
+  #   Psych.safe_load yaml               # => raises an exception
+  #   Psych.safe_load yaml, [], [], true # => loads the aliases
+  #
+  # A Psych::DisallowedClass exception will be raised if the yaml contains a
+  # class that isn't in the whitelist.
+  #
+  # A Psych::BadAlias exception will be raised if the yaml contains aliases
+  # but the +aliases+ parameter is set to false.
+  def self.safe_load yaml, whitelist_classes = [], whitelist_symbols = [], aliases = false, filename = nil
+    result = parse(yaml, filename)
+    return unless result
+
+    class_loader = ClassLoader::Restricted.new(whitelist_classes.map(&:to_s),
+                                               whitelist_symbols.map(&:to_s))
+    scanner      = ScalarScanner.new class_loader
+    if aliases
+      visitor = Visitors::ToRuby.new scanner, class_loader
+    else
+      visitor = Visitors::NoAliasRuby.new scanner, class_loader
+    end
+    visitor.accept result
+  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("--- `", "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) 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
+    File.open filename, 'r:bom|utf-8' do |f|
+      parse f, filename
+    end
+  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("--- `", "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_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.
+  #
+  # 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)
+  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
+
+  ###
+  # 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
+    if block_given?
+      parse_stream(yaml, filename) do |node|
+        yield node.to_ruby
+      end
+    else
+      parse_stream(yaml, filename).children.map { |child| child.to_ruby }
+    end
+  end
+
+  ###
+  # Load the document contained in +filename+.  Returns the yaml contained in
+  # +filename+ as a Ruby object
+  def self.load_file filename
+    File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename }
+  end
+
+  # :stopdoc:
+  @domain_types = {}
+  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
+
+  @load_tags = {}
+  @dump_tags = {}
+  def self.add_tag tag, klass
+    @load_tags[tag] = klass.name
+    @dump_tags[klass] = tag
+  end
+
+  class << self
+    attr_accessor :load_tags
+    attr_accessor :dump_tags
+    attr_accessor :domain_types
+  end
+  # :startdoc:
+end
diff --git a/jni/ruby/ext/psych/lib/psych/class_loader.rb b/jni/ruby/ext/psych/lib/psych/class_loader.rb
new file mode 100644
index 0000000..46c6b93
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/class_loader.rb
@@ -0,0 +1,101 @@
+require 'psych/omap'
+require 'psych/set'
+
+module Psych
+  class ClassLoader # :nodoc:
+    BIG_DECIMAL = 'BigDecimal'
+    COMPLEX     = 'Complex'
+    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
+      define_method(const.to_s.downcase) do
+        load konst
+      end
+    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]
+
+    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, 'Symbol'
+        end
+      end
+
+      private
+
+      def find klassname
+        if @classes.include? klassname
+          super
+        else
+          raise DisallowedClass, klassname
+        end
+      end
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/coder.rb b/jni/ruby/ext/psych/lib/psych/coder.rb
new file mode 100644
index 0000000..2b830d2
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/coder.rb
@@ -0,0 +1,94 @@
+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/jni/ruby/ext/psych/lib/psych/core_ext.rb b/jni/ruby/ext/psych/lib/psych/core_ext.rb
new file mode 100644
index 0000000..9c8134d
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/core_ext.rb
@@ -0,0 +1,35 @@
+class Object
+  def self.yaml_tag url
+    Psych.add_tag(url, self)
+  end
+
+  # FIXME: rename this to "to_yaml" when syck is removed
+
+  ###
+  # call-seq: to_yaml(options = {})
+  #
+  # Convert an object to YAML.  See Psych.dump for more information on the
+  # available +options+.
+  def psych_to_yaml options = {}
+    Psych.dump self, options
+  end
+  remove_method :to_yaml rescue nil
+  alias :to_yaml :psych_to_yaml
+end
+
+class Module
+  def psych_yaml_as url
+    return if caller[0].end_with?('rubytypes.rb')
+    if $VERBOSE
+      warn "#{caller[0]}: yaml_as is deprecated, please use yaml_tag"
+    end
+    Psych.add_tag(url, self)
+  end
+
+  remove_method :yaml_as rescue nil
+  alias :yaml_as :psych_yaml_as
+end
+
+if defined?(::IRB)
+  require 'psych/y'
+end
diff --git a/jni/ruby/ext/psych/lib/psych/deprecated.rb b/jni/ruby/ext/psych/lib/psych/deprecated.rb
new file mode 100644
index 0000000..8c310b3
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/deprecated.rb
@@ -0,0 +1,85 @@
+require 'date'
+
+module Psych
+  DEPRECATED = __FILE__ # :nodoc:
+
+  module DeprecatedMethods # :nodoc:
+    attr_accessor :taguri
+    attr_accessor :to_yaml_style
+  end
+
+  def self.quick_emit thing, opts = {}, &block # :nodoc:
+    warn "#{caller[0]}: YAML.quick_emit is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
+    target = eval 'self', block.binding
+    target.extend DeprecatedMethods
+    metaclass = class << target; self; end
+    metaclass.send(:define_method, :encode_with) do |coder|
+      target.taguri        = coder.tag
+      target.to_yaml_style = coder.style
+      block.call coder
+    end
+    target.psych_to_yaml unless opts[:nodump]
+  end
+
+  # This method is deprecated, use Psych.load_stream instead.
+  def self.load_documents yaml, &block
+    if $VERBOSE
+      warn "#{caller[0]}: load_documents is deprecated, use load_stream"
+    end
+    list = load_stream yaml
+    return list unless block_given?
+    list.each(&block)
+  end
+
+  def self.detect_implicit thing
+    warn "#{caller[0]}: detect_implicit is deprecated" if $VERBOSE
+    return '' unless String === thing
+    return 'null' if '' == thing
+    ss = ScalarScanner.new(ClassLoader.new)
+    ss.tokenize(thing).class.name.downcase
+  end
+
+  def self.add_ruby_type type_tag, &block
+    warn "#{caller[0]}: add_ruby_type is deprecated, use add_domain_type" if $VERBOSE
+    domain = 'ruby.yaml.org,2002'
+    key = ['tag', domain, type_tag].join ':'
+    @domain_types[key] = [key, block]
+  end
+
+  def self.add_private_type type_tag, &block
+    warn "#{caller[0]}: add_private_type is deprecated, use add_domain_type" if $VERBOSE
+    domain = 'x-private'
+    key = [domain, type_tag].join ':'
+    @domain_types[key] = [key, block]
+  end
+
+  def self.tagurize thing
+    warn "#{caller[0]}: add_private_type is deprecated, use add_domain_type" if $VERBOSE
+    return thing unless String === thing
+    "tag:yaml.org,2002:#{thing}"
+  end
+
+  def self.read_type_class type, reference
+    warn "#{caller[0]}: read_type_class is deprecated" if $VERBOSE
+    _, _, type, name = type.split ':', 4
+
+    reference = name.split('::').inject(reference) do |k,n|
+      k.const_get(n.to_sym)
+    end if name
+    [type, reference]
+  end
+
+  def self.object_maker klass, hash
+    warn "#{caller[0]}: object_maker is deprecated" if $VERBOSE
+    klass.allocate.tap do |obj|
+      hash.each { |k,v| obj.instance_variable_set(:"@#{k}", v) }
+    end
+  end
+end
+
+class Object
+  undef :to_yaml_properties rescue nil
+  def to_yaml_properties # :nodoc:
+    instance_variables
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/exception.rb b/jni/ruby/ext/psych/lib/psych/exception.rb
new file mode 100644
index 0000000..ce9d2ca
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/exception.rb
@@ -0,0 +1,13 @@
+module Psych
+  class Exception < RuntimeError
+  end
+
+  class BadAlias < Exception
+  end
+
+  class DisallowedClass < Exception
+    def initialize klass_name
+      super "Tried to load unspecified class: #{klass_name}"
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/handler.rb b/jni/ruby/ext/psych/lib/psych/handler.rb
new file mode 100644
index 0000000..c55afe7
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/handler.rb
@@ -0,0 +1,249 @@
+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 achor, *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 idicating 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
+
+    ###
+    # Is this handler a streaming handler?
+    def streaming?
+      false
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/handlers/document_stream.rb b/jni/ruby/ext/psych/lib/psych/handlers/document_stream.rb
new file mode 100644
index 0000000..e429993
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/handlers/document_stream.rb
@@ -0,0 +1,22 @@
+require 'psych/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/jni/ruby/ext/psych/lib/psych/handlers/recorder.rb b/jni/ruby/ext/psych/lib/psych/handlers/recorder.rb
new file mode 100644
index 0000000..4eae62e
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/handlers/recorder.rb
@@ -0,0 +1,39 @@
+require 'psych/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/jni/ruby/ext/psych/lib/psych/json/ruby_events.rb b/jni/ruby/ext/psych/lib/psych/json/ruby_events.rb
new file mode 100644
index 0000000..6b73249
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/json/ruby_events.rb
@@ -0,0 +1,19 @@
+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/jni/ruby/ext/psych/lib/psych/json/stream.rb b/jni/ruby/ext/psych/lib/psych/json/stream.rb
new file mode 100644
index 0000000..fe2a6e9
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/json/stream.rb
@@ -0,0 +1,16 @@
+require 'psych/json/ruby_events'
+require 'psych/json/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/jni/ruby/ext/psych/lib/psych/json/tree_builder.rb b/jni/ruby/ext/psych/lib/psych/json/tree_builder.rb
new file mode 100644
index 0000000..b799c93
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/json/tree_builder.rb
@@ -0,0 +1,12 @@
+require 'psych/json/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/jni/ruby/ext/psych/lib/psych/json/yaml_events.rb b/jni/ruby/ext/psych/lib/psych/json/yaml_events.rb
new file mode 100644
index 0000000..d054d9b
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/json/yaml_events.rb
@@ -0,0 +1,29 @@
+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/jni/ruby/ext/psych/lib/psych/nodes.rb b/jni/ruby/ext/psych/lib/psych/nodes.rb
new file mode 100644
index 0000000..f3b33fe
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes.rb
@@ -0,0 +1,77 @@
+require 'psych/nodes/node'
+require 'psych/nodes/stream'
+require 'psych/nodes/document'
+require 'psych/nodes/sequence'
+require 'psych/nodes/scalar'
+require 'psych/nodes/mapping'
+require 'psych/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/jni/ruby/ext/psych/lib/psych/nodes/alias.rb b/jni/ruby/ext/psych/lib/psych/nodes/alias.rb
new file mode 100644
index 0000000..5bd4df1
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes/alias.rb
@@ -0,0 +1,18 @@
+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
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/nodes/document.rb b/jni/ruby/ext/psych/lib/psych/nodes/document.rb
new file mode 100644
index 0000000..32014d6
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes/document.rb
@@ -0,0 +1,60 @@
+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
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/nodes/mapping.rb b/jni/ruby/ext/psych/lib/psych/nodes/mapping.rb
new file mode 100644
index 0000000..5ba95ce
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes/mapping.rb
@@ -0,0 +1,56 @@
+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
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/nodes/node.rb b/jni/ruby/ext/psych/lib/psych/nodes/node.rb
new file mode 100644
index 0000000..83233a6
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes/node.rb
@@ -0,0 +1,55 @@
+require 'stringio'
+require 'psych/class_loader'
+require 'psych/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
+
+      # 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
+        Visitors::ToRuby.create.accept(self)
+      end
+      alias :transform :to_ruby
+
+      ###
+      # Convert this node to YAML.
+      #
+      # See also Psych::Visitors::Emitter
+      def yaml io = nil, options = {}
+        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
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/nodes/scalar.rb b/jni/ruby/ext/psych/lib/psych/nodes/scalar.rb
new file mode 100644
index 0000000..1b1b25b
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes/scalar.rb
@@ -0,0 +1,67 @@
+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 idicating 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
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/nodes/sequence.rb b/jni/ruby/ext/psych/lib/psych/nodes/sequence.rb
new file mode 100644
index 0000000..7e907fe
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes/sequence.rb
@@ -0,0 +1,81 @@
+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
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/nodes/stream.rb b/jni/ruby/ext/psych/lib/psych/nodes/stream.rb
new file mode 100644
index 0000000..7cf5e03
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/nodes/stream.rb
@@ -0,0 +1,37 @@
+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
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/omap.rb b/jni/ruby/ext/psych/lib/psych/omap.rb
new file mode 100644
index 0000000..6286270
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/omap.rb
@@ -0,0 +1,4 @@
+module Psych
+  class Omap < ::Hash
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/parser.rb b/jni/ruby/ext/psych/lib/psych/parser.rb
new file mode 100644
index 0000000..84085f1
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/parser.rb
@@ -0,0 +1,51 @@
+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
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/scalar_scanner.rb b/jni/ruby/ext/psych/lib/psych/scalar_scanner.rb
new file mode 100644
index 0000000..9300790
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/scalar_scanner.rb
@@ -0,0 +1,149 @@
+require 'strscan'
+
+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
+    FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10)
+              |[-+]?[0-9][0-9_,]*(:[0-5]?[0-9])+\.[0-9_]*(?# base 60)
+              |[-+]?\.(inf|Inf|INF)(?# infinity)
+              |\.(nan|NaN|NAN)(?# not a number))$/x
+
+    # Taken from http://yaml.org/type/int.html
+    INTEGER = /^(?:[-+]?0b[0-1_]+          (?# base 2)
+                  |[-+]?0[0-7_]+           (?# base 8)
+                  |[-+]?(?:0|[1-9][0-9_]*) (?# base 10)
+                  |[-+]?0x[0-9a-fA-F_]+    (?# base 16))$/x
+
+    attr_reader :class_loader
+
+    # Create a new scanner
+    def initialize class_loader
+      @string_cache = {}
+      @symbol_cache = {}
+      @class_loader = class_loader
+    end
+
+    # Tokenize +string+ returning the Ruby object
+    def tokenize string
+      return nil if string.empty?
+      return string if @string_cache.key?(string)
+      return @symbol_cache[string] if @symbol_cache.key?(string)
+
+      case string
+      # Check for a String type, being careful not to get caught by hash keys, hex values, and
+      # special floats (e.g., -.inf).
+      when /^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/, /\n/
+        if string.length > 5
+          @string_cache[string] = true
+          return string
+        end
+
+        case string
+        when /^[^ytonf~]/i
+          @string_cache[string] = true
+          string
+        when '~', /^null$/i
+          nil
+        when /^(yes|true|on)$/i
+          true
+        when /^(no|false|off)$/i
+          false
+        else
+          @string_cache[string] = true
+          string
+        end
+      when TIME
+        begin
+          parse_time string
+        rescue ArgumentError
+          string
+        end
+      when /^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/
+        require 'date'
+        begin
+          class_loader.date.strptime(string, '%Y-%m-%d')
+        rescue ArgumentError
+          string
+        end
+      when /^\.inf$/i
+        Float::INFINITY
+      when /^-\.inf$/i
+        -Float::INFINITY
+      when /^\.nan$/i
+        Float::NAN
+      when /^:./
+        if string =~ /^:(["'])(.*)\1/
+          @symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, ''))
+        else
+          @symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, ''))
+        end
+      when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+$/
+        i = 0
+        string.split(':').each_with_index do |n,e|
+          i += (n.to_i * 60 ** (e - 2).abs)
+        end
+        i
+      when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]*$/
+        i = 0
+        string.split(':').each_with_index do |n,e|
+          i += (n.to_f * 60 ** (e - 2).abs)
+        end
+        i
+      when FLOAT
+        if string =~ /\A[-+]?\.\Z/
+          @string_cache[string] = true
+          string
+        else
+          Float(string.gsub(/[,_]|\.$/, ''))
+        end
+      else
+        int = parse_int string.gsub(/[,_]/, '')
+        return int if int
+
+        @string_cache[string] = true
+        string
+      end
+    end
+
+    ###
+    # Parse and return an int from +string+
+    def parse_int string
+      return unless INTEGER === string
+      Integer(string)
+    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.at((time - offset).to_i, us)
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/set.rb b/jni/ruby/ext/psych/lib/psych/set.rb
new file mode 100644
index 0000000..6793a8e
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/set.rb
@@ -0,0 +1,4 @@
+module Psych
+  class Set < ::Hash
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/stream.rb b/jni/ruby/ext/psych/lib/psych/stream.rb
new file mode 100644
index 0000000..88c4c4c
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/stream.rb
@@ -0,0 +1,37 @@
+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/jni/ruby/ext/psych/lib/psych/streaming.rb b/jni/ruby/ext/psych/lib/psych/streaming.rb
new file mode 100644
index 0000000..9d94eb5
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/streaming.rb
@@ -0,0 +1,27 @@
+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/jni/ruby/ext/psych/lib/psych/syntax_error.rb b/jni/ruby/ext/psych/lib/psych/syntax_error.rb
new file mode 100644
index 0000000..e200ef0
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/syntax_error.rb
@@ -0,0 +1,21 @@
+require 'psych/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/jni/ruby/ext/psych/lib/psych/tree_builder.rb b/jni/ruby/ext/psych/lib/psych/tree_builder.rb
new file mode 100644
index 0000000..c8f3447
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/tree_builder.rb
@@ -0,0 +1,96 @@
+require 'psych/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
+    end
+
+    %w{
+      Sequence
+      Mapping
+    }.each do |node|
+      class_eval %{
+        def start_#{node.downcase}(anchor, tag, implicit, style)
+          n = Nodes::#{node}.new(anchor, tag, implicit, style)
+          @last.children << n
+          push n
+        end
+
+        def end_#{node.downcase}
+          pop
+        end
+      }
+    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
+      @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
+      pop
+    end
+
+    def start_stream encoding
+      @root = Nodes::Stream.new(encoding)
+      push @root
+    end
+
+    def end_stream
+      pop
+    end
+
+    def scalar value, anchor, tag, plain, quoted, style
+      s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style)
+      @last.children << s
+      s
+    end
+
+    def alias anchor
+      @last.children << Nodes::Alias.new(anchor)
+    end
+
+    private
+    def push value
+      @stack.push value
+      @last = value
+    end
+
+    def pop
+      x = @stack.pop
+      @last = @stack.last
+      x
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/visitors.rb b/jni/ruby/ext/psych/lib/psych/visitors.rb
new file mode 100644
index 0000000..cc98b10
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/visitors.rb
@@ -0,0 +1,6 @@
+require 'psych/visitors/visitor'
+require 'psych/visitors/to_ruby'
+require 'psych/visitors/emitter'
+require 'psych/visitors/yaml_tree'
+require 'psych/visitors/json_tree'
+require 'psych/visitors/depth_first'
diff --git a/jni/ruby/ext/psych/lib/psych/visitors/depth_first.rb b/jni/ruby/ext/psych/lib/psych/visitors/depth_first.rb
new file mode 100644
index 0000000..c6eb814
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/visitors/depth_first.rb
@@ -0,0 +1,26 @@
+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/jni/ruby/ext/psych/lib/psych/visitors/emitter.rb b/jni/ruby/ext/psych/lib/psych/visitors/emitter.rb
new file mode 100644
index 0000000..c886e50
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/visitors/emitter.rb
@@ -0,0 +1,51 @@
+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/jni/ruby/ext/psych/lib/psych/visitors/json_tree.rb b/jni/ruby/ext/psych/lib/psych/visitors/json_tree.rb
new file mode 100644
index 0000000..0127ac8
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/visitors/json_tree.rb
@@ -0,0 +1,24 @@
+require 'psych/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/jni/ruby/ext/psych/lib/psych/visitors/to_ruby.rb b/jni/ruby/ext/psych/lib/psych/visitors/to_ruby.rb
new file mode 100644
index 0000000..e696ebd
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -0,0 +1,389 @@
+require 'psych/scalar_scanner'
+require 'psych/class_loader'
+require 'psych/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
+      def self.create
+        class_loader = ClassLoader.new
+        scanner      = ScalarScanner.new class_loader
+        new(scanner, class_loader)
+      end
+
+      attr_reader :class_loader
+
+      def initialize ss, class_loader
+        super()
+        @st = {}
+        @ss = ss
+        @domain_types = Psych.domain_types
+        @class_loader = class_loader
+      end
+
+      def accept target
+        result = super
+        return result if @domain_types.empty? || !target.tag
+
+        key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:')
+        key = "tag:#{key}" unless key =~ /^(tag:|x-private)/
+
+        if @domain_types.key? key
+          value, block = @domain_types[key]
+          return block.call value, result
+        end
+
+        result
+      end
+
+      def deserialize o
+        if klass = resolve_class(Psych.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'
+          class_loader.big_decimal._load o.value
+        when "!ruby/object:DateTime"
+          class_loader.date_time
+          require 'date'
+          @ss.parse_time(o.value).to_datetime
+        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
+          o.value =~ /^\/(.*)\/([mixn]*)$/
+          source  = $1
+          options = 0
+          lang    = nil
+          ($2 || '').split('').each 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(Psych.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 Psych.load_tags[o.tag]
+          return revive(resolve_class(Psych.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\/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'))
+          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 /^!map:(.*)$/, /^!ruby\/hash:(.*)$/
+          revive_hash register(o, resolve_class($1).new), 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 BadAlias, "Unknown alias: #{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 revive_hash hash, o
+        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
+            hash[key] = val
+          end
+
+        }
+        hash
+      end
+
+      def merge_key hash, key, val
+      end
+
+      def revive klass, node
+        s = register(node, klass.allocate)
+        init_with(s, revive_hash({}, node), 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
+        elsif o.respond_to?(:yaml_initialize)
+          if $VERBOSE
+            warn "Implementing #{o.class}#yaml_initialize is deprecated, please implement \"init_with(coder)\""
+          end
+          o.yaml_initialize c.tag, c.map
+        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 BadAlias, "Unknown alias: #{o.anchor}"
+      end
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/visitors/visitor.rb b/jni/ruby/ext/psych/lib/psych/visitors/visitor.rb
new file mode 100644
index 0000000..4d7772f
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/visitors/visitor.rb
@@ -0,0 +1,19 @@
+module Psych
+  module Visitors
+    class Visitor
+      def accept target
+        visit target
+      end
+
+      private
+
+      DISPATCH = Hash.new do |hash, klass|
+        hash[klass] = "visit_#{klass.name.gsub('::', '_')}"
+      end
+
+      def visit target
+        send DISPATCH[target.class], target
+      end
+    end
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/visitors/yaml_tree.rb b/jni/ruby/ext/psych/lib/psych/visitors/yaml_tree.rb
new file mode 100644
index 0000000..989e1f0
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/visitors/yaml_tree.rb
@@ -0,0 +1,565 @@
+require 'psych/tree_builder'
+require 'psych/scalar_scanner'
+require 'psych/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   = {}
+          @obj_to_node = {}
+          @targets     = []
+          @counter     = 0
+        end
+
+        def register target, node
+          @targets << target
+          @obj_to_node[target.object_id] = node
+        end
+
+        def key? target
+          @obj_to_node.key? target.object_id
+        rescue NoMethodError
+          false
+        end
+
+        def id_for target
+          @obj_to_id[target.object_id] ||= (@counter += 1)
+        end
+
+        def node_for target
+          @obj_to_node[target.object_id]
+        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 self.new emitter = nil, ss = nil, options = nil
+        return super if emitter && ss && options
+
+        if $VERBOSE
+          warn "This API is deprecated, please pass an emitter, scalar scanner, and options or call #{self}.create() (#{caller.first})"
+        end
+        create emitter, ss
+      end
+
+      def initialize emitter, ss, options
+        super()
+        @started  = false
+        @finished = false
+        @emitter  = emitter
+        @st       = Registrar.new
+        @ss       = ss
+        @options  = options
+        @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 #{target.class}") unless method
+
+          h[klass] = method
+        end
+      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?(:to_yaml)
+          begin
+            loc = target.method(:to_yaml).source_location.first
+            if loc !~ /(syck\/rubytypes.rb|psych\/core_ext.rb)/
+              unless target.respond_to?(:encode_with)
+                if $VERBOSE
+                  warn "implementing to_yaml is deprecated, please implement \"encode_with\""
+                end
+
+                target.to_yaml(:nodump => true)
+              end
+            end
+          rescue
+            # public_method or source_location might be overridden,
+            # and it's OK to skip it since it's only to emit a warning
+          end
+        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, '!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
+
+      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
+        tag = ['!ruby/exception', o.class.name].join ':'
+
+        @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
+
+        {
+          'message'   => private_iv_get(o, 'mesg'),
+          'backtrace' => private_iv_get(o, 'backtrace'),
+        }.each do |k,v|
+          next unless v
+          @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
+          accept v
+        end
+
+        dump_ivars o
+
+        @emitter.end_mapping
+      end
+
+      def visit_NameError o
+        tag = ['!ruby/exception', o.class.name].join ':'
+
+        @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
+
+        {
+          'message'   => o.message.to_s,
+          'backtrace' => private_iv_get(o, 'backtrace'),
+        }.each do |k,v|
+          next unless v
+          @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
+          accept v
+        end
+
+        dump_ivars o
+
+        @emitter.end_mapping
+      end
+
+      def visit_Regexp o
+        register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
+      end
+
+      def visit_DateTime o
+        formatted = if o.offset.zero?
+                      o.strftime("%Y-%m-%d %H:%M:%S.%9N Z".freeze)
+                    else
+                      o.strftime("%Y-%m-%d %H:%M:%S.%9N %:z".freeze)
+                    end
+        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
+      alias :visit_Date :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
+        str   = o
+
+        if binary?(o)
+          str   = [o].pack('m').chomp
+          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 =~ /\n/
+          style = Nodes::Scalar::LITERAL
+        elsif o == '<<'
+          style = Nodes::Scalar::SINGLE_QUOTED
+          tag   = 'tag:yaml.org,2002:str'
+          plain = false
+          quote = false
+        elsif o =~ /^\W[^"]*$/
+          style = Nodes::Scalar::DOUBLE_QUOTED
+        else
+          unless String === @ss.tokenize(o)
+            style = Nodes::Scalar::SINGLE_QUOTED
+          end
+        end
+
+        ivars = find_ivars o
+
+        if ivars.empty?
+          unless o.class == ::String
+            tag = "!ruby/string:#{o.class}"
+            plain = false
+            quote = false
+          end
+          @emitter.scalar str, nil, tag, plain, quote, style
+        else
+          maptag = '!ruby/string'
+          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 str, 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
+        tag      = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}"
+        implicit = !tag
+
+        register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK))
+
+        o.each do |k,v|
+          accept k
+          accept v
+        end
+
+        @emitter.end_mapping
+      end
+
+      def visit_Psych_Set o
+        register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))
+
+        o.each do |k,v|
+          accept k
+          accept v
+        end
+
+        @emitter.end_mapping
+      end
+
+      def visit_Array o
+        if o.class == ::Array
+          register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
+          o.each { |c| accept c }
+          @emitter.end_sequence
+        else
+          visit_array_subclass o
+        end
+      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
+      # FIXME: Remove the index and count checks in Psych 3.0
+      NULL         = "\x00"
+      BINARY_RANGE = "\x00-\x7F"
+      WS_RANGE     = "^ -~\t\r\n"
+
+      def binary? string
+        (string.encoding == Encoding::ASCII_8BIT && !string.ascii_only?) ||
+          string.index(NULL) ||
+          string.count(BINARY_RANGE, WS_RANGE).fdiv(string.length) > 0.3
+      end
+
+      def visit_array_subclass o
+        tag = "!ruby/array:#{o.class}"
+        if o.instance_variables.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)
+          o.instance_variables.each do |ivar|
+            accept ivar
+            accept o.instance_variable_get ivar
+          end
+          @emitter.end_mapping
+
+          @emitter.end_mapping
+        end
+      end
+
+      def dump_list o
+      end
+
+      # '%:z' was no defined until 1.9.3
+      if RUBY_VERSION < '1.9.3'
+        def format_time time
+          formatted = time.strftime("%Y-%m-%d %H:%M:%S.%9N")
+
+          if time.utc?
+            formatted += " Z"
+          else
+            zone = time.strftime('%z')
+            formatted += " #{zone[0,3]}:#{zone[3,5]}"
+          end
+
+          formatted
+        end
+      else
+        def format_time time
+          if time.utc?
+            time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
+          else
+            time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z")
+          end
+        end
+      end
+
+      # FIXME: remove this method once "to_yaml_properties" is removed
+      def find_ivars target
+        begin
+          loc = target.method(:to_yaml_properties).source_location.first
+          unless loc.start_with?(Psych::DEPRECATED) || loc.end_with?('rubytypes.rb')
+            if $VERBOSE
+              warn "#{loc}: to_yaml_properties is deprecated, please implement \"encode_with(coder)\""
+            end
+            return target.to_yaml_properties
+          end
+        rescue
+          # public_method or source_location might be overridden,
+          # and it's OK to skip it since it's only to emit a warning.
+        end
+
+        target.instance_variables
+      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
+      end
+
+      def emit_coder c
+        case c.type
+        when :scalar
+          @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY
+        when :seq
+          @emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK
+          c.seq.each do |thing|
+            accept thing
+          end
+          @emitter.end_sequence
+        when :map
+          @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
+        ivars = find_ivars target
+
+        ivars.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
+  end
+end
diff --git a/jni/ruby/ext/psych/lib/psych/y.rb b/jni/ruby/ext/psych/lib/psych/y.rb
new file mode 100644
index 0000000..d0e049d
--- /dev/null
+++ b/jni/ruby/ext/psych/lib/psych/y.rb
@@ -0,0 +1,9 @@
+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
+
-- 
cgit v1.2.3-70-g09d2