tty-config 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55d72fde5f6fbfded2c40705454c4d3cb9b92b5c
4
- data.tar.gz: 5dc7c64fe76b97427b8b62141a64d3ac34faf948
3
+ metadata.gz: b7d2891f50d6ec7735ddf4c68e811d2b9726d5f1
4
+ data.tar.gz: a4c6a91a265b84c849aa7be416eb0062d9253ff7
5
5
  SHA512:
6
- metadata.gz: 1076327953cebbfae39402c5c3fcb61049c7299be02903628442f8eaf8dc2c4ca1d1b8d1515bc627373fc382ea22c7f7389fe2655b06993612a8e6e0cea794e2
7
- data.tar.gz: 9ee8ed6258b9eb4cd319068ef227af4f4a8bfc5bb168308d0cf193849bcc5556ae3debdcd57a5fef49250ee106303c9779d8d5c35a78ee296f5ddc5476a3892e
6
+ metadata.gz: 2f735b5c715194df5873b78bee19062392effc855f712659ab3fc07cd6c87737eedcc79fbce15362ecbe473df226090a3d76c00c1438f0f522c265f742141c50
7
+ data.tar.gz: 282c1817e5c73f18bf1be3c0b2c32d41d142a22a894ab5c528901bdfda0a573cbda9cfe74961b92dfe63ee91e89d89f2e06649cd4c208c7e85db47e226dd2ce5
data/CHANGELOG.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.2.0] - 2018-05-07
4
+
5
+ ### Added
6
+ * Add ability to validate values for arbitrarily nested keys
7
+
8
+ ### Changed
9
+ * Change to ensure that either value or block is provided when setting a value
10
+
3
11
  ## [v0.1.0] - 2018-04-14
4
12
 
5
13
  * Initial implementation and release
6
14
 
7
- [v0.1.0]: https://github.com/piotrmurach/tty-markdown/compare/v0.1.0
15
+ [v0.2.0]: https://github.com/piotrmurach/tty-config/compare/v0.1.0...v0.2.0
16
+ [v0.1.0]: https://github.com/piotrmurach/tty-config/compare/v0.1.0
data/README.md CHANGED
@@ -44,6 +44,7 @@ Or install it yourself as:
44
44
  ## Contents
45
45
 
