[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, upstream, updated. puppet-0.24.5-rc3-1456-g2f0b1e5

James Turnbull james at lovedthanlost.net
Tue Oct 27 17:06:02 UTC 2009


The following commit has been merged in the upstream branch:
commit bca3b70437666a8b840af032cab20fc1ea4f18a2
Author: Markus Roberts <Markus at reality.com>
Date:   Fri Oct 9 15:23:19 2009 -0700

    Bundling of pure ruby json lib as "pson"
    
    Bundeling and renaming the pure ruby json library to addresses a
    number of cross version serliaization bugs (#2615, et al).
    
    This patch adds a subset of the files from the json_pure gem to
    lib/puppet/external/pson (renamed to avoid conflicts with rails) so
    that we will always have a known-good erialization format available.
    
    The pure ruby json gem as distibuted defers to the compiled version
    if it is installed.  This is problematic in some circumstances so the
    files that have been brought over have been modified to always and
    only use the bundled version.
    
    It's a large patch, so here's a breakdown of the change categories:
    
    The majority of the lines are only marginally interesting:
    
    * The json lib itself (in lib/puppet/external/pson) make up the bulk
      of the lines.
    * Renaming of json to pson make up the second largest group.
    
    Somewhat more interesting are the following, which can be located by
    searching the diffs for the indicated strings:
    
    * Adjusting tests to reflect the changes
    * Changing the encoding/decoding behavior so that nested structures
      (e.g. resources) don't serialize as escaped strings.  This should
      make it much easier to process the results with external tools, if
      needed.  Search for "to_pson" and "to_pson_data_hash"
    * Cleaning up the envelope/metadata
        * Now provides a document_type (as opposed to a ruby class name) by
          using a symple registration scheme instead of constant lookup
          (search for "document_type")
        * Added an api_version (search for "api_version")
        * Added a hash for document metadata (search for "metadata")
    * Removing the yaml monkeypatch and instead disabling yaml serialization
      on ruby 1.8.1 in favor of pson (search for "yaml")
    * Cleaning up the json/rails feature interaction (they're now totally
      independent) (search for "feature")

diff --git a/lib/puppet/application/puppet.rb b/lib/puppet/application/puppet.rb
index a87ae48..6fdd5a0 100644
--- a/lib/puppet/application/puppet.rb
+++ b/lib/puppet/application/puppet.rb
@@ -49,12 +49,12 @@ Puppet::Application.new(:puppet) do
         end
 
         begin
-            catalog = JSON.parse(text)
+            catalog = PSON.parse(text)
             unless catalog.is_a?(Puppet::Resource::Catalog)
-                catalog = Puppet::Resource::Catalog.json_create(catalog)
+                catalog = Puppet::Resource::Catalog.pson_create(catalog)
             end
         rescue => detail
-            raise Puppet::Error, "Could not deserialize catalog from json: %s" % detail
+            raise Puppet::Error, "Could not deserialize catalog from pson: %s" % detail
         end
 
         catalog = catalog.to_ral
diff --git a/lib/puppet/application/puppetmasterd.rb b/lib/puppet/application/puppetmasterd.rb
index 40bc306..9b0bf30 100644
--- a/lib/puppet/application/puppetmasterd.rb
+++ b/lib/puppet/application/puppetmasterd.rb
@@ -53,13 +53,13 @@ Puppet::Application.new(:puppetmasterd) do
 
     command(:compile) do
         Puppet::Util::Log.newdestination :console
-        raise ArgumentError, "Cannot render compiled catalogs without json support" unless Puppet.features.json?
+        raise ArgumentError, "Cannot render compiled catalogs without pson support" unless Puppet.features.pson?
         begin
             unless catalog = Puppet::Resource::Catalog.find(options[:node])
                 raise "Could not compile catalog for %s" % options[:node] 
             end
 
-            $stdout.puts catalog.render(:json)
+            $stdout.puts catalog.render(:pson)
         rescue => detail
             $stderr.puts detail
             exit(30)
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 3a0feec..4924f2c 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -168,7 +168,7 @@ module Puppet
         :queue_source => ["stomp://localhost:61613/", "Which type of queue to use for asynchronous processing.  If your stomp server requires
             authentication, you can include it in the URI as long as your stomp client library is at least 1.1.1"],
         :async_storeconfigs => {:default => false, :desc => "Whether to use a queueing system to provide asynchronous database integration.
-            Requires that ``puppetqd`` be running and that 'JSON' support for ruby be installed.",
+            Requires that ``puppetqd`` be running and that 'PSON' support for ruby be installed.",
             :hook => proc do |value|
                 if value
                     # This reconfigures the terminii for Node, Facts, and Catalog
@@ -522,7 +522,7 @@ module Puppet
             authority requests.  It's a separate server because it cannot
             and does not need to horizontally scale."],
         :ca_port => ["$masterport", "The port to use for the certificate authority."],
-        :preferred_serialization_format => ["json", "The preferred means of serializing
+        :preferred_serialization_format => ["pson", "The preferred means of serializing
             ruby instances for passing over the wire.  This won't guarantee that all
             instances will be serialized using this method, since not all classes
             can be guaranteed to support this format, but it will be used for all
diff --git a/lib/puppet/external/pson/common.rb b/lib/puppet/external/pson/common.rb
new file mode 100644
index 0000000..71b85ce
--- /dev/null
+++ b/lib/puppet/external/pson/common.rb
@@ -0,0 +1,367 @@
+require 'puppet/external/pson/version'
+
+module PSON
+  class << self
+    # If _object_ is string-like parse the string and return the parsed result
+    # as a Ruby data structure. Otherwise generate a PSON text from the Ruby
+    # data structure object and return it.
+    #
+    # The _opts_ argument is passed through to generate/parse respectively, see
+    # generate and parse for their documentation.
+    def [](object, opts = {})
+      if object.respond_to? :to_str
+        PSON.parse(object.to_str, opts => {})
+      else
+        PSON.generate(object, opts => {})
+      end
+    end
+
+    # Returns the PSON parser class, that is used by PSON. This might be either
+    # PSON::Ext::Parser or PSON::Pure::Parser.
+    attr_reader :parser
+
+    # Set the PSON parser class _parser_ to be used by PSON.
+    def parser=(parser) # :nodoc:
+      @parser = parser
+      remove_const :Parser if const_defined? :Parser
+      const_set :Parser, parser
+    end
+
+    def registered_document_types
+        @registered_document_types ||= {}
+    end
+
+    # Register a class-constant for deserializaion.
+    def register_document_type(name,klass)
+        registered_document_types[name.to_s] = klass        
+    end
+
+    # Return the constant located at _path_. 
+    # Anything may be registered as a path by calling register_path, above.
+    # Otherwise, the format of _path_ has to be either ::A::B::C or A::B::C. 
+    # In either of these cases A has to be defined in Object (e.g. the path
+    # must be an absolute namespace path.  If the constant doesn't exist at
+    # the given path, an ArgumentError is raised.
+    def deep_const_get(path) # :nodoc:
+      path = path.to_s
+      registered_document_types[path] || path.split(/::/).inject(Object) do |p, c|
+        case
+        when c.empty?             then p
+        when p.const_defined?(c)  then p.const_get(c)
+        else                      raise ArgumentError, "can't find const #{path}"
+        end
+      end
+    end
+
+    # Set the module _generator_ to be used by PSON.
+    def generator=(generator) # :nodoc:
+      @generator = generator
+      generator_methods = generator::GeneratorMethods
+      for const in generator_methods.constants
+        klass = deep_const_get(const)
+        modul = generator_methods.const_get(const)
+        klass.class_eval do
+          instance_methods(false).each do |m|
+            m.to_s == 'to_pson' and remove_method m
+          end
+          include modul
+        end
+      end
+      self.state = generator::State
+      const_set :State, self.state
+    end
+
+    # Returns the PSON generator modul, that is used by PSON. This might be
+    # either PSON::Ext::Generator or PSON::Pure::Generator.
+    attr_reader :generator
+
+    # Returns the PSON generator state class, that is used by PSON. This might
+    # be either PSON::Ext::Generator::State or PSON::Pure::Generator::State.
+    attr_accessor :state
+
+    # This is create identifier, that is used to decide, if the _pson_create_
+    # hook of a class should be called. It defaults to 'document_type'.
+    attr_accessor :create_id
+  end
+  self.create_id = 'document_type'
+
+  NaN           = (-1.0) ** 0.5
+
+  Infinity      = 1.0/0
+
+  MinusInfinity = -Infinity
+
+  # The base exception for PSON errors.
+  class PSONError < StandardError; end
+
+  # This exception is raised, if a parser error occurs.
+  class ParserError < PSONError; end
+
+  # This exception is raised, if the nesting of parsed datastructures is too
+  # deep.
+  class NestingError < ParserError; end
+
+  # This exception is raised, if a generator or unparser error occurs.
+  class GeneratorError < PSONError; end
+  # For backwards compatibility
+  UnparserError = GeneratorError
+
+  # If a circular data structure is encountered while unparsing
+  # this exception is raised.
+  class CircularDatastructure < GeneratorError; end
+
+  # This exception is raised, if the required unicode support is missing on the
+  # system. Usually this means, that the iconv library is not installed.
+  class MissingUnicodeSupport < PSONError; end
+
+  module_function
+
+  # Parse the PSON string _source_ into a Ruby data structure and return it.
+  #
+  # _opts_ can have the following
+  # keys:
+  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+  #   structures. Disable depth checking with :max_nesting => false, it defaults
+  #   to 19.
+  # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+  #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+  #   to false.
+  # * *create_additions*: If set to false, the Parser doesn't create
+  #   additions even if a matchin class and create_id was found. This option
+  #   defaults to true.
+  def parse(source, opts = {})
+    PSON.parser.new(source, opts).parse
+  end
+
+  # Parse the PSON string _source_ into a Ruby data structure and return it.
+  # The bang version of the parse method, defaults to the more dangerous values
+  # for the _opts_ hash, so be sure only to parse trusted _source_ strings.
+  #
+  # _opts_ can have the following keys:
+  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+  #   structures. Enable depth checking with :max_nesting => anInteger. The parse!
+  #   methods defaults to not doing max depth checking: This can be dangerous,
+  #   if someone wants to fill up your stack.
+  # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
+  #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+  #   to true.
+  # * *create_additions*: If set to false, the Parser doesn't create
+  #   additions even if a matchin class and create_id was found. This option
+  #   defaults to true.
+  def parse!(source, opts = {})
+    opts = {
+      :max_nesting => false,
+      :allow_nan => true
+    }.update(opts)
+    PSON.parser.new(source, opts).parse
+  end
+
+  # Unparse the Ruby data structure _obj_ into a single line PSON string and
+  # return it. _state_ is
+  # * a PSON::State object,
+  # * or a Hash like object (responding to to_hash),
+  # * an object convertible into a hash by a to_h method,
+  # that is used as or to configure a State object.
+  #
+  # It defaults to a state object, that creates the shortest possible PSON text
+  # in one line, checks for circular data structures and doesn't allow NaN,
+  # Infinity, and -Infinity.
+  #
+  # A _state_ hash can have the following keys:
+  # * *indent*: a string used to indent levels (default: ''),
+  # * *space*: a string that is put after, a : or , delimiter (default: ''),
+  # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+  # * *object_nl*: a string that is put at the end of a PSON object (default: ''), 
+  # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
+  # * *check_circular*: true if checking for circular data structures
+  #   should be done (the default), false otherwise.
+  # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+  #   generated, otherwise an exception is thrown, if these values are
+  #   encountered. This options defaults to false.
+  # * *max_nesting*: The maximum depth of nesting allowed in the data
+  #   structures from which PSON is to be generated. Disable depth checking
+  #   with :max_nesting => false, it defaults to 19.
+  #
+  # See also the fast_generate for the fastest creation method with the least
+  # amount of sanity checks, and the pretty_generate method for some
+  # defaults for a pretty output.
+  def generate(obj, state = nil)
+    if state
+      state = State.from_state(state)
+    else
+      state = State.new
+    end
+    obj.to_pson(state)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and
+  # later delete them.
+  alias unparse generate
+  module_function :unparse
+  # :startdoc:
+
+  # Unparse the Ruby data structure _obj_ into a single line PSON string and
+  # return it. This method disables the checks for circles in Ruby objects, and
+  # also generates NaN, Infinity, and, -Infinity float values.
+  #
+  # *WARNING*: Be careful not to pass any Ruby data structures with circles as
+  # _obj_ argument, because this will cause PSON to go into an infinite loop.
+  def fast_generate(obj)
+    obj.to_pson(nil)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+  alias fast_unparse fast_generate
+  module_function :fast_unparse
+  # :startdoc:
+
+  # Unparse the Ruby data structure _obj_ into a PSON string and return it. The
+  # returned string is a prettier form of the string returned by #unparse.
+  #
+  # The _opts_ argument can be used to configure the generator, see the
+  # generate method for a more detailed explanation.
+  def pretty_generate(obj, opts = nil)
+    state = PSON.state.new(
+      :indent     => '  ',
+      :space      => ' ',
+      :object_nl  => "\n",
+      :array_nl   => "\n",
+      :check_circular => true
+    )
+    if opts
+      if opts.respond_to? :to_hash
+        opts = opts.to_hash
+      elsif opts.respond_to? :to_h
+        opts = opts.to_h
+      else
+        raise TypeError, "can't convert #{opts.class} into Hash"
+      end
+      state.configure(opts)
+    end
+    obj.to_pson(state)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+  alias pretty_unparse pretty_generate
+  module_function :pretty_unparse
+  # :startdoc:
+
+  # Load a ruby data structure from a PSON _source_ and return it. A source can
+  # either be a string-like object, an IO like object, or an object responding
+  # to the read method. If _proc_ was given, it will be called with any nested
+  # Ruby object as an argument recursively in depth first order.
+  #
+  # This method is part of the implementation of the load/dump interface of
+  # Marshal and YAML.
+  def load(source, proc = nil)
+    if source.respond_to? :to_str
+      source = source.to_str
+    elsif source.respond_to? :to_io
+      source = source.to_io.read
+    else
+      source = source.read
+    end
+    result = parse(source, :max_nesting => false, :allow_nan => true)
+    recurse_proc(result, &proc) if proc
+    result
+  end
+
+  def recurse_proc(result, &proc)
+    case result
+    when Array
+      result.each { |x| recurse_proc x, &proc }
+      proc.call result
+    when Hash
+      result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
+      proc.call result
+    else
+      proc.call result
+    end
+  end
+  private :recurse_proc
+  module_function :recurse_proc
+
+  alias restore load
+  module_function :restore
+
+  # Dumps _obj_ as a PSON string, i.e. calls generate on the object and returns
+  # the result.
+  #
+  # If anIO (an IO like object or an object that responds to the write method)
+  # was given, the resulting PSON is written to it.
+  #
+  # If the number of nested arrays or objects exceeds _limit_ an ArgumentError
+  # exception is raised. This argument is similar (but not exactly the
+  # same!) to the _limit_ argument in Marshal.dump.
+  #
+  # This method is part of the implementation of the load/dump interface of
+  # Marshal and YAML.
+  def dump(obj, anIO = nil, limit = nil)
+    if anIO and limit.nil?
+      anIO = anIO.to_io if anIO.respond_to?(:to_io)
+      unless anIO.respond_to?(:write)
+        limit = anIO
+        anIO = nil
+      end
+    end
+    limit ||= 0
+    result = generate(obj, :allow_nan => true, :max_nesting => limit)
+    if anIO
+      anIO.write result
+      anIO
+    else
+      result
+    end
+  rescue PSON::NestingError
+    raise ArgumentError, "exceed depth limit"
+  end
+end
+
+module ::Kernel
+  private
+
+  # Outputs _objs_ to STDOUT as PSON strings in the shortest form, that is in
+  # one line.
+  def j(*objs)
+    objs.each do |obj|
+      puts PSON::generate(obj, :allow_nan => true, :max_nesting => false)
+    end
+    nil
+  end
+
+  # Ouputs _objs_ to STDOUT as PSON strings in a pretty format, with
+  # indentation and over many lines.
+  def jj(*objs)
+    objs.each do |obj|
+      puts PSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
+    end
+    nil
+  end
+
+  # If _object_ is string-like parse the string and return the parsed result as
+  # a Ruby data structure. Otherwise generate a PSON text from the Ruby data
+  # structure object and return it.
+  #
+  # The _opts_ argument is passed through to generate/parse respectively, see
+  # generate and parse for their documentation.
+  def PSON(object, opts = {})
+    if object.respond_to? :to_str
+      PSON.parse(object.to_str, opts)
+    else
+      PSON.generate(object, opts)
+    end
+  end
+end
+
+class ::Class
+  # Returns true, if this class can be used to create an instance
+  # from a serialised PSON string. The class has to implement a class
+  # method _pson_create_ that expects a hash as first parameter, which includes
+  # the required data.
+  def pson_creatable?
+    respond_to?(:pson_create)
+  end
+end
diff --git a/lib/puppet/external/pson/pure.rb b/lib/puppet/external/pson/pure.rb
new file mode 100644
index 0000000..43f39b2
--- /dev/null
+++ b/lib/puppet/external/pson/pure.rb
@@ -0,0 +1,77 @@
+require 'puppet/external/pson/common'
+require 'puppet/external/pson/pure/parser'
+require 'puppet/external/pson/pure/generator'
+
+module PSON
+  begin
+    require 'iconv'
+    # An iconv instance to convert from UTF8 to UTF16 Big Endian.
+    UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be') # :nodoc:
+    # An iconv instance to convert from UTF16 Big Endian to UTF8.
+    UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc:
+    UTF8toUTF16.iconv('no bom')
+  rescue LoadError
+    raise MissingUnicodeSupport,
+      "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions"
+  rescue Errno::EINVAL, Iconv::InvalidEncoding
+    # Iconv doesn't support big endian utf-16. Let's try to hack this manually
+    # into the converters.
+    begin
+      old_verbose, $VERBSOSE = $VERBOSE, nil
+      # An iconv instance to convert from UTF8 to UTF16 Big Endian.
+      UTF16toUTF8 = Iconv.new('utf-8', 'utf-16') # :nodoc:
+      # An iconv instance to convert from UTF16 Big Endian to UTF8.
+      UTF8toUTF16 = Iconv.new('utf-16', 'utf-8') # :nodoc:
+      UTF8toUTF16.iconv('no bom')
+      if UTF8toUTF16.iconv("\xe2\x82\xac") == "\xac\x20"
+        swapper = Class.new do
+          def initialize(iconv) # :nodoc:
+            @iconv = iconv
+          end
+
+          def iconv(string) # :nodoc:
+            result = @iconv.iconv(string)
+            PSON.swap!(result)
+          end
+        end
+        UTF8toUTF16 = swapper.new(UTF8toUTF16) # :nodoc:
+      end
+      if UTF16toUTF8.iconv("\xac\x20") == "\xe2\x82\xac"
+        swapper = Class.new do
+          def initialize(iconv) # :nodoc:
+            @iconv = iconv
+          end
+
+          def iconv(string) # :nodoc:
+            string = PSON.swap!(string.dup)
+            @iconv.iconv(string)
+          end
+        end
+        UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc:
+      end
+    rescue Errno::EINVAL, Iconv::InvalidEncoding
+      raise MissingUnicodeSupport, "iconv doesn't seem to support UTF-8/UTF-16 conversions"
+    ensure
+      $VERBOSE = old_verbose
+    end
+  end
+
+  # Swap consecutive bytes of _string_ in place.
+  def self.swap!(string) # :nodoc:
+    0.upto(string.size / 2) do |i|
+      break unless string[2 * i + 1]
+      string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
+    end
+    string
+  end
+
+  # This module holds all the modules/classes that implement PSON's
+  # functionality in pure ruby.
+  module Pure
+    $DEBUG and warn "Using pure library for PSON."
+    PSON.parser = Parser
+    PSON.generator = Generator
+  end
+
+  PSON_LOADED = true
+end
diff --git a/lib/puppet/external/pson/pure/generator.rb b/lib/puppet/external/pson/pure/generator.rb
new file mode 100644
index 0000000..b2a7dde
--- /dev/null
+++ b/lib/puppet/external/pson/pure/generator.rb
@@ -0,0 +1,429 @@
+module PSON
+  MAP = {
+    "\x0" => '\u0000',
+    "\x1" => '\u0001',
+    "\x2" => '\u0002',
+    "\x3" => '\u0003',
+    "\x4" => '\u0004',
+    "\x5" => '\u0005',
+    "\x6" => '\u0006',
+    "\x7" => '\u0007',
+    "\b"  =>  '\b',
+    "\t"  =>  '\t',
+    "\n"  =>  '\n',
+    "\xb" => '\u000b',
+    "\f"  =>  '\f',
+    "\r"  =>  '\r',
+    "\xe" => '\u000e',
+    "\xf" => '\u000f',
+    "\x10" => '\u0010',
+    "\x11" => '\u0011',
+    "\x12" => '\u0012',
+    "\x13" => '\u0013',
+    "\x14" => '\u0014',
+    "\x15" => '\u0015',
+    "\x16" => '\u0016',
+    "\x17" => '\u0017',
+    "\x18" => '\u0018',
+    "\x19" => '\u0019',
+    "\x1a" => '\u001a',
+    "\x1b" => '\u001b',
+    "\x1c" => '\u001c',
+    "\x1d" => '\u001d',
+    "\x1e" => '\u001e',
+    "\x1f" => '\u001f',
+    '"'   =>  '\"',
+    '\\'  =>  '\\\\',
+  } # :nodoc:
+
+  # Convert a UTF8 encoded Ruby string _string_ to a PSON string, encoded with
+  # UTF16 big endian characters as \u????, and return it.
+  if String.method_defined?(:force_encoding)
+    def utf8_to_pson(string) # :nodoc:
+      string = string.dup
+      string << '' # XXX workaround: avoid buffer sharing
+      string.force_encoding(Encoding::ASCII_8BIT)
+      string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] }
+      string.gsub!(/(
+                      (?:
+                        [\xc2-\xdf][\x80-\xbf]    |
+                        [\xe0-\xef][\x80-\xbf]{2} |
+                        [\xf0-\xf4][\x80-\xbf]{3}
+                      )+ |
+                      [\x80-\xc1\xf5-\xff]       # invalid
+                    )/nx) { |c|
+                      c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
+                      s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
+                      s.gsub!(/.{4}/n, '\\\\u\&')
+                    }
+      string.force_encoding(Encoding::UTF_8)
+      string
+    rescue Iconv::Failure => e
+      raise GeneratorError, "Caught #{e.class}: #{e}"
+    end
+  else
+    def utf8_to_pson(string) # :nodoc:
+      string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] }
+      string.gsub!(/(
+                      (?:
+                        [\xc2-\xdf][\x80-\xbf]    |
+                        [\xe0-\xef][\x80-\xbf]{2} |
+                        [\xf0-\xf4][\x80-\xbf]{3}
+                      )+ |
+                      [\x80-\xc1\xf5-\xff]       # invalid
+                    )/nx) { |c|
+        c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
+        s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
+        s.gsub!(/.{4}/n, '\\\\u\&')
+      }
+      string
+    rescue Iconv::Failure => e
+      raise GeneratorError, "Caught #{e.class}: #{e}"
+    end
+  end
+  module_function :utf8_to_pson
+
+  module Pure
+    module Generator
+      # This class is used to create State instances, that are use to hold data
+      # while generating a PSON text from a a Ruby data structure.
+      class State
+        # Creates a State object from _opts_, which ought to be Hash to create
+        # a new State instance configured by _opts_, something else to create
+        # an unconfigured instance. If _opts_ is a State object, it is just
+        # returned.
+        def self.from_state(opts)
+          case opts
+          when self
+            opts
+          when Hash
+            new(opts)
+          else
+            new
+          end
+        end
+
+        # Instantiates a new State object, configured by _opts_.
+        #
+        # _opts_ can have the following keys:
+        #
+        # * *indent*: a string used to indent levels (default: ''),
+        # * *space*: a string that is put after, a : or , delimiter (default: ''),
+        # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+        # * *object_nl*: a string that is put at the end of a PSON object (default: ''), 
+        # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
+        # * *check_circular*: true if checking for circular data structures
+        #   should be done (the default), false otherwise.
+        # * *check_circular*: true if checking for circular data structures
+        #   should be done, false (the default) otherwise.
+        # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+        #   generated, otherwise an exception is thrown, if these values are
+        #   encountered. This options defaults to false.
+        def initialize(opts = {})
+          @seen = {}
+          @indent         = ''
+          @space          = ''
+          @space_before   = ''
+          @object_nl      = ''
+          @array_nl       = ''
+          @check_circular = true
+          @allow_nan      = false
+          configure opts
+        end
+
+        # This string is used to indent levels in the PSON text.
+        attr_accessor :indent
+
+        # This string is used to insert a space between the tokens in a PSON
+        # string.
+        attr_accessor :space
+
+        # This string is used to insert a space before the ':' in PSON objects.
+        attr_accessor :space_before
+
+        # This string is put at the end of a line that holds a PSON object (or
+        # Hash).
+        attr_accessor :object_nl
+
+        # This string is put at the end of a line that holds a PSON array.
+        attr_accessor :array_nl
+
+        # This integer returns the maximum level of data structure nesting in
+        # the generated PSON, max_nesting = 0 if no maximum is checked.
+        attr_accessor :max_nesting
+
+        def check_max_nesting(depth) # :nodoc:
+          return if @max_nesting.zero?
+          current_nesting = depth + 1
+          current_nesting > @max_nesting and
+            raise NestingError, "nesting of #{current_nesting} is too deep"
+        end
+
+        # Returns true, if circular data structures should be checked,
+        # otherwise returns false.
+        def check_circular?
+          @check_circular
+        end
+
+        # Returns true if NaN, Infinity, and -Infinity should be considered as
+        # valid PSON and output.
+        def allow_nan?
+          @allow_nan
+        end
+
+        # Returns _true_, if _object_ was already seen during this generating
+        # run. 
+        def seen?(object)
+          @seen.key?(object.__id__)
+        end
+
+        # Remember _object_, to find out if it was already encountered (if a
+        # cyclic data structure is if a cyclic data structure is rendered). 
+        def remember(object)
+          @seen[object.__id__] = true
+        end
+
+        # Forget _object_ for this generating run.
+        def forget(object)
+          @seen.delete object.__id__
+        end
+
+        # Configure this State instance with the Hash _opts_, and return
+        # itself.
+        def configure(opts)
+          @indent         = opts[:indent] if opts.key?(:indent)
+          @space          = opts[:space] if opts.key?(:space)
+          @space_before   = opts[:space_before] if opts.key?(:space_before)
+          @object_nl      = opts[:object_nl] if opts.key?(:object_nl)
+          @array_nl       = opts[:array_nl] if opts.key?(:array_nl)
+          @check_circular = !!opts[:check_circular] if opts.key?(:check_circular)
+          @allow_nan      = !!opts[:allow_nan] if opts.key?(:allow_nan)
+          if !opts.key?(:max_nesting) # defaults to 19
+            @max_nesting = 19
+          elsif opts[:max_nesting]
+            @max_nesting = opts[:max_nesting]
+          else
+            @max_nesting = 0
+          end
+          self
+        end
+
+        # Returns the configuration instance variables as a hash, that can be
+        # passed to the configure method.
+        def to_h
+          result = {}
+          for iv in %w[indent space space_before object_nl array_nl check_circular allow_nan max_nesting]
+            result[iv.intern] = instance_variable_get("@#{iv}")
+          end
+          result
+        end
+      end
+
+      module GeneratorMethods
+        module Object
+          # Converts this object to a string (calling #to_s), converts
+          # it to a PSON string, and returns the result. This is a fallback, if no
+          # special method #to_pson was defined for some object.
+          def to_pson(*) to_s.to_pson end
+        end
+
+        module Hash
+          # Returns a PSON string containing a PSON object, that is unparsed from
+          # this Hash instance.
+          # _state_ is a PSON::State object, that can also be used to configure the
+          # produced PSON string output further.
+          # _depth_ is used to find out nesting depth, to indent accordingly.
+          def to_pson(state = nil, depth = 0, *)
+            if state
+              state = PSON.state.from_state(state)
+              state.check_max_nesting(depth)
+              pson_check_circular(state) { pson_transform(state, depth) }
+            else
+              pson_transform(state, depth)
+            end
+          end
+
+          private
+
+          def pson_check_circular(state)
+            if state and state.check_circular?
+              state.seen?(self) and raise PSON::CircularDatastructure,
+                  "circular data structures not supported!"
+              state.remember self
+            end
+            yield
+          ensure
+            state and state.forget self
+          end
+
+          def pson_shift(state, depth)
+            state and not state.object_nl.empty? or return ''
+            state.indent * depth
+          end
+
+          def pson_transform(state, depth)
+            delim = ','
+            if state
+              delim << state.object_nl
+              result = '{'
+              result << state.object_nl
+              result << map { |key,value|
+                s = pson_shift(state, depth + 1)
+                s << key.to_s.to_pson(state, depth + 1)
+                s << state.space_before
+                s << ':'
+                s << state.space
+                s << value.to_pson(state, depth + 1)
+              }.join(delim)
+              result << state.object_nl
+              result << pson_shift(state, depth)
+              result << '}'
+            else
+              result = '{'
+              result << map { |key,value|
+                key.to_s.to_pson << ':' << value.to_pson
+              }.join(delim)
+              result << '}'
+            end
+            result
+          end
+        end
+
+        module Array
+          # Returns a PSON string containing a PSON array, that is unparsed from
+          # this Array instance.
+          # _state_ is a PSON::State object, that can also be used to configure the
+          # produced PSON string output further.
+          # _depth_ is used to find out nesting depth, to indent accordingly.
+          def to_pson(state = nil, depth = 0, *)
+            if state
+              state = PSON.state.from_state(state)
+              state.check_max_nesting(depth)
+              pson_check_circular(state) { pson_transform(state, depth) }
+            else
+              pson_transform(state, depth)
+            end
+          end
+
+          private
+
+          def pson_check_circular(state)
+            if state and state.check_circular?
+              state.seen?(self) and raise PSON::CircularDatastructure,
+                "circular data structures not supported!"
+              state.remember self
+            end
+            yield
+          ensure
+            state and state.forget self
+          end
+
+          def pson_shift(state, depth)
+            state and not state.array_nl.empty? or return ''
+            state.indent * depth
+          end
+
+          def pson_transform(state, depth)
+            delim = ','
+            if state
+              delim << state.array_nl
+              result = '['
+              result << state.array_nl
+              result << map { |value|
+                pson_shift(state, depth + 1) << value.to_pson(state, depth + 1)
+              }.join(delim)
+              result << state.array_nl
+              result << pson_shift(state, depth) 
+              result << ']'
+            else
+              '[' << map { |value| value.to_pson }.join(delim) << ']'
+            end
+          end
+        end
+
+        module Integer
+          # Returns a PSON string representation for this Integer number.
+          def to_pson(*) to_s end
+        end
+
+        module Float
+          # Returns a PSON string representation for this Float number.
+          def to_pson(state = nil, *)
+            case
+            when infinite?
+              if !state || state.allow_nan?
+                to_s
+              else
+                raise GeneratorError, "#{self} not allowed in PSON"
+              end
+            when nan?
+              if !state || state.allow_nan?
+                to_s
+              else
+                raise GeneratorError, "#{self} not allowed in PSON"
+              end
+            else
+              to_s
+            end
+          end
+        end
+
+        module String
+          # This string should be encoded with UTF-8 A call to this method
+          # returns a PSON string encoded with UTF16 big endian characters as
+          # \u????.
+          def to_pson(*)
+            '"' << PSON.utf8_to_pson(self) << '"'
+          end
+
+          # Module that holds the extinding methods if, the String module is
+          # included.
+          module Extend
+            # Raw Strings are PSON Objects (the raw bytes are stored in an array for the
+            # key "raw"). The Ruby String can be created by this module method.
+            def pson_create(o)
+              o['raw'].pack('C*')
+            end
+          end
+
+          # Extends _modul_ with the String::Extend module.
+          def self.included(modul)
+            modul.extend Extend
+          end
+
+          # This method creates a raw object hash, that can be nested into
+          # other data structures and will be unparsed as a raw string. This
+          # method should be used, if you want to convert raw strings to PSON
+          # instead of UTF-8 strings, e. g. binary data.
+          def to_pson_raw_object
+            {
+              PSON.create_id  => self.class.name,
+              'raw'           => self.unpack('C*'),
+            }
+          end
+
+          # This method creates a PSON text from the result of
+          # a call to to_pson_raw_object of this String.
+          def to_pson_raw(*args)
+            to_pson_raw_object.to_pson(*args)
+          end
+        end
+
+        module TrueClass
+          # Returns a PSON string for true: 'true'.
+          def to_pson(*) 'true' end
+        end
+
+        module FalseClass
+          # Returns a PSON string for false: 'false'.
+          def to_pson(*) 'false' end
+        end
+
+        module NilClass
+          # Returns a PSON string for nil: 'null'.
+          def to_pson(*) 'null' end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/puppet/external/pson/pure/parser.rb b/lib/puppet/external/pson/pure/parser.rb
new file mode 100644
index 0000000..16643ac
--- /dev/null
+++ b/lib/puppet/external/pson/pure/parser.rb
@@ -0,0 +1,269 @@
+require 'strscan'
+
+module PSON
+  module Pure
+    # This class implements the PSON parser that is used to parse a PSON string
+    # into a Ruby data structure.
+    class Parser < StringScanner
+      STRING                = /" ((?:[^\x0-\x1f"\\] |
+                                   # escaped special characters:
+                                  \\["\\\/bfnrt] |
+                                  \\u[0-9a-fA-F]{4} |
+                                   # match all but escaped special characters:
+                                  \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*)
+                              "/nx
+      INTEGER               = /(-?0|-?[1-9]\d*)/
+      FLOAT                 = /(-?
+                                (?:0|[1-9]\d*)
+                                (?:
+                                  \.\d+(?i:e[+-]?\d+) |
+                                  \.\d+ |
+                                  (?i:e[+-]?\d+)
+                                )
+                                )/x
+      NAN                   = /NaN/
+      INFINITY              = /Infinity/
+      MINUS_INFINITY        = /-Infinity/
+      OBJECT_OPEN           = /\{/
+      OBJECT_CLOSE          = /\}/
+      ARRAY_OPEN            = /\[/
+      ARRAY_CLOSE           = /\]/
+      PAIR_DELIMITER        = /:/
+      COLLECTION_DELIMITER  = /,/
+      TRUE                  = /true/
+      FALSE                 = /false/
+      NULL                  = /null/
+      IGNORE                = %r(
+        (?:
+         //[^\n\r]*[\n\r]| # line comments
+         /\*               # c-style comments
+         (?:
+          [^*/]|        # normal chars
+          /[^*]|        # slashes that do not start a nested comment
+          \*[^/]|       # asterisks that do not end this comment
+          /(?=\*/)      # single slash before this comment's end 
+         )*
+           \*/               # the End of this comment
+           |[ \t\r\n]+       # whitespaces: space, horicontal tab, lf, cr
+        )+
+      )mx
+
+      UNPARSED = Object.new
+
+      # Creates a new PSON::Pure::Parser instance for the string _source_.
+      #
+      # It will be configured by the _opts_ hash. _opts_ can have the following
+      # keys:
+      # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+      #   structures. Disable depth checking with :max_nesting => false|nil|0,
+      #   it defaults to 19.
+      # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+      #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+      #   to false.
+      # * *create_additions*: If set to false, the Parser doesn't create
+      #   additions even if a matchin class and create_id was found. This option
+      #   defaults to true.
+      # * *object_class*: Defaults to Hash
+      # * *array_class*: Defaults to Array
+      def initialize(source, opts = {})
+        super
+        if !opts.key?(:max_nesting) # defaults to 19
+          @max_nesting = 19
+        elsif opts[:max_nesting]
+          @max_nesting = opts[:max_nesting]
+        else
+          @max_nesting = 0
+        end
+        @allow_nan = !!opts[:allow_nan]
+        ca = true
+        ca = opts[:create_additions] if opts.key?(:create_additions)
+        @create_id = ca ? PSON.create_id : nil
+        @object_class = opts[:object_class] || Hash
+        @array_class = opts[:array_class] || Array
+      end
+
+      alias source string
+
+      # Parses the current PSON string _source_ and returns the complete data
+      # structure as a result.
+      def parse
+        reset
+        obj = nil
+        until eos?
+          case
+          when scan(OBJECT_OPEN)
+            obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
+            @current_nesting = 1
+            obj = parse_object
+          when scan(ARRAY_OPEN)
+            obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
+            @current_nesting = 1
+            obj = parse_array
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "source '#{peek(20)}' not in PSON!"
+          end
+        end
+        obj or raise ParserError, "source did not contain any PSON!"
+        obj
+      end
+
+      private
+
+      # Unescape characters in strings.
+      UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
+      UNESCAPE_MAP.update({
+        ?"  => '"',
+        ?\\ => '\\',
+        ?/  => '/',
+        ?b  => "\b",
+        ?f  => "\f",
+        ?n  => "\n",
+        ?r  => "\r",
+        ?t  => "\t",
+        ?u  => nil, 
+      })
+
+      def parse_string
+        if scan(STRING)
+          return '' if self[1].empty?
+          string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
+            if u = UNESCAPE_MAP[$&[1]]
+              u
+            else # \uXXXX
+              bytes = ''
+              i = 0
+              while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
+                bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
+                i += 1
+              end
+              PSON::UTF16toUTF8.iconv(bytes)
+            end
+          end
+          if string.respond_to?(:force_encoding)
+            string.force_encoding(Encoding::UTF_8)
+          end
+          string
+        else
+          UNPARSED
+        end
+      rescue Iconv::Failure => e
+        raise GeneratorError, "Caught #{e.class}: #{e}"
+      end
+
+      def parse_value
+        case
+        when scan(FLOAT)
+          Float(self[1])
+        when scan(INTEGER)
+          Integer(self[1])
+        when scan(TRUE)
+          true
+        when scan(FALSE)
+          false
+        when scan(NULL)
+          nil
+        when (string = parse_string) != UNPARSED
+          string
+        when scan(ARRAY_OPEN)
+          @current_nesting += 1
+          ary = parse_array
+          @current_nesting -= 1
+          ary
+        when scan(OBJECT_OPEN)
+          @current_nesting += 1
+          obj = parse_object
+          @current_nesting -= 1
+          obj
+        when @allow_nan && scan(NAN)
+          NaN
+        when @allow_nan && scan(INFINITY)
+          Infinity
+        when @allow_nan && scan(MINUS_INFINITY)
+          MinusInfinity
+        else
+          UNPARSED
+        end
+      end
+
+      def parse_array
+        raise NestingError, "nesting of #@current_nesting is too deep" if
+          @max_nesting.nonzero? && @current_nesting > @max_nesting
+        result = @array_class.new
+        delim = false
+        until eos?
+          case
+          when (value = parse_value) != UNPARSED
+            delim = false
+            result << value
+            skip(IGNORE)
+            if scan(COLLECTION_DELIMITER)
+              delim = true
+            elsif match?(ARRAY_CLOSE)
+              ;
+            else
+              raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
+            end
+          when scan(ARRAY_CLOSE)
+            if delim
+              raise ParserError, "expected next element in array at '#{peek(20)}'!"
+            end
+            break
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "unexpected token in array at '#{peek(20)}'!"
+          end
+        end
+        result
+      end
+
+      def parse_object
+        raise NestingError, "nesting of #@current_nesting is too deep" if
+          @max_nesting.nonzero? && @current_nesting > @max_nesting
+        result = @object_class.new
+        delim = false
+        until eos?
+          case
+          when (string = parse_string) != UNPARSED
+            skip(IGNORE)
+            unless scan(PAIR_DELIMITER)
+              raise ParserError, "expected ':' in object at '#{peek(20)}'!"
+            end
+            skip(IGNORE)
+            unless (value = parse_value).equal? UNPARSED
+              result[string] = value
+              delim = false
+              skip(IGNORE)
+              if scan(COLLECTION_DELIMITER)
+                delim = true
+              elsif match?(OBJECT_CLOSE)
+                ;
+              else
+                raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
+              end
+            else
+              raise ParserError, "expected value in object at '#{peek(20)}'!"
+            end
+          when scan(OBJECT_CLOSE)
+            if delim
+              raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
+            end
+            if @create_id and klassname = result[@create_id]
+              klass = PSON.deep_const_get klassname
+              break unless klass and klass.pson_creatable?
+              result = klass.pson_create(result)
+            end
+            break
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "unexpected token in object at '#{peek(20)}'!"
+          end
+        end
+        result
+      end
+    end
+  end
+end
diff --git a/lib/puppet/external/pson/version.rb b/lib/puppet/external/pson/version.rb
new file mode 100644
index 0000000..a5a8e47
--- /dev/null
+++ b/lib/puppet/external/pson/version.rb
@@ -0,0 +1,8 @@
+module PSON
+  # PSON version
+  VERSION         = '1.1.9'
+  VERSION_ARRAY   = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
+  VERSION_MAJOR   = VERSION_ARRAY[0] # :nodoc:
+  VERSION_MINOR   = VERSION_ARRAY[1] # :nodoc:
+  VERSION_BUILD   = VERSION_ARRAY[2] # :nodoc:
+end
diff --git a/lib/puppet/feature/json.rb b/lib/puppet/feature/json.rb
deleted file mode 100644
index 1f3845c..0000000
--- a/lib/puppet/feature/json.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-# This is here so it autoloads correctly.
-Puppet.features.rails?
diff --git a/lib/puppet/feature/pson.rb b/lib/puppet/feature/pson.rb
new file mode 100644
index 0000000..21576c6
--- /dev/null
+++ b/lib/puppet/feature/pson.rb
@@ -0,0 +1,6 @@
+Puppet.features.add(:pson) do
+    require 'puppet/external/pson/common'
+    require 'puppet/external/pson/version'
+    require 'puppet/external/pson/pure'
+    true
+end
diff --git a/lib/puppet/feature/rails.rb b/lib/puppet/feature/rails.rb
index 87b408c..a290072 100644
--- a/lib/puppet/feature/rails.rb
+++ b/lib/puppet/feature/rails.rb
@@ -35,8 +35,3 @@ Puppet.features.add(:rails) do
         true
     end
 end
-
-# We have JSON available
-# This is stupid - Rails breaks json compatibility if we load json before
-# rails, therefore we load rails and then json.  Dumb, mother-dumb.
-Puppet.features.add(:json, :libs => ["json"])
diff --git a/lib/puppet/indirector/queue.rb b/lib/puppet/indirector/queue.rb
index 3a70496..27ef219 100644
--- a/lib/puppet/indirector/queue.rb
+++ b/lib/puppet/indirector/queue.rb
@@ -24,7 +24,7 @@ class Puppet::Indirector::Queue < Puppet::Indirector::Terminus
 
     def initialize(*args)
         super
-        raise ArgumentError, "Queueing requires json support" unless Puppet.features.json?
+        raise ArgumentError, "Queueing requires pson support" unless Puppet.features.pson?
     end
 
     # Queue has no idiomatic "find"
@@ -37,7 +37,7 @@ class Puppet::Indirector::Queue < Puppet::Indirector::Terminus
         begin
             result = nil
             benchmark :info, "Queued %s for %s" % [indirection.name, request.key] do
-                result = client.send_message(queue, request.instance.render(:json))
+                result = client.send_message(queue, request.instance.render(:pson))
             end
             result
         rescue => detail
@@ -62,7 +62,7 @@ class Puppet::Indirector::Queue < Puppet::Indirector::Terminus
     def self.intern(message)
         result = nil
         benchmark :info, "Loaded queued %s" % [indirection.name] do
-            result = model.convert_from(:json, message)
+            result = model.convert_from(:pson, message)
         end
         result
     end
diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb
index 3a19b0b..df6ef39 100644
--- a/lib/puppet/network/formats.rb
+++ b/lib/puppet/network/formats.rb
@@ -26,9 +26,9 @@ Puppet::Network::FormatHandler.create(:yaml, :mime => "text/yaml") do
         yaml
     end
 
-    # Everything's supported
+    # Everything's supported unless you're on 1.8.1
     def supported?(klass)
-        true
+        RUBY_VERSION != '1.8.1'
     end
 
     # fixup invalid yaml as per:
@@ -89,22 +89,22 @@ Puppet::Network::FormatHandler.create(:raw, :mime => "application/x-raw", :weigh
     end
 end
 
-Puppet::Network::FormatHandler.create(:json, :mime => "text/json", :weight => 10, :required_methods => [:render_method, :intern_method]) do
-    confine :true => Puppet.features.json?
+Puppet::Network::FormatHandler.create(:pson, :mime => "text/pson", :weight => 10, :required_methods => [:render_method, :intern_method]) do
+    confine :true => Puppet.features.pson?
 
     def intern(klass, text)
-        data_to_instance(klass, JSON.parse(text))
+        data_to_instance(klass, PSON.parse(text))
     end
 
     def intern_multiple(klass, text)
-        JSON.parse(text).collect do |data|
+        PSON.parse(text).collect do |data|
             data_to_instance(klass, data)
         end
     end
 
-    # JSON monkey-patches Array, so this works.
+    # PSON monkey-patches Array, so this works.
     def render_multiple(instances)
-        instances.to_json
+        instances.to_pson
     end
 
     # If they pass class information, we want to ignore it.  By default,
@@ -118,6 +118,6 @@ Puppet::Network::FormatHandler.create(:json, :mime => "text/json", :weight => 10
         if data.is_a?(klass)
             return data
         end
-        klass.from_json(data)
+        klass.from_pson(data)
     end
 end
diff --git a/lib/puppet/relationship.rb b/lib/puppet/relationship.rb
index 96a71c3..18eb4ea 100644
--- a/lib/puppet/relationship.rb
+++ b/lib/puppet/relationship.rb
@@ -6,26 +6,26 @@
 # subscriptions are permanent associations determining how different
 # objects react to an event
 
-require 'puppet/util/json'
+require 'puppet/util/pson'
 
 # This is Puppet's class for modeling edges in its configuration graph.
 # It used to be a subclass of GRATR::Edge, but that class has weird hash
 # overrides that dramatically slow down the graphing.
 class Puppet::Relationship
-    extend Puppet::Util::Json
+    extend Puppet::Util::Pson
     attr_accessor :source, :target, :callback
 
     attr_reader :event
 
-    def self.from_json(json)
-        source = json["source"]
-        target = json["target"]
+    def self.from_pson(pson)
+        source = pson["source"]
+        target = pson["target"]
 
         args = {}
-        if event = json["event"]
+        if event = pson["event"]
             args[:event] = event
         end
-        if callback = json["callback"]
+        if callback = pson["callback"]
             args[:callback] = callback
         end
 
@@ -73,7 +73,7 @@ class Puppet::Relationship
         "%s => %s" % [source, target]
     end
 
-    def to_json(*args)
+    def to_pson_data_hash
         data = {
             'source' => source.to_s,
             'target' => target.to_s
@@ -83,11 +83,11 @@ class Puppet::Relationship
             next unless value = send(attr)
             data[attr] = value
         end
+        data
+    end
 
-        {
-            'json_class' => self.class.to_s,
-            'data' => data
-        }.to_json(*args)
+    def to_pson(*args)
+        to_pson_data_hash.to_pson(*args)
     end
 
     def to_s
diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb
index 3e27e0e..91dd547 100644
--- a/lib/puppet/resource.rb
+++ b/lib/puppet/resource.rb
@@ -1,35 +1,35 @@
 require 'puppet'
 require 'puppet/util/tagging'
 require 'puppet/resource/reference'
-require 'puppet/util/json'
+require 'puppet/util/pson'
 
 # The simplest resource class.  Eventually it will function as the
 # base class for all resource-like behaviour.
 class Puppet::Resource
     include Puppet::Util::Tagging
-    extend Puppet::Util::Json
+    extend Puppet::Util::Pson
     include Enumerable
     attr_accessor :file, :line, :catalog, :exported, :virtual
     attr_writer :type, :title
 
     ATTRIBUTES = [:file, :line, :exported]
 
-    def self.from_json(json)
-        raise ArgumentError, "No resource type provided in json data" unless type = json['type']
-        raise ArgumentError, "No resource title provided in json data" unless title = json['title']
+    def self.from_pson(pson)
+        raise ArgumentError, "No resource type provided in pson data" unless type = pson['type']
+        raise ArgumentError, "No resource title provided in pson data" unless title = pson['title']
 
         resource = new(type, title)
 
-        if params = json['parameters']
+        if params = pson['parameters']
             params.each { |param, value| resource[param] = value }
         end
 
-        if tags = json['tags']
+        if tags = pson['tags']
             tags.each { |tag| resource.tag(tag) }
         end
 
         ATTRIBUTES.each do |a|
-            if value = json[a.to_s]
+            if value = pson[a.to_s]
                 resource.send(a.to_s + "=", value)
             end
         end
@@ -39,9 +39,7 @@ class Puppet::Resource
         resource
     end
 
-    def to_json(*args)
-        raise "Cannot convert to JSON unless the 'json' library is installed" unless Puppet.features.json?
-
+    def to_pson_data_hash
         data = ([:type, :title, :tags] + ATTRIBUTES).inject({}) do |hash, param|
             next hash unless value = self.send(param)
             hash[param.to_s] = value
@@ -59,15 +57,13 @@ class Puppet::Resource
             hash
         end
 
-        unless params.empty?
-            data["parameters"] = params
-        end
+        data["parameters"] = params unless params.empty?
+
+        data
+    end
 
-        res = {
-            'json_class' => self.class.name,
-            'data' => data
-        }
-        res.to_json(*args)
+    def to_pson(*args)
+        to_pson_data_hash.to_pson(*args)
     end
 
     # Proxy these methods to the parameters hash.  It's likely they'll
diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb
index 561be82..8ab788e 100644
--- a/lib/puppet/resource/catalog.rb
+++ b/lib/puppet/resource/catalog.rb
@@ -4,7 +4,7 @@ require 'puppet/simple_graph'
 require 'puppet/transaction'
 
 require 'puppet/util/cacher'
-require 'puppet/util/json'
+require 'puppet/util/pson'
 
 require 'puppet/util/tagging'
 
@@ -19,7 +19,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph
     indirects :catalog, :terminus_class => :compiler
 
     include Puppet::Util::Tagging
-    extend Puppet::Util::Json
+    extend Puppet::Util::Pson
     include Puppet::Util::Cacher::Expirer
 
     # The host name this is a catalog for.
@@ -393,7 +393,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph
         @resource_table.keys
     end
 
-    def self.from_json(data)
+    def self.from_pson(data)
         result = new(data['name'])
 
         if tags = data['tags'] 
@@ -405,60 +405,63 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph
         end
 
         if resources = data['resources']
-            resources = JSON.parse(resources) if resources.is_a?(String)
+            resources = PSON.parse(resources) if resources.is_a?(String)
             resources.each do |res|
-                resource_from_json(result, res)
+                resource_from_pson(result, res)
             end
         end
 
         if edges = data['edges']
-            edges = JSON.parse(edges) if edges.is_a?(String)
+            edges = PSON.parse(edges) if edges.is_a?(String)
             edges.each do |edge|
-                edge_from_json(result, edge)
+                edge_from_pson(result, edge)
             end
         end
 
         result
     end
 
-    def self.edge_from_json(result, edge)
-        # If no json_class information was presented, we manually find
+    def self.edge_from_pson(result, edge)
+        # If no type information was presented, we manually find
         # the class.
-        edge = Puppet::Relationship.from_json(edge) if edge.is_a?(Hash)
+        edge = Puppet::Relationship.from_pson(edge) if edge.is_a?(Hash)
         unless source = result.resource(edge.source)
-            raise ArgumentError, "Could not convert from json: Could not find relationship source '%s'" % source
+            raise ArgumentError, "Could not convert from pson: Could not find relationship source '%s'" % source
         end
         edge.source = source
 
         unless target = result.resource(edge.target)
-            raise ArgumentError, "Could not convert from json: Could not find relationship target '%s'" % target
+            raise ArgumentError, "Could not convert from pson: Could not find relationship target '%s'" % target
         end
         edge.target = target
 
         result.add_edge(edge)
     end
 
-    def self.resource_from_json(result, res)
-        # If no json_class information was presented, we manually find
-        # the class.
-        if res.is_a?(Hash)
-            res = res['data'] if res['json_class']
-            res = Puppet::Resource.from_json(res)
-        end
+    def self.resource_from_pson(result, res)
+        res = Puppet::Resource.from_pson(res) if res.is_a? Hash
         result.add_resource(res)
     end
 
-    def to_json(*args)
+    PSON.register_document_type('Catalog',self)
+    def to_pson_data_hash
         {
-            'json_class' => 'Puppet::Resource::Catalog',
-            'data' => {
-                'tags' => tags,
-                'name' => name,
-                'version' => version,
-                'resources' => vertices.to_json(*args),
-                'edges' => edges.to_json(*args)
-            }
-        }.to_json(*args)
+            'document_type' => 'Catalog',
+            'data'       => {
+                'tags'      => tags,
+                'name'      => name,
+                'version'   => version,
+                'resources' => vertices.collect { |v| v.to_pson_data_hash },
+                'edges'     => edges.   collect { |e| e.to_pson_data_hash }
+                },
+            'metadata' => {
+                'api_version' => 1
+                }
+       }
+    end
+
+    def to_pson(*args)
+       to_pson_data_hash.to_pson(*args)
     end
 
     # Convert our catalog into a RAL catalog.
diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb
index 817b813..e69de29 100644
--- a/lib/puppet/util/monkey_patches.rb
+++ b/lib/puppet/util/monkey_patches.rb
@@ -1,43 +0,0 @@
-#
-# Monkey patches to ruby classes for compatibility
-#
-#
-# In earlier versions of ruby (e.g. 1.8.1) yaml serialized symbols with an explicit
-# type designation.  Later versions understand the explicit form in addition to the
-# implicit "literal" form (e.g. :symbol) which they produce.
-#
-# This causes problems when the puppet master and the client are running on different
-# versions of ruby; the newer version can produce yaml that it's older partner can't 
-# decypher.
-#
-# This patch causes newer versions to produce the older encoding for Symbols.  It is
-# only applied if the existing library does not already produce them.  Thus it will
-# not be applied on older rubys and it will not be applied more than once.  It also 
-# checks that it has been applied to a version which support it and, if not reverts
-# to the original.
-#
-require "yaml"
-
-if :test.to_yaml !~ %r{!ruby/sym}
-    class Symbol
-        if !respond_to? :original_to_yaml
-            alias :original_to_yaml :to_yaml
-            def to_yaml(opts={})
-                YAML::quick_emit(nil,opts) { |out|
-                    if out.respond_to? :scalar
-                        # 1.8.5 through 1.8.8, possibly others
-                        out.scalar("tag:ruby:sym", to_s,:to_yaml_style)
-                    elsif out.respond_to? :<<
-                        # 1.8.2, possibly others
-                        out << "!ruby/sym "
-                        self.id2name.to_yaml( :Emitter => out )
-                    else
-                        # go back to the base version if neither of the above work
-                        alias :to_yaml :original_to_yaml
-                        to_yaml(opts)
-                    end
-                }
-            end    
-        end
-    end
-end
diff --git a/lib/puppet/util/json.rb b/lib/puppet/util/pson.rb
similarity index 53%
rename from lib/puppet/util/json.rb
rename to lib/puppet/util/pson.rb
index d6f1a2f..3356437 100644
--- a/lib/puppet/util/json.rb
+++ b/lib/puppet/util/pson.rb
@@ -1,13 +1,13 @@
-# A simple module to provide consistency between how we use JSON and how 
+# A simple module to provide consistency between how we use PSON and how 
 # ruby expects it to be used.  Basically, we don't want to require
 # that the sender specify a class.
-#  Ruby wants everyone to provide a 'json_class' field, and the JSON support
+#  Ruby wants everyone to provide a 'type' field, and the PSON support
 # requires such a field to track the class down.  Because we use our URL to
 # figure out what class we're working on, we don't need that, and we don't want
 # our consumers and producers to need to know anything about our internals.
-module Puppet::Util::Json
-    def json_create(json)
-        raise ArgumentError, "No data provided in json data" unless json['data']
-        from_json(json['data'])
+module Puppet::Util::Pson
+    def pson_create(pson)
+        raise ArgumentError, "No data provided in pson data" unless pson['data']
+        from_pson(pson['data'])
     end
 end
diff --git a/spec/integration/application/puppet.rb b/spec/integration/application/puppet.rb
index e3f8fb9..1342f3c 100755
--- a/spec/integration/application/puppet.rb
+++ b/spec/integration/application/puppet.rb
@@ -10,16 +10,16 @@ describe "Puppet" do
     include PuppetSpec::Files
 
     describe "when applying provided catalogs" do
-        confine "JSON library is missing; cannot test applying catalogs" => Puppet.features.json?
-        it "should be able to apply catalogs provided in a file in json" do
-            file_to_create = tmpfile("json_catalog")
+        confine "PSON library is missing; cannot test applying catalogs" => Puppet.features.pson?
+        it "should be able to apply catalogs provided in a file in pson" do
+            file_to_create = tmpfile("pson_catalog")
             catalog = Puppet::Resource::Catalog.new
             resource = Puppet::Resource.new(:file, file_to_create, :content => "my stuff")
             catalog.add_resource resource
 
             manifest = tmpfile("manifest")
 
-            File.open(manifest, "w") { |f| f.print catalog.to_json }
+            File.open(manifest, "w") { |f| f.print catalog.to_pson }
 
             puppet = Puppet::Application[:puppet]
             puppet.options[:catalog] = manifest
diff --git a/spec/integration/defaults.rb b/spec/integration/defaults.rb
index c38a1a1..fb00f86 100755
--- a/spec/integration/defaults.rb
+++ b/spec/integration/defaults.rb
@@ -89,8 +89,8 @@ describe "Puppet defaults" do
         end
     end
 
-    it "should default to json for the preferred serialization format" do
-        Puppet.settings.value(:preferred_serialization_format).should == "json"
+    it "should default to pson for the preferred serialization format" do
+        Puppet.settings.value(:preferred_serialization_format).should == "pson"
     end
 
     describe "when enabling storeconfigs" do
diff --git a/spec/integration/indirector/catalog/queue.rb b/spec/integration/indirector/catalog/queue.rb
index bf12181..5a781c1 100755
--- a/spec/integration/indirector/catalog/queue.rb
+++ b/spec/integration/indirector/catalog/queue.rb
@@ -6,7 +6,7 @@ require 'puppet/resource/catalog'
 
 
 describe "Puppet::Resource::Catalog::Queue" do
-    confine "Missing json support; cannot test queue" => Puppet.features.json?
+    confine "Missing pson support; cannot test queue" => Puppet.features.pson?
 
     before do
         Puppet::Resource::Catalog.indirection.terminus(:queue)
@@ -23,13 +23,13 @@ describe "Puppet::Resource::Catalog::Queue" do
 
     after { Puppet.settings.clear }
 
-    it "should render catalogs to json and send them via the queue client when catalogs are saved" do
+    it "should render catalogs to pson and send them via the queue client when catalogs are saved" do
         terminus = Puppet::Resource::Catalog.indirection.terminus(:queue)
 
         client = mock 'client'
         terminus.stubs(:client).returns client
 
-        client.expects(:send_message).with(:catalog, @catalog.to_json)
+        client.expects(:send_message).with(:catalog, @catalog.to_pson)
 
         request = Puppet::Indirector::Request.new(:catalog, :save, "foo", :instance => @catalog)
 
@@ -40,9 +40,9 @@ describe "Puppet::Resource::Catalog::Queue" do
         client = mock 'client'
         Puppet::Resource::Catalog::Queue.stubs(:client).returns client
 
-        json = @catalog.to_json
+        pson = @catalog.to_pson
 
-        client.expects(:subscribe).with(:catalog).yields(json)
+        client.expects(:subscribe).with(:catalog).yields(pson)
 
         Puppet.expects(:err).never
 
diff --git a/spec/integration/network/formats.rb b/spec/integration/network/formats.rb
index 7d0d47e..35e7977 100755
--- a/spec/integration/network/formats.rb
+++ b/spec/integration/network/formats.rb
@@ -4,13 +4,13 @@ require File.dirname(__FILE__) + '/../../spec_helper'
 
 require 'puppet/network/formats'
 
-class JsonIntTest
+class PsonIntTest
     attr_accessor :string
     def ==(other)
         other.class == self.class and string == other.string
     end
 
-    def self.from_json(data)
+    def self.from_pson(data)
         new(data[0])
     end
 
@@ -18,15 +18,15 @@ class JsonIntTest
         @string = string
     end
 
-    def to_json(*args)
+    def to_pson(*args)
         {
-            'json_class' => self.class.name,
+            'type' => self.class.name,
             'data' => [@string]
-        }.to_json(*args)
+        }.to_pson(*args)
     end
 
     def self.canonical_order(s)
-        s.gsub(/\{"data":\[(.*?)\],"json_class":"JsonIntTest"\}/,'{"json_class":"JsonIntTest","data":[\1]}')
+        s.gsub(/\{"data":\[(.*?)\],"type":"PsonIntTest"\}/,'{"type":"PsonIntTest","data":[\1]}')
     end
 
 end
@@ -45,65 +45,65 @@ describe Puppet::Network::FormatHandler.format(:s) do
     end
 end
 
-describe Puppet::Network::FormatHandler.format(:json) do
-    describe "when json is absent" do
-        confine "'json' library is present" => (! Puppet.features.json?)
+describe Puppet::Network::FormatHandler.format(:pson) do
+    describe "when pson is absent" do
+        confine "'pson' library is present" => (! Puppet.features.pson?)
 
         before do
-            @json = Puppet::Network::FormatHandler.format(:json)
+            @pson = Puppet::Network::FormatHandler.format(:pson)
         end
 
         it "should not be suitable" do
-            @json.should_not be_suitable
+            @pson.should_not be_suitable
         end
     end
 
-    describe "when json is available" do
-        confine "Missing 'json' library" => Puppet.features.json?
+    describe "when pson is available" do
+        confine "Missing 'pson' library" => Puppet.features.pson?
 
         before do
-            @json = Puppet::Network::FormatHandler.format(:json)
+            @pson = Puppet::Network::FormatHandler.format(:pson)
         end
 
-        it "should be able to render an instance to json" do
-            instance = JsonIntTest.new("foo")
-            JsonIntTest.canonical_order(@json.render(instance)).should == JsonIntTest.canonical_order('{"json_class":"JsonIntTest","data":["foo"]}' )
+        it "should be able to render an instance to pson" do
+            instance = PsonIntTest.new("foo")
+            PsonIntTest.canonical_order(@pson.render(instance)).should == PsonIntTest.canonical_order('{"type":"PsonIntTest","data":["foo"]}' )
         end
 
-        it "should be able to render arrays to json" do
-            @json.render([1,2]).should == '[1,2]'
+        it "should be able to render arrays to pson" do
+            @pson.render([1,2]).should == '[1,2]'
         end
 
-        it "should be able to render arrays containing hashes to json" do
-            @json.render([{"one"=>1},{"two"=>2}]).should == '[{"one":1},{"two":2}]'
+        it "should be able to render arrays containing hashes to pson" do
+            @pson.render([{"one"=>1},{"two"=>2}]).should == '[{"one":1},{"two":2}]'
         end
 
-        it "should be able to render multiple instances to json" do
-            Puppet.features.add(:json, :libs => ["json"])
+        it "should be able to render multiple instances to pson" do
+            Puppet.features.add(:pson, :libs => ["pson"])
 
-            one = JsonIntTest.new("one")
-            two = JsonIntTest.new("two")
+            one = PsonIntTest.new("one")
+            two = PsonIntTest.new("two")
 
-            JsonIntTest.canonical_order(@json.render([one,two])).should == JsonIntTest.canonical_order('[{"json_class":"JsonIntTest","data":["one"]},{"json_class":"JsonIntTest","data":["two"]}]')
+            PsonIntTest.canonical_order(@pson.render([one,two])).should == PsonIntTest.canonical_order('[{"type":"PsonIntTest","data":["one"]},{"type":"PsonIntTest","data":["two"]}]')
         end
 
-        it "should be able to intern json into an instance" do
-            @json.intern(JsonIntTest, '{"json_class":"JsonIntTest","data":["foo"]}').should == JsonIntTest.new("foo")
+        it "should be able to intern pson into an instance" do
+            @pson.intern(PsonIntTest, '{"type":"PsonIntTest","data":["foo"]}').should == PsonIntTest.new("foo")
         end
 
-        it "should be able to intern json with no class information into an instance" do
-            @json.intern(JsonIntTest, '["foo"]').should == JsonIntTest.new("foo")
+        it "should be able to intern pson with no class information into an instance" do
+            @pson.intern(PsonIntTest, '["foo"]').should == PsonIntTest.new("foo")
         end
 
-        it "should be able to intern multiple instances from json" do
-            @json.intern_multiple(JsonIntTest, '[{"json_class": "JsonIntTest", "data": ["one"]},{"json_class": "JsonIntTest", "data": ["two"]}]').should == [
-                JsonIntTest.new("one"), JsonIntTest.new("two")
+        it "should be able to intern multiple instances from pson" do
+            @pson.intern_multiple(PsonIntTest, '[{"type": "PsonIntTest", "data": ["one"]},{"type": "PsonIntTest", "data": ["two"]}]').should == [
+                PsonIntTest.new("one"), PsonIntTest.new("two")
             ]
         end
 
-        it "should be able to intern multiple instances from json with no class information" do
-            @json.intern_multiple(JsonIntTest, '[["one"],["two"]]').should == [
-                JsonIntTest.new("one"), JsonIntTest.new("two")
+        it "should be able to intern multiple instances from pson with no class information" do
+            @pson.intern_multiple(PsonIntTest, '[["one"],["two"]]').should == [
+                PsonIntTest.new("one"), PsonIntTest.new("two")
             ]
         end
     end
diff --git a/spec/integration/resource/catalog.rb b/spec/integration/resource/catalog.rb
index 9c7c37d..f400445 100755
--- a/spec/integration/resource/catalog.rb
+++ b/spec/integration/resource/catalog.rb
@@ -6,10 +6,10 @@
 require File.dirname(__FILE__) + '/../../spec_helper'
 
 describe Puppet::Resource::Catalog do
-    describe "when json is available" do
-        confine "JSON library is missing" => Puppet.features.json?
-        it "should support json" do
-            Puppet::Resource::Catalog.supported_formats.should be_include(:json)
+    describe "when pson is available" do
+        confine "PSON library is missing" => Puppet.features.pson?
+        it "should support pson" do
+            Puppet::Resource::Catalog.supported_formats.should be_include(:pson)
         end
     end
 
diff --git a/spec/unit/application/puppet.rb b/spec/unit/application/puppet.rb
index 3c11430..f4d6065 100755
--- a/spec/unit/application/puppet.rb
+++ b/spec/unit/application/puppet.rb
@@ -332,17 +332,17 @@ describe "Puppet" do
         end
 
         describe "the 'apply' command" do
-            confine "JSON library is missing; cannot test applying catalogs" => Puppet.features.json?
+            confine "PSON library is missing; cannot test applying catalogs" => Puppet.features.pson?
 
             before do
-                #Puppet::Resource::Catalog.stubs(:json_create).returns Puppet::Resource::Catalog.new
-                JSON.stubs(:parse).returns Puppet::Resource::Catalog.new
+                #Puppet::Resource::Catalog.stubs(:pson_create).returns Puppet::Resource::Catalog.new
+                PSON.stubs(:parse).returns Puppet::Resource::Catalog.new
             end
 
             it "should read the catalog in from disk if a file name is provided" do
-                @puppet.options[:catalog] = "/my/catalog.json"
+                @puppet.options[:catalog] = "/my/catalog.pson"
 
-                File.expects(:read).with("/my/catalog.json").returns "something"
+                File.expects(:read).with("/my/catalog.pson").returns "something"
 
                 @puppet.apply
             end
@@ -355,41 +355,41 @@ describe "Puppet" do
                 @puppet.apply
             end
 
-            it "should deserialize the catalog from json" do
-                @puppet.options[:catalog] = "/my/catalog.json"
+            it "should deserialize the catalog from pson" do
+                @puppet.options[:catalog] = "/my/catalog.pson"
 
                 File.expects(:read).returns "something"
-                JSON.expects(:parse).with("something").returns Puppet::Resource::Catalog.new
+                PSON.expects(:parse).with("something").returns Puppet::Resource::Catalog.new
 
                 @puppet.apply
             end
 
             it "should fail helpfully if deserializing fails" do
-                @puppet.options[:catalog] = "/my/catalog.json"
+                @puppet.options[:catalog] = "/my/catalog.pson"
 
                 File.expects(:read).returns "something"
-                JSON.expects(:parse).raises ArgumentError
+                PSON.expects(:parse).raises ArgumentError
 
                 lambda { @puppet.apply }.should raise_error(Puppet::Error)
             end
 
             it "should convert plain data structures into a catalog if deserialization does not do so" do
-                @puppet.options[:catalog] = "/my/catalog.json"
+                @puppet.options[:catalog] = "/my/catalog.pson"
 
                 File.expects(:read).returns "something"
-                JSON.expects(:parse).with("something").returns({:foo => "bar"})
-                Puppet::Resource::Catalog.expects(:json_create).with({:foo => "bar"}).returns(Puppet::Resource::Catalog.new)
+                PSON.expects(:parse).with("something").returns({:foo => "bar"})
+                Puppet::Resource::Catalog.expects(:pson_create).with({:foo => "bar"}).returns(Puppet::Resource::Catalog.new)
 
                 @puppet.apply
             end
 
             it "should convert the catalog to a RAL catalog and use a Configurer instance to apply it" do
-                @puppet.options[:catalog] = "/my/catalog.json"
+                @puppet.options[:catalog] = "/my/catalog.pson"
 
                 File.expects(:read).returns "something"
 
                 catalog = Puppet::Resource::Catalog.new
-                JSON.expects(:parse).returns catalog
+                PSON.expects(:parse).returns catalog
 
                 catalog.expects(:to_ral).returns "mycatalog"
 
diff --git a/spec/unit/application/puppetmasterd.rb b/spec/unit/application/puppetmasterd.rb
index a4875c7..9801387 100644
--- a/spec/unit/application/puppetmasterd.rb
+++ b/spec/unit/application/puppetmasterd.rb
@@ -294,11 +294,11 @@ describe "PuppetMaster" do
                 Puppet.stubs(:err)
                 @puppetmasterd.stubs(:exit)
                 Puppet::Parser::Interpreter.stubs(:new).returns(@interpreter)
-                Puppet.features.stubs(:json?).returns true
+                Puppet.features.stubs(:pson?).returns true
             end
 
-            it "should fail if json isn't available" do
-                Puppet.features.expects(:json?).returns false
+            it "should fail if pson isn't available" do
+                Puppet.features.expects(:pson?).returns false
                 lambda { @puppetmasterd.compile }.should raise_error
             end
 
@@ -310,13 +310,13 @@ describe "PuppetMaster" do
                 @puppetmasterd.compile
             end
 
-            it "should render the catalog to json and print the output" do
+            it "should render the catalog to pson and print the output" do
                 @puppetmasterd.options[:node] = "foo"
                 catalog = Puppet::Resource::Catalog.new
-                catalog.expects(:render).with(:json).returns "myjson"
+                catalog.expects(:render).with(:pson).returns "mypson"
                 Puppet::Resource::Catalog.expects(:find).returns catalog
 
-                $stdout.expects(:puts).with("myjson")
+                $stdout.expects(:puts).with("mypson")
                 @puppetmasterd.compile
             end
 
diff --git a/spec/unit/indirector/queue.rb b/spec/unit/indirector/queue.rb
index c81cefe..0748b58 100755
--- a/spec/unit/indirector/queue.rb
+++ b/spec/unit/indirector/queue.rb
@@ -9,25 +9,25 @@ end
 class FooExampleData
     attr_accessor :name
 
-    def self.json_create(json)
-        new(json['data'].to_sym)
+    def self.pson_create(pson)
+        new(pson['data'].to_sym)
     end
 
     def initialize(name = nil)
         @name = name if name
     end
 
-    def render(format = :json)
-        to_json
+    def render(format = :pson)
+        to_pson
     end
 
-    def to_json(*args)
-        {:json_class => self.class.to_s, :data => name}.to_json(*args)
+    def to_pson(*args)
+        {:type => self.class.to_s, :data => name}.to_pson(*args)
     end
 end
 
 describe Puppet::Indirector::Queue do
-    confine "JSON library is missing; cannot test queueing" => Puppet.features.json?
+    confine "PSON library is missing; cannot test queueing" => Puppet.features.pson?
 
     before :each do
         @model = mock 'model'
@@ -51,8 +51,8 @@ describe Puppet::Indirector::Queue do
         @request = stub 'request', :key => :me, :instance => @subject
     end
 
-    it "should require JSON" do
-        Puppet.features.expects(:json?).returns false
+    it "should require PSON" do
+        Puppet.features.expects(:pson?).returns false
 
         lambda { @store_class.new }.should raise_error(ArgumentError)
     end
@@ -63,16 +63,16 @@ describe Puppet::Indirector::Queue do
     end
 
     describe "when saving" do
-        it 'should render the instance using json' do
-            @subject.expects(:render).with(:json)
+        it 'should render the instance using pson' do
+            @subject.expects(:render).with(:pson)
             @store.client.stubs(:send_message)
             @store.save(@request)
         end
 
         it "should send the rendered message to the appropriate queue on the client" do
-            @subject.expects(:render).returns "myjson"
+            @subject.expects(:render).returns "mypson"
 
-            @store.client.expects(:send_message).with(:my_queue, "myjson")
+            @store.client.expects(:send_message).with(:my_queue, "mypson")
 
             @store.save(@request)
         end
@@ -89,8 +89,8 @@ describe Puppet::Indirector::Queue do
             @store_class.stubs(:model).returns @model
         end
 
-        it "should use the model's Format support to intern the message from json" do
-            @model.expects(:convert_from).with(:json, "mymessage")
+        it "should use the model's Format support to intern the message from pson" do
+            @model.expects(:convert_from).with(:pson, "mymessage")
 
             @store_class.client.expects(:subscribe).yields("mymessage")
             @store_class.subscribe {|o| o }
diff --git a/spec/unit/network/formats.rb b/spec/unit/network/formats.rb
index c766f55..de2e0af 100755
--- a/spec/unit/network/formats.rb
+++ b/spec/unit/network/formats.rb
@@ -4,13 +4,13 @@ require File.dirname(__FILE__) + '/../../spec_helper'
 
 require 'puppet/network/formats'
 
-class JsonTest
+class PsonTest
     attr_accessor :string
     def ==(other)
         string == other.string
     end
 
-    def self.from_json(data)
+    def self.from_pson(data)
         new(data)
     end
 
@@ -18,11 +18,11 @@ class JsonTest
         @string = string
     end
 
-    def to_json(*args)
+    def to_pson(*args)
         {
-            'json_class' => self.class.name,
+            'type' => self.class.name,
             'data' => @string
-        }.to_json(*args)
+        }.to_pson(*args)
     end
 end
 
@@ -173,76 +173,76 @@ describe "Puppet Network Format" do
         end
     end
 
-    it "should include a json format" do
-        Puppet::Network::FormatHandler.format(:json).should_not be_nil
+    it "should include a pson format" do
+        Puppet::Network::FormatHandler.format(:pson).should_not be_nil
     end
 
-    describe "json" do
-        confine "Missing 'json' library" => Puppet.features.json?
+    describe "pson" do
+        confine "Missing 'pson' library" => Puppet.features.pson?
 
         before do
-            @json = Puppet::Network::FormatHandler.format(:json)
+            @pson = Puppet::Network::FormatHandler.format(:pson)
         end
 
-        it "should have its mime type set to text/json" do
-            Puppet::Network::FormatHandler.format(:json).mime.should == "text/json"
+        it "should have its mime type set to text/pson" do
+            Puppet::Network::FormatHandler.format(:pson).mime.should == "text/pson"
         end
 
         it "should require the :render_method" do
-            Puppet::Network::FormatHandler.format(:json).required_methods.should be_include(:render_method)
+            Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:render_method)
         end
 
         it "should require the :intern_method" do
-            Puppet::Network::FormatHandler.format(:json).required_methods.should be_include(:intern_method)
+            Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:intern_method)
         end
 
         it "should have a weight of 10" do
-            @json.weight.should == 10
+            @pson.weight.should == 10
         end
 
         describe "when supported" do
-            it "should render by calling 'to_json' on the instance" do
-                instance = JsonTest.new("foo")
-                instance.expects(:to_json).returns "foo"
-                @json.render(instance).should == "foo"
+            it "should render by calling 'to_pson' on the instance" do
+                instance = PsonTest.new("foo")
+                instance.expects(:to_pson).returns "foo"
+                @pson.render(instance).should == "foo"
             end
 
-            it "should render multiple instances by calling 'to_json' on the array" do
+            it "should render multiple instances by calling 'to_pson' on the array" do
                 instances = [mock('instance')]
 
-                instances.expects(:to_json).returns "foo"
+                instances.expects(:to_pson).returns "foo"
 
-                @json.render_multiple(instances).should == "foo"
+                @pson.render_multiple(instances).should == "foo"
             end
 
-            it "should intern by calling 'JSON.parse' on the text and then using from_json to convert the data into an instance" do
+            it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the data into an instance" do
                 text = "foo"
-                JSON.expects(:parse).with("foo").returns("json_class" => "JsonTest", "data" => "foo")
-                JsonTest.expects(:from_json).with("foo").returns "parsed_json"
-                @json.intern(JsonTest, text).should == "parsed_json"
+                PSON.expects(:parse).with("foo").returns("type" => "PsonTest", "data" => "foo")
+                PsonTest.expects(:from_pson).with("foo").returns "parsed_pson"
+                @pson.intern(PsonTest, text).should == "parsed_pson"
             end
 
-            it "should not render twice if 'JSON.parse' creates the appropriate instance" do
+            it "should not render twice if 'PSON.parse' creates the appropriate instance" do
                 text = "foo"
-                instance = JsonTest.new("foo")
-                JSON.expects(:parse).with("foo").returns(instance)
-                JsonTest.expects(:from_json).never
-                @json.intern(JsonTest, text).should equal(instance)
+                instance = PsonTest.new("foo")
+                PSON.expects(:parse).with("foo").returns(instance)
+                PsonTest.expects(:from_pson).never
+                @pson.intern(PsonTest, text).should equal(instance)
             end
 
-            it "should intern by calling 'JSON.parse' on the text and then using from_json to convert the actual into an instance if the json has no class/data separation" do
+            it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the actual into an instance if the pson has no class/data separation" do
                 text = "foo"
-                JSON.expects(:parse).with("foo").returns("foo")
-                JsonTest.expects(:from_json).with("foo").returns "parsed_json"
-                @json.intern(JsonTest, text).should == "parsed_json"
+                PSON.expects(:parse).with("foo").returns("foo")
+                PsonTest.expects(:from_pson).with("foo").returns "parsed_pson"
+                @pson.intern(PsonTest, text).should == "parsed_pson"
             end
 
             it "should intern multiples by parsing the text and using 'class.intern' on each resulting data structure" do
                 text = "foo"
-                JSON.expects(:parse).with("foo").returns ["bar", "baz"]
-                JsonTest.expects(:from_json).with("bar").returns "BAR"
-                JsonTest.expects(:from_json).with("baz").returns "BAZ"
-                @json.intern_multiple(JsonTest, text).should == %w{BAR BAZ}
+                PSON.expects(:parse).with("foo").returns ["bar", "baz"]
+                PsonTest.expects(:from_pson).with("bar").returns "BAR"
+                PsonTest.expects(:from_pson).with("baz").returns "BAZ"
+                @pson.intern_multiple(PsonTest, text).should == %w{BAR BAZ}
             end
         end
     end
diff --git a/spec/unit/relationship.rb b/spec/unit/relationship.rb
index fd7e0aa..5a52cb5 100755
--- a/spec/unit/relationship.rb
+++ b/spec/unit/relationship.rb
@@ -155,68 +155,43 @@ describe Puppet::Relationship, " when matching edges with a non-standard event"
     end
 end
 
-describe Puppet::Relationship, "when converting to json" do
-    confine "Missing 'json' library" => Puppet.features.json?
+describe Puppet::Relationship, "when converting to pson" do
+    confine "Missing 'pson' library" => Puppet.features.pson?
 
     before do
         @edge = Puppet::Relationship.new(:a, :b, :event => :random, :callback => :whatever)
     end
 
-    def json_output_should
-        @edge.class.expects(:json_create).with { |hash| yield hash }
-    end
-
-    # LAK:NOTE For all of these tests, we convert back to the edge so we can
-    # trap the actual data structure then.
-    it "should set the 'json_class' to Puppet::Relationship" do
-        json_output_should { |hash| hash['json_class'] == "Puppet::Relationship" }
-
-        JSON.parse @edge.to_json
-    end
-
     it "should store the stringified source as the source in the data" do
-        json_output_should { |hash| hash['data']['source'] == "a" }
-
-        JSON.parse @edge.to_json
+        PSON.parse(@edge.to_pson)["source"].should == "a"
     end
 
     it "should store the stringified target as the target in the data" do
-        json_output_should { |hash| hash['data']['target'] == "b" }
-
-        JSON.parse @edge.to_json
+        PSON.parse(@edge.to_pson)['target'].should == "b"
     end
 
-    it "should store the jsonified event as the event in the data" do
-        @edge.event = :random
-        json_output_should { |hash| hash['data']['event'] == "random" }
-
-        JSON.parse @edge.to_json
+    it "should store the psonified event as the event in the data" do
+        PSON.parse(@edge.to_pson)["event"].should == "random"
     end
 
     it "should not store an event when none is set" do
         @edge.event = nil
-        json_output_should { |hash| hash['data']['event'].nil? }
-
-        JSON.parse @edge.to_json
+        PSON.parse(@edge.to_pson)["event"].should be_nil
     end
 
-    it "should store the jsonified callback as the callback in the data" do
+    it "should store the psonified callback as the callback in the data" do
         @edge.callback = "whatever"
-        json_output_should { |hash| hash['data']['callback'] == "whatever" }
-
-        JSON.parse @edge.to_json
+        PSON.parse(@edge.to_pson)["callback"].should == "whatever"
     end
 
     it "should not store a callback when none is set in the edge" do
         @edge.callback = nil
-        json_output_should { |hash| hash['data']['callback'].nil? }
-
-        JSON.parse @edge.to_json
+        PSON.parse(@edge.to_pson)["callback"].should be_nil
     end
 end
 
-describe Puppet::Relationship, "when converting from json" do
-    confine "Missing 'json' library" => Puppet.features.json?
+describe Puppet::Relationship, "when converting from pson" do
+    confine "Missing 'pson' library" => Puppet.features.pson?
 
     before do
         @event = "random"
@@ -227,35 +202,35 @@ describe Puppet::Relationship, "when converting from json" do
             "event" => @event,
             "callback" => @callback
         }
