psych_backport.patch

Aaron Patterson, 03/28/2012 07:56 AM

Download (52.6 KB)

View differences:

ChangeLog
1
Mon Jul 18 13:36:47 2011  Aaron Patterson <aaron@tenderlovemaking.com>
2

  
3
	* ext/psych/lib/psych.rb: define a new BadAlias error class.
4

  
5
	* ext/psych/lib/psych/visitors/to_ruby.rb: raise an exception when
6
	  deserializing an alias that does not exist.
7

  
8
	* test/psych/test_merge_keys.rb: corresponding test.
9

  
10
Fri Mar  9 06:29:22 2012  Aaron Patterson <aaron@tenderlovemaking.com>
11

  
12
	* ext/psych/lib/psych.rb (load, parse): stop parsing or loading after
13
	  the first document has been parsed.
14

  
15
	* test/psych/test_stream.rb: pertinent tests.
16

  
17
Fri Mar  9 06:17:05 2012  Aaron Patterson <aaron@tenderlovemaking.com>
18

  
19
	* ext/psych/lib/psych.rb (parse_stream, load_stream): if a block is
20
	  given, documents will be yielded to the block as they are parsed.
21
	  [ruby-core:42404] [Bug #5978]
22

  
23
	* ext/psych/lib/psych/handlers/document_stream.rb: add a handler that
24
	  yields documents as they are parsed
25

  
26
	* test/psych/test_stream.rb: corresponding tests.
27

  
28
Tue Mar  6 02:31:20 2012  Aaron Patterson <aaron@tenderlovemaking.com>
29

  
30
	* ext/psych/lib/psych/core_ext.rb: only extend Kernel if IRB is loaded
31
	  in order to stop method pollution.
32

  
33
Tue Feb 28 10:28:51 2012  Aaron Patterson <aaron@tenderlovemaking.com>
34

  
35
	* ext/psych/lib/psych.rb: default open YAML files with utf8 external
36
	  encoding. [ruby-core:42967]
37
	* test/psych/test_tainted.rb: ditto
38

  
39
Fri Feb 24 13:54:33 2012  Aaron Patterson <aaron@tenderlovemaking.com>
40

  
41
	* ext/psych/parser.c: prevent a memory leak by protecting calls to
42
	  handler callbacks.
43
	* test/psych/test_parser.rb: test to demonstrate leak.
44

  
45
Fri Feb 24 08:08:38 2012  Aaron Patterson <aaron@tenderlovemaking.com>
46

  
47
	* ext/psych/parser.c: set parser encoding based on the YAML input
48
	  rather than user configuration.
49
	* test/psych/test_encoding.rb: corresponding tests.
50
	* test/psych/test_parser.rb: ditto
51
	* test/psych/test_tainted.rb: ditto
52

  
53
Fri Feb 10 03:41:31 2012  Aaron Patterson <aaron@tenderlovemaking.com>
54

  
55
	* ext/psych/parser.c: removed external encoding setter, allow parser
56
	  to be reused.
57
	* ext/psych/lib/psych/parser.rb: added external encoding setter.
58
	* test/psych/test_parser.rb: test parser reuse
59

  
60
Wed Jan 18 12:49:15 2012  Aaron Patterson <aaron@tenderlovemaking.com>
61

  
62
	* ext/psych/lib/psych/visitors/to_ruby.rb: Added support for loading
63
	  subclasses of String with ivars
64
	* ext/psych/lib/psych/visitors/yaml_tree.rb: Added support for dumping
65
	  subclasses of String with ivars
66
	* test/psych/test_string.rb: corresponding tests
67

  
68
Wed Jan 18 10:39:47 2012  Aaron Patterson <aaron@tenderlovemaking.com>
69

  
70
	* ext/psych/lib/psych/visitors/to_ruby.rb: Added ability to load array
71
	  subclasses with ivars.
72
	* ext/psych/lib/psych/visitors/yaml_tree.rb: Added ability to dump
73
	  array subclasses with ivars.
74
	* test/psych/test_array.rb: corresponding tests
75

  
76
Wed Dec 21 02:25:36 2011  Aaron Patterson <aaron@tenderlovemaking.com>
77

  
78
	* ext/psych/emitter.c: fixing clang warnings. Thanks Joey!
79

  
80
Sun Dec 18 12:42:48 2011  Aaron Patterson <aaron@tenderlovemaking.com>
81

  
82
	* ext/psych/lib/psych/visitors/to_ruby.rb: BigDecimals can be restored
83
	  from YAML.
84
	* ext/psych/lib/psych/visitors/yaml_tree.rb: BigDecimals can be dumped
85
	  to YAML.
86
	* test/psych/test_numeric.rb: tests for BigDecimal serialization
87

  
88
Sun Dec 18 12:03:13 2011  Aaron Patterson <aaron@tenderlovemaking.com>
89

  
90
	* ext/psych/lib/psych/scalar_scanner.rb: Strings that look like dates
91
	  should be treated as strings and not dates.
92

  
93
	* test/psych/test_scalar_scanner.rb: corresponding tests.
94

  
95
Wed Dec  7 08:04:31 2011  Aaron Patterson <aaron@tenderlovemaking.com>
96

  
97
	* ext/psych/lib/psych.rb (module Psych): parse and load methods take
98
	  an optional file name that is used when raising Psych::SyntaxError
99
	  exceptions
100
	* ext/psych/lib/psych/syntax_error.rb (module Psych): allow nil file
101
	  names and handle nil file names in the exception message
102
	* test/psych/test_exception.rb (module Psych): Tests for changes.
103

  
104
Wed Nov 30 09:09:37 2011  Aaron Patterson <aaron@tenderlovemaking.com>
105

  
106
	* ext/psych/parser.c (parse): parse method can take an option file
107
	  name for use in exception messages.
108
	* test/psych/test_parser.rb: corresponding tests.
109

  
110
Tue Nov 22 04:46:22 2011  Aaron Patterson <aaron@tenderlovemaking.com>
111

  
112
	* ext/psych/lib/psych.rb: remove autoload from psych
113
	* ext/psych/lib/psych/json.rb: ditto
114

  
115
Wed Nov  9 04:52:16 2011  Aaron Patterson <aaron@tenderlovemaking.com>
116

  
117
	* ext/psych/lib/psych/tree_builder.rb: dump complex numbers,
118
	  rationals, etc with reference ids.
119
	* ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
120
	* ext/psych/lib/psych/visitors/to_ruby.rb: loading complex numbers,
121
	  rationals, etc with reference ids.
122
	* test/psych/test_object_references.rb: corresponding tests
123

  
124
Mon Nov  7 20:31:52 2011  Aaron Patterson <aaron@tenderlovemaking.com>
125

  
126
	* ext/psych/lib/psych/scalar_scanner.rb: make sure strings that look
127
	  like base 60 numbers are serialized as quoted strings.
128
	* test/psych/test_string.rb: test for change.
129

  
130
Thu Oct 27 08:47:38 2011  Martin Bosslet  <Martin.Bosslet@googlemail.com>
131

  
132
	* ext/psych/parser.c: remove unused variable.
133

  
134
Wed Oct  5 02:50:27 2011  Aaron Patterson <aaron@tenderlovemaking.com>
135

  
136
	* ext/psych/lib/psych/syntax_error.rb: Add file, line, offset, and
137
	  message attributes during parse failure.
138
	* ext/psych/parser.c: Update parser to raise exception with correct
139
	  values.
140
	* test/psych/test_exception.rb: corresponding tests.
141

  
142
Wed Oct  5 01:52:16 2011  Aaron Patterson <aaron@tenderlovemaking.com>
143

  
144
	* ext/psych/parser.c (parse): Use context_mark for indicating error
145
	  line and column.
146

  
147
Wed Oct  5 01:22:08 2011  Aaron Patterson <aaron@tenderlovemaking.com>
148

  
149
	* ext/psych/lib/psych/scalar_scanner.rb: use normal begin / rescue
150
	  since postfix rescue cannot receive the exception class. Thanks
151
	  nagachika!
152

  
1 153
Tue Mar 27 22:22:50 2012  Nobuyoshi Nakada  <nobu@ruby-lang.org>
2 154

  
3 155
	* configure.in (RUBY_STACK_GROW_DIRECTION): substitute CPU name as
ext/psych/emitter.c
351 351
	    (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)),
352 352
	    (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)),
353 353
	    implicit ? 1 : 0,
354
	    (yaml_sequence_style_t)NUM2INT(style)
354
	    (yaml_mapping_style_t)NUM2INT(style)
355 355
	    );
356 356

  
357 357
    emit(emitter, &event);
ext/psych/lib/psych.rb
10 10
require 'psych/coder'
11 11
require 'psych/core_ext'
12 12
require 'psych/deprecated'
13
require 'psych/json'
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
......
98 101
  class Exception < RuntimeError
99 102
  end
100 103

  
101
  autoload :Stream, 'psych/stream'
104
  class BadAlias < Exception
105
  end
102 106

  
103 107
  ###
104 108
  # Load +yaml+ in to a Ruby data structure.  If multiple documents are
105 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.
106 114
  #
107 115
  # Example:
108 116
  #
109
  #   Psych.load("--- a")           # => 'a'
110
  #   Psych.load("---\n - a\n - b") # => ['a', 'b']
111
  def self.load yaml
112
    result = parse(yaml)
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)
113 128
    result ? result.to_ruby : result
114 129
  end
115 130

  
116 131
  ###
117 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.
118 137
  #
119 138
  # Example:
120 139
  #
121 140
  #   Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Sequence:0x00>
122 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
  #
123 149
  # See Psych::Nodes for more information about YAML AST.
124
  def self.parse yaml
125
    children = parse_stream(yaml).children
126
    children.empty? ? false : children.first.children.first
150
  def self.parse yaml, filename = nil
151
    parse_stream(yaml, filename) do |node|
152
      return node
153
    end
154
    false
127 155
  end
128 156

  
129 157
  ###
130 158
  # Parse a file at +filename+. Returns the YAML AST.
159
  #
160
  # Raises a Psych::SyntaxError when a YAML syntax error is detected.
131 161
  def self.parse_file filename
132
    File.open filename do |f|
133
      parse f
162
    File.open filename, 'r:bom|utf-8' do |f|
163
      parse f, filename
134 164
    end
135 165
  end
136 166

  
......
143 173
  ###
144 174
  # Parse a YAML string in +yaml+.  Returns the full AST for the YAML document.
145 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.
146 183
  #
147 184
  # Example:
148 185
  #
149 186
  #   Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00>
150 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
  #
151 199
  # See Psych::Nodes for more information about YAML AST.
152
  def self.parse_stream yaml
153
    parser = self.parser
154
    parser.parse yaml
155
    parser.handler.root
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
156 209
  end
157 210

  
158 211
  ###
......
214 267

  
215 268
  ###
216 269
  # Load multiple documents given in +yaml+.  Returns the parsed documents
217
  # as a list.  For example:
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:
218 274
  #
219 275
  #   Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']
220 276
  #
221
  def self.load_stream yaml
222
    parse_stream(yaml).children.map { |child| child.to_ruby }
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
223 291
  end
224 292

  
225 293
  ###
226 294
  # Load the document contained in +filename+.  Returns the yaml contained in
227 295
  # +filename+ as a ruby object
228 296
  def self.load_file filename
229
    File.open(filename) { |f| self.load f }
297
    File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename }
230 298
  end
231 299

  
232 300
  # :stopdoc:
ext/psych/lib/psych/core_ext.rb
30 30
  alias :yaml_as :psych_yaml_as
31 31
end
32 32

  
33
if defined?(::IRB)
33 34
module Kernel
34 35
  def psych_y *objects
35 36
    puts Psych.dump_stream(*objects)
......
38 39
  alias y psych_y
39 40
  private :y
40 41
end
42
end
ext/psych/lib/psych/handlers/document_stream.rb
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
ext/psych/lib/psych/json.rb
1
module Psych
2
  module JSON
3
    autoload :TreeBuilder, 'psych/json/tree_builder'
4
    autoload :Stream, 'psych/json/stream'
5
  end
6
end
ext/psych/lib/psych/parser.rb
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
ext/psych/lib/psych/scalar_scanner.rb
46 46
        end
47 47
      when TIME
48 48
        parse_time string
49
      when /^\d{4}-\d{1,2}-\d{1,2}$/
49
      when /^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/
50 50
        require 'date'
51
        Date.strptime(string, '%Y-%m-%d')
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 65
        else
62 66
          string.sub(/^:/, '').to_sym
63 67
        end
