ttl_memoizeable 0.3.0 → 0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5763160f9370ac1bc7695b8299a6528953e6b90cd30806784b45763be6eae8c
4
- data.tar.gz: 04e05378018dc76ad58718a170d2212f554a8838b53d071ec9ac2943f8a2bdf3
3
+ metadata.gz: c5d04e1b3ea5834552d353149bdecbe3e34e665ff81309cf2ec235c0a1948b0d
4
+ data.tar.gz: 10f4a41c7671cb6ed3b8a82006b9f21610d9e6a74b22a4808e2ae99e60ed9704
5
5
  SHA512:
6
- metadata.gz: 358dde19960ec800c5f58eddbd414a2126a866302c12c350714f355e0f29e049dadd055aa7584ba83e6e89717d5713e1f073718dc17276efb0827238340a89a4
7
- data.tar.gz: 77486fa2db3df97f9c2b68217838ad36ed75c678f8c1e67b781f2618eacaf3253406e8344aba51f973b85afed2ac4bd26c5aec1c48b13839aa53e0957e4b810c
6
+ metadata.gz: 773703b9c7190e19474cef1b049a26ec0458c9a9ab4393e72364b96ec2fb913d3e3efdb19885f02eed2ca1ece6bebb42614b6edf297551d4b36ce48247c9ff6b
7
+ data.tar.gz: 709f01839f542b3c7c82ad828d0ffd5533286840bc0769c2e113be739ab9843a5b737a5ed346b3944722faaea4ebf494dea14401bb1a3cae4f0a78c765555083
data/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
1
  ## [Unreleased]
