psych 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/.autotest +18 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +3 -0
  4. data/Manifest.txt +87 -0
  5. data/README.rdoc +50 -0
  6. data/Rakefile +66 -0
  7. data/ext/psych/emitter.c +517 -0
  8. data/ext/psych/emitter.h +8 -0
  9. data/ext/psych/extconf.rb +22 -0
  10. data/ext/psych/parser.c +384 -0
  11. data/ext/psych/parser.h +6 -0
  12. data/ext/psych/psych.c +34 -0
  13. data/ext/psych/psych.h +20 -0
  14. data/ext/psych/to_ruby.c +41 -0
  15. data/ext/psych/to_ruby.h +8 -0
  16. data/ext/psych/yaml_tree.c +24 -0
  17. data/ext/psych/yaml_tree.h +8 -0
  18. data/lib/psych.rb +263 -0
  19. data/lib/psych/coder.rb +94 -0
  20. data/lib/psych/core_ext.rb +39 -0
  21. data/lib/psych/deprecated.rb +82 -0
  22. data/lib/psych/handler.rb +221 -0
  23. data/lib/psych/json.rb +6 -0
  24. data/lib/psych/json/ruby_events.rb +19 -0
  25. data/lib/psych/json/stream.rb +15 -0
  26. data/lib/psych/json/tree_builder.rb +12 -0
  27. data/lib/psych/json/yaml_events.rb +29 -0
  28. data/lib/psych/nodes.rb +77 -0
  29. data/lib/psych/nodes/alias.rb +18 -0
  30. data/lib/psych/nodes/document.rb +60 -0
  31. data/lib/psych/nodes/mapping.rb +56 -0
  32. data/lib/psych/nodes/node.rb +52 -0
  33. data/lib/psych/nodes/scalar.rb +67 -0
  34. data/lib/psych/nodes/sequence.rb +81 -0
  35. data/lib/psych/nodes/stream.rb +37 -0
  36. data/lib/psych/omap.rb +4 -0
  37. data/lib/psych/parser.rb +47 -0
  38. data/lib/psych/scalar_scanner.rb +105 -0
  39. data/lib/psych/set.rb +4 -0
  40. data/lib/psych/stream.rb +36 -0
  41. data/lib/psych/streaming.rb +22 -0
  42. data/lib/psych/tree_builder.rb +94 -0
  43. data/lib/psych/visitors.rb +6 -0
  44. data/lib/psych/visitors/depth_first.rb +26 -0
  45. data/lib/psych/visitors/emitter.rb +44 -0
  46. data/lib/psych/visitors/json_tree.rb +21 -0
  47. data/lib/psych/visitors/to_ruby.rb +267 -0
  48. data/lib/psych/visitors/visitor.rb +19 -0
  49. data/lib/psych/visitors/yaml_tree.rb +373 -0
  50. data/test/psych/helper.rb +63 -0
  51. data/test/psych/json/test_stream.rb +109 -0
  52. data/test/psych/nodes/test_enumerable.rb +43 -0
  53. data/test/psych/test_alias_and_anchor.rb +26 -0
  54. data/test/psych/test_array.rb +19 -0
  55. data/test/psych/test_boolean.rb +36 -0
  56. data/test/psych/test_class.rb +17 -0
  57. data/test/psych/test_coder.rb +184 -0
  58. data/test/psych/test_date_time.rb +17 -0
  59. data/test/psych/test_deprecated.rb +210 -0
  60. data/test/psych/test_document.rb +46 -0
  61. data/test/psych/test_emitter.rb +94 -0
  62. data/test/psych/test_encoding.rb +179 -0
  63. data/test/psych/test_engine_manager.rb +57 -0
  64. data/test/psych/test_exception.rb +39 -0
  65. data/test/psych/test_hash.rb +30 -0
  66. data/test/psych/test_json_tree.rb +65 -0
  67. data/test/psych/test_merge_keys.rb +72 -0
  68. data/test/psych/test_nil.rb +18 -0
  69. data/test/psych/test_null.rb +19 -0
  70. data/test/psych/test_object.rb +27 -0
  71. data/test/psych/test_omap.rb +68 -0
  72. data/test/psych/test_parser.rb +297 -0
  73. data/test/psych/test_psych.rb +168 -0
  74. data/test/psych/test_scalar.rb +11 -0
  75. data/test/psych/test_scalar_scanner.rb +69 -0
  76. data/test/psych/test_serialize_subclasses.rb +38 -0
  77. data/test/psych/test_set.rb +49 -0
  78. data/test/psych/test_stream.rb +49 -0
  79. data/test/psych/test_string.rb +49 -0
  80. data/test/psych/test_struct.rb +51 -0
  81. data/test/psych/test_symbol.rb +17 -0
  82. data/test/psych/test_to_yaml_properties.rb +63 -0
  83. data/test/psych/test_tree_builder.rb +79 -0
  84. data/test/psych/test_yaml.rb +1256 -0
  85. data/test/psych/visitors/test_depth_first.rb +49 -0
  86. data/test/psych/visitors/test_emitter.rb +144 -0
  87. data/test/psych/visitors/test_to_ruby.rb +325 -0
  88. data/test/psych/visitors/test_yaml_tree.rb +155 -0
  89. metadata +232 -0
