super_settings 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +1 -0
- data/VERSION +1 -1
- data/lib/super_settings/configuration.rb +17 -22
- data/lib/super_settings/history_item.rb +6 -2
- data/lib/super_settings/setting.rb +15 -11
- data/lib/super_settings/storage/http_storage.rb +19 -9
- data/lib/super_settings/storage/redis_storage.rb +14 -3
- data/lib/super_settings/storage/test_storage.rb +18 -6
- data/lib/super_settings/storage.rb +3 -1
- data/lib/super_settings.rb +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f58b7aa08a4a6082168ff9fa1487f79ff84bf9374b9463d9ba3ebe4e188b6a47
|
4
|
+
data.tar.gz: b4bf73f87885acacc091e3f455a8a33a8b0baa770dd00db42a1fac6b468e5427
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 973a1ac38488a2cdc4d4cc639f9057d8a1cfd24e216cd7b8cfe4b034af5085b3e0245999b918f3aac7a95416d47fcba46f099d8312afaa2406f63bd5a17f1d25
|
7
|
+
data.tar.gz: e1922327a1c8965dd72d8b11826f398b7dd0cd4f3a3f27be7cc3aa5a81f44da925a159ae2321a122267a9605dd7fbb5fa6af909d4daeeae3cf371087b4df7a7f
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [1.0.1]
|
8
|
+
|
9
|
+
### Added
|
10
|
+
- Optimize object shapes for the Ruby interpreter by declaring instance variables in constructors.
|
11
|
+
|
7
12
|
## [1.0.0]
|
8
13
|
|
9
14
|
### Added
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# SuperSettings
|
2
2
|
|
3
3
|
[![Continuous Integration](https://github.com/bdurand/super_settings/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/bdurand/super_settings/actions/workflows/continuous_integration.yml)
|
4
|
+
[![Regression Test](https://github.com/bdurand/super_settings/actions/workflows/regression_test.yml/badge.svg)](https://github.com/bdurand/super_settings/actions/workflows/regression_test.yml)
|
4
5
|
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
|
5
6
|
|
6
7
|
This gem provides a framework for maintaining runtime application settings. Settings are persisted in a database but cached in memory for quick, efficient access. The settings are designed so they can be updated dynamically without requiring code deployment or restarting processes. The code scales very well and can easily handle very high throughput environments.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.1
|
@@ -22,8 +22,14 @@ module SuperSettings
|
|
22
22
|
# since it will be compatible with class reloading in a development environment.
|
23
23
|
attr_writer :superclass
|
24
24
|
|
25
|
+
def initialize
|
26
|
+
@superclass = nil
|
27
|
+
@web_ui_enabled = true
|
28
|
+
@changed_by_block = nil
|
29
|
+
end
|
30
|
+
|
25
31
|
def superclass
|
26
|
-
if
|
32
|
+
if @superclass.is_a?(String)
|
27
33
|
@superclass.constantize
|
28
34
|
else
|
29
35
|
@superclass
|
@@ -54,9 +60,6 @@ module SuperSettings
|
|
54
60
|
attr_writer :web_ui_enabled
|
55
61
|
|
56
62
|
def web_ui_enabled?
|
57
|
-
unless defined?(@web_ui_enabled)
|
58
|
-
@web_ui_enabled = true
|
59
|
-
end
|
60
63
|
!!@web_ui_enabled
|
61
64
|
end
|
62
65
|
|
@@ -87,7 +90,7 @@ module SuperSettings
|
|
87
90
|
#
|
88
91
|
# @api private
|
89
92
|
def changed_by(controller)
|
90
|
-
if
|
93
|
+
if @changed_by_block
|
91
94
|
controller.instance_eval(&@changed_by_block)
|
92
95
|
end
|
93
96
|
end
|
@@ -101,15 +104,19 @@ module SuperSettings
|
|
101
104
|
|
102
105
|
attr_writer :storage
|
103
106
|
|
107
|
+
attr_reader :after_save_blocks, :changed_by_display
|
108
|
+
|
109
|
+
def initialize
|
110
|
+
@storage = :active_record
|
111
|
+
@after_save_blocks = []
|
112
|
+
@changed_by_display = nil
|
113
|
+
end
|
114
|
+
|
104
115
|
# Specify the storage engine to use for persisting settings. The value can either be specified
|
105
116
|
# as a full class name or an underscored class name for a storage classed defined in the
|
106
117
|
# SuperSettings::Storage namespace. The default storage engine is +SuperSettings::Storage::ActiveRecord+.
|
107
118
|
def storage
|
108
|
-
|
109
|
-
@storage
|
110
|
-
else
|
111
|
-
:active_record
|
112
|
-
end
|
119
|
+
@storage || :active_record
|
113
120
|
end
|
114
121
|
|
115
122
|
# @return [Class]
|
@@ -135,12 +142,6 @@ module SuperSettings
|
|
135
142
|
after_save_blocks << block
|
136
143
|
end
|
137
144
|
|
138
|
-
# @return [Array<Proc>] The after_save block
|
139
|
-
# @api private
|
140
|
-
def after_save_blocks
|
141
|
-
@after_save_blocks ||= []
|
142
|
-
end
|
143
|
-
|
144
145
|
# Define how the changed_by attibute on the setting history will be displayed. The block
|
145
146
|
# will be called with the changed_by attribute and should return a string to display.
|
146
147
|
# The block will not be called if the changed_by attribute is nil.
|
@@ -153,12 +154,6 @@ module SuperSettings
|
|
153
154
|
def define_changed_by_display(&block)
|
154
155
|
@changed_by_display = block
|
155
156
|
end
|
156
|
-
|
157
|
-
# @return [Proc, nil] The block to call to display the changed_by attribute in setting history
|
158
|
-
# @api private
|
159
|
-
def changed_by_display
|
160
|
-
@changed_by_display if defined?(@changed_by_display)
|
161
|
-
end
|
162
157
|
end
|
163
158
|
|
164
159
|
# Return the model specific configuration object.
|
@@ -9,9 +9,13 @@ module SuperSettings
|
|
9
9
|
attr_accessor :key, :value, :changed_by, :created_at
|
10
10
|
attr_writer :deleted
|
11
11
|
|
12
|
+
def initialize(*)
|
13
|
+
@deleted = false
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
12
17
|
def deleted?
|
13
|
-
|
14
|
-
!!(defined?(@deleted) && @deleted)
|
18
|
+
!!@deleted
|
15
19
|
end
|
16
20
|
|
17
21
|
# The display value for the changed_by attribute. This method can be overridden
|
@@ -22,6 +22,9 @@ module SuperSettings
|
|
22
22
|
|
23
23
|
ARRAY_DELIMITER = /[\n\r]+/.freeze
|
24
24
|
|
25
|
+
NOT_SET = Object.new.freeze
|
26
|
+
private_constant :NOT_SET
|
27
|
+
|
25
28
|
# Exception raised if you try to save with invalid data.
|
26
29
|
class InvalidRecordError < StandardError
|
27
30
|
end
|
@@ -33,6 +36,9 @@ module SuperSettings
|
|
33
36
|
# and is cleared after the record is saved.
|
34
37
|
attr_accessor :changed_by
|
35
38
|
|
39
|
+
@storage = NOT_SET
|
40
|
+
@after_save_blocks = []
|
41
|
+
|
36
42
|
class << self
|
37
43
|
# Set a cache to use for caching values. This feature is optional. The cache must respond
|
38
44
|
# to +delete(key)+ and +fetch(key, &block)+. If you are running in a Rails environment,
|
@@ -42,15 +48,19 @@ module SuperSettings
|
|
42
48
|
# Set the storage class to use for persisting data.
|
43
49
|
attr_writer :storage
|
44
50
|
|
51
|
+
attr_reader :after_save_blocks
|
52
|
+
|
45
53
|
# @return [Class] The storage class to use for persisting data.
|
46
54
|
# @api private
|
47
55
|
def storage
|
48
|
-
if
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
if @storage == NOT_SET
|
57
|
+
if defined?(::SuperSettings::Storage::ActiveRecordStorage)
|
58
|
+
::SuperSettings::Storage::ActiveRecordStorage
|
59
|
+
else
|
60
|
+
raise ArgumentError.new("No storage class defined for #{name}")
|
61
|
+
end
|
52
62
|
else
|
53
|
-
|
63
|
+
@storage
|
54
64
|
end
|
55
65
|
end
|
56
66
|
|
@@ -63,12 +73,6 @@ module SuperSettings
|
|
63
73
|
after_save_blocks << block
|
64
74
|
end
|
65
75
|
|
66
|
-
# @return [Array<Proc>] Blocks to be called after a setting is saved.
|
67
|
-
# @api private
|
68
|
-
def after_save_blocks
|
69
|
-
@after_save_blocks ||= []
|
70
|
-
end
|
71
|
-
|
72
76
|
# Create a new setting with the specified attributes.
|
73
77
|
#
|
74
78
|
# @param attributes [Hash] hash of attribute names and values
|
@@ -14,6 +14,9 @@ module SuperSettings
|
|
14
14
|
DEFAULT_HEADERS = {"Accept" => "application/json"}.freeze
|
15
15
|
DEFAULT_TIMEOUT = 5.0
|
16
16
|
|
17
|
+
@headers = {}
|
18
|
+
@query_params = {}
|
19
|
+
|
17
20
|
attr_reader :key, :raw_value, :description, :value_type, :updated_at, :created_at
|
18
21
|
|
19
22
|
class Error < StandardError
|
@@ -36,12 +39,17 @@ module SuperSettings
|
|
36
39
|
|
37
40
|
attr_accessor :key, :value, :changed_by, :deleted
|
38
41
|
|
42
|
+
def initialize(*)
|
43
|
+
@deleted = false
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
39
47
|
def created_at=(val)
|
40
48
|
@created_at = SuperSettings::Coerce.time(val)
|
41
49
|
end
|
42
50
|
|
43
51
|
def deleted?
|
44
|
-
|
52
|
+
!!@deleted
|
45
53
|
end
|
46
54
|
end
|
47
55
|
|
@@ -75,13 +83,9 @@ module SuperSettings
|
|
75
83
|
|
76
84
|
attr_accessor :timeout
|
77
85
|
|
78
|
-
|
79
|
-
@headers ||= {}
|
80
|
-
end
|
86
|
+
attr_reader :headers
|
81
87
|
|
82
|
-
|
83
|
-
@query_params ||= {}
|
84
|
-
end
|
88
|
+
attr_reader :query_params
|
85
89
|
|
86
90
|
protected
|
87
91
|
|
@@ -178,6 +182,12 @@ module SuperSettings
|
|
178
182
|
end
|
179
183
|
end
|
180
184
|
|
185
|
+
def initialize(*)
|
186
|
+
@persisted = false
|
187
|
+
@deleted = false
|
188
|
+
super
|
189
|
+
end
|
190
|
+
|
181
191
|
def save!
|
182
192
|
payload = {key: key}
|
183
193
|
if deleted?
|
@@ -248,11 +258,11 @@ module SuperSettings
|
|
248
258
|
end
|
249
259
|
|
250
260
|
def deleted?
|
251
|
-
|
261
|
+
!!@deleted
|
252
262
|
end
|
253
263
|
|
254
264
|
def persisted?
|
255
|
-
|
265
|
+
!!@persisted
|
256
266
|
end
|
257
267
|
|
258
268
|
private
|
@@ -65,6 +65,11 @@ module SuperSettings
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
def initialize(*)
|
69
|
+
@deleted = false
|
70
|
+
super
|
71
|
+
end
|
72
|
+
|
68
73
|
def created_at=(val)
|
69
74
|
@created_at = SuperSettings::Coerce.time(val)
|
70
75
|
end
|
@@ -77,7 +82,7 @@ module SuperSettings
|
|
77
82
|
end
|
78
83
|
|
79
84
|
def deleted?
|
80
|
-
|
85
|
+
!!@deleted
|
81
86
|
end
|
82
87
|
|
83
88
|
private
|
@@ -184,6 +189,12 @@ module SuperSettings
|
|
184
189
|
end
|
185
190
|
end
|
186
191
|
|
192
|
+
def initialize(*)
|
193
|
+
@deleted = false
|
194
|
+
@persisted = false
|
195
|
+
super
|
196
|
+
end
|
197
|
+
|
187
198
|
def history(limit: nil, offset: 0)
|
188
199
|
HistoryStorage.find_all_by_key(key: key, limit: limit, offset: offset).collect do |record|
|
189
200
|
HistoryItem.new(key: key, value: record.value, changed_by: record.changed_by, created_at: record.created_at, deleted: record.deleted?)
|
@@ -242,11 +253,11 @@ module SuperSettings
|
|
242
253
|
end
|
243
254
|
|
244
255
|
def deleted?
|
245
|
-
|
256
|
+
!!@deleted
|
246
257
|
end
|
247
258
|
|
248
259
|
def persisted?
|
249
|
-
|
260
|
+
!!@persisted
|
250
261
|
end
|
251
262
|
|
252
263
|
private
|
@@ -13,13 +13,13 @@ module SuperSettings
|
|
13
13
|
attr_reader :key, :raw_value, :description, :value_type, :updated_at, :created_at
|
14
14
|
attr_accessor :changed_by
|
15
15
|
|
16
|
+
@settings = {}
|
17
|
+
@history = {}
|
18
|
+
|
16
19
|
class << self
|
17
|
-
|
18
|
-
@settings ||= {}
|
19
|
-
end
|
20
|
+
attr_reader :settings
|
20
21
|
|
21
22
|
def history(key)
|
22
|
-
@history ||= {}
|
23
23
|
items = @history[key]
|
24
24
|
unless items
|
25
25
|
items = []
|
@@ -68,6 +68,18 @@ module SuperSettings
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def initialize(*)
|
72
|
+
@original_key = nil
|
73
|
+
@raw_value = nil
|
74
|
+
@created_at = nil
|
75
|
+
@updated_at = nil
|
76
|
+
@description = nil
|
77
|
+
@value_type = nil
|
78
|
+
@deleted = false
|
79
|
+
@persisted = false
|
80
|
+
super
|
81
|
+
end
|
82
|
+
|
71
83
|
def history(limit: nil, offset: 0)
|
72
84
|
items = self.class.history(key)
|
73
85
|
items[offset, limit || items.length].collect do |attributes|
|
@@ -121,11 +133,11 @@ module SuperSettings
|
|
121
133
|
end
|
122
134
|
|
123
135
|
def deleted?
|
124
|
-
|
136
|
+
!!@deleted
|
125
137
|
end
|
126
138
|
|
127
139
|
def persisted?
|
128
|
-
|
140
|
+
!!@persisted
|
129
141
|
end
|
130
142
|
|
131
143
|
private
|
@@ -10,6 +10,8 @@ module SuperSettings
|
|
10
10
|
def self.included(base)
|
11
11
|
base.extend(ClassMethods)
|
12
12
|
base.include(Attributes) unless base.instance_methods.include?(:attributes=)
|
13
|
+
|
14
|
+
base.instance_variable_set(:@load_asynchronous, nil)
|
13
15
|
end
|
14
16
|
|
15
17
|
module ClassMethods
|
@@ -76,7 +78,7 @@ module SuperSettings
|
|
76
78
|
#
|
77
79
|
# @return [Boolean]
|
78
80
|
def load_asynchronous?
|
79
|
-
!!(
|
81
|
+
!!(@load_asynchronous.nil? ? default_load_asynchronous? : @load_asynchronous)
|
80
82
|
end
|
81
83
|
|
82
84
|
# Set to true to force loading setting asynchronously in a background thread.
|
data/lib/super_settings.rb
CHANGED
@@ -23,6 +23,8 @@ end
|
|
23
23
|
module SuperSettings
|
24
24
|
DEFAULT_REFRESH_INTERVAL = 5.0
|
25
25
|
|
26
|
+
@local_cache = LocalCache.new(refresh_interval: DEFAULT_REFRESH_INTERVAL)
|
27
|
+
|
26
28
|
class << self
|
27
29
|
# Get a setting value cast to a string.
|
28
30
|
#
|
@@ -219,9 +221,7 @@ module SuperSettings
|
|
219
221
|
|
220
222
|
private
|
221
223
|
|
222
|
-
|
223
|
-
@local_cache ||= LocalCache.new(refresh_interval: DEFAULT_REFRESH_INTERVAL)
|
224
|
-
end
|
224
|
+
attr_reader :local_cache
|
225
225
|
|
226
226
|
def current_context
|
227
227
|
Thread.current[:super_settings_context]
|
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: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|