system_settings 0.7.0 → 0.9.2

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 (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