rubysl-yaml 2.0.0 → 2.0.2

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.
@@ -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,227 @@
1
+ #
2
+ # YAML::BaseNode class
3
+ #
4
+
5
+ module Syck
6
+ #
7
+ # YAML Generic Model container
8
+ #
9
+ module BaseNode
10
+
11
+ #
12
+ # Search for YPath entry and return
13
+ # qualified nodes.
14
+ #
15
+ def select( ypath_str )
16
+ warn "#{caller[0]}: select is deprecated" if $VERBOSE
17
+ matches = match_path( ypath_str )
18
+
19
+ #
20
+ # Create a new generic view of the elements selected
21
+ #
22
+ if matches
23
+ result = []
24
+ matches.each { |m|
25
+ result.push m.last
26
+ }
27
+ Syck.transfer( 'seq', result )
28
+ end
29
+ end
30
+
31
+ #
32
+ # Search for YPath entry and return
33
+ # transformed nodes.
34
+ #
35
+ def select!( ypath_str )
36
+ warn "#{caller[0]}: select!() is deprecated" if $VERBOSE
37
+ matches = match_path( ypath_str )
38
+
39
+ #
40
+ # Create a new generic view of the elements selected
41
+ #
42
+ if matches
43
+ result = []
44
+ matches.each { |m|
45
+ result.push m.last.transform
46
+ }
47
+ result
48
+ end
49
+ end
50
+
51
+ #
52
+ # Search for YPath entry and return a list of
53
+ # qualified paths.
54
+ #
55
+ def search( ypath_str )
56
+ warn "#{caller[0]}: search() is deprecated" if $VERBOSE
57
+ matches = match_path( ypath_str )
58
+
59
+ if matches
60
+ matches.collect { |m|
61
+ path = []
62
+ m.each_index { |i|
63
+ path.push m[i] if ( i % 2 ).zero?
64
+ }
65
+ "/" + path.compact.join( "/" )
66
+ }
67
+ end
68
+ end
69
+
70
+ def at( seg )
71
+ warn "#{caller[0]}: at() is deprecated" if $VERBOSE
72
+ if Hash === @value
73
+ self[seg]
74
+ elsif Array === @value and seg =~ /\A\d+\Z/ and @value[seg.to_i]
75
+ @value[seg.to_i]
76
+ end
77
+ end
78
+
79
+ #
80
+ # YPath search returning a complete depth array
81
+ #
82
+ def match_path( ypath_str )
83
+ warn "#{caller[0]}: match_path is deprecated" if $VERBOSE
84
+ require 'syck/ypath'
85
+ matches = []
86
+ YPath.each_path( ypath_str ) do |ypath|
87
+ seg = match_segment( ypath, 0 )
88
+ matches += seg if seg
89
+ end
90
+ matches.uniq
91
+ end
92
+
93
+ #
94
+ # Search a node for a single YPath segment
95
+ #
96
+ def match_segment( ypath, depth )
97
+ warn "#{caller[0]}: match_segment is deprecated" if $VERBOSE
98
+ deep_nodes = []
99
+ seg = ypath.segments[ depth ]
100
+ if seg == "/"
101
+ unless String === @value
102
+ idx = -1
103
+ @value.collect { |v|
104
+ idx += 1
105
+ if Hash === @value
106
+ match_init = [v[0].transform, v[1]]
107
+ match_deep = v[1].match_segment( ypath, depth )
108
+ else
109
+ match_init = [idx, v]
110
+ match_deep = v.match_segment( ypath, depth )
111
+ end
112
+ if match_deep
113
+ match_deep.each { |m|
114
+ deep_nodes.push( match_init + m )
115
+ }
116
+ end
117
+ }
118
+ end
119
+ depth += 1
120
+ seg = ypath.segments[ depth ]
121
+ end
122
+ match_nodes =
123
+ case seg
124
+ when "."
125
+ [[nil, self]]
126
+ when ".."
127
+ [["..", nil]]
128
+ when "*"
129
+ if @value.is_a? Enumerable
130
+ idx = -1
131
+ @value.collect { |h|
132
+ idx += 1
133
+ if Hash === @value
134
+ [h[0].transform, h[1]]
135
+ else
136
+ [idx, h]
137
+ end
138
+ }
139
+ end
140
+ else
141
+ if seg =~ /^"(.*)"$/
142
+ seg = $1
143
+ elsif seg =~ /^'(.*)'$/
144
+ seg = $1
145
+ end
146
+ if ( v = at( seg ) )
147
+ [[ seg, v ]]
148
+ end
149
+ end
150
+ return deep_nodes unless match_nodes
151
+ pred = ypath.predicates[ depth ]
152
+ if pred
153
+ case pred
154
+ when /^\.=/
155
+ pred = $' # '
156
+ match_nodes.reject! { |n|
157
+ n.last.value != pred
158
+ }
159
+ else
160
+ match_nodes.reject! { |n|
161
+ n.last.at( pred ).nil?
162
+ }
163
+ end
164
+ end
165
+ return match_nodes + deep_nodes unless ypath.segments.length > depth + 1
166
+
167
+ #puts "DEPTH: #{depth + 1}"
168
+ deep_nodes = []
169
+ match_nodes.each { |n|
170
+ if n[1].is_a? BaseNode
171
+ match_deep = n[1].match_segment( ypath, depth + 1 )
172
+ if match_deep
173
+ match_deep.each { |m|
174
+ deep_nodes.push( n + m )
175
+ }
176
+ end
177
+ else
178
+ deep_nodes = []
179
+ end
180
+ }
181
+ deep_nodes = nil if deep_nodes.length == 0
182
+ deep_nodes
183
+ end
184
+
185
+ #
186
+ # We want the node to act like as Hash
187
+ # if it is.
188
+ #
189
+ def []( *key )
190
+ if Hash === @value
191
+ v = @value.detect { |k,| k.transform == key.first }
192
+ v[1] if v
193
+ elsif Array === @value
194
+ @value.[]( *key )
195
+ end
196
+ end
197
+
198
+ def children
199
+ if Hash === @value
200
+ @value.values.collect { |c| c[1] }
201
+ elsif Array === @value
202
+ @value
203
+ end
204
+ end
205
+
206
+ def children_with_index
207
+ warn "#{caller[0]}: children_with_index is deprecated, use children" if $VERBOSE
208
+ if Hash === @value
209
+ @value.keys.collect { |i| [self[i], i] }
210
+ elsif Array === @value
211
+ i = -1; @value.collect { |v| i += 1; [v, i] }
212
+ end
213
+ end
214
+
215
+ def emit
216
+ transform.to_yaml
217
+ end
218
+ end
219
+
220
+ #
221
+ # Mixin BaseNode functionality
222
+ #
223
+ class Node
224
+ include Syck::BaseNode
225
+ end
226
+ end
227
+