-        @json = {
-            "json_class" => "Puppet::Relationship",
+        @pson = {
+            "type" => "Puppet::Relationship",
             "data" => @data
         }
     end
 
-    def json_result_should
+    def pson_result_should
         Puppet::Relationship.expects(:new).with { |*args| yield args }
     end
 
-    it "should be extended with the JSON utility module" do
-        Puppet::Relationship.metaclass.ancestors.should be_include(Puppet::Util::Json)
+    it "should be extended with the PSON utility module" do
+        Puppet::Relationship.metaclass.ancestors.should be_include(Puppet::Util::Pson)
     end
 
     # LAK:NOTE For all of these tests, we convert back to the edge so we can
     # trap the actual data structure then.
     it "should pass the source in as the first argument" do
-        Puppet::Relationship.from_json("source" => "mysource", "target" => "mytarget").source.should == "mysource"
+        Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget").source.should == "mysource"
     end
 
     it "should pass the target in as the second argument" do
-        Puppet::Relationship.from_json("source" => "mysource", "target" => "mytarget").target.should == "mytarget"
+        Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget").target.should == "mytarget"
     end
 
     it "should pass the event as an argument if it's provided" do
-        Puppet::Relationship.from_json("source" => "mysource", "target" => "mytarget", "event" => "myevent", "callback" => "eh").event.should == "myevent"
+        Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget", "event" => "myevent", "callback" => "eh").event.should == "myevent"
     end
 
     it "should pass the callback as an argument if it's provided" do
-        Puppet::Relationship.from_json("source" => "mysource", "target" => "mytarget", "callback" => "mycallback").callback.should == "mycallback"
+        Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget", "callback" => "mycallback").callback.should == "mycallback"
     end
 end
diff --git a/spec/unit/resource.rb b/spec/unit/resource.rb
index c233dd3..b26f4f9 100755
--- a/spec/unit/resource.rb
+++ b/spec/unit/resource.rb
@@ -354,63 +354,60 @@ describe Puppet::Resource do
         end
     end
 
-    describe "when converting to json" do
-        confine "Missing 'json' library" => Puppet.features.json?
+    describe "when converting to pson" do
+        confine "Missing 'pson' library" => Puppet.features.pson?
 
-        def json_output_should
-            @resource.class.expects(:json_create).with { |hash| yield hash }
+        def pson_output_should
+            @resource.class.expects(:pson_create).with { |hash| yield hash }
         end
 
-        it "should include the json util module" do
-            Puppet::Resource.metaclass.ancestors.should be_include(Puppet::Util::Json)
+        it "should include the pson util module" do
+            Puppet::Resource.metaclass.ancestors.should be_include(Puppet::Util::Pson)
         end
 
         # LAK:NOTE For all of these tests, we convert back to the resource so we can
         # trap the actual data structure then.
-        it "should set its json_class to 'Puppet::Resource'" do
-            JSON.parse(Puppet::Resource.new("file", "yay").to_json).should be_instance_of(Puppet::Resource)
-        end
 
         it "should set its type to the provided type" do
-            JSON.parse(Puppet::Resource.new("File", "/foo").to_json).type.should == "File"
+            Puppet::Resource.from_pson(PSON.parse(Puppet::Resource.new("File", "/foo").to_pson)).type.should == "File"
         end
 
         it "should set its title to the provided title" do
-            JSON.parse(Puppet::Resource.new("File", "/foo").to_json).title.should == "/foo"
+            Puppet::Resource.from_pson(PSON.parse(Puppet::Resource.new("File", "/foo").to_pson)).title.should == "/foo"
         end
 
         it "should include all tags from the resource" do
             resource = Puppet::Resource.new("File", "/foo")
             resource.tag("yay")
 
-            JSON.parse(resource.to_json).tags.should == resource.tags
+            Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).tags.should == resource.tags
         end
 
         it "should include the file if one is set" do
             resource = Puppet::Resource.new("File", "/foo")
             resource.file = "/my/file"
 
