system_settings 0.6.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -13
  3. data/app/assets/config/manifest.js +1 -0
  4. data/app/assets/stylesheets/system_settings/application.css +227 -0
  5. data/app/controllers/system_settings/application_controller.rb +3 -9
  6. data/app/controllers/system_settings/settings_controller.rb +25 -21
  7. data/app/helpers/system_settings/application_helper.rb +36 -0
  8. data/app/models/system_settings/application_record.rb +2 -4
  9. data/app/models/system_settings/boolean_setting.rb +3 -5
  10. data/app/models/system_settings/configurator.rb +103 -79
  11. data/app/models/system_settings/decimal_list_setting.rb +6 -0
  12. data/app/models/system_settings/decimal_setting.rb +6 -0
  13. data/app/models/system_settings/errors/error.rb +2 -4
  14. data/app/models/system_settings/errors/not_found_error.rb +2 -4
  15. data/app/models/system_settings/errors/not_loaded_error.rb +6 -0
  16. data/app/models/system_settings/errors/settings_read_error.rb +2 -4
  17. data/app/models/system_settings/integer_list_setting.rb +3 -5
  18. data/app/models/system_settings/integer_setting.rb +3 -5
  19. data/app/models/system_settings/list_of_decimals_validator.rb +35 -0
  20. data/app/models/system_settings/list_of_integers_validator.rb +23 -25
  21. data/app/models/system_settings/list_of_strings_validator.rb +23 -25
  22. data/app/models/system_settings/setting.rb +3 -5
  23. data/app/models/system_settings/string_list_setting.rb +3 -5
  24. data/app/models/system_settings/string_setting.rb +7 -4
  25. data/app/models/system_settings/type/decimal_list.rb +40 -0
  26. data/app/models/system_settings/type/integer_list.rb +24 -33
  27. data/app/models/system_settings/type/string_list.rb +19 -21
  28. data/app/views/layouts/system_settings/application.html.erb +21 -0
  29. data/app/views/system_settings/settings/_common_attributes.html.erb +14 -0
  30. data/app/views/system_settings/settings/_form.html.erb +18 -0
  31. data/app/views/system_settings/settings/edit.html.erb +2 -0
  32. data/app/views/system_settings/settings/index.html.erb +29 -0
  33. data/app/views/system_settings/settings/show.html.erb +9 -0
  34. data/config/locales/system_settings.en.yml +27 -1
  35. data/config/routes.rb +5 -4
  36. data/lib/system_settings.rb +3 -2
  37. data/lib/system_settings/engine.rb +3 -12
  38. data/lib/system_settings/version.rb +1 -1
  39. metadata +17 -14
  40. data/app/controllers/system_settings/root_controller.rb +0 -13
  41. data/app/models/system_settings/pagination.rb +0 -20
  42. data/frontend/build/asset-manifest.json +0 -11
  43. data/frontend/build/favicon.ico +0 -0
  44. data/frontend/build/index.html +0 -1
  45. data/frontend/build/precache-manifest.c31853abffc7c301755b0e5b8443e875.js +0 -22
  46. data/frontend/build/service-worker.js +0 -39
  47. data/frontend/build/static/css/main.879d159f.chunk.css +0 -1
  48. data/frontend/build/static/js/2.8729aa12.chunk.js +0 -1
  49. data/frontend/build/static/js/main.99494978.chunk.js +0 -1
  50. data/frontend/build/static/js/runtime~main.ea5ad98e.js +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19edc85867dc8e77f5c478253810138cfa2e1d3de4bb32543a7d18adbb5e9732
4
- data.tar.gz: '00488e7c29d499bc5c1f48ba7ac59b0fcde7cd70c413706ccd99ac119e9ad01e'
3
+ metadata.gz: 213bb372d94ea27ce951f424559b1e19812248cca9df0f66136d4776d9848fb8
4
+ data.tar.gz: 0530b07ab886e8e2515d957c839b37c1eb7817d90deb2e1e2996d10457c08efa
5
5
  SHA512:
