rubysl-yaml 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+