rails-options_config 1.3.1 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5e669dc9026caa28b374c95341eea0ad720b8d1de0f1f5c789ef7c4f20a7556
4
- data.tar.gz: 899c092cb5a2dd5bfe081baff6a7407f59e63488ad06c2585ee95cc71318a60e
3
+ metadata.gz: 3d0be5348ae96aee4ddcd3569581ea8f9a0b0671fa65d3465c95153a3d87ebfb
4
+ data.tar.gz: 94433d9ccd8d477e9cf98defce9a90ca513d3164c386c11a4a6ec662c03cd3c0
5
5
  SHA512:
6
- metadata.gz: a82af4388620233d6117a20d495f7ab3bc036ecd5e53591d5bc7705b4c80d12ff55e2bbd200ee1fd65291bcdffbc55da25257a282e8db8da715b759b346d2896
7
- data.tar.gz: 2111daef39809e54c1b5c0aec3cf3beda5d9ffd6d8ee24f1983eb41ec9d3a08448da4b601e54317049b642b3412ad07e2acde9fdd246dd19d9fd21318619f886
6
+ metadata.gz: 8bda52d73c5635fca923af2e5a4d282e00eff8db8e9ac02622fd831855a4943564569d5fba5c443b63c64decd89593c883749a2f7a0217d51a0df0a4e74c9757
7
+ data.tar.gz: c49b73a140ab6072640a77d6f24c80cb00546969f60aa2275b8d46eeca9bec238f592daf0f42f352e585fcd41df4cb3a09c1a053b3d94537adc3d05c5a8dc1cc
data/README.md CHANGED
@@ -9,7 +9,7 @@ As a project's size increases, its credentials file tends to become unmanageable
9
9
  Add this line to your application's Gemfile:
10
10
 
11
11
  ```ruby
12
- gem 'rails-options', '~> 1.0'
12
+ gem 'rails-options_config', '~> 1.0'
13
13
  ```
14
14
 
15
15
  And then execute:
@@ -44,7 +44,7 @@ The YAML files can be encrypted: if the filename ends in `.enc`, the content wil
44
44
 
45
45
  If a filename contains an environment tag, the content will be considered only in the respective environment: `config/options/pokemon.development.yml` will only be loaded in the `development` environment.
46
46
 
47
- Files with the same root name will overwrite each other: environment specific files will overwrite generic ones, and encrypted files will overwrite clear text ones. This way you can provide sensible defaults in the generic files, with encryption if necessary, and override them in specific environments (for example using a `.development` gitignored file to use a local mocked server instead of the real thing).
47
+ Files with the same root name will overwrite each other: environment specific files will overwrite generic ones, and encrypted files will overwrite clear text ones. This way you can provide sensible defaults in the generic files, with encryption if necessary, and override them in specific environments (for example using a `.development` gitignored file to use a local mocked server instead of the real thing). The values are overwritten using `Hash#deep_merge` from Active Support, so you can overwrite only selected values and keep the default for the rest.
48
48
 
49
49
  Options can also be picked up from environment variables. Any `!env/VAR` YAML tag will be substituted for the value of the `VAR` variable, anywhere in the file (even in keys). For example, setting `VAR=variable`:
50
50
 
@@ -60,11 +60,21 @@ will become:
60
60
  }
61
61
  ```
62
62
 
63
+ If for any reason you need to load the options for a different environment from the current one (for example, Rails creates both the development and test databases running in the `development` environment, so if you want to fill in the `config/database.yml` file using Options, you need to force the test environment when filling the respective section), you just need to pass it to `Rails.application.options`:
64
+
65
+ ```ruby
66
+ # RAILS_ENV=staging rails c
67
+ Rails.application.options # => staging options
68
+ Rails.application.options(:production) # => production options
69
+ ```
70
+
71
+ Notice that only the options for the current environment are cached, the others are loaded on call every time.
72
+
63
73
  ### Options
64
74
 
65
75
  You can set these options in `application.rb` or in any of the `environments/*.rb` files.
66
76
 
67
- - `config.options.roots` : the directories, relative to `Rails.root`, in which to look for options files. You can either add to the existing array with `<<` or assign a new array. Default: `['config']`.
77
+ - `config.options.roots` : the directories, relative to `Rails.root`, in which to look for options files. You can either add to the existing array with `<<` or assign a new array. Default: `['config']`.
68
78
  - `config.options.paths` : the patterns (in the format of `Dir.glob`) corresponding to the options files. They will be looked for in all the `roots` directories. Default: `['options.{yml,yaml}{.enc,}', 'options/**/*.{yml,yaml}{.enc,}']`.
