km-psych 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/README.rdoc +129 -0
  2. data/ext/psych/emitter.c +488 -0
  3. data/ext/psych/emitter.h +8 -0
  4. data/ext/psych/extconf.rb +22 -0
  5. data/ext/psych/parser.c +349 -0
  6. data/ext/psych/parser.h +6 -0
  7. data/ext/psych/psych.c +34 -0
  8. data/ext/psych/psych.h +20 -0
  9. data/ext/psych/to_ruby.c +41 -0
  10. data/ext/psych/to_ruby.h +8 -0
  11. data/ext/psych/yaml_tree.c +24 -0
  12. data/ext/psych/yaml_tree.h +8 -0
  13. data/lib/km-psych.rb +244 -0
  14. data/lib/psych/coder.rb +86 -0
  15. data/lib/psych/core_ext.rb +38 -0
  16. data/lib/psych/deprecated.rb +82 -0
  17. data/lib/psych/handler.rb +221 -0
  18. data/lib/psych/json.rb +6 -0
  19. data/lib/psych/json/stream.rb +32 -0
  20. data/lib/psych/json/tree_builder.rb +32 -0
  21. data/lib/psych/nodes.rb +77 -0
  22. data/lib/psych/nodes/alias.rb +18 -0
  23. data/lib/psych/nodes/document.rb +60 -0
  24. data/lib/psych/nodes/mapping.rb +56 -0
  25. data/lib/psych/nodes/node.rb +42 -0
  26. data/lib/psych/nodes/scalar.rb +67 -0
  27. data/lib/psych/nodes/sequence.rb +81 -0
  28. data/lib/psych/nodes/stream.rb +37 -0
  29. data/lib/psych/omap.rb +4 -0
  30. data/lib/psych/parser.rb +44 -0
  31. data/lib/psych/scalar_scanner.rb +105 -0
  32. data/lib/psych/set.rb +4 -0
  33. data/lib/psych/stream.rb +53 -0
  34. data/lib/psych/tree_builder.rb +94 -0
  35. data/lib/psych/visitors.rb +5 -0
  36. data/lib/psych/visitors/emitter.rb +41 -0
  37. data/lib/psych/visitors/json_tree.rb +14 -0
  38. data/lib/psych/visitors/to_ruby.rb +263 -0
  39. data/lib/psych/visitors/visitor.rb +27 -0
  40. data/lib/psych/visitors/yaml_tree.rb +342 -0
  41. data/test/psych/helper.rb +63 -0
  42. data/test/psych/json/test_stream.rb +75 -0
  43. data/test/psych/test_alias_and_anchor.rb +26 -0
  44. data/test/psych/test_array.rb +19 -0
  45. data/test/psych/test_boolean.rb +36 -0
  46. data/test/psych/test_class.rb +17 -0
  47. data/test/psych/test_coder.rb +169 -0
  48. data/test/psych/test_date_time.rb +17 -0
  49. data/test/psych/test_deprecated.rb +210 -0
  50. data/test/psych/test_document.rb +46 -0
  51. data/test/psych/test_emitter.rb +88 -0
  52. data/test/psych/test_encoding.rb +179 -0
  53. data/test/psych/test_engine_manager.rb +57 -0
  54. data/test/psych/test_exception.rb +39 -0
  55. data/test/psych/test_hash.rb +30 -0
  56. data/test/psych/test_json_tree.rb +43 -0
  57. data/test/psych/test_null.rb +19 -0
  58. data/test/psych/test_object.rb +27 -0
  59. data/test/psych/test_omap.rb +68 -0
  60. data/test/psych/test_parser.rb +216 -0
  61. data/test/psych/test_psych.rb +133 -0
  62. data/test/psych/test_scalar.rb +11 -0
  63. data/test/psych/test_scalar_scanner.rb +70 -0
  64. data/test/psych/test_serialize_subclasses.rb +38 -0
  65. data/test/psych/test_set.rb +49 -0
  66. data/test/psych/test_stream.rb +49 -0
  67. data/test/psych/test_string.rb +49 -0
  68. data/test/psych/test_struct.rb +51 -0
  69. data/test/psych/test_symbol.rb +17 -0
  70. data/test/psych/test_to_yaml_properties.rb +63 -0
  71. data/test/psych/test_tree_builder.rb +79 -0
  72. data/test/psych/test_yaml.rb +1251 -0
  73. data/test/psych/visitors/test_emitter.rb +124 -0
  74. data/test/psych/visitors/test_to_ruby.rb +325 -0
  75. data/test/psych/visitors/test_yaml_tree.rb +149 -0
  76. metadata +187 -0
