summaryrefslogtreecommitdiffstats
path: root/lib/puppet/external/pson
diff options
context:
space:
mode:
authorMarkus Roberts <Markus@reality.com>2010-07-09 18:05:04 -0700
committerMarkus Roberts <Markus@reality.com>2010-07-09 18:05:04 -0700
commit9ee56f2e67be973da49b1d3f21de1bf87de35e6f (patch)
treeddab8c01509f47664c52c8a6b165bb5a974f138f /lib/puppet/external/pson
parent051bd98751d9d4bc97f93f66723d9b7a00c0cfb4 (diff)
downloadpuppet-9ee56f2e67be973da49b1d3f21de1bf87de35e6f.tar.gz
puppet-9ee56f2e67be973da49b1d3f21de1bf87de35e6f.tar.xz
puppet-9ee56f2e67be973da49b1d3f21de1bf87de35e6f.zip
Code smell: Inconsistent indentation and related formatting issues
* Replaced 163 occurances of defined\? +([@a-zA-Z_.0-9?=]+) with defined?(\1) This makes detecting subsequent patterns easier. 3 Examples: The code: if ! defined? @parse_config becomes: if ! defined?(@parse_config) The code: return @option_parser if defined? @option_parser becomes: return @option_parser if defined?(@option_parser) The code: if defined? @local and @local becomes: if defined?(@local) and @local * Eliminate trailing spaces. Replaced 428 occurances of ^(.*?) +$ with \1 1 file was skipped. test/ral/providers/host/parsed.rb because 0 * Replace leading tabs with an appropriate number of spaces. Replaced 306 occurances of ^(\t+)(.*) with Tabs are not consistently expanded in all environments. * Don't arbitrarily wrap on sprintf (%) operator. Replaced 143 occurances of (.*['"] *%) +(.*) with Splitting the line does nothing to aid clarity and hinders further refactorings. 3 Examples: The code: raise Puppet::Error, "Cannot create %s: basedir %s is a file" % [dir, File.join(path)] becomes: raise Puppet::Error, "Cannot create %s: basedir %s is a file" % [dir, File.join(path)] The code: Puppet.err "Will not start without authorization file %s" % Puppet[:authconfig] becomes: Puppet.err "Will not start without authorization file %s" % Puppet[:authconfig] The code: $stderr.puts "Could not find host for PID %s with status %s" % [pid, $?.exitstatus] becomes: $stderr.puts "Could not find host for PID %s with status %s" % [pid, $?.exitstatus] * Don't break short arrays/parameter list in two. Replaced 228 occurances of (.*) +(.*) with 3 Examples: The code: puts @format.wrap(type.provider(prov).doc, :indent => 4, :scrub => true) becomes: puts @format.wrap(type.provider(prov).doc, :indent => 4, :scrub => true) The code: assert(FileTest.exists?(daily), "Did not make daily graph for %s" % type) becomes: assert(FileTest.exists?(daily), "Did not make daily graph for %s" % type) The code: assert(prov.target_object(:first).read !~ /^notdisk/, "Did not remove thing from disk") becomes: assert(prov.target_object(:first).read !~ /^notdisk/, "Did not remove thing from disk") * If arguments must wrap, treat them all equally Replaced 510 occurances of lines ending in things like ...(foo, or ...(bar(1,3), with \1 \2 3 Examples: The code: midscope.to_hash(false), becomes: assert_equal( The code: botscope.to_hash(true), becomes: # bottomscope, then checking that we see the right stuff. The code: :path => link, becomes: * Replaced 4516 occurances of ^( *)(.*) with The present code base is supposed to use four-space indentation. In some places we failed to maintain that standard. These should be fixed regardless of the 2 vs. 4 space question. 15 Examples: The code: def run_comp(cmd) puts cmd results = [] old_sync = $stdout.sync $stdout.sync = true line = [] begin open("| #{cmd}", "r") do |f| until f.eof? do c = f.getc becomes: def run_comp(cmd) puts cmd results = [] old_sync = $stdout.sync $stdout.sync = true line = [] begin open("| #{cmd}", "r") do |f| until f.eof? do c = f.getc The code: 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!(/( becomes: 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!(/( The code: end } rvalues: rvalue | rvalues comma rvalue { if val[0].instance_of?(AST::ASTArray) result = val[0].push(val[2]) else result = ast AST::ASTArray, :children => [val[0],val[2]] end } becomes: end } rvalues: rvalue | rvalues comma rvalue { if val[0].instance_of?(AST::ASTArray) result = val[0].push(val[2]) else result = ast AST::ASTArray, :children => [val[0],val[2]] end } The code: #passwdproc = proc { @password } keytext = @key.export( OpenSSL::Cipher::DES.new(:EDE3, :CBC), @password ) File.open(@keyfile, "w", 0400) { |f| f << keytext } becomes: # passwdproc = proc { @password } keytext = @key.export( OpenSSL::Cipher::DES.new(:EDE3, :CBC), @password ) File.open(@keyfile, "w", 0400) { |f| f << keytext } The code: end def to_manifest "%s { '%s':\n%s\n}" % [self.type.to_s, self.name, @params.collect { |p, v| if v.is_a? Array " #{p} => [\'#{v.join("','")}\']" else " #{p} => \'#{v}\'" end }.join(",\n") becomes: end def to_manifest "%s { '%s':\n%s\n}" % [self.type.to_s, self.name, @params.collect { |p, v| if v.is_a? Array " #{p} => [\'#{v.join("','")}\']" else " #{p} => \'#{v}\'" end }.join(",\n") The code: via the augeas tool. Requires: - augeas to be installed (http://www.augeas.net) - ruby-augeas bindings Sample usage with a string:: augeas{\"test1\" : context => \"/files/etc/sysconfig/firstboot\", changes => \"set RUN_FIRSTBOOT YES\", becomes: via the augeas tool. Requires: - augeas to be installed (http://www.augeas.net) - ruby-augeas bindings Sample usage with a string:: augeas{\"test1\" : context => \"/files/etc/sysconfig/firstboot\", changes => \"set RUN_FIRSTBOOT YES\", The code: names.should_not be_include("root") end describe "when generating a purgeable resource" do it "should be included in the generated resources" do Puppet::Type.type(:host).stubs(:instances).returns [@purgeable_resource] @resources.generate.collect { |r| r.ref }.should include(@purgeable_resource.ref) end end describe "when the instance's do not have an ensure property" do becomes: names.should_not be_include("root") end describe "when generating a purgeable resource" do it "should be included in the generated resources" do Puppet::Type.type(:host).stubs(:instances).returns [@purgeable_resource] @resources.generate.collect { |r| r.ref }.should include(@purgeable_resource.ref) end end describe "when the instance's do not have an ensure property" do The code: describe "when the instance's do not have an ensure property" do it "should not be included in the generated resources" do @no_ensure_resource = Puppet::Type.type(:exec).new(:name => '/usr/bin/env echo') Puppet::Type.type(:host).stubs(:instances).returns [@no_ensure_resource] @resources.generate.collect { |r| r.ref }.should_not include(@no_ensure_resource.ref) end end describe "when the instance's ensure property does not accept absent" do it "should not be included in the generated resources" do @no_absent_resource = Puppet::Type.type(:service).new(:name => 'foobar') becomes: describe "when the instance's do not have an ensure property" do it "should not be included in the generated resources" do @no_ensure_resource = Puppet::Type.type(:exec).new(:name => '/usr/bin/env echo') Puppet::Type.type(:host).stubs(:instances).returns [@no_ensure_resource] @resources.generate.collect { |r| r.ref }.should_not include(@no_ensure_resource.ref) end end describe "when the instance's ensure property does not accept absent" do it "should not be included in the generated resources" do @no_absent_resource = Puppet::Type.type(:service).new(:name => 'foobar') The code: func = nil assert_nothing_raised do func = Puppet::Parser::AST::Function.new( :name => "template", :ftype => :rvalue, :arguments => AST::ASTArray.new( :children => [stringobj(template)] ) becomes: func = nil assert_nothing_raised do func = Puppet::Parser::AST::Function.new( :name => "template", :ftype => :rvalue, :arguments => AST::ASTArray.new( :children => [stringobj(template)] ) The code: assert( @store.allowed?("hostname.madstop.com", "192.168.1.50"), "hostname not allowed") assert( ! @store.allowed?("name.sub.madstop.com", "192.168.0.50"), "subname name allowed") becomes: assert( @store.allowed?("hostname.madstop.com", "192.168.1.50"), "hostname not allowed") assert( ! @store.allowed?("name.sub.madstop.com", "192.168.0.50"), "subname name allowed") The code: assert_nothing_raised { server = Puppet::Network::Handler.fileserver.new( :Local => true, :Config => false ) } becomes: assert_nothing_raised { server = Puppet::Network::Handler.fileserver.new( :Local => true, :Config => false ) } The code: 'yay', { :failonfail => false, :uid => @user.uid, :gid => @user.gid } ).returns('output') output = Puppet::Util::SUIDManager.run_and_capture 'yay', @user.uid, @user.gid becomes: 'yay', { :failonfail => false, :uid => @user.uid, :gid => @user.gid } ).returns('output') output = Puppet::Util::SUIDManager.run_and_capture 'yay', @user.uid, @user.gid The code: ).times(1) pkg.provider.expects( :aptget ).with( '-y', '-q', 'remove', 'faff' becomes: ).times(1) pkg.provider.expects( :aptget ).with( '-y', '-q', 'remove', 'faff' The code: johnny one two billy three four\n" # Just parse and generate, to make sure it's isomorphic. assert_nothing_raised do assert_equal(text, @parser.to_file(@parser.parse(text)), "parsing was not isomorphic") end end def test_valid_attrs becomes: johnny one two billy three four\n" # Just parse and generate, to make sure it's isomorphic. assert_nothing_raised do assert_equal(text, @parser.to_file(@parser.parse(text)), "parsing was not isomorphic") end end def test_valid_attrs The code: "testing", :onboolean => [true, "An on bool"], :string => ["a string", "A string arg"] ) result = [] should = [] assert_nothing_raised("Add args failed") do @config.addargs(result) end @config.each do |name, element| becomes: "testing", :onboolean => [true, "An on bool"], :string => ["a string", "A string arg"] ) result = [] should = [] assert_nothing_raised("Add args failed") do @config.addargs(result) end @config.each do |name, element|
Diffstat (limited to 'lib/puppet/external/pson')
-rw-r--r--lib/puppet/external/pson/common.rb675
-rw-r--r--lib/puppet/external/pson/pure.rb124
-rw-r--r--lib/puppet/external/pson/pure/generator.rb840
-rw-r--r--lib/puppet/external/pson/pure/parser.rb501
-rw-r--r--lib/puppet/external/pson/version.rb12
5 files changed, 1079 insertions, 1073 deletions
diff --git a/lib/puppet/external/pson/common.rb b/lib/puppet/external/pson/common.rb
index 87bce988b..17da5ad11 100644
--- a/lib/puppet/external/pson/common.rb
+++ b/lib/puppet/external/pson/common.rb
@@ -1,367 +1,370 @@
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
+ 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
+ # 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
+ # 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 for unregistered document type #{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
- def registered_document_types
- @registered_document_types ||= {}
+ # 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
- # Register a class-constant for deserializaion.
- def register_document_type(name,klass)
- registered_document_types[name.to_s] = klass
+ # 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
- # 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 for unregistered document type #{path}"
- end
- 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
- # 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
+ # 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
- end
- self.state = generator::State
- const_set :State, self.state
+ obj.to_pson(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)
+ # :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
- 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
+
+ # :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
- 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
+
+ # :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
- 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
+
+ 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
- limit ||= 0
- result = generate(obj, :allow_nan => true, :max_nesting => limit)
- if anIO
- anIO.write result
- anIO
- else
- result
+ 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
- rescue PSON::NestingError
- raise ArgumentError, "exceed depth limit"
- end
end
module ::Kernel
- private
+ 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)
+ # 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
- 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)
+
+ # 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
- 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)
+
+ # 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
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
+ # 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
index 53d1ea2a7..dffd06d92 100644
--- a/lib/puppet/external/pson/pure.rb
+++ b/lib/puppet/external/pson/pure.rb
@@ -3,75 +3,75 @@ 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
- # We actually don't care
- Puppet.warning "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
+ 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
+ # We actually don't care
+ Puppet.warning "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:
+ 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
+ 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
+ Puppet.warning "iconv doesn't seem to support UTF-8/UTF-16 conversions"
+ ensure
+ $VERBOSE = old_verbose
end
- UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc:
- end
- rescue Errno::EINVAL, Iconv::InvalidEncoding
- Puppet.warning "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]
+ # 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
- 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
+ # 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
+ PSON_LOADED = true
end
diff --git a/lib/puppet/external/pson/pure/generator.rb b/lib/puppet/external/pson/pure/generator.rb
index b2a7ddeb5..44aa526c7 100644
--- a/lib/puppet/external/pson/pure/generator.rb
+++ b/lib/puppet/external/pson/pure/generator.rb
@@ -1,429 +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
+ 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
-
- 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
+ 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
-
- 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
+ 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
- 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*')
+ 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
-
- # 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
index 56c27f762..ef14d4009 100644
--- a/lib/puppet/external/pson/pure/parser.rb
+++ b/lib/puppet/external/pson/pure/parser.rb
@@ -1,269 +1,272 @@
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
+ 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
+ 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
+ # 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
+ 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
+ # 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
+ 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,
- })
+ # Unescape characters in strings.
+ UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
- 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
+ UNESCAPE_MAP.update(
+ {
+ ?" => '"',
+ ?\\ => '\\',
+ ?/ => '/',
+ ?b => "\b",
+ ?f => "\f",
+ ?n => "\n",
+ ?r => "\r",
+ ?t => "\t",
+ ?u => nil,
- 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)}'!"
+ 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
- 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)}'!"
+ 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
- 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)}'!"
+
+ 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
- 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)
+
+ 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
- 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
index a5a8e4702..0bcfa4ad8 100644
--- a/lib/puppet/external/pson/version.rb
+++ b/lib/puppet/external/pson/version.rb
@@ -1,8 +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:
+ # 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