app_configurable 0.1.1 → 0.1.4

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: '008ea1c3e9903d1ade8d43500aee26d9006173f2a51fd94ad20bda97f682a693'
4
- data.tar.gz: 0d905a63926d10af5b3f660d0e9c9051c4e4f44d190919c1c93e11c7b50cc598
3
+ metadata.gz: 044562b2da9b8df939abe454b140aab3d3389a893dc2dd31f278d9e9eae8495b
4
+ data.tar.gz: 932b8ae2e26fb5449a52c815e578689ea24a88578c11df79165d42edd5a2801a
5
5
  SHA512:
6
- metadata.gz: 5d98d1e7c611cc49a14a3ba0cec6fa1f1785fa9a3bd84b34cf663d1b0a1d4e3b27e4e0285af004565db73ad4a587d7b5e2f5b5f10bb1a40d3bec61204167c21f
7
- data.tar.gz: a5c238318515ebfe84cb4df741bc50b8be30a183b3f9c41f07e94fe11867743d10ecf67fbe83589f92d8e196d054344ffb67c5e89d75dcf683cdfe42faa8bc62
6
+ metadata.gz: 389a4ff576b8a3da9207ca41570becd67f3b5af38fb0e046c80468102ccd30a1d925f7a8817044f2ebaa88e900df26f5378972d5f92bc09bd0ac6eded9df9148
7
+ data.tar.gz: 190ec85b5ce0a351ae45d343d685a438b2b681f72746506c75ab01b5a373f5ffb493aa7d97706a0c1cabdd21878769ee4224880cd3d0afd7b1a1e99a8adacf94
data/.rubocop.yml CHANGED
@@ -26,7 +26,7 @@ Style/StringLiteralsInInterpolation:
26
26
  EnforcedStyle: double_quotes
27
27
 
28
28
  Layout/LineLength:
29
- Max: 120
29
+ Max: 180
30
30
 
31
31
  Style/ClassAndModuleChildren:
32
32
  Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- app_configurable (0.1.1)
4
+ app_configurable (0.1.4)
5
5
  dotenv
6
6
 
7
7
  GEM
@@ -112,7 +112,7 @@ GEM
112
112
  net-smtp
113
113
  marcel (1.0.4)
114
114
  mini_mime (1.1.5)
115
- minitest (5.25.1)
115
+ minitest (5.25.2)
116
116
  net-imap (0.5.1)
117
117
  date
118
118
  net-protocol
@@ -257,4 +257,4 @@ DEPENDENCIES
257
257
  rubocop-rspec_rails (~> 2.30.0)
258
258
 
259
259
  BUNDLED WITH
