super_settings 1.0.2 → 2.0.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +110 -16
- data/VERSION +1 -1
- data/app/helpers/super_settings/settings_helper.rb +13 -3
- data/app/views/layouts/super_settings/settings.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/db/migrate/20210414004553_create_super_settings.rb +1 -7
- data/lib/super_settings/application/api.js +4 -1
- data/lib/super_settings/application/helper.rb +56 -17
- data/lib/super_settings/application/images/arrow-down-short.svg +3 -0
- data/lib/super_settings/application/images/arrow-up-short.svg +3 -0
- data/lib/super_settings/application/images/info-circle.svg +4 -0
- data/lib/super_settings/application/images/pencil-square.svg +4 -0
- data/lib/super_settings/application/images/plus.svg +3 -1
- data/lib/super_settings/application/images/trash3.svg +3 -0
- data/lib/super_settings/application/images/x-circle.svg +4 -0
- data/lib/super_settings/application/index.html.erb +54 -37
- data/lib/super_settings/application/layout.html.erb +5 -2
- data/lib/super_settings/application/layout_styles.css +7 -151
- data/lib/super_settings/application/layout_vars.css.erb +21 -0
- data/lib/super_settings/application/scripts.js +100 -21
- data/lib/super_settings/application/style_vars.css.erb +62 -0
- data/lib/super_settings/application/styles.css +183 -14
- data/lib/super_settings/application.rb +18 -11
- data/lib/super_settings/attributes.rb +1 -8
- data/lib/super_settings/configuration.rb +9 -0
- data/lib/super_settings/controller_actions.rb +2 -2
- data/lib/super_settings/engine.rb +1 -1
- data/lib/super_settings/history_item.rb +1 -1
- data/lib/super_settings/http_client.rb +165 -0
- data/lib/super_settings/rack_application.rb +3 -3
- data/lib/super_settings/rest_api.rb +5 -4
- data/lib/super_settings/setting.rb +13 -2
- data/lib/super_settings/storage/active_record_storage.rb +7 -0
- data/lib/super_settings/storage/history_attributes.rb +31 -0
- data/lib/super_settings/storage/http_storage.rb +60 -184
- data/lib/super_settings/storage/json_storage.rb +201 -0
- data/lib/super_settings/storage/mongodb_storage.rb +238 -0
- data/lib/super_settings/storage/redis_storage.rb +49 -111
- data/lib/super_settings/storage/s3_storage.rb +165 -0
- data/lib/super_settings/storage/storage_attributes.rb +64 -0
- data/lib/super_settings/storage/test_storage.rb +3 -5
- data/lib/super_settings/storage/transaction.rb +67 -0
- data/lib/super_settings/storage.rb +13 -6
- data/lib/super_settings/time_precision.rb +36 -0
- data/lib/super_settings.rb +11 -0
- data/super_settings.gemspec +4 -2
- metadata +22 -9
- data/lib/super_settings/application/images/edit.svg +0 -1
- data/lib/super_settings/application/images/info.svg +0 -1
- data/lib/super_settings/application/images/slash.svg +0 -1
- data/lib/super_settings/application/images/trash.svg +0 -1
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SuperSettings
|
4
|
+
module Storage
|
5
|
+
# Generic class that can be extended to represent a setting in memory.
|
6
|
+
class StorageAttributes
|
7
|
+
include SuperSettings::Storage
|
8
|
+
|
9
|
+
attr_reader :key, :raw_value, :description, :value_type, :updated_at, :created_at
|
10
|
+
|
11
|
+
def initialize(attributes = nil)
|
12
|
+
@key = nil
|
13
|
+
@raw_value = nil
|
14
|
+
@description = nil
|
15
|
+
@value_type = nil
|
16
|
+
@deleted = false
|
17
|
+
@updated_at = nil
|
18
|
+
@created_at = nil
|
19
|
+
@persisted = false
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def key=(value)
|
24
|
+
@key = (Coerce.blank?(value) ? nil : value.to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw_value=(value)
|
28
|
+
@raw_value = (Coerce.blank?(value) ? nil : value.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def value_type=(value)
|
32
|
+
@value_type = (Coerce.blank?(value) ? nil : value.to_s)
|
33
|
+
end
|
34
|
+
|
35
|
+
def description=(value)
|
36
|
+
@description = (Coerce.blank?(value) ? nil : value.to_s)
|
37
|
+
end
|
38
|
+
|
39
|
+
def updated_at=(value)
|
40
|
+
@updated_at = SuperSettings::Coerce.time(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def created_at=(value)
|
44
|
+
@created_at = SuperSettings::Coerce.time(value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def deleted?
|
48
|
+
!!@deleted
|
49
|
+
end
|
50
|
+
|
51
|
+
def deleted=(val)
|
52
|
+
@deleted = !!val
|
53
|
+
end
|
54
|
+
|
55
|
+
def persisted?
|
56
|
+
!!@persisted
|
57
|
+
end
|
58
|
+
|
59
|
+
def persisted=(val)
|
60
|
+
@persisted = !!val
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "json"
|
4
|
-
|
5
3
|
module SuperSettings
|
6
4
|
module Storage
|
7
5
|
# Implementation of the SuperSettings::Storage model for running unit tests.
|
@@ -28,7 +26,7 @@ module SuperSettings
|
|
28
26
|
items
|
29
27
|
end
|
30
28
|
|
31
|
-
def
|
29
|
+
def destroy_all
|
32
30
|
@settings = {}
|
33
31
|
@history = {}
|
34
32
|
end
|
@@ -42,7 +40,7 @@ module SuperSettings
|
|
42
40
|
end
|
43
41
|
|
44
42
|
def updated_since(time)
|
45
|
-
settings.values.select { |attributes| attributes[:updated_at].to_f
|
43
|
+
settings.values.select { |attributes| attributes[:updated_at].to_f > time.to_f }.collect do |attributes|
|
46
44
|
setting = new(attributes)
|
47
45
|
setting.send(:set_persisted!)
|
48
46
|
setting
|
@@ -54,7 +52,7 @@ module SuperSettings
|
|
54
52
|
return nil unless attributes
|
55
53
|
setting = new(attributes)
|
56
54
|
setting.send(:set_persisted!)
|
57
|
-
setting
|
55
|
+
setting unless setting.deleted?
|
58
56
|
end
|
59
57
|
|
60
58
|
def last_updated_at
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SuperSettings
|
4
|
+
module Storage
|
5
|
+
# This module provides support for transactions in storage models that don't natively
|
6
|
+
# support transactions.
|
7
|
+
module Transaction
|
8
|
+
def self.included(base)
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def transaction(&block)
|
14
|
+
if Thread.current[transaction_key]
|
15
|
+
yield Thread.current[transaction_key]
|
16
|
+
else
|
17
|
+
begin
|
18
|
+
changes = []
|
19
|
+
Thread.current[transaction_key] = changes
|
20
|
+
|
21
|
+
yield(changes)
|
22
|
+
|
23
|
+
if save_all(changes) != false
|
24
|
+
changes.each do |object|
|
25
|
+
object.persisted = true if object.respond_to?(:persisted=)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
ensure
|
29
|
+
Thread.current[transaction_key] = nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def save_all(changes)
|
35
|
+
# :nocov:
|
36
|
+
raise NotImplementedError
|
37
|
+
# :nocov:
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def transaction_key
|
43
|
+
"#{name}.transaction"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def persisted=(value)
|
48
|
+
@persisted = Coerce.boolean(value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def persisted?
|
52
|
+
!!@persisted
|
53
|
+
end
|
54
|
+
|
55
|
+
def save!
|
56
|
+
self.updated_at ||= Time.now
|
57
|
+
self.created_at ||= updated_at
|
58
|
+
|
59
|
+
self.class.transaction do |changes|
|
60
|
+
changes << self
|
61
|
+
end
|
62
|
+
|
63
|
+
true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -4,12 +4,15 @@ module SuperSettings
|
|
4
4
|
# Abstraction over how a setting is stored and retrieved from the storage engine. Models
|
5
5
|
# must implement the methods module in this module that raise NotImplementedError.
|
6
6
|
module Storage
|
7
|
+
autoload :StorageAttributes, File.join(__dir__, "storage/storage_attributes")
|
8
|
+
autoload :HistoryAttributes, File.join(__dir__, "storage/history_attributes")
|
9
|
+
autoload :Transaction, File.join(__dir__, "storage/transaction")
|
7
10
|
autoload :ActiveRecordStorage, File.join(__dir__, "storage/active_record_storage")
|
8
11
|
autoload :HttpStorage, File.join(__dir__, "storage/http_storage")
|
9
12
|
autoload :RedisStorage, File.join(__dir__, "storage/redis_storage")
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
autoload :JSONStorage, File.join(__dir__, "storage/json_storage")
|
14
|
+
autoload :S3Storage, File.join(__dir__, "storage/s3_storage")
|
15
|
+
autoload :MongoDBStorage, File.join(__dir__, "storage/mongodb_storage")
|
13
16
|
|
14
17
|
def self.included(base)
|
15
18
|
base.extend(ClassMethods)
|
@@ -88,6 +91,11 @@ module SuperSettings
|
|
88
91
|
# Set to true to force loading setting asynchronously in a background thread.
|
89
92
|
attr_writer :load_asynchronous
|
90
93
|
|
94
|
+
# Implementing classes can override this method to delete all settings. This is used
|
95
|
+
# for testing purposes.
|
96
|
+
def destroy_all
|
97
|
+
end
|
98
|
+
|
91
99
|
protected
|
92
100
|
|
93
101
|
# Implementing classes can override this method to indicate if it is safe to load the
|
@@ -155,6 +163,7 @@ module SuperSettings
|
|
155
163
|
end
|
156
164
|
|
157
165
|
# The description for the setting.
|
166
|
+
#
|
158
167
|
# @return [String]
|
159
168
|
def description
|
160
169
|
# :nocov:
|
@@ -163,7 +172,7 @@ module SuperSettings
|
|
163
172
|
end
|
164
173
|
|
165
174
|
# Set the description for the setting.
|
166
|
-
|
175
|
+
#
|
167
176
|
# @param val [String]
|
168
177
|
# @return [void]
|
169
178
|
def description=(val)
|
@@ -273,8 +282,6 @@ module SuperSettings
|
|
273
282
|
end
|
274
283
|
|
275
284
|
# :nocov:
|
276
|
-
require_relative "storage/http_storage"
|
277
|
-
require_relative "storage/redis_storage"
|
278
285
|
if defined?(ActiveSupport) && ActiveSupport.respond_to?(:on_load)
|
279
286
|
ActiveSupport.on_load(:active_record_base) do
|
280
287
|
require_relative "storage/active_record_storage"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SuperSettings
|
4
|
+
# Helper class for truncating timestamps to a specific precision. This is used by storage engines
|
5
|
+
# to ensure that timestamps are stored and compared with the same precision.
|
6
|
+
class TimePrecision
|
7
|
+
attr_reader :time
|
8
|
+
|
9
|
+
def initialize(time, precision = :microsecond)
|
10
|
+
raise ArgumentError.new("Invalid precision: #{precision}") unless valid_precision?(precision)
|
11
|
+
|
12
|
+
@time = time_with_precision(time.to_f, precision) if time
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_f
|
16
|
+
@time.to_f
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def valid_precision?(precision)
|
22
|
+
[:microsecond, :millisecond].include?(precision)
|
23
|
+
end
|
24
|
+
|
25
|
+
def time_with_precision(timestamp, precision)
|
26
|
+
usec = (timestamp % 1) * 1_000_000.0
|
27
|
+
if precision == :millisecond
|
28
|
+
milliseconds = (usec / 1000.0).round(3).floor
|
29
|
+
Time.at(timestamp.to_i, milliseconds, :millisecond).utc
|
30
|
+
else
|
31
|
+
microseconds = usec.round
|
32
|
+
Time.at(timestamp.to_i, microseconds, :microsecond).utc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/super_settings.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "json"
|
4
|
+
|
3
5
|
# These classes are required for the gem to function.
|
4
6
|
require_relative "super_settings/attributes"
|
5
7
|
require_relative "super_settings/coerce"
|
@@ -8,6 +10,7 @@ require_relative "super_settings/context"
|
|
8
10
|
require_relative "super_settings/local_cache"
|
9
11
|
require_relative "super_settings/setting"
|
10
12
|
require_relative "super_settings/storage"
|
13
|
+
require_relative "super_settings/time_precision"
|
11
14
|
|
12
15
|
# This is the main interface to the access settings.
|
13
16
|
module SuperSettings
|
@@ -17,6 +20,7 @@ module SuperSettings
|
|
17
20
|
autoload :RackApplication, "super_settings/rack_application"
|
18
21
|
autoload :ControllerActions, "super_settings/controller_actions"
|
19
22
|
autoload :HistoryItem, "super_settings/history_item"
|
23
|
+
autoload :HttpClient, "super_settings/http_client"
|
20
24
|
autoload :VERSION, "super_settings/version"
|
21
25
|
|
22
26
|
DEFAULT_REFRESH_INTERVAL = 5.0
|
@@ -221,6 +225,13 @@ module SuperSettings
|
|
221
225
|
end
|
222
226
|
end
|
223
227
|
|
228
|
+
# Return the configuration object.
|
229
|
+
#
|
230
|
+
# @return [SuperSettings::Configuration]
|
231
|
+
def configuration
|
232
|
+
Configuration.instance
|
233
|
+
end
|
234
|
+
|
224
235
|
# Set the number of seconds between checks to synchronize the in memory cache from the database.
|
225
236
|
# This setting aids in performance since it throttles the number of times the database is queried
|
226
237
|
# for changes. However, changes made to the settings in the databae will take up to the number of
|
data/super_settings.gemspec
CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.authors = ["Brian Durand"]
|
5
5
|
spec.email = ["bbdurand@gmail.com"]
|
6
6
|
|
7
|
-
spec.summary = "
|
7
|
+
spec.summary = "SuperSettings provides a scalable framework for managing dynamic runtime application settings with in-memory caching, strong typing, a built-in web UI, and support for multiple storage backends."
|
8
8
|
|
9
9
|
spec.homepage = "https://github.com/bdurand/super_settings"
|
10
10
|
spec.license = "MIT"
|
@@ -23,6 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
Gemfile
|
24
24
|
Gemfile.lock
|
25
25
|
Rakefile
|
26
|
+
docker-compose.yml
|
27
|
+
config.ru
|
26
28
|
assets/
|
27
29
|
bin/
|
28
30
|
gemfiles/
|
@@ -36,5 +38,5 @@ Gem::Specification.new do |spec|
|
|
36
38
|
|
37
39
|
spec.add_development_dependency "bundler"
|
38
40
|
|
39
|
-
spec.required_ruby_version = ">= 2.
|
41
|
+
spec.required_ruby_version = ">= 2.6"
|
40
42
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: super_settings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -43,15 +43,19 @@ files:
|
|
43
43
|
- lib/super_settings/application.rb
|
44
44
|
- lib/super_settings/application/api.js
|
45
45
|
- lib/super_settings/application/helper.rb
|
46
|
-
- lib/super_settings/application/images/
|
47
|
-
- lib/super_settings/application/images/
|
46
|
+
- lib/super_settings/application/images/arrow-down-short.svg
|
47
|
+
- lib/super_settings/application/images/arrow-up-short.svg
|
48
|
+
- lib/super_settings/application/images/info-circle.svg
|
49
|
+
- lib/super_settings/application/images/pencil-square.svg
|
48
50
|
- lib/super_settings/application/images/plus.svg
|
49
|
-
- lib/super_settings/application/images/
|
50
|
-
- lib/super_settings/application/images/
|
51
|
+
- lib/super_settings/application/images/trash3.svg
|
52
|
+
- lib/super_settings/application/images/x-circle.svg
|
51
53
|
- lib/super_settings/application/index.html.erb
|
52
54
|
- lib/super_settings/application/layout.html.erb
|
53
55
|
- lib/super_settings/application/layout_styles.css
|
56
|
+
- lib/super_settings/application/layout_vars.css.erb
|
54
57
|
- lib/super_settings/application/scripts.js
|
58
|
+
- lib/super_settings/application/style_vars.css.erb
|
55
59
|
- lib/super_settings/application/styles.css
|
56
60
|
- lib/super_settings/attributes.rb
|
57
61
|
- lib/super_settings/coerce.rb
|
@@ -63,6 +67,7 @@ files:
|
|
63
67
|
- lib/super_settings/controller_actions.rb
|
64
68
|
- lib/super_settings/engine.rb
|
65
69
|
- lib/super_settings/history_item.rb
|
70
|
+
- lib/super_settings/http_client.rb
|
66
71
|
- lib/super_settings/local_cache.rb
|
67
72
|
- lib/super_settings/rack_application.rb
|
68
73
|
- lib/super_settings/rest_api.rb
|
@@ -70,9 +75,16 @@ files:
|
|
70
75
|
- lib/super_settings/storage.rb
|
71
76
|
- lib/super_settings/storage/active_record_storage.rb
|
72
77
|
- lib/super_settings/storage/active_record_storage/models.rb
|
78
|
+
- lib/super_settings/storage/history_attributes.rb
|
73
79
|
- lib/super_settings/storage/http_storage.rb
|
80
|
+
- lib/super_settings/storage/json_storage.rb
|
81
|
+
- lib/super_settings/storage/mongodb_storage.rb
|
74
82
|
- lib/super_settings/storage/redis_storage.rb
|
83
|
+
- lib/super_settings/storage/s3_storage.rb
|
84
|
+
- lib/super_settings/storage/storage_attributes.rb
|
75
85
|
- lib/super_settings/storage/test_storage.rb
|
86
|
+
- lib/super_settings/storage/transaction.rb
|
87
|
+
- lib/super_settings/time_precision.rb
|
76
88
|
- lib/super_settings/version.rb
|
77
89
|
- super_settings.gemspec
|
78
90
|
homepage: https://github.com/bdurand/super_settings
|
@@ -90,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
90
102
|
requirements:
|
91
103
|
- - ">="
|
92
104
|
- !ruby/object:Gem::Version
|
93
|
-
version: '2.
|
105
|
+
version: '2.6'
|
94
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
107
|
requirements:
|
96
108
|
- - ">="
|
@@ -100,6 +112,7 @@ requirements: []
|
|
100
112
|
rubygems_version: 3.4.10
|
101
113
|
signing_key:
|
102
114
|
specification_version: 4
|
103
|
-
summary:
|
104
|
-
|
115
|
+
summary: SuperSettings provides a scalable framework for managing dynamic runtime
|
116
|
+
application settings with in-memory caching, strong typing, a built-in web UI, and
|
117
|
+
support for multiple storage backends.
|
105
118
|
test_files: []
|
@@ -1 +0,0 @@
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
|
@@ -1 +0,0 @@
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-info"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>
|
@@ -1 +0,0 @@
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-slash"><circle cx="12" cy="12" r="10"></circle><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line></svg>
|
@@ -1 +0,0 @@
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-trash-2"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
|