rubysl-yaml 0.0.1 → 1.0.1

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