psych 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +6 -0
- data/CHANGELOG.rdoc +126 -0
- data/Manifest.txt +3 -2
- data/README.rdoc +1 -1
- data/Rakefile +1 -1
- data/ext/psych/emitter.c +1 -1
- data/ext/psych/parser.c +241 -62
- data/lib/psych.rb +86 -21
- data/lib/psych/core_ext.rb +2 -0
- data/lib/psych/handlers/document_stream.rb +22 -0
- data/lib/psych/parser.rb +4 -0
- data/lib/psych/scalar_scanner.rb +15 -5
- data/lib/psych/syntax_error.rb +19 -0
- data/lib/psych/tree_builder.rb +3 -1
- data/lib/psych/visitors/to_ruby.rb +51 -15
- data/lib/psych/visitors/yaml_tree.rb +58 -11
- data/test/psych/test_array.rb +28 -0
- data/test/psych/test_encoding.rb +73 -0
- data/test/psych/test_exception.rb +91 -0
- data/test/psych/test_numeric.rb +11 -0
- data/test/psych/test_object_references.rb +67 -0
- data/test/psych/test_parser.rb +44 -9
- data/test/psych/test_scalar_scanner.rb +22 -0
- data/test/psych/test_stream.rb +44 -0
- data/test/psych/test_string.rb +31 -0
- data/test/psych/test_struct.rb +1 -3
- data/test/psych/test_tainted.rb +3 -1
- data/test/psych/test_yamldbm.rb +16 -9
- data/test/psych/test_yamlstore.rb +6 -6
- metadata +57 -68
- data/Gemfile +0 -11
- data/lib/psych/json.rb +0 -6
    
        data/lib/psych.rb
    CHANGED
    
    | @@ -10,7 +10,10 @@ require 'psych/set' | |
| 10 10 | 
             
            require 'psych/coder'
         | 
| 11 11 | 
             
            require 'psych/core_ext'
         | 
| 12 12 | 
             
            require 'psych/deprecated'
         | 
| 13 | 
            -
            require 'psych/ | 
| 13 | 
            +
            require 'psych/stream'
         | 
| 14 | 
            +
            require 'psych/json/tree_builder'
         | 
| 15 | 
            +
            require 'psych/json/stream'
         | 
| 16 | 
            +
            require 'psych/handlers/document_stream'
         | 
| 14 17 |  | 
| 15 18 | 
             
            ###
         | 
| 16 19 | 
             
            # = Overview
         | 
| @@ -90,7 +93,7 @@ require 'psych/json' | |
| 90 93 |  | 
| 91 94 | 
             
            module Psych
         | 
| 92 95 | 
             
              # The version is Psych you're using
         | 
| 93 | 
            -
              VERSION         = '1. | 
| 96 | 
            +
              VERSION         = '1.3.0'
         | 
| 94 97 |  | 
| 95 98 | 
             
              # The version of libyaml Psych is using
         | 
| 96 99 | 
             
              LIBYAML_VERSION = Psych.libyaml_version.join '.'
         | 
| @@ -101,39 +104,63 @@ module Psych | |
| 101 104 | 
             
              class BadAlias < Exception
         | 
| 102 105 | 
             
              end
         | 
| 103 106 |  | 
| 104 | 
            -
              autoload :Stream, 'psych/stream'
         | 
| 105 | 
            -
             | 
| 106 107 | 
             
              ###
         | 
| 107 108 | 
             
              # Load +yaml+ in to a Ruby data structure.  If multiple documents are
         | 
| 108 109 | 
             
              # provided, the object contained in the first document will be returned.
         | 
| 110 | 
            +
              # +filename+ will be used in the exception message if any exception is raised
         | 
| 111 | 
            +
              # while parsing.
         | 
| 112 | 
            +
              #
         | 
| 113 | 
            +
              # Raises a Psych::SyntaxError when a YAML syntax error is detected.
         | 
| 109 114 | 
             
              #
         | 
| 110 115 | 
             
              # Example:
         | 
| 111 116 | 
             
              #
         | 
| 112 | 
            -
              #   Psych.load("--- a") | 
| 113 | 
            -
              #   Psych.load("---\n - a\n - b") | 
| 114 | 
            -
               | 
| 115 | 
            -
             | 
| 117 | 
            +
              #   Psych.load("--- a")             # => 'a'
         | 
| 118 | 
            +
              #   Psych.load("---\n - a\n - b")   # => ['a', 'b']
         | 
