km-psych 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +129 -0
- data/ext/psych/emitter.c +488 -0
- data/ext/psych/emitter.h +8 -0
- data/ext/psych/extconf.rb +22 -0
- data/ext/psych/parser.c +349 -0
- data/ext/psych/parser.h +6 -0
- data/ext/psych/psych.c +34 -0
- data/ext/psych/psych.h +20 -0
- data/ext/psych/to_ruby.c +41 -0
- data/ext/psych/to_ruby.h +8 -0
- data/ext/psych/yaml_tree.c +24 -0
- data/ext/psych/yaml_tree.h +8 -0
- data/lib/km-psych.rb +244 -0
- data/lib/psych/coder.rb +86 -0
- data/lib/psych/core_ext.rb +38 -0
- data/lib/psych/deprecated.rb +82 -0
- data/lib/psych/handler.rb +221 -0
- data/lib/psych/json.rb +6 -0
- data/lib/psych/json/stream.rb +32 -0
- data/lib/psych/json/tree_builder.rb +32 -0
- data/lib/psych/nodes.rb +77 -0
- data/lib/psych/nodes/alias.rb +18 -0
- data/lib/psych/nodes/document.rb +60 -0
- data/lib/psych/nodes/mapping.rb +56 -0
- data/lib/psych/nodes/node.rb +42 -0
- data/lib/psych/nodes/scalar.rb +67 -0
- data/lib/psych/nodes/sequence.rb +81 -0
- data/lib/psych/nodes/stream.rb +37 -0
- data/lib/psych/omap.rb +4 -0
- data/lib/psych/parser.rb +44 -0
- data/lib/psych/scalar_scanner.rb +105 -0
- data/lib/psych/set.rb +4 -0
- data/lib/psych/stream.rb +53 -0
- data/lib/psych/tree_builder.rb +94 -0
- data/lib/psych/visitors.rb +5 -0
- data/lib/psych/visitors/emitter.rb +41 -0
- data/lib/psych/visitors/json_tree.rb +14 -0
- data/lib/psych/visitors/to_ruby.rb +263 -0
- data/lib/psych/visitors/visitor.rb +27 -0
- data/lib/psych/visitors/yaml_tree.rb +342 -0
- data/test/psych/helper.rb +63 -0
- data/test/psych/json/test_stream.rb +75 -0
- data/test/psych/test_alias_and_anchor.rb +26 -0
- data/test/psych/test_array.rb +19 -0
- data/test/psych/test_boolean.rb +36 -0
- data/test/psych/test_class.rb +17 -0
- data/test/psych/test_coder.rb +169 -0
- data/test/psych/test_date_time.rb +17 -0
- data/test/psych/test_deprecated.rb +210 -0
- data/test/psych/test_document.rb +46 -0
- data/test/psych/test_emitter.rb +88 -0
- data/test/psych/test_encoding.rb +179 -0
- data/test/psych/test_engine_manager.rb +57 -0
- data/test/psych/test_exception.rb +39 -0
- data/test/psych/test_hash.rb +30 -0
- data/test/psych/test_json_tree.rb +43 -0
- data/test/psych/test_null.rb +19 -0
- data/test/psych/test_object.rb +27 -0
- data/test/psych/test_omap.rb +68 -0
- data/test/psych/test_parser.rb +216 -0
- data/test/psych/test_psych.rb +133 -0
- data/test/psych/test_scalar.rb +11 -0
- data/test/psych/test_scalar_scanner.rb +70 -0
- data/test/psych/test_serialize_subclasses.rb +38 -0
- data/test/psych/test_set.rb +49 -0
- data/test/psych/test_stream.rb +49 -0
- data/test/psych/test_string.rb +49 -0
- data/test/psych/test_struct.rb +51 -0
- data/test/psych/test_symbol.rb +17 -0
- data/test/psych/test_to_yaml_properties.rb +63 -0
- data/test/psych/test_tree_builder.rb +79 -0
- data/test/psych/test_yaml.rb +1251 -0
- data/test/psych/visitors/test_emitter.rb +124 -0
- data/test/psych/visitors/test_to_ruby.rb +325 -0
- data/test/psych/visitors/test_yaml_tree.rb +149 -0
- metadata +187 -0
data/lib/psych/stream.rb
ADDED
@@ -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,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
|