-            JSON.parse(resource.to_json).file.should == "/my/file"
+            Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).file.should == "/my/file"
         end
 
         it "should include the line if one is set" do
             resource = Puppet::Resource.new("File", "/foo")
             resource.line = 50
 
-            JSON.parse(resource.to_json).line.should == 50
+            Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).line.should == 50
         end
 
         it "should include the 'exported' value if one is set" do
             resource = Puppet::Resource.new("File", "/foo")
             resource.exported = true
 
-            JSON.parse(resource.to_json).exported.should be_true
+            Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).exported.should be_true
         end
 
         it "should set 'exported' to false if no value is set" do
             resource = Puppet::Resource.new("File", "/foo")
 
-            JSON.parse(resource.to_json).exported.should be_false
+            Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).exported.should be_false
         end
 
         it "should set all of its parameters as the 'parameters' entry" do
@@ -418,16 +415,16 @@ describe Puppet::Resource do
             resource[:foo] = %w{bar eh}
             resource[:fee] = %w{baz}
 
-            result = JSON.parse(resource.to_json)
+            result = Puppet::Resource.from_pson(PSON.parse(resource.to_pson))
             result["foo"].should == %w{bar eh}
             result["fee"].should == %w{baz}
         end
     end
 
-    describe "when converting from json" do
-        confine "Missing 'json' library" => Puppet.features.json?
+    describe "when converting from pson" do
+        confine "Missing 'pson' library" => Puppet.features.pson?
 