6
- metadata.gz: 9cbacb36e4b9b5272da2f7756843fe232bf16b878a77467e8b464e88f909d545d6c6f55725345a4b8e3513bc05a3d4f493f9127ab01e676518d6396b337d5134
7
- data.tar.gz: cb1ab8e4b6183a1fdf3670a1785b77f3c57f2a9bfa53b95feb42392fab65effb7a9ce9862958ed4f05b1635ef79c32ce7fc0b2f9ec8e142a829b1f7106b187d2
6
+ metadata.gz: 5d4ea1661ba9b875628ae3ac32e26cb593607ce8e470bc651287d105e23889b6794a1db594dff754dc1fcf89f0118995b4dc544c1d4d9a8fbfc3391d20e532a6
7
+ data.tar.gz: 397e5ade494169a4ff92c6bab9abada406c4d5ae9b2e3725a1ac282ec2d7cb7a066f8f7c69a724826d1e20bd3dc97f4decf48a80c08c61c54ad8a80193bdfcea
data/README.md CHANGED
@@ -42,10 +42,14 @@ string :default_locale, value: "en"
42
42
  integer :default_records_per_page, value: 25
43
43
  integer :remainder_interval_in_hours, value: 48
44
44
 
45
- # Array type strings and integers
45
+ # Decimal values
46
+ decimal :max_temp, value: 95.2
47
+
48
+ # Array type strings, integers and decimals
46
49
  string_list :admin_emails, description: "Will receive alerts"
47
50
  string_list :upload_allowed_extensions, value: ["docx", "pdf", "txt"]
48
51
  integer_list :lucky_numbers, description: "Prime numbers are more effective", value: [2, 3, 5, 11]
52
+ decimal_list :allowed_multipliers, value: [12.3, 99, BigDecimal("-87")]
49
53
  ```
50
54
 
51
55
  Load values from `config/system_settings.rb` into database:
@@ -93,19 +97,16 @@ If you would like to store your settings somewhere else than `config/system_sett
93
97
 
94
98
  ## Using System Settings in tests
95
99
 
96
- Your test suite probably clears database before/after every test example. Fortunately is very easy to load fresh settings from configuration file. It can be done by running `SystemSettings.load`.
100
+ Your test suite probably clears database before/after every test example. Fortunately is very easy to load fresh settings from configuration file.
101
+ It can be done by running `SystemSettings.load`. It will persist all loaded settings. But if you would like to persist only a subset of loaded settings run `SystemSettings.load(:one, :two, :three)`.
102
+
97
103
  And if you modify settings values in test example you can reset to defaults with `SystemSettings.reset_to_defaults`.
98
104
 
99
105
 
100
106
  ## Development
101
107
 
