sycl 1.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.
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
+