| 119 | 
            +
              #
         | 
| 120 | 
            +
              #   begin
         | 
| 121 | 
            +
              #     Psych.load("--- `", "file.txt")
         | 
| 122 | 
            +
              #   rescue Psych::SyntaxError => ex
         | 
| 123 | 
            +
              #     ex.file    # => 'file.txt'
         | 
| 124 | 
            +
              #     ex.message # => "(foo.txt): found character that cannot start any token"
         | 
| 125 | 
            +
              #   end
         | 
| 126 | 
            +
              def self.load yaml, filename = nil
         | 
| 127 | 
            +
                result = parse(yaml, filename)
         | 
| 116 128 | 
             
                result ? result.to_ruby : result
         | 
| 117 129 | 
             
              end
         | 
| 118 130 |  | 
| 119 131 | 
             
              ###
         | 
| 120 132 | 
             
              # Parse a YAML string in +yaml+.  Returns the first object of a YAML AST.
         | 
| 133 | 
            +
              # +filename+ is used in the exception message if a Psych::SyntaxError is
         | 
| 134 | 
            +
              # raised.
         | 
| 135 | 
            +
              #
         | 
| 136 | 
            +
              # Raises a Psych::SyntaxError when a YAML syntax error is detected.
         | 
| 121 137 | 
             
              #
         | 
| 122 138 | 
             
              # Example:
         | 
| 123 139 | 
             
              #
         | 
| 124 140 | 
             
              #   Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Sequence:0x00>
         | 
| 125 141 | 
             
              #
         | 
| 142 | 
            +
              #   begin
         | 
| 143 | 
            +
              #     Psych.parse("--- `", "file.txt")
         | 
| 144 | 
            +
              #   rescue Psych::SyntaxError => ex
         | 
| 145 | 
            +
              #     ex.file    # => 'file.txt'
         | 
| 146 | 
            +
              #     ex.message # => "(foo.txt): found character that cannot start any token"
         | 
| 147 | 
            +
              #   end
         | 
| 148 | 
            +
              #
         | 
| 126 149 | 
             
              # See Psych::Nodes for more information about YAML AST.
         | 
| 127 | 
            -
              def self.parse yaml
         | 
| 128 | 
            -
                 | 
| 129 | 
            -
             | 
| 150 | 
            +
              def self.parse yaml, filename = nil
         | 
| 151 | 
            +
                parse_stream(yaml, filename) do |node|
         | 
| 152 | 
            +
                  return node
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
                false
         | 
| 130 155 | 
             
              end
         | 
| 131 156 |  | 
| 132 157 | 
             
              ###
         | 
| 133 158 | 
             
              # Parse a file at +filename+. Returns the YAML AST.
         | 
| 159 | 
            +
              #
         | 
| 160 | 
            +
              # Raises a Psych::SyntaxError when a YAML syntax error is detected.
         | 
| 134 161 | 
             
              def self.parse_file filename
         | 
| 135 | 
            -
                File.open filename do |f|
         | 
| 136 | 
            -
                  parse f
         | 
| 162 | 
            +
                File.open filename, 'r:bom|utf-8' do |f|
         | 
| 163 | 
            +
                  parse f, filename
         | 
| 137 164 | 
             
                end
         | 
| 138 165 | 
             
              end
         | 
| 139 166 |  | 
| @@ -146,16 +173,39 @@ module Psych | |
| 146 173 | 
             
              ###
         | 
| 147 174 | 
             
              # Parse a YAML string in +yaml+.  Returns the full AST for the YAML document.
         | 
| 148 175 | 
             
              # This method can handle multiple YAML documents contained in +yaml+.
         | 
| 176 | 
            +
              # +filename+ is used in the exception message if a Psych::SyntaxError is
         | 
| 177 | 
            +
              # raised.
         | 
| 178 | 
            +
              #
         | 
| 179 | 
            +
              # If a block is given, a Psych::Nodes::Document node will be yielded to the
         | 
| 180 | 
            +
              # block as it's being parsed.
         | 
| 181 | 
            +
              #
         | 
| 182 | 
            +
              # Raises a Psych::SyntaxError when a YAML syntax error is detected.
         | 
| 149 183 | 
             
              #
         | 
| 150 184 | 
             
              # Example:
         | 
| 151 185 | 
             
              #
         | 
| 152 186 | 
             
              #   Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00>
         | 
| 153 187 | 
             
              #
         | 