102
- Required development dependencies:
103
- * [Node.js](https://nodejs.org/) - JavaScript runtime
104
- * [Yarn](https://yarnpkg.com/) - package manager
105
-
106
108
  Optional development tools:
107
- * [overmind](https://github.com/DarthSim/overmind) - Process manager for Procfile-based applications and tmux
108
- * [direnv](https://direnv.net/) - Unclutter your .profile
109
+ * [direnv](https://direnv.net/) - Unclutter your .profile
109
110
 
110
111
  Required environment variables:
111
112
  * `RAILS_VERSION`
@@ -120,16 +121,13 @@ Getting started with development:
120
121
  1) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 bundle`
121
122
  2) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails db:create db:migrate`
122
123
  3) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails test`
123
- 4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails frontend:install`
124
- 4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails app:system_settings:load`
125
- 4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 overmind start`
126
-
127
124
 
128
125
  ## Build status
129
126
  System Settings is being tested with Rails versions - `5.0`, `5.1`, `5.2`, `6.0`, `rails repo master branch`
130
127
 
131
128
  [![Build Status](https://dev.azure.com/kristsozols/System%20Settings/_apis/build/status/krists.system_settings?branchName=master)](https://dev.azure.com/kristsozols/System%20Settings/_build/latest?definitionId=1&branchName=master)
132
-
129
+ [![Maintainability](https://api.codeclimate.com/v1/badges/3ad889ca36f62bad04dc/maintainability)](https://codeclimate.com/github/krists/system_settings/maintainability)
130
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/3ad889ca36f62bad04dc/test_coverage)](https://codeclimate.com/github/krists/system_settings/test_coverage)
133
131
 
134
132
  ## License
135
133
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,227 @@
1
+ html {
2
+ box-sizing: border-box;
3
+ font-size: 14px;
4
+ font-family: Arial, Helvetica, sans-serif;
5
+ overflow-y: scroll;
6
+ }
7
+
8
+ *, *:before, *:after {box-sizing: inherit;}
9
+
10
+ body {
11
+ margin: 0;
12
+ padding: 0;
13
+ font-weight: normal;
14
+ min-height: 100vh;
15
+ position: relative;
16
+ display: flex;
17
+ flex-direction: column;
18
+ color: #233656;
19
+ background: white;
20
+ font-size: 1rem;
21
+ line-height: 1.5rem;
22
+ }
23
+
24
+ header {
25
+ border-bottom: 1px solid #e1e1e1;
26
+ height: 2rem;
27
+ padding: 0.5rem 0;
28
+ box-sizing: content-box;
29
+ background: white;
30
+ position: sticky;
31
+ top: 0;
32
+ width: 100%;
33
+ }
34
+
35
+ main {
36
+ padding: 3rem 0;
37
+ }
38
+
39
+ header .container,
40
+ main .container {
41
+ max-width: 1020px;
42
+ margin: 0 auto;
43
+ }
44
+
45
+ a { color: #233656; text-decoration: none; }
46
+ a:hover { text-decoration: underline; }
47
+
48
+ .app-name, .app-name:hover, .app-name:active {
49
+ font-size: 1.5rem;
50
+ line-height: 2rem;
51
+ font-weight: bold;
52
+ user-select: none;
53
+ text-decoration: none;
54
+ }
55
+
56
+ .sys-name {
57
+ display: inline-block;
58
+ background: #f2f2f2;
59
+ border-radius: 3px;
60
+ padding: 0 0.5em;
61
+ font-family: "Courier New", Courier, monospace;
62
+ font-size: 0.75em;
63
+ max-width: 100%;
64
+ }
65
+
66
+ table th {
67
+ text-align: left;
68
+ }
69
+
70
+ .settings-table {
71
+ width: 100%;
72
+ table-layout: fixed;
73
+ white-space: nowrap;
74
+ user-select: none;
75
+ }
76
+
77
+ .settings-table td:empty:after {
78
+ content: "-";
79
+ }
80
+
81
+ .settings-table td {
82
+ overflow: hidden;
83
+ text-overflow: ellipsis;
84
+ }
85
+
86
+ .settings-table .description { width: 35% }
87
+ .settings-table .value { width: 25% }
88
+
89
+ .settings-table tbody td.no-entries {
90
+ color: #737373;
91
+ padding-top: 1rem;
92
+ margin-bottom: 1rem;
93
+ }
94
+
95
+ .settings-table tfoot td {
96
+ font-size: 0.8em;
97
+ padding-top: 1rem;
98
+ margin-bottom: 1rem;
99
+ }
100
+
101
+ .settings-table .value .value-part, .attribute .value .value-part {
102
+ max-width: 100%;
103
+ margin-right: 0.25em;
104
+ }
105
+
106
+ .settings-table .value .value-part:last-child, .attribute .value .value-part:last-child {
107
+ margin-right: 0;
108
+ }
109
+
110
+ .attribute {
111
+ display: flex;
112
+ flex-direction: column;
113
+ margin-bottom: 1rem;
114
+ }
115
+
116
+ .attribute .name {
117
+ font-size: 0.8em;
118
+ color: #737373;
119
+ user-select: none;
120
+ }
121
+
122
+ .attribute .value {
123
+ align-self: flex-start;
124
+ }
125
+ .attribute .value:empty:after {
126
+ content: "-";
127
+ }
128
+
129
+ .attribute .field_with_errors .name, .attribute .errors {
130
+ color: #d01d1d;
131
+ }
132
+ .attribute .hint {
133
+ font-size: 0.8em;
134
+ display: block;
135
+ }
136
+
137
+ .buttons {
138
+ border-top: 1px dotted #f2f2f2;
139
+ padding-top: 1rem;
140
+ margin-bottom: 1rem;
141
+ }
142
+ .buttons > * {
143
+ margin-right: 0.5rem;
144
+ }
145
+
146
+ button, input[type=submit], input[type=button], a.button {
147
+ display: inline-block;
148
+ cursor: pointer;
149
+ border: none;
150
+ border-radius: 3px;
151
+ padding: 0.375rem 0.75rem;
152
+ font-size: 1rem;
153
+ line-height: 1.5;
154
+ user-select: none;
155
+ white-space: nowrap;
156
+ }
157
+
158
+ button, input[type=submit], input[type=button] {
159
+ color: #4d4d4d;
160
+ background-color: #d9d9d9;
161
+ transition: background-color 0.1s ease-in-out;
162
+ outline: none;
163
+ }
164
+
165
+ button:focus, button:hover, input[type=submit]:focus, input[type=submit]:hover, input[type=button]:focus, input[type=button]:hover {
166
+ background-color: #b8b8b8;
167
+ }
168
+
169
+ button:active, input[type=submit]:active, input[type=button]:active {
170
+ background-color: #828282;
171
+ }
172
+
173
+ a.button {
174
+ color: #4d4d4d;
175
+ background-color: transparent;
176
+ transition: background-color 0.1s ease-in-out;
177
+ outline: none;
178
+ text-decoration: none;
179
+ }
180
+
181
+ a.button:focus, a.button:hover {
182
+ background-color: rgba(0, 0, 0, 0.15);
183
+ }
184
+
185
+ a.button:active {
186
+ background-color: rgba(0, 0, 0, 0.4);
187
+ }
188
+
189
+ button.primary, input[type=submit].primary, input[type=button].primary, a.button.primary {
190
+ color: #4d4d4d;
191
+ background-color: #a6a6a6;
192
+ transition: background-color 0.1s ease-in-out;
193
+ outline: none;
194
+ }
195
+
196
+ button.primary:focus, button.primary:hover, input[type=submit].primary:focus, input[type=submit].primary:hover, input[type=button].primary:focus, input[type=button].primary:hover, a.button.primary:focus, a.button.primary:hover {
197
+ background-color: #8d8d8d;
198
+ }
199
+
200
+ button.primary:active, input[type=submit].primary:active, input[type=button].primary:active, a.button.primary:active {
201
+ background-color: #646464;
202
+ }
203
+
204
+ input[type=text] {
205
+ border: none;
206
+ border-radius: 3px;
207
+ padding: 0.5em;
208
+ font-size: 1rem;
209
+ line-height: normal;
210
+ color: #4d4d4d;
211
+ background-color: #e6e6e6;
212
+ transition: background-color 0.1s ease-in-out;
213
+ outline: none;
214
+ box-sizing: content-box;
215
+ width: auto;
216
+ min-width: 12ch;
217
+ max-width: calc(100% - 2em);
218
+ will-change: width;
219
+ }
220
+
221
+ input[type=text]:focus {
222
+ background-color: #c4c4c4;
223
+ }
224
+
225
+ input[type=text]:active {
226
+ background-color: #bfbfbf;
227
+ }
@@ -1,13 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SystemSettings
4
- class ApplicationController < ActionController::Base
5
- protect_from_forgery with: :exception
3
+ class SystemSettings::ApplicationController < ActionController::Base
4
+ protect_from_forgery with: :exception
6
5
 
7
- private
8
-
9
- def add_authenticity_token
10
- response.headers["Authenticity-Token"] = form_authenticity_token if protect_against_forgery?
11
- end
12
- end
6
+ ActiveSupport.run_load_hooks(:system_settings_application_controller, self)
13
7
  end
@@ -1,28 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SystemSettings
4
- class SettingsController < SystemSettings::ApplicationController
5
- RETURN_ATTRIBUTES = ["id", "name", "type", "value", "description"].freeze
6
-
7
- def index
8
- @total_count = SystemSettings::Setting.count
9
- @settings = SystemSettings::Setting.order(:name).extending(SystemSettings::Pagination).page(params[:page], per_page: params[:per])
10
- render json: {items: @settings.map { |s| s.as_json(only: RETURN_ATTRIBUTES) }, total_count: @total_count}
11
- end
3
+ class SystemSettings::SettingsController < SystemSettings::ApplicationController
4
+ RETURN_ATTRIBUTES = %w[id name type value description].freeze
5
+ before_action :set_setting, only: [:edit, :show, :update]
12
6
 
13
- def show
14
- @setting = SystemSettings::Setting.find(params[:id])
15
- add_authenticity_token
16
- render json: @setting.as_json(only: RETURN_ATTRIBUTES)
17
- end
7
+ def index
8
+ @settings = SystemSettings::Setting.order(:name)
9
+ end
10
+
11
+ def edit; end
12
+
13
+ def show; end
18
14
 
19
- def update
20
- @setting = SystemSettings::Setting.find(params[:id])
21
- if @setting.update(value: params[:value])
22
- render json: @setting.as_json(only: RETURN_ATTRIBUTES)
23
- else
24
- render json: {errors: @setting.errors.as_json}, status: :unprocessable_entity
25
- end
15
+ def update
16
+ if @setting.update(setting_params)
17
+ redirect_to setting_path(@setting)
18
+ else
19
+ render :edit
26
20
  end
27
21
  end
22
+
23
+ private
24
+
25
+ def set_setting
26
+ @setting = SystemSettings::Setting.find(params[:id])
27
+ end
28
+
29
+ def setting_params
30
+ params.require(:setting).permit(:value)
31
+ end
28
32
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemSettings::ApplicationHelper
4
+ SEPARATOR = ";"
5
+
6
+ def format_value(value)
7
+ if value.respond_to?(:each)
8
+ capture do
9
+ value.each do |v|
10
+ concat content_tag(:span, v, class: "value-part")
11
+ end
12
+ end
13
+ else
14
+ value
15
+ end
16
+ end
17
+
18
+ def format_value_for_form(record)
19
+ case record
20
+ when SystemSettings::StringListSetting
21
+ record.value.map { |v| v.gsub(SEPARATOR, "\\#{SEPARATOR}") }.join(SEPARATOR)
22
+ when SystemSettings::IntegerListSetting, SystemSettings::DecimalListSetting
23
+ record.value.join(SEPARATOR)
24
+ else
25
+ record.value
26
+ end
27
+ end
28
+
29
+ def display_settings_file_path
30
+ if SystemSettings.settings_file_path.to_s.include?(Rails.root.to_s)
31
+ Pathname.new(SystemSettings.settings_file_path).relative_path_from(Rails.root)
32
+ else
33
+ SystemSettings.settings_file_path
34
+ end
35
+ end
36
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SystemSettings
4
- class ApplicationRecord < ActiveRecord::Base
5
- self.abstract_class = true
6
- end
3
+ class SystemSettings::ApplicationRecord < ActiveRecord::Base
4
+ self.abstract_class = true
7
5
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SystemSettings
4
- class BooleanSetting < SystemSettings::Setting
5
- attribute :value, :boolean
6
- validates :value, inclusion: [true, false]
7
- end
3
+ class SystemSettings::BooleanSetting < SystemSettings::Setting
4
+ attribute :value, :boolean
5
+ validates :value, inclusion: [true, false]
8
6
  end
@@ -1,110 +1,134 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SystemSettings
4
- class Configurator
5
- class << self
6
- def from_file(file_name, kernel_class: Kernel)
7
- file_name = file_name.to_path if file_name.respond_to?(:to_path)
8
- raise SystemSettings::Errors::SettingsReadError, "The file name must either be a String or implement #to_path" unless file_name.is_a?(String)
9
- raise SystemSettings::Errors::SettingsReadError, "#{file_name} file does not exist" unless File.exist?(file_name)
10
- raise SystemSettings::Errors::SettingsReadError, "#{file_name} file not readable" unless File.readable?(file_name)
11
- SystemSettings.instrument("system_settings.from_file", path: file_name) do |payload|
12
- file_content = File.read(file_name)
13
- new(kernel_class: kernel_class).tap do |obj|
14
- obj.instance_eval(file_content, file_name, 1)
15
- payload[:items] = obj.items
16
- end
3
+ class SystemSettings::Configurator
4
+ class << self
5
+ def from_file(file_name, kernel_class: Kernel)
6
+ file_name = file_name.to_path if file_name.respond_to?(:to_path)
7
+ raise SystemSettings::Errors::SettingsReadError, "The file name must either be a String or implement #to_path" unless file_name.is_a?(String)
8
+ raise SystemSettings::Errors::SettingsReadError, "#{file_name} file does not exist" unless File.exist?(file_name)
9
+ raise SystemSettings::Errors::SettingsReadError, "#{file_name} file not readable" unless File.readable?(file_name)
10
+ SystemSettings.instrument("system_settings.from_file", path: file_name) do |payload|
11
+ file_content = File.read(file_name)
12
+ new(kernel_class: kernel_class).tap do |obj|
13
+ obj.instance_eval(file_content, file_name, 1)
14
+ payload[:items] = obj.items
17
15
  end
18
16
  end
17
+ end
19
18
 
20
- def purge
21
- new.purge
22
- end
19
+ def purge
20
+ new.purge
23
21
  end
22
+ end
24
23
 
25
- attr_reader :items
24
+ attr_reader :items
26
25
 
27
- def initialize(kernel_class: Kernel, &block)
28
- @items = []
29
- @kernel_class = kernel_class
30
- return unless block_given?
31
- if block.arity == 1
32
- yield self
33
- else
34
- instance_exec(&block)
35
- end
26
+ def initialize(kernel_class: Kernel, &block)
27
+ @items = []
28
+ @kernel_class = kernel_class
29
+ return unless block_given?
30
+ if block.arity == 1
31
+ yield self
32
+ else
33
+ instance_exec(&block)
36
34
  end
35
+ end
37
36
 
38
- def string(name, value: nil, description: nil, &blk)
39
- add(name, SystemSettings::StringSetting, value: value, description: description, &blk)
40
- end
37
+ def string(name, value: nil, description: nil, &blk)
38
+ add(name, SystemSettings::StringSetting, value: value, description: description, &blk)
39
+ end
41
40
 
42
- def string_list(name, value: nil, description: nil, &blk)
43
- add(name, SystemSettings::StringListSetting, value: value || [], description: description, &blk)
44
- end
41
+ def string_list(name, value: nil, description: nil, &blk)
42
+ add(name, SystemSettings::StringListSetting, value: value || [], description: description, &blk)
43
+ end
45
44
 
46
- def integer(name, value: nil, description: nil, &blk)
47
- add(name, SystemSettings::IntegerSetting, value: value, description: description, &blk)
48
- end
45
+ def integer(name, value: nil, description: nil, &blk)
46
+ add(name, SystemSettings::IntegerSetting, value: value, description: description, &blk)
47
+ end
49
48
 
50
- def integer_list(name, value: nil, description: nil, &blk)
51
- add(name, SystemSettings::IntegerListSetting, value: value || [], description: description, &blk)
52
- end
49
+ def integer_list(name, value: nil, description: nil, &blk)
50
+ add(name, SystemSettings::IntegerListSetting, value: value || [], description: description, &blk)
51
+ end
53
52
 
54
- def boolean(name, value: nil, description: nil, &blk)
55
- add(name, SystemSettings::BooleanSetting, value: value, description: description, &blk)
56
- end
53
+ def boolean(name, value: nil, description: nil, &blk)
54
+ add(name, SystemSettings::BooleanSetting, value: value, description: description, &blk)
55
+ end
57
56
 
58
- def persist
59
- SystemSettings.instrument("system_settings.persist", items: @items) do |payload|
60
- if settings_table_exists?
61
- SystemSettings::Setting.transaction do
62
- @items.each do |entry|
63
- persisted_record = SystemSettings::Setting.find_by(name: entry[:name])
64
- if persisted_record
65
- if persisted_record.class == entry[:class]
66
- persisted_record.update!(description: entry[:description])
67
- else
68
- warn "SystemSettings: Type mismatch detected! Previously #{entry[:name]} had type #{persisted_record.class.name} but you are loading #{entry[:class].name}"
69
- end
70
- else
71
- entry[:class].create!(name: entry[:name], value: entry[:value], description: entry[:description])
57
+ def decimal(name, value: nil, description: nil, &blk)
58
+ add(name, SystemSettings::DecimalSetting, value: value, description: description, &blk)
59
+ end
60
+
61
+ def decimal_list(name, value: nil, description: nil, &blk)
62
+ add(name, SystemSettings::DecimalListSetting, value: value || [], description: description, &blk)
63
+ end
64
+
65
+ def persist(only: [])
66
+ SystemSettings.instrument("system_settings.persist", items: @items) do |payload|
67
+ if settings_table_exists?
68
+ SystemSettings::Setting.transaction do
69
+ if only.empty?
70
+ @items.each { |item| create_or_update_item(item) }
71
+ else
72
+ only.each do |wanted_name|
73
+ item = @items.find { |i| i[:name] == wanted_name } || begin
74
+ loaded_names = @items.empty? ? "(none)" : @items.map{ |i| i[:name] }.join("\n")
75
+ message = <<~MESSAGE.strip
76
+ Couldn't persist system setting #{wanted_name}. There are no items by this name. Could it be a typo?
77
+
78
+ Configurator has loaded following items:
79
+ #{loaded_names}
80
+ MESSAGE
81
+ raise(SystemSettings::Errors::NotLoadedError, message)
72
82
  end
83
+ create_or_update_item(item)
73
84
  end
74
85
  end
75
- payload[:success] = true
76
- else
77
- warn "SystemSettings: Settings table has not been created!"
78
- payload[:success] = false
79
86
  end
87
+ payload[:success] = true
88
+ else
89
+ warn "SystemSettings: Settings table has not been created!"
90
+ payload[:success] = false
80
91
  end
81
92
  end
93
+ end
82
94
 
83
- def purge
84
- SystemSettings.instrument("system_settings.purge") do |payload|
85
- if settings_table_exists?
86
- SystemSettings::Setting.delete_all
87
- payload[:success] = true
88
- else
89
- payload[:success] = false
90
- end
95
+ def purge
96
+ SystemSettings.instrument("system_settings.purge") do |payload|
97
+ if settings_table_exists?
98
+ SystemSettings::Setting.delete_all
99
+ payload[:success] = true
100
+ else
101
+ payload[:success] = false
91
102
  end
92
103
  end
104
+ end
93
105
 
94
- private
106
+ private
95
107
 
96
- def warn(*args)
97
- @kernel_class.warn(*args)
98
- end
108
+ def warn(*args)
109
+ @kernel_class.warn(*args)
110
+ end
99
111
 
100
- def settings_table_exists?
101
- SystemSettings::Setting.table_exists?
102
- end
112
+ def settings_table_exists?
113
+ SystemSettings::Setting.table_exists?
114
+ end
103
115
 
104
- def add(name, class_const, value:, description:)
105
- value = yield(value) if block_given?
106
- value = value.call if value.is_a?(Proc)
107
- @items.push(name: name, class: class_const, value: value, description: description)
116
+ def add(name, class_const, value:, description:)
117
+ value = yield(value) if block_given?
118
+ value = value.call if value.is_a?(Proc)
119
+ @items.push(name: name, class: class_const, value: value, description: description)
120
+ end
121
+
122
+ def create_or_update_item(item)
123
+ persisted_record = SystemSettings::Setting.find_by(name: item[:name])
124
+ if persisted_record
125
+ if persisted_record.class == item[:class]
126
+ persisted_record.update!(description: item[:description])
127
+ else
128
+ warn "SystemSettings: Type mismatch detected! Previously #{item[:name]} had type #{persisted_record.class.name} but you are loading #{item[:class].name}"
129
+ end
130
+ else
131
+ item[:class].create!(name: item[:name], value: item[:value], description: item[:description])
108
132
  end
109
133
  end
110
134
  end