2
+ ## [0.4.1] - 2026-09-25
3
+ - Calculate TTL using monotonic time, which is much more performant (#16) @kbennoune
4
+ ## [0.4.0] - 2024-09-18
5
+ - Add support for globally disabling TTLMemoizeable (#15) @danielwestendorf
6
+ - Add support for globally resetting all ttls (#13) @danielwestendorf
2
7
  ## [0.3.0] - 2024-01-04
3
8
  - Bug fixes
4
9
  ## [0.2.0] - 2023-11-27
data/Gemfile CHANGED
@@ -7,4 +7,4 @@ gemspec
7
7
 
8
8
  gem "rake"
9
9
  gem "rspec"
10
- gem "standard"
10
+ gem "standard", "1.40.0"
data/README.md CHANGED
@@ -151,7 +151,7 @@ application_config.config # => {...} Redis/JSON.parse will be called
151
151
 
152
152
  ## Testing a TTLMemoized Method
153
153
 
154
- You likely don't want to test the implementation of this library, but the logic of your memoized method. In that case you probably want "fresh" data on every invocation of the method. There are two approaches, depending on your preference of flavor.
154
+ You likely don't want to test the implementation of this library, but the logic of your memoized method. In that case you probably want "fresh" data on every invocation of the method. There are a few approaches, depending on your preference of flavor.
155
155
 
156
156
  1. Use the reset method provided for you. It follows the pattern of `reset_memoized_value_for_#{method_name}`. Note that this will only reset the value for the current thread, and shouldn't be used to try and create consistent data state across processes.
157
157
  ```ruby
@@ -162,7 +162,31 @@ def test_config
162
162
  end
163
163
  ```
164
164
 
165
- 2. Conditionally TTL memoize the method based on test environment or some other condition.
165
+ 2. Disable ttl memoization globally in your tests. This will prevent a memoized value from ever being returned.
166
+
167
+ ```ruby
168
+ TTLMemoizeable.disable!
169
+ ```
170
+
171
+ 3. Reset ttl memoization values before/after your test runs.
172
+
173
+ ```ruby
174
+ # RSpec
175
+ RSpec.configure do |config|
176
+ config.around { TTLMemoizeable.reset!; _1.run; TTLMemoizeable.reset! }
177
+ end
178
+
179
+ # minitest
180
+ def setup
181
+ TTLMemoizeable.reset!
182
+ end
183
+
184
+ def teardown
185
+ TTLMemoizeable.reset!
186
+ end
187
+ ```
188
+
189
+ 4. Conditionally TTL memoize the method based on test environment or some other condition.
166
190
  ```ruby
167
191
  def config
168
192
  JSON.parse($redis.get("some_big_json_string"))
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTLMemoizeable
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.1"
5
5
  end
@@ -8,15 +8,29 @@ require_relative "ttl_memoizeable/version"
8
8
  module TTLMemoizeable
9
9
  TTLMemoizationError = Class.new(StandardError)
10
10
  SetupMutex = Mutex.new
11
+ EXPIRED_MONOTONIC_TIME = -365.0 * 24 * 60 * 60 # one year before the monotonic clock origin
12
+
13
+ @ttl_index = 0
14
+ @disabled = false
15
+
16
+ def self.disable!
17
+ @disabled = true
18
+ end
19
+
20
+ def self.reset!
21
+ @ttl_index += 1
22
+ end
11
23
 
12
24
  def ttl_memoized_method(method_name, ttl: 1000)
13
25
  raise TTLMemoizationError, "Method not defined: #{method_name}" unless method_defined?(method_name) || private_method_defined?(method_name)
14
26
 
15
27
  ivar_name = method_name.to_s.gsub(/\??/, "") # remove trailing question marks
16
28
  time_based_ttl = ttl.is_a?(ActiveSupport::Duration)
17
- expired_ttl = time_based_ttl ? 1.year.ago : 1
29
+ ttl_seconds = ttl.to_f if time_based_ttl
30
+ expired_ttl = time_based_ttl ? EXPIRED_MONOTONIC_TIME : 1
18
31
 
19
32
  ttl_variable_name = :"@_ttl_for_#{ivar_name}"
33
+ ttl_index_variable_name = :"@_ttl_index_for_#{ivar_name}"
20
34
  mutex_variable_name = :"@_mutex_for_#{ivar_name}"
21
35
  value_variable_name = :"@_value_for_#{ivar_name}"
22
36
 
@@ -60,15 +74,20 @@ module TTLMemoizeable
60
74
  end
61
75
 
62
76
  define_method ttl_exceeded_method_name do
77
+ return true if TTLMemoizeable.instance_variable_get(:@disabled)
78
+ return true if TTLMemoizeable.instance_variable_get(:@ttl_index) != instance_variable_get(ttl_index_variable_name)
63
79
  return true unless instance_variable_defined?(value_variable_name)
64
80
 
65
- compared_to = time_based_ttl ? ttl.ago : 0
66
- instance_variable_get(ttl_variable_name) <= compared_to
81
+ if time_based_ttl
82
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - instance_variable_get(ttl_variable_name) >= ttl_seconds
83
+ else
84
+ instance_variable_get(ttl_variable_name) <= 0
85
+ end
67
86
  end
68
87
 
69
88
  define_method extend_ttl_method_name do
70
89
  if time_based_ttl
71
- instance_variable_set(ttl_variable_name, Time.current)
90
+ instance_variable_set(ttl_variable_name, Process.clock_gettime(Process::CLOCK_MONOTONIC))
72
91
  else
73
92
  instance_variable_set(ttl_variable_name, ttl)
74
93
  end
@@ -85,6 +104,9 @@ module TTLMemoizeable
85
104
  if send(ttl_exceeded_method_name)
86
105
  send(extend_ttl_method_name)
87
106
 
107
+ # Synchronize the ttl index to match the module's value
108
+ instance_variable_set(ttl_index_variable_name, TTLMemoizeable.instance_variable_get(:@ttl_index))
109
+
88
110
  # Refresh value from the original method
89
111
  instance_variable_set(value_variable_name, super())
90
112
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ttl_memoizeable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Westendorf
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-01-04 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -61,7 +60,6 @@ licenses:
61
60
  metadata:
62
61
  homepage_uri: https://github.com/huntresslabs/ttl_memoizeable
63
62
  source_code_uri: https://github.com/huntresslabs/ttl_memoizeable
64
- post_install_message:
65
63
  rdoc_options: []
66
64
  require_paths:
67
65
  - lib
@@ -76,8 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
74
  - !ruby/object:Gem::Version
77
75
  version: '0'
78
76
  requirements: []
79
- rubygems_version: 3.4.1
80
- signing_key:
77
+ rubygems_version: 4.0.16
81
78
  specification_version: 4
82
79
  summary: Cross-thread memoization in ruby with eventual consistency.
83
80
  test_files: []