46
46
  * [1. Usage](#1-usage)
47
+ * [1.1 app](#11-app)
47
48
  * [2. Interface](#2-interface)
48
49
  * [2.1 set](#21-set)
49
50
  * [2.2 set_if_empty](#22-set_if_empty)
@@ -53,13 +54,14 @@ Or install it yourself as:
53
54
  * [2.6 append](#26-append)
54
55
  * [2.7 remove](#27-remove)
55
56
  * [2.8 delete](#28-delete)
56
- * [2.9 filename=](#29-filename)
57
- * [2.10 extname=](#210-extname)
58
- * [2.11 append_path](#211-append_path)
59
- * [2.12 prepend_path](#212-prepend_path)
60
- * [2.13 read](#213-read)
61
- * [2.14 write](#214-write)
62
- * [2.15 persisted?](#215-persisted)
57
+ * [2.9 validate](#29-validate)
58
+ * [2.10 filename=](#210-filename)
59
+ * [2.11 extname=](#211-extname)
60
+ * [2.12 append_path](#212-append_path)
61
+ * [2.13 prepend_path](#213-prepend_path)
62
+ * [2.14 read](#214-read)
63
+ * [2.15 write](#215-write)
64
+ * [2.16 persisted?](#216-persisted)
63
65
 
64
66
  ## 1. Usage
65
67
 
@@ -119,6 +121,28 @@ Finally, read in configuration back again:
119
121
  config.read
120
122
  ```
121
123
 
124
+ ### 1.1 app
125
+
126
+ An example of an application configuration:
127
+
128
+ ```ruby
129
+ class App
130
+ attr_reader :config
131
+
132
+ def initialize
133
+ @config = TTY::Config.new
134
+ @config.filename = 'investments'
135
+ @config.extname = '.toml'
136
+ @config.append_path Dir.pwd
137
+ @config.append_path Dir.home
138
+ end
139
+
140
+ def self.config
141
+ @config ||= self.class.new.config
142
+ end
143
+ end
144
+ ```
145
+
122
146
  ## 2. Interface
123
147
 
124
148
  ### 2.1 set
@@ -282,7 +306,36 @@ config.delete(:settings, :base)
282
306
  # "USD"
283
307
  ```
284
308
 
285
- ### 2.9 filename=
309
+ ### 2.9 validate
310
+
311
+ To ensure consistency of the data, you can validate values being set at arbitrarily deep keys using `validate` method, that takes an arbitrarily nested key as its argument and a validation block.
312
+
313
+ ```ruby
314
+ config.validate(:settings, :base) do |key, value|
315
+ if value.length != 3
316
+ raise TTY::Config::ValidationError, "Currency code needs to be 3 chars long."
317
+ end
318
+ end
319
+ ```
320
+
321
+ You can assign multiple validations for a given key and each of them will be run in the order they were registered when checking a value.
322
+
323
+ When setting value all the validaitons will be run:
324
+
325
+ ```ruby
326
+ config.set(:settings, :base, value: 'PL')
327
+ # raises TTY::Config::ValidationError, 'Currency code needs to be 3 chars long.'
328
+ ```
329
+
330
+ If the value s provided as a proc or a block then the validation will be delayed until the value is actually read:
331
+
332
+ ```ruby
333
+ config.set(:settings, :base) { 'PL' }
334
+ config.fetch(:settings, :base)
335
+ # raises TTY::Config::ValidationError, 'Currency code needs to be 3 chars long.'
336
+ ```
337
+
338
+ ### 2.10 filename=
286
339
 
287
340
  By default, **TTY::Config** searches for `config` named configuration file. To change this use `filename=` method without the extension name:
288
341
 
@@ -292,7 +345,7 @@ config.filename = 'investments'
292
345
 
293
346
  Then any supported extensions will be search for such as `.yml`, `.json` and `.toml`.
294
347
 
295
- ### 2.10 extname=
348
+ ### 2.11 extname=
296
349
 
297
350
  By default '.yml' extension is used to write configuration out to a file but you can change that with `extname=`:
298
351
 
@@ -300,7 +353,7 @@ By default '.yml' extension is used to write configuration out to a file but you
300
353
  config.extname = '.toml'
301
354
  ```
302
355
 
303
- ### 2.11 append_path
356
+ ### 2.12 append_path
304
357
 
305
358
  You need to tell the **TTY::Config** where to search for configuration files. To search multiple paths for a configuration file use `append_path` or `prepend_path` methods.
306
359
 
@@ -314,7 +367,7 @@ config.append_path(Dir.pwd) # look in current working directory
314
367
 
315
368
  None of these paths are required, but you should provide at least one path if you wish to read configuration file.
316
369
 
317
- ### 2.12 prepend_path
370
+ ### 2.13 prepend_path
318
371
 
319
372
  The `prepend_path` allows you to add configuration search paths that should be searched first.
320
373
 
@@ -323,7 +376,7 @@ config.append_path(Dir.pwd) # look in current working directory second
323
376
  config.prepend_path(Dir.home) # look in user's home directory first
324
377
  ```
325
378
 
326
- ### 2.13 read
379
+ ### 2.14 read
327
380
 
328
381
  There are two ways for reading configuration files and both use the `read` method.
329
382
 
@@ -346,7 +399,7 @@ However, you can also specify directly the file to read without setting up any s
346
399
  config.read('./investments.toml')
347
400
  ```
348
401
 
349
- ### 2.14 write
402
+ ### 2.15 write
350
403
 
351
404
  By default **TTY::Config**, persists configuration file in the current working directory with a `config.yml` name. However, you can change that by specifying the filename and extension type:
352
405
 
@@ -376,7 +429,7 @@ config.write(force: true) # overwrite any found config fi
376
429
  config.write('./investments.toml', force: true) # overwrite specific config file
377
430
  ```
378
431
 
379
- ### 2.15 persisted?
432
+ ### 2.16 persisted?
380
433
 
381
434
  To check if a configuration file exists within the configured search paths use `persisted?` method:
382
435
 
data/lib/tty/config.rb CHANGED
@@ -12,6 +12,8 @@ module TTY
12
12
  WriteError = Class.new(StandardError)
13
13
  # Erorrr raised when setting unknown file extension
14
14
  UnsupportedExtError = Class.new(StandardError)
15
+ # Error raised when validation assertion fails
16
+ ValidationError = Class.new(StandardError)
15
17
 
16
18
  def self.coerce(hash, &block)
17
19
  new(normalize_hash(hash), &block)
@@ -44,6 +46,10 @@ module TTY
44
46
  # @api public
45
47
  attr_reader :extname
46
48
 
49
+ # The validations for this configuration
50
+ # @api public
51
+ attr_reader :validators
52
+
47
53
  def initialize(settings = {})
48
54
  @location_paths = []
49
55
  @settings = settings
@@ -88,10 +94,21 @@ module TTY
88
94
  # @api public
89
95
  def set(*keys, value: nil, &block)
90
96
  assert_either_value_or_block(value, block)
97
+
91
98
  keys = convert_to_keys(keys)
99
+ key = flatten_keys(keys)
100
+ value_to_eval = block || value
101
+
102
+ if validators.key?(key)
103
+ if callable_without_params?(value_to_eval)
104
+ value_to_eval = delay_validation(key, value_to_eval)
105
+ else
106
+ assert_valid(key, value)
107
+ end
108
+ end
92
109
 
93
110
  deepest_setting = deep_set(@settings, *keys[0...-1])
94
- deepest_setting[keys.last] = block || value
111
+ deepest_setting[keys.last] = value_to_eval
95
112
  deepest_setting[keys.last]
96
113
  end
97
114
 
@@ -165,6 +182,36 @@ module TTY
165
182
  deep_delete(*keys, @settings)
166
183
  end
167
184
 
185
+ # Register validation for a nested key
186
+ #
187
+ # @api public
188
+ def validate(*keys, &validator)
189
+ key = flatten_keys(keys)
190
+ values = validators[key] || []
191
+ values << validator
192
+ validators[key] = values
193
+ end
194
+
195
+ # Check if key passes all registered validations
196
+ #
197
+ # @api private
198
+ def assert_valid(key, value)
199
+ validators[key].each do |validator|
200
+ validator.call(key, value)
201
+ end
202
+ end
203
+
204
+ # Delay key validation
205
+ #
206
+ # @api private
207
+ def delay_validation(key, callback)
208
+ -> do
209
+ val = callback.()
210
+ assert_valid(key, val)
211
+ val
212
+ end
213
+ end
214
+
168
215
  # @api private
169
216
  def find_file
170
217
  @location_paths.each do |location_path|
@@ -245,8 +292,11 @@ module TTY
245
292
  end
246
293
 
247
294
  def assert_either_value_or_block(value, block)
248
- return if value.nil? || block.nil?
249
- raise ArgumentError, "Can't set both value and block"
295
+ if value.nil? && block.nil?
296
+ raise ArgumentError, "Need to set either value or block"
297
+ elsif !(value.nil? || block.nil?)
298
+ raise ArgumentError, "Can't set both value and block"
299
+ end
250
300
  end
251
301
 
252
302
  # Set value under deeply nested keys
@@ -295,6 +345,15 @@ module TTY
295
345
  end
296
346
  end
297
347
 
348
+ def flatten_keys(keys)
349
+ first_key = keys[0]
350
+ if first_key.to_s.include?(key_delim)
351
+ first_key
352
+ else
353
+ keys.join(key_delim)
354
+ end
355
+ end
356
+
298
357
  # Fetch value under deeply nested keys with indiffernt key access
299
358
  #
300
359
  # @param [Hash] settings
@@ -1,5 +1,5 @@
1
1
  module TTY
2
2
  class Config
3
- VERSION = "0.1.0".freeze
3
+ VERSION = "0.2.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tty-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-14 00:00:00.000000000 Z
11
+ date: 2018-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler