etcher 1.4.0 → 1.6.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
  SHA256:
3
- metadata.gz: 4a7381f41e75ad83f44a491f33f396be3ffb5b401a1a72fdcef2086984424fff
4
- data.tar.gz: '09b9c86d96af82fbc821e23c92e7966c97234e61625d3d23838471b930906629'
3
+ metadata.gz: 3e462682ab4cb1a7149595a36e1d2893f329db37813209655c53a6fd767e9751
4
+ data.tar.gz: 2f1a5bd597dfa8590d6ad48f9bd92de9688023b14a40c3856842d4539c9e3ca7
5
5
  SHA512:
6
- metadata.gz: 3d3008b4581dfd66426ba9e9c2ed0158241d130c2e68372f124369dd42c5893fed86aff36fe9e1b14612fff2139f39cf7e4b07492b5faac13699a3f0d87f609c
7
- data.tar.gz: 885d3f522cefba39eeb8765fe671ea822d52edefc700d1633997825fd7cb61c834db7d6111cbd92881c5c9d232519e70bb4aa120027cc6ad432e82286d15fb99
6
+ metadata.gz: 37067ae8933e3512d3be4a0e10147cad3813a76c969c414801b915b31c164bd1154b11dff58bb1196857e7f30b5fc9455ade7f305824ddf2a0c61c7149eec610
7
+ data.tar.gz: d37ae593f29bc0a8c2402dc39bc4d6df37478baec964480b76bbd94a23b00ff17d4236d21deff7e57b92cd18ed1d0f5cc29f00f7b7c907c0c6158c7ecf8543a7
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -111,7 +111,7 @@ transformer = lambda do |attributes, key = :user|
111
111
  end
112
112
 
113
113
  Etcher::Registry.new(contract:, model:, transformers: [transformer])
114
- .add_loader(Etcher::Loaders::Environment.new(%w[USER HOME]))
114
+ .add_loader(:environment, %w[USER HOME])
115
115
  .then { |registry| Etcher.new(registry).call }
116
116
 
117
117
  # Success(#<data user="DEMO", home="/Users/demo">)
@@ -297,11 +297,29 @@ There are a few guidelines to using them:
297
297
  * All nested keys will be flattened after being loaded. This means a key structure of `{demo: {one: "test"}}` will be flattened to `demo_one: "test"` which adheres to the {demeter_link} when a new recored is _etched_ for you.
298
298
  * The order in which you define your loaders matters. This means the first loader defined will be processed first, then the second, and so forth. Loaders defined last take precedence over previously defined loaders when overriding the same keys.
299
299
 
300
- The next couple of sections will help you learn about the supported loaders and how to build your own custom loader.
300
+ For convenience, all loaders -- only packaged with this gem -- can be registered by symbol instead of constant/instance. Example:
301
+
302
+ [source,ruby]
303
+ ----
304
+ registry = Etcher::Registry.new
305
+
306
+ # Environment
307
+ registry.add_loader :environment
308
+
309
+ # JSON
310
+ registry.add_loader :json, "path/to/configuration.json"
311
+
312
+ # YAML
313
+ registry.add_loader :yaml, "path/to/configuration.yml"
314
+ ----
315
+
316
+ Any positional or keyword arguments will be passed to the loader's constructor. _This only works when using `Registry#add_loader`, though._
317
+
318
+ The next sections will help you learn about the supported loaders and how to build your own custom loader.
301
319
 
302
320
  ==== Environment
303
321
 
304
- Use `Etcher::Loaders::Environment` to load configuration information from your {environment_link}. By default, this object wraps `ENV`, uses an empty array for keys to include, and answers a filtered hash where all keys are downcased. _If you don't specify keys to include, then an empty hash is answered back_. Here's a few examples:
322
+ Use `:environment` or `Etcher::Loaders::Environment` to load configuration information from your {environment_link}. By default, this object wraps `ENV`, uses an empty array for included keys, and answers a filtered hash where all keys are downcased. _If you don't specify keys to include, then an empty hash is answered back_. Here's a few examples:
305
323
 
306
324
  [source,ruby]
307
325
  ----
@@ -414,16 +432,15 @@ registry = Etcher::Registry[transformers: [MyTransformer]]
414
432
  registry = Etcher::Registry.new.add_transformer MyTransformer
415
433
  ----
416
434
 
417
- Here are a few guidelines to using them:
435
+ The guidelines for using transformers are:
418
436
 
419
- * They can be initialized with whatever requirements you might need.
437
+ * They can be initialized with whatever requirements you need.
420
438
  * They must respond to `#call` which takes a required `attributes` positional argument and answers a modified version of these attributes (`Hash`) wrapped as a monad.
421
- * A second _optional_ positional `key` parameter should follow your `attributes` parameter when implementing your transformer. This allows you to quickly refactor the key later while also reducing key duplication throughout your implementation.
439
+ * When using a proc/lambda, the first, _required_, parameter should be the `attributes` parameter followed by an _optional_ positional `key` parameter with a default value. This allows you to quickly refactor the key later while also reducing key duplication throughout your implementation.
440
+ * When using a class, the `key` should be your first positional parameter with a default value. Additional parameters can be supplied after if desired.
422
441
  * The `attributes` passed to your transformer will have symbolized keys so you don't need to transform them further.
423
442
 
424
- Here are a few examples of where you could go with this:
425
-
426
- The following capitalizes all values (which may or may not be good depending on your data structure).
443
+ For example, the following capitalizes all values (which may or may not be good depending on your data structure):
427
444
 
428
445
  [source,ruby]
429
446
  ----
@@ -435,28 +452,7 @@ Capitalize.call(name: "test")
435
452
  # Success({:name=>"Test"})
436
453
  ----
437
454
 
438
- The following updates current time relative to when configuration was transformed.
439
-
440
- [source,ruby]
441
- ----
442
- require "dry/monads"
443
-
444
- CurrentTime = lambda do |attributes, key = :at, at: Time.now|
445
- attributes.fetch(key) { at }
446
- .then { |value| Dry::Monads::Success attributes.merge!(key => value) }
447
- end
448
-
449
- CurrentTime.call({})
450
- # Success({:at=>2023-04-23 15:22:23.746408 -0600})
451
-
452
- CurrentTime.call({at: Time.utc(2023, 10, 15)})
453
- # Success({:at=>2023-10-15 00:00:00 UTC})
454
-
455
- CurrentTime.call({}, at: Time.utc(2023, 1, 10))
456
- # Success({:at=>2023-01-10 00:00:00 UTC})
457
- ----
458
-
459
- The following obtains the current Git user's email address from the global Git configuration using the {gitt_link} gem.
455
+ The following obtains the current Git user's email address from the global Git configuration using the {gitt_link} gem:
460
456
 
461
457
  [source,ruby]
462
458
  ----
@@ -485,11 +481,79 @@ To use all of the above, you'd only need to register and use them:
485
481
 
486
482
  [source,ruby]
487
483
  ----
488
- registry = Etcher::Registry[transformers: [Capitalize, CurrentTime, GitEmail.new]]
484
+ registry = Etcher::Registry[transformers: [Capitalize, GitEmail.new]]
489
485
  etcher = Etcher.new(registry)
490
486
  etcher.call
491
487
  ----
492
488
 
489
+ For convenience, all transformers -- only packaged with this gem -- can be registered by symbol instead of constant/instance. Example:
490
+
491
+ [source,ruby]
492
+ ----
493
+ registry = Etcher::Registry.new
494
+
495
+ # String
496
+ registry.add_transformer :string, :project_uri
497
+
498
+ # Time
499
+ registry.add_transformer :time
500
+ ----
501
+
502
+ Any positional or keyword arguments will be passed to the transformers's constructor. _This only works when using `Registry#add_transformer`, though._ The following sections provide more details on each.
503
+
504
+ ==== String
505
+
506
+ Use `Etcher::Transformers::String` to transform any key in your configuration by using the configuration's existing keys. Example:
507
+
508
+ [source,ruby]
509
+ ----
510
+ attributes = {
511
+ organization_uri: "https://acme.io",
512
+ project_name: "test",
513
+ project_uri: "%<organization_uri>s/projects/%<project_name>s"
514
+ }
515
+
516
+ transformer = Etcher::Transformers::String.new :project_uri
517
+
518
+ transformer.call attributes
519
+ # Success(
520
+ {
521
+ organization_uri: "https://acme.io",
522
+ project_name: "test",
523
+ project_uri: "https://acme.io/projects/test"
524
+ }
525
+ )
526
+
527
+ attributes.delete :project_name
528
+ transformer.call attributes
529
+ # Failure("Unable to transform :project_uri, missing specifier: \"<project_name>\".")
530
+ ----
531
+
532
+ ==== Time
533
+
534
+ Use `Etcher::Transformers::Time` to transform the `loaded_at` key in your configuration when you want to know the current time at which the configuration was loaded. Handy for situations where you need to calculate relative time or format time based on when your configuration was loaded.
535
+
536
+ Even though `loaded_at` is the default key and `Time.now.utc` is the default fallback, you're not limited to using different keys and fallbacks. Example:
537
+
538
+ [source,ruby]
539
+ ----
540
+ transformer = Etcher::Transformers::Time.new
541
+ transformer.call({})
542
+ # Success({:loaded_at=>2024-05-23 22:18:27.92767 UTC})
543
+
544
+ transformer = Etcher::Transformers::Time.new :now
545
+ transformer.call({})
546
+ # Success({:now=>2024-05-23 22:18:49.93189 UTC})
547
+
548
+ transformer = Etcher::Transformers::Time.new :now, fallback: Time.utc(2000, 1, 1)
549
+ transformer.call({})
550
+ # Success({:now=>2000-01-01 00:00:00 UTC})
551
+
552
+ transformer = Etcher::Transformers::Time.new
553
+ transformer.call({loaded_at: Time.utc(2000, 1, 1)})
554
+ # Success({:loaded_at=>2000-01-01 00:00:00 UTC})
555
+ ----
556
+
493
557
  === Overrides
494
558
 
495
559
  Overrides are what you pass to the Etcher instance when called. Example:
data/etcher.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "etcher"
5
- spec.version = "1.4.0"
5
+ spec.version = "1.6.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/etcher"
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ # Finds internal constant if moniker matches, otherwise answers a failure.
6
+ module Etcher
7
+ include Dry::Monads[:result]
8
+
9
+ Finder = lambda do |namespace, moniker|
10
+ Etcher.const_get(namespace)
11
+ .constants
12
+ .find { |constant| constant.downcase == moniker }
13
+ .then do |constant|
14
+ return Dry::Monads::Success Etcher.const_get("#{namespace}::#{constant}") if constant
15
+
16
+ Dry::Monads::Failure "Unable to select #{moniker.inspect} within #{namespace.downcase}."
17
+ end
18
+ rescue NameError
19
+ Dry::Monads::Failure "Invalid namespace: #{namespace.inspect}."
20
+ end
21
+ end
@@ -3,17 +3,37 @@
3
3
  module Etcher
4
4
  # Provides a registry of customization for loading and resolving a configuration.
5
5
  Registry = Data.define :contract, :model, :loaders, :transformers do
6
+ def self.find namespace, moniker, logger: LOGGER
7
+ case Finder.call namespace, moniker
8
+ in Success(constant) then constant
9
+ in Failure(message) then logger.abort message
10
+ else logger.abort "Unable to find constant in registry."
11
+ end
12
+ end
13
+
6
14
  def initialize contract: Contract, model: Hash, loaders: [], transformers: []
7
15
  super
8
16
  end
9
17
 
10
- def add_loader loader
11
- loaders.append loader
18
+ def add_loader(loader, *, **)
19
+ if loader.is_a? Symbol
20
+ self.class.find(:Loaders, loader).then { |constant| loaders.append constant.new(*, **) }
21
+ else
22
+ loaders.append loader
23
+ end
24
+
12
25
  self
13
26
  end
14
27
 
15
- def add_transformer transformer
16
- transformers.append transformer
28
+ def add_transformer(transformer, *, **)
29
+ if transformer.is_a? Symbol
30
+ self.class.find(:Transformers, transformer).then do |constant|
31
+ transformers.append constant.new(*, **)
32
+ end
33
+ else
34
+ transformers.append transformer
35
+ end
36
+
17
37
  self
18
38
  end
19
39
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Etcher
6
+ module Transformers
7
+ # Formats given key using existing and/or ancillary attributes.
8
+ class String
9
+ include Dry::Monads[:result]
10
+
11
+ def initialize key, **ancillary
12
+ @key = key
13
+ @ancillary = ancillary
14
+ end
15
+
16
+ def call attributes
17
+ value = attributes[key]
18
+
19
+ return Success attributes unless value
20
+
21
+ Success attributes.merge(key => format(value, **attributes, **ancillary))
22
+ rescue KeyError => error
23
+ Failure "Unable to transform #{key.inspect}, missing specifier: " \
24
+ "\"#{error.message[/<.+>/]}\"."
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :key, :ancillary
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Etcher
6
+ module Transformers
7
+ # Conditionally transforms current time for key.
8
+ class Time
9
+ include Dry::Monads[:result]
10
+
11
+ def initialize key = :loaded_at, fallback: ::Time.now.utc
12
+ @key = key
13
+ @fallback = fallback
14
+ end
15
+
16
+ def call attributes
17
+ attributes.fetch(key) { fallback }
18
+ .then { |value| Success attributes.merge!(key => value) }
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :key, :fallback
24
+ end
25
+ end
26
+ end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: etcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -35,7 +35,7 @@ cert_chain:
35
35
  3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
36
36
  gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
37
37
  -----END CERTIFICATE-----
38
- date: 2024-05-11 00:00:00.000000000 Z
38
+ date: 2024-05-31 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: cogger
@@ -150,11 +150,14 @@ files:
150
150
  - lib/etcher.rb
151
151
  - lib/etcher/builder.rb
152
152
  - lib/etcher/contract.rb
153
+ - lib/etcher/finder.rb
153
154
  - lib/etcher/loaders/environment.rb
154
155
  - lib/etcher/loaders/json.rb
155
156
  - lib/etcher/loaders/yaml.rb
156
157
  - lib/etcher/registry.rb
157
158
  - lib/etcher/resolver.rb
159
+ - lib/etcher/transformers/string.rb
160
+ - lib/etcher/transformers/time.rb
158
161
  - lib/etcher/types.rb
159
162
  homepage: https://alchemists.io/projects/etcher
160
163
  licenses:
@@ -182,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
185
  - !ruby/object:Gem::Version
183
186
  version: '0'
184
187
  requirements: []
185
- rubygems_version: 3.5.10
188
+ rubygems_version: 3.5.11
186
189
  signing_key:
187
190
  specification_version: 4
188
191
  summary: A monadic configuration loader, transformer, and validator.
metadata.gz.sig CHANGED
Binary file