64
      when /^[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+$/
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 78
        end
75 79
        i
76 80
      when FLOAT
77
        return Float(string.gsub(/[,_]/, '')) rescue ArgumentError
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
          return Integer(string.gsub(/[,_]/, '')) rescue ArgumentError
90
          begin
91
            return Integer(string.gsub(/[,_]/, ''))
92
          rescue ArgumentError
93
          end
84 94
        end
85 95

  
86 96
        @string_cache[string] = true
ext/psych/lib/psych/syntax_error.rb
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
ext/psych/lib/psych/tree_builder.rb
72 72
    end
73 73

  
74 74
    def scalar value, anchor, tag, plain, quoted, style
75
      @last.children << Nodes::Scalar.new(value,anchor,tag,plain,quoted,style)
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
ext/psych/lib/psych/visitors/to_ruby.rb
31 31
        result
32 32
      end
33 33

  
34
      def visit_Psych_Nodes_Scalar o
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 50
        case o.tag
53 51
        when '!binary', 'tag:yaml.org,2002:binary'
54 52
          o.value.unpack('m').first
55
        when '!str', 'tag:yaml.org,2002:str'
56
          o.value
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 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 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 141
        return revive_hash({}, o) unless o.tag
128 142

  
129 143
        case o.tag
130
        when '!str', 'tag:yaml.org,2002:str'
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 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 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'
......
205 236
      end
206 237

  
207 238
      def visit_Psych_Nodes_Alias o
208
        @st[o.anchor]
239
        @st.fetch(o.anchor) { raise BadAlias, "Unknown alias: #{o.anchor}" }
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

  
ext/psych/lib/psych/visitors/yaml_tree.rb
159 159
      end
160 160

  
161 161
      def visit_Regexp o
162
        @emitter.scalar o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY
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 formatted, nil, tag, false, false, Nodes::Scalar::ANY
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 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 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 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 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
          @emitter.start_mapping nil, '!str', false, Nodes::Mapping::BLOCK
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 265

  
256 266
      def visit_Module o
257 267
        raise TypeError, "can't dump anonymous module: #{o}" unless o.name
258
        @emitter.scalar o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED
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 o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED
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 nil, '!ruby/range', false, Nodes::Mapping::BLOCK
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 307
      end
298 308

  
299 309
      def visit_Array o
300
        register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
301
        o.each { |c| accept c }
302
        @emitter.end_sequence
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 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
ext/psych/parser.c
59 59
    return Data_Wrap_Struct(klass, 0, dealloc, parser);
60 60
}
61 61

  
62
static VALUE make_exception(yaml_parser_t * parser, VALUE path)
63
{
64
    size_t line, column;
65

  
66
    line = parser->context_mark.line + 1;
67
    column = parser->context_mark.column + 1;
68

  
69
    return rb_funcall(ePsychSyntaxError, rb_intern("new"), 6,
70
	    path,
71
	    INT2NUM(line),
72
	    INT2NUM(column),
73
	    INT2NUM(parser->problem_offset),
74
	    parser->problem ? rb_usascii_str_new2(parser->problem) : Qnil,
75
	    parser->context ? rb_usascii_str_new2(parser->context) : Qnil);
76
}
77

  
78
#ifdef HAVE_RUBY_ENCODING_H
79
static VALUE transcode_string(VALUE src, int * parser_encoding)
80
{
81
    int utf8    = rb_utf8_encindex();
82
    int utf16le = rb_enc_find_index("UTF16_LE");
83
    int utf16be = rb_enc_find_index("UTF16_BE");
84
    int source_encoding = rb_enc_get_index(src);
85

  
86
    if (source_encoding == utf8) {
87
	*parser_encoding = YAML_UTF8_ENCODING;
88
	return src;
89
    }
90

  
91
    if (source_encoding == utf16le) {
92
	*parser_encoding = YAML_UTF16LE_ENCODING;
93
	return src;
94
    }
95

  
96
    if (source_encoding == utf16be) {
97
	*parser_encoding = YAML_UTF16BE_ENCODING;
98
	return src;
99
    }
100

  
101
    src = rb_str_export_to_enc(src, rb_utf8_encoding());
102
    RB_GC_GUARD(src);
103

  
104
    *parser_encoding = YAML_UTF8_ENCODING;
105
    return src;
106
}
107

  
108
static VALUE transcode_io(VALUE src, int * parser_encoding)
109
{
110
    VALUE io_external_encoding;
111
    int io_external_enc_index;
112

  
113
    io_external_encoding = rb_funcall(src, rb_intern("external_encoding"), 0);
114

  
115
    /* if no encoding is returned, assume ascii8bit. */
116
    if (NIL_P(io_external_encoding)) {
117
	io_external_enc_index = rb_ascii8bit_encindex();
118
    } else {
119
	io_external_enc_index = rb_to_encoding_index(io_external_encoding);
120
    }
121

  
122
    /* Treat US-ASCII as utf_8 */
123
    if (io_external_enc_index == rb_usascii_encindex()) {
124
	*parser_encoding = YAML_UTF8_ENCODING;
125
	return src;
126
    }
127

  
128
    if (io_external_enc_index == rb_utf8_encindex()) {
129
	*parser_encoding = YAML_UTF8_ENCODING;
130
	return src;
131
    }
132

  
133
    if (io_external_enc_index == rb_enc_find_index("UTF-16LE")) {
134
	*parser_encoding = YAML_UTF16LE_ENCODING;
135
	return src;
136
    }
137

  
138
    if (io_external_enc_index == rb_enc_find_index("UTF-16BE")) {
139
	*parser_encoding = YAML_UTF16BE_ENCODING;
140
	return src;
141
    }
142

  
143
    /* Just guess on ASCII-8BIT */
144
    if (io_external_enc_index == rb_ascii8bit_encindex()) {
145
	*parser_encoding = YAML_ANY_ENCODING;
146
	return src;
147
    }
148

  
149
    rb_raise(rb_eArgError, "YAML file must be UTF-8, UTF-16LE, or UTF-16BE, not %s",
150
	    rb_enc_name(rb_enc_from_index(io_external_enc_index)));
151

  
152
    return Qnil;
153
}
154

  
155
#endif
156

  
157
static VALUE protected_start_stream(VALUE pointer)
158
{
159
    VALUE *args = (VALUE *)pointer;
160
    return rb_funcall(args[0], id_start_stream, 1, args[1]);
161
}
162

  
163
static VALUE protected_start_document(VALUE pointer)
164
{
165
    VALUE *args = (VALUE *)pointer;
166
    return rb_funcall3(args[0], id_start_document, 3, args + 1);
167
}
168

  
169
static VALUE protected_end_document(VALUE pointer)
170
{
171
    VALUE *args = (VALUE *)pointer;
172
    return rb_funcall(args[0], id_end_document, 1, args[1]);
173
}
174

  
175
static VALUE protected_alias(VALUE pointer)
176
{
177
    VALUE *args = (VALUE *)pointer;
178
    return rb_funcall(args[0], id_alias, 1, args[1]);
179
}
180

  
181
static VALUE protected_scalar(VALUE pointer)
182
{
183
    VALUE *args = (VALUE *)pointer;
184
    return rb_funcall3(args[0], id_scalar, 6, args + 1);
185
}
186

  
187
static VALUE protected_start_sequence(VALUE pointer)
188
{
189
    VALUE *args = (VALUE *)pointer;
190
    return rb_funcall3(args[0], id_start_sequence, 4, args + 1);
191
}
192

  
193
static VALUE protected_end_sequence(VALUE handler)
194
{
195
    return rb_funcall(handler, id_end_sequence, 0);
196
}
197

  
198
static VALUE protected_start_mapping(VALUE pointer)
199
{
200
    VALUE *args = (VALUE *)pointer;
201
    return rb_funcall3(args[0], id_start_mapping, 4, args + 1);
202
}
203

  
204
static VALUE protected_end_mapping(VALUE handler)
205
{
206
    return rb_funcall(handler, id_end_mapping, 0);
207
}
208

  
209
static VALUE protected_empty(VALUE handler)
210
{
211
    return rb_funcall(handler, id_empty, 0);
212
}
213

  
214
static VALUE protected_end_stream(VALUE handler)
215
{
216
    return rb_funcall(handler, id_end_stream, 0);
217
}
218

  
62 219
/*
63 220
 * call-seq:
64 221
 *    parser.parse(yaml)
......
68 225
 *
69 226
 * See Psych::Parser and Psych::Parser#handler
70 227
 */
