sycl 1.2 → 1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sycl.rb +270 -77
- metadata +4 -4
data/lib/sycl.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
# sycl.rb - Simple YAML Configuration Library
|
2
|
-
#
|
1
|
+
# = sycl.rb - Simple YAML Configuration Library
|
2
|
+
#
|
3
|
+
# For more details, visit the
|
4
|
+
# {Sycl GitHub page}[https://github.com/groupon/sycl/"target="_parent].
|
5
|
+
#
|
6
|
+
# == License
|
3
7
|
#
|
4
8
|
# Copyright (c) 2012, Groupon, Inc.
|
5
9
|
# All rights reserved.
|
@@ -33,20 +37,44 @@
|
|
33
37
|
|
34
38
|
require 'yaml'
|
35
39
|
|
40
|
+
# = sycl.rb - Simple YAML Configuration Library
|
41
|
+
#
|
42
|
+
# Sycl is a gem that makes using YAML[http://yaml.org/] for
|
43
|
+
# configuration files convenient and easy. Hashes and arrays made from
|
44
|
+
# parsing YAML via Sycl get helper methods that provide simple and natural
|
45
|
+
# syntax for querying and setting values. YAML output through Sycl is
|
46
|
+
# sorted, so configuration file versions can be compared consistently, and
|
47
|
+
# Sycl has hooks to add output styles, so your configuration files stay
|
48
|
+
# easy for humans to read and edit, even after being parsed and
|
49
|
+
# re-emitted.
|
50
|
+
#
|
51
|
+
# For more details, visit the
|
52
|
+
# {Sycl GitHub page}[https://github.com/groupon/sycl/"target="_parent].
|
53
|
+
|
36
54
|
module Sycl
|
37
55
|
|
38
|
-
# Sycl::load(yaml)
|
39
|
-
#
|
40
|
-
#
|
56
|
+
# Sycl::load(yaml) is the Sycl counterpart to YAML::load(yaml). It
|
57
|
+
# accepts YAML text, and returns a Sycl::Hash or Sycl::Array object
|
58
|
+
# representing the parsed YAML.
|
41
59
|
|
42
60
|
def self.load(yaml)
|
43
61
|
from_object YAML::load(yaml)
|
44
62
|
end
|
45
63
|
|
64
|
+
# Sycl::load(filename) is the Sycl counterpart to
|
65
|
+
# YAML::load_file(filename). It accepts a filename, and returns a
|
66
|
+
# Sycl::Hash or Sycl::Array object representing the parsed YAML from
|
67
|
+
# that file.
|
68
|
+
|
46
69
|
def self.load_file(filename)
|
47
70
|
from_object YAML::load_file(filename)
|
48
71
|
end
|
49
72
|
|
73
|
+
# Sycl::dump(object) is the Sycl counterpart to YAML::dump(object). It
|
74
|
+
# takes a Sycl::Hash or a Sycl::Array, and renders it as YAML. Sycl
|
75
|
+
# YAML output is always sorted in canonical order, so you can parse
|
76
|
+
# and re-emit data in a reliable way.
|
77
|
+
|
50
78
|
def self.dump(object)
|
51
79
|
if (object.is_a?(::Hash) && !object.is_a?(Sycl::Hash)) ||
|
52
80
|
(object.is_a?(::Array) && !object.is_a?(Sycl::Array))
|
@@ -70,32 +98,58 @@ module Sycl
|
|
70
98
|
end
|
71
99
|
|
72
100
|
|
73
|
-
# A Sycl::Array is like an Array, but creating one from an array
|
74
|
-
# any child Array or Hash objects into Sycl::Array or
|
101
|
+
# A Sycl::Array is like an Array, but creating one from an array
|
102
|
+
# blesses any child Array or Hash objects into Sycl::Array or
|
103
|
+
# Sycl::Hash objects. All the normal Array methods are supported,
|
104
|
+
# and automatically promote any inputs into Sycl equivalents. The
|
105
|
+
# following example illustrates this:
|
106
|
+
#
|
107
|
+
# h = { 'a' => { 'b' => 'Hello, world!' } }
|
108
|
+
# a = Sycl::Array.new
|
109
|
+
# a << h
|
110
|
+
#
|
111
|
+
# puts a.first.a.b # outputs 'Hello, world!'
|
112
|
+
#
|
113
|
+
# A Sycl::Array supports YAML preprocessing and postprocessing, and
|
114
|
+
# having individual nodes marked as being rendered in inline style.
|
115
|
+
# YAML output is always sorted, unless individual nodes are marked
|
116
|
+
# as being rendered unsorted.
|
117
|
+
#
|
118
|
+
# a = Sycl::Array.from_array %w{bravo delta charlie alpha}
|
119
|
+
# a.render_inline!
|
120
|
+
# a.yaml_preprocessor { |x| x.each { |e| e.capitalize! } }
|
121
|
+
# a.yaml_postprocessor { |yaml| yaml.sub(/\A---\s+/, '') }
|
75
122
|
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
# output is also always sorted.
|
123
|
+
# puts a.first # outputs 'bravo'
|
124
|
+
# puts a.to_yaml # outputs '[Alpha, Bravo, Charlie, Delta]'
|
79
125
|
|
80
126
|
class Array < ::Array
|
81
|
-
def initialize(*args)
|
127
|
+
def initialize(*args) # :nodoc:
|
82
128
|
@yaml_preprocessor = nil
|
83
129
|
@yaml_postprocessor = nil
|
84
130
|
@yaml_style = nil
|
131
|
+
@render_sorted = true
|
85
132
|
super
|
86
133
|
end
|
87
134
|
|
88
|
-
def self.[](*args)
|
135
|
+
def self.[](*args) # :nodoc:
|
89
136
|
Sycl::Array.from_array super
|
90
137
|
end
|
91
138
|
|
92
|
-
|
93
|
-
|
139
|
+
# Like Sycl::load_file(), a shortcut method to create a Sycl::Array
|
140
|
+
# from loading and parsing YAML from a file.
|
141
|
+
|
142
|
+
def self.load_file(filename)
|
143
|
+
Sycl::Array.from_array YAML::load_file filename
|
94
144
|
end
|
95
145
|
|
96
|
-
|
146
|
+
# Create a Sycl::Array from a normal Array, or, really, any object
|
147
|
+
# that supports Enumerable#each(). Every child Array or Hash gets
|
148
|
+
# promoted to a Sycl::Array or Sycl::Hash.
|
149
|
+
|
150
|
+
def self.from_array(array) # :nodoc:
|
97
151
|
retval = Sycl::Array.new
|
98
|
-
|
152
|
+
array.each { |e| retval << Sycl::from_object(e) }
|
99
153
|
retval
|
100
154
|
end
|
101
155
|
|
@@ -104,7 +158,7 @@ module Sycl
|
|
104
158
|
# to their Sycl equivalents. This lets dot notation, styled YAML,
|
105
159
|
# and other Sycl goodies continue.
|
106
160
|
|
107
|
-
def []=(*args)
|
161
|
+
def []=(*args) # :nodoc:
|
108
162
|
raise ArgumentError => 'wrong number of arguments' unless args.size > 1
|
109
163
|
unless args[-1].is_a?(Sycl::Hash) || args[-1].is_a?(Sycl::Array)
|
110
164
|
args[-1] = Sycl::from_object(args[-1])
|
@@ -112,24 +166,27 @@ module Sycl
|
|
112
166
|
super
|
113
167
|
end
|
114
168
|
|
115
|
-
def <<(e)
|
169
|
+
def <<(e) # :nodoc:
|
116
170
|
unless e.is_a?(Sycl::Hash) || e.is_a?(Sycl::Array)
|
117
171
|
e = Sycl::from_object(e)
|
118
172
|
end
|
119
173
|
super
|
120
174
|
end
|
121
175
|
|
122
|
-
def collect!(&block)
|
176
|
+
def collect!(&block) # :nodoc:
|
177
|
+
super { |o| Sycl::from_object(block.call o) }
|
178
|
+
end
|
179
|
+
|
180
|
+
def map!(&block) # :nodoc:
|
123
181
|
super { |o| Sycl::from_object(block.call o) }
|
124
182
|
end
|
125
|
-
alias_method :map!, :collect!
|
126
183
|
|
127
|
-
def concat(a)
|
184
|
+
def concat(a) # :nodoc:
|
128
185
|
a = Sycl::Array.from_array(a) unless a.is_a?(Sycl::Array)
|
129
186
|
super
|
130
187
|
end
|
131
188
|
|
132
|
-
def fill(*args, &block)
|
189
|
+
def fill(*args, &block) # :nodoc:
|
133
190
|
raise ArgumentError => 'wrong number of arguments' if args.empty?
|
134
191
|
if block_given?
|
135
192
|
super { |idx| Sycl::from_object(block.call idx) }
|
@@ -141,7 +198,7 @@ module Sycl
|
|
141
198
|
end
|
142
199
|
end
|
143
200
|
|
144
|
-
def insert(i, *args)
|
201
|
+
def insert(i, *args) # :nodoc:
|
145
202
|
raise ArgumentError => 'wrong number of arguments' if args.empty?
|
146
203
|
args.collect! do |o|
|
147
204
|
unless o.is_a?(Sycl::Hash) || o.is_a?(Sycl::Array)
|
@@ -151,7 +208,7 @@ module Sycl
|
|
151
208
|
super
|
152
209
|
end
|
153
210
|
|
154
|
-
def push(*args)
|
211
|
+
def push(*args) # :nodoc:
|
155
212
|
raise ArgumentError => 'wrong number of arguments' if args.empty?
|
156
213
|
args.collect! do |o|
|
157
214
|
unless o.is_a?(Sycl::Hash) || o.is_a?(Sycl::Array)
|
@@ -161,12 +218,12 @@ module Sycl
|
|
161
218
|
super
|
162
219
|
end
|
163
220
|
|
164
|
-
def replace(a)
|
221
|
+
def replace(a) # :nodoc:
|
165
222
|
a = Sycl::Array.from_array(a) unless a.is_a?(Sycl::Array)
|
166
223
|
super
|
167
224
|
end
|
168
225
|
|
169
|
-
def unshift(*args)
|
226
|
+
def unshift(*args) # :nodoc:
|
170
227
|
raise ArgumentError => 'wrong number of arguments' if args.empty?
|
171
228
|
args.collect! do |o|
|
172
229
|
unless o.is_a?(Sycl::Hash) || o.is_a?(Sycl::Array)
|
@@ -177,13 +234,35 @@ module Sycl
|
|
177
234
|
end
|
178
235
|
|
179
236
|
|
180
|
-
# Make this array,
|
237
|
+
# Make this array, and its children, rendered in inline/flow style.
|
181
238
|
# The default is to render arrays in block (multi-line) style.
|
239
|
+
#
|
240
|
+
# Example:
|
241
|
+
#
|
242
|
+
# a = Sycl::Array::from_array %w{one two}
|
243
|
+
# a.yaml_postprocessor { |yaml| yaml.sub(/\A---\s+/, '') }
|
244
|
+
#
|
245
|
+
# puts a.to_yaml # output: "- one\n- two"
|
246
|
+
# a.render_inline!
|
247
|
+
# puts a.to_yaml # output: '[one, two]'
|
182
248
|
|
183
249
|
def render_inline!
|
184
250
|
@yaml_style = :inline
|
185
251
|
end
|
186
252
|
|
253
|
+
# Keep rendering this array in block (multi-line) style, but, make
|
254
|
+
# this array's children rendered in inline/flow style.
|
255
|
+
#
|
256
|
+
# Example:
|
257
|
+
#
|
258
|
+
# a = Sycl::Array::from_array ['one', {'two' => ['three']}]
|
259
|
+
# a.yaml_postprocessor { |yaml| yaml.sub(/\A---\s+/, '') }
|
260
|
+
#
|
261
|
+
# a.render_values_inline!
|
262
|
+
# puts a.to_yaml # output: "- one\n- two: [three]"
|
263
|
+
# a.render_inline!
|
264
|
+
# puts a.to_yaml # output: '[one, {two: [three]}]'
|
265
|
+
|
187
266
|
def render_values_inline!
|
188
267
|
self.each do |e|
|
189
268
|
e.render_inline! if e.respond_to?(:render_inline!)
|
@@ -191,21 +270,52 @@ module Sycl
|
|
191
270
|
end
|
192
271
|
|
193
272
|
|
194
|
-
#
|
273
|
+
# Do not sort this array when it is rendered as YAML. Usually we want
|
274
|
+
# elements sorted so that diffs are human-readable, however, there are
|
275
|
+
# certain cases where array ordering is significant (for example, a
|
276
|
+
# sorted list of queues).
|
277
|
+
|
278
|
+
def render_unsorted!
|
279
|
+
@render_sorted = false
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
# Set a preprocessor hook which runs before each time YAML is
|
284
|
+
# dumped, for example, via to_yaml() or Sycl::dump(). The hook is a
|
285
|
+
# block that gets the object itself as an argument. The hook can
|
286
|
+
# then set render_inline!() or similar style arguments, prune nil or
|
287
|
+
# empty leaf values from hashes, or do whatever other styling needs
|
288
|
+
# to be done before a Sycl object is rendered as YAML.
|
195
289
|
|
196
290
|
def yaml_preprocessor(&block)
|
197
291
|
@yaml_preprocessor = block if block_given?
|
198
292
|
end
|
199
293
|
|
294
|
+
# Set a postprocessor hook which runs after YML is dumped, for
|
295
|
+
# example, via to_yaml() or Sycl::dump(). The hook is a block that
|
296
|
+
# gets the YAML text string as an argument, and returns a new,
|
297
|
+
# possibly different, YAML text string.
|
298
|
+
#
|
299
|
+
# A common example use case is to suppress the initial document
|
300
|
+
# separator, which is just visual noise when humans are viewing or
|
301
|
+
# editing a single YAML file:
|
302
|
+
#
|
303
|
+
# a.yaml_postprocessor { |yaml| yaml.sub(/\A---\s+/, '') }
|
304
|
+
#
|
305
|
+
# Your conventions might also prohibit trailing whitespace, which at
|
306
|
+
# least the Syck library will tack on the end of YAML hash keys:
|
307
|
+
#
|
308
|
+
# a.yaml_postprocessor { |yaml| yaml.gsub(/:\s+$/, '') }
|
309
|
+
|
200
310
|
def yaml_postprocessor(&block)
|
201
311
|
@yaml_postprocessor = block if block_given?
|
202
312
|
end
|
203
313
|
|
204
|
-
def yaml_preprocess!
|
314
|
+
def yaml_preprocess! # :nodoc:
|
205
315
|
@yaml_preprocessor.call(self) if @yaml_preprocessor
|
206
316
|
end
|
207
317
|
|
208
|
-
def yaml_postprocess(yaml)
|
318
|
+
def yaml_postprocess(yaml) # :nodoc:
|
209
319
|
@yaml_postprocessor ? @yaml_postprocessor.call(yaml) : yaml
|
210
320
|
end
|
211
321
|
|
@@ -214,50 +324,68 @@ module Sycl
|
|
214
324
|
# if to_yaml is over-ridden on a non-native type. So, we fake out
|
215
325
|
# Psych and pretend Sycl::Array is a native type.
|
216
326
|
|
217
|
-
class MockNativeType
|
327
|
+
class MockNativeType # :nodoc:
|
218
328
|
def source_location
|
219
329
|
['psych/core_ext.rb']
|
220
330
|
end
|
221
331
|
end
|
222
332
|
|
223
|
-
def method(sym)
|
333
|
+
def method(sym) # :nodoc:
|
224
334
|
sym == :to_yaml ? MockNativeType.new : super
|
225
335
|
end
|
226
336
|
|
227
337
|
|
228
|
-
# YAML rendering
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
coder.represent_seq nil, sort
|
237
|
-
end
|
238
|
-
end
|
338
|
+
# Render this object as YAML. Before rendering, run the object
|
339
|
+
# through any yaml_preprocessor() code block. After rendering,
|
340
|
+
# filter the YAML text through any yaml_postprocessor() code block.
|
341
|
+
#
|
342
|
+
# Nodes marked with render_inline!() or render_values_inline!()
|
343
|
+
# will be output in flow/inline style, all hashes and arrays will
|
344
|
+
# be sorted, and we set a long line width to more or less support
|
345
|
+
# line wrap under the Psych library.
|
239
346
|
|
240
347
|
def to_yaml(opts = {})
|
241
348
|
yaml_preprocess!
|
242
349
|
if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
|
243
350
|
opts ||= {}
|
244
|
-
opts[:line_width] ||= 999999
|
351
|
+
opts[:line_width] ||= 999999 # Psych doesn't let you disable line wrap
|
245
352
|
yaml = super
|
246
353
|
else
|
247
354
|
yaml = YAML::quick_emit(self, opts) do |out|
|
248
|
-
|
249
|
-
|
355
|
+
if @render_sorted
|
356
|
+
out.seq(nil, @yaml_style || to_yaml_style) do |seq|
|
357
|
+
sort.each { |e| seq.add(e) }
|
358
|
+
end
|
359
|
+
else
|
360
|
+
out.seq(nil, @yaml_style || to_yaml_style) do |seq|
|
361
|
+
each { |e| seq.add(e) }
|
362
|
+
end
|
250
363
|
end
|
251
364
|
end
|
252
365
|
end
|
253
366
|
yaml_postprocess yaml
|
254
367
|
end
|
255
368
|
|
369
|
+
if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
|
370
|
+
def encode_with(coder) # :nodoc:
|
371
|
+
coder.style = Psych::Nodes::Sequence::FLOW if @yaml_style == :inline
|
372
|
+
coder.represent_seq nil, sort
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
256
376
|
end
|
257
377
|
|
258
378
|
|
259
379
|
# 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
|
380
|
+
# any child Array or Hash objects into Sycl::Array or Sycl::Hash
|
381
|
+
# objects. All the normal Hash methods are supported, and
|
382
|
+
# automatically promote any inputs into Sycl equivalents. The
|
383
|
+
# following example illustrates this:
|
384
|
+
#
|
385
|
+
# h = Sycl::Hash.new
|
386
|
+
# h['a'] = { 'b' => { 'c' => 'Hello, world!' } }
|
387
|
+
#
|
388
|
+
# puts h.a.b.c # outputs 'Hello, world!'
|
261
389
|
#
|
262
390
|
# Hash contents can be accessed via "dot notation" (h.foo.bar means
|
263
391
|
# the same as h['foo']['bar']). However, h.foo.bar dies if h['foo']
|
@@ -266,27 +394,42 @@ module Sycl
|
|
266
394
|
# There is also a convenient deep_merge() that is like Hash#merge(),
|
267
395
|
# but also descends into and merges child nodes of the new hash.
|
268
396
|
#
|
269
|
-
# Sycl::
|
270
|
-
# individual nodes marked as being rendered in inline style.
|
271
|
-
# output is also always sorted by key.
|
397
|
+
# A Sycl::Hash supports YAML preprocessing and postprocessing, and
|
398
|
+
# having individual nodes marked as being rendered in inline style.
|
399
|
+
# YAML output is also always sorted by key.
|
400
|
+
#
|
401
|
+
# h = Sycl::Hash.from_hash({'b' => 'bravo', 'a' => 'alpha'})
|
402
|
+
# h.render_inline!
|
403
|
+
# h.yaml_preprocessor { |x| x.values.each { |e| e.capitalize! } }
|
404
|
+
# h.yaml_postprocessor { |yaml| yaml.sub(/\A---\s+/, '') }
|
405
|
+
#
|
406
|
+
# puts h['a'] # outputs 'alpha'
|
407
|
+
# puts h.keys.first # outputs 'a' or 'b' depending on Hash order
|
408
|
+
# puts h.to_yaml # outputs '{a: Alpha, b: Bravo}'
|
272
409
|
|
273
410
|
class Hash < ::Hash
|
274
411
|
|
275
|
-
def initialize(*args)
|
412
|
+
def initialize(*args) # :nodoc:
|
276
413
|
@yaml_preprocessor = nil
|
277
414
|
@yaml_postprocessor = nil
|
278
415
|
@yaml_style = nil
|
279
416
|
super
|
280
417
|
end
|
281
418
|
|
282
|
-
def self.[](*args)
|
419
|
+
def self.[](*args) # :nodoc:
|
283
420
|
Sycl::Hash.from_hash super
|
284
421
|
end
|
285
422
|
|
423
|
+
# Like Sycl::load_file(), a shortcut method to create a Sycl::Hash
|
424
|
+
# from loading and parsing YAML from a file.
|
425
|
+
|
286
426
|
def self.load_file(f)
|
287
427
|
Sycl::Hash.from_hash YAML::load_file f
|
288
428
|
end
|
289
429
|
|
430
|
+
# Create a Sycl::Array from a normal Hash or Hash-like object. Every
|
431
|
+
# child Array or Hash gets promoted to a Sycl::Array or Sycl::Hash.
|
432
|
+
|
290
433
|
def self.from_hash(h)
|
291
434
|
retval = Sycl::Hash.new
|
292
435
|
h.each { |k, v| retval[k] = Sycl::from_object(v) }
|
@@ -298,19 +441,29 @@ module Sycl
|
|
298
441
|
# to their Sycl equivalents. This lets dot notation, styled YAML,
|
299
442
|
# and other Sycl goodies continue.
|
300
443
|
|
301
|
-
def []=(k, v)
|
444
|
+
def []=(k, v) # :nodoc:
|
302
445
|
unless v.is_a?(Sycl::Hash) || v.is_a?(Sycl::Array)
|
303
446
|
v = Sycl::from_object(v)
|
304
447
|
end
|
305
448
|
super
|
306
449
|
end
|
307
|
-
alias_method :store, :[]=
|
308
450
|
|
309
|
-
def
|
451
|
+
def store(k, v) # :nodoc:
|
452
|
+
unless v.is_a?(Sycl::Hash) || v.is_a?(Sycl::Array)
|
453
|
+
v = Sycl::from_object(v)
|
454
|
+
end
|
455
|
+
super
|
456
|
+
end
|
457
|
+
|
458
|
+
def merge!(h) # :nodoc:
|
459
|
+
h = Sycl::Hash.from_hash(h) unless h.is_a?(Sycl::Hash)
|
460
|
+
super
|
461
|
+
end
|
462
|
+
|
463
|
+
def update(h) # :nodoc:
|
310
464
|
h = Sycl::Hash.from_hash(h) unless h.is_a?(Sycl::Hash)
|
311
465
|
super
|
312
466
|
end
|
313
|
-
alias_method :update, :merge!
|
314
467
|
|
315
468
|
|
316
469
|
# Allow method call syntax: h.foo.bar.baz == h['foo']['bar']['baz'].
|
@@ -394,22 +547,37 @@ module Sycl
|
|
394
547
|
|
395
548
|
include Comparable
|
396
549
|
|
397
|
-
def <=>(another)
|
550
|
+
def <=>(another) # :nodoc:
|
398
551
|
self.to_str <=> another.to_str
|
399
552
|
end
|
400
553
|
|
401
|
-
def to_str
|
554
|
+
def to_str # :nodoc:
|
402
555
|
self.keys.sort.first
|
403
556
|
end
|
404
557
|
|
405
558
|
|
406
|
-
# Make this hash,
|
407
|
-
# The default is to render
|
559
|
+
# Make this hash, and its children, rendered in inline/flow style.
|
560
|
+
# The default is to render arrays in block (multi-line) style.
|
408
561
|
|
409
562
|
def render_inline!
|
410
563
|
@yaml_style = :inline
|
411
564
|
end
|
412
565
|
|
566
|
+
# Keep rendering this hash in block (multi-line) style, but, make
|
567
|
+
# this array's children rendered in inline/flow style.
|
568
|
+
#
|
569
|
+
# Example:
|
570
|
+
#
|
571
|
+
# h = Sycl::Hash.new
|
572
|
+
# h['one'] = 'two'
|
573
|
+
# h['three'] = %w{four five}
|
574
|
+
# h.yaml_postprocessor { |yaml| yaml.sub(/\A---\s+/, '') }
|
575
|
+
#
|
576
|
+
# h.render_values_inline!
|
577
|
+
# puts h.to_yaml # output: "one: two\nthree: [five four]"
|
578
|
+
# h.render_inline!
|
579
|
+
# puts h.to_yaml # output: '{one: two, three: [five four]}'
|
580
|
+
|
413
581
|
def render_values_inline!
|
414
582
|
self.values.each do |v|
|
415
583
|
v.render_inline! if v.respond_to?(:render_inline!)
|
@@ -417,21 +585,42 @@ module Sycl
|
|
417
585
|
end
|
418
586
|
|
419
587
|
|
420
|
-
#
|
588
|
+
# Set a preprocessor hook which runs before each time YAML is
|
589
|
+
# dumped, for example, via to_yaml() or Sycl::dump(). The hook is a
|
590
|
+
# block that gets the object itself as an argument. The hook can
|
591
|
+
# then set render_inline!() or similar style arguments, prune nil or
|
592
|
+
# empty leaf values from hashes, or do whatever other styling needs
|
593
|
+
# to be done before a Sycl object is rendered as YAML.
|
421
594
|
|
422
595
|
def yaml_preprocessor(&block)
|
423
596
|
@yaml_preprocessor = block if block_given?
|
424
597
|
end
|
425
598
|
|
599
|
+
# Set a postprocessor hook which runs after YML is dumped, for
|
600
|
+
# example, via to_yaml() or Sycl::dump(). The hook is a block that
|
601
|
+
# gets the YAML text string as an argument, and returns a new,
|
602
|
+
# possibly different, YAML text string.
|
603
|
+
#
|
604
|
+
# A common example use case is to suppress the initial document
|
605
|
+
# separator, which is just visual noise when humans are viewing or
|
606
|
+
# editing a single YAML file:
|
607
|
+
#
|
608
|
+
# a.yaml_postprocessor { |yaml| yaml.sub(/\A---\s+/, '') }
|
609
|
+
#
|
610
|
+
# Your conventions might also prohibit trailing whitespace, which at
|
611
|
+
# least the Syck library will tack on the end of YAML hash keys:
|
612
|
+
#
|
613
|
+
# a.yaml_postprocessor { |yaml| yaml.gsub(/:\s+$/, '') }
|
614
|
+
|
426
615
|
def yaml_postprocessor(&block)
|
427
616
|
@yaml_postprocessor = block if block_given?
|
428
617
|
end
|
429
618
|
|
430
|
-
def yaml_preprocess!
|
619
|
+
def yaml_preprocess! # :nodoc:
|
431
620
|
@yaml_preprocessor.call(self) if @yaml_preprocessor
|
432
621
|
end
|
433
622
|
|
434
|
-
def yaml_postprocess(yaml)
|
623
|
+
def yaml_postprocess(yaml) # :nodoc:
|
435
624
|
@yaml_postprocessor ? @yaml_postprocessor.call(yaml) : yaml
|
436
625
|
end
|
437
626
|
|
@@ -440,34 +629,31 @@ module Sycl
|
|
440
629
|
# if to_yaml is over-ridden on a non-native type. So, we fake out
|
441
630
|
# Psych and pretend Sycl::Hash is a native type.
|
442
631
|
|
443
|
-
class MockNativeType
|
632
|
+
class MockNativeType # :nodoc:
|
444
633
|
def source_location
|
445
634
|
['psych/core_ext.rb']
|
446
635
|
end
|
447
636
|
end
|
448
637
|
|
449
|
-
def method(sym)
|
638
|
+
def method(sym) # :nodoc:
|
450
639
|
sym == :to_yaml ? MockNativeType.new : super
|
451
640
|
end
|
452
641
|
|
453
642
|
|
454
|
-
# YAML rendering
|
455
|
-
#
|
456
|
-
#
|
457
|
-
#
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
coder.represent_map nil, sort
|
463
|
-
end
|
464
|
-
end
|
643
|
+
# Render this object as YAML. Before rendering, run the object
|
644
|
+
# through any yaml_preprocessor() code block. After rendering,
|
645
|
+
# filter the YAML text through any yaml_postprocessor() code block.
|
646
|
+
#
|
647
|
+
# Nodes marked with render_inline!() or render_values_inline!()
|
648
|
+
# will be output in flow/inline style, all hashes and arrays will
|
649
|
+
# be sorted, and we set a long line width to more or less support
|
650
|
+
# line wrap under the Psych library.
|
465
651
|
|
466
652
|
def to_yaml(opts = {})
|
467
653
|
yaml_preprocess!
|
468
654
|
if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
|
469
655
|
opts ||= {}
|
470
|
-
opts[:line_width] ||= 999999
|
656
|
+
opts[:line_width] ||= 999999 # Psych doesn't let you disable line wrap
|
471
657
|
yaml = super
|
472
658
|
else
|
473
659
|
yaml = YAML::quick_emit(self, opts) do |out|
|
@@ -479,5 +665,12 @@ module Sycl
|
|
479
665
|
yaml_postprocess yaml
|
480
666
|
end
|
481
667
|
|
668
|
+
if defined?(YAML::ENGINE) && YAML::ENGINE.yamler == 'psych'
|
669
|
+
def encode_with(coder) # :nodoc:
|
670
|
+
coder.style = Psych::Nodes::Mapping::FLOW if @yaml_style == :inline
|
671
|
+
coder.represent_map nil, sort
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
482
675
|
end
|
483
676
|
end
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sycl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: "1.
|
8
|
+
- 3
|
9
|
+
version: "1.3"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Andrew Ho
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-
|
17
|
+
date: 2012-10-15 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|