super_settings 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -1
- data/README.md +12 -0
- data/VERSION +1 -1
- data/lib/super_settings/attributes.rb +2 -2
- data/lib/super_settings/configuration.rb +17 -22
- data/lib/super_settings/context/current.rb +33 -0
- data/lib/super_settings/context.rb +3 -0
- data/lib/super_settings/engine.rb +0 -2
- data/lib/super_settings/history_item.rb +6 -2
- data/lib/super_settings/local_cache.rb +0 -15
- data/lib/super_settings/setting.rb +15 -11
- data/lib/super_settings/storage/active_record_storage/models.rb +28 -0
- data/lib/super_settings/storage/active_record_storage.rb +3 -20
- data/lib/super_settings/storage/http_storage.rb +19 -9
- data/lib/super_settings/storage/redis_storage.rb +15 -3
- data/lib/super_settings/storage/test_storage.rb +18 -6
- data/lib/super_settings/storage.rb +8 -4
- data/lib/super_settings.rb +40 -16
- data/super_settings.gemspec +8 -1
- metadata +12 -7
- /data/{MIT-LICENSE → MIT-LICENSE.txt} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56ed02dddf10d95bcb20863a4c5918c0396ac510de6815d5ebfdc8d4f7de2847
|
4
|
+
data.tar.gz: 0f2f7d2ae0cbf5948b2d1683b374fbc865e7aaa6a87a1f7e30d73870dc2eac42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6972f850704fd153fec84125c801e3c10627a0d4cc2cde1c3f15274d2cef7867239999aba2f95e83bbf452abc5dd6db9a264b322e46d3fb17673d34cbf362db1
|
7
|
+
data.tar.gz: 3889cb5652b9fd01b6e31a512fa9919bab40abad9d4e5367058c045eb406425d988aab2617a2d148a8bf669340d2839c07225a9d3c5e768a02807f191c24ec26
|
data/CHANGELOG.md
CHANGED
@@ -4,7 +4,22 @@ 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
|
-
##
|
7
|
+
## 1.0.2
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Added SuperSetting.rand method that can return a consistent random number inside of a context block.
|
12
|
+
|
13
|
+
### Changed
|
14
|
+
|
15
|
+
- Lazy load non-required classes.
|
16
|
+
|
17
|
+
## 1.0.1
|
18
|
+
|
19
|
+
### Added
|
20
|
+
- Optimize object shapes for the Ruby interpreter by declaring instance variables in constructors.
|
21
|
+
|
22
|
+
## 1.0.0
|
8
23
|
|
9
24
|
### Added
|
10
25
|
- Everything!
|
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
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)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/super_settings.svg)](https://badge.fury.io/rb/super_settings)
|
5
7
|
|
6
8
|
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.
|
7
9
|
|
@@ -101,6 +103,16 @@ SuperSettings.context do
|
|
101
103
|
end
|
102
104
|
```
|
103
105
|
|
106
|
+
You can also use the `SuperSettings.rand` method inside a context block to return a consistent random number. This can be useful for things like feature flags that you want to turn on for only a percentage of requests:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
def enabled?
|
110
|
+
SuperSettings.float("feature_rollout_percent") <= SuperSettings.rand
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
Now the value of `enabled?` will always return the same value inside of a context block. It will still be random if it is enabled for each context block.
|
115
|
+
|
104
116
|
It's a good idea to add a `context` block around your main unit of work:
|
105
117
|
|
106
118
|
- Rack application: add `SuperSettings::Context::RackMiddleware` to your middleware stack
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.2
|
@@ -13,8 +13,8 @@ module SuperSettings
|
|
13
13
|
|
14
14
|
def attributes=(values)
|
15
15
|
values.each do |name, value|
|
16
|
-
if respond_to?("#{name}=", true)
|
17
|
-
send("#{name}=", value)
|
16
|
+
if respond_to?(:"#{name}=", true)
|
17
|
+
send(:"#{name}=", value)
|
18
18
|
else
|
19
19
|
raise UnknownAttributeError.new("unknown attribute #{name.to_s.inspect} for #{self.class}")
|
20
20
|
end
|
@@ -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.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SuperSettings
|
4
|
+
module Context
|
5
|
+
class Current
|
6
|
+
def initialize
|
7
|
+
@context = {}
|
8
|
+
@seed = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def include?(key)
|
12
|
+
@context.include?(key)
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
@context[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def []=(key, value)
|
20
|
+
@context[key] = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete(key)
|
24
|
+
@context.delete(key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def rand(max = nil)
|
28
|
+
@seed ||= Random.new_seed
|
29
|
+
Random.new(@seed).rand(max || 1.0)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -17,8 +17,6 @@ module SuperSettings
|
|
17
17
|
end
|
18
18
|
|
19
19
|
if defined?(Sidekiq.server?) && Sidekiq.server?
|
20
|
-
require_relative "context/sidekiq_middleware"
|
21
|
-
|
22
20
|
Sidekiq.configure_server do |sidekiq_config|
|
23
21
|
sidekiq_config.server_middleware do |chain|
|
24
22
|
chain.prepend(SuperSettings::Context::SidekiqMiddleware)
|
@@ -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
|
@@ -240,21 +240,6 @@ module SuperSettings
|
|
240
240
|
end
|
241
241
|
end
|
242
242
|
|
243
|
-
# Recusive method for creating a nested hash from delimited keys.
|
244
|
-
def set_nested_hash_value(hash, key, value, current_depth, delimiter:, max_depth:)
|
245
|
-
key, sub_key = ((max_depth && current_depth < max_depth) ? [key, nil] : key.split(delimiter, 2))
|
246
|
-
if sub_key
|
247
|
-
sub_hash = hash[key]
|
248
|
-
unless sub_hash.is_a?(Hash)
|
249
|
-
sub_hash = {}
|
250
|
-
hash[key] = sub_hash
|
251
|
-
end
|
252
|
-
set_nested_hash_value(sub_hash, sub_key, value, current_depth + 1, delimiter: delimiter, max_depth: max_depth)
|
253
|
-
else
|
254
|
-
hash[key] = value
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
243
|
# Recursively freeze a hash.
|
259
244
|
def deep_freeze_hash(hash)
|
260
245
|
hash.each_value do |value|
|
@@ -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?(ActiveRecord) && 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
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SuperSettings
|
4
|
+
module Storage
|
5
|
+
class ActiveRecordStorage
|
6
|
+
# Base class that the models extend from.
|
7
|
+
class ApplicationRecord < ActiveRecord::Base
|
8
|
+
self.abstract_class = true
|
9
|
+
end
|
10
|
+
|
11
|
+
class Model < ApplicationRecord
|
12
|
+
self.table_name = "super_settings"
|
13
|
+
|
14
|
+
has_many :history_items, class_name: "SuperSettings::Storage::ActiveRecordStorage::HistoryModel", foreign_key: :key, primary_key: :key
|
15
|
+
end
|
16
|
+
|
17
|
+
class HistoryModel < ApplicationRecord
|
18
|
+
self.table_name = "super_settings_histories"
|
19
|
+
|
20
|
+
# Since these models are created automatically on a callback, ensure that the data will
|
21
|
+
# fit into the database columns since we can't handle any validation errors.
|
22
|
+
before_validation do
|
23
|
+
self.changed_by = changed_by.to_s[0, 150] if changed_by.present?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -10,26 +10,9 @@ module SuperSettings
|
|
10
10
|
# @example
|
11
11
|
# rake app:super_settings:install:migrations
|
12
12
|
class ActiveRecordStorage
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
class Model < ApplicationRecord
|
19
|
-
self.table_name = "super_settings"
|
20
|
-
|
21
|
-
has_many :history_items, class_name: "SuperSettings::Storage::ActiveRecordStorage::HistoryModel", foreign_key: :key, primary_key: :key
|
22
|
-
end
|
23
|
-
|
24
|
-
class HistoryModel < ApplicationRecord
|
25
|
-
self.table_name = "super_settings_histories"
|
26
|
-
|
27
|
-
# Since these models are created automatically on a callback, ensure that the data will
|
28
|
-
# fit into the database columns since we can't handle any validation errors.
|
29
|
-
before_validation do
|
30
|
-
self.changed_by = changed_by.to_s[0, 150] if changed_by.present?
|
31
|
-
end
|
32
|
-
end
|
13
|
+
autoload :ApplicationRecord, File.join(__dir__, "active_record_storage/models")
|
14
|
+
autoload :Model, File.join(__dir__, "active_record_storage/models")
|
15
|
+
autoload :HistoryModel, File.join(__dir__, "active_record_storage/models")
|
33
16
|
|
34
17
|
include Storage
|
35
18
|
|
@@ -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
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "json"
|
4
|
+
require "redis"
|
4
5
|
|
5
6
|
module SuperSettings
|
6
7
|
module Storage
|
@@ -65,6 +66,11 @@ module SuperSettings
|
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
69
|
+
def initialize(*)
|
70
|
+
@deleted = false
|
71
|
+
super
|
72
|
+
end
|
73
|
+
|
68
74
|
def created_at=(val)
|
69
75
|
@created_at = SuperSettings::Coerce.time(val)
|
70
76
|
end
|
@@ -77,7 +83,7 @@ module SuperSettings
|
|
77
83
|
end
|
78
84
|
|
79
85
|
def deleted?
|
80
|
-
|
86
|
+
!!@deleted
|
81
87
|
end
|
82
88
|
|
83
89
|
private
|
@@ -184,6 +190,12 @@ module SuperSettings
|
|
184
190
|
end
|
185
191
|
end
|
186
192
|
|
193
|
+
def initialize(*)
|
194
|
+
@deleted = false
|
195
|
+
@persisted = false
|
196
|
+
super
|
197
|
+
end
|
198
|
+
|
187
199
|
def history(limit: nil, offset: 0)
|
188
200
|
HistoryStorage.find_all_by_key(key: key, limit: limit, offset: offset).collect do |record|
|
189
201
|
HistoryItem.new(key: key, value: record.value, changed_by: record.changed_by, created_at: record.created_at, deleted: record.deleted?)
|
@@ -242,11 +254,11 @@ module SuperSettings
|
|
242
254
|
end
|
243
255
|
|
244
256
|
def deleted?
|
245
|
-
|
257
|
+
!!@deleted
|
246
258
|
end
|
247
259
|
|
248
260
|
def persisted?
|
249
|
-
|
261
|
+
!!@persisted
|
250
262
|
end
|
251
263
|
|
252
264
|
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
|
@@ -4,12 +4,18 @@ 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 :ActiveRecordStorage, File.join(__dir__, "storage/active_record_storage")
|
8
|
+
autoload :HttpStorage, File.join(__dir__, "storage/http_storage")
|
9
|
+
autoload :RedisStorage, File.join(__dir__, "storage/redis_storage")
|
10
|
+
|
7
11
|
class RecordInvalid < StandardError
|
8
12
|
end
|
9
13
|
|
10
14
|
def self.included(base)
|
11
15
|
base.extend(ClassMethods)
|
12
16
|
base.include(Attributes) unless base.instance_methods.include?(:attributes=)
|
17
|
+
|
18
|
+
base.instance_variable_set(:@load_asynchronous, nil)
|
13
19
|
end
|
14
20
|
|
15
21
|
module ClassMethods
|
@@ -76,7 +82,7 @@ module SuperSettings
|
|
76
82
|
#
|
77
83
|
# @return [Boolean]
|
78
84
|
def load_asynchronous?
|
79
|
-
!!(
|
85
|
+
!!(@load_asynchronous.nil? ? default_load_asynchronous? : @load_asynchronous)
|
80
86
|
end
|
81
87
|
|
82
88
|
# Set to true to force loading setting asynchronously in a background thread.
|
@@ -270,10 +276,8 @@ end
|
|
270
276
|
require_relative "storage/http_storage"
|
271
277
|
require_relative "storage/redis_storage"
|
272
278
|
if defined?(ActiveSupport) && ActiveSupport.respond_to?(:on_load)
|
273
|
-
ActiveSupport.on_load(:
|
279
|
+
ActiveSupport.on_load(:active_record_base) do
|
274
280
|
require_relative "storage/active_record_storage"
|
275
281
|
end
|
276
|
-
elsif defined?(ActiveRecord::Base)
|
277
|
-
require_relative "storage/active_record_storage"
|
278
282
|
end
|
279
283
|
# :nocov:
|
data/lib/super_settings.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# These classes are required for the gem to function.
|
4
|
+
require_relative "super_settings/attributes"
|
4
5
|
require_relative "super_settings/coerce"
|
5
6
|
require_relative "super_settings/configuration"
|
6
7
|
require_relative "super_settings/context"
|
7
|
-
require_relative "super_settings/context/rack_middleware"
|
8
8
|
require_relative "super_settings/local_cache"
|
9
|
-
require_relative "super_settings/rest_api"
|
10
|
-
require_relative "super_settings/rack_application"
|
11
|
-
require_relative "super_settings/controller_actions"
|
12
|
-
require_relative "super_settings/attributes"
|
13
9
|
require_relative "super_settings/setting"
|
14
|
-
require_relative "super_settings/history_item"
|
15
10
|
require_relative "super_settings/storage"
|
16
|
-
require_relative "super_settings/version"
|
17
|
-
|
18
|
-
if defined?(Rails::Engine)
|
19
|
-
require_relative "super_settings/engine"
|
20
|
-
end
|
21
11
|
|
22
12
|
# This is the main interface to the access settings.
|
23
13
|
module SuperSettings
|
14
|
+
# These classes are autoloaded when they are needed.
|
15
|
+
autoload :Application, "super_settings/application"
|
16
|
+
autoload :RestAPI, "super_settings/rest_api"
|
17
|
+
autoload :RackApplication, "super_settings/rack_application"
|
18
|
+
autoload :ControllerActions, "super_settings/controller_actions"
|
19
|
+
autoload :HistoryItem, "super_settings/history_item"
|
20
|
+
autoload :VERSION, "super_settings/version"
|
21
|
+
|
24
22
|
DEFAULT_REFRESH_INTERVAL = 5.0
|
25
23
|
|
24
|
+
@local_cache = LocalCache.new(refresh_interval: DEFAULT_REFRESH_INTERVAL)
|
25
|
+
|
26
26
|
class << self
|
27
27
|
# Get a setting value cast to a string.
|
28
28
|
#
|
@@ -103,6 +103,28 @@ module SuperSettings
|
|
103
103
|
Array(val).collect { |v| v&.to_s }
|
104
104
|
end
|
105
105
|
|
106
|
+
# Get a pseudo random number. This method works the same as Kernel.rand. However, if you are
|
107
|
+
# inside a context block, then the random number will be the same each time you call this method.
|
108
|
+
# This is useful when you need to generate a random number for a setting that you want to remain
|
109
|
+
# constant for the duration of the block.
|
110
|
+
#
|
111
|
+
# So, for instance, if you are generating a random number to determine if a feature is enabled,
|
112
|
+
# you can use this method to ensure that the feature is either always enabled or always disabled
|
113
|
+
# for the duration of the block.
|
114
|
+
#
|
115
|
+
# @param max [Integer, Float, Range] the maximum value or range to use for the random number
|
116
|
+
# @return [Integer, Float] the random number. It will be an integer if max is an integer, otherwise
|
117
|
+
# it will be a float.
|
118
|
+
def rand(max = nil)
|
119
|
+
max ||= 1.0
|
120
|
+
context = current_context
|
121
|
+
if context
|
122
|
+
context.rand(max)
|
123
|
+
else
|
124
|
+
Random.rand(max)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
106
128
|
# Create settings and update the local cache with the values. If a block is given, then the
|
107
129
|
# value will be reverted at the end of the block. This method can be used in tests when you
|
108
130
|
# need to inject a specific value into your settings.
|
@@ -146,7 +168,7 @@ module SuperSettings
|
|
146
168
|
def context(&block)
|
147
169
|
reset_context = Thread.current[:super_settings_context].nil?
|
148
170
|
begin
|
149
|
-
Thread.current[:super_settings_context] ||=
|
171
|
+
Thread.current[:super_settings_context] ||= Context::Current.new
|
150
172
|
yield
|
151
173
|
ensure
|
152
174
|
Thread.current[:super_settings_context] = nil if reset_context
|
@@ -219,9 +241,7 @@ module SuperSettings
|
|
219
241
|
|
220
242
|
private
|
221
243
|
|
222
|
-
|
223
|
-
@local_cache ||= LocalCache.new(refresh_interval: DEFAULT_REFRESH_INTERVAL)
|
224
|
-
end
|
244
|
+
attr_reader :local_cache
|
225
245
|
|
226
246
|
def current_context
|
227
247
|
Thread.current[:super_settings_context]
|
@@ -241,3 +261,7 @@ module SuperSettings
|
|
241
261
|
end
|
242
262
|
end
|
243
263
|
end
|
264
|
+
|
265
|
+
if defined?(Rails::Engine)
|
266
|
+
require_relative "super_settings/engine"
|
267
|
+
end
|
data/super_settings.gemspec
CHANGED
@@ -4,10 +4,17 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.authors = ["Brian Durand"]
|
5
5
|
spec.email = ["bbdurand@gmail.com"]
|
6
6
|
|
7
|
-
spec.summary = "Fast access runtime settings for
|
7
|
+
spec.summary = "Fast access runtime settings for applications with an included UI and API for administration."
|
8
|
+
|
8
9
|
spec.homepage = "https://github.com/bdurand/super_settings"
|
9
10
|
spec.license = "MIT"
|
10
11
|
|
12
|
+
spec.metadata = {
|
13
|
+
"homepage_uri" => spec.homepage,
|
14
|
+
"source_code_uri" => spec.homepage,
|
15
|
+
"changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md"
|
16
|
+
}
|
17
|
+
|
11
18
|
# Specify which files should be added to the gem when it is released.
|
12
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
13
20
|
ignore_files = %w[
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -32,7 +32,7 @@ extensions: []
|
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
34
|
- CHANGELOG.md
|
35
|
-
- MIT-LICENSE
|
35
|
+
- MIT-LICENSE.txt
|
36
36
|
- README.md
|
37
37
|
- VERSION
|
38
38
|
- app/helpers/super_settings/settings_helper.rb
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- lib/super_settings/coerce.rb
|
58
58
|
- lib/super_settings/configuration.rb
|
59
59
|
- lib/super_settings/context.rb
|
60
|
+
- lib/super_settings/context/current.rb
|
60
61
|
- lib/super_settings/context/rack_middleware.rb
|
61
62
|
- lib/super_settings/context/sidekiq_middleware.rb
|
62
63
|
- lib/super_settings/controller_actions.rb
|
@@ -68,6 +69,7 @@ files:
|
|
68
69
|
- lib/super_settings/setting.rb
|
69
70
|
- lib/super_settings/storage.rb
|
70
71
|
- lib/super_settings/storage/active_record_storage.rb
|
72
|
+
- lib/super_settings/storage/active_record_storage/models.rb
|
71
73
|
- lib/super_settings/storage/http_storage.rb
|
72
74
|
- lib/super_settings/storage/redis_storage.rb
|
73
75
|
- lib/super_settings/storage/test_storage.rb
|
@@ -76,7 +78,10 @@ files:
|
|
76
78
|
homepage: https://github.com/bdurand/super_settings
|
77
79
|
licenses:
|
78
80
|
- MIT
|
79
|
-
metadata:
|
81
|
+
metadata:
|
82
|
+
homepage_uri: https://github.com/bdurand/super_settings
|
83
|
+
source_code_uri: https://github.com/bdurand/super_settings
|
84
|
+
changelog_uri: https://github.com/bdurand/super_settings/blob/main/CHANGELOG.md
|
80
85
|
post_install_message:
|
81
86
|
rdoc_options: []
|
82
87
|
require_paths:
|
@@ -92,9 +97,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
97
|
- !ruby/object:Gem::Version
|
93
98
|
version: '0'
|
94
99
|
requirements: []
|
95
|
-
rubygems_version: 3.4.
|
100
|
+
rubygems_version: 3.4.10
|
96
101
|
signing_key:
|
97
102
|
specification_version: 4
|
98
|
-
summary: Fast access runtime settings for
|
99
|
-
|
103
|
+
summary: Fast access runtime settings for applications with an included UI and API
|
104
|
+
for administration.
|
100
105
|
test_files: []
|
File without changes
|