260
- 2.5.11
260
+ 2.5.23
data/README.md CHANGED
@@ -1,74 +1,113 @@
1
- # AppConfigurable
2
-
3
- Single source of truth for app configuration.
4
-
5
- ## Adding a new config
6
-
7
- There are 2 types of configs:
8
- - Namespaced - used to store configs which could be grouped by attributes such as external service name e.g Hubspot.
9
- - Root-level configs - generic configs for the app such as `rails_serve_static_files`.
10
-
11
- Example of namespaced config:
12
-
13
- ```ruby
14
- class AppConfig::Hubspot
15
- include AppConfigurable
16
-
17
- entry :access_token, default: 'secret'
18
- entry :base_url, default: 'https://app-eu1.hubspot.com/contacts/26265873', production: 'https://app-eu1.hubspot.com/contacts/25696692'
19
- entry :client_secret, default: 'secret'
20
- end
21
- ```
22
-
23
- Then config entries could be accessed through: `AppConfig::Hubspot.base_url`.
1
+ # App Configurable
2
+
3
+ ## Single source of truth for app configuration
4
+
5
+ App Configurable is a simple Ruby gem that provides a centralized and consistent way to manage application configurations. It allows you to define configurations in a single place and access them throughout your application, ensuring that your app's settings are always up-to-date and consistent across different environments.
6
+
7
+ ### Features
8
+ - Centralized configuration management
9
+ - Environment-specific settings
10
+ - Fail on demand or on app startup
11
+ - Support for namespaced and root-level configurations
12
+ - Easy integration with Rails applications
13
+
14
+ ### Installation
15
+ 1. Add the gem to your Gemfile:
16
+ ```ruby
17
+ gem 'app_configurable'
18
+ ```
19
+ 2. Define your configurations in `config/app_config.rb`:
20
+ ```ruby
21
+ class AppConfig
22
+ include AppConfigurable
23
+
24
+ entry :secret_key, default: 'your_secret_key'
25
+ entry :base_url, default: 'http://my-site.local', production: 'http:// my-site.io', staging: 'http://staging.my-site.io'
26
+ end
27
+ ```
28
+ 3. Load the configurations:
29
+
30
+ Define an initializer `config/initializers/_app_config.rb`:
31
+ ```ruby
32
+ AppConfigurable.load(%w[./config/app_config.rb])
33
+ ```
34
+ OR
35
+ ```ruby
36
+ AppConfigurable.load(%w[./config/app_config.rb], raise_on_missing: true) # Fails on startup, reporting missing configs.
37
+ ```
38
+ *Alternatively, you could define your configs under the autoloading path if failing on demand is acceptable.*
39
+
40
+ 4. Access your configurations:
41
+ ```ruby
42
+ AppConfig.secret_key
43
+ ```
44
+
45
+ ### Adding a config
46
+ There are two types of configurations:
47
+ - **Namespaced**: Used to store configurations grouped by attributes such as external service names (e.g., Hubspot).
48
+ - **Root-level configs**: Generic configurations for the app, such as `rails_serve_static_files`.
49
+
50
+ ### Example
51
+ `./config/app_config.rb`:
52
+ ```ruby
53
+ class AppConfig
54
+ include AppConfigurable
55
+
56
+ entry :secret_key_base, default: 'secret_key_base'
57
+ entry :base_url, default: 'http://my-site.local', production: 'http:// my-site.io', staging: 'http://staging.my-site.io'
58
+ entry :client_secret, default: 'client_secret_token'
59
+ end
60
+ ```
61
+
62
+ `./config/app_config/hubspot.rb`:
63
+ ```ruby
64
+ class AppConfig::Hubspot
65
+ include AppConfigurable
66
+
67
+ entry :access_token, default: 'secret_access_token'
68
+ entry :base_url, default: 'https://hubspot.com/1234', production: 'https:// hubspot.com/4321'
69
+ entry :client_secret, default: 'client_secret_token'
70
+ end
71
+ ```
72
+
73
+ Declared configs can be accessed through: `AppConfig.secret_key_base` and `AppConfig::Hubspot.base_url`.
24
74
 
25
75
  ## Attributes
26
- Attributes are declared using `entry` directive.
76
+
77
+ Attributes are declared using the `entry` directive.
27
78
  Example: `entry :rails_serve_static_files`.
28
79
 
29
80
  ### Options
30
- `production/staging/development/test` - sets attributes per environment.
31
-
32
- `default`:
33
- - sets default attribute, used in `production/staging/development` environments as a fallback.
34
- - accepts `string`/`number`/`boolean` as well as `Proc`/`Lambda` as a parameter.
35
- - in `test` environment always falls back to a dummy value `some_super_dummy_#{namespaced_attribute_name}`
81
+ - **production/staging/development/test**: Sets attributes per environment.
82
+ - **default**:
83
+ - Sets the default attribute, used in `production/staging/development` environments as a fallback.
84
+ - Accepts `string`/`number`/`boolean` as well as `Proc`/`Lambda` as a parameter.
85
+ - In the `test` environment, always falls back to a dummy value `some_super_dummy_#{namespaced_attribute_name}` unless specified explicitly.
36
86
 
