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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca29611f95d52ce78e465c06876bfedfef76fa166b0f2d5d6279e08cfada0397
4
- data.tar.gz: cee494a62d579c2518ae1ca5db8b2483ab5906a3323a1c01e86dd45430fb495d
3
+ metadata.gz: 6740e40d7198c0cb0573b24f5e61c0f679e8fb62b0c18bee3ee79a29748bc908
4
+ data.tar.gz: d35bb1603d4acfedcf32c8cc7c6063e0deeabb47e825d646ff104568a30de898
5
5
  SHA512:
6
- metadata.gz: 99dedad75b7b425ea2b44a1b3002a5b53b54edd999e69f49cfed3ff331fab9ec907fbfb43465c30be0cb23559288c5904201764b95cfcb3b38833aa402a1c007
7
- data.tar.gz: 010f49d61c14a24b46e4fb42ceb70ee6d714b83c8d9d9d653463b5933ad20d7f3ff7adaad53707fe53fc32d3c03af39430fc478040d39fbb481ac2e6f2863e9f
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
- This gem provides a method for managing application settings and loading their values from a variety of sources. It can help you get a handle on you application's configuration by providing a consistent method for accessing settings. It also provides a method for documenting your application's settings.
7
+ ## Introduction
8
8
 
9
- It allows you to define a hierarchy with three layers of sources for your configuration values:
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
- 1. Environment variables
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
- Settings at a higher level will override those set at a lower level. So, for instance, you can override values set in a YAML file with either environment variables or runtime settings. The hierarchy is an optional feature and can be disabled in favor of explicitly defined data sources if you want.
13
+ ## Key Features
16
14
 
17
- Your application code does not need to concern itself with how a setting value is being loaded or from what source. It can just reference configuration settings using plain old Ruby objects and methods.
15
+ This gem supports a three-layer hierarchy for defining configuration sources:
18
16
 