| 188 | 
            +
              #   Psych.parse_stream("--- a\n--- b") do |node|
         | 
| 189 | 
            +
              #     node # => #<Psych::Nodes::Document:0x00>
         | 
| 190 | 
            +
              #   end
         | 
| 191 | 
            +
              #
         | 
| 192 | 
            +
              #   begin
         | 
| 193 | 
            +
              #     Psych.parse_stream("--- `", "file.txt")
         | 
| 194 | 
            +
              #   rescue Psych::SyntaxError => ex
         | 
| 195 | 
            +
              #     ex.file    # => 'file.txt'
         | 
| 196 | 
            +
              #     ex.message # => "(foo.txt): found character that cannot start any token"
         | 
| 197 | 
            +
              #   end
         | 
| 198 | 
            +
              #
         | 
| 154 199 | 
             
              # See Psych::Nodes for more information about YAML AST.
         | 
| 155 | 
            -
              def self.parse_stream yaml
         | 
| 156 | 
            -
                 | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 200 | 
            +
              def self.parse_stream yaml, filename = nil, &block
         | 
| 201 | 
            +
                if block_given?
         | 
| 202 | 
            +
                  parser = Psych::Parser.new(Handlers::DocumentStream.new(&block))
         | 
| 203 | 
            +
                  parser.parse yaml, filename
         | 
| 204 | 
            +
                else
         | 
| 205 | 
            +
                  parser = self.parser
         | 
| 206 | 
            +
                  parser.parse yaml, filename
         | 
| 207 | 
            +
                  parser.handler.root
         | 
| 208 | 
            +
                end
         | 
| 159 209 | 
             
              end
         | 
| 160 210 |  | 
| 161 211 | 
             
              ###
         | 
| @@ -217,19 +267,34 @@ module Psych | |
| 217 267 |  | 
| 218 268 | 
             
              ###
         | 
| 219 269 | 
             
              # Load multiple documents given in +yaml+.  Returns the parsed documents
         | 
| 220 | 
            -
              # as a list.   | 
| 270 | 
            +
              # as a list.  If a block is given, each document will be converted to ruby
         | 
| 271 | 
            +
              # and passed to the block during parsing
         | 
| 272 | 
            +
              #
         | 
| 273 | 
            +
              # Example:
         | 
| 221 274 | 
             
              #
         | 
| 222 275 | 
             
              #   Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']
         | 
| 223 276 | 
             
              #
         | 
| 224 | 
            -
               | 
| 225 | 
            -
             | 
| 277 | 
            +
              #   list = []
         | 
| 278 | 
            +
              #   Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby|
         | 
| 279 | 
            +
              #     list << ruby
         | 
| 280 | 
            +
              #   end
         | 
| 281 | 
            +
              #   list # => ['foo', 'bar']
         | 
| 282 | 
            +
              #
         | 
| 283 | 
            +
              def self.load_stream yaml, filename = nil
         | 
| 284 | 
            +
                if block_given?
         | 
| 285 | 
            +
                  parse_stream(yaml, filename) do |node|
         | 
| 286 | 
            +
                    yield node.to_ruby
         | 
| 287 | 
            +
                  end
         | 
| 288 | 
            +
                else
         | 
| 289 | 
            +
                  parse_stream(yaml, filename).children.map { |child| child.to_ruby }
         | 
| 290 | 
            +
                end
         | 
| 226 291 | 
             
              end
         | 
| 227 292 |  | 
| 228 293 | 
             
              ###
         | 
| 229 294 | 
             
              # Load the document contained in +filename+.  Returns the yaml contained in
         | 
| 230 295 | 
             
              # +filename+ as a ruby object
         | 
| 231 296 | 
             
              def self.load_file filename
         | 
| 232 | 
            -
                 | 
| 297 | 
            +
                File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename }
         | 
| 233 298 | 
             
              end
         | 
| 234 299 |  | 
| 235 300 | 
             
              # :stopdoc:
         | 
    
        data/lib/psych/core_ext.rb
    CHANGED
    
    
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            require 'psych/tree_builder'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Psych
         | 
| 4 | 
            +
              module Handlers
         | 
| 5 | 
            +
                class DocumentStream < Psych::TreeBuilder # :nodoc:
         | 
| 6 | 
            +
                  def initialize &block
         | 
| 7 | 
            +
                    super
         | 
| 8 | 
            +
                    @block = block
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def start_document version, tag_directives, implicit
         | 