37
- #### Priority and lifecycle:
38
- `production/staging/development`:
39
- 1) Tries to find a value in joint hash of `ENV` and `Rails.application.credentials`.
40
- 2) Gets value from specific environment attribute passed to `entry`.
41
- 3) Get's value from `default`.
42
- 4) Raises `AppConfig::Error::RequiredVarMissing` if no attribute found.
87
+ #### Priority
88
+ - **production/staging/development**:
89
+ 1. Find value in `ENV`.
90
+ 2. Find value in specific environment attribute passed to `entry`.
91
+ 3. Find value from `default`.
92
+ 4. Fail with `AppConfig::Error::RequiredVarMissing`.
43
93
 
44
- `testing`:
45
- 1) Tries to find a value in joint hash of `ENV` and `Rails.application.credentials`.
46
- 2) Gets value from `test` environment attribute.
47
- 3) Returns `some_super_dummy_#{namespaced_attribute_name}`, ignores specified `default` attribute.
94
+ - **testing**:
95
+ 1. Find value in `ENV`.
96
+ 2. Find value in `test` attribute of config `entry`.
97
+ 3. Return `some_super_dummy_#{namespaced_attribute_name}`, **ignoring the specified `default` attribute**.
48
98
 
49
- ### Setting the environment:
50
- You could set environment per namespace like so:
99
+ ### Setting the Environment
100
+ You can set the environment per namespace like so:
51
101
 
52
- Given namespace `AppConfig::MyNiceConfigClass` and `.env.staging`
102
+ Given namespace `AppConfig::MyNiceConfigClass` and `.env.staging`:
53
103
 
54
104
  ```bash
55
105
  APPCONFIG_MYNICEMODULE_ENV=staging rspec
56
106
  ```
57
107
 
58
- *`.env.#{RAILS_ENV}` will be read per specific `AppConfig::SomeNiceClass` class.*
59
-
60
- ### Fail on startup:
61
- Create a new initializer in `config/initializers/_app_config.rb`
62
-
63
- ```
64
- # Require your config files
65
- require './config/app_config' # Root-level configs.
66
- FileList['./config/app_config/*.rb'].each { |file| require file } # Secondary-level/namespaced configs.
67
-
68
- missing = AppConfigurable.missing_required_vars
69
- missing.present? and raise "Missing required ENV variables/encrypted credentials: #{missing.inspect}"
70
- ```
108
+ `.env.#{RAILS_ENV}` will be read per specific `AppConfig::SomeNiceClass` class.
71
109
 
72
110
  ### TODO:
73
- - Read `Rails.application.credentials`
74
- - Make dynamic switch possible, simillar to what we have with `ENV`.
111
+
112
+ - Read `Rails.application.credentials`.
113
+ - Make dynamic switch possible, similar to what we have with `ENV`.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppConfigurable
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.4'
5
5
  end
@@ -18,10 +18,26 @@ module AppConfigurable
18
18
  owner.include InstanceMethods
19
19
  end
20
20
 
21
+ # Returns the list of available configuration attributes,
22
+ # which are defined with the `entry` method.
23
+ # @return [Array]
21
24
  def self.available_config_attributes
22
25
  @@available_config_attributes
23
26
  end
24
27
 
28
+ # @param paths [Array] List of paths to load.
29
+ # @param raise_on_missing [Boolean] Raise an error if required variables are missing, default is `false`.
30
+ # @return [void]
31
+ def self.load_configs(paths = [], raise_on_missing: false)
32
+ paths.each do |path|
33
+ absolute_path = Dir.pwd + "/#{path}"
34
+
35
+ File.directory?(absolute_path) ? Dir["#{absolute_path}/**/*.rb"].each { |f| require f } : require(absolute_path)
36
+ end
37
+
38
+ raise_on_missing && missing_required_vars.any? && raise(Error::RequiredVarMissing, missing_required_vars.join(', '))
39
+ end
40
+
25
41
  # Report missing required `ENV` variables.
26
42
  # @return [Array]
