syck 1.0.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/.autotest.erb +8 -0
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +6 -0
- data/Manifest.txt +52 -0
- data/README.rdoc +51 -0
- data/Rakefile +32 -0
- data/ext/syck/bytecode.c +1165 -0
- data/ext/syck/emitter.c +1247 -0
- data/ext/syck/extconf.h +3 -0
- data/ext/syck/extconf.rb +5 -0
- data/ext/syck/gram.c +1894 -0
- data/ext/syck/gram.h +79 -0
- data/ext/syck/handler.c +173 -0
- data/ext/syck/implicit.c +2990 -0
- data/ext/syck/node.c +407 -0
- data/ext/syck/rubyext.c +2328 -0
- data/ext/syck/syck.c +524 -0
- data/ext/syck/syck.h +453 -0
- data/ext/syck/token.c +2724 -0
- data/ext/syck/yaml2byte.c +259 -0
- data/ext/syck/yamlbyte.h +171 -0
- data/lib/syck.bundle +0 -0
- data/lib/syck.rb +447 -0
- data/lib/syck/baseemitter.rb +242 -0
- data/lib/syck/basenode.rb +222 -0
- data/lib/syck/constants.rb +45 -0
- data/lib/syck/encoding.rb +35 -0
- data/lib/syck/error.rb +34 -0
- data/lib/syck/loader.rb +14 -0
- data/lib/syck/rubytypes.rb +450 -0
- data/lib/syck/stream.rb +41 -0
- data/lib/syck/stringio.rb +85 -0
- data/lib/syck/syck.rb +16 -0
- data/lib/syck/tag.rb +95 -0
- data/lib/syck/types.rb +192 -0
- data/lib/syck/yamlnode.rb +54 -0
- data/lib/syck/ypath.rb +54 -0
- data/lib/yaml/syck.rb +14 -0
- data/test/helper.rb +2 -0
- data/test/test_array.rb +13 -0
- data/test/test_boolean.rb +36 -0
- data/test/test_class.rb +11 -0
- data/test/test_exception.rb +45 -0
- data/test/test_hash.rb +24 -0
- data/test/test_null.rb +19 -0
- data/test/test_omap.rb +55 -0
- data/test/test_set.rb +30 -0
- data/test/test_string.rb +44 -0
- data/test/test_struct.rb +32 -0
- data/test/test_symbol.rb +21 -0
- data/test/test_time.rb +23 -0
- data/test/test_yaml.rb +1403 -0
- data/test/test_yaml_properties.rb +63 -0
- metadata +187 -0
@@ -0,0 +1,242 @@
|
|
1
|
+
#
|
2
|
+
# BaseEmitter
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'syck/constants'
|
6
|
+
require 'syck/encoding'
|
7
|
+
require 'syck/error'
|
8
|
+
|
9
|
+
module Syck
|
10
|
+
module BaseEmitter
|
11
|
+
def options( opt = nil )
|
12
|
+
if opt
|
13
|
+
@options[opt] || DEFAULTS[opt]
|
14
|
+
else
|
15
|
+
@options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def options=( opt )
|
20
|
+
@options = opt
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Emit binary data
|
25
|
+
#
|
26
|
+
def binary_base64( value )
|
27
|
+
self << "!binary "
|
28
|
+
self.node_text( [value].pack("m"), '|' )
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Emit plain, normal flowing text
|
33
|
+
#
|
34
|
+
def node_text( value, block = nil )
|
35
|
+
@seq_map = false
|
36
|
+
valx = value.dup
|
37
|
+
unless block
|
38
|
+
block =
|
39
|
+
if options(:UseBlock)
|
40
|
+
'|'
|
41
|
+
elsif not options(:UseFold) and valx =~ /\n[ \t]/ and not valx =~ /#{ESCAPE_CHAR}/
|
42
|
+
'|'
|
43
|
+
else
|
44
|
+
'>'
|
45
|
+
end
|
46
|
+
indt = $&.to_i if block =~ /\d+/
|
47
|
+
if valx =~ /(\A\n*[ \t#]|^---\s+)/
|
48
|
+
indt = options(:Indent) unless indt.to_i > 0
|
49
|
+
block += indt.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
block +=
|
53
|
+
if valx =~ /\n\Z\n/
|
54
|
+
"+"
|
55
|
+
elsif valx =~ /\Z\n/
|
56
|
+
""
|
57
|
+
else
|
58
|
+
"-"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
block += "\n"
|
62
|
+
if block[0] == ?"
|
63
|
+
esc_skip = ( "\t\n" unless valx =~ /^[ \t]/ ) || ""
|
64
|
+
valx = fold( Syck.escape( valx, esc_skip ) + "\"" ).chomp
|
65
|
+
self << '"' + indent_text( valx, indt, false )
|
66
|
+
else
|
67
|
+
if block[0] == ?>
|
68
|
+
valx = fold( valx )
|
69
|
+
end
|
70
|
+
#p [block, indt]
|
71
|
+
self << block + indent_text( valx, indt )
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Emit a simple, unqouted string
|
77
|
+
#
|
78
|
+
def simple( value )
|
79
|
+
@seq_map = false
|
80
|
+
self << value.to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Emit double-quoted string
|
85
|
+
#
|
86
|
+
def double( value )
|
87
|
+
"\"#{Syck.escape( value )}\""
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Emit single-quoted string
|
92
|
+
#
|
93
|
+
def single( value )
|
94
|
+
"'#{value}'"
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Write a text block with the current indent
|
99
|
+
#
|
100
|
+
def indent_text( text, mod, first_line = true )
|
101
|
+
return "" if text.to_s.empty?
|
102
|
+
spacing = indent( mod )
|
103
|
+
text = text.gsub( /\A([^\n])/, "#{ spacing }\\1" ) if first_line
|
104
|
+
return text.gsub( /\n^([^\n])/, "\n#{spacing}\\1" )
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# Write a current indent
|
109
|
+
#
|
110
|
+
def indent( mod = nil )
|
111
|
+
#p [ self.id, level, mod, :INDENT ]
|
112
|
+
if level <= 0
|
113
|
+
mod ||= 0
|
114
|
+
else
|
115
|
+
mod ||= options(:Indent)
|
116
|
+
mod += ( level - 1 ) * options(:Indent)
|
117
|
+
end
|
118
|
+
return " " * mod
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Add indent to the buffer
|
123
|
+
#
|
124
|
+
def indent!
|
125
|
+
self << indent
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Folding paragraphs within a column
|
130
|
+
#
|
131
|
+
def fold( value )
|
132
|
+
value.gsub( /(^[ \t]+.*$)|(\S.{0,#{options(:BestWidth) - 1}})(?:[ \t]+|(\n+(?=[ \t]|\Z))|$)/ ) do
|
133
|
+
$1 || $2 + ( $3 || "\n" )
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# Quick mapping
|
139
|
+
#
|
140
|
+
def map( type, &e )
|
141
|
+
val = Mapping.new
|
142
|
+
e.call( val )
|
143
|
+
self << "#{type} " if type.length.nonzero?
|
144
|
+
|
145
|
+
#
|
146
|
+
# Empty hashes
|
147
|
+
#
|
148
|
+
if val.length.zero?
|
149
|
+
self << "{}"
|
150
|
+
@seq_map = false
|
151
|
+
else
|
152
|
+
# FIXME
|
153
|
+
# if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero?
|
154
|
+
# @headless = 1
|
155
|
+
# end
|
156
|
+
|
157
|
+
defkey = @options.delete( :DefaultKey )
|
158
|
+
if defkey
|
159
|
+
seq_map_shortcut
|
160
|
+
self << "= : "
|
161
|
+
defkey.to_yaml( :Emitter => self )
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# Emit the key and value
|
166
|
+
#
|
167
|
+
val.each { |v|
|
168
|
+
seq_map_shortcut
|
169
|
+
if v[0].is_complex_yaml?
|
170
|
+
self << "? "
|
171
|
+
end
|
172
|
+
v[0].to_yaml( :Emitter => self )
|
173
|
+
if v[0].is_complex_yaml?
|
174
|
+
self << "\n"
|
175
|
+
indent!
|
176
|
+
end
|
177
|
+
self << ": "
|
178
|
+
v[1].to_yaml( :Emitter => self )
|
179
|
+
}
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def seq_map_shortcut
|
184
|
+
# FIXME: seq_map needs to work with the new anchoring system
|
185
|
+
# if @seq_map
|
186
|
+
# @anchor_extras[@buffer.length - 1] = "\n" + indent
|
187
|
+
# @seq_map = false
|
188
|
+
# else
|
189
|
+
self << "\n"
|
190
|
+
indent!
|
191
|
+
# end
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
# Quick sequence
|
196
|
+
#
|
197
|
+
def seq( type, &e )
|
198
|
+
@seq_map = false
|
199
|
+
val = Sequence.new
|
200
|
+
e.call( val )
|
201
|
+
self << "#{type} " if type.length.nonzero?
|
202
|
+
|
203
|
+
#
|
204
|
+
# Empty arrays
|
205
|
+
#
|
206
|
+
if val.length.zero?
|
207
|
+
self << "[]"
|
208
|
+
else
|
209
|
+
# FIXME
|
210
|
+
# if @buffer.length == 1 and options(:UseHeader) == false and type.length.zero?
|
211
|
+
# @headless = 1
|
212
|
+
# end
|
213
|
+
|
214
|
+
#
|
215
|
+
# Emit the key and value
|
216
|
+
#
|
217
|
+
val.each { |v|
|
218
|
+
self << "\n"
|
219
|
+
indent!
|
220
|
+
self << "- "
|
221
|
+
@seq_map = true if v.class == Hash
|
222
|
+
v.to_yaml( :Emitter => self )
|
223
|
+
}
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
#
|
229
|
+
# Emitter helper classes
|
230
|
+
#
|
231
|
+
class Mapping < Array
|
232
|
+
def add( k, v )
|
233
|
+
push [k, v]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
class Sequence < Array
|
238
|
+
def add( v )
|
239
|
+
push v
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
#
|
2
|
+
# YAML::BaseNode class
|
3
|
+
#
|
4
|
+
|
5
|
+
module Syck
|
6
|
+
|
7
|
+
#
|
8
|
+
# YAML Generic Model container
|
9
|
+
#
|
10
|
+
module BaseNode
|
11
|
+
|
12
|
+
#
|
13
|
+
# Search for YPath entry and return
|
14
|
+
# qualified nodes.
|
15
|
+
#
|
16
|
+
def select( ypath_str )
|
17
|
+
warn "#{caller[0]}: select is deprecated" if $VERBOSE
|
18
|
+
matches = match_path( ypath_str )
|
19
|
+
|
20
|
+
#
|
21
|
+
# Create a new generic view of the elements selected
|
22
|
+
#
|
23
|
+
if matches
|
24
|
+
result = []
|
25
|
+
matches.each { |m|
|
26
|
+
result.push m.last
|
27
|
+
}
|
28
|
+
Syck.transfer( 'seq', result )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Search for YPath entry and return
|
34
|
+
# transformed nodes.
|
35
|
+
#
|
36
|
+
def select!( ypath_str )
|
37
|
+
warn "#{caller[0]}: select!() is deprecated" if $VERBOSE
|
38
|
+
matches = match_path( ypath_str )
|
39
|
+
|
40
|
+
#
|
41
|
+
# Create a new generic view of the elements selected
|
42
|
+
#
|
43
|
+
if matches
|
44
|
+
result = []
|
45
|
+
matches.each { |m|
|
46
|
+
result.push m.last.transform
|
47
|
+
}
|
48
|
+
result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Search for YPath entry and return a list of
|
54
|
+
# qualified paths.
|
55
|
+
#
|
56
|
+
def search( ypath_str )
|
57
|
+
warn "#{caller[0]}: search() is deprecated" if $VERBOSE
|
58
|
+
matches = match_path( ypath_str )
|
59
|
+
|
60
|
+
if matches
|
61
|
+
matches.collect { |m|
|
62
|
+
path = []
|
63
|
+
m.each_index { |i|
|
64
|
+
path.push m[i] if ( i % 2 ).zero?
|
65
|
+
}
|
66
|
+
"/" + path.compact.join( "/" )
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def at( seg )
|
72
|
+
warn "#{caller[0]}: at() is deprecated" if $VERBOSE
|
73
|
+
if Hash === @value
|
74
|
+
self[seg]
|
75
|
+
elsif Array === @value and seg =~ /\A\d+\Z/ and @value[seg.to_i]
|
76
|
+
@value[seg.to_i]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# YPath search returning a complete depth array
|
82
|
+
#
|
83
|
+
def match_path( ypath_str )
|
84
|
+
warn "#{caller[0]}: match_path is deprecated" if $VERBOSE
|
85
|
+
require 'syck/ypath'
|
86
|
+
matches = []
|
87
|
+
YPath.each_path( ypath_str ) do |ypath|
|
88
|
+
seg = match_segment( ypath, 0 )
|
89
|
+
matches += seg if seg
|
90
|
+
end
|
91
|
+
matches.uniq
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Search a node for a single YPath segment
|
96
|
+
#
|
97
|
+
def match_segment( ypath, depth )
|
98
|
+
warn "#{caller[0]}: match_segment is deprecated" if $VERBOSE
|
99
|
+
deep_nodes = []
|
100
|
+
seg = ypath.segments[ depth ]
|
101
|
+
if seg == "/"
|
102
|
+
unless String === @value
|
103
|
+
idx = -1
|
104
|
+
@value.collect { |v|
|
105
|
+
idx += 1
|
106
|
+
if Hash === @value
|
107
|
+
match_init = [v[0].transform, v[1]]
|
108
|
+
match_deep = v[1].match_segment( ypath, depth )
|
109
|
+
else
|
110
|
+
match_init = [idx, v]
|
111
|
+
match_deep = v.match_segment( ypath, depth )
|
112
|
+
end
|
113
|
+
if match_deep
|
114
|
+
match_deep.each { |m|
|
115
|
+
deep_nodes.push( match_init + m )
|
116
|
+
}
|
117
|
+
end
|
118
|
+
}
|
119
|
+
end
|
120
|
+
depth += 1
|
121
|
+
seg = ypath.segments[ depth ]
|
122
|
+
end
|
123
|
+
match_nodes =
|
124
|
+
case seg
|
125
|
+
when "."
|
126
|
+
[[nil, self]]
|
127
|
+
when ".."
|
128
|
+
[["..", nil]]
|
129
|
+
when "*"
|
130
|
+
if @value.is_a? Enumerable
|
131
|
+
idx = -1
|
132
|
+
@value.collect { |h|
|
133
|
+
idx += 1
|
134
|
+
if Hash === @value
|
135
|
+
[h[0].transform, h[1]]
|
136
|
+
else
|
137
|
+
[idx, h]
|
138
|
+
end
|
139
|
+
}
|
140
|
+
end
|
141
|
+
else
|
142
|
+
if seg =~ /^"(.*)"$/
|
143
|
+
seg = $1
|
144
|
+
elsif seg =~ /^'(.*)'$/
|
145
|
+
seg = $1
|
146
|
+
end
|
147
|
+
if ( v = at( seg ) )
|
148
|
+
[[ seg, v ]]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
return deep_nodes unless match_nodes
|
152
|
+
pred = ypath.predicates[ depth ]
|
153
|
+
if pred
|
154
|
+
case pred
|
155
|
+
when /^\.=/
|
156
|
+
pred = $' # '
|
157
|
+
match_nodes.reject! { |n|
|
158
|
+
n.last.value != pred
|
159
|
+
}
|
160
|
+
else
|
161
|
+
match_nodes.reject! { |n|
|
162
|
+
n.last.at( pred ).nil?
|
163
|
+
}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
return match_nodes + deep_nodes unless ypath.segments.length > depth + 1
|
167
|
+
|
168
|
+
#puts "DEPTH: #{depth + 1}"
|
169
|
+
deep_nodes = []
|
170
|
+
match_nodes.each { |n|
|
171
|
+
if n[1].is_a? BaseNode
|
172
|
+
match_deep = n[1].match_segment( ypath, depth + 1 )
|
173
|
+
if match_deep
|
174
|
+
match_deep.each { |m|
|
175
|
+
deep_nodes.push( n + m )
|
176
|
+
}
|
177
|
+
end
|
178
|
+
else
|
179
|
+
deep_nodes = []
|
180
|
+
end
|
181
|
+
}
|
182
|
+
deep_nodes = nil if deep_nodes.length == 0
|
183
|
+
deep_nodes
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# We want the node to act like as Hash
|
188
|
+
# if it is.
|
189
|
+
#
|
190
|
+
def []( *key )
|
191
|
+
if Hash === @value
|
192
|
+
v = @value.detect { |k,| k.transform == key.first }
|
193
|
+
v[1] if v
|
194
|
+
elsif Array === @value
|
195
|
+
@value.[]( *key )
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def children
|
200
|
+
if Hash === @value
|
201
|
+
@value.values.collect { |c| c[1] }
|
202
|
+
elsif Array === @value
|
203
|
+
@value
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def children_with_index
|
208
|
+
warn "#{caller[0]}: children_with_index is deprecated, use children" if $VERBOSE
|
209
|
+
if Hash === @value
|
210
|
+
@value.keys.collect { |i| [self[i], i] }
|
211
|
+
elsif Array === @value
|
212
|
+
i = -1; @value.collect { |v| i += 1; [v, i] }
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def emit
|
217
|
+
transform.to_yaml
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|