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
data/lib/ultra_settings/field.rb
CHANGED
@@ -5,51 +5,41 @@ module UltraSettings
|
|
5
5
|
class Field
|
6
6
|
attr_reader :name
|
7
7
|
attr_reader :type
|
8
|
+
attr_reader :description
|
8
9
|
attr_reader :default
|
9
10
|
attr_reader :default_if
|
10
11
|
attr_reader :env_var
|
11
|
-
attr_reader :
|
12
|
+
attr_reader :runtime_setting
|
12
13
|
attr_reader :yaml_key
|
13
|
-
attr_reader :env_var_prefix
|
14
|
-
attr_reader :env_var_upcase
|
15
|
-
attr_reader :setting_prefix
|
16
|
-
attr_reader :setting_upcase
|
17
14
|
|
18
15
|
# @param name [String, Symbol] The name of the field.
|
19
16
|
# @param type [Symbol] The type of the field.
|
17
|
+
# @param description [String] The description of the field.
|
20
18
|
# @param default [Object] The default value of the field.
|
21
19
|
# @param default_if [Proc] A proc that returns true if the default value should be used.
|
22
20
|
# @param env_var [String, Symbol] The name of the environment variable to use for the field.
|
23
|
-
# @param
|
21
|
+
# @param runtime_setting [String, Symbol] The name of the setting to use for the field.
|
24
22
|
# @param yaml_key [String, Symbol] The name of the YAML key to use for the field.
|
25
|
-
# @param env_var_prefix [String, Symbol] The prefix to use for the environment variable name.
|
26
|
-
# @param env_var_upcase [Boolean] Whether or not to upcase the environment variable name.
|
27
|
-
# @param setting_prefix [String, Symbol] The prefix to use for the setting name.
|
28
|
-
# @param setting_upcase [Boolean] Whether or not to upcase the setting name.
|
29
23
|
def initialize(
|
30
24
|
name:,
|
31
25
|
type: :string,
|
26
|
+
description: nil,
|
32
27
|
default: nil,
|
33
28
|
default_if: nil,
|
34
29
|
env_var: nil,
|
35
|
-
|
30
|
+
runtime_setting: nil,
|
36
31
|
yaml_key: nil,
|
37
|
-
|
38
|
-
env_var_upcase: true,
|
39
|
-
setting_prefix: nil,
|
40
|
-
setting_upcase: false
|
32
|
+
static: false
|
41
33
|
)
|
42
|
-
@name =
|
34
|
+
@name = name.to_s.freeze
|
43
35
|
@type = type.to_sym
|
44
|
-
@
|
36
|
+
@description = description&.to_s&.freeze
|
37
|
+
@default = Coerce.coerce_value(default, @type).freeze
|
45
38
|
@default_if = default_if
|
46
|
-
@env_var =
|
47
|
-
@
|
48
|
-
@yaml_key =
|
49
|
-
@
|
50
|
-
@env_var_upcase = !!env_var_upcase
|
51
|
-
@setting_prefix = frozen_string(setting_prefix)
|
52
|
-
@setting_upcase = !!setting_upcase
|
39
|
+
@env_var = env_var&.to_s&.freeze
|
40
|
+
@runtime_setting = runtime_setting&.to_s&.freeze
|
41
|
+
@yaml_key = yaml_key&.to_s&.freeze
|
42
|
+
@static = !!static
|
53
43
|
end
|
54
44
|
|
55
45
|
# Get the value for the field from the passed in state.
|
@@ -58,85 +48,64 @@ module UltraSettings
|
|
58
48
|
# @param settings [#[]] The runtime settings.
|
59
49
|
# @param yaml_config [#[]] The YAML configuration.
|
60
50
|
def value(env: nil, settings: nil, yaml_config: nil)
|
61
|
-
|
62
|
-
val = coerce_value(val).freeze
|
63
|
-
val = @default if use_default?(val)
|
64
|
-
val
|
51
|
+
fetch_value_and_source(env: env, settings: settings, yaml_config: yaml_config).first
|
65
52
|
end
|
66
53
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
54
|
+
# Get the source for the field from the passed in state.
|
55
|
+
#
|
56
|
+
# @param env [Hash] The environment variables.
|
57
|
+
# @param settings [Hash] The runtime settings.
|
58
|
+
# @param yaml_config [Hash] The YAML configuration.
|
59
|
+
# @return [Symbol, nil] The source of the value (:env, :settings, or :yaml).
|
60
|
+
def source(env: nil, settings: nil, yaml_config: nil)
|
61
|
+
fetch_value_and_source(env: env, settings: settings, yaml_config: yaml_config).last
|
62
|
+
end
|
77
63
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
64
|
+
# Coerce the passed in value to the type of the field.
|
65
|
+
#
|
66
|
+
# @param value [Object] The value to coerce.
|
67
|
+
# @return [Object] The coerced value.
|
68
|
+
def coerce(value)
|
69
|
+
Coerce.coerce_value(value, @type)
|
70
|
+
end
|
82
71
|
|
83
|
-
|
72
|
+
# Returns true if the field is static.
|
73
|
+
#
|
74
|
+
# @return [Boolean]
|
75
|
+
def static?
|
76
|
+
@static
|
84
77
|
end
|
85
78
|
|
86
|
-
|
87
|
-
|
79
|
+
private
|
80
|
+
|
81
|
+
def fetch_value_and_source(env:, settings:, yaml_config:)
|
82
|
+
source = nil
|
88
83
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
value
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
value.to_s.to_sym
|
84
|
+
value = env[env_var] if env && env_var
|
85
|
+
value = nil if value == ""
|
86
|
+
if value.nil?
|
87
|
+
value = settings[runtime_setting] if settings && runtime_setting
|
88
|
+
value = nil if value == ""
|
89
|
+
if value.nil?
|
90
|
+
value = yaml_value(yaml_config)
|
91
|
+
value = nil if value == ""
|
92
|
+
source = :yaml unless value.nil?
|
93
|
+
else
|
94
|
+
source = :settings
|
95
|
+
end
|
102
96
|
else
|
103
|
-
|
97
|
+
source = :env
|
104
98
|
end
|
105
|
-
end
|
106
99
|
|
107
|
-
|
108
|
-
var_name = env_var
|
109
|
-
if var_name.nil?
|
110
|
-
var_name = "#{env_var_prefix}#{name}"
|
111
|
-
var_name = var_name.upcase if env_var_upcase
|
112
|
-
end
|
113
|
-
env[var_name.to_s]
|
114
|
-
end
|
100
|
+
value = coerce(value).freeze
|
115
101
|
|
116
|
-
|
117
|
-
var_name = setting_name
|
118
|
-
if var_name.nil?
|
119
|
-
var_name = "#{setting_prefix}#{name}"
|
120
|
-
var_name = var_name.upcase if setting_upcase
|
121
|
-
end
|
122
|
-
settings[var_name.to_s]
|
102
|
+
[value, source]
|
123
103
|
end
|
124
104
|
|
125
105
|
def yaml_value(yaml_config)
|
126
|
-
|
127
|
-
yaml_config[key.to_s]
|
128
|
-
end
|
129
|
-
|
130
|
-
def use_default?(value)
|
131
|
-
if value && @default_if
|
132
|
-
@default_if.call(value)
|
133
|
-
else
|
134
|
-
value.nil?
|
135
|
-
end
|
136
|
-
end
|
106
|
+
return nil unless yaml_config && yaml_key
|
137
107
|
|
138
|
-
|
139
|
-
value&.to_s&.dup&.freeze
|
108
|
+
yaml_config[yaml_key]
|
140
109
|
end
|
141
110
|
end
|
142
111
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UltraSettings
|
4
|
+
# Rack application for displaying the current settings in an HTML page.
|
5
|
+
# No setting values are displayed, but you should still add some
|
6
|
+
# sort of authentication if you want to use this in production.
|
7
|
+
class RackApp
|
8
|
+
def initialize
|
9
|
+
@webview = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
[200, {"content-type" => "text/html; charset=utf8"}, [webview.render_settings]]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def webview
|
19
|
+
if ENV.fetch("RAILS_ENV", ENV.fetch("RACK_ENV", "development")) == "development"
|
20
|
+
@webview = nil
|
21
|
+
end
|
22
|
+
@webview ||= WebView.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UltraSettings
|
4
|
+
# Railtie to automatically configure settings for Rails applications.
|
5
|
+
# By default this will automatically load any configuration classes in the
|
6
|
+
# app/configurations directory. This can be customized by setting the
|
7
|
+
# `config.ultra_settings.auto_load_directories` option.
|
8
|
+
class Railtie < Rails::Railtie
|
9
|
+
config.ultra_settings = ActiveSupport::OrderedOptions.new
|
10
|
+
config.ultra_settings.auto_load_directories = [File.join("app", "configurations")]
|
11
|
+
|
12
|
+
config.before_configuration do
|
13
|
+
UltraSettings.yaml_config_env = Rails.env
|
14
|
+
UltraSettings.yaml_config_path = Rails.root.join("config")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Automatically register any configuration classes in the app/configurations
|
18
|
+
# directory. The path to load can be customized by setting the
|
19
|
+
# `config.ultra_settings.auto_load_directory` option.
|
20
|
+
config.after_initialize do
|
21
|
+
Array(Rails.application.config.ultra_settings.auto_load_directories).each do |directory|
|
22
|
+
next unless directory
|
23
|
+
|
24
|
+
app_config_dir = Rails.root.join(directory)
|
25
|
+
app_config_dir.glob("**/*_configuration.rb").each do |file_path|
|
26
|
+
config_name = file_path.basename("_configuration.rb")
|
27
|
+
class_name = file_path.relative_path_from(app_config_dir).to_s.chomp(".rb").classify
|
28
|
+
UltraSettings.add(config_name, class_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UltraSettings
|
4
|
+
# Helper class for rendering the settings information in an HTML page.
|
5
|
+
class WebView
|
6
|
+
attr_reader :css
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@index_template = erb_template("index.html.erb")
|
10
|
+
@layout_template = erb_template("layout.html.erb")
|
11
|
+
@layout_css = read_app_file("layout.css")
|
12
|
+
@css = read_app_file("application.css")
|
13
|
+
@javascript = read_app_file("application.js")
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_settings
|
17
|
+
@layout_template.result(binding)
|
18
|
+
end
|
19
|
+
|
20
|
+
def content
|
21
|
+
@index_template.result(binding)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def erb_template(path)
|
27
|
+
ERB.new(read_app_file(path))
|
28
|
+
end
|
29
|
+
|
30
|
+
def read_app_file(path)
|
31
|
+
File.read(File.join(app_dir, path))
|
32
|
+
end
|
33
|
+
|
34
|
+
def app_dir
|
35
|
+
File.expand_path(File.join("..", "..", "app"), __dir__)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UltraSettings
|
4
|
+
# Helper class to load YAML configuration files. Any ERB markup in the YAML
|
5
|
+
# file will be evaluated. The YAML file should be structured like this:
|
6
|
+
#
|
7
|
+
# ```yaml
|
8
|
+
# shared:
|
9
|
+
# foo: bar
|
10
|
+
# bar: baz
|
11
|
+
#
|
12
|
+
# development:
|
13
|
+
# bar: qux
|
14
|
+
# biz: buz
|
15
|
+
#
|
16
|
+
# test:
|
17
|
+
# bar: qix
|
18
|
+
# biz: biz
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
# The section with the key matching the environment name is merged into
|
22
|
+
# the shared section. In this example, the development environment would
|
23
|
+
# have the following configuration:
|
24
|
+
#
|
25
|
+
# ```ruby
|
26
|
+
# {
|
27
|
+
# "foo" => "bar",
|
28
|
+
# "bar" => "qux",
|
29
|
+
# "biz" => "buz"
|
30
|
+
# }
|
31
|
+
# ```
|
32
|
+
#
|
33
|
+
# In addition, the keys are flattened into a one level deep hash with dots
|
34
|
+
# separating the keys.
|
35
|
+
class YamlConfig
|
36
|
+
def initialize(path, environment)
|
37
|
+
yaml = load_yaml(path)
|
38
|
+
@config = environment_config(yaml, environment)
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_h
|
42
|
+
@config
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def load_yaml(path)
|
48
|
+
yaml = File.read(path)
|
49
|
+
|
50
|
+
if yaml.include?("<%")
|
51
|
+
yaml = ERB.new(yaml).result
|
52
|
+
end
|
53
|
+
|
54
|
+
hash = YAML.load(yaml) # rubocop:disable Security/YAMLLoad
|
55
|
+
hash = {} unless hash.is_a?(Hash)
|
56
|
+
hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def environment_config(yaml, environment)
|
60
|
+
shared = flatten_hash(yaml.fetch("shared", {}))
|
61
|
+
env = flatten_hash(yaml.fetch(environment, {}))
|
62
|
+
shared.merge(env)
|
63
|
+
end
|
64
|
+
|
65
|
+
def flatten_hash(hash, prefix = nil)
|
66
|
+
hash.each_with_object({}) do |(key, value), result|
|
67
|
+
key = key.to_s
|
68
|
+
key = "#{prefix}.#{key}" if prefix
|
69
|
+
|
70
|
+
if value.is_a?(Hash)
|
71
|
+
result.merge!(flatten_hash(value, key))
|
72
|
+
else
|
73
|
+
result[key] = value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|