| 12 | 
            +
                    n = Nodes::Document.new version, tag_directives, implicit
         | 
| 13 | 
            +
                    push n
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def end_document implicit_end = !streaming?
         | 
| 17 | 
            +
                    @last.implicit_end = implicit_end
         | 
| 18 | 
            +
                    @block.call pop
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
    
        data/lib/psych/parser.rb
    CHANGED
    
    | @@ -36,12 +36,16 @@ module Psych | |
| 36 36 | 
             
                # The handler on which events will be called
         | 
| 37 37 | 
             
                attr_accessor :handler
         | 
| 38 38 |  | 
| 39 | 
            +
                # Set the encoding for this parser to +encoding+
         | 
| 40 | 
            +
                attr_writer :external_encoding
         | 
| 41 | 
            +
             | 
| 39 42 | 
             
                ###
         | 
| 40 43 | 
             
                # Creates a new Psych::Parser instance with +handler+.  YAML events will
         | 
| 41 44 | 
             
                # be called on +handler+.  See Psych::Parser for more details.
         | 
| 42 45 |  | 
| 43 46 | 
             
                def initialize handler = Handler.new
         | 
| 44 47 | 
             
                  @handler = handler
         | 
| 48 | 
            +
                  @external_encoding = ANY
         | 
| 45 49 | 
             
                end
         | 
| 46 50 | 
             
              end
         | 
| 47 51 | 
             
            end
         | 
    
        data/lib/psych/scalar_scanner.rb
    CHANGED
    
    | @@ -46,9 +46,13 @@ module Psych | |
| 46 46 | 
             
                    end
         | 
| 47 47 | 
             
                  when TIME
         | 
| 48 48 | 
             
                    parse_time string
         | 
| 49 | 
            -
                  when /^\d{4} | 
| 49 | 
            +
                  when /^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/
         | 
| 50 50 | 
             
                    require 'date'
         | 
| 51 | 
            -
                     | 
| 51 | 
            +
                    begin
         | 
| 52 | 
            +
                      Date.strptime(string, '%Y-%m-%d')
         | 
| 53 | 
            +
                    rescue ArgumentError
         | 
| 54 | 
            +
                      string
         | 
| 55 | 
            +
                    end
         | 
| 52 56 | 
             
                  when /^\.inf$/i
         | 
| 53 57 | 
             
                    1 / 0.0
         | 
| 54 58 | 
             
                  when /^-\.inf$/i
         | 
| @@ -61,7 +65,7 @@ module Psych | |
| 61 65 | 
             
                    else
         | 
| 62 66 | 
             
                      string.sub(/^:/, '').to_sym
         | 
| 63 67 | 
             
                    end
         | 
| 64 | 
            -
                  when /^[-+]?[ | 
| 68 | 
            +
                  when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+$/
         | 
| 65 69 | 
             
                    i = 0
         | 
| 66 70 | 
             
                    string.split(':').each_with_index do |n,e|
         | 
| 67 71 | 
             
                      i += (n.to_i * 60 ** (e - 2).abs)
         | 
| @@ -74,13 +78,19 @@ module Psych | |
| 74 78 | 
             
                    end
         | 
| 75 79 | 
             
                    i
         | 
| 76 80 | 
             
                  when FLOAT
         | 
| 77 | 
            -
                     | 
| 81 | 
            +
                    begin
         | 
| 82 | 
            +
                      return Float(string.gsub(/[,_]/, ''))
         | 
| 83 | 
            +
                    rescue ArgumentError
         | 
| 84 | 
            +
                    end
         | 
| 78 85 |  | 
| 79 86 | 
             
                    @string_cache[string] = true
         | 
| 80 87 | 
             
                    string
         | 
| 81 88 | 
             
                  else
         | 
| 82 89 | 
             
                    if string.count('.') < 2
         | 
| 83 | 
            -
                       | 
| 90 | 
            +
                      begin
         | 
| 91 | 
            +
                        return Integer(string.gsub(/[,_]/, ''))
         | 
| 92 | 
            +
                      rescue ArgumentError
         | 
| 93 | 
            +
                      end
         | 
| 84 94 | 
             
                    end
         | 
| 85 95 |  | 
| 86 96 | 
             
                    @string_cache[string] = true
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module Psych
         | 
| 2 | 
            +
              class SyntaxError < ::SyntaxError
         | 
| 3 | 
            +
                attr_reader :file, :line, :column, :offset, :problem, :context
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize file, line, col, offset, problem, context
         | 
| 6 | 
            +
                  err      = [problem, context].compact.join ' '
         | 
| 7 | 
            +
                  filename = file || '<unknown>'
         | 
| 8 | 
            +
                  message  = "(%s): %s at line %d column %d" % [filename, err, line, col]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  @file    = file
         | 
| 11 | 
            +
                  @line    = line
         | 
| 12 | 
            +
                  @column  = col
         | 
| 13 | 
            +
                  @offset  = offset
         | 
| 14 | 
            +
                  @problem = problem
         | 
| 15 | 
            +
                  @context = context
         | 
| 16 | 
            +
                  super(message)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
    
        data/lib/psych/tree_builder.rb
    CHANGED
    
    | @@ -72,7 +72,9 @@ module Psych | |
| 72 72 | 
             
                end
         | 
| 73 73 |  | 
| 74 74 | 
             
                def scalar value, anchor, tag, plain, quoted, style
         | 
| 75 | 
            -
                   | 
| 75 | 
            +
                  s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style)
         | 