71
static VALUE parse(VALUE self, VALUE yaml)
228
static VALUE parse(int argc, VALUE *argv, VALUE self)
72 229
{
230
    VALUE yaml, path;
73 231
    yaml_parser_t * parser;
74 232
    yaml_event_t event;
75 233
    int done = 0;
76 234
    int tainted = 0;
235
    int state = 0;
236
    int parser_encoding = YAML_ANY_ENCODING;
77 237
#ifdef HAVE_RUBY_ENCODING_H
78 238
    int encoding = rb_utf8_encindex();
79 239
    rb_encoding * internal_enc = rb_default_internal_encoding();
80 240
#endif
81 241
    VALUE handler = rb_iv_get(self, "@handler");
82 242

  
243
    if (rb_scan_args(argc, argv, "11", &yaml, &path) == 1) {
244
	if(rb_respond_to(yaml, id_path))
245
	    path = rb_funcall(yaml, id_path, 0);
246
	else
247
	    path = rb_str_new2("<unknown>");
248
    }
249

  
83 250
    Data_Get_Struct(self, yaml_parser_t, parser);
84 251

  
252
    yaml_parser_delete(parser);
253
    yaml_parser_initialize(parser);
254

  
85 255
    if (OBJ_TAINTED(yaml)) tainted = 1;
86 256

  
87
    if(rb_respond_to(yaml, id_read)) {
257
    if (rb_respond_to(yaml, id_read)) {
258
#ifdef HAVE_RUBY_ENCODING_H
259
	yaml = transcode_io(yaml, &parser_encoding);
260
	yaml_parser_set_encoding(parser, parser_encoding);
261
#endif
88 262
	yaml_parser_set_input(parser, io_reader, (void *)yaml);
89 263
	if (RTEST(rb_obj_is_kind_of(yaml, rb_cIO))) tainted = 1;
90 264
    } else {
91 265
	StringValue(yaml);
266
#ifdef HAVE_RUBY_ENCODING_H
267
	yaml = transcode_string(yaml, &parser_encoding);
268
	yaml_parser_set_encoding(parser, parser_encoding);
269
#endif
92 270
	yaml_parser_set_input_string(
93 271
		parser,
94 272
		(const unsigned char *)RSTRING_PTR(yaml),
......
98 276

  
99 277
    while(!done) {
100 278
	if(!yaml_parser_parse(parser, &event)) {
101
	    VALUE path;
102
	    size_t line   = parser->mark.line;
103
	    size_t column = parser->mark.column;
104

  
105
	    if(rb_respond_to(yaml, id_path))
106
		path = rb_funcall(yaml, id_path, 0);
107
	    else
108
		path = rb_str_new2("<unknown>");
279
	    VALUE exception;
109 280

  
281
	    exception = make_exception(parser, path);
110 282
	    yaml_parser_delete(parser);
111 283
	    yaml_parser_initialize(parser);
112 284

  
113
	    rb_raise(ePsychSyntaxError, "(%s): couldn't parse YAML at line %d column %d",
114
		    StringValuePtr(path),
115
		    (int)line, (int)column);
285
	    rb_exc_raise(exception);
116 286
	}
117 287

  
118 288
	switch(event.type) {
119
	  case YAML_STREAM_START_EVENT:
120

  
121
	    rb_funcall(handler, id_start_stream, 1,
122
		       INT2NUM((long)event.data.stream_start.encoding)
123
		);
124
	    break;
289
	    case YAML_STREAM_START_EVENT:
290
	      {
291
		  VALUE args[2];
292

  
293
		  args[0] = handler;
294
		  args[1] = INT2NUM((long)event.data.stream_start.encoding);
295
		  rb_protect(protected_start_stream, (VALUE)args, &state);
296
	      }
297
	      break;
125 298
	  case YAML_DOCUMENT_START_EVENT:
126 299
	    {
300
		VALUE args[4];
127 301
		/* Get a list of tag directives (if any) */
128 302
		VALUE tag_directives = rb_ary_new();
129 303
		/* Grab the document version */
......
161 335
			rb_ary_push(tag_directives, rb_ary_new3((long)2, handle, prefix));
162 336
		    }
163 337
		}
164
		rb_funcall(handler, id_start_document, 3,
165
			   version, tag_directives,
166
			   event.data.document_start.implicit == 1 ? Qtrue : Qfalse
167
		    );
338
		args[0] = handler;
339
		args[1] = version;
340
		args[2] = tag_directives;
341
		args[3] = event.data.document_start.implicit == 1 ? Qtrue : Qfalse;
342
		rb_protect(protected_start_document, (VALUE)args, &state);
168 343
	    }
169 344
	    break;
170 345
	  case YAML_DOCUMENT_END_EVENT:
171
	    rb_funcall(handler, id_end_document, 1,
172
		       event.data.document_end.implicit == 1 ? Qtrue : Qfalse
173
		);
346
	    {
347
		VALUE args[2];
348

  
349
		args[0] = handler;
350
		args[1] = event.data.document_end.implicit == 1 ? Qtrue : Qfalse;
351
		rb_protect(protected_end_document, (VALUE)args, &state);
352
	    }
174 353
	    break;
175 354
	  case YAML_ALIAS_EVENT:
176 355
	    {
356
		VALUE args[2];
177 357
		VALUE alias = Qnil;
178 358
		if(event.data.alias.anchor) {
179 359
		    alias = rb_str_new2((const char *)event.data.alias.anchor);
......
183 363
#endif
184 364
		}
185 365

  
186
		rb_funcall(handler, id_alias, 1, alias);
366
		args[0] = handler;
367
		args[1] = alias;
368
		rb_protect(protected_alias, (VALUE)args, &state);
187 369
	    }
188 370
	    break;
189 371
	  case YAML_SCALAR_EVENT:
190 372
	    {
373
		VALUE args[7];
191 374
		VALUE anchor = Qnil;
192 375
		VALUE tag = Qnil;
193 376
		VALUE plain_implicit, quoted_implicit, style;
......
225 408

  
226 409
		style = INT2NUM((long)event.data.scalar.style);
227 410

  
228
		rb_funcall(handler, id_scalar, 6,
229
			   val, anchor, tag, plain_implicit, quoted_implicit, style);
411
		args[0] = handler;
412
		args[1] = val;
413
		args[2] = anchor;
414
		args[3] = tag;
415
		args[4] = plain_implicit;
416
		args[5] = quoted_implicit;
417
		args[6] = style;
418
		rb_protect(protected_scalar, (VALUE)args, &state);
230 419
	    }
231 420
	    break;
232 421
	  case YAML_SEQUENCE_START_EVENT:
233 422
	    {
423
		VALUE args[5];
234 424
		VALUE anchor = Qnil;
235 425
		VALUE tag = Qnil;
236 426
		VALUE implicit, style;
......
256 446

  
257 447
		style = INT2NUM((long)event.data.sequence_start.style);
258 448

  
259
		rb_funcall(handler, id_start_sequence, 4,
260
			   anchor, tag, implicit, style);
449
		args[0] = handler;
450
		args[1] = anchor;
451
		args[2] = tag;
452
		args[3] = implicit;
453
		args[4] = style;
454

  
455
		rb_protect(protected_start_sequence, (VALUE)args, &state);
261 456
	    }
262 457
	    break;
263 458
	  case YAML_SEQUENCE_END_EVENT:
264
	    rb_funcall(handler, id_end_sequence, 0);
459
	    rb_protect(protected_end_sequence, handler, &state);
265 460
	    break;
266 461
	  case YAML_MAPPING_START_EVENT:
267 462
	    {
463
		VALUE args[5];
268 464
		VALUE anchor = Qnil;
269 465
		VALUE tag = Qnil;
270 466
		VALUE implicit, style;
......
289 485

  
290 486
		style = INT2NUM((long)event.data.mapping_start.style);
291 487

  
292
		rb_funcall(handler, id_start_mapping, 4,
293
			   anchor, tag, implicit, style);
488
		args[0] = handler;
489
		args[1] = anchor;
490
		args[2] = tag;
491
		args[3] = implicit;
492
		args[4] = style;
493

  
494
		rb_protect(protected_start_mapping, (VALUE)args, &state);
294 495
	    }
295 496
	    break;
296 497
	  case YAML_MAPPING_END_EVENT:
297
	    rb_funcall(handler, id_end_mapping, 0);
498
	    rb_protect(protected_end_mapping, handler, &state);
298 499
	    break;
299 500
	  case YAML_NO_EVENT:
300
	    rb_funcall(handler, id_empty, 0);
501
	    rb_protect(protected_empty, handler, &state);
301 502
	    break;
302 503
	  case YAML_STREAM_END_EVENT:
303
	    rb_funcall(handler, id_end_stream, 0);
504
	    rb_protect(protected_end_stream, handler, &state);
304 505
	    done = 1;
305 506
	    break;
306 507
	}
307 508
	yaml_event_delete(&event);
509
	if (state) rb_jump_tag(state);
308 510
    }
309 511

  
310 512
    return self;
......
312 514

  
313 515
/*
314 516
 * call-seq:
315
 *    parser.external_encoding=(encoding)
316
 *
317
 * Set the encoding for this parser to +encoding+
318
 */
319
static VALUE set_external_encoding(VALUE self, VALUE encoding)
320
{
321
    yaml_parser_t * parser;
322
    VALUE exception;
323

  
324
    Data_Get_Struct(self, yaml_parser_t, parser);
325

  
326
    if(parser->encoding) {
327
	exception = rb_const_get_at(mPsych, rb_intern("Exception"));
328
	rb_raise(exception, "don't set the encoding twice!");
329
    }
330

  
331
    yaml_parser_set_encoding(parser, NUM2INT(encoding));
332

  
333
    return encoding;
334
}
335

  
336
/*
337
 * call-seq:
338 517
 *    parser.mark # => #<Psych::Parser::Mark>
339 518
 *
340 519
 * Returns a Psych::Parser::Mark object that contains line, column, and index
......
376 555
    /* UTF-16-BE Encoding with BOM */
377 556
    rb_define_const(cPsychParser, "UTF16BE", INT2NUM(YAML_UTF16BE_ENCODING));
378 557

  
558
    rb_require("psych/syntax_error");
379 559
    ePsychSyntaxError = rb_define_class_under(mPsych, "SyntaxError", rb_eSyntaxError);
380 560

  
381
    rb_define_method(cPsychParser, "parse", parse, 1);
561
    rb_define_method(cPsychParser, "parse", parse, -1);
382 562
    rb_define_method(cPsychParser, "mark", mark, 0);
383
    rb_define_method(cPsychParser, "external_encoding=", set_external_encoding, 1);
384 563

  
385 564
    id_read           = rb_intern("read");
386 565
    id_path           = rb_intern("path");
test/psych/test_array.rb
2 2

  
3 3
module Psych
4 4
  class TestArray < TestCase
5
    class X < Array
6
    end
7

  
8
    class Y < Array
9
      attr_accessor :val
10
    end
11

  
5 12
    def setup
6 13
      super
7 14
      @list = [{ :a => 'b' }, 'foo']
8 15
    end
9 16

  
17
    def test_subclass
18
      yaml = Psych.dump X.new
19
      assert_match X.name, yaml
20

  
21
      list = X.new
22
      list << 1
23
      assert_equal X, list.class
24
      assert_equal 1, list.first
25
    end
26

  
27
    def test_subclass_with_attributes
28
      y = Psych.load Psych.dump Y.new.tap {|y| y.val = 1}
29
      assert_equal Y, y.class
30
      assert_equal 1, y.val
31
    end
32

  
33
    def test_backwards_with_syck
34
      x = Psych.load "--- !seq:#{X.name} []\n\n"
35
      assert_equal X, x.class
36
    end
37

  
10 38
    def test_self_referential
11 39
      @list << @list
12 40
      assert_cycle(@list)
test/psych/test_encoding.rb
31 31
      @emitter = Psych::Emitter.new @buffer
32 32
    end
33 33

  
34
    def test_transcode_shiftjis
35
      str = "こんにちは!"
36
      loaded = Psych.load("--- こんにちは!".encode('SHIFT_JIS'))
37
      assert_equal str, loaded
38
    end
39

  
40
    def test_transcode_utf16le
41
      str = "こんにちは!"
42
      loaded = Psych.load("--- こんにちは!".encode('UTF-16LE'))
43
      assert_equal str, loaded
44
    end
45

  
46
    def test_transcode_utf16be
47
      str = "こんにちは!"
48
      loaded = Psych.load("--- こんにちは!".encode('UTF-16BE'))
49
      assert_equal str, loaded
50
    end
51

  
52
    def test_io_shiftjis
53
      t = Tempfile.new(['shiftjis', 'yml'], :encoding => 'SHIFT_JIS')
54
      t.write '--- こんにちは!'
55
      t.close
56

  
57
      # If the external encoding isn't utf8, utf16le, or utf16be, we cannot
58
      # process the file.
59
      File.open(t.path, 'r', :encoding => 'SHIFT_JIS') do |f|
60
        assert_raises ArgumentError do
61
          Psych.load(f)
62
        end
63
      end
64

  
65
      t.close(true)
66
    end
67

  
68
    def test_io_utf16le
69
      t = Tempfile.new(['utf16le', 'yml'])
70
      t.binmode
71
      t.write '--- こんにちは!'.encode('UTF-16LE')
72
      t.close
73

  
74
      File.open(t.path, 'rb', :encoding => 'UTF-16LE') do |f|
75
        assert_equal "こんにちは!", Psych.load(f)
76
      end
77

  
78
      t.close(true)
79
    end
80

  
81
    def test_io_utf16be
82
      t = Tempfile.new(['utf16be', 'yml'])
83
      t.binmode
84
      t.write '--- こんにちは!'.encode('UTF-16BE')
85
      t.close
86

  
87
      File.open(t.path, 'rb', :encoding => 'UTF-16BE') do |f|
88
        assert_equal "こんにちは!", Psych.load(f)
89
      end
90

  
91
      t.close(true)
92
    end
93

  
94
    def test_io_utf8
95
      t = Tempfile.new(['utf8', 'yml'])
96
      t.binmode
97
      t.write '--- こんにちは!'.encode('UTF-8')
98
      t.close
99

  
100
      File.open(t.path, 'rb', :encoding => 'UTF-8') do |f|
101
        assert_equal "こんにちは!", Psych.load(f)
102
      end
103

  
104
      t.close(true)
105
    end
106

  
34 107
    def test_emit_alias
35 108
      @emitter.start_stream Psych::Parser::UTF8
36 109
      @emitter.start_document [], [], true
test/psych/test_exception.rb
16 16
      @wups = Wups.new
17 17
    end
18 18

  
19
    def test_load_takes_file
20
      ex = assert_raises(Psych::SyntaxError) do
21
        Psych.load '--- `'
22
      end
23
      assert_nil ex.file
24

  
25
      ex = assert_raises(Psych::SyntaxError) do
26
        Psych.load '--- `', 'meow'
27
      end
28
      assert_equal 'meow', ex.file
29
    end
30

  
31
    def test_psych_parse_stream_takes_file
32
      ex = assert_raises(Psych::SyntaxError) do
33
        Psych.parse_stream '--- `'
34
      end
35
      assert_nil ex.file
36
      assert_match '(<unknown>)', ex.message
37

  
38
      ex = assert_raises(Psych::SyntaxError) do
39
        Psych.parse_stream '--- `', 'omg!'
40
      end
41
      assert_equal 'omg!', ex.file
42
      assert_match 'omg!', ex.message
43
    end
44

  
45
    def test_load_stream_takes_file
46
      ex = assert_raises(Psych::SyntaxError) do
47
        Psych.load_stream '--- `'
48
      end
49
      assert_nil ex.file
50
      assert_match '(<unknown>)', ex.message
51

  
52
      ex = assert_raises(Psych::SyntaxError) do
53
        Psych.load_stream '--- `', 'omg!'
54
      end
55
      assert_equal 'omg!', ex.file
56
    end
57

  
58
    def test_parse_file_exception
59
      t = Tempfile.new(['parsefile', 'yml'])
60
      t.binmode
61
      t.write '--- `'
62
      t.close
63
      ex = assert_raises(Psych::SyntaxError) do
64
        Psych.parse_file t.path
65
      end
66
      assert_equal t.path, ex.file
67
      t.close(true)
68
    end
69

  
70
    def test_load_file_exception
71
      t = Tempfile.new(['loadfile', 'yml'])
72
      t.binmode
73
      t.write '--- `'
74
      t.close
75
      ex = assert_raises(Psych::SyntaxError) do
76
        Psych.load_file t.path
77
      end
78
      assert_equal t.path, ex.file
79
      t.close(true)
80
    end
81

  
82
    def test_psych_parse_takes_file
83
      ex = assert_raises(Psych::SyntaxError) do
84
        Psych.parse '--- `'
85
      end
86
      assert_match '(<unknown>)', ex.message
87
      assert_nil ex.file
88

  
89
      ex = assert_raises(Psych::SyntaxError) do
90
        Psych.parse '--- `', 'omg!'
91
      end
92
      assert_match 'omg!', ex.message
93
    end
94

  
95
    def test_attributes
96
      e = assert_raises(Psych::SyntaxError) {
97
        Psych.load '--- `foo'
98
      }
99

  
100
      assert_nil e.file
101
      assert_equal 1, e.line
102
      assert_equal 5, e.column
103
      # FIXME: offset isn't being set correctly by libyaml
104
      # assert_equal 5, e.offset
105

  
106
      assert e.problem
107
      assert e.context
108
    end
109

  
19 110
    def test_convert
20 111
      w = Psych.load(Psych.dump(@wups))
21 112
      assert_equal @wups, w
test/psych/test_merge_keys.rb
2 2

  
3 3
module Psych
4 4
  class TestMergeKeys < TestCase
5
    def test_missing_merge_key
6
      yaml = <<-eoyml
7
bar:
8
  << : *foo
9
      eoyml
10
      exp = assert_raises(Psych::BadAlias) { Psych.load yaml }
11
      assert_match 'foo', exp.message
12
    end
13

  
5 14
    # [ruby-core:34679]
6 15
    def test_merge_key
7 16
      yaml = <<-eoyml
... This diff was truncated because it exceeds the maximum size that can be displayed.