system_settings 0.7.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -12
  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 +100 -94
  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 +8 -3
  15. data/app/models/system_settings/errors/not_loaded_error.rb +2 -4
  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/locales/system_settings.lv.yml +65 -0
  36. data/config/routes.rb +5 -4
  37. data/lib/system_settings/engine.rb +3 -12
  38. data/lib/system_settings/version.rb +1 -1
  39. data/lib/system_settings.rb +1 -0
  40. metadata +18 -19
  41. data/app/controllers/system_settings/root_controller.rb +0 -13
  42. data/app/models/system_settings/pagination.rb +0 -20
  43. data/frontend/build/asset-manifest.json +0 -15
  44. data/frontend/build/favicon.ico +0 -0
  45. data/frontend/build/index.html +0 -1
  46. data/frontend/build/precache-manifest.3d1bd8b01752fe34cb52390bc898ad26.js +0 -22
  47. data/frontend/build/service-worker.js +0 -39
  48. data/frontend/build/static/css/main.04fc5f62.chunk.css +0 -2
  49. data/frontend/build/static/css/main.04fc5f62.chunk.css.map +0 -1
  50. data/frontend/build/static/js/2.8729aa12.chunk.js +0 -2
  51. data/frontend/build/static/js/2.8729aa12.chunk.js.map +0 -1
  52. data/frontend/build/static/js/main.8f1e7b9c.chunk.js +0 -2
  53. data/frontend/build/static/js/main.8f1e7b9c.chunk.js.map +0 -1
  54. data/frontend/build/static/js/runtime~main.ea5ad98e.js +0 -2
  55. data/frontend/build/static/js/runtime~main.ea5ad98e.js.map +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31daefc694eec828325485d392252b528bd8fb0e854fefc5ba87b2237962f3b8
4
- data.tar.gz: 8c55a9aefff97bc4619833b17550973cb579680abae5964ec64a35d20ee91e33
3
+ metadata.gz: d5c97af4888389d99d26caaed6a9816a77eff42311ff77bafec0602ec3937828
4
+ data.tar.gz: 74d29ce78b5e1198b8a0457ec43175c2cc95bab08aeba54a1646e3d7a4afd766
5
5
  SHA512:
6
- metadata.gz: 66b49f85d2d9d36d5d6928ada5f87d5b1757224e38b50480c371c30b9de384f55bea1dc0dd65908cc3f4801c107cef260dff4aef6856c352b6a543d2ffed8015
7
- data.tar.gz: 13f018cab8b3452c38d97ccee1950228ef8f77e4cfa80292f90ec582d5adb71640f94ebefc3b0112f2a4426e31b1050255de2a724cf63a7dc94ec6ceadbdc5f0
6
+ metadata.gz: 496aaa24ade23507f00b0f435635cc99f140f7bb4ea2e63e7bfac1386cfa2fef5bcc3283dc40a31511becf229eb113c0cd19013763a04a0f84643e0d30480524
7
+ data.tar.gz: 22b45e507dba3428b8ef88013c47df36e80acff2389ac28aaf59f4b629e32076a0219cc407630bdb448218ffe46f9cc6cc9bd993157ec7f7116b755e2b43f3e8
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:
@@ -101,13 +105,8 @@ And if you modify settings values in test example you can reset to defaults with
101
105
 
102
106
  ## Development
103
107
 