| 76 | 
            +
                  @last.children << s
         | 
| 77 | 
            +
                  s
         | 
| 76 78 | 
             
                end
         | 
| 77 79 |  | 
| 78 80 | 
             
                def alias anchor
         | 
| @@ -31,9 +31,7 @@ module Psych | |
| 31 31 | 
             
                    result
         | 
| 32 32 | 
             
                  end
         | 
| 33 33 |  | 
| 34 | 
            -
                  def  | 
| 35 | 
            -
                    @st[o.anchor] = o.value if o.anchor
         | 
| 36 | 
            -
             | 
| 34 | 
            +
                  def deserialize o
         | 
| 37 35 | 
             
                    if klass = Psych.load_tags[o.tag]
         | 
| 38 36 | 
             
                      instance = klass.allocate
         | 
| 39 37 |  | 
| @@ -52,8 +50,16 @@ module Psych | |
| 52 50 | 
             
                    case o.tag
         | 
| 53 51 | 
             
                    when '!binary', 'tag:yaml.org,2002:binary'
         | 
| 54 52 | 
             
                      o.value.unpack('m').first
         | 
| 55 | 
            -
                    when  | 
| 56 | 
            -
                       | 
| 53 | 
            +
                    when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str'
         | 
| 54 | 
            +
                      klass = resolve_class($1)
         | 
| 55 | 
            +
                      if klass
         | 
| 56 | 
            +
                        klass.allocate.replace o.value
         | 
| 57 | 
            +
                      else
         | 
| 58 | 
            +
                        o.value
         | 
| 59 | 
            +
                      end
         | 
| 60 | 
            +
                    when '!ruby/object:BigDecimal'
         | 
| 61 | 
            +
                      require 'bigdecimal'
         | 
| 62 | 
            +
                      BigDecimal._load o.value
         | 
| 57 63 | 
             
                    when "!ruby/object:DateTime"
         | 
| 58 64 | 
             
                      require 'date'
         | 
| 59 65 | 
             
                      @ss.parse_time(o.value).to_datetime
         | 
| @@ -92,6 +98,11 @@ module Psych | |
| 92 98 | 
             
                      @ss.tokenize o.value
         | 
| 93 99 | 
             
                    end
         | 
| 94 100 | 
             
                  end
         | 
| 101 | 
            +
                  private :deserialize
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  def visit_Psych_Nodes_Scalar o
         | 
| 104 | 
            +
                    register o, deserialize(o)
         | 
| 105 | 
            +
                  end
         | 
| 95 106 |  | 
| 96 107 | 
             
                  def visit_Psych_Nodes_Sequence o
         | 
| 97 108 | 
             
                    if klass = Psych.load_tags[o.tag]
         | 
| @@ -108,15 +119,18 @@ module Psych | |
| 108 119 |  | 
| 109 120 | 
             
                    case o.tag
         | 
| 110 121 | 
             
                    when '!omap', 'tag:yaml.org,2002:omap'
         | 
| 111 | 
            -
                      map = Psych::Omap.new
         | 
| 112 | 
            -
                      @st[o.anchor] = map if o.anchor
         | 
| 122 | 
            +
                      map = register(o, Psych::Omap.new)
         | 
| 113 123 | 
             
                      o.children.each { |a|
         | 
| 114 124 | 
             
                        map[accept(a.children.first)] = accept a.children.last
         | 
| 115 125 | 
             
                      }
         | 