@@ -0,0 +1,27 @@
1
+ module Psych
2
+ module Visitors
3
+ class Visitor
4
+ attr_reader :started, :finished
5
+ alias :finished? :finished
6
+ alias :started? :started
7
+
8
+ def initialize
9
+ @started = false
10
+ @finished = false
11
+ end
12
+
13
+ def accept target
14
+ case target
15
+ when Psych::Nodes::Scalar then visit_Psych_Nodes_Scalar target
16
+ when Psych::Nodes::Mapping then visit_Psych_Nodes_Mapping target
17
+ when Psych::Nodes::Sequence then visit_Psych_Nodes_Sequence target
18
+ when Psych::Nodes::Alias then visit_Psych_Nodes_Alias target
19
+ when Psych::Nodes::Document then visit_Psych_Nodes_Document target
20
+ when Psych::Nodes::Stream then visit_Psych_Nodes_Stream target
21
+ else
22
+ raise "Can't handle #{target}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,342 @@
1
+ module Psych
2
+ module Visitors
3
+ ###
4
+ # YAMLTree builds a YAML ast given a ruby object. For example:
5
+ #
6
+ # builder = Psych::Visitors::YAMLTree.new
7
+ # builder << { :foo => 'bar' }
8
+ # builder.tree # => #<Psych::Nodes::Stream .. }
9
+ #
10
+ class YAMLTree < Psych::Visitors::Visitor
11
+ def initialize options = {}, emitter = Psych::TreeBuilder.new
12
+ super()
13
+ @emitter = emitter
14
+ @st = {}
15
+ @ss = ScalarScanner.new
16
+
17
+ @dispatch_cache = Hash.new do |h,klass|
18
+ method = "visit_#{(klass.name || '').split('::').join('_')}"
19
+
20
+ method = respond_to?(method) ? method : h[klass.superclass]
21
+
22
+ raise(TypeError, "Can't dump #{target.class}") unless method
23
+
24
+ h[klass] = method
25
+ end
26
+ end
27
+
28
+ def start encoding = Nodes::Stream::UTF8
29
+ @emitter.start_stream(encoding).tap do
30
+ @started = true
31
+ end
32
+ end
33
+
34
+ def finish
35
+ @emitter.end_stream.tap do
36
+ @finished = true
37
+ end
38
+ end
39
+
40
+ def tree
41
+ finish unless finished?
42
+ end
43
+
44
+ def push object
45
+ start unless started?
46
+ @emitter.start_document [], [], false
47
+ accept object
48
+ @emitter.end_document
49
+ end
50
+ alias :<< :push
51
+
52
+ def accept target
53
+ # return any aliases we find
54
+ if node = @st[target.object_id]
55
+ node.anchor = target.object_id.to_s
56
+ return @emitter.alias target.object_id.to_s
57
+ end
58
+
59
+ if target.respond_to?(:to_yaml)
60
+ loc = target.method(:to_yaml).source_location.first
61
+ if loc !~ /(syck\/rubytypes.rb|psych\/core_ext.rb)/
62
+ unless target.respond_to?(:encode_with)
63
+ if $VERBOSE
64
+ warn "implementing to_yaml is deprecated, please implement \"encode_with\""
65
+ end
66
+
67
+ target.to_yaml(:nodump => true)
68
+ end
69
+ end
70
+ end
71
+
72
+ if target.respond_to?(:encode_with)
73
+ dump_coder target
74
+ else
75
+ send(@dispatch_cache[target.class], target)
76
+ end
77
+ end
78
+
79
+ def visit_Psych_Omap o
80
+ seq = @emitter.start_sequence(nil, '!omap', false, Nodes::Sequence::BLOCK)
81
+ register(o, seq)
82
+
83
+ o.each { |k,v| visit_Hash k => v }
84
+ @emitter.end_sequence
85
+ end
86
+
87
+ def visit_Object o
88
+ tag = Psych.dump_tags[o.class]
89
+ unless tag
90
+ klass = o.class == Object ? nil : o.class.name
91
+ tag = ['!ruby/object', klass].compact.join(':')
92
+ end
93
+
94
+ map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
95
+ register(o, map)
96
+
97
+ dump_ivars o
98
+ @emitter.end_mapping
99
+ end
100
+
101
+ def visit_Struct o
102
+ tag = ['!ruby/struct', o.class.name].compact.join(':')
103
+
104
+ register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
105
+ o.members.each do |member|
106
+ @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
107
+ accept o[member]
108
+ end
109
+
110
+ dump_ivars o
111
+
112
+ @emitter.end_mapping
113
+ end
114
+
115
+ def visit_Exception o
116
+ tag = ['!ruby/exception', o.class.name].join ':'
117
+
118
+ @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
119
+
120
+ {
121
+ 'message' => private_iv_get(o, 'mesg'),
122
+ 'backtrace' => private_iv_get(o, 'backtrace'),
123
+ }.each do |k,v|
124
+ next unless v
125
+ @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
126
+ accept v
127
+ end
128
+
129
+ dump_ivars o
130
+
131
+ @emitter.end_mapping
132
+ end
133
+
134
+ def visit_Regexp o
135
+ @emitter.scalar o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY
136
+ end
137
+
138
+ def visit_DateTime o
139
+ formatted = format_time o.to_time
140
+ tag = '!ruby/object:DateTime'
141
+ @emitter.scalar formatted, nil, tag, false, false, Nodes::Scalar::ANY
142
+ end
143
+
144
+ def visit_Time o
145
+ formatted = format_time o
146
+ @emitter.scalar formatted, nil, nil, true, false, Nodes::Scalar::ANY
147
+ end
148
+
149
+ def visit_Rational o
150
+ @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK)
151
+
152
+ [
153
+ 'denominator', o.denominator.to_s,
154
+ 'numerator', o.numerator.to_s
155
+ ].each do |m|
156
+ @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
157
+ end
158
+
159
+ @emitter.end_mapping
160
+ end
161
+
162
+ def visit_Complex o
163
+ @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK)
164
+
165
+ ['real', o.real.to_s, 'image', o.imag.to_s].each do |m|
166
+ @emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
167
+ end
168
+
169
+ @emitter.end_mapping
170
+ end
171
+
172
+ def visit_Integer o
173
+ @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY
174
+ end
175
+ alias :visit_TrueClass :visit_Integer
176
+ alias :visit_FalseClass :visit_Integer
177
+ alias :visit_Date :visit_Integer
178
+
179
+ def visit_Float o
180
+ if o.nan?
181
+ @emitter.scalar '.nan', nil, nil, true, false, Nodes::Scalar::ANY
182
+ elsif o.infinite?
183
+ @emitter.scalar((o.infinite? > 0 ? '.inf' : '-.inf'),
184
+ nil, nil, true, false, Nodes::Scalar::ANY)
185
+ else
186
+ @emitter.scalar o.to_s, nil, nil, true, false, Nodes::Scalar::ANY
187
+ end
188
+ end
189
+
190
+ def visit_String o
191
+ plain = false
192
+ quote = false
193
+ style = Nodes::Scalar::ANY
194
+
195
+ if o.index("\x00") || o.count("^ -~\t\r\n").fdiv(o.length) > 0.3
196
+ str = [o].pack('m').chomp
197
+ tag = '!binary' # FIXME: change to below when syck is removed
198
+ #tag = 'tag:yaml.org,2002:binary'
199
+ style = Nodes::Scalar::LITERAL
200
+ else
201
+ str = o
202
+ tag = nil
203
+ quote = !(String === @ss.tokenize(o))
204
+ plain = !quote
205
+ end
206
+
207
+ ivars = find_ivars o
208
+
209
+ if ivars.empty?
210
+ @emitter.scalar str, nil, tag, plain, quote, style
211
+ else
212
+ @emitter.start_mapping nil, '!str', false, Nodes::Mapping::BLOCK
213
+ @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY
214
+ @emitter.scalar str, nil, tag, plain, quote, style
215
+
216
+ dump_ivars o
217
+
218
+ @emitter.end_mapping
219
+ end
220
+ end
221
+
222
+ def visit_Class o
223
+ raise TypeError, "can't dump anonymous class #{o.class}"
224
+ end
225
+
226
+ def visit_Range o
227
+ @emitter.start_mapping nil, '!ruby/range', false, Nodes::Mapping::BLOCK
228
+ ['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m|
229
+ accept m
230
+ end
231
+ @emitter.end_mapping
232
+ end
233
+
234
+ def visit_Hash o
235
+ register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK))
236
+
237
+ o.each do |k,v|
238
+ accept k
239
+ accept v
240
+ end
241
+
242
+ @emitter.end_mapping
243
+ end
244
+
245
+ def visit_Psych_Set o
246
+ register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))
247
+
248
+ o.each do |k,v|
249
+ accept k
250
+ accept v
251
+ end
252
+
253
+ @emitter.end_mapping
254
+ end
255
+
256
+ def visit_Array o
257
+ register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK)
258
+ o.each { |c| accept c }
259
+ @emitter.end_sequence
260
+ end
261
+
262
+ def visit_NilClass o
263
+ @emitter.scalar('', nil, 'tag:yaml.org,2002:null', false, false, Nodes::Scalar::ANY)
264
+ end
265
+
266
+ def visit_Symbol o
267
+ @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY
268
+ end
269
+
270
+ private
271
+ def format_time time
272
+ formatted = time.strftime("%Y-%m-%d %H:%M:%S.%9N")
273
+ if time.utc?
274
+ formatted += "Z"
275
+ else
276
+ zone = time.strftime('%z')
277
+ formatted += " #{zone[0,3]}:#{zone[3,5]}"
278
+ end
279
+ formatted
280
+ end
281
+
282
+ # FIXME: remove this method once "to_yaml_properties" is removed
283
+ def find_ivars target
284
+ loc = target.method(:to_yaml_properties).source_location.first
285
+ unless loc.start_with?(Psych::DEPRECATED) || loc.end_with?('rubytypes.rb')
286
+ if $VERBOSE
287
+ warn "#{loc}: to_yaml_properties is deprecated, please implement \"encode_with(coder)\""
288
+ end
289
+ return target.to_yaml_properties
290
+ end
291
+
292
+ target.instance_variables
293
+ end
294
+
295
+ def register target, yaml_obj
296
+ @st[target.object_id] = yaml_obj
297
+ yaml_obj
298
+ end
299
+
300
+ def dump_coder o
301
+ tag = Psych.dump_tags[o.class]
302
+ unless tag
303
+ klass = o.class == Object ? nil : o.class.name
304
+ tag = ['!ruby/object', klass].compact.join(':')
305
+ end
306
+
307
+ c = Psych::Coder.new(tag)
308
+ o.encode_with(c)
309
+ emit_coder c
310
+ end
311
+
312
+ def emit_coder c
313
+ case c.type
314
+ when :scalar
315
+ @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY
316
+ when :seq
317
+ @emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK
318
+ c.seq.each do |thing|
319
+ accept thing
320
+ end
321
+ @emitter.end_sequence
322
+ when :map
323
+ @emitter.start_mapping nil, c.tag, c.implicit, c.style
324
+ c.map.each do |k,v|
325
+ @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
326
+ accept v
327
+ end
328
+ @emitter.end_mapping
329
+ end
330
+ end
331
+
332
+ def dump_ivars target
333
+ ivars = find_ivars target
334
+
335
+ ivars.each do |iv|
336
+ @emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY)
337
+ accept target.instance_variable_get(iv)
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
@@ -0,0 +1,63 @@
1
+ require 'minitest/autorun'
2
+ require 'stringio'
3
+ require 'tempfile'
4
+ require 'date'
5
+
6
+ module Psych
7
+ class TestCase < MiniTest::Unit::TestCase
8
+ #
9
+ # Convert between Psych and the object to verify correct parsing and
10
+ # emitting
11
+ #
12
+ def assert_to_yaml( obj, yaml )
13
+ assert_equal( obj, Psych::load( yaml ) )
14
+ assert_equal( obj, Psych::parse( yaml ).transform )
15
+ assert_equal( obj, Psych::load( obj.psych_to_yaml ) )
16
+ assert_equal( obj, Psych::parse( obj.psych_to_yaml ).transform )
17
+ assert_equal( obj, Psych::load(
18
+ obj.psych_to_yaml(
19
+ :UseVersion => true, :UseHeader => true, :SortKeys => true
20
+ )
21
+ ))
22
+ end
23
+
24
+ #
25
+ # Test parser only
26
+ #
27
+ def assert_parse_only( obj, yaml )
28
+ assert_equal( obj, Psych::load( yaml ) )
29
+ assert_equal( obj, Psych::parse( yaml ).transform )
30
+ end
31
+
32
+ def assert_cycle( obj )
33
+ v = Visitors::YAMLTree.new
34
+ v << obj
35
+ assert_equal(obj, Psych.load(v.tree.to_yaml))
36
+ assert_equal( obj, Psych::load(Psych.dump(obj)))
37
+ assert_equal( obj, Psych::load( obj.psych_to_yaml ) )
38
+ end
39
+
40
+ #
41
+ # Make a time with the time zone
42
+ #
43
+ def mktime( year, mon, day, hour, min, sec, usec, zone = "Z" )
44
+ usec = Rational(usec.to_s) * 1000000
45
+ val = Time::utc( year.to_i, mon.to_i, day.to_i, hour.to_i, min.to_i, sec.to_i, usec )
46
+ if zone != "Z"
47
+ hour = zone[0,3].to_i * 3600
48
+ min = zone[3,2].to_i * 60
49
+ ofs = (hour + min)
50
+ val = Time.at( val.tv_sec - ofs, val.tv_nsec / 1000.0 )
51
+ end
52
+ return val
53
+ end
54
+ end
55
+ end
56
+
57
+ require 'psych'
58
+
59
+ # FIXME: remove this when syck is removed
60
+ o = Object.new
61
+ a = o.method(:psych_to_yaml)
62
+ b = o.method(:to_yaml)
63
+ raise "psych should define to_yaml" unless a == b
@@ -0,0 +1,75 @@
1
+ require_relative '../helper'
2
+
3
+ module Psych
4
+ module JSON
5
+ class TestStream < TestCase
6
+ def setup
7
+ @io = StringIO.new
8
+ @stream = Psych::JSON::Stream.new(@io)
9
+ @stream.start
10
+ end
11
+
12
+ def test_explicit_documents
13
+ @io = StringIO.new
14
+ @stream = Psych::JSON::Stream.new(@io)
15
+ @stream.start
16
+
17
+ @stream.push({ 'foo' => 'bar' })
18
+
19
+ assert !@stream.finished?, 'stream not finished'
20
+ @stream.finish
21
+ assert @stream.finished?, 'stream finished'
22
+
23
+ assert_match(/^---/, @io.string)
24
+ assert_match(/\.\.\.$/, @io.string)
25
+ end
26
+
27
+ def test_null
28
+ @stream.push(nil)
29
+ assert_match(/^--- null/, @io.string)
30
+ end
31
+
32
+ def test_string
33
+ @stream.push "foo"
34
+ assert_match(/(['"])foo\1/, @io.string)
35
+ end
36
+
37
+ def test_symbol
38
+ @stream.push :foo
39
+ assert_match(/(['"])foo\1/, @io.string)
40
+ end
41
+
42
+ def test_int
43
+ @stream.push 10
44
+ assert_match(/^--- 10/, @io.string)
45
+ end
46
+
47
+ def test_float
48
+ @stream.push 1.2
49
+ assert_match(/^--- 1.2/, @io.string)
50
+ end
51
+
52
+ def test_hash
53
+ hash = { 'one' => 'two' }
54
+ @stream.push hash
55
+
56
+ json = @io.string
57
+ assert_match(/}$/, json)
58
+ assert_match(/^--- \{/, json)
59
+ assert_match(/['"]one['"]/, json)
60
+ assert_match(/['"]two['"]/, json)
61
+ end
62
+
63
+ def test_list_to_json
64
+ list = %w{ one two }
65
+ @stream.push list
66
+
67
+ json = @io.string
68
+ assert_match(/]$/, json)
69
+ assert_match(/^--- \[/, json)
70
+ assert_match(/['"]one['"]/, json)
71
+ assert_match(/['"]two['"]/, json)
72
+ end
73
+ end
74
+ end
75
+ end