69
79
  - `config.options.raise_on_override` : set this to `true` if you want an exception to be raised if any key would be set by multiple files. If this is `false` and a "conflict" happens, one key will overwrite the other, but the order is undefined. This only applies to files with a different `path/to/file`, not to conflicts between the base and any environment-specific version. Default: `false`.
70
80
 
@@ -1,75 +1,11 @@
1
- require_relative 'yaml/env_visitor'
2
- require_relative 'key_override_error'
3
-
4
1
  module Rails
5
2
  class Application
6
- def options
7
- @options ||= begin
8
- yaml_visitor = OptionsConfig::EnvVisitor.create symbolize_names: true
9
- Array(config.options.roots)
10
- .flat_map do |root|
11
- Dir
12
- .glob(Array(config.options.paths), base: root)
13
- .map do |path|
14
- path.match %r{^(?<filename>.*?)(?<env>\..*?)?(?<extension>\.ya?ml)(?<enc>\.enc)?$} do |md|
15
- full_path = Pathname(root).join(path)
16
- encrypted = md[:enc].present?
17
- content = if encrypted
18
- yaml_visitor.accept YAML.parse(encrypted(full_path).read)
19
- else
20
- yaml_visitor.accept YAML.parse_file(full_path)
21
- end
22
-
23
- {
24
- path: full_path,
25
- filename: md[:filename],
26
- content: content,
27
- encrypted: encrypted
28
- }
29
- .tap do |hash|
30
- hash[:environment] = md[:env].delete_prefix('.').to_sym if md[:env].present?
31
- end
32
- end
33
- end
34
- end
35
- .group_by { |file| file[:filename] }
36
- .map do |_, files|
37
- # Specifics overwrite bases, and encrypted overwrite cleartexts for each.
38
- bases = files
39
- .reject { |file| file.key? :environment }
40
- .sort_by { |file| file[:encrypted] ? 1 : 0 }
41
- specifics = files
42
- .filter { |file| file[:environment] == Rails.env.to_sym }
43
- .sort_by { |file| file[:encrypted] ? 1 : 0 }
44
-
45
- (bases + specifics)
46
- .reduce({}) { |acc, override| acc.deep_merge override[:content] }
47
- end
48
- .then do |hashes|
49
- if config.options.raise_on_override
50
- hashes.reduce credentials.config do |acc, hash|
51
- acc.deep_merge hash do |key, value1, value2|
52
- raise Options::KeyOverrideError,
53
- 'Key override while loading options: ' \
54
- "trying to set `#{key}' to #{value2.inspect}:#{value2.class}, " \
55
- "but it is already set to #{value1.inspect}:#{value1.class}"
56
- end
57
- end
58
- else
59
- hashes.reduce(credentials.config, &:deep_merge)
60
- end
61
- end
62
- .then do |hash|
63
- deep_transform = proc do |value|
64
- if value.is_a? Hash
65
- ActiveSupport::OrderedOptions[value.transform_values(&deep_transform)]
66
- else
67
- value
68
- end
69
- end
70
- deep_transform.call hash
71
- end
72
- end
3
+ def options env=nil
4
+ if env.nil? || env.to_sym == Rails.env.to_sym
5
+ @options ||= OptionsConfig.parse_options self, Rails.env.to_sym
6
+ else
7
+ OptionsConfig.parse_options self, env.to_sym
8
+ end
73
9
  end
74
10
  end
75
11
  end
@@ -0,0 +1,6 @@
1
+ module Rails
2
+ module OptionsConfig
3
+ class UnusableOptionsError < StandardError
4
+ end
5
+ end
6
+ end
@@ -1,5 +1,5 @@
1
1
  module Rails
2
2
  module OptionsConfig
3
- VERSION = '1.3.1'.freeze
3
+ VERSION = '1.4.0'.freeze
4
4
  end
5
5
  end