-        def json_result_should
+        def pson_result_should
             Puppet::Resource.expects(:new).with { |hash| yield hash }
         end
 
@@ -439,59 +436,59 @@ describe Puppet::Resource do
         end
 
         it "should set its type to the provided type" do
-            Puppet::Resource.from_json(@data).type.should == "File"
+            Puppet::Resource.from_pson(@data).type.should == "File"
         end
 
         it "should set its title to the provided title" do
-            Puppet::Resource.from_json(@data).title.should == "yay"
+            Puppet::Resource.from_pson(@data).title.should == "yay"
         end
 
         it "should tag the resource with any provided tags" do
             @data['tags'] = %w{foo bar}
-            resource = Puppet::Resource.from_json(@data)
+            resource = Puppet::Resource.from_pson(@data)
             resource.tags.should be_include("foo")
             resource.tags.should be_include("bar")
         end
 
         it "should set its file to the provided file" do
             @data['file'] = "/foo/bar"
-            Puppet::Resource.from_json(@data).file.should == "/foo/bar"
+            Puppet::Resource.from_pson(@data).file.should == "/foo/bar"
         end
 
         it "should set its line to the provided line" do
             @data['line'] = 50
-            Puppet::Resource.from_json(@data).line.should == 50
+            Puppet::Resource.from_pson(@data).line.should == 50
         end
 