19
- Settings are also type cast so you can always be assured that values are returned as a predetermined class and your application does not need to worry about type coercion. The supported types are:
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
- You can also define default values to be returned in case the configured value is missing or it fails to match a constraint.
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. Configuration classes are [singleton classes](https://ruby-doc.org/3.2.2/stdlibs/singleton/Singleton.html).
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
- field :host, type: :string
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, type: :float, default: 1.0, default_if: ->(val) { val <= 0 }
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
- - You can specify a return type with the `:type` option. The value of the setting will be cast to this type. Valid types are:
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
- - You can specify a default value with the `:default` option. Note that this value will still be cast to the defined type.
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
- - You can specify a trigger of when the default should be used with the `:default_if` option. If this option is provided, then it should be either a `Proc` or the name of a method in the class to call with the value from the settings. You can use this feature, for example, to always ensure that a value meets certain constraints.
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
- - You can describe what your setting does with the `:description` option. This value is only for documentation purposes.
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
- - You can override the environment variable used to populate the setting with the `:env_var` option. You can use this to point to an environment variable name that does not match the conventional pattern. You can also set this to `false` to disable loading the field from an environment variable.
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
- - You can override the key in the YAML file with the `:yaml_key` option. You can use this to map a setting to a key in the YAML hash if the key doesn't match the field name. You can also set this to `false` to disable loading the field from a YAML file.
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
- - You can override the name of the runtime setting used to populate the setting with the `:runtime_setting` option. You can use this to point to a setting whose name does not match the conventional pattern. You can also set this to `false` to disable loading the field from runtime settings.
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
- - You can define a value as a static value by setting the `:static` option to true. Static values will not be changed once they are set. Static values also cannot be set from runtime settings. If you are referencing a setting during your application's initialization, then you should declare it as a static field.
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
- By default settings will be loaded from environment variables 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. By default environment variables will be in all uppercase letters.
117
+ #### Customizing Environment Variables
95
118
 
96
- You can use lowercase environment variable names by setting `env_var_upcase` to `false` on your configuration class.
119
+ You can customize the behavior of environment variable naming in several ways:
97
120
 
98
- You can use a different delimiter by setting `env_var_delimiter` on your configuration class. The delimiter is used between modules and before the setting name so a delimiter of "." on `Configs::MySettingsConfiguration#setting` would produce "CONFIGS.MY_SETTINGS.SETTING".
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
- You can set an explicit prefix by setting `env_var_prefix` on your configuration class.
123
+ - **Lowercase Environment Variables:** Set `env_var_upcase` to false in your configuration class to use lowercase environment variable names.
101
124
 
102
- You can disable environment variables as a default source on your fields by setting `environment_variables_disabled` to `true` on your configuration class.
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 settings that are loaded at runtime while your application is running. The advantage to this kind of setting is that your application does not need to restart in order to get an updated value.
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 use runtime settings, you need to set the `UltraSettings.runtime_settings` attribute to an object that defines the `[]` method and takes a string as the argument. For instance, if you wanted to load runtime settings from a Redis database, you could implement them like this.
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
- 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 itself.
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
- 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. By default runtime settings will be in all lowercase letters.
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 use uppercase runtime setting names by setting `runtime_setting_upcase` to `true` on your configuration class.
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
- You can use a different delimiter by setting `runtime_setting_delimiter` on your configuration class. The delimiter is used between modules and before the setting name so a delimiter of "/" on `Configs::MySettingsConfiguration#setting` would produce "configs/my_settings/setting".
171
+ - **Uppercase Runtime Setting Names:** Set `runtime_setting_upcase` to true in your configuration class to use uppercase runtime setting names.
137
172
 
138
- You can set an explicit prefix by setting `runtime_setting_prefix` on your configuration class.
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
- You can disable runtime settings as a default source on your fields by setting `runtime_settings_disabled` to `true` on your configuration class.
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
- The last place settings will be loaded from are from static YAML files. These can provide a good place to store default values for you application since they can be distributed with your application code.
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
- 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 will be searched for in the path defined by `UltraSettings.yaml_config_path`. If the file does not exist, then settings will not use the YAML source strategy.
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
- You can specify an explicit YAML file to use by setting `configuration_file` on your configuration class to the path to the file.
195
+ #### ERB Support
151
196
 
152
- You can disable YAML files as a default source on your fields by setting `yaml_config_disabled` to `true` on your configuration class.
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
- YAML files will be evaluated for an ERB markup (i.e. `<%= %>`) before the YAML itself is evaluated. You can use this feature to dynamically generate values within the YAML file.
199
+ #### Environment-Specific Configurations
155
200
 
156
- YAML files define environment specific configurations. YAML files must define a hash where the keys are the names of your application environments (i.e. development, test, production, etc.). You define which environment to use with `UltraSettings.yaml_config_env` (the default environment is "development"). There is also a special key `"shared"` which, if defined, will be merged with the environment hash.
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
- So, for this YAML file:
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 "development" environment would be the combination of development and shared:
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 "production", the values would be the combination of production and shared:
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
- Values for the environment will always overwrite values from the shared hash.
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 don't like the default behavior of the hierarchy of environment variables, runtime settings, and YAML files, you can disable it and then explicitly enable only the appropriate data source on each field.
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. Settings are accessed by calling methods.
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
- You can add configurations as methods onto the `UltraSettings` object. By default the configuration class name will be guessed (i.e. "my_service" maps to `MyServiceConfiguration`).
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
- You can also specify the class name to map to a different method name.
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 some syntactic sugar and expose the `UltraSettings` object as a helper method in application.rb.
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
- You can also keep things clean if your configuration is mostly accessed from within another class.
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
- There is a web UI available via a mountable Rack application. The UI will only expose the source of where settings are being loaded from. For security reasons, it will not show any of the setting values. It is still highly advised to put it behind whatever authorization framework you application uses.
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
- Here is a simple example of how to mount in a Rails application behind HTTP Basic authentication with hard coded credentials.
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
- ### Testing
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
- You can use the `UltraSettings.override!` method to force different configuration settings in you automated tests. Here's examples of overriding the `TestConfiguration#foo` value in a test block:
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
- If you are using RSpec, you can set up a global before handler to make it easier to specify settings within your test blocks.
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[:ultra_settings].is_a?(Hash)
320
- UltraSettings.override!(example.metadata[:ultra_settings]) do
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
- # In a test
330
- it 'has the settings I want', ultra_settings: {test: {foo: "bar"}} do
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.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-description {
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
- <% unless configuration.class.yaml_config_disabled? %>
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
- &#x2714;
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 ||= (self.class.load_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
@@ -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 [#[]] The environment variables.
48
- # @param settings [#[]] The runtime settings.
49
- # @param yaml_config [#[]] The YAML configuration.
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:)
@@ -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
- # Explicitly set setting values within a block. This is useful for testing
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.
@@ -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 = "Unified application configuration that allows for configuration via environment variables, YAML files, and dynamic runtime setting."
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.1
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: 2023-11-11 00:00:00.000000000 Z
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.12
77
+ rubygems_version: 3.4.10
73
78
  signing_key:
74
79
  specification_version: 4
75
- summary: Unified application configuration that allows for configuration via environment
76
- variables, YAML files, and dynamic runtime setting.
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