| 116 126 | 
             
                      map
         | 
| 127 | 
            +
                    when /^!(?:seq|ruby\/array):(.*)$/
         | 
| 128 | 
            +
                      klass = resolve_class($1)
         | 
| 129 | 
            +
                      list  = register(o, klass.allocate)
         | 
| 130 | 
            +
                      o.children.each { |c| list.push accept c }
         | 
| 131 | 
            +
                      list
         | 
| 117 132 | 
             
                    else
         | 
| 118 | 
            -
                      list = []
         | 
| 119 | 
            -
                      @st[o.anchor] = list if o.anchor
         | 
| 133 | 
            +
                      list = register(o, [])
         | 
| 120 134 | 
             
                      o.children.each { |c| list.push accept c }
         | 
| 121 135 | 
             
                      list
         | 
| 122 136 | 
             
                    end
         | 
| @@ -127,16 +141,33 @@ module Psych | |
| 127 141 | 
             
                    return revive_hash({}, o) unless o.tag
         | 
| 128 142 |  | 
| 129 143 | 
             
                    case o.tag
         | 
| 130 | 
            -
                    when  | 
| 144 | 
            +
                    when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str'
         | 
| 145 | 
            +
                      klass = resolve_class($1)
         | 
| 131 146 | 
             
                      members = Hash[*o.children.map { |c| accept c }]
         | 
| 132 147 | 
             
                      string = members.delete 'str'
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                      if klass
         | 
| 150 | 
            +
                        string = klass.allocate
         | 
| 151 | 
            +
                        string.replace string
         | 
| 152 | 
            +
                      end
         | 
| 153 | 
            +
             | 
| 133 154 | 
             
                      init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o)
         | 
| 155 | 
            +
                    when /^!ruby\/array:(.*)$/
         | 
| 156 | 
            +
                      klass = resolve_class($1)
         | 
| 157 | 
            +
                      list  = register(o, klass.allocate)
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                      members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a]
         | 
| 160 | 
            +
                      list.replace members['internal']
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                      members['ivars'].each do |ivar, v|
         | 
| 163 | 
            +
                        list.instance_variable_set ivar, v
         | 
| 164 | 
            +
                      end
         | 
| 165 | 
            +
                      list
         | 
| 134 166 | 
             
                    when /^!ruby\/struct:?(.*)?$/
         | 
| 135 167 | 
             
                      klass = resolve_class($1)
         | 
| 136 168 |  | 
| 137 169 | 
             
                      if klass
         | 
| 138 | 
            -
                        s = klass.allocate
         | 
| 139 | 
            -
                        @st[o.anchor] = s if o.anchor
         | 
| 170 | 
            +
                        s = register(o, klass.allocate)
         | 
| 140 171 |  | 
| 141 172 | 
             
                        members = {}
         | 
| 142 173 | 
             
                        struct_members = s.members.map { |x| x.to_sym }
         | 
| @@ -158,7 +189,7 @@ module Psych | |
| 158 189 |  | 
| 159 190 | 
             
                    when '!ruby/range'
         | 
| 160 191 | 
             
                      h = Hash[*o.children.map { |c| accept c }]
         | 
| 161 | 
            -
                      Range.new(h['begin'], h['end'], h['excl'])
         | 
| 192 | 
            +
                      register o, Range.new(h['begin'], h['end'], h['excl'])
         | 
| 162 193 |  | 
| 163 194 | 
             
                    when /^!ruby\/exception:?(.*)?$/
         | 
| 164 195 | 
             
                      h = Hash[*o.children.map { |c| accept c }]
         | 
| @@ -177,11 +208,11 @@ module Psych | |
| 177 208 |  | 
| 178 209 | 
             
                    when '!ruby/object:Complex'
         | 
| 179 210 | 
             
                      h = Hash[*o.children.map { |c| accept c }]
         | 
| 180 | 
            -
                      Complex(h['real'], h['image'])
         | 
| 211 | 
            +
                      register o, Complex(h['real'], h['image'])
         | 
| 181 212 |  | 
| 182 213 | 
             
                    when '!ruby/object:Rational'
         | 
| 183 214 | 
             
                      h = Hash[*o.children.map { |c| accept c }]
         | 
| 184 | 
            -
                      Rational(h['numerator'], h['denominator'])
         | 
| 215 | 
            +
                      register o, Rational(h['numerator'], h['denominator'])
         | 