data/ext/psych/psych.h ADDED
@@ -0,0 +1,20 @@
1
+ #ifndef PSYCH_H
2
+ #define PSYCH_H
3
+
4
+ #include <ruby.h>
5
+
6
+ #ifdef HAVE_RUBY_ENCODING_H
7
+ #include <ruby/encoding.h>
8
+ #endif
9
+
10
+ #include <yaml.h>
11
+
12
+ #include <parser.h>
13
+ #include <emitter.h>
14
+ #include <to_ruby.h>
15
+ #include <yaml_tree.h>
16
+
17
+ extern VALUE mPsych;
18
+
19
+
20
+ #endif
@@ -0,0 +1,41 @@
1
+ #include <psych.h>
2
+
3
+ VALUE cPsychVisitorsToRuby;
4
+
5
+ /* call-seq: vis.build_exception(klass, message)
6
+ *
7
+ * Create an exception with class +klass+ and +message+
8
+ */
9
+ static VALUE build_exception(VALUE self, VALUE klass, VALUE mesg)
10
+ {
11
+ VALUE e = rb_obj_alloc(klass);
12
+
13
+ rb_iv_set(e, "mesg", mesg);
14
+
15
+ return e;
16
+ }
17
+
18
+ /* call-seq: vis.path2class(path)
19
+ *
20
+ * Convert +path+ string to a class
21
+ */
22
+ static VALUE path2class(VALUE self, VALUE path)
23
+ {
24
+ #ifdef HAVE_RUBY_ENCODING_H
25
+ return rb_path_to_class(path);
26
+ #else
27
+ return rb_path2class(StringValuePtr(path));
28
+ #endif
29
+ }
30
+
31
+ void Init_psych_to_ruby(void)
32
+ {
33
+ VALUE psych = rb_define_module("Psych");
34
+ VALUE visitors = rb_define_module_under(psych, "Visitors");
35
+ VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject);
36
+ cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor);
37
+
38
+ rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2);
39
+ rb_define_private_method(cPsychVisitorsToRuby, "path2class", path2class, 1);
40
+ }
41
+ /* vim: set noet sws=4 sw=4: */
@@ -0,0 +1,8 @@
1
+ #ifndef PSYCH_TO_RUBY_H
2
+ #define PSYCH_TO_RUBY_H
3
+
4
+ #include <psych.h>
5
+
6
+ void Init_psych_to_ruby(void);
7
+
8
+ #endif
@@ -0,0 +1,24 @@
1
+ #include <psych.h>
2
+
3
+ VALUE cPsychVisitorsYamlTree;
4
+
5
+ /*
6
+ * call-seq: private_iv_get(target, prop)
7
+ *
8
+ * Get the private instance variable +prop+ from +target+
9
+ */
10
+ static VALUE private_iv_get(VALUE self, VALUE target, VALUE prop)
11
+ {
12
+ return rb_attr_get(target, rb_intern(StringValuePtr(prop)));
13
+ }
14
+
15
+ void Init_psych_yaml_tree(void)
16
+ {
17
+ VALUE psych = rb_define_module("Psych");
18
+ VALUE visitors = rb_define_module_under(psych, "Visitors");
19
+ VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject);
20
+ cPsychVisitorsYamlTree = rb_define_class_under(visitors, "YAMLTree", visitor);
21
+
22
+ rb_define_private_method(cPsychVisitorsYamlTree, "private_iv_get", private_iv_get, 2);
23
+ }
24
+ /* vim: set noet sws=4 sw=4: */
@@ -0,0 +1,8 @@
1
+ #ifndef PSYCH_YAML_TREE_H
2
+ #define PSYCH_YAML_TREE_H
3
+
4
+ #include <psych.h>
5
+
6
+ void Init_psych_yaml_tree(void);
7
+
8
+ #endif
data/lib/psych.rb ADDED
@@ -0,0 +1,263 @@
1
+ require 'psych.so'
2
+ require 'psych/nodes'
3
+ require 'psych/streaming'
4
+ require 'psych/visitors'
5
+ require 'psych/handler'
6
+ require 'psych/tree_builder'
7
+ require 'psych/parser'
8
+ require 'psych/omap'
9
+ require 'psych/set'
10
+ require 'psych/coder'
11
+ require 'psych/core_ext'
12
+ require 'psych/deprecated'
13
+ require 'psych/json'
14
+
15
+ ###
16
+ # = Overview
17
+ #
18
+ # Psych is a YAML parser and emitter. Psych leverages
19
+ # libyaml[http://libyaml.org] for it's YAML parsing and emitting capabilities.
20
+ # In addition to wrapping libyaml, Psych also knows how to serialize and
21
+ # de-serialize most Ruby objects to and from the YAML format.
22
+ #
23
+ # = I NEED TO PARSE OR EMIT YAML RIGHT NOW!
24
+ #
25
+ # # Parse some YAML
26
+ # Psych.load("--- foo") # => "foo"
27
+ #
28
+ # # Emit some YAML
29
+ # Psych.dump("foo") # => "--- foo\n...\n"
30
+ # { :a => 'b'}.to_yaml # => "---\n:a: b\n"
31
+ #
32
+ # Got more time on your hands? Keep on reading!
33
+ #
34
+ # == YAML Parsing
35
+ #
36
+ # Psych provides a range of interfaces for parsing a YAML document ranging from
37
+ # low level to high level, depending on your parsing needs. At the lowest
38
+ # level, is an event based parser. Mid level is access to the raw YAML AST,
39
+ # and at the highest level is the ability to unmarshal YAML to ruby objects.
40
+ #
41
+ # === Low level parsing
42
+ #
43
+ # The lowest level parser should be used when the YAML input is already known,
44
+ # and the developer does not want to pay the price of building an AST or
45
+ # automatic detection and conversion to ruby objects. See Psych::Parser for
46
+ # more information on using the event based parser.
47
+ #
48
+ # === Mid level parsing
49
+ #
50
+ # Psych provides access to an AST produced from parsing a YAML document. This
51
+ # tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can
52
+ # be examined and manipulated freely. Please see Psych::parse_stream,
53
+ # Psych::Nodes, and Psych::Nodes::Node for more information on dealing with
54
+ # YAML syntax trees.
55
+ #
56
+ # === High level parsing
57
+ #
58
+ # The high level YAML parser provided by Psych simply takes YAML as input and
59
+ # returns a Ruby data structure. For information on using the high level parser
60
+ # see Psych.load
61
+ #
62
+ # == YAML Emitting
63
+ #
64
+ # Psych provides a range of interfaces ranging from low to high level for
65
+ # producing YAML documents. Very similar to the YAML parsing interfaces, Psych
66
+ # provides at the lowest level, an event based system, mid-level is building
67
+ # a YAML AST, and the highest level is converting a Ruby object straight to
68
+ # a YAML document.
69
+ #
70
+ # === Low level emitting
71
+ #
72
+ # The lowest level emitter is an event based system. Events are sent to a
73
+ # Psych::Emitter object. That object knows how to convert the events to a YAML
74
+ # document. This interface should be used when document format is known in
75
+ # advance or speed is a concern. See Psych::Emitter for more information.
76
+ #
77
+ # === Mid level emitting
78
+ #
79
+ # At the mid level is building an AST. This AST is exactly the same as the AST
80
+ # used when parsing a YAML document. Users can build an AST by hand and the
81
+ # AST knows how to emit itself as a YAML document. See Psych::Nodes,
82
+ # Psych::Nodes::Node, and Psych::TreeBuilder for more information on building
83
+ # a YAML AST.
84
+ #
85
+ # === High level emitting
86
+ #
87
+ # The high level emitter has the easiest interface. Psych simply takes a Ruby
88
+ # data structure and converts it to a YAML document. See Psych.dump for more
89
+ # information on dumping a Ruby data structure.
90
+
91
+ module Psych
92
+ # The version is Psych you're using
93
+ VERSION = '1.1.0'
94
+
95
+ # The version of libyaml Psych is using
96
+ LIBYAML_VERSION = Psych.libyaml_version.join '.'
97
+
98
+ class Exception < RuntimeError
99
+ end
100
+
101
+ autoload :Stream, 'psych/stream'
102
+
103
+ ###
104
+ # Load +yaml+ in to a Ruby data structure. If multiple documents are
105
+ # provided, the object contained in the first document will be returned.
106
+ #
107
+ # Example:
108
+ #
109
+ # Psych.load("--- a") # => 'a'
110
+ # Psych.load("---\n - a\n - b") # => ['a', 'b']
111
+ def self.load yaml
112
+ result = parse(yaml)
113
+ result ? result.to_ruby : result
114
+ end
115
+
116
+ ###
117
+ # Parse a YAML string in +yaml+. Returns the first object of a YAML AST.
118
+ #
119
+ # Example:
120
+ #
121
+ # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Sequence:0x00>
122
+ #
123
+ # 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
127
+ end
128
+
129
+ ###
130
+ # Parse a file at +filename+. Returns the YAML AST.
131
+ def self.parse_file filename
132
+ File.open filename do |f|
133
+ parse f
134
+ end
135
+ end
136
+
137
+ ###
138
+ # Returns a default parser
139
+ def self.parser
140
+ Psych::Parser.new(TreeBuilder.new)
141
+ end
142
+
143
+ ###
144
+ # Parse a YAML string in +yaml+. Returns the full AST for the YAML document.
145
+ # This method can handle multiple YAML documents contained in +yaml+.
146
+ #
147
+ # Example:
148
+ #
149
+ # Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00>
150
+ #
151
+ # 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
156
+ end
157
+
158
+ ###
159
+ # call-seq:
160
+ # Psych.dump(o) -> string of yaml
161
+ # Psych.dump(o, options) -> string of yaml
162
+ # Psych.dump(o, io) -> io object passed in
163
+ # Psych.dump(o, io, options) -> io object passed in
164
+ #
165
+ # Dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in
166
+ # to control the output format. If an IO object is passed in, the YAML will
167
+ # be dumped to that IO object.
168
+ #
169
+ # Example:
170
+ #
171
+ # # Dump an array, get back a YAML string
172
+ # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n"
173
+ #
174
+ # # Dump an array to an IO object
175
+ # Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890>
176
+ #
177
+ # # Dump an array with indentation set
178
+ # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n"
179
+ #
180
+ # # Dump an array to an IO with indentation set
181
+ # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3)
182
+ def self.dump o, io = nil, options = {}
183
+ if Hash === io
184
+ options = io
185
+ io = nil
186
+ end
187
+
188
+ visitor = Psych::Visitors::YAMLTree.new options
189
+ visitor << o
190
+ visitor.tree.to_yaml io, options
191
+ end
192
+
193
+ ###
194
+ # Dump a list of objects as separate documents to a document stream.
195
+ #
196
+ # Example:
197
+ #
198
+ # Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n"
199
+ def self.dump_stream *objects
200
+ visitor = Psych::Visitors::YAMLTree.new {}
201
+ objects.each do |o|
202
+ visitor << o
203
+ end
204
+ visitor.tree.to_yaml
205
+ end
206
+
207
+ ###
208
+ # Dump Ruby object +o+ to a JSON string.
209
+ def self.to_json o
210
+ visitor = Psych::Visitors::JSONTree.new
211
+ visitor << o
212
+ visitor.tree.to_yaml
213
+ end
214
+
215
+ ###
216
+ # Load multiple documents given in +yaml+. Returns the parsed documents
217
+ # as a list. For example:
218
+ #
219
+ # Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']
220
+ #
221
+ def self.load_stream yaml
222
+ parse_stream(yaml).children.map { |child| child.to_ruby }
223
+ end
224
+
225
+ ###
226
+ # Load the document contained in +filename+. Returns the yaml contained in
227
+ # +filename+ as a ruby object
228
+ def self.load_file filename
229
+ self.load File.open(filename)
230
+ end
231
+
232
+ # :stopdoc:
233
+ @domain_types = {}
234
+ def self.add_domain_type domain, type_tag, &block
235
+ key = ['tag', domain, type_tag].join ':'
236
+ @domain_types[key] = [key, block]
237
+ @domain_types["tag:#{type_tag}"] = [key, block]
238
+ end
239
+
240
+ def self.add_builtin_type type_tag, &block
241
+ domain = 'yaml.org,2002'
242
+ key = ['tag', domain, type_tag].join ':'
243
+ @domain_types[key] = [key, block]
244
+ end
245
+
246
+ def self.remove_type type_tag
247
+ @domain_types.delete type_tag
248
+ end
249
+
250
+ @load_tags = {}
251
+ @dump_tags = {}
252
+ def self.add_tag tag, klass
253
+ @load_tags[tag] = klass
254
+ @dump_tags[klass] = tag
255
+ end
256
+
257
+ class << self
258
+ attr_accessor :load_tags
259
+ attr_accessor :dump_tags
260
+ attr_accessor :domain_types
261
+ end
262
+ # :startdoc:
263
+ end
@@ -0,0 +1,94 @@
1
+ module Psych
2
+ ###
3
+ # If an object defines +encode_with+, then an instance of Psych::Coder will
4
+ # be passed to the method when the object is being serialized. The Coder
5
+ # automatically assumes a Psych::Nodes::Mapping is being emitted. Other
6
+ # objects like Sequence and Scalar may be emitted if +seq=+ or +scalar=+ are
7
+ # called, respectively.
8
+ class Coder
9
+ attr_accessor :tag, :style, :implicit, :object
10
+ attr_reader :type, :seq
11
+
12
+ def initialize tag
13
+ @map = {}
14
+ @seq = []
15
+ @implicit = false
16
+ @type = :map
17
+ @tag = tag
18
+ @style = Psych::Nodes::Mapping::BLOCK
19
+ @scalar = nil
20
+ @object = nil
21
+ end
22
+
23
+ def scalar *args
24
+ if args.length > 0
25
+ warn "#{caller[0]}: Coder#scalar(a,b,c) is deprecated" if $VERBOSE
26
+ @tag, @scalar, _ = args
27
+ @type = :scalar
28
+ end
29
+ @scalar
30
+ end
31
+
32
+ # Emit a map. The coder will be yielded to the block.
33
+ def map tag = @tag, style = @style
34
+ @tag = tag
35
+ @style = style
36
+ yield self if block_given?
37
+ @map
38
+ end
39
+
40
+ # Emit a scalar with +value+ and +tag+
41
+ def represent_scalar tag, value
42
+ self.tag = tag
43
+ self.scalar = value
44
+ end
45
+
46
+ # Emit a sequence with +list+ and +tag+
47
+ def represent_seq tag, list
48
+ @tag = tag
49
+ self.seq = list
50
+ end
51
+
52
+ # Emit a sequence with +map+ and +tag+
53
+ def represent_map tag, map
54
+ @tag = tag
55
+ self.map = map
56
+ end
57
+
58
+ # Emit an arbitrary object +obj+ and +tag+
59
+ def represent_object tag, obj
60
+ @tag = tag
61
+ @type = :object
62
+ @object = obj
63
+ end
64
+
65
+ # Emit a scalar with +value+
66
+ def scalar= value
67
+ @type = :scalar
68
+ @scalar = value
69
+ end
70
+
71
+ # Emit a map with +value+
72
+ def map= map
73
+ @type = :map
74
+ @map = map
75
+ end
76
+
77
+ def []= k, v
78
+ @type = :map
79
+ @map[k] = v
80
+ end
81
+ alias :add :[]=
82
+
83
+ def [] k
84
+ @type = :map
85
+ @map[k]
86
+ end
87
+
88
+ # Emit a sequence of +list+
89
+ def seq= list
90
+ @type = :seq
91
+ @seq = list
92
+ end
93
+ end
94
+ end