app_configurable 0.1.1 → 0.1.4

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: '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