ultra_settings 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +150 -68
- data/VERSION +1 -1
- data/app/application.css +4 -25
- data/app/configuration.html.erb +134 -0
- data/app/index.html.erb +1 -73
- data/lib/ultra_settings/configuration.rb +73 -5
- data/lib/ultra_settings/configuration_view.rb +91 -0
- data/lib/ultra_settings/field.rb +19 -4
- data/lib/ultra_settings.rb +7 -1
- data/ultra_settings.gemspec +7 -1
- metadata +13 -7
- /data/{MIT-LICENSE → MIT-LICENSE.txt} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6740e40d7198c0cb0573b24f5e61c0f679e8fb62b0c18bee3ee79a29748bc908
|
4
|
+
data.tar.gz: d35bb1603d4acfedcf32c8cc7c6063e0deeabb47e825d646ff104568a30de898
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f4e91264bd4466d0509f813a8b33391a15645ec939395055c353b1d0e162a6de0c89ea78f84139bdffeae3b61033652b58cb373d7cde47b4ee559923e2fe8a5
|
7
|
+
data.tar.gz: 341535915553d7d4d906c79850c4d42630c115ed030fae69b2e851042b999a654982ec7416a120195e65c0b436587b75e330259d675308facea3dedc5db59b98
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 1.1.0
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Revamped web UI that can now display setting values.
|
12
|
+
- Added option to specify fields as a secret in the configuration to prevent exposing sensitive information in the web interface. By default all fields are considered secrets. This can be changed per configuration by setting the `fields_secret_by_default` property to `false`.
|
13
|
+
- Added `UltraSettings::ConfigurationView` which can be used to embed the HTML table showing the configuration options and values other admin views. So now you can integrate the settings view into your own admin tools.
|
14
|
+
- Add `__to_hash__` method to `UltraSettings::Configuration` which can to serialize the current configuration values as a hash. This value can be used for comparing configuration between environments.
|
15
|
+
|
7
16
|
## 1.0.1
|
8
17
|
|
9
18
|
### Added
|
data/README.md
CHANGED
@@ -1,22 +1,30 @@
|
|
1
1
|
# UltraSettings
|
2
2
|
|
3
3
|
[![Continuous Integration](https://github.com/bdurand/ultra_settings/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/bdurand/ultra_settings/actions/workflows/continuous_integration.yml)
|
4
|
-
[![Regression Test](https://github.com/bdurand/ultra_settings/actions/workflows/regression_test.yml/badge.svg)](https://github.com/bdurand/ultra_settings/actions/workflows/regression_test.yml)
|
5
4
|
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/ultra_settings.svg)](https://badge.fury.io/rb/ultra_settings)
|
6
6
|
|
7
|
-
|
7
|
+
## Introduction
|
8
8
|
|
9
|
-
|
9
|
+
UltraSettings is a Ruby gem designed for managing application settings from various sources providing a consistent method for accessing configuration values. It simplifies your application's configuration management by allowing settings to be defined, documented, and accessed seamlessly.
|
10
10
|
|
11
|
-
|
12
|
-
2. Runtime settings (i.e. settings updatable from within the running application)
|
13
|
-
3. YAML configuration files
|
11
|
+
UltraSettings emphasizes well-documented configuration. You can include documentation directly in the configuration code. The gem also includes a [web UI](#web-ui) that can be mounted as a Rack app or embedded in other views allowing admin users to easily view configuration settings and documentation.
|
14
12
|
|
15
|
-
|
13
|
+
## Key Features
|
16
14
|
|
17
|
-
|
15
|
+
This gem supports a three-layer hierarchy for defining configuration sources:
|
18
16
|
|
19
|
-
|
17
|
+
1. Environment Variables
|
18
|
+
2. Runtime Settings (modifiable within the running application)
|
19
|
+
3. YAML Configuration Files
|
20
|
+
|
21
|
+
Settings from higher levels override those from lower ones. For example, values defined in environment variables or runtime settings will override those specified in YAML files. This hierarchy is optional — you can disable it and define specific data sources as needed for each configuration field.
|
22
|
+
|
23
|
+
### Simplified Access and Type Safety
|
24
|
+
|
25
|
+
With UltraSettings, your application code does not need to worry about how or from where a setting value is loaded from. Configuration settings can be accessed using plain Ruby objects and methods simplifying the development process.
|
26
|
+
|
27
|
+
The gem also ensures type safety by typecasting settings to specific data types, so you can rely on consistent data formats without manual type coercion. Supported types include:
|
20
28
|
|
21
29
|
- `String`
|
22
30
|
- `Integer`
|
@@ -26,34 +34,39 @@ Settings are also type cast so you can always be assured that values are returne
|
|
26
34
|
- `Symbol`
|
27
35
|
- `Array<String>`
|
28
36
|
|
29
|
-
|
30
|
-
|
31
|
-
Settings are accessed through singleton classes that you define.
|
37
|
+
Additionally, you can define default values for settings, ensuring that a fallback value is available if a configuration is missing or does not meet constraints.
|
32
38
|
|
33
39
|
## Usage
|
34
40
|
|
35
41
|
### Defining Configurations
|
36
42
|
|
37
|
-
Configurations are classes that extend from the `UltraSettings::Configuration` class.
|
43
|
+
Configurations are defined as classes that extend from the `UltraSettings::Configuration` class. These configuration classes are [singleton classes](https://ruby-doc.org/3.2.2/stdlibs/singleton/Singleton.html).
|
38
44
|
|
39
45
|
You can define fields on your configuration classes with the `field` method. This will define a method on your configuration object with the given name.
|
40
46
|
|
41
47
|
```ruby
|
42
48
|
class MyServiceConfiguration < UltraSettings::Configuration
|
43
|
-
|
49
|
+
self.fields_secret_by_default = false
|
50
|
+
|
51
|
+
field :host, type: :string, description: "The hostname for the service"
|
44
52
|
|
45
|
-
field :port, type: :integer, default: 80
|
53
|
+
field :port, type: :integer, default: 80, description: "The port for the service"
|
46
54
|
|
47
|
-
field :protocol, type: :string, default: "https"
|
55
|
+
field :protocol, type: :string, default: "https", description: "The protocol for the service"
|
48
56
|
|
49
|
-
field :timeout,
|
57
|
+
field :timeout,
|
58
|
+
type: :float,
|
59
|
+
default: 1.0,
|
60
|
+
default_if: ->(val) { val <= 0 },
|
61
|
+
description: "Network timeout in seconds for requests to the service."
|
50
62
|
|
51
63
|
field :auth_token,
|
52
64
|
type: :string,
|
53
65
|
env_var: "MY_SERVICE_TOKEN",
|
54
66
|
runtime_setting: false,
|
55
67
|
yaml_key: false,
|
56
|
-
description: "Bearer token for accessing the service"
|
68
|
+
description: "Bearer token for accessing the service",
|
69
|
+
secret: true
|
57
70
|
|
58
71
|
# You aren't limited to just defining fields, you can define other
|
59
72
|
# helper methods to make using the configuration easier.
|
@@ -63,51 +76,67 @@ class MyServiceConfiguration < UltraSettings::Configuration
|
|
63
76
|
end
|
64
77
|
```
|
65
78
|
|
66
|
-
|
79
|
+
#### Field Options
|
80
|
+
|
81
|
+
You can customize the behavior of each field using various options:
|
82
|
+
|
83
|
+
- `:type` - Specifies the type of the field. The value of the setting will be cast to this type. If the value in the data source cannot be cast to the data type, then it will not be used. Supported types are:
|
67
84
|
|
68
85
|
- `:string` (the default)
|
69
86
|
- `:integer`
|
70
87
|
- `:float`
|
71
|
-
- `:boolean`
|
88
|
+
- `:boolean` (will accept case insensitive strings "true", "false", "1", "0", "t", "f", "yes", "no", "y", "n")
|
72
89
|
- `:datetime`
|
73
90
|
- `:symbol`
|
74
91
|
- `:array` (of strings)
|
75
92
|
|
76
|
-
-
|
93
|
+
- `:description` - Provides a description of the field. This is used for documentation purposes.
|
94
|
+
|
95
|
+
- `:default` - Sets a default value for the field. The value will be cast to the specified type.
|
77
96
|
|
78
|
-
-
|
97
|
+
- `:default_if` - Provides a condition for when the default should be used. This should be a Proc or the name of a method within the class. Useful for ensuring values meet specific constraints. This can provide protection from misconfiguration that can break the application. In the above example, the default value for `timeout` will be used if the value is less than or equal to 0.
|
79
98
|
|
80
|
-
-
|
99
|
+
- `:secret` - Marks the field as secret. Secret fields are not displayed in the web UI. By default, all fields are considered secret to avoid accidentally exposing sensitive values. You can change this default behavior by setting `fields_secret_by_default` to `false` either globally or per configuration.
|
81
100
|
|
82
|
-
-
|
101
|
+
- `:env_var` - Overrides the environment variable name used to populate the field. This is useful if the variable name does not follow the conventional pattern. Set this to `false` to disable loading the field from an environment variable.
|
83
102
|
|
84
|
-
-
|
103
|
+
- `:runtime_setting` - Overrides the runtime setting name for the field. Useful if the runtime setting name does not match the conventional pattern. Set this to `false` to disable loading the field from runtime settings.
|
85
104
|
|
86
|
-
-
|
105
|
+
- `:yaml_key` - Overrides the key in the YAML configuration file for this field. This is useful when the key does not match the field name. Set this to `false` to disable loading the field from a YAML file.
|
87
106
|
|
88
|
-
-
|
107
|
+
- `:static` - Marks the field as a static value. Static values cannot be changed once set and are not allowed to be set from runtime settings. Use this for settings that need to be referenced at the application is initializing.
|
89
108
|
|
90
109
|
### Environment Variables
|
91
110
|
|
92
|
-
Settings will first try to load values from environment variables. Environment variables are a good place to define environment specific values.
|
111
|
+
Settings will first try to load values from environment variables. Environment variables are a good place to define environment specific values or sensitive values that you do not want to store in your codebase.
|
112
|
+
|
113
|
+
#### Default Behavior
|
114
|
+
|
115
|
+
By default, environment variables for settings are constructed using a prefix based on the configuration class name, with the field name appended. For example, a class named `Configs::MySettingsConfiguration` will use the prefix `CONFIGS_MY_SETTINGS_`, resulting in environment variables like `CONFIGS_MY_SETTINGS_HOST`.
|
93
116
|
|
94
|
-
|
117
|
+
#### Customizing Environment Variables
|
95
118
|
|
96
|
-
You can
|
119
|
+
You can customize the behavior of environment variable naming in several ways:
|
97
120
|
|
98
|
-
You can
|
121
|
+
- **Explicit Environment Variables:** You can specify the name of the environment variable to use for a field by setting the `env_var` option on the field. This allows you to use a different name than the default.
|
99
122
|
|
100
|
-
|
123
|
+
- **Lowercase Environment Variables:** Set `env_var_upcase` to false in your configuration class to use lowercase environment variable names.
|
101
124
|
|
102
|
-
|
125
|
+
- **Custom Delimiter:** The delimiter between module names and before the setting name can be customized by setting `env_var_delimiter` on your configuration class. For example, using a delimiter of "." in `Configs::MySettingsConfiguration` would produce environment variables like `CONFIGS.MY_SETTINGS.HOST`.
|
126
|
+
|
127
|
+
- **Custom Prefix:** Set `env_var_prefix` on your configuration class to specify an explicit prefix for environment variables. This allows for more flexibility in naming conventions.
|
128
|
+
|
129
|
+
- **Disabling Environment Variables:** You can disable environment variables as a default source for fields by setting `environment_variables_disabled` to `true` in your configuration class. You can disable environent variables on individual fields by setting `env_var` on the field to `false`.
|
103
130
|
|
104
131
|
If a setting value cannot be loaded from an environment variable, then it's value will attempt to be loaded from a runtime setting.
|
105
132
|
|
106
133
|
### Runtime Settings
|
107
134
|
|
108
|
-
Runtime settings are
|
135
|
+
Runtime settings are configurations loaded while your application is running, allowing for dynamic updates without needing to restart the application. This flexibility makes them ideal for settings that may change frequently or need quick adjustments.
|
136
|
+
|
137
|
+
#### Setting Up Runtime Settings
|
109
138
|
|
110
|
-
To
|
139
|
+
To enable runtime settings, set the `UltraSettings.runtime_settings` attribute to an object that implements a `[]` method and accepts a string argument. For example, to load runtime settings from a Redis database, you could use the following implementation:
|
111
140
|
|
112
141
|
```ruby
|
113
142
|
class RedisRuntimeSettings
|
@@ -123,39 +152,57 @@ end
|
|
123
152
|
UltraSettings.runtime_settings = RedisRuntimeSettings.new
|
124
153
|
```
|
125
154
|
|
126
|
-
|
155
|
+
#### Using the `super_settings` gem
|
156
|
+
|
157
|
+
There is a companion gem [super_settings](https://github.com/bdurand/super_settings) that can be used as a drop in implementation for the runtime settings. You just need to set the runtime settings to the `SuperSettings` object.
|
127
158
|
|
128
159
|
```ruby
|
129
160
|
UltraSettings.runtime_settings = SuperSettings
|
130
161
|
```
|
131
162
|
|
132
|
-
|
163
|
+
#### Customizing Runtime Settings
|
164
|
+
|
165
|
+
By default settings will be loaded from runtime settings by constructing a prefix from the configuration class name (i.e. `Configs::MySettingsConfiguration` uses the prefix `configs.my_settings.`) with the field name appended to it (e.g. `configs.my_settings.host`). By default runtime settings will be in all lowercase letters.
|
166
|
+
|
167
|
+
You can customize the behavior of runtime setting names with the following options:
|
133
168
|
|
134
|
-
You can
|
169
|
+
- **Explicit Runtime Setting Names:** You can specify the name of the runtime setting to use for a field by setting the `runtime_setting` option on the field. This allows you to use a different name than the default.
|
135
170
|
|
136
|
-
|
171
|
+
- **Uppercase Runtime Setting Names:** Set `runtime_setting_upcase` to true in your configuration class to use uppercase runtime setting names.
|
137
172
|
|
138
|
-
|
173
|
+
- **Custom Delimiter:** Change the delimiter used between module names and before the setting name by setting `runtime_setting_delimiter` on your configuration class. For example, using a delimiter of "/" would produce runtime settings like `configs/my_settings/host`.
|
139
174
|
|
140
|
-
|
175
|
+
- **Custom Prefix:** Set `runtime_setting_prefix` on your configuration class to specify a custom prefix for runtime settings, giving you flexibility in naming conventions.
|
176
|
+
|
177
|
+
- **Disabling Runtime Settings:** You can disable runtime settings as a default source for fields by setting `runtime_settings_disabled` to `true` in your configuration class. You can disable runtime settings on individual fields by setting `runtime_setting` on the field to `false`.
|
141
178
|
|
142
179
|
If a setting value cannot be loaded from the runtime settings, then it's value will attempt to be loaded from a YAML file.
|
143
180
|
|
144
181
|
### YAML Files
|
145
182
|
|
146
|
-
|
183
|
+
YAML files are the final source UltraSettings will check when loading configuration values. They provide a convenient way to store default values that can be distributed with your application code.
|
184
|
+
|
185
|
+
By default settings will be loaded from a YAML file determined by its class name (i.e. `Configs::MySettingsConfiguration` uses the file `configs/my_settings.yml`). The file is searched for in the path defined by `UltraSettings.yaml_config_path`. If the file does not exist, the YAML source strategy will not be used.
|
186
|
+
|
187
|
+
#### Customizing YAML Files
|
188
|
+
|
189
|
+
- **Explicit YAML Key:** You can specify the key in the YAML file to use for a field by setting the `yaml_key` option on the field. This allows you to use a different key than the default.
|
190
|
+
|
191
|
+
- **Custom YAML File Path:** You can specify an explicit YAML file by setting `configuration_file` on your configuration class to the desired file path.
|
147
192
|
|
148
|
-
|
193
|
+
- **Disable YAML Source:** To disable YAML files as a default source for your fields, set `yaml_config_disabled` to true on your configuration class. You can disable YAML files on individual fields by setting `yaml_key` on the field to `false`.
|
149
194
|
|
150
|
-
|
195
|
+
#### ERB Support
|
151
196
|
|
152
|
-
|
197
|
+
YAML files support ERB markup (i.e., <%= %>) that will be evaluated before the YAML is parsed. This feature allows for dynamically generated values within the YAML file.
|
153
198
|
|
154
|
-
|
199
|
+
#### Environment-Specific Configurations
|
155
200
|
|
156
|
-
YAML files define environment
|
201
|
+
YAML files can define environment-specific configurations. The file must contain a hash where the keys represent the names of your application environments (e.g., `development`, `test`, `production`). You can specify the environment to use by setting `UltraSettings.yaml_config_env` (default is "development").
|
157
202
|
|
158
|
-
|
203
|
+
A special key, `shared`, can be defined in the YAML file. The settings under this key will be merged with the environment-specific settings. Values from the specific environment will always overwrite those from `shared`.
|
204
|
+
|
205
|
+
#### Example YAML File
|
159
206
|
|
160
207
|
```yaml
|
161
208
|
shared:
|
@@ -170,7 +217,7 @@ production:
|
|
170
217
|
host: prod.example.com
|
171
218
|
```
|
172
219
|
|
173
|
-
The values for the
|
220
|
+
The values for the development environment would be the combination of `development` and `shared`:
|
174
221
|
|
175
222
|
```ruby
|
176
223
|
{
|
@@ -180,7 +227,7 @@ The values for the "development" environment would be the combination of develop
|
|
180
227
|
}
|
181
228
|
```
|
182
229
|
|
183
|
-
While for
|
230
|
+
While for production, the values would be the combination of `production` and `shared`:
|
184
231
|
|
185
232
|
```ruby
|
186
233
|
{
|
@@ -190,13 +237,13 @@ While for "production", the values would be the combination of production and sh
|
|
190
237
|
}
|
191
238
|
```
|
192
239
|
|
193
|
-
|
240
|
+
#### Rails Integration
|
194
241
|
|
195
242
|
In a Rails application, the YAML environment will be set to the Rails environment and YAML files will be assumed to exist in the `config` directory.
|
196
243
|
|
197
244
|
### Removing The Hierarchy
|
198
245
|
|
199
|
-
If you
|
246
|
+
If you prefer not to use the default hierarchy of environment variables, runtime settings, and YAML files, you can disable it. This allows you to explicitly define which data sources should be used for each field.
|
200
247
|
|
201
248
|
```ruby
|
202
249
|
class MyServiceConfiguration < UtraSettings::Configuration
|
@@ -220,25 +267,30 @@ UltraSettings.yaml_config_disabled = true
|
|
220
267
|
|
221
268
|
### Accessing settings
|
222
269
|
|
223
|
-
Configurations are singleton objects
|
270
|
+
Configurations in UltraSettings are singleton objects, and settings are accessed by calling methods directly on these objects.
|
224
271
|
|
225
272
|
```ruby
|
226
273
|
MyServiceConfiguration.instance.host
|
227
274
|
```
|
228
275
|
|
229
|
-
|
276
|
+
#### Adding Configurations to UltraSettings
|
277
|
+
|
278
|
+
To simplify access, you can add configurations to the `UltraSettings` object. UltraSettings will derive the configuration class name based on the name provided and define a method that returns the configuraiton object. For example:
|
279
|
+
|
230
280
|
```ruby
|
231
281
|
UltraSettings.add(:my_service)
|
282
|
+
UltraSettings.my_service # => MyServiceConfiguration.instance
|
232
283
|
UltraSettings.my_service.host
|
233
284
|
```
|
234
285
|
|
235
|
-
|
286
|
+
Alternatively, you can explicitly specify the class name to map to a method name:
|
287
|
+
|
236
288
|
```ruby
|
237
289
|
UltraSettings.add(:my, "MyServiceConfiguration")
|
238
290
|
UltraSettings.my.host
|
239
291
|
```
|
240
292
|
|
241
|
-
In a Rails application, you could add
|
293
|
+
In a Rails application, you could add syntactic sugar by exposing the `UltraSettings` object as a helper method in application.rb.
|
242
294
|
|
243
295
|
```ruby
|
244
296
|
module MyApp
|
@@ -252,7 +304,10 @@ end
|
|
252
304
|
Rails.application.settings.my_service.host
|
253
305
|
```
|
254
306
|
|
255
|
-
|
307
|
+
#### Using a Helper Method
|
308
|
+
|
309
|
+
To keep your codebase clean, especially if most configurations are accessed from within a specific class, you can encapsulate the configuration access in a helper method.
|
310
|
+
|
256
311
|
|
257
312
|
```ruby
|
258
313
|
class MyService
|
@@ -269,11 +324,16 @@ end
|
|
269
324
|
|
270
325
|
### Web UI
|
271
326
|
|
272
|
-
|
327
|
+
UltraSettings provides a web UI via a mountable Rack application. You can use this to view the settings values and documentation. The UI will not display the value of any setting marked as secret.
|
273
328
|
|
274
329
|
![Web UI](assets/web_ui.png)
|
275
330
|
|
276
|
-
|
331
|
+
It is strongly recommended to secure the web UI with your application's authorization framework so that it is only visible to internal admin users.
|
332
|
+
|
333
|
+
#### Mounting the Web UI in a Rails Application
|
334
|
+
|
335
|
+
Below is an example of mounting the web UI in a Rails application using HTTP Basic authentication.
|
336
|
+
|
277
337
|
|
278
338
|
```ruby
|
279
339
|
# config/routes.rb
|
@@ -286,13 +346,26 @@ mount Rack::Builder.new do
|
|
286
346
|
end, at: "/ultra_settings"
|
287
347
|
```
|
288
348
|
|
289
|
-
|
349
|
+
#### Embedding the Settings View in Admin Tools
|
350
|
+
|
351
|
+
If you prefer to embed the settings view directly into your own admin tools or dashboard, you can use the `UltraSettings::ConfigurationView` class to render the settings interface within your existing views:
|
352
|
+
|
353
|
+
```erb
|
354
|
+
<h1>My Service Settings</h1>
|
355
|
+
|
356
|
+
<%= UltraSettings::ConfigurationView.new(MyServiceConfiguration.instance).render %>
|
357
|
+
```
|
358
|
+
|
359
|
+
This approach allows for seamless integration of the settings UI into your application's admin interface, leveraging your existing authentication and authorization mechanisms. The settings are rendered in an HTML table which you can format with your own CSS.
|
290
360
|
|
291
|
-
|
361
|
+
### Testing With UltraSettings
|
362
|
+
|
363
|
+
When writing automated tests, you may need to override configuration settings to test different scenarios. UltraSettings provides the `UltraSettings.override!` method to temporarily change settings within a test block. Below are examples of how to override the `TestConfiguration#foo` value in a test.
|
292
364
|
|
293
365
|
```ruby
|
294
|
-
# Override a configuration added on the global namespace
|
366
|
+
# Override a configuration added on the global namespace.
|
295
367
|
|
368
|
+
# Note: you must have already added the configuration with UltraSettings.add(:test)
|
296
369
|
UltraSettings.override!(test: {foo: "bar"}) do
|
297
370
|
expect(TestConfiguration.instance.foo).to eq "bar"
|
298
371
|
end
|
@@ -310,14 +383,17 @@ TestConfiguration.instance.override!(foo: "bar") do
|
|
310
383
|
end
|
311
384
|
```
|
312
385
|
|
313
|
-
|
386
|
+
#### RSpec Integration
|
387
|
+
|
388
|
+
If you are using RSpec, you can simplify overriding settings by setting up a global around hook. This hook will check for the presence of a :settings metadata key and apply the overrides automatically within the test block.
|
389
|
+
|
314
390
|
|
315
391
|
```ruby
|
316
392
|
# RSpec setup
|
317
393
|
RSpec.configure do |config|
|
318
|
-
config.around do |example|
|
319
|
-
if example.metadata[:
|
320
|
-
UltraSettings.override!(example.metadata[:
|
394
|
+
config.around(:each, :settings) do |example|
|
395
|
+
if example.metadata[:settings].is_a?(Hash)
|
396
|
+
UltraSettings.override!(example.metadata[:settings]) do
|
321
397
|
example.run
|
322
398
|
end
|
323
399
|
else
|
@@ -325,13 +401,19 @@ RSpec.configure do |config|
|
|
325
401
|
end
|
326
402
|
end
|
327
403
|
end
|
404
|
+
```
|
405
|
+
|
406
|
+
With this setup, you can easily specify settings overrides within individual test blocks using metadata:
|
328
407
|
|
329
|
-
|
330
|
-
it 'has the settings I want',
|
408
|
+
```ruby
|
409
|
+
it 'has the settings I want', settings: {test: {foo: "bar"}} do
|
331
410
|
expect(UltraSettings.test.foo).to eq("bar")
|
332
411
|
end
|
333
412
|
```
|
334
413
|
|
414
|
+
This approach keeps your tests clean and readable while allowing for flexible configuration management during testing.
|
415
|
+
|
416
|
+
|
335
417
|
## Installation
|
336
418
|
|
337
419
|
Add this line to your application's Gemfile:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/app/application.css
CHANGED
@@ -28,39 +28,18 @@
|
|
28
28
|
background-color: rgba(0, 0, 0, .03);
|
29
29
|
}
|
30
30
|
|
31
|
-
.ultra-settings-code {
|
31
|
+
.ultra-settings-table code {
|
32
32
|
font-family: monospace;
|
33
33
|
font-size: 0.9rem;
|
34
34
|
display: inline;
|
35
|
-
|
36
|
-
|
37
|
-
.ultra-settings-static {
|
38
|
-
color: gray;
|
39
|
-
font-style: italic;
|
40
|
-
font-size: 0.9rem;
|
41
|
-
}
|
42
|
-
|
43
|
-
.ultra-settings-current-source {
|
35
|
+
color: darkred;
|
44
36
|
font-weight: 600;
|
45
|
-
color: blue;
|
46
37
|
}
|
47
38
|
|
48
|
-
.ultra-settings-
|
49
|
-
font-size: 0.9rem;
|
39
|
+
.ultra-settings-table em {
|
50
40
|
color: gray;
|
51
|
-
}
|
52
|
-
|
53
|
-
.ultra-settings-info {
|
54
|
-
margin-bottom: 1rem;
|
55
|
-
}
|
56
|
-
|
57
|
-
.ultra-settings-error {
|
58
|
-
color: darkred;
|
59
|
-
}
|
60
|
-
|
61
|
-
.ultra-settings-not-applicable {
|
62
|
-
color: #999;
|
63
41
|
font-style: italic;
|
42
|
+
font-size: 0.9rem;
|
64
43
|
}
|
65
44
|
|
66
45
|
.ultra-settings-select {
|
@@ -0,0 +1,134 @@
|
|
1
|
+
<table class="<%= html_escape(table_class.to_s) %>">
|
2
|
+
<thead>
|
3
|
+
<% unless configuration.class.yaml_config_disabled? || configuration.class.configuration_file.nil? %>
|
4
|
+
<tr>
|
5
|
+
<th colspan="6">
|
6
|
+
Configuration File:
|
7
|
+
<span style="font-weight: normal;">
|
8
|
+
<%= html_escape(relative_path(configuration.class.configuration_file)) %>
|
9
|
+
<% unless configuration.class.configuration_file&.exist? %>
|
10
|
+
<em>(File does not exist)</em>
|
11
|
+
<% end %>
|
12
|
+
</span>
|
13
|
+
</th>
|
14
|
+
</tr>
|
15
|
+
<% end %>
|
16
|
+
<tr>
|
17
|
+
<th>Name</th>
|
18
|
+
<th>Value</th>
|
19
|
+
<th>Type</th>
|
20
|
+
<th>Notes</th>
|
21
|
+
</tr>
|
22
|
+
</thead>
|
23
|
+
<tbody>
|
24
|
+
<% configuration.class.fields.each do |field| %>
|
25
|
+
<% source = configuration.__source__(field.name) %>
|
26
|
+
<tr>
|
27
|
+
<td>
|
28
|
+
<code><%= html_escape(field.name) %></code>
|
29
|
+
</td>
|
30
|
+
|
31
|
+
<td style="word-wrap: break-word; max-width:30em;">
|
32
|
+
<% if configuration[field.name].nil? %>
|
33
|
+
<em>nil</em>
|
34
|
+
<% elsif field.secret? %>
|
35
|
+
<%= html_escape(secret_value(configuration[field.name])) %>
|
36
|
+
<% else %>
|
37
|
+
<%= html_escape(display_value(configuration[field.name])) %>
|
38
|
+
<% end %>
|
39
|
+
</td>
|
40
|
+
|
41
|
+
<td>
|
42
|
+
<%= html_escape(field.type) %>
|
43
|
+
<%
|
44
|
+
options = []
|
45
|
+
options << 'static' if field.static?
|
46
|
+
options << 'secret' if field.secret?
|
47
|
+
%>
|
48
|
+
<% unless options.empty? %>
|
49
|
+
<div>
|
50
|
+
<em><%= html_escape(options.join(', ')) %></em>
|
51
|
+
</div>
|
52
|
+
<% end %>
|
53
|
+
</td>
|
54
|
+
|
55
|
+
<td>
|
56
|
+
<% unless field.description.to_s.empty? %>
|
57
|
+
<div>
|
58
|
+
<%= html_escape(field.description) %>
|
59
|
+
</div>
|
60
|
+
<% end %>
|
61
|
+
|
62
|
+
<ul style="margin: 0; padding: 0;list-style-type: disc; list-style-position: inside;">
|
63
|
+
<% if field.env_var && !configuration.class.environment_variables_disabled? %>
|
64
|
+
<li>
|
65
|
+
<% if source == :env %>
|
66
|
+
<strong>
|
67
|
+
Currently
|
68
|
+
<% else %>
|
69
|
+
Can be
|
70
|
+
<% end %>
|
71
|
+
set with the
|
72
|
+
<code><%= show_defined_value(field.env_var, configuration.__value_from_source__(field.name, :env), field.secret?) %></code>
|
73
|
+
environment variable.
|
74
|
+
<% if source == :env %>
|
75
|
+
</strong>
|
76
|
+
<% end %>
|
77
|
+
</li>
|
78
|
+
<% end %>
|
79
|
+
<% if field.runtime_setting && !configuration.class.runtime_settings_disabled? %>
|
80
|
+
<li>
|
81
|
+
<% if source == :settings %>
|
82
|
+
<strong>
|
83
|
+
Currently
|
84
|
+
<% else %>
|
85
|
+
Can be
|
86
|
+
<% end %>
|
87
|
+
set with the
|
88
|
+
<code><%= show_defined_value(field.runtime_setting, configuration.__value_from_source__(field.name, :settings), field.secret?) %></code>
|
89
|
+
runtime setting.
|
90
|
+
<% if source == :settings %>
|
91
|
+
</strong>
|
92
|
+
<% end %>
|
93
|
+
</li>
|
94
|
+
<% end %>
|
95
|
+
<% if field.yaml_key && !configuration.class.yaml_config_disabled? %>
|
96
|
+
<li>
|
97
|
+
<% if source == :yaml %>
|
98
|
+
<strong>
|
99
|
+
Currently
|
100
|
+
<% else %>
|
101
|
+
Can be
|
102
|
+
<% end %>
|
103
|
+
set with the
|
104
|
+
<code><%= show_defined_value(field.yaml_key, configuration.__value_from_source__(field.name, :yaml), field.secret?) %></code>
|
105
|
+
key in the configuration file.
|
106
|
+
<% if source == :yaml %>
|
107
|
+
</strong>
|
108
|
+
<% end %>
|
109
|
+
</li>
|
110
|
+
<% end %>
|
111
|
+
<% if field.default.nil? %>
|
112
|
+
<% if source == :default %>
|
113
|
+
<li>
|
114
|
+
<strong>Not set</strong>
|
115
|
+
</li>
|
116
|
+
<% end %>
|
117
|
+
<% else %>
|
118
|
+
<li>
|
119
|
+
<% if source == :default %>
|
120
|
+
<strong>
|
121
|
+
Currently set with the
|
122
|
+
<%= show_defined_value("default value", field.default, field.secret?) %>.
|
123
|
+
</strong>
|
124
|
+
<% else %>
|
125
|
+
This field has a <%= show_defined_value("default value", field.default, field.secret?) %>.
|
126
|
+
<% end %>
|
127
|
+
</li>
|
128
|
+
<% end %>
|
129
|
+
</ul>
|
130
|
+
</td>
|
131
|
+
</tr>
|
132
|
+
<% end %>
|
133
|
+
</tbody>
|
134
|
+
</table>
|
data/app/index.html.erb
CHANGED
@@ -12,79 +12,7 @@
|
|
12
12
|
<% configuration = UltraSettings.send(name) %>
|
13
13
|
|
14
14
|
<div class="ultra-settings-configuration" id="config-<%= name %>" style="display:none;">
|
15
|
-
|
16
|
-
<div class="ultra-settings-info">
|
17
|
-
YAML File:
|
18
|
-
<span class="ultra-settings-code <%= 'ultra-settings-error' unless configuration.class.configuration_file %>">
|
19
|
-
<%= configuration.class.configuration_file.to_s.sub(/\A#{Regexp.escape(UltraSettings::Configuration.yaml_config_path.to_s)}\//, "") %>
|
20
|
-
</span>
|
21
|
-
</div>
|
22
|
-
<% end %>
|
23
|
-
|
24
|
-
<table class="ultra-settings-table">
|
25
|
-
<thead>
|
26
|
-
<tr>
|
27
|
-
<th>Name</th>
|
28
|
-
<th>Type</th>
|
29
|
-
<th>Environment Variable</th>
|
30
|
-
<th>Runtime Setting</th>
|
31
|
-
<th>YAML Key</th>
|
32
|
-
<th>Default</th>
|
33
|
-
</tr>
|
34
|
-
</thead>
|
35
|
-
<tbody>
|
36
|
-
<% configuration.class.fields.sort_by(&:name).each do |field| %>
|
37
|
-
<tr>
|
38
|
-
<td>
|
39
|
-
<%= field.name %>
|
40
|
-
<% unless field.description.to_s.empty? %>
|
41
|
-
<div class="ultra-settings-description">
|
42
|
-
<%= field.description %>
|
43
|
-
</div>
|
44
|
-
<% end %>
|
45
|
-
</td>
|
46
|
-
<td>
|
47
|
-
<%= field.type %>
|
48
|
-
<% if field.static? %>
|
49
|
-
<div class="ultra-settings-static">
|
50
|
-
static
|
51
|
-
</div>
|
52
|
-
<% end %>
|
53
|
-
</td>
|
54
|
-
<td>
|
55
|
-
<% if field.env_var && !configuration.class.environment_variables_disabled? %>
|
56
|
-
<pre class="ultra-settings-code <%= 'ultra-settings-current-source' if configuration.__source__(field.name) == :env %>"><%= field.env_var %></pre>
|
57
|
-
<% else %>
|
58
|
-
<span class="ultra-settings-not-applicable">n/a</span>
|
59
|
-
<% end %>
|
60
|
-
</td>
|
61
|
-
<td>
|
62
|
-
<% if field.runtime_setting && !configuration.class.runtime_settings_disabled? %>
|
63
|
-
<pre class="ultra-settings-code <%= 'ultra-settings-current-source' if configuration.__source__(field.name) == :settings %>"><%= field.runtime_setting %></pre>
|
64
|
-
<% else %>
|
65
|
-
<span class="ultra-settings-not-applicable">n/a</span>
|
66
|
-
<% end %>
|
67
|
-
</td>
|
68
|
-
<td>
|
69
|
-
<% if field.yaml_key && !configuration.class.yaml_config_disabled? %>
|
70
|
-
<pre class="ultra-settings-code <%= 'ultra-settings-current-source' if configuration.__source__(field.name) == :yaml %>"><%= field.yaml_key %></pre>
|
71
|
-
<% else %>
|
72
|
-
<span class="ultra-settings-not-applicable">n/a</span>
|
73
|
-
<% end %>
|
74
|
-
</td>
|
75
|
-
<td>
|
76
|
-
<span class="<%= 'ultra-settings-current-source' if configuration.__source__(field.name) == :default %>">
|
77
|
-
<% if field.default.nil? %>
|
78
|
-
<em>nil</em>
|
79
|
-
<% else %>
|
80
|
-
✔
|
81
|
-
<% end %>
|
82
|
-
</span>
|
83
|
-
</td>
|
84
|
-
</tr>
|
85
|
-
<% end %>
|
86
|
-
</tbody>
|
87
|
-
</table>
|
15
|
+
<%= UltraSettings::ConfigurationView.new(configuration) %>
|
88
16
|
</div>
|
89
17
|
<% end %>
|
90
18
|
|
@@ -33,10 +33,11 @@ module UltraSettings
|
|
33
33
|
# @param yaml_key [String, Symbol] The name of the YAML key to use for the field. By default
|
34
34
|
# this is the name of the field.
|
35
35
|
# @return [void]
|
36
|
-
def field(name, type: :string, description: nil, default: nil, default_if: nil, static: nil, runtime_setting: nil, env_var: nil, yaml_key: nil)
|
36
|
+
def field(name, type: :string, description: nil, default: nil, default_if: nil, static: nil, secret: nil, runtime_setting: nil, env_var: nil, yaml_key: nil)
|
37
37
|
name = name.to_s
|
38
38
|
type = type.to_sym
|
39
39
|
static = !!static
|
40
|
+
secret = lambda { fields_secret_by_default? } if secret.nil?
|
40
41
|
|
41
42
|
unless name.match?(ALLOWED_NAME_PATTERN)
|
42
43
|
raise ArgumentError.new("Invalid name: #{name.inspect}")
|
@@ -59,7 +60,8 @@ module UltraSettings
|
|
59
60
|
env_var: construct_env_var(name, env_var),
|
60
61
|
runtime_setting: (static ? nil : construct_runtime_setting(name, runtime_setting)),
|
61
62
|
yaml_key: construct_yaml_key(name, yaml_key),
|
62
|
-
static: static
|
63
|
+
static: static,
|
64
|
+
secret: secret
|
63
65
|
)
|
64
66
|
|
65
67
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Security/Eval
|
@@ -69,7 +71,7 @@ module UltraSettings
|
|
69
71
|
RUBY
|
70
72
|
|
71
73
|
if type == :boolean
|
72
|
-
alias_method "#{name}?", name
|
74
|
+
alias_method :"#{name}?", name
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
@@ -306,6 +308,23 @@ module UltraSettings
|
|
306
308
|
get_inheritable_class_attribute(:@yaml_config_env, "development")
|
307
309
|
end
|
308
310
|
|
311
|
+
# Sets the default value for the secret property of fields. Individual fields can still
|
312
|
+
# override this value by explicitly setting the secret property. By default, fields are
|
313
|
+
# considered secret.
|
314
|
+
#
|
315
|
+
# @param value [Boolean]
|
316
|
+
# @return [void]
|
317
|
+
def fields_secret_by_default=(value)
|
318
|
+
set_inheritable_class_attribute(:@fields_secret_by_default, !!value)
|
319
|
+
end
|
320
|
+
|
321
|
+
# Check if fields are considered secret by default.
|
322
|
+
#
|
323
|
+
# @return [Boolean]
|
324
|
+
def fields_secret_by_default?
|
325
|
+
get_inheritable_class_attribute(:@fields_secret_by_default, true)
|
326
|
+
end
|
327
|
+
|
309
328
|
# Override field values within a block.
|
310
329
|
#
|
311
330
|
# @param values [Hash<Symbol, Object>]] List of fields with the values they
|
@@ -450,12 +469,61 @@ module UltraSettings
|
|
450
469
|
end
|
451
470
|
end
|
452
471
|
|
472
|
+
# Get the current source for the field.
|
473
|
+
#
|
474
|
+
# @param name [String, Symbol] the name of the field.
|
475
|
+
# @return [Symbol, nil] The source of the value (:env, :settings, :yaml, or :default).
|
453
476
|
def __source__(name)
|
454
|
-
field = self.class.send(:defined_fields)[name]
|
477
|
+
field = self.class.send(:defined_fields)[name.to_s]
|
478
|
+
raise ArgumentError.new("Unknown field: #{name.inspect}") unless field
|
479
|
+
|
455
480
|
source = field.source(env: ENV, settings: UltraSettings.__runtime_settings__, yaml_config: __yaml_config__)
|
456
481
|
source || :default
|
457
482
|
end
|
458
483
|
|
484
|
+
# Get the value of the field from the specified source.
|
485
|
+
#
|
486
|
+
# @param name [String, Symbol] the name of the field.
|
487
|
+
# @param source [Symbol] the source of the value (:env, :settings, :yaml, or :default).
|
488
|
+
# @return [Object] The value of the field.
|
489
|
+
def __value_from_source__(name, source)
|
490
|
+
field = self.class.send(:defined_fields)[name.to_s]
|
491
|
+
raise ArgumentError.new("Unknown field: #{name.inspect}") unless field
|
492
|
+
|
493
|
+
case source
|
494
|
+
when :env
|
495
|
+
field.value(env: ENV)
|
496
|
+
when :settings
|
497
|
+
field.value(settings: UltraSettings.__runtime_settings__)
|
498
|
+
when :yaml
|
499
|
+
field.value(yaml_config: __yaml_config__)
|
500
|
+
when :default
|
501
|
+
field.default
|
502
|
+
else
|
503
|
+
raise ArgumentError.new("Unknown source: #{source.inspect}")
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
# Output the current state of the configuration as a hash. If the field is marked as a secret,
|
508
|
+
# then the value will be a secure hash of the value instead of the value itself.
|
509
|
+
#
|
510
|
+
# The intent of this method is to provide a serializable value that captures the current state
|
511
|
+
# of the configuration without exposing any secrets. You could, for instance, use the output
|
512
|
+
# to compare the configuration of you application between two different environments.
|
513
|
+
#
|
514
|
+
# @return [Hash]
|
515
|
+
def __to_hash__
|
516
|
+
payload = {}
|
517
|
+
self.class.fields.each do |field|
|
518
|
+
value = self[field.name]
|
519
|
+
if field.secret? && !value.nil?
|
520
|
+
value = "securehash:#{Digest::MD5.hexdigest(Digest::SHA256.hexdigest(value.to_s))}"
|
521
|
+
end
|
522
|
+
payload[field.name] = value
|
523
|
+
end
|
524
|
+
payload
|
525
|
+
end
|
526
|
+
|
459
527
|
private
|
460
528
|
|
461
529
|
def __get_value__(name)
|
@@ -510,7 +578,7 @@ module UltraSettings
|
|
510
578
|
end
|
511
579
|
|
512
580
|
def __yaml_config__
|
513
|
-
@yaml_config ||=
|
581
|
+
@yaml_config ||= self.class.load_yaml_config || {}
|
514
582
|
end
|
515
583
|
end
|
516
584
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UltraSettings
|
4
|
+
# This class can render information about a configuration in an HTML table. It is used by the
|
5
|
+
# bundled web UI, but you can use it to embed the configuration information in your own web pages.
|
6
|
+
#
|
7
|
+
# The output will be an HTML table. You can specify the CSS class for the table by passing the
|
8
|
+
# `table_class` option to the `render` method. By default the table will have the class
|
9
|
+
# `ultra-settings-table`.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# <h1>Service Configuration</h1>
|
13
|
+
# <%= UltraSettings::ConfigurationView.new(ServiceConfiguration.instance).render(table_class: "table table-striped") %>
|
14
|
+
class ConfigurationView
|
15
|
+
@template = nil
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def template
|
19
|
+
@template ||= ERB.new(read_app_file("configuration.html.erb"))
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def read_app_file(path)
|
25
|
+
File.read(File.join(app_dir, path))
|
26
|
+
end
|
27
|
+
|
28
|
+
def app_dir
|
29
|
+
File.expand_path(File.join("..", "..", "app"), __dir__)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(configuration)
|
34
|
+
@configuration = configuration
|
35
|
+
end
|
36
|
+
|
37
|
+
def render(table_class: "ultra-settings-table")
|
38
|
+
configuration = @configuration
|
39
|
+
html = self.class.template.result(binding)
|
40
|
+
html = html.html_safe if html.respond_to?(:html_safe)
|
41
|
+
html
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
render
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def html_escape(value)
|
51
|
+
ERB::Util.html_escape(value)
|
52
|
+
end
|
53
|
+
|
54
|
+
def display_value(value)
|
55
|
+
case value
|
56
|
+
when Time
|
57
|
+
value.iso8601
|
58
|
+
else
|
59
|
+
value.inspect
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def show_defined_value(label, value, secret)
|
64
|
+
title = if value.nil?
|
65
|
+
"Not set"
|
66
|
+
elsif secret
|
67
|
+
"Secret value"
|
68
|
+
else
|
69
|
+
"Value: #{display_value(value)}"
|
70
|
+
end
|
71
|
+
"<dfn title=\"#{html_escape(title)}\">#{html_escape(label)}</dfn>"
|
72
|
+
end
|
73
|
+
|
74
|
+
def secret_value(value)
|
75
|
+
if value.nil?
|
76
|
+
"nil"
|
77
|
+
else
|
78
|
+
"••••••••••••••••"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def relative_path(path)
|
83
|
+
root_path = Pathname.new(Dir.pwd)
|
84
|
+
config_path = UltraSettings::Configuration.yaml_config_path
|
85
|
+
unless config_path.realpath.to_s.start_with?("#{root_path.realpath}#{File::SEPARATOR}")
|
86
|
+
root_path = config_path
|
87
|
+
end
|
88
|
+
path.relative_path_from(root_path)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/ultra_settings/field.rb
CHANGED
@@ -20,6 +20,8 @@ module UltraSettings
|
|
20
20
|
# @param env_var [String, Symbol] The name of the environment variable to use for the field.
|
21
21
|
# @param runtime_setting [String, Symbol] The name of the setting to use for the field.
|
22
22
|
# @param yaml_key [String, Symbol] The name of the YAML key to use for the field.
|
23
|
+
# @param static [Boolean] Whether or not the field is static and cannot be changed at runtime.
|
24
|
+
# @param secret [Boolean] Whether or not the field contains a value that should be kept secret.
|
23
25
|
def initialize(
|
24
26
|
name:,
|
25
27
|
type: :string,
|
@@ -29,7 +31,8 @@ module UltraSettings
|
|
29
31
|
env_var: nil,
|
30
32
|
runtime_setting: nil,
|
31
33
|
yaml_key: nil,
|
32
|
-
static: false
|
34
|
+
static: false,
|
35
|
+
secret: false
|
33
36
|
)
|
34
37
|
@name = name.to_s.freeze
|
35
38
|
@type = type.to_sym
|
@@ -40,13 +43,14 @@ module UltraSettings
|
|
40
43
|
@runtime_setting = runtime_setting&.to_s&.freeze
|
41
44
|
@yaml_key = yaml_key&.to_s&.freeze
|
42
45
|
@static = !!static
|
46
|
+
@secret = (secret.respond_to?(:call) ? secret : !!secret)
|
43
47
|
end
|
44
48
|
|
45
49
|
# Get the value for the field from the passed in state.
|
46
50
|
#
|
47
|
-
# @param env [
|
48
|
-
# @param settings [
|
49
|
-
# @param yaml_config [
|
51
|
+
# @param env [Hash, nil] The environment variables.
|
52
|
+
# @param settings [Hash, nil] The runtime settings.
|
53
|
+
# @param yaml_config [Hash, nil] The YAML configuration.
|
50
54
|
def value(env: nil, settings: nil, yaml_config: nil)
|
51
55
|
fetch_value_and_source(env: env, settings: settings, yaml_config: yaml_config).first
|
52
56
|
end
|
@@ -76,6 +80,17 @@ module UltraSettings
|
|
76
80
|
@static
|
77
81
|
end
|
78
82
|
|
83
|
+
# Returns true if the field is marked as having a secret value.
|
84
|
+
#
|
85
|
+
# @return [Boolean]
|
86
|
+
def secret?
|
87
|
+
if @secret.respond_to?(:call)
|
88
|
+
!!@secret.call
|
89
|
+
else
|
90
|
+
@secret
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
79
94
|
private
|
80
95
|
|
81
96
|
def fetch_value_and_source(env:, settings:, yaml_config:)
|
data/lib/ultra_settings.rb
CHANGED
@@ -5,12 +5,14 @@ require "yaml"
|
|
5
5
|
require "time"
|
6
6
|
require "pathname"
|
7
7
|
require "singleton"
|
8
|
+
require "digest"
|
8
9
|
|
9
10
|
require_relative "ultra_settings/configuration"
|
10
11
|
require_relative "ultra_settings/coerce"
|
11
12
|
require_relative "ultra_settings/field"
|
12
13
|
require_relative "ultra_settings/rack_app"
|
13
14
|
require_relative "ultra_settings/web_view"
|
15
|
+
require_relative "ultra_settings/configuration_view"
|
14
16
|
require_relative "ultra_settings/yaml_config"
|
15
17
|
require_relative "ultra_settings/version"
|
16
18
|
|
@@ -164,7 +166,11 @@ module UltraSettings
|
|
164
166
|
@runtime_settings
|
165
167
|
end
|
166
168
|
|
167
|
-
|
169
|
+
def fields_secret_by_default=(value)
|
170
|
+
Configuration.fields_secret_by_default = value
|
171
|
+
end
|
172
|
+
|
173
|
+
# Explicitly set values for setting within a block. This is useful for testing
|
168
174
|
# or other situations where you want hard code a specific set of values.
|
169
175
|
#
|
170
176
|
# @param settings [Hash] The settings to set.
|
data/ultra_settings.gemspec
CHANGED
@@ -4,11 +4,17 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.authors = ["Brian Durand"]
|
5
5
|
spec.email = ["bbdurand@gmail.com"]
|
6
6
|
|
7
|
-
spec.summary = "
|
7
|
+
spec.summary = "UltraSettings is a Ruby gem that provides a flexible and documented approach to managing application configurations from multiple sources, including environment variables, runtime settings, and YAML files, with an optional web UI for easy documentation."
|
8
8
|
|
9
9
|
spec.homepage = "https://github.com/bdurand/ultra_settings"
|
10
10
|
spec.license = "MIT"
|
11
11
|
|
12
|
+
spec.metadata = {
|
13
|
+
"homepage_uri" => spec.homepage,
|
14
|
+
"source_code_uri" => spec.homepage,
|
15
|
+
"changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md"
|
16
|
+
}
|
17
|
+
|
12
18
|
# Specify which files should be added to the gem when it is released.
|
13
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
14
20
|
ignore_files = %w[
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ultra_settings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -32,17 +32,19 @@ extensions: []
|
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
34
|
- CHANGELOG.md
|
35
|
-
- MIT-LICENSE
|
35
|
+
- MIT-LICENSE.txt
|
36
36
|
- README.md
|
37
37
|
- VERSION
|
38
38
|
- app/application.css
|
39
39
|
- app/application.js
|
40
|
+
- app/configuration.html.erb
|
40
41
|
- app/index.html.erb
|
41
42
|
- app/layout.css
|
42
43
|
- app/layout.html.erb
|
43
44
|
- lib/ultra_settings.rb
|
44
45
|
- lib/ultra_settings/coerce.rb
|
45
46
|
- lib/ultra_settings/configuration.rb
|
47
|
+
- lib/ultra_settings/configuration_view.rb
|
46
48
|
- lib/ultra_settings/field.rb
|
47
49
|
- lib/ultra_settings/rack_app.rb
|
48
50
|
- lib/ultra_settings/railtie.rb
|
@@ -53,7 +55,10 @@ files:
|
|
53
55
|
homepage: https://github.com/bdurand/ultra_settings
|
54
56
|
licenses:
|
55
57
|
- MIT
|
56
|
-
metadata:
|
58
|
+
metadata:
|
59
|
+
homepage_uri: https://github.com/bdurand/ultra_settings
|
60
|
+
source_code_uri: https://github.com/bdurand/ultra_settings
|
61
|
+
changelog_uri: https://github.com/bdurand/ultra_settings/blob/main/CHANGELOG.md
|
57
62
|
post_install_message:
|
58
63
|
rdoc_options: []
|
59
64
|
require_paths:
|
@@ -69,9 +74,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
74
|
- !ruby/object:Gem::Version
|
70
75
|
version: '0'
|
71
76
|
requirements: []
|
72
|
-
rubygems_version: 3.4.
|
77
|
+
rubygems_version: 3.4.10
|
73
78
|
signing_key:
|
74
79
|
specification_version: 4
|
75
|
-
summary:
|
76
|
-
|
80
|
+
summary: UltraSettings is a Ruby gem that provides a flexible and documented approach
|
81
|
+
to managing application configurations from multiple sources, including environment
|
82
|
+
variables, runtime settings, and YAML files, with an optional web UI for easy documentation.
|
77
83
|
test_files: []
|
File without changes
|