ultra_settings 0.0.1.rc1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +321 -2
- data/VERSION +1 -1
- data/app/application.css +85 -0
- data/app/application.js +19 -0
- data/app/index.html.erb +93 -0
- data/app/layout.css +27 -0
- data/app/layout.html.erb +21 -0
- data/lib/ultra_settings/coerce.rb +98 -0
- data/lib/ultra_settings/configuration.rb +379 -79
- data/lib/ultra_settings/field.rb +57 -88
- data/lib/ultra_settings/rack_app.rb +25 -0
- data/lib/ultra_settings/railtie.rb +33 -0
- data/lib/ultra_settings/version.rb +5 -0
- data/lib/ultra_settings/web_view.rb +38 -0
- data/lib/ultra_settings/yaml_config.rb +78 -0
- data/lib/ultra_settings.rb +168 -74
- data/ultra_settings.gemspec +3 -4
- metadata +18 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca29611f95d52ce78e465c06876bfedfef76fa166b0f2d5d6279e08cfada0397
|
4
|
+
data.tar.gz: cee494a62d579c2518ae1ca5db8b2483ab5906a3323a1c01e86dd45430fb495d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99dedad75b7b425ea2b44a1b3002a5b53b54edd999e69f49cfed3ff331fab9ec907fbfb43465c30be0cb23559288c5904201764b95cfcb3b38833aa402a1c007
|
7
|
+
data.tar.gz: 010f49d61c14a24b46e4fb42ceb70ee6d714b83c8d9d9d653463b5933ad20d7f3ff7adaad53707fe53fc32d3c03af39430fc478040d39fbb481ac2e6f2863e9f
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,11 @@ 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.0.1
|
8
|
+
|
9
|
+
### Added
|
10
|
+
- Optimize object shapes for the Ruby interpreter by declaring instance variables in constructors.
|
11
|
+
|
7
12
|
## 1.0.0
|
8
13
|
|
9
14
|
### Added
|
data/README.md
CHANGED
@@ -1,18 +1,337 @@
|
|
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)
|
4
5
|
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
|
5
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.
|
8
|
+
|
9
|
+
It allows you to define a hierarchy with three layers of sources for your configuration values:
|
10
|
+
|
11
|
+
1. Environment variables
|
12
|
+
2. Runtime settings (i.e. settings updatable from within the running application)
|
13
|
+
3. YAML configuration files
|
14
|
+
|
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.
|
16
|
+
|
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.
|
18
|
+
|
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:
|
20
|
+
|
21
|
+
- `String`
|
22
|
+
- `Integer`
|
23
|
+
- `Float`
|
24
|
+
- `Boolean`
|
25
|
+
- `Time`
|
26
|
+
- `Symbol`
|
27
|
+
- `Array<String>`
|
28
|
+
|
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.
|
7
32
|
|
8
33
|
## Usage
|
9
34
|
|
35
|
+
### Defining Configurations
|
36
|
+
|
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).
|
38
|
+
|
39
|
+
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
|
+
|
41
|
+
```ruby
|
42
|
+
class MyServiceConfiguration < UltraSettings::Configuration
|
43
|
+
field :host, type: :string
|
44
|
+
|
45
|
+
field :port, type: :integer, default: 80
|
46
|
+
|
47
|
+
field :protocol, type: :string, default: "https"
|
48
|
+
|
49
|
+
field :timeout, type: :float, default: 1.0, default_if: ->(val) { val <= 0 }
|
50
|
+
|
51
|
+
field :auth_token,
|
52
|
+
type: :string,
|
53
|
+
env_var: "MY_SERVICE_TOKEN",
|
54
|
+
runtime_setting: false,
|
55
|
+
yaml_key: false,
|
56
|
+
description: "Bearer token for accessing the service"
|
57
|
+
|
58
|
+
# You aren't limited to just defining fields, you can define other
|
59
|
+
# helper methods to make using the configuration easier.
|
60
|
+
def uri
|
61
|
+
URI("#{protocol}://#{host}:#{port}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
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:
|
67
|
+
|
68
|
+
- `:string` (the default)
|
69
|
+
- `:integer`
|
70
|
+
- `:float`
|
71
|
+
- `:boolean`
|
72
|
+
- `:datetime`
|
73
|
+
- `:symbol`
|
74
|
+
- `:array` (of strings)
|
75
|
+
|
76
|
+
- You can specify a default value with the `:default` option. Note that this value will still be cast to the defined type.
|
77
|
+
|
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.
|
79
|
+
|
80
|
+
- You can describe what your setting does with the `:description` option. This value is only for documentation purposes.
|
81
|
+
|
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.
|
83
|
+
|
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.
|
85
|
+
|
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.
|
87
|
+
|
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.
|
89
|
+
|
90
|
+
### Environment Variables
|
91
|
+
|
92
|
+
Settings will first try to load values from environment variables. Environment variables are a good place to define environment specific values.
|
93
|
+
|
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.
|
95
|
+
|
96
|
+
You can use lowercase environment variable names by setting `env_var_upcase` to `false` on your configuration class.
|
97
|
+
|
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".
|
99
|
+
|
100
|
+
You can set an explicit prefix by setting `env_var_prefix` on your configuration class.
|
101
|
+
|
102
|
+
You can disable environment variables as a default source on your fields by setting `environment_variables_disabled` to `true` on your configuration class.
|
103
|
+
|
104
|
+
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
|
+
|
106
|
+
### Runtime Settings
|
107
|
+
|
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.
|
109
|
+
|
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.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
class RedisRuntimeSettings
|
114
|
+
def initialize
|
115
|
+
@redis = Redis.new
|
116
|
+
end
|
117
|
+
|
118
|
+
def [](name)
|
119
|
+
@redis.get(name)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
UltraSettings.runtime_settings = RedisRuntimeSettings.new
|
124
|
+
```
|
125
|
+
|
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.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
UltraSettings.runtime_settings = SuperSettings
|
130
|
+
```
|
131
|
+
|
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.
|
133
|
+
|
134
|
+
You can use uppercase runtime setting names by setting `runtime_setting_upcase` to `true` on your configuration class.
|
135
|
+
|
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".
|
137
|
+
|
138
|
+
You can set an explicit prefix by setting `runtime_setting_prefix` on your configuration class.
|
139
|
+
|
140
|
+
You can disable runtime settings as a default source on your fields by setting `runtime_settings_disabled` to `true` on your configuration class.
|
141
|
+
|
142
|
+
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
|
+
|
144
|
+
### YAML Files
|
145
|
+
|
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.
|
147
|
+
|
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.
|
149
|
+
|
150
|
+
You can specify an explicit YAML file to use by setting `configuration_file` on your configuration class to the path to the file.
|
151
|
+
|
152
|
+
You can disable YAML files as a default source on your fields by setting `yaml_config_disabled` to `true` on your configuration class.
|
153
|
+
|
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.
|
155
|
+
|
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.
|
157
|
+
|
158
|
+
So, for this YAML file:
|
159
|
+
|
160
|
+
```yaml
|
161
|
+
shared:
|
162
|
+
timeout: 5
|
163
|
+
port: 8000
|
164
|
+
|
165
|
+
development:
|
166
|
+
timeout: 10
|
167
|
+
host: localhost
|
168
|
+
|
169
|
+
production:
|
170
|
+
host: prod.example.com
|
171
|
+
```
|
172
|
+
|
173
|
+
The values for the "development" environment would be the combination of development and shared:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
{
|
177
|
+
timeout: 10,
|
178
|
+
port: 8000,
|
179
|
+
host: "localhost"
|
180
|
+
}
|
181
|
+
```
|
182
|
+
|
183
|
+
While for "production", the values would be the combination of production and shared:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
{
|
187
|
+
timeout: 5,
|
188
|
+
port: 8000,
|
189
|
+
host: "prod.example.com"
|
190
|
+
}
|
191
|
+
```
|
192
|
+
|
193
|
+
Values for the environment will always overwrite values from the shared hash.
|
194
|
+
|
195
|
+
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
|
+
|
197
|
+
### Removing The Hierarchy
|
198
|
+
|
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.
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
class MyServiceConfiguration < UtraSettings::Configuration
|
203
|
+
self.environment_variables_disabled = false
|
204
|
+
self.runtime_settings_disabled = false
|
205
|
+
self.yaml_config_disabled = false
|
206
|
+
|
207
|
+
field :host, yaml_key: "host"
|
208
|
+
field :token, env_var: "MY_SERVICE_TOKEN"
|
209
|
+
field :timeout, runtime_setting: "my_service.timeout", default: 5
|
210
|
+
end
|
211
|
+
```
|
212
|
+
|
213
|
+
If you don't want the hierarchy in any configuration, then you can disable it globally.
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
UltraSettings.environment_variables_disabled = true
|
217
|
+
UltraSettings.runtime_settings_disabled = true
|
218
|
+
UltraSettings.yaml_config_disabled = true
|
219
|
+
```
|
220
|
+
|
221
|
+
### Accessing settings
|
222
|
+
|
223
|
+
Configurations are singleton objects. Settings are accessed by calling methods.
|
224
|
+
|
10
225
|
```ruby
|
226
|
+
MyServiceConfiguration.instance.host
|
227
|
+
```
|
228
|
+
|
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`).
|
230
|
+
```ruby
|
231
|
+
UltraSettings.add(:my_service)
|
11
232
|
UltraSettings.my_service.host
|
233
|
+
```
|
234
|
+
|
235
|
+
You can also specify the class name to map to a different method name.
|
236
|
+
```ruby
|
237
|
+
UltraSettings.add(:my, "MyServiceConfiguration")
|
238
|
+
UltraSettings.my.host
|
239
|
+
```
|
240
|
+
|
241
|
+
In a Rails application, you could add some syntactic sugar and expose the `UltraSettings` object as a helper method in application.rb.
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
module MyApp
|
245
|
+
class Application < Rails::Application
|
246
|
+
def settings
|
247
|
+
UltraSettings
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
12
251
|
|
13
252
|
Rails.application.settings.my_service.host
|
14
253
|
```
|
15
254
|
|
255
|
+
You can also keep things clean if your configuration is mostly accessed from within another class.
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
class MyService
|
259
|
+
|
260
|
+
# Reference the value as `settings.host`
|
261
|
+
|
262
|
+
private
|
263
|
+
|
264
|
+
def settings
|
265
|
+
MyServiceConfiguration.instance
|
266
|
+
end
|
267
|
+
end
|
268
|
+
```
|
269
|
+
|
270
|
+
### Web UI
|
271
|
+
|
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.
|
273
|
+
|
274
|
+
![Web UI](assets/web_ui.png)
|
275
|
+
|
276
|
+
Here is a simple example of how to mount in a Rails application behind HTTP Basic authentication with hard coded credentials.
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
# config/routes.rb
|
280
|
+
|
281
|
+
mount Rack::Builder.new do
|
282
|
+
use Rack::Auth::Basic do |username, password|
|
283
|
+
username == ENV.fetch("AUTH_USER") && password == ENV.fetch("AUTH_PASSWORD")
|
284
|
+
end
|
285
|
+
run UltraSettings::RackApp
|
286
|
+
end, at: "/ultra_settings"
|
287
|
+
```
|
288
|
+
|
289
|
+
### Testing
|
290
|
+
|
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:
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
# Override a configuration added on the global namespace
|
295
|
+
|
296
|
+
UltraSettings.override!(test: {foo: "bar"}) do
|
297
|
+
expect(TestConfiguration.instance.foo).to eq "bar"
|
298
|
+
end
|
299
|
+
|
300
|
+
# or directly on the configuration class
|
301
|
+
|
302
|
+
TestConfiguration.override!(foo: "bar") do
|
303
|
+
expect(TestConfiguration.instance.foo).to eq "bar"
|
304
|
+
end
|
305
|
+
|
306
|
+
# or on the instance itself
|
307
|
+
|
308
|
+
TestConfiguration.instance.override!(foo: "bar") do
|
309
|
+
expect(TestConfiguration.instance.foo).to eq "bar"
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
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.
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
# RSpec setup
|
317
|
+
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
|
321
|
+
example.run
|
322
|
+
end
|
323
|
+
else
|
324
|
+
example.run
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# In a test
|
330
|
+
it 'has the settings I want', ultra_settings: {test: {foo: "bar"}} do
|
331
|
+
expect(UltraSettings.test.foo).to eq("bar")
|
332
|
+
end
|
333
|
+
```
|
334
|
+
|
16
335
|
## Installation
|
17
336
|
|
18
337
|
Add this line to your application's Gemfile:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.0.1
|
data/app/application.css
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
.ultra-settings-nav {
|
2
|
+
margin-bottom: 1rem;
|
3
|
+
}
|
4
|
+
|
5
|
+
.ultra-settings-nav form {
|
6
|
+
margin: 0;
|
7
|
+
}
|
8
|
+
|
9
|
+
.ultra-settings-table {
|
10
|
+
width: 100%;
|
11
|
+
max-width: 100%;
|
12
|
+
margin-bottom: 1rem;
|
13
|
+
border-collapse: collapse;
|
14
|
+
}
|
15
|
+
|
16
|
+
.ultra-settings-table thead th {
|
17
|
+
vertical-align: bottom;
|
18
|
+
border-bottom: 2px solid #dee2e6;
|
19
|
+
}
|
20
|
+
|
21
|
+
.ultra-settings-table td, .ultra-settings-table th {
|
22
|
+
padding: 0.75rem;
|
23
|
+
vertical-align: top;
|
24
|
+
border-top: 1px solid #dee2e6;
|
25
|
+
}
|
26
|
+
|
27
|
+
.ultra-settings-table tbody tr:nth-of-type(odd) {
|
28
|
+
background-color: rgba(0, 0, 0, .03);
|
29
|
+
}
|
30
|
+
|
31
|
+
.ultra-settings-code {
|
32
|
+
font-family: monospace;
|
33
|
+
font-size: 0.9rem;
|
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 {
|
44
|
+
font-weight: 600;
|
45
|
+
color: blue;
|
46
|
+
}
|
47
|
+
|
48
|
+
.ultra-settings-description {
|
49
|
+
font-size: 0.9rem;
|
50
|
+
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
|
+
font-style: italic;
|
64
|
+
}
|
65
|
+
|
66
|
+
.ultra-settings-select {
|
67
|
+
display: inline-block;
|
68
|
+
padding: .375rem 2.25rem .375rem .75rem;
|
69
|
+
-moz-padding-start: calc(0.75rem - 3px);
|
70
|
+
font-size: 1rem;
|
71
|
+
font-weight: 400;
|
72
|
+
line-height: 1.5;
|
73
|
+
color: #212529;
|
74
|
+
background-color: #fff;
|
75
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
76
|
+
background-repeat: no-repeat;
|
77
|
+
background-position: right .75rem center;
|
78
|
+
background-size: 16px 12px;
|
79
|
+
border: 1px solid #ced4da;
|
80
|
+
border-radius: .25rem;
|
81
|
+
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
82
|
+
-webkit-appearance: none;
|
83
|
+
-moz-appearance: none;
|
84
|
+
appearance: none;
|
85
|
+
}
|
data/app/application.js
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
document.addEventListener("DOMContentLoaded", () => {
|
2
|
+
const menu = document.getElementById("config-selector");
|
3
|
+
|
4
|
+
showCurrentConfiguration = () => {
|
5
|
+
const selectedId = menu.options[menu.selectedIndex].value;
|
6
|
+
|
7
|
+
document.querySelectorAll(".ultra-settings-configuration").forEach((configuration) => {
|
8
|
+
if (configuration.id === selectedId) {
|
9
|
+
configuration.style.display = "block";
|
10
|
+
} else {
|
11
|
+
configuration.style.display = "none";
|
12
|
+
}
|
13
|
+
});
|
14
|
+
}
|
15
|
+
|
16
|
+
menu.addEventListener("change", showCurrentConfiguration);
|
17
|
+
|
18
|
+
showCurrentConfiguration();
|
19
|
+
});
|
data/app/index.html.erb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
<div class="ultra-settings-nav">
|
2
|
+
<form onsubmit="return false">
|
3
|
+
<select class="ultra-settings-select" size="1" id="config-selector">
|
4
|
+
<% UltraSettings.__configuration_names__.sort.each do |name| %>
|
5
|
+
<option value="config-<%= name %>"><%= name %></option>
|
6
|
+
<% end %>
|
7
|
+
</select>
|
8
|
+
</form>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<% UltraSettings.__configuration_names__.sort.each do |name| %>
|
12
|
+
<% configuration = UltraSettings.send(name) %>
|
13
|
+
|
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
|
+
✔
|
81
|
+
<% end %>
|
82
|
+
</span>
|
83
|
+
</td>
|
84
|
+
</tr>
|
85
|
+
<% end %>
|
86
|
+
</tbody>
|
87
|
+
</table>
|
88
|
+
</div>
|
89
|
+
<% end %>
|
90
|
+
|
91
|
+
<script>
|
92
|
+
<%= @javascript %>
|
93
|
+
</script>
|
data/app/layout.css
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
* {box-sizing:border-box;}
|
2
|
+
|
3
|
+
body {
|
4
|
+
font-family: sans-serif;
|
5
|
+
font-size: 1rem;
|
6
|
+
line-height: 1.5;
|
7
|
+
text-align: left;
|
8
|
+
color: #212529;
|
9
|
+
background-color: #ffffff;
|
10
|
+
margin: 0;
|
11
|
+
padding: 0;
|
12
|
+
}
|
13
|
+
|
14
|
+
header {
|
15
|
+
background-color: #666;
|
16
|
+
color: white;
|
17
|
+
padding: 1rem;
|
18
|
+
margin-bottom: 1rem;
|
19
|
+
}
|
20
|
+
|
21
|
+
header h1 {
|
22
|
+
margin: 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
main {
|
26
|
+
margin: 1rem;
|
27
|
+
}
|
data/app/layout.html.erb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<title>Application Settings</title>
|
6
|
+
<meta charset="utf-8">
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
8
|
+
<style type="text/css">
|
9
|
+
<%= @layout_css %>
|
10
|
+
<%= css %>
|
11
|
+
</style>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<header>
|
15
|
+
<h1>Application Settings</h1>
|
16
|
+
</header>
|
17
|
+
<main>
|
18
|
+
<%= content %>
|
19
|
+
</main>
|
20
|
+
</body>
|
21
|
+
</html>
|