-        it "should 'exported' to true if set in the json data" do
+        it "should 'exported' to true if set in the pson data" do
             @data['exported'] = true
-            Puppet::Resource.from_json(@data).exported.should be_true
+            Puppet::Resource.from_pson(@data).exported.should be_true
         end
 
-        it "should 'exported' to false if not set in the json data" do
-            Puppet::Resource.from_json(@data).exported.should be_false
+        it "should 'exported' to false if not set in the pson data" do
+            Puppet::Resource.from_pson(@data).exported.should be_false
         end
 
         it "should fail if no title is provided" do
             @data.delete('title')
-            lambda { Puppet::Resource.from_json(@data) }.should raise_error(ArgumentError)
+            lambda { Puppet::Resource.from_pson(@data) }.should raise_error(ArgumentError)
         end
 
         it "should fail if no type is provided" do
             @data.delete('type')
-            lambda { Puppet::Resource.from_json(@data) }.should raise_error(ArgumentError)
+            lambda { Puppet::Resource.from_pson(@data) }.should raise_error(ArgumentError)
         end
 
         it "should set each of the provided parameters" do
             @data['parameters'] = {'foo' => %w{one two}, 'fee' => %w{three four}}
-            resource = Puppet::Resource.from_json(@data)
+            resource = Puppet::Resource.from_pson(@data)
             resource['foo'].should == %w{one two}
             resource['fee'].should == %w{three four}
         end
 
         it "should convert single-value array parameters to normal values" do
             @data['parameters'] = {'foo' => %w{one}}
