psych 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|