@@ -1,3 +1,86 @@
1
+ require_relative 'options_config/yaml/env_visitor'
2
+ require_relative 'options_config/key_override_error'
3
+ require_relative 'options_config/unusable_options_error'
4
+
5
+ module Rails
6
+ module OptionsConfig
7
+ def self.parse_options application, env
8
+ application.instance_exec do
9
+ yaml_visitor = EnvVisitor.create symbolize_names: true
10
+ Array(config.options.roots)
11
+ .flat_map do |root|
12
+ Dir
13
+ .glob(Array(config.options.paths), base: root)
14
+ .map do |path|
15
+ path.match %r{^(?<filename>.*?)(?<env>\..*?)?(?<extension>\.ya?ml)(?<enc>\.enc)?$} do |md|
16
+ full_path = Pathname(root).join(path)
17
+ encrypted = md[:enc].present?
18
+ content = if encrypted
19
+ YAML.parse encrypted(full_path).read
20
+ else
21
+ YAML.parse_file full_path
22
+ end
23
+ .therefore { |yaml| yaml_visitor.accept yaml }
24
+
25
+ unless content.is_a? Hash
26
+ raise UnusableOptionsError,
27
+ "The contents of options file `#{full_path}` are unsuitable. It must be a hash."
28
+ end
29
+
30
+ {
31
+ path: full_path,
32
+ filename: md[:filename],
33
+ content: content,
34
+ encrypted: encrypted
35
+ }
36
+ .tap do |hash|
37
+ hash[:environment] = md[:env].delete_prefix('.').to_sym if md[:env].present?
38
+ end
39
+ end
40
+ end
41
+ end
42
+ .group_by { |file| file[:filename] }
43
+ .map do |_, files|
44
+ # Specifics overwrite bases, and encrypted overwrite cleartexts for each.
45
+ bases = files
46
+ .reject { |file| file.key? :environment }
47
+ .sort_by { |file| file[:encrypted] ? 1 : 0 }
48
+ specifics = files
49
+ .filter { |file| file[:environment] == env }
50
+ .sort_by { |file| file[:encrypted] ? 1 : 0 }
51
+
52
+ (bases + specifics)
53
+ .reduce({}) { |acc, override| acc.deep_merge override[:content] }
54
+ end
55
+ .then do |hashes|
56
+ if config.options.raise_on_override
57
+ hashes.reduce credentials.config do |acc, hash|
58
+ acc.deep_merge hash do |key, value1, value2|
59
+ raise KeyOverrideError,
60
+ 'Key override while loading options: ' \
61
+ "trying to set `#{key}' to #{value2.inspect}:#{value2.class}, " \
62
+ "but it is already set to #{value1.inspect}:#{value1.class}"
63
+ end
64
+ end
65
+ else
66
+ hashes.reduce(credentials.config, &:deep_merge)
67
+ end
68
+ end
69
+ .then do |hash|
70
+ deep_transform = proc do |value|
71
+ if value.is_a? Hash
72
+ ActiveSupport::OrderedOptions[value.transform_values(&deep_transform)]
73
+ else
74
+ value
75
+ end
76
+ end
77
+ deep_transform.call hash
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
1
84
  require 'rails/options_config/version'
2
85
  require 'rails/options_config/engine'
3
86
  require 'rails/options_config/application'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-options_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Moku S.r.l.
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-03-19 00:00:00.000000000 Z
12
+ date: 2025-07-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '7.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: therefore
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
28
42
  description: As a project's size increases, its credentials file tends to become unmanageable.
29
43
  With Rails Options Config you can split the credentials into smaller separate YAML
30
44
  files.
@@ -40,6 +54,7 @@ files:
40
54
  - lib/rails/options_config/application.rb
41
55
  - lib/rails/options_config/engine.rb
42
56
  - lib/rails/options_config/key_override_error.rb
57
+ - lib/rails/options_config/unusable_options_error.rb
43
58
  - lib/rails/options_config/version.rb
44
59
  - lib/rails/options_config/yaml/env_visitor.rb
45
60
  homepage: https://github.com/moku-io/rails-options
@@ -64,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
79
  - !ruby/object:Gem::Version
65
80
  version: '0'
66
81
  requirements: []
67
- rubygems_version: 3.4.21
82
+ rubygems_version: 3.5.22
68
83
  signing_key:
69
84
  specification_version: 4
70
85
  summary: A uniform interface to multiple option YAML files.