-            resource = Puppet::Resource.from_json(@data)
+            resource = Puppet::Resource.from_pson(@data)
             resource['foo'].should == %w{one}
         end
     end
diff --git a/spec/unit/resource/catalog.rb b/spec/unit/resource/catalog.rb
index 1fbe3a9..39f185a 100755
--- a/spec/unit/resource/catalog.rb
+++ b/spec/unit/resource/catalog.rb
@@ -887,71 +887,70 @@ describe Puppet::Resource::Catalog, "when compiling" do
     end
 end
 
-describe Puppet::Resource::Catalog, "when converting to json" do
-    confine "Missing 'json' library" => Puppet.features.json?
+describe Puppet::Resource::Catalog, "when converting to pson" do
+    confine "Missing 'pson' library" => Puppet.features.pson?
 
     before do
         @catalog = Puppet::Resource::Catalog.new("myhost")
     end
 
-    def json_output_should
-        @catalog.class.expects(:json_create).with { |hash| yield hash }
+    def pson_output_should
+        @catalog.class.expects(:pson_create).with { |hash| yield hash }.returns(:something)
     end
 
     # LAK:NOTE For all of these tests, we convert back to the resource so we can
     # trap the actual data structure then.
-    it "should set its json_class to 'Puppet::Resource::Catalog'" do
-        json_output_should { |hash| hash['json_class'] == "Puppet::Resource::Catalog" }
+    it "should set its document_type to 'Catalog'" do
+        pson_output_should { |hash| hash['document_type'] == "Catalog" }
 