| 185 216 |  | 
| 186 217 | 
             
                    when /^!ruby\/object:?(.*)?$/
         | 
| 187 218 | 
             
                      name = $1 || 'Object'
         | 
| @@ -209,6 +240,11 @@ module Psych | |
| 209 240 | 
             
                  end
         | 
| 210 241 |  | 
| 211 242 | 
             
                  private
         | 
| 243 | 
            +
                  def register node, object
         | 
| 244 | 
            +
                    @st[node.anchor] = object if node.anchor
         | 
| 245 | 
            +
                    object
         | 
| 246 | 
            +
                  end
         | 
| 247 | 
            +
             | 
| 212 248 | 
             
                  def revive_hash hash, o
         | 
| 213 249 | 
             
                    @st[o.anchor] = hash if o.anchor
         | 
| 214 250 |  | 
| @@ -159,13 +159,13 @@ module Psych | |
| 159 159 | 
             
                  end
         | 
| 160 160 |  | 
| 161 161 | 
             
                  def visit_Regexp o
         | 
| 162 | 
            -
                    @emitter.scalar | 
| 162 | 
            +
                    register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
         | 
| 163 163 | 
             
                  end
         | 
| 164 164 |  | 
| 165 165 | 
             
                  def visit_DateTime o
         | 
| 166 166 | 
             
                    formatted = format_time o.to_time
         | 
| 167 167 | 
             
                    tag = '!ruby/object:DateTime'
         | 
| 168 | 
            -
                    @emitter.scalar | 
| 168 | 
            +
                    register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY)
         | 
| 169 169 | 
             
                  end
         | 
| 170 170 |  | 
| 171 171 | 
             
                  def visit_Time o
         | 
| @@ -174,7 +174,7 @@ module Psych | |
| 174 174 | 
             
                  end
         | 
| 175 175 |  | 
| 176 176 | 
             
                  def visit_Rational o
         | 
| 177 | 
            -
                    @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK)
         | 
| 177 | 
            +
                    register o, @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK)
         | 
| 178 178 |  | 
| 179 179 | 
             
                    [
         | 
| 180 180 | 
             
                      'denominator', o.denominator.to_s,
         | 
| @@ -187,7 +187,7 @@ module Psych | |
| 187 187 | 
             
                  end
         | 
| 188 188 |  | 
| 189 189 | 
             
                  def visit_Complex o
         | 
| 190 | 
            -
                    @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK)
         | 
| 190 | 
            +
                    register o, @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK)
         | 
| 191 191 |  | 
| 192 192 | 
             
                    ['real', o.real.to_s, 'image', o.imag.to_s].each do |m|
         | 
| 193 193 | 
             
                      @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
         | 
| @@ -214,6 +214,10 @@ module Psych | |
| 214 214 | 
             
                    end
         | 
| 215 215 | 
             
                  end
         | 
| 216 216 |  | 
| 217 | 
            +
                  def visit_BigDecimal o
         | 
| 218 | 
            +
                    @emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY
         | 
| 219 | 
            +
                  end
         | 
| 220 | 
            +
             | 
| 217 221 | 
             
                  def binary? string
         | 
| 218 222 | 
             
                    string.encoding == Encoding::ASCII_8BIT ||
         | 
| 219 223 | 
             
                      string.index("\x00") ||
         | 
| @@ -241,9 +245,15 @@ module Psych | |
| 241 245 | 
             
                    ivars = find_ivars o
         | 
| 242 246 |  | 
| 243 247 | 
             
                    if ivars.empty?
         | 
| 248 | 
            +
                      unless o.class == ::String
         | 
| 249 | 
            +
                        tag = "!ruby/string:#{o.class}"
         | 
| 250 | 
            +
                      end
         | 
| 244 251 | 
             
                      @emitter.scalar str, nil, tag, plain, quote, style
         | 
| 245 252 | 
             
                    else
         | 
| 246 | 
            -
                       | 
| 253 | 
            +
                      maptag = '!ruby/string'
         | 
| 254 | 
            +
                      maptag << ":#{o.class}" unless o.class == ::String
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                      @emitter.start_mapping nil, maptag, false, Nodes::Mapping::BLOCK
         | 
| 247 257 | 
             
                      @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY
         | 
| 248 258 | 
             
                      @emitter.scalar str, nil, tag, plain, quote, style
         | 
| 249 259 |  | 
| @@ -255,16 +265,16 @@ module Psych | |
| 255 265 |  | 
| 256 266 | 
             
                  def visit_Module o
         | 