104
- Required development dependencies:
105
- * [Node.js](https://nodejs.org/) - JavaScript runtime
106
- * [Yarn](https://yarnpkg.com/) - package manager
107
-
108
108
  Optional development tools:
109
- * [overmind](https://github.com/DarthSim/overmind) - Process manager for Procfile-based applications and tmux
110
- * [direnv](https://direnv.net/) - Unclutter your .profile
109
+ * [direnv](https://direnv.net/) - Unclutter your .profile
111
110
 
112
111
  Required environment variables:
113
112
  * `RAILS_VERSION`
@@ -122,16 +121,13 @@ Getting started with development:
122
121
  1) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 bundle`
123
122
  2) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails db:create db:migrate`
124
123
  3) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails test`
125
- 4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails frontend:install`
126
- 4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 ./bin/rails app:system_settings:load`
127
- 4) `RAILS_VERSION=5.2.3 SQLITE3_VERSION=1.4.1 overmind start`
128
-
129
124
 
130
125
  ## Build status
131
126
  System Settings is being tested with Rails versions - `5.0`, `5.1`, `5.2`, `6.0`, `rails repo master branch`
132
127
 
133
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)
134
-
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)
135
131
 
136
132
  ## License
137
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,128 +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(only: [])
59
- SystemSettings.instrument("system_settings.persist", items: @items) do |payload|
60
- if settings_table_exists?
61
- SystemSettings::Setting.transaction do
62
- if only.empty?
63
- @items.each { |item| create_or_update_item(item) }
64
- else
65
- only.each do |wanted_name|
66
- item = @items.find { |i| i[:name] == wanted_name } || begin
67
- loaded_names = @items.empty? ? "(none)" : @items.map{ |i| i[:name] }.join("\n")
68
- message = <<~MESSAGE.strip
69
- Couldn't persist system setting #{wanted_name}. There are no items by this name. Could it be a typo?
70
-
71
- Configurator has loaded following items:
72
- #{loaded_names}
73
- MESSAGE
74
- raise(SystemSettings::Errors::NotLoadedError, message)
75
- end
76
- create_or_update_item(item)
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)
77
82
  end
83
+ create_or_update_item(item)
78
84
  end
79
85
  end
80
- payload[:success] = true
81
- else
82
- warn "SystemSettings: Settings table has not been created!"
83
- payload[:success] = false
84
86
  end
87
+ payload[:success] = true
88
+ else
89
+ warn "SystemSettings: Settings table has not been created!"
90
+ payload[:success] = false
85
91
  end
86
92
  end
93
+ end
87
94
 
88
- def purge
89
- SystemSettings.instrument("system_settings.purge") do |payload|
90
- if settings_table_exists?
91
- SystemSettings::Setting.delete_all
92
- payload[:success] = true
93
- else
94
- payload[:success] = false
95
- 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
96
102
  end
97
103
  end
104
+ end
98
105
 
99
- private
106
+ private
100
107
 
101
- def warn(*args)
102
- @kernel_class.warn(*args)
103
- end
108
+ def warn(*args)
109
+ @kernel_class.warn(*args)
110
+ end
104
111
 
105
- def settings_table_exists?
106
- SystemSettings::Setting.table_exists?
107
- end
112
+ def settings_table_exists?
113
+ SystemSettings::Setting.table_exists?
114
+ end
108
115
 
109
- def add(name, class_const, value:, description:)
110
- value = yield(value) if block_given?
111
- value = value.call if value.is_a?(Proc)
112
- @items.push(name: name, class: class_const, value: value, description: description)
113
- end
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
114
121
 
115
- def create_or_update_item(item)
116
- persisted_record = SystemSettings::Setting.find_by(name: item[:name])
117
- if persisted_record
118
- if persisted_record.class == item[:class]
119
- persisted_record.update!(description: item[:description])
120
- else
121
- warn "SystemSettings: Type mismatch detected! Previously #{item[:name]} had type #{persisted_record.class.name} but you are loading #{item[:class].name}"
122
- end
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])
123
127
  else
124
- item[:class].create!(name: item[:name], value: item[:value], description: item[:description])
128
+ warn "SystemSettings: Type mismatch detected! Previously #{item[:name]} had type #{persisted_record.class.name} but you are loading #{item[:class].name}"
125
129
  end
130
+ else
131
+ item[:class].create!(name: item[:name], value: item[:value], description: item[:description])
126
132
  end
127
133
  end
128
134
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SystemSettings::DecimalListSetting < SystemSettings::Setting
4
+ attribute :value, SystemSettings::Type::DecimalList.new(scale: 6)
5
+ validates :value, "system_settings/list_of_decimals": true
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SystemSettings::DecimalSetting < SystemSettings::Setting
4
+ attribute :value, :decimal, scale: 6
5
+ validates :value, numericality: true
6
+ end