-        JSON.parse @catalog.to_json
+        PSON.parse @catalog.to_pson
     end
 
     it "should set its data as a hash" do
-        json_output_should { |hash| hash['data'].is_a?(Hash) }
-        JSON.parse @catalog.to_json
+        pson_output_should { |hash| hash['data'].is_a?(Hash) }
+        PSON.parse @catalog.to_pson
     end
 
     [:name, :version, :tags].each do |param|
         it "should set its #{param} to the #{param} of the resource" do
             @catalog.send(param.to_s + "=", "testing") unless @catalog.send(param)
 
-            json_output_should { |hash| hash['data'][param.to_s] == @catalog.send(param) }
-            JSON.parse @catalog.to_json
+            pson_output_should { |hash| hash['data'][param.to_s] == @catalog.send(param) }
+            PSON.parse @catalog.to_pson
         end
     end
 
-    it "should convert its resources to a JSON-encoded array and store it as the 'resources' data" do
-        one = stub 'one', :to_json => '"one_resource"', :ref => "Foo[one]"
-        two = stub 'two', :to_json => '"two_resource"', :ref => "Foo[two]"
+    it "should convert its resources to a PSON-encoded array and store it as the 'resources' data" do
+        one = stub 'one', :to_pson_data_hash => "one_resource", :ref => "Foo[one]"
+        two = stub 'two', :to_pson_data_hash => "two_resource", :ref => "Foo[two]"
 
         @catalog.add_resource(one)
         @catalog.add_resource(two)
 
         # TODO this should really guarantee sort order
