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,53 @@
1
+ module Psych
2
+ ###
3
+ # Psych::Stream is a streaming YAML emitter. It will not buffer your YAML,
4
+ # but send it straight to an IO.
5
+ #
6
+ # Here is an example use:
7
+ #
8
+ # stream = Psych::Stream.new($stdout)
9
+ # stream.start
10
+ # stream.push({:foo => 'bar'})
11
+ # stream.finish
12
+ #
13
+ # YAML will be immediately emitted to $stdout with no buffering.
14
+ #
15
+ # Psych::Stream#start will take a block and ensure that Psych::Stream#finish
16
+ # is called, so you can do this form:
17
+ #
18
+ # stream = Psych::Stream.new($stdout)
19
+ # stream.start do |em|
20
+ # em.push(:foo => 'bar')
21
+ # end
22
+ #
23
+ class Stream < Psych::Visitors::YAMLTree
24
+ class Emitter < Psych::Emitter # :nodoc:
25
+ def end_document implicit_end = !streaming?
26
+ super
27
+ end
28
+
29
+ def streaming?
30
+ true
31
+ end
32
+ end
33
+
34
+ ###
35
+ # Create a new streaming emitter. Emitter will print to +io+. See
36
+ # Psych::Stream for an example.
37
+ def initialize io
38
+ super({}, self.class.const_get(:Emitter).new(io))
39
+ end
40
+
41
+ ###
42
+ # Start streaming using +encoding+
43
+ def start encoding = Nodes::Stream::UTF8
44
+ super.tap { yield self if block_given? }
45
+ ensure
46
+ finish if block_given?
47
+ end
48
+
49
+ private
50
+ def register target, obj
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,94 @@
1
+ require 'psych/handler'
2
+
3
+ module Psych
4
+ ###
5
+ # This class works in conjunction with Psych::Parser to build an in-memory
6
+ # parse tree that represents a YAML document.
7
+ #
8
+ # == Example
9
+ #
10
+ # parser = Psych::Parser.new Psych::TreeBuilder.new
11
+ # parser.parse('--- foo')
12
+ # tree = parser.handler.root
13
+ #
14
+ # See Psych::Handler for documentation on the event methods used in this
15
+ # class.
16
+ class TreeBuilder < Psych::Handler
17
+ # Returns the root node for the built tree
18
+ attr_reader :root
19
+
20
+ # Create a new TreeBuilder instance
21
+ def initialize
22
+ @stack = []
23
+ @last = nil
24
+ @root = nil
25
+ end
26
+
27
+ %w{
28
+ Sequence
29
+ Mapping
30
+ }.each do |node|
31
+ class_eval %{
32
+ def start_#{node.downcase}(anchor, tag, implicit, style)
33
+ n = Nodes::#{node}.new(anchor, tag, implicit, style)
34
+ @last.children << n
35
+ push n
36
+ end
37
+
38
+ def end_#{node.downcase}
39
+ pop
40
+ end
41
+ }
42
+ end
43
+
44
+ ###
45
+ # Handles start_document events with +version+, +tag_directives+,
46
+ # and +implicit+ styling.
47
+ #
48
+ # See Psych::Handler#start_document
49
+ def start_document version, tag_directives, implicit
50
+ n = Nodes::Document.new version, tag_directives, implicit
51
+ @last.children << n
52
+ push n
53
+ end
54
+
55
+ ###
56
+ # Handles end_document events with +version+, +tag_directives+,
57
+ # and +implicit+ styling.
58
+ #
59
+ # See Psych::Handler#start_document
60
+ def end_document implicit_end = !streaming?
61
+ @last.implicit_end = implicit_end
62
+ pop
63
+ end
64
+
65
+ def start_stream encoding
66
+ @root = Nodes::Stream.new(encoding)
67
+ push @root
68
+ end
69
+
70
+ def end_stream
71
+ pop
72
+ end
73
+
74
+ def scalar value, anchor, tag, plain, quoted, style
75
+ @last.children << Nodes::Scalar.new(value,anchor,tag,plain,quoted,style)
76
+ end
77
+
78
+ def alias anchor
79
+ @last.children << Nodes::Alias.new(anchor)
80
+ end
81
+
82
+ private
83
+ def push value
84
+ @stack.push value
85
+ @last = value
86
+ end
87
+
88
+ def pop
89
+ x = @stack.pop
90
+ @last = @stack.last
91
+ x
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,5 @@
1
+ require 'psych/visitors/visitor'
2
+ require 'psych/visitors/to_ruby'
3
+ require 'psych/visitors/emitter'
4
+ require 'psych/visitors/yaml_tree'
5
+ require 'psych/visitors/json_tree'
@@ -0,0 +1,41 @@
1
+ module Psych
2
+ module Visitors
3
+ class Emitter < Psych::Visitors::Visitor
4
+ def initialize io
5
+ @handler = Psych::Emitter.new io
6
+ end
7
+
8
+ def visit_Psych_Nodes_Stream o
9
+ @handler.start_stream o.encoding
10
+ o.children.each { |c| accept c }
11
+ @handler.end_stream
12
+ end
13
+
14
+ def visit_Psych_Nodes_Document o
15
+ @handler.start_document o.version, o.tag_directives, o.implicit
16
+ o.children.each { |c| accept c }
17
+ @handler.end_document o.implicit_end
18
+ end
19
+
20
+ def visit_Psych_Nodes_Scalar o
21
+ @handler.scalar o.value, o.anchor, o.tag, o.plain, o.quoted, o.style
22
+ end
23
+
24
+ def visit_Psych_Nodes_Sequence o
25
+ @handler.start_sequence o.anchor, o.tag, o.implicit, o.style
26
+ o.children.each { |c| accept c }
27
+ @handler.end_sequence
28
+ end
29
+
30
+ def visit_Psych_Nodes_Mapping o
31
+ @handler.start_mapping o.anchor, o.tag, o.implicit, o.style
32
+ o.children.each { |c| accept c }
33
+ @handler.end_mapping
34
+ end
35
+
36
+ def visit_Psych_Nodes_Alias o
37
+ @handler.alias o.anchor
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ module Psych
2
+ module Visitors
3
+ class JSONTree < YAMLTree
4
+ def initialize options = {}, emitter = Psych::JSON::TreeBuilder.new
5
+ super
6
+ end
7
+
8
+ def visit_String o
9
+ @emitter.scalar o.to_s, nil, nil, false, true, Nodes::Scalar::ANY
10
+ end
11
+ alias :visit_Symbol :visit_String
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,263 @@
1
+ require 'psych/scalar_scanner'
2
+
3
+ module Psych
4
+ module Visitors
5
+ ###
6
+ # This class walks a YAML AST, converting each node to ruby
7
+ class ToRuby < Psych::Visitors::Visitor
8
+ def initialize
9
+ super
10
+ @st = {}
11
+ @ss = ScalarScanner.new
12
+ @domain_types = Psych.domain_types
13
+ end
14
+
15
+ def accept target
16
+ result = super
17
+ return result if @domain_types.empty? || !target.tag
18
+
19
+ key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:')
20
+ key = "tag:#{key}" unless key =~ /^(tag:|x-private)/
21
+
22
+ if @domain_types.key? key
23
+ value, block = @domain_types[key]
24
+ return block.call value, result
25
+ end
26
+
27
+ result
28
+ end
29
+
30
+ def visit_Psych_Nodes_Scalar o
31
+ @st[o.anchor] = o.value if o.anchor
32
+
33
+ if klass = Psych.load_tags[o.tag]
34
+ instance = klass.allocate
35
+
36
+ if instance.respond_to?(:init_with)
37
+ coder = Psych::Coder.new(o.tag)
38
+ coder.scalar = o.value
39
+ instance.init_with coder
40
+ end
41
+
42
+ return instance
43
+ end
44
+
45
+ return o.value if o.quoted
46
+ return @ss.tokenize(o.value) unless o.tag
47
+
48
+ case o.tag
49
+ when '!binary', 'tag:yaml.org,2002:binary'
50
+ o.value.unpack('m').first
51
+ when '!str', 'tag:yaml.org,2002:str'
52
+ o.value
53
+ when "!ruby/object:DateTime"
54
+ require 'date'
55
+ @ss.parse_time(o.value).to_datetime
56
+ when "!ruby/object:Complex"
57
+ Complex(o.value)
58
+ when "!ruby/object:Rational"
59
+ Rational(o.value)
60
+ when "tag:yaml.org,2002:float", "!float"
61
+ Float(@ss.tokenize(o.value))
62
+ when "!ruby/regexp"
63
+ o.value =~ /^\/(.*)\/([mix]*)$/
64
+ source = $1
65
+ options = 0
66
+ lang = nil
67
+ ($2 || '').split('').each do |option|
68
+ case option
69
+ when 'x' then options |= Regexp::EXTENDED
70
+ when 'i' then options |= Regexp::IGNORECASE
71
+ when 'm' then options |= Regexp::MULTILINE
72
+ else lang = option
73
+ end
74
+ end
75
+ Regexp.new(*[source, options, lang].compact)
76
+ when "!ruby/range"
77
+ args = o.value.split(/([.]{2,3})/, 2).map { |s|
78
+ accept Nodes::Scalar.new(s)
79
+ }
80
+ args.push(args.delete_at(1) == '...')
81
+ Range.new(*args)
82
+ when /^!ruby\/sym(bol)?:?(.*)?$/
83
+ o.value.to_sym
84
+ else
85
+ @ss.tokenize o.value
86
+ end
87
+ end
88
+
89
+ def visit_Psych_Nodes_Sequence o
90
+ if klass = Psych.load_tags[o.tag]
91
+ instance = klass.allocate
92
+
93
+ if instance.respond_to?(:init_with)
94
+ coder = Psych::Coder.new(o.tag)
95
+ coder.seq = o.children.map { |c| accept c }
96
+ instance.init_with coder
97
+ end
98
+
99
+ return instance
100
+ end
101
+
102
+ case o.tag
103
+ when '!omap', 'tag:yaml.org,2002:omap'
104
+ map = Psych::Omap.new
105
+ @st[o.anchor] = map if o.anchor
106
+ o.children.each { |a|
107
+ map[accept(a.children.first)] = accept a.children.last
108
+ }
109
+ map
110
+ else
111
+ list = []
112
+ @st[o.anchor] = list if o.anchor
113
+ o.children.each { |c| list.push accept c }
114
+ list
115
+ end
116
+ end
117
+
118
+ def visit_Psych_Nodes_Mapping o
119
+ return revive(Psych.load_tags[o.tag], o) if Psych.load_tags[o.tag]
120
+
121
+ case o.tag
122
+ when '!str', 'tag:yaml.org,2002:str'
123
+ members = Hash[*o.children.map { |c| accept c }]
124
+ string = members.delete 'str'
125
+ init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o)
126
+ when /^!ruby\/struct:?(.*)?$/
127
+ klass = resolve_class($1)
128
+
129
+ if klass
130
+ s = klass.allocate
131
+ @st[o.anchor] = s if o.anchor
132
+
133
+ members = {}
134
+ struct_members = s.members.map { |x| x.to_sym }
135
+ o.children.each_slice(2) do |k,v|
136
+ member = accept(k)
137
+ value = accept(v)
138
+ if struct_members.include?(member.to_sym)
139
+ s.send("#{member}=", value)
140
+ else
141
+ members[member.to_s.sub(/^@/, '')] = value
142
+ end
143
+ end
144
+ init_with(s, members, o)
145
+ else
146
+ members = o.children.map { |c| accept c }
147
+ h = Hash[*members]
148
+ Struct.new(*h.map { |k,v| k.to_sym }).new(*h.map { |k,v| v })
149
+ end
150
+
151
+ when '!ruby/range'
152
+ h = Hash[*o.children.map { |c| accept c }]
153
+ Range.new(h['begin'], h['end'], h['excl'])
154
+
155
+ when /^!ruby\/exception:?(.*)?$/
156
+ h = Hash[*o.children.map { |c| accept c }]
157
+
158
+ e = build_exception((resolve_class($1) || Exception),
159
+ h.delete('message'))
160
+ init_with(e, h, o)
161
+
162
+ when '!set', 'tag:yaml.org,2002:set'
163
+ set = Psych::Set.new
164
+ @st[o.anchor] = set if o.anchor
165
+ o.children.each_slice(2) do |k,v|
166
+ set[accept(k)] = accept(v)
167
+ end
168
+ set
169
+
170
+ when '!ruby/object:Complex'
171
+ h = Hash[*o.children.map { |c| accept c }]
172
+ Complex(h['real'], h['image'])
173
+
174
+ when '!ruby/object:Rational'
175
+ h = Hash[*o.children.map { |c| accept c }]
176
+ Rational(h['numerator'], h['denominator'])
177
+
178
+ when /^!ruby\/object:?(.*)?$/
179
+ name = $1 || 'Object'
180
+ obj = revive((resolve_class(name) || Object), o)
181
+ @st[o.anchor] = obj if o.anchor
182
+ obj
183
+ else
184
+ hash = {}
185
+ @st[o.anchor] = hash if o.anchor
186
+
187
+ o.children.each_slice(2) { |k,v|
188
+ key = accept(k)
189
+
190
+ if key == '<<' && Nodes::Alias === v
191
+ # FIXME: remove this when "<<" syntax is deprecated
192
+ if $VERBOSE
193
+ where = caller.find { |x| x !~ /psych/ }
194
+ warn where
195
+ warn "\"<<: *#{v.anchor}\" is no longer supported, please switch to \"*#{v.anchor}\""
196
+ end
197
+ return accept(v)
198
+ else
199
+ hash[key] = accept(v)
200
+ end
201
+
202
+ }
203
+ hash
204
+ end
205
+ end
206
+
207
+ def visit_Psych_Nodes_Document o
208
+ accept o.root
209
+ end
210
+
211
+ def visit_Psych_Nodes_Stream o
212
+ o.children.map { |c| accept c }
213
+ end
214
+
215
+ def visit_Psych_Nodes_Alias o
216
+ @st[o.anchor]
217
+ end
218
+
219
+ private
220
+ def revive klass, node
221
+ s = klass.allocate
222
+ h = Hash[*node.children.map { |c| accept c }]
223
+ init_with(s, h, node)
224
+ end
225
+
226
+ def init_with o, h, node
227
+ c = Psych::Coder.new(node.tag)
228
+ c.map = h
229
+
230
+ if o.respond_to?(:init_with)
231
+ o.init_with c
232
+ elsif o.respond_to?(:yaml_initialize)
233
+ if $VERBOSE
234
+ "Implementing #{o.class}#yaml_initialize is deprecated, please implement \"init_with(coder)\""
235
+ end
236
+ o.yaml_initialize c.tag, c.map
237
+ else
238
+ h.each { |k,v| o.instance_variable_set(:"@#{k}", v) }
239
+ end
240
+ o
241
+ end
242
+
243
+ # Convert +klassname+ to a Class
244
+ def resolve_class klassname
245
+ return nil unless klassname and not klassname.empty?
246
+
247
+ name = klassname
248
+ retried = false
249
+
250
+ begin
251
+ path2class(name)
252
+ rescue ArgumentError, NameError => ex
253
+ unless retried
254
+ name = "Struct::#{name}"
255
+ retried = ex
256
+ retry
257
+ end
258
+ raise retried
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end