27
43
  def self.missing_required_vars
@@ -118,16 +134,14 @@ module AppConfigurable
118
134
  attrs.each { |k, v| public_send(:"#{k}=", v) }
119
135
  end
120
136
 
121
- # A *copy* of the credentials for value-reading purposes.
122
- # @return [Hash]
123
- def credentials
124
- @credentials ||= ::Rails.application&.credentials.to_h
125
- end
126
-
127
137
  # A *copy* of the environment for value-reading purposes.
128
138
  # @return [Hash]
129
139
  def env
130
- @env ||= ::Rails.env == rails_env ? ENV.to_h : ::Dotenv.parse(".env.#{rails_env}")
140
+ @env ||=
141
+ begin
142
+ result = ::Rails.env == rails_env ? ENV.to_h : ::Dotenv.parse(".env.#{rails_env}")
143
+ result.deep_transform_keys!(&:downcase).with_indifferent_access
144
+ end
131
145
  end
132
146
 
133
147
  # @!attribute rails_env
@@ -171,13 +185,13 @@ module AppConfigurable
171
185
 
172
186
  # @see #env_truthy?
173
187
  def env_falsey?(key)
174
- self.class.env_value_falsey?(secrets[key.to_s])
188
+ self.class.env_value_falsey?(env[key.to_s])
175
189
  end
176
190
 
177
191
  # @param key [String/Symbol]
178
192
  # @return [String/Boolean] The value of the environment variable, converts `bolean`'ish values into boolean.
179
193
  def env_value(key)
180
- v = secrets.dig(*key)
194
+ v = env.dig(*key)
181
195
  v = env_truthy?(key) if env_boolean?(key)
182
196
  v
183
197
  end
@@ -190,7 +204,7 @@ module AppConfigurable
190
204
  # @param key [String]
191
205
  # @return [Boolean]
192
206
  def env_truthy?(key)
193
- self.class.env_value_truthy?(secrets[key.to_s])
207
+ self.class.env_value_truthy?(env[key.to_s])
194
208
  end
195
209
 
196
210
  # @param name [Symbol/String]
@@ -209,7 +223,7 @@ module AppConfigurable
209
223
  result = default_value.call(dummy_value) if result.nil?
210
224
  if result.nil?
211
225
  raise Error::RequiredVarMissing,
212
- "Required ENV variable or credential missing: #{self.class.name}.#{name}"
226
+ "Required ENV variable is missing: #{self.class.name}.#{name}"
213
227
  end
214
228
 
215
229
  result
@@ -232,14 +246,6 @@ module AppConfigurable
232
246
  send(:env)
233
247
  end
234
248
 
235
- # TODO: Implement this. Currently it's not re-reading secrets after enviromnemt change.
236
- # Recalculates the `credentials` hash.
237
- # @return [void]
238
- def recalculate_credentials
239
- remove_instance_variable(:@credentials) if instance_variable_defined?(:@credentials)
240
- send(:credentials)
241
- end
242
-
243
249
  # Recalculates the values of all the attributes.
244
250
  # @return [void]
245
251
  def recalculate_values
@@ -248,11 +254,5 @@ module AppConfigurable
248
254
  send(a)
249
255
  end
250
256
  end
251
-
252
- # Joint hash of `ENV` and `Rails.application.credentials`
253
- # @return [HashWithIndifferentAccess]
254
- def secrets
255
- { **env }.deep_transform_keys!(&:downcase).with_indifferent_access
256
- end
257
257
  end
258
258
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_configurable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmytro Pasichnyk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-20 00:00:00.000000000 Z
11
+ date: 2024-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -184,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
184
  - !ruby/object:Gem::Version
185
185
  version: '0'
186
186
  requirements: []
187
- rubygems_version: 3.3.27
187
+ rubygems_version: 3.5.22
188
188
  signing_key:
189
189
  specification_version: 4
190
190
  summary: AppConfigurable allows you to configure your application with a simple DSL