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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b4e4df83235545b59d31ec20206e265ab19bbe0d4a21de81405bdc7fab892c6
4
- data.tar.gz: 8de1f0d4f30714f93f11e1c5b7f004232793676877f2f0396d3fe757cbd2629e
3
+ metadata.gz: 56ed02dddf10d95bcb20863a4c5918c0396ac510de6815d5ebfdc8d4f7de2847
4
+ data.tar.gz: 0f2f7d2ae0cbf5948b2d1683b374fbc865e7aaa6a87a1f7e30d73870dc2eac42
5
5
  SHA512:
6
- metadata.gz: e7d3fa4f5025a6c541fab3f61d906bf1be43e1378c3c88c27d33e726ff18fd3f5d3d3a73c43b11f43945fcc5677eb23ac34fc8f52d66582d755c4a44247454df
7
- data.tar.gz: 7b0915ea64422d358d5d93a299c75ee63c620b1d2a476dd15f379c0129ccf67d3760536aaf16798094c1f8c8afa99594b5ace27126d18eaafde004fb30556e44
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
- ## [1.0.0]
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.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 defined?(@superclass) && @superclass.is_a?(String)
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 defined?(@changed_by_block) && @changed_by_block
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
- if defined?(@storage) && @storage
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
@@ -2,5 +2,8 @@
2
2
 
3
3
  module SuperSettings
4
4
  module Context
5
+ autoload :Current, File.join(__dir__, "context/current")
6
+ autoload :RackMiddleware, File.join(__dir__, "context/rack_middleware")
7
+ autoload :SidekiqMiddleware, File.join(__dir__, "context/sidekiq_middleware")
5
8
  end
6
9
  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
- # Stupid strict mode...
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 defined?(@storage)
49
- @storage
50
- elsif defined?(::SuperSettings::Storage::ActiveRecordStorage)
51
- ::SuperSettings::Storage::ActiveRecordStorage
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
- raise ArgumentError.new("No storage class defined for #{name}")
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
- # Base class that the models extend from.
14
- class ApplicationRecord < ActiveRecord::Base
15
- self.abstract_class = true
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
- !!(defined?(@deleted) && @deleted)
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
- def headers
79
- @headers ||= {}
80
- end
86
+ attr_reader :headers
81
87
 
82
- def query_params
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
- !!(defined?(@deleted) && @deleted)
261
+ !!@deleted
252
262
  end
253
263
 
254
264
  def persisted?
255
- !!(defined?(@persisted) && @persisted)
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
- !!(defined?(@deleted) && @deleted)
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
- !!(defined?(@deleted) && @deleted)
257
+ !!@deleted
246
258
  end
247
259
 
248
260
  def persisted?
249
- !!(defined?(@persisted) && @persisted)
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
- def settings
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
- !!(defined?(@deleted) && @deleted)
136
+ !!@deleted
125
137
  end
126
138
 
127
139
  def persisted?
128
- !!(defined?(@persisted) && @persisted)
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
- !!((defined?(@load_asynchronous) && !@load_asynchronous.nil?) ? @load_asynchronous : default_load_asynchronous?)
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(:active_record) do
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:
@@ -1,28 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "super_settings/application"
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
- def local_cache
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
@@ -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 a Rails application with an included UI and API for administration."
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.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: 2023-09-30 00:00:00.000000000 Z
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.12
100
+ rubygems_version: 3.4.10
96
101
  signing_key:
97
102
  specification_version: 4
98
- summary: Fast access runtime settings for a Rails application with an included UI
99
- and API for administration.
103
+ summary: Fast access runtime settings for applications with an included UI and API
104
+ for administration.
100
105
  test_files: []
File without changes