| 257 267 | 
             
                    raise TypeError, "can't dump anonymous module: #{o}" unless o.name
         | 
| 258 | 
            -
                    @emitter.scalar | 
| 268 | 
            +
                    register o, @emitter.scalar(o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED)
         | 
| 259 269 | 
             
                  end
         | 
| 260 270 |  | 
| 261 271 | 
             
                  def visit_Class o
         | 
| 262 272 | 
             
                    raise TypeError, "can't dump anonymous class: #{o}" unless o.name
         | 
| 263 | 
            -
                    @emitter.scalar | 
| 273 | 
            +
                    register o, @emitter.scalar(o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED)
         | 
| 264 274 | 
             
                  end
         | 
| 265 275 |  | 
| 266 276 | 
             
                  def visit_Range o
         | 
| 267 | 
            -
                    @emitter.start_mapping | 
| 277 | 
            +
                    register o, @emitter.start_mapping(nil, '!ruby/range', false, Nodes::Mapping::BLOCK)
         | 
| 268 278 | 
             
                    ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m|
         | 
| 269 279 | 
             
                      accept m
         | 
| 270 280 | 
             
                    end
         | 
| @@ -297,9 +307,13 @@ module Psych | |
| 297 307 | 
             
                  end
         | 
| 298 308 |  | 
| 299 309 | 
             
                  def visit_Array o
         | 
| 300 | 
            -
                     | 
| 301 | 
            -
             | 
| 302 | 
            -
             | 
| 310 | 
            +
                    if o.class == ::Array
         | 
| 311 | 
            +
                      register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
         | 
| 312 | 
            +
                      o.each { |c| accept c }
         | 
| 313 | 
            +
                      @emitter.end_sequence
         | 
| 314 | 
            +
                    else
         | 
| 315 | 
            +
                      visit_array_subclass o
         | 
| 316 | 
            +
                    end
         | 
| 303 317 | 
             
                  end
         | 
| 304 318 |  | 
| 305 319 | 
             
                  def visit_NilClass o
         | 
| @@ -311,6 +325,39 @@ module Psych | |
| 311 325 | 
             
                  end
         | 
| 312 326 |  | 
| 313 327 | 
             
                  private
         | 
| 328 | 
            +
                  def visit_array_subclass o
         | 
| 329 | 
            +
                    tag = "!ruby/array:#{o.class}"
         | 
| 330 | 
            +
                    if o.instance_variables.empty?
         | 
| 331 | 
            +
                      node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK)
         | 
| 332 | 
            +
                      register o, node
         | 
| 333 | 
            +
                      o.each { |c| accept c }
         | 
| 334 | 
            +
                      @emitter.end_sequence
         | 
| 335 | 
            +
                    else
         | 
| 336 | 
            +
                      node = @emitter.start_mapping(nil, tag, false, Nodes::Sequence::BLOCK)
         | 
| 337 | 
            +
                      register o, node
         | 
| 338 | 
            +
             | 
| 339 | 
            +
                      # Dump the internal list
         | 
| 340 | 
            +
                      accept 'internal'
         | 
| 341 | 
            +
                      @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
         | 
| 342 | 
            +
                      o.each { |c| accept c }
         | 
| 343 | 
            +
                      @emitter.end_sequence
         | 
| 344 | 
            +
             | 
| 345 | 
            +
                      # Dump the ivars
         | 
| 346 | 
            +
                      accept 'ivars'
         | 
| 347 | 
            +
                      @emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK)
         | 
| 348 | 
            +
                      o.instance_variables.each do |ivar|
         | 
| 349 | 
            +
                        accept ivar
         | 
| 350 | 
            +
                        accept o.instance_variable_get ivar
         | 
| 351 | 
            +
                      end
         | 
| 352 | 
            +
                      @emitter.end_mapping
         | 
| 353 | 
            +
             | 
| 354 | 
            +
                      @emitter.end_mapping
         | 
| 355 | 
            +
                    end
         | 
| 356 | 
            +
                  end
         | 
| 357 | 
            +
             | 
| 358 | 
            +
                  def dump_list o
         | 
| 359 | 
            +
                  end
         | 
| 360 | 
            +
             | 
| 314 361 | 
             
                  # '%:z' was no defined until 1.9.3
         | 
| 315 362 | 
             
                  if RUBY_VERSION < '1.9.3'
         | 
| 316 363 | 
             
                    def format_time time
         |