sycl 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/sycl +184 -0
  2. data/lib/sycl.rb +483 -0
  3. metadata +67 -0
data/bin/sycl ADDED
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env ruby
2
+ # sycl - command line YAML manipulation tool using Sycl library
3
+ # Andrew Ho (ho@groupon.com)
4
+ #
5
+ # Copyright (c) 2012, Groupon, Inc.
6
+ # All rights reserved.
7
+ #
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions
10
+ # are met:
11
+ #
12
+ # Redistributions of source code must retain the above copyright notice,
13
+ # this list of conditions and the following disclaimer.
14
+ #
15
+ # Redistributions in binary form must reproduce the above copyright
16
+ # notice, this list of conditions and the following disclaimer in the
17
+ # documentation and/or other materials provided with the distribution.
18
+ #
19
+ # Neither the name of GROUPON nor the names of its contributors may be
20
+ # used to endorse or promote products derived from this software without
21
+ # specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26
+ # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
+ # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ require 'optparse'
36
+ require 'sycl'
37
+ require 'pp'
38
+
39
+ $ME = File.basename $0
40
+ $USAGE = "usage: #$ME [-h] [-i] [-y] program [file1 [file2 ...]]"
41
+ $HELP = <<"EndHelp"
42
+
43
+ #$USAGE
44
+
45
+ #$ME is a command line utility to run Ruby code on one or more YAML files.
46
+ It is similar to awk, but instead of processing lines of a file, it reads
47
+ full files as YAML; and instead of using awk language, you write Ruby code
48
+ which works with the data parsed from YAML.
49
+
50
+ The required first argument is a literal Ruby program. When this code is
51
+ run, the following variables are available:
52
+
53
+ f filename of the file being parsed
54
+ y the YAML text that was parsed
55
+ d data parsed from interpreting YAML
56
+
57
+ The d variable is a Sycl object (https://github.com/groupon/sycl)
58
+ This lets you access hashes with dot notation (for example, the lookup
59
+ d['foo']['bar'] can be written as d.foo.bar), including safe variants
60
+ with get() and set() methods (d.get('foo.bar') returns nil instead of
61
+ dying if d['foo'] does not exist). YAML output is sorted.
62
+
63
+ Options:
64
+ -h, --help display this help text and exit
65
+ -i, --inplace overwrite YAML files in place if d is modified
66
+ -y, --yaml output return value of program as YAML
67
+
68
+ Examples:
69
+ sycl 'puts "\#{d.hostname} \#{d.interfaces.eth0.inet[0]}"' host*.yml
70
+ sycl -i 'd.params.ntp_servers = %w{ns1 ns2}' host2.yml
71
+ sycl -y d unsorted.yml > sorted.yml
72
+
73
+ EndHelp
74
+
75
+ def main(argv)
76
+ in_place = false
77
+ yaml_output = false
78
+ opts = OptionParser.new do |opts|
79
+ opts.on('-h', '--help') { puts $HELP; exit 0 }
80
+ opts.on('-i', '--inplace') { in_place = true }
81
+ opts.on('-y', '--yaml') { yaml_output = true }
82
+ begin
83
+ opts.parse! argv
84
+ rescue OptionParser::InvalidOption => e
85
+ abort "#$ME: #{e}\n#$USAGE"
86
+ end
87
+ end
88
+ abort "#$ME: missing required program\n#$USAGE" if argv.empty?
89
+ code = argv.shift
90
+ options = {}
91
+ if argv.empty?
92
+ abort "#$ME: cannot modify stdin in place" if in_place
93
+ $stderr.puts "#$ME: waiting for input from stdin..." if $stdin.tty?
94
+ retval = sycl_process code, $stdin, 'stdin'
95
+ puts retval.to_yaml if retval && yaml_output
96
+ else
97
+ modified = []
98
+ argv.each do |filename|
99
+ begin
100
+ fh = File.open filename
101
+ retval, new_data = sycl_process code, fh, filename
102
+ fh.close
103
+ rescue Errno::ENOENT, Errno::EACCES => e
104
+ abort "#$ME: could not open file: #{e}"
105
+ end
106
+ if in_place && new_data
107
+ output = new_data.to_yaml
108
+ output.sub! /^\-\-\- \n/, ''
109
+ output.gsub! /: $/m, ':'
110
+ begin
111
+ tmpfile = "#{filename}.tmp.#$$"
112
+ tmp = File.open tmpfile, 'w'
113
+ tmp.puts output
114
+ tmp.close
115
+ File.rename tmpfile, filename
116
+ modified << filename
117
+ ensure
118
+ begin
119
+ File.unlink tmpfile
120
+ rescue
121
+ end
122
+ end
123
+ end
124
+ puts retval.to_yaml if retval && yaml_output
125
+ end
126
+ end
127
+ 0
128
+ end
129
+
130
+
131
+ # sycl_process(code, fh, filename) loads YAML from opened filehandle fh
132
+ # into a local variable y, parses it as a Sycl object into d, and runs
133
+ # the code string on it; the optional filename is used for error
134
+ # reporting, and also exposed as f. It returns the return value from the
135
+ # code that was run, and the new data structure, if it was modified.
136
+
137
+ def sycl_process(code, fh, f = nil)
138
+ begin
139
+ y = fh.read
140
+ d_orig = Sycl::load y
141
+ d = Sycl::load y
142
+ rescue Exception => e
143
+ abort "#$ME: could not parse YAML from #{f || 'unknown file'}: #{e}"
144
+ end
145
+ begin
146
+ retval = eval code
147
+ rescue Exception => e
148
+ abort "#$ME: program error while processing #{f || 'unknown file'}: #{e}"
149
+ end
150
+ prune_nil_values! d_orig
151
+ prune_nil_values! d
152
+ if d_orig.to_yaml == d.to_yaml
153
+ return [ retval ]
154
+ else
155
+ return [ retval, d ]
156
+ end
157
+ end
158
+
159
+
160
+ # Walk hashes and arrays, and delete any nil values.
161
+
162
+ def prune_nil_values!(o)
163
+ if o.is_a? Hash
164
+ o.keys.each do |k|
165
+ if o[k].nil?
166
+ o.delete k
167
+ else
168
+ o[k] = prune_nil_values o[k]
169
+ o.delete k if o[k].nil?
170
+ end
171
+ end
172
+ o
173
+ elsif o.is_a? Array
174
+ o.reject { |e| e.nil? }
175
+ o.collect! { |e| prune_nil_values e }
176
+ else
177
+ o
178
+ end
179
+ end
180
+
181
+
182
+ # Run main loop and exit
183
+
184
+ exit main ARGV
data/lib/sycl.rb ADDED
@@ -0,0 +1,483 @@
1
+ # sycl.rb - Simple YAML Configuration Library
2
+ # Andrew Ho (ho@groupon.com)
3
+ #
4
+ # Copyright (c) 2012, Groupon, Inc.
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ #
11
+ # Redistributions of source code must retain the above copyright notice,
12
+ # this list of conditions and the following disclaimer.
13
+ #
14
+ # Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in the
16
+ # documentation and/or other materials provided with the distribution.
17
+ #
18
+ # Neither the name of GROUPON nor the names of its contributors may be
19
+ # used to endorse or promote products derived from this software without
20
+ # specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24
+ # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25
+ # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
+ # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ require 'yaml'
35
+
36
+ module Sycl
37
+
38
+ # Sycl::load(yaml), Sycl::load_file(filename), and Sycl::dump(object)
39
+ # function just like their YAML counterparts, but return and act on
40
+ # Sycl-blessed variants of Hashes and Arrays.
41
+
42
+ def self.load(yaml)
43
+ from_object YAML::load(yaml)
44
+ end
45
+
46
+ def self.load_file(filename)
47
+ from_object YAML::load_file(filename)
48
+ end
49
+
50
+ def self.dump(object)
51
+ if (object.is_a?(::Hash) && !object.is_a?(Sycl::Hash)) ||
52
+ (object.is_a?(::Array) && !object.is_a?(Sycl::Array))
53
+ sycl_version = from_object object
54
+ sycl_version.to_yaml
55
+ else
56
+ object.to_yaml
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def self.from_object(o)
63
+ if o.is_a?(::Hash)
64
+ Sycl::Hash.from_hash(o)
65
+ elsif o.is_a?(::Array)
66
+ Sycl::Array.from_array(o)
67
+ else
68
+ o
69
+ end
70
+ end
71
+
72
+
73
+ # A Sycl::Array is like an Array, but creating one from an array blesses
74
+ # any child Array or Hash objects into Sycl::Array or Sycl::Hash objects.
75
+ #
76
+ # Sycl::Arrays support YAML preprocessing and postprocessing, and having
77
+ # individual nodes marked as being rendered in inline style. YAML
78
+ # output is also always sorted.
79
+
80
+ class Array < ::Array
81
+ def initialize(*args)
82
+ @yaml_preprocessor = nil
83
+ @yaml_postprocessor = nil
84
+ @yaml_style = nil
85
+ super
86
+ end
87
+
88
+ def self.[](*args)
89
+ Sycl::Array.from_array super
90
+ end
91
+
92
+ def self.load_file(f)
93
+ Sycl::Array.from_array YAML::load_file f
94
+ end
95
+
96
+ def self.from_array(a)
97
+ retval = Sycl::Array.new
98
+ a.each { |e| retval << Sycl::from_object(e) }
99
+ retval
100
+ end
101
+
102
+
103
+ # Make sure that if we write to this array, we promote any inputs
104
+ # to their Sycl equivalents. This lets dot notation, styled YAML,
105
+ # and other Sycl goodies continue.
106
+
107
+ def []=(*args)
108
+ raise ArgumentError => 'wrong number of arguments' unless args.size > 1
109
+ unless args[-1].is_a?(Sycl::Hash) || args[-1].is_a?(Sycl::Array)
110
+ args[-1] = Sycl::from_object(args[-1])
111
+ end
112
+ super
113
+ end
114
+
115
+ def <<(e)
116
+ unless e.is_a?(Sycl::Hash) || e.is_a?(Sycl::Array)
117
+ e = Sycl::from_object(e)
118
+ end
119
+ super
120
+ end
121
+
122
+ def collect!(&block)
123
+ super { |o| Sycl::from_object(block.call o) }
124
+ end
125
+ alias_method :map!, :collect!
126
+
127
+ def concat(a)
128
+ a = Sycl::Array.from_array(a) unless a.is_a?(Sycl::Array)
129
+ super
130
+ end
131
+
132
+ def fill(*args, &block)
133
+ raise ArgumentError => 'wrong number of arguments' if args.empty?
134
+ if block_given?
135
+ super { |idx| Sycl::from_object(block.call idx) }
136
+ else
137
+ unless args[0].is_a?(Sycl::Hash) || args[0].is_a?(Sycl::Array)
138
+ args[0] = Sycl::from_object(args[0])
139
+ end
140
+ super
141
+ end
142
+ end
143
+
144
+ def insert(i, *args)
145
+ raise ArgumentError => 'wrong number of arguments' if args.empty?
146
+ args.collect! do |o|
147
+ unless o.is_a?(Sycl::Hash) || o.is_a?(Sycl::Array)
148
+ o = Sycl::from_object(o)
149
+ end
150
+ end
151
+ super
152
+ end
153
+
154
+ def push(*args)
155
+ raise ArgumentError => 'wrong number of arguments' if args.empty?
156
+ args.collect! do |o|
157
+ unless o.is_a?(Sycl::Hash) || o.is_a?(Sycl::Array)
158
+ o = Sycl::from_object(o)
159
+ end
160
+ end
161
+ super
162
+ end
163
+
164
+ def replace(a)
165
+ a = Sycl::Array.from_array(a) unless a.is_a?(Sycl::Array)
166
+ super
167
+ end
168
+
169
+ def unshift(*args)
170
+ raise ArgumentError => 'wrong number of arguments' if args.empty?
171
+ args.collect! do |o|
172
+ unless o.is_a?(Sycl::Hash) || o.is_a?(Sycl::Array)
173
+ o = Sycl::from_object(o)
174
+ end
175
+ end
176
+ super
177
+ end
178
+
179
+
180
+ # Make this array, or its children, rendered in inline/flow style YAML.
181
+ # The default is to render arrays in block (multi-line) style.
182
+
183
+ def render_inline!
184
+ @yaml_style = :inline
185
+ end
186
+
187
+ def render_values_inline!
188
+ self.each do |e|
189
+ e.render_inline! if e.respond_to?(:render_inline!)
190
+ end
191
+ end
192
+
193
+
194
+ # Hooks to run before and after YAML dumping
195
+
196
+ def yaml_preprocessor(&block)
197
+ @yaml_preprocessor = block if block_given?
198
+ end
199
+
200
+ def yaml_postprocessor(&block)
201
+ @yaml_postprocessor = block if block_given?
202
+ end
203
+
204
+ def yaml_preprocess!
205
+ @yaml_preprocessor.call(self) if @yaml_preprocessor
206
+ end
207
+
208
+ def yaml_postprocess(yaml)
209
+ @yaml_postprocessor ? @yaml_postprocessor.call(yaml) : yaml
210
+ end
211
+
212
+
213
+ # The Psych YAML engine has a bug that results in infinite recursion
214
+ # if to_yaml is over-ridden on a non-native type. So, we fake out
215
+ # Psych and pretend Sycl::Array is a native type.
216
+
217
+ class MockNativeType
218
+ def source_location
219
+ ['psych/core_ext.rb']
220
+ end
221
+ end
222
+
223
+ def method(sym)
224
+ sym == :to_yaml ? MockNativeType.new : super
225
+ end
226
+
227
+
228
+ # YAML rendering overrides: run preprocessing and postprocessing,
229
+ # set flow/inline style if this node is marked accordingly, sort
230
+ # elements, and suppress taguri on output. For Psych, set a long line
231
+ # width to more or less suppress line wrap.
232
+
233
+ if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
234
+ def encode_with(coder)
235
+ coder.style = Psych::Nodes::Sequence::FLOW if @yaml_style == :inline
236
+ coder.represent_seq nil, sort
237
+ end
238
+ end
239
+
240
+ def to_yaml(opts = {})
241
+ yaml_preprocess!
242
+ if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
243
+ opts ||= {}
244
+ opts[:line_width] ||= 999999
245
+ yaml = super
246
+ else
247
+ yaml = YAML::quick_emit(self, opts) do |out|
248
+ out.seq(nil, @yaml_style || to_yaml_style) do |seq|
249
+ sort.each { |e| seq.add(e) }
250
+ end
251
+ end
252
+ end
253
+ yaml_postprocess yaml
254
+ end
255
+
256
+ end
257
+
258
+
259
+ # A Sycl::Hash is like a Hash, but creating one from an hash blesses
260
+ # any child Array or Hash objects into Sycl::Array or Sycl::Hash objects.
261
+ #
262
+ # Hash contents can be accessed via "dot notation" (h.foo.bar means
263
+ # the same as h['foo']['bar']). However, h.foo.bar dies if h['foo']
264
+ # does not exist, so get() and set() methods exist: h.get('foo.bar')
265
+ # will return nil instead of dying if h['foo'] does not exist.
266
+ # There is also a convenient deep_merge() that is like Hash#merge(),
267
+ # but also descends into and merges child nodes of the new hash.
268
+ #
269
+ # Sycl::Hashes support YAML preprocessing and postprocessing, and having
270
+ # individual nodes marked as being rendered in inline style. YAML
271
+ # output is also always sorted by key.
272
+
273
+ class Hash < ::Hash
274
+
275
+ def initialize(*args)
276
+ @yaml_preprocessor = nil
277
+ @yaml_postprocessor = nil
278
+ @yaml_style = nil
279
+ super
280
+ end
281
+
282
+ def self.[](*args)
283
+ Sycl::Hash.from_hash super
284
+ end
285
+
286
+ def self.load_file(f)
287
+ Sycl::Hash.from_hash YAML::load_file f
288
+ end
289
+
290
+ def self.from_hash(h)
291
+ retval = Sycl::Hash.new
292
+ h.each { |k, v| retval[k] = Sycl::from_object(v) }
293
+ retval
294
+ end
295
+
296
+
297
+ # Make sure that if we write to this hash, we promote any inputs
298
+ # to their Sycl equivalents. This lets dot notation, styled YAML,
299
+ # and other Sycl goodies continue.
300
+
301
+ def []=(k, v)
302
+ unless v.is_a?(Sycl::Hash) || v.is_a?(Sycl::Array)
303
+ v = Sycl::from_object(v)
304
+ end
305
+ super
306
+ end
307
+ alias_method :store, :[]=
308
+
309
+ def merge!(h)
310
+ h = Sycl::Hash.from_hash(h) unless h.is_a?(Sycl::Hash)
311
+ super
312
+ end
313
+ alias_method :update, :merge!
314
+
315
+
316
+ # Allow method call syntax: h.foo.bar.baz == h['foo']['bar']['baz'].
317
+ #
318
+ # Accessing hash keys whose names overlap with names of Ruby Object
319
+ # built-in methods (id, type, etc.) will still need to be passed in
320
+ # with bracket notation (h['type'] instead of h.type).
321
+
322
+ def method_missing(method_symbol, *args, &block)
323
+ key = method_symbol.to_s
324
+ set = key.chomp!('=')
325
+ if set
326
+ self[key] = args.first
327
+ elsif self.key?(key)
328
+ self[key]
329
+ else
330
+ nil
331
+ end
332
+ end
333
+
334
+
335
+ # Safe dotted notation reads: h.get('foo.bar') == h['foo']['bar'].
336
+ #
337
+ # This will return nil instead of dying if h['foo'] does not exist.
338
+
339
+ def get(path)
340
+ path = path.split(/\./) if path.is_a?(String)
341
+ candidate = self
342
+ while !path.empty?
343
+ key = path.shift
344
+ if candidate[key]
345
+ candidate = candidate[key]
346
+ else
347
+ candidate = nil
348
+ last
349
+ end
350
+ end
351
+ candidate
352
+ end
353
+
354
+
355
+ # Dotted writes: h.set('foo.bar' => 'baz') means h['foo']['bar'] = 'baz'.
356
+ #
357
+ # This will auto-vivify any missing intervening hash keys, and also
358
+ # promote Hash and Array objects in the input to Scyl variants.
359
+
360
+ def set(path, value)
361
+ path = path.split(/\./) if path.is_a?(String)
362
+ target = self
363
+ while path.size > 1
364
+ key = path.shift
365
+ if !(target.key?(key) && target[key].is_a?(::Hash))
366
+ target[key] = Sycl::Hash.new
367
+ else
368
+ target[key] = Sycl::Hash.from_hash(target[key])
369
+ end
370
+ target = target[key]
371
+ end
372
+ target[path.first] = value
373
+ end
374
+
375
+
376
+ # Deep merge two hashes (the new hash wins on conflicts). Hash or
377
+ # and Array objects in the new hash are promoted to Sycl variants.
378
+
379
+ def deep_merge(h)
380
+ self.merge(h) do |key, v1, v2|
381
+ if v1.is_a?(::Hash) && v2.is_a?(Sycl::Hash)
382
+ self[key].deep_merge(v2)
383
+ elsif v1.is_a?(::Hash) && v2.is_a?(::Hash)
384
+ self[key].deep_merge(Sycl::Hash.from_hash(v2))
385
+ else
386
+ self[key] = Sycl::from_object(v2)
387
+ end
388
+ end
389
+ end
390
+
391
+
392
+ # Make Sycl::Hashes sortable alongside Sycl::Hashes and Strings.
393
+ # This makes YAML output in sorted order work.
394
+
395
+ include Comparable
396
+
397
+ def <=>(another)
398
+ self.to_str <=> another.to_str
399
+ end
400
+
401
+ def to_str
402
+ self.keys.sort.first
403
+ end
404
+
405
+
406
+ # Make this hash, or its children, rendered in inline/flow style YAML.
407
+ # The default is to render hashes in block (multi-line) style.
408
+
409
+ def render_inline!
410
+ @yaml_style = :inline
411
+ end
412
+
413
+ def render_values_inline!
414
+ self.values.each do |v|
415
+ v.render_inline! if v.respond_to?(:render_inline!)
416
+ end
417
+ end
418
+
419
+
420
+ # Hooks to run before and after YAML dumping
421
+
422
+ def yaml_preprocessor(&block)
423
+ @yaml_preprocessor = block if block_given?
424
+ end
425
+
426
+ def yaml_postprocessor(&block)
427
+ @yaml_postprocessor = block if block_given?
428
+ end
429
+
430
+ def yaml_preprocess!
431
+ @yaml_preprocessor.call(self) if @yaml_preprocessor
432
+ end
433
+
434
+ def yaml_postprocess(yaml)
435
+ @yaml_postprocessor ? @yaml_postprocessor.call(yaml) : yaml
436
+ end
437
+
438
+
439
+ # The Psych YAML engine has a bug that results in infinite recursion
440
+ # if to_yaml is over-ridden on a non-native type. So, we fake out
441
+ # Psych and pretend Sycl::Hash is a native type.
442
+
443
+ class MockNativeType
444
+ def source_location
445
+ ['psych/core_ext.rb']
446
+ end
447
+ end
448
+
449
+ def method(sym)
450
+ sym == :to_yaml ? MockNativeType.new : super
451
+ end
452
+
453
+
454
+ # YAML rendering overrides: run preprocessing and postprocessing,
455
+ # set flow/inline style if this node is marked accordingly, sort by
456
+ # key, and suppress taguri on output. For Psych, set a long line
457
+ # width to more or less suppress line wrap.
458
+
459
+ if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
460
+ def encode_with(coder)
461
+ coder.style = Psych::Nodes::Mapping::FLOW if @yaml_style == :inline
462
+ coder.represent_map nil, sort
463
+ end
464
+ end
465
+
466
+ def to_yaml(opts = {})
467
+ yaml_preprocess!
468
+ if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
469
+ opts ||= {}
470
+ opts[:line_width] ||= 999999
471
+ yaml = super
472
+ else
473
+ yaml = YAML::quick_emit(self, opts) do |out|
474
+ out.map(nil, @yaml_style || to_yaml_style) do |map|
475
+ sort.each { |k, v| map.add(k, v) }
476
+ end
477
+ end
478
+ end
479
+ yaml_postprocess yaml
480
+ end
481
+
482
+ end
483
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sycl
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ version: "1.0"
10
+ platform: ruby
11
+ authors:
12
+ - Andrew Ho
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-03-23 00:00:00 +00:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: This library makes using YAML for configuration files convenient and easy.
22
+ email: rubygems@andrew.zeuscat.com
23
+ executables:
24
+ - sycl
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/sycl.rb
31
+ - bin/sycl
32
+ has_rdoc: true
33
+ homepage: http://zeuscat.com/andrew/sycl
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.5.3
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: Simple YAML Config Library
66
+ test_files: []
67
+