-        json_output_should { |hash| JSON.parse(hash['data']['resources']).sort == ["one_resource", "two_resource"].sort }
-        JSON.parse @catalog.to_json
+        PSON.parse(@catalog.to_pson,:create_additions => false)['data']['resources'].sort.should == ["one_resource", "two_resource"].sort
+
     end
 
-    it "should convert its edges to a JSON-encoded array and store it as the 'edges' data" do
-        one = stub 'one', :to_json => '"one_resource"', :ref => 'Foo[one]'
-        two = stub 'two', :to_json => '"two_resource"', :ref => 'Foo[two]'
-        three = stub 'three', :to_json => '"three_resource"', :ref => 'Foo[three]'
+    it "should convert its edges to a PSON-encoded array and store it as the 'edges' data" do
+        one   = stub 'one',   :to_pson_data_hash => "one_resource",   :ref => 'Foo[one]'
+        two   = stub 'two',   :to_pson_data_hash => "two_resource",   :ref => 'Foo[two]'
+        three = stub 'three', :to_pson_data_hash => "three_resource", :ref => 'Foo[three]'
 
         @catalog.add_edge(one, two)
         @catalog.add_edge(two, three)
 
-        @catalog.edge(one, two).expects(:to_json).returns '"one_two_json"'
-        @catalog.edge(two, three).expects(:to_json).returns '"two_three_json"'
+        @catalog.edge(one, two  ).expects(:to_pson_data_hash).returns "one_two_pson"
+        @catalog.edge(two, three).expects(:to_pson_data_hash).returns "two_three_pson"
 
-        json_output_should { |hash| JSON.parse(hash['data']['edges']).sort == %w{one_two_json two_three_json}.sort }
-        JSON.parse @catalog.to_json
+        PSON.parse(@catalog.to_pson,:create_additions => false)['data']['edges'].sort.should == %w{one_two_pson two_three_pson}.sort
     end
 end
 
-describe Puppet::Resource::Catalog, "when converting from json" do
-    confine "Missing 'json' library" => Puppet.features.json?
+describe Puppet::Resource::Catalog, "when converting from pson" do
+    confine "Missing 'pson' library" => Puppet.features.pson?
 
-    def json_result_should
+    def pson_result_should
         Puppet::Resource::Catalog.expects(:new).with { |hash| yield hash }
     end
 
@@ -959,54 +958,54 @@ describe Puppet::Resource::Catalog, "when converting from json" do
         @data = {
             'name' => "myhost"
         }
-        @json = {
-            'json_class' => 'Puppet::Resource::Catalog',
-            'data' => @data
+        @pson = {
+            'document_type' => 'Puppet::Resource::Catalog',
+            'data' => @data,
+            'metadata' => {}
         }
 
         @catalog = Puppet::Resource::Catalog.new("myhost")
         Puppet::Resource::Catalog.stubs(:new).returns @catalog
     end
 
-    it "should be extended with the JSON utility module" do
-        Puppet::Resource::Catalog.metaclass.ancestors.should be_include(Puppet::Util::Json)
+    it "should be extended with the PSON utility module" do
+        Puppet::Resource::Catalog.metaclass.ancestors.should be_include(Puppet::Util::Pson)
     end
 
     it "should create it with the provided name" do
         Puppet::Resource::Catalog.expects(:new).with('myhost').returns @catalog
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
     it "should set the provided version on the catalog if one is set" do
         @data['version'] = 50
         @catalog.expects(:version=).with(@data['version'])
 
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
     it "should set any provided tags on the catalog" do
         @data['tags'] = %w{one two}
         @catalog.expects(:tag).with("one", "two")
 
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
     it 'should convert the resources list into resources and add each of them' do
         @data['resources'] = [Puppet::Resource.new(:file, "/foo"), Puppet::Resource.new(:file, "/bar")]
 
         @catalog.expects(:add_resource).times(2).with { |res| res.type == "File" }
-
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
-    it 'should convert resources even if they do not include "json_class" information' do
+    it 'should convert resources even if they do not include "type" information' do
         @data['resources'] = [Puppet::Resource.new(:file, "/foo")]
 
-        @data['resources'][0].expects(:to_json).returns "{\"title\":\"\\/foo\",\"tags\":[\"file\"],\"type\":\"File\"}"
+        @data['resources'][0].expects(:to_pson).returns '{"title":"/foo","tags":["file"],"type":"File"}'
 
         @catalog.expects(:add_resource).with { |res| res.type == "File" }
 
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
     it 'should convert the edges list into edges and add each of them' do
@@ -1020,12 +1019,12 @@ describe Puppet::Resource::Catalog, "when converting from json" do
         @catalog.expects(:add_edge).with { |edge| edge.event == "one" }
         @catalog.expects(:add_edge).with { |edge| edge.event == "two" }
 
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
-    it "should be able to convert relationships that do not include 'json_class' information" do
+    it "should be able to convert relationships that do not include 'type' information" do
         one = Puppet::Relationship.new("osource", "otarget", :event => "one", :callback => "refresh")
-        one.expects(:to_json).returns "{\"event\":\"one\",\"callback\":\"refresh\",\"source\":\"osource\",\"target\":\"otarget\"}"
+        one.expects(:to_pson).returns "{\"event\":\"one\",\"callback\":\"refresh\",\"source\":\"osource\",\"target\":\"otarget\"}"
 
         @data['edges'] = [one]
 
@@ -1033,7 +1032,7 @@ describe Puppet::Resource::Catalog, "when converting from json" do
 
         @catalog.expects(:add_edge).with { |edge| edge.event == "one" }
 
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
     it "should set the source and target for each edge to the actual resource" do
@@ -1046,7 +1045,7 @@ describe Puppet::Resource::Catalog, "when converting from json" do
 
         @catalog.expects(:add_edge).with { |edge| edge.source == "source_resource" and edge.target == "target_resource" }
 
-        JSON.parse @json.to_json
+        PSON.parse @pson.to_pson
     end
 
     it "should fail if the source resource cannot be found" do
@@ -1057,7 +1056,7 @@ describe Puppet::Resource::Catalog, "when converting from json" do
         @catalog.expects(:resource).with("source").returns(nil)
         @catalog.stubs(:resource).with("target").returns("target_resource")
 
-        lambda { JSON.parse @json.to_json }.should raise_error(ArgumentError)
+        lambda { PSON.parse @pson.to_pson }.should raise_error(ArgumentError)
     end
 
     it "should fail if the target resource cannot be found" do
@@ -1068,6 +1067,6 @@ describe Puppet::Resource::Catalog, "when converting from json" do
         @catalog.stubs(:resource).with("source").returns("source_resource")
         @catalog.expects(:resource).with("target").returns(nil)
 
-        lambda { JSON.parse @json.to_json }.should raise_error(ArgumentError)
+        lambda { PSON.parse @pson.to_pson }.should raise_error(ArgumentError)
     end
 end
diff --git a/spec/unit/util/json.rb b/spec/unit/util/json.rb
index 5ef5dc6..ce96486 100755
--- a/spec/unit/util/json.rb
+++ b/spec/unit/util/json.rb
@@ -2,20 +2,20 @@
 
 Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") }
 
-require 'puppet/util/json'
+require 'puppet/util/pson'
 
-class JsonUtil
-    include Puppet::Util::Json
+class PsonUtil
+    include Puppet::Util::Pson
 end
 
-describe Puppet::Util::Json do
+describe Puppet::Util::Pson do
     it "should fail if no data is provided" do
-        lambda { JsonUtil.new.json_create("json_class" => "foo") }.should raise_error(ArgumentError)
+        lambda { PsonUtil.new.pson_create("type" => "foo") }.should raise_error(ArgumentError)
     end
 
-    it "should call 'from_json' with the provided data" do
-        json = JsonUtil.new
-        json.expects(:from_json).with("mydata")
-        json.json_create("json_class" => "foo", "data" => "mydata")
+    it "should call 'from_pson' with the provided data" do
+        pson = PsonUtil.new
+        pson.expects(:from_pson).with("mydata")
+        pson.pson_create("type" => "foo", "data" => "mydata")
     end
 end

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list