tty-config 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/LICENSE.txt +1 -1
- data/README.md +217 -150
- data/lib/tty-config.rb +1 -1
- data/lib/tty/config.rb +311 -66
- data/lib/tty/config/dependency_loader.rb +1 -1
- data/lib/tty/config/generator.rb +5 -5
- data/lib/tty/config/marshaller.rb +13 -3
- data/lib/tty/config/marshaller_registry.rb +4 -2
- data/lib/tty/config/marshallers/hcl_marshaller.rb +3 -0
- data/lib/tty/config/marshallers/ini_marshaller.rb +4 -1
- data/lib/tty/config/marshallers/java_props_marshaller.rb +3 -0
- data/lib/tty/config/marshallers/json_marshaller.rb +3 -0
- data/lib/tty/config/marshallers/toml_marshaller.rb +3 -0
- data/lib/tty/config/marshallers/yaml_marshaller.rb +3 -0
- data/lib/tty/config/version.rb +3 -3
- metadata +21 -33
data/lib/tty-config.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative "tty/config"
|
data/lib/tty/config.rb
CHANGED
@@ -12,6 +12,9 @@ require_relative "config/marshallers/hcl_marshaller"
|
|
12
12
|
require_relative "config/marshallers/java_props_marshaller"
|
13
13
|
|
14
14
|
module TTY
|
15
|
+
# Responsible for managing application configuration
|
16
|
+
#
|
17
|
+
# @api public
|
15
18
|
class Config
|
16
19
|
include Marshallers
|
17
20
|
|
@@ -26,18 +29,30 @@ module TTY
|
|
26
29
|
# Error raised when validation assertion fails
|
27
30
|
ValidationError = Class.new(StandardError)
|
28
31
|
|
32
|
+
# Coerce a hash object into Config instance
|
33
|
+
#
|
34
|
+
# @return [TTY::Config]
|
35
|
+
#
|
36
|
+
# @api private
|
29
37
|
def self.coerce(hash, &block)
|
30
38
|
new(normalize_hash(hash), &block)
|
31
39
|
end
|
32
40
|
|
33
41
|
# Convert string keys via method
|
34
42
|
#
|
43
|
+
# @param [Hash] hash
|
44
|
+
# the hash to normalize keys for
|
45
|
+
# @param [Symbol] method
|
46
|
+
# the method to use for converting keys
|
47
|
+
#
|
48
|
+
# @return [Hash{Symbol => Object}]
|
49
|
+
# the converted hash
|
50
|
+
#
|
35
51
|
# @api private
|
36
52
|
def self.normalize_hash(hash, method = :to_sym)
|
37
|
-
hash.
|
53
|
+
hash.each_with_object({}) do |(key, val), acc|
|
38
54
|
value = val.is_a?(::Hash) ? normalize_hash(val, method) : val
|
39
55
|
acc[key.public_send(method)] = value
|
40
|
-
acc
|
41
56
|
end
|
42
57
|
end
|
43
58
|
|
@@ -65,6 +80,10 @@ module TTY
|
|
65
80
|
# @api public
|
66
81
|
attr_accessor :env_prefix
|
67
82
|
|
83
|
+
# The string used to separate parts in ENV variable name
|
84
|
+
# @api public
|
85
|
+
attr_accessor :env_separator
|
86
|
+
|
68
87
|
# Create a configuration instance
|
69
88
|
#
|
70
89
|
# @api public
|
@@ -72,11 +91,12 @@ module TTY
|
|
72
91
|
@settings = settings
|
73
92
|
@location_paths = []
|
74
93
|
@validators = {}
|
75
|
-
@filename =
|
76
|
-
@extname =
|
77
|
-
@key_delim =
|
94
|
+
@filename = "config"
|
95
|
+
@extname = ".yml"
|
96
|
+
@key_delim = "."
|
78
97
|
@envs = {}
|
79
|
-
@env_prefix =
|
98
|
+
@env_prefix = ""
|
99
|
+
@env_separator = "_"
|
80
100
|
@autoload_env = false
|
81
101
|
@aliases = {}
|
82
102
|
|
@@ -99,11 +119,20 @@ module TTY
|
|
99
119
|
unless extensions.include?(name)
|
100
120
|
raise UnsupportedExtError, "Config file format `#{name}` is not supported."
|
101
121
|
end
|
122
|
+
|
102
123
|
@extname = name
|
103
124
|
end
|
104
125
|
|
105
126
|
# Add path to locations to search in
|
106
127
|
#
|
128
|
+
# @example
|
129
|
+
# append_path(Dir.pwd)
|
130
|
+
#
|
131
|
+
# @param [String] path
|
132
|
+
# the path to append
|
133
|
+
#
|
134
|
+
# @return [Array<String>]
|
135
|
+
#
|
107
136
|
# @api public
|
108
137
|
def append_path(path)
|
109
138
|
@location_paths << path
|
@@ -111,6 +140,14 @@ module TTY
|
|
111
140
|
|
112
141
|
# Insert location path at the begining
|
113
142
|
#
|
143
|
+
# @example
|
144
|
+
# prepend_path(Dir.pwd)
|
145
|
+
#
|
146
|
+
# @param [String] path
|
147
|
+
# the path to prepend
|
148
|
+
#
|
149
|
+
# @return [Array<String>]
|
150
|
+
#
|
114
151
|
# @api public
|
115
152
|
def prepend_path(path)
|
116
153
|
@location_paths.unshift(path)
|
@@ -118,6 +155,8 @@ module TTY
|
|
118
155
|
|
119
156
|
# Check if env variables are auto loaded
|
120
157
|
#
|
158
|
+
# @return [Boolean]
|
159
|
+
#
|
121
160
|
# @api public
|
122
161
|
def autoload_env?
|
123
162
|
@autoload_env == true
|
@@ -130,9 +169,26 @@ module TTY
|
|
130
169
|
@autoload_env = true
|
131
170
|
end
|
132
171
|
|
133
|
-
# Set a value for a composite key and overrides any existing keys
|
172
|
+
# Set a value for a composite key and overrides any existing keys
|
134
173
|
# Keys are case-insensitive
|
135
174
|
#
|
175
|
+
# @example
|
176
|
+
# set(:foo, :bar, :baz, value: 2)
|
177
|
+
#
|
178
|
+
# @example
|
179
|
+
# set(:foo, :bar, :baz) { 2 }
|
180
|
+
#
|
181
|
+
# @example
|
182
|
+
# set("foo.bar.baz", value: 2)
|
183
|
+
#
|
184
|
+
# @param [Array<String, Symbol>, String] keys
|
185
|
+
# the nested key to set value for
|
186
|
+
# @param [Object] value
|
187
|
+
# the value to set
|
188
|
+
#
|
189
|
+
# @return [Object]
|
190
|
+
# the set value
|
191
|
+
#
|
136
192
|
# @api public
|
137
193
|
def set(*keys, value: nil, &block)
|
138
194
|
assert_either_value_or_block(value, block)
|
@@ -156,12 +212,22 @@ module TTY
|
|
156
212
|
|
157
213
|
# Set a value for a composite key if not present already
|
158
214
|
#
|
159
|
-
# @
|
215
|
+
# @example
|
216
|
+
# set_if_empty(:foo, :bar, :baz, value: 2)
|
217
|
+
#
|
218
|
+
# @param [Array<String, Symbol>] keys
|
160
219
|
# the keys to set value for
|
220
|
+
# @param [Object] value
|
221
|
+
# the value to set
|
222
|
+
#
|
223
|
+
# @return [Object, nil]
|
224
|
+
# the set value or nil
|
161
225
|
#
|
162
226
|
# @api public
|
163
227
|
def set_if_empty(*keys, value: nil, &block)
|
164
|
-
|
228
|
+
keys = convert_to_keys(keys)
|
229
|
+
return unless deep_fetch(@settings, *keys).nil?
|
230
|
+
|
165
231
|
block ? set(*keys, &block) : set(*keys, value: value)
|
166
232
|
end
|
167
233
|
|
@@ -171,12 +237,11 @@ module TTY
|
|
171
237
|
# set_from_env(:host)
|
172
238
|
# set_from_env(:foo, :bar) { 'HOST' }
|
173
239
|
#
|
174
|
-
# @param [Array
|
240
|
+
# @param [Array<String>] keys
|
175
241
|
# the keys to bind to ENV variables
|
176
242
|
#
|
177
243
|
# @api public
|
178
244
|
def set_from_env(*keys, &block)
|
179
|
-
assert_keys_with_block(convert_to_keys(keys), block)
|
180
245
|
key = flatten_keys(keys)
|
181
246
|
env_key = block.nil? ? key : block.()
|
182
247
|
env_key = to_env_key(env_key)
|
@@ -187,17 +252,32 @@ module TTY
|
|
187
252
|
#
|
188
253
|
# @param [String] key
|
189
254
|
#
|
255
|
+
# @return [String]
|
256
|
+
#
|
190
257
|
# @api private
|
191
258
|
def to_env_key(key)
|
192
|
-
env_key = key.to_s.upcase
|
193
|
-
@env_prefix ==
|
259
|
+
env_key = key.to_s.gsub(key_delim, env_separator).upcase
|
260
|
+
if @env_prefix == ""
|
261
|
+
env_key
|
262
|
+
else
|
263
|
+
"#{@env_prefix.to_s.upcase}#{env_separator}#{env_key}"
|
264
|
+
end
|
194
265
|
end
|
195
266
|
|
196
267
|
# Fetch value under a composite key
|
197
268
|
#
|
198
|
-
# @
|
269
|
+
# @example
|
270
|
+
# fetch(:foo, :bar, :baz)
|
271
|
+
#
|
272
|
+
# @example
|
273
|
+
# fetch("foo.bar.baz")
|
274
|
+
#
|
275
|
+
# @param [Array<String, Symbol>, String] keys
|
199
276
|
# the keys to get value at
|
200
277
|
# @param [Object] default
|
278
|
+
# the default value
|
279
|
+
#
|
280
|
+
# @return [Object]
|
201
281
|
#
|
202
282
|
# @api public
|
203
283
|
def fetch(*keys, default: nil, &block)
|
@@ -217,14 +297,17 @@ module TTY
|
|
217
297
|
value = block || default if value.nil?
|
218
298
|
|
219
299
|
while callable_without_params?(value)
|
220
|
-
value = value.
|
300
|
+
value = value.()
|
221
301
|
end
|
222
302
|
value
|
223
303
|
end
|
224
304
|
|
225
305
|
# Merge in other configuration settings
|
226
306
|
#
|
227
|
-
# @param [Hash
|
307
|
+
# @param [Hash{Symbol => Object]] other_settings
|
308
|
+
#
|
309
|
+
# @return [Hash, nil]
|
310
|
+
# the combined settings or nil
|
228
311
|
#
|
229
312
|
# @api public
|
230
313
|
def merge(other_settings)
|
@@ -235,8 +318,16 @@ module TTY
|
|
235
318
|
|
236
319
|
# Append values to an already existing nested key
|
237
320
|
#
|
238
|
-
# @
|
321
|
+
# @example
|
322
|
+
# append(1, 2, to: %i[foo bar])
|
323
|
+
#
|
324
|
+
# @param [Array<Object>] values
|
239
325
|
# the values to append
|
326
|
+
# @param [Array<String, Symbol] to
|
327
|
+
# the nested key to append to
|
328
|
+
#
|
329
|
+
# @return [Array<Object>]
|
330
|
+
# the values for a nested key
|
240
331
|
#
|
241
332
|
# @api public
|
242
333
|
def append(*values, to: nil)
|
@@ -246,24 +337,45 @@ module TTY
|
|
246
337
|
|
247
338
|
# Remove a set of values from a nested key
|
248
339
|
#
|
249
|
-
# @
|
250
|
-
#
|
340
|
+
# @example
|
341
|
+
# remove(1, 2, from: :foo)
|
342
|
+
#
|
343
|
+
# @example
|
344
|
+
# remove(1, 2, from: %i[foo bar])
|
345
|
+
#
|
346
|
+
# @param [Array<Object>] values
|
347
|
+
# the values to remove from a nested key
|
348
|
+
# @param [Array<String, Symbol>, String] from
|
349
|
+
# the nested key to remove values from
|
251
350
|
#
|
252
351
|
# @api public
|
253
352
|
def remove(*values, from: nil)
|
254
353
|
keys = Array(from)
|
354
|
+
raise ArgumentError, "Need to set key to remove from" if keys.empty?
|
355
|
+
|
255
356
|
set(*keys, value: Array(fetch(*keys)) - values)
|
256
357
|
end
|
257
358
|
|
258
359
|
# Delete a value from a nested key
|
259
360
|
#
|
260
|
-
# @
|
361
|
+
# @example
|
362
|
+
# delete(:foo, :bar, :baz)
|
363
|
+
#
|
364
|
+
# @example
|
365
|
+
# delete(:unknown) { |key| "#{key} isn't set" }
|
366
|
+
#
|
367
|
+
# @param [Array<String, Symbol>] keys
|
261
368
|
# the keys for a value deletion
|
262
369
|
#
|
370
|
+
# @yield [key] Invoke the block with a missing key
|
371
|
+
#
|
372
|
+
# @return [Object]
|
373
|
+
# the deleted value(s)
|
374
|
+
#
|
263
375
|
# @api public
|
264
|
-
def delete(*keys)
|
376
|
+
def delete(*keys, &default)
|
265
377
|
keys = convert_to_keys(keys)
|
266
|
-
deep_delete(*keys, @settings)
|
378
|
+
deep_delete(*keys, @settings, &default)
|
267
379
|
end
|
268
380
|
|
269
381
|
# Define an alias to a nested key
|
@@ -271,7 +383,7 @@ module TTY
|
|
271
383
|
# @example
|
272
384
|
# alias_setting(:foo, to: :bar)
|
273
385
|
#
|
274
|
-
# @param [Array
|
386
|
+
# @param [Array<String>] keys
|
275
387
|
# the alias key
|
276
388
|
#
|
277
389
|
# @api public
|
@@ -281,11 +393,11 @@ module TTY
|
|
281
393
|
alias_key = flatten_keys(alias_keys)
|
282
394
|
|
283
395
|
if alias_key == flat_setting
|
284
|
-
raise ArgumentError,
|
396
|
+
raise ArgumentError, "Alias matches setting key"
|
285
397
|
end
|
286
398
|
|
287
399
|
if fetch(alias_key)
|
288
|
-
raise ArgumentError,
|
400
|
+
raise ArgumentError, "Setting already exists with an alias " \
|
289
401
|
"'#{alias_keys.map(&:inspect).join(', ')}'"
|
290
402
|
end
|
291
403
|
|
@@ -294,7 +406,7 @@ module TTY
|
|
294
406
|
|
295
407
|
# Register a validation rule for a nested key
|
296
408
|
#
|
297
|
-
# @param [Array
|
409
|
+
# @param [Array<String>] keys
|
298
410
|
# a deep nested keys
|
299
411
|
# @param [Proc] validator
|
300
412
|
# the logic to use to validate given nested key
|
@@ -345,7 +457,7 @@ module TTY
|
|
345
457
|
# @api public
|
346
458
|
def read(file = find_file, format: :auto)
|
347
459
|
if file.nil?
|
348
|
-
raise ReadError,
|
460
|
+
raise ReadError, "No file found to read configuration from!"
|
349
461
|
elsif !::File.exist?(file)
|
350
462
|
raise ReadError, "Configuration file `#{file}` does not exist!"
|
351
463
|
end
|
@@ -360,36 +472,44 @@ module TTY
|
|
360
472
|
|
361
473
|
# Write current configuration to a file.
|
362
474
|
#
|
475
|
+
# @example
|
476
|
+
# write(force: true, create: true)
|
477
|
+
#
|
363
478
|
# @param [String] file
|
364
|
-
# the
|
479
|
+
# the file to write to
|
480
|
+
# @param [Boolean] create
|
481
|
+
# whether or not to create missing path directories, false by default
|
482
|
+
# @param [Boolean] force
|
483
|
+
# whether or not to overwrite existing configuration file, false by default
|
484
|
+
# @param [String] format
|
485
|
+
# the format name for the configuration file, :auto by defualt
|
486
|
+
# @param [String] path
|
487
|
+
# the custom path to use to write a file to
|
488
|
+
#
|
489
|
+
# @raise [TTY::Config::WriteError]
|
365
490
|
#
|
366
491
|
# @api public
|
367
|
-
def write(file = find_file, force: false, format: :auto
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
'Use :force option to overwrite.'
|
372
|
-
elsif !::File.writable?(file)
|
373
|
-
raise WriteError, "Cannot write to #{file}."
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
if file.nil?
|
378
|
-
dir = @location_paths.empty? ? Dir.pwd : @location_paths.first
|
379
|
-
file = ::File.join(dir, "#{filename}#{@extname}")
|
380
|
-
end
|
492
|
+
def write(file = find_file, create: false, force: false, format: :auto,
|
493
|
+
path: nil)
|
494
|
+
file = fullpath(file, path)
|
495
|
+
check_can_write(file, force)
|
381
496
|
|
382
497
|
set_file_metadata(file)
|
383
|
-
|
384
498
|
ext = (format == :auto ? extname : ".#{format}")
|
385
499
|
content = marshal(@settings, ext: ext)
|
500
|
+
filepath = Pathname.new(file)
|
386
501
|
|
387
|
-
|
502
|
+
create_missing_dirs(filepath, create)
|
503
|
+
::File.write(filepath, content)
|
388
504
|
end
|
389
505
|
|
390
506
|
# Set file name and extension
|
391
507
|
#
|
508
|
+
# @example
|
509
|
+
# set_file_metadata("config.yml")
|
510
|
+
#
|
392
511
|
# @param [File] file
|
512
|
+
# the file to set metadata for
|
393
513
|
#
|
394
514
|
# @api public
|
395
515
|
def set_file_metadata(file)
|
@@ -412,7 +532,7 @@ module TTY
|
|
412
532
|
# @api private
|
413
533
|
def assert_either_value_or_block(value, block)
|
414
534
|
if value.nil? && block.nil?
|
415
|
-
raise ArgumentError,
|
535
|
+
raise ArgumentError, "Need to set either value or block"
|
416
536
|
elsif !(value.nil? || block.nil?)
|
417
537
|
raise ArgumentError, "Can't set both value and block"
|
418
538
|
end
|
@@ -432,7 +552,11 @@ module TTY
|
|
432
552
|
# that will be performed at point when a new proc is invoked.
|
433
553
|
#
|
434
554
|
# @param [String] key
|
555
|
+
# the key to set validation for
|
435
556
|
# @param [Proc] callback
|
557
|
+
# the callback to wrap
|
558
|
+
#
|
559
|
+
# @return [Proc]
|
436
560
|
#
|
437
561
|
# @api private
|
438
562
|
def delay_validation(key, callback)
|
@@ -446,18 +570,14 @@ module TTY
|
|
446
570
|
# Check if key passes all registered validations for a key
|
447
571
|
#
|
448
572
|
# @param [String] key
|
573
|
+
# the key to validate a value for
|
449
574
|
# @param [Object] value
|
575
|
+
# the value to check
|
450
576
|
#
|
451
577
|
# @api private
|
452
578
|
def assert_valid(key, value)
|
453
579
|
validators[key].each do |validator|
|
454
|
-
validator.
|
455
|
-
end
|
456
|
-
end
|
457
|
-
|
458
|
-
def assert_keys_with_block(keys, block)
|
459
|
-
if keys.size > 1 && block.nil?
|
460
|
-
raise ArgumentError, 'Need to set env var in block'
|
580
|
+
validator.(key, value)
|
461
581
|
end
|
462
582
|
end
|
463
583
|
|
@@ -469,12 +589,16 @@ module TTY
|
|
469
589
|
#
|
470
590
|
# @param [Hash] settings
|
471
591
|
#
|
472
|
-
# @param [Array
|
592
|
+
# @param [Array<Object>] keys
|
473
593
|
# the keys to nest
|
474
594
|
#
|
595
|
+
# @return [Hash]
|
596
|
+
# the nested setting
|
597
|
+
#
|
475
598
|
# @api private
|
476
599
|
def deep_set(settings, *keys)
|
477
600
|
return settings if keys.empty?
|
601
|
+
|
478
602
|
key, *rest = *keys
|
479
603
|
value = settings[key]
|
480
604
|
|
@@ -489,15 +613,13 @@ module TTY
|
|
489
613
|
end
|
490
614
|
end
|
491
615
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
end
|
500
|
-
|
616
|
+
# Convert key to an array of key elements
|
617
|
+
#
|
618
|
+
# @param [String, Array<String, Symbol>] keys
|
619
|
+
#
|
620
|
+
# @return [Array<String>]
|
621
|
+
#
|
622
|
+
# @api private
|
501
623
|
def convert_to_keys(keys)
|
502
624
|
first_key = keys[0]
|
503
625
|
if first_key.to_s.include?(key_delim)
|
@@ -507,6 +629,18 @@ module TTY
|
|
507
629
|
end
|
508
630
|
end
|
509
631
|
|
632
|
+
# Convert nested key from an array to a string
|
633
|
+
#
|
634
|
+
# @example
|
635
|
+
# flatten_keys(%i[foo bar baz]) # => "foo.bar.baz"
|
636
|
+
#
|
637
|
+
# @param [Array<String, Symbol>] keys
|
638
|
+
# the nested key to convert
|
639
|
+
#
|
640
|
+
# @return [String]
|
641
|
+
# the delimited nested key
|
642
|
+
#
|
643
|
+
# @api private
|
510
644
|
def flatten_keys(keys)
|
511
645
|
first_key = keys[0]
|
512
646
|
if first_key.to_s.include?(key_delim)
|
@@ -519,8 +653,12 @@ module TTY
|
|
519
653
|
# Fetch value under deeply nested keys with indiffernt key access
|
520
654
|
#
|
521
655
|
# @param [Hash] settings
|
656
|
+
# the settings to search
|
657
|
+
# @param [Array<Object>] keys
|
658
|
+
# the nested key to look up
|
522
659
|
#
|
523
|
-
# @
|
660
|
+
# @return [Object, nil]
|
661
|
+
# the value or nil
|
524
662
|
#
|
525
663
|
# @api private
|
526
664
|
def deep_fetch(settings, *keys)
|
@@ -533,6 +671,14 @@ module TTY
|
|
533
671
|
end
|
534
672
|
end
|
535
673
|
|
674
|
+
# Merge two deeply nested hash objects
|
675
|
+
#
|
676
|
+
# @param [Hash] this_hash
|
677
|
+
# @param [Hash] other_hash
|
678
|
+
#
|
679
|
+
# @return [Hash]
|
680
|
+
# the merged hash object
|
681
|
+
#
|
536
682
|
# @api private
|
537
683
|
def deep_merge(this_hash, other_hash, &block)
|
538
684
|
this_hash.merge(other_hash) do |key, this_val, other_val|
|
@@ -546,17 +692,37 @@ module TTY
|
|
546
692
|
end
|
547
693
|
end
|
548
694
|
|
695
|
+
# Delete a deeply nested key
|
696
|
+
#
|
697
|
+
# @param [Array<String>] keys
|
698
|
+
# the nested key to delete
|
699
|
+
# @param [Hash{String => Object}]
|
700
|
+
# the settings to delete key from
|
701
|
+
#
|
702
|
+
# @return [Object]
|
703
|
+
# the deleted object(s)
|
704
|
+
#
|
549
705
|
# @api private
|
550
|
-
def deep_delete(*keys, settings)
|
706
|
+
def deep_delete(*keys, settings, &default)
|
551
707
|
key, *rest = keys
|
552
708
|
value = settings[key]
|
553
|
-
if !
|
554
|
-
deep_delete(*rest, value)
|
709
|
+
if !rest.empty? && value.is_a?(::Hash)
|
710
|
+
deep_delete(*rest, value, &default)
|
555
711
|
elsif !value.nil?
|
556
712
|
settings.delete(key)
|
713
|
+
elsif default
|
714
|
+
default.(key)
|
557
715
|
end
|
558
716
|
end
|
559
717
|
|
718
|
+
# Search for a configuration file in a path
|
719
|
+
#
|
720
|
+
# @param [String] path
|
721
|
+
# the path to search
|
722
|
+
#
|
723
|
+
# @return [String, nil]
|
724
|
+
# the configuration file path or nil
|
725
|
+
#
|
560
726
|
# @api private
|
561
727
|
def search_in_path(path)
|
562
728
|
path = Pathname.new(path)
|
@@ -568,8 +734,77 @@ module TTY
|
|
568
734
|
nil
|
569
735
|
end
|
570
736
|
|
737
|
+
# Create a full path to a configuration file
|
738
|
+
#
|
739
|
+
# @param [String] file
|
740
|
+
# the configuration file
|
741
|
+
# @param [String] path
|
742
|
+
# the path to configuration file
|
743
|
+
#
|
744
|
+
# @return [String]
|
745
|
+
# the full path to a file
|
746
|
+
#
|
747
|
+
# @api private
|
748
|
+
def fullpath(file, path)
|
749
|
+
if file.nil?
|
750
|
+
dir = path || @location_paths.first || Dir.pwd
|
751
|
+
::File.join(dir, "#{filename}#{@extname}")
|
752
|
+
elsif file && path
|
753
|
+
::File.join(path, ::File.basename(file))
|
754
|
+
else
|
755
|
+
file
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
# Check if a file can be written to
|
760
|
+
#
|
761
|
+
# @param [String] file
|
762
|
+
# the configuration file
|
763
|
+
# @param [Boolean] force
|
764
|
+
# whether or not to force writing
|
765
|
+
#
|
766
|
+
# @raise [TTY::Config::WriteError]
|
767
|
+
#
|
768
|
+
# @return [nil]
|
769
|
+
#
|
770
|
+
# @api private
|
771
|
+
def check_can_write(file, force)
|
772
|
+
return unless file && ::File.exist?(file)
|
773
|
+
|
774
|
+
if !force
|
775
|
+
raise WriteError, "File `#{file}` already exists. " \
|
776
|
+
"Use :force option to overwrite."
|
777
|
+
elsif !::File.writable?(file)
|
778
|
+
raise WriteError, "Cannot write to #{file}."
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
# Create any missing directories
|
783
|
+
#
|
784
|
+
# @param [Pathname] filepath
|
785
|
+
# the file path
|
786
|
+
# @param [Boolean] create
|
787
|
+
# whether or not to create missing directories
|
788
|
+
#
|
789
|
+
# @raise [TTY::Config::WriteError]
|
790
|
+
#
|
791
|
+
# @return [nil]
|
792
|
+
#
|
793
|
+
# @api private
|
794
|
+
def create_missing_dirs(filepath, create)
|
795
|
+
if !filepath.dirname.exist? && !create
|
796
|
+
raise WriteError, "Directory `#{filepath.dirname}` doesn't exist. " \
|
797
|
+
"Use :create option to create missing directories."
|
798
|
+
else
|
799
|
+
filepath.dirname.mkpath
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
571
803
|
# Crate a marshaller instance based on the extension name
|
572
804
|
#
|
805
|
+
# @param [String] ext
|
806
|
+
# the extension name
|
807
|
+
#
|
573
808
|
# @return [nil, Marshaller]
|
574
809
|
#
|
575
810
|
# @api private
|
@@ -581,6 +816,13 @@ module TTY
|
|
581
816
|
marshaller.new
|
582
817
|
end
|
583
818
|
|
819
|
+
# Unmarshal content into a hash object
|
820
|
+
#
|
821
|
+
# @param [String] content
|
822
|
+
# the content to convert into a hash object
|
823
|
+
#
|
824
|
+
# @return [Hash{String => Object}]
|
825
|
+
#
|
584
826
|
# @api private
|
585
827
|
def unmarshal(content, ext: nil)
|
586
828
|
ext ||= extname
|
@@ -593,6 +835,9 @@ module TTY
|
|
593
835
|
|
594
836
|
# Marshal hash object into a configuration file content
|
595
837
|
#
|
838
|
+
# @param [Hash{String => Object}] object
|
839
|
+
# the object to convert to string
|
840
|
+
#
|
596
841
|
# @return [String]
|
597
842
|
#
|
598
843
|
# @api private
|