memery 1.6.0 → 1.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2fee1d8473d6873f228f16f5f9a0b3dce5f3e54350101b69be7d2842a2d4fc1f
4
- data.tar.gz: 24eb3da54355028d92664c734a2c28ea5a52462351b6a598c6acd80a5b3cca7c
3
+ metadata.gz: 56c60aff8199aebc5f2b15e9b777937eea73a7246c61b265c2f6ee980b6dbcd1
4
+ data.tar.gz: f16d9b904ded0d29ca13a7a3690f07e4ecec2cb681e56fce6c390db75a20e4cc
5
5
  SHA512:
6
- metadata.gz: fe66f7ef175fae643de7382ad2b311a546c079f9f105118f2907437a439ccde57b86143b46d063f868805921d72a33eb790625610c43f111268eeb21b8b5821c
7
- data.tar.gz: 28120e605bbf3627d09376f081ba1071745e0d8d0a32ccef9675012c12596baf695aaa37275bcce27bbf6998e4b22b92c0787e2b973decd87f15e201a6fa1294
6
+ metadata.gz: 55a891049c8df688bad894e69ece34b11e4319ce1e00c63a081b01df728918661ff1bc7148f0278c20f1c5fa150eca036fcb3b3f7a35b13c859a7552e5f2d39f
7
+ data.tar.gz: 491214a08cf1286d6dc908f8972c02c9273b5b8e571cc894e377ab425a965fe0997a5053cd6ab3faae240af0a78159e2cc3418d08b74d8639e2f133d6f54dc27
@@ -12,7 +12,7 @@ jobs:
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- ruby: ["2.7", "3.0", "3.1", "3.2", "3.3"]
15
+ ruby: ["3.0", "3.1", "3.2", "3.3", "3.4"]
16
16
 
17
17
  name: ${{ matrix.ruby }}
18
18
 
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ inherit_gem:
3
3
 
4
4
  AllCops:
5
5
  DisplayCopNames: true
6
- TargetRubyVersion: 2.7
6
+ TargetRubyVersion: 3.0
7
7
 
8
8
  Naming/MethodParameterName:
9
9
  AllowedNames: ["x", "y", "z"]
data/Gemfile.lock CHANGED
@@ -1,111 +1,109 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- memery (1.6.0)
4
+ memery (1.7.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- activesupport (7.1.4)
9
+ activesupport (7.1.5.1)
10
10
  base64
11
+ benchmark (>= 0.3)
11
12
  bigdecimal
12
13
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
14
  connection_pool (>= 2.2.5)
14
15
  drb
15
16
  i18n (>= 1.6, < 2)
17
+ logger (>= 1.4.2)
16
18
  minitest (>= 5.1)
17
19
  mutex_m
20
+ securerandom (>= 0.3)
18
21
  tzinfo (~> 2.0)
19
22
  ast (2.4.2)
20
23
  base64 (0.2.0)
24
+ benchmark (0.4.0)
21
25
  benchmark-ips (2.14.0)
22
26
  benchmark-memory (0.2.0)
23
27
  memory_profiler (~> 1)
24
- bigdecimal (3.1.8)
28
+ bigdecimal (3.1.9)
25
29
  coderay (1.1.3)
26
30
  concurrent-ruby (1.3.4)
27
31
  connection_pool (2.4.1)
28
32
  diff-lcs (1.5.1)
29
33
  docile (1.4.1)
30
34
  drb (2.2.1)
31
- i18n (1.14.5)
35
+ i18n (1.14.6)
32
36
  concurrent-ruby (~> 1.0)
33
- json (2.7.2)
37
+ json (2.9.1)
34
38
  language_server-protocol (3.17.0.3)
39
+ logger (1.6.4)
35
40
  memory_profiler (1.0.2)
36
41
  method_source (1.1.0)
37
- minitest (5.25.1)
38
- mutex_m (0.2.0)
42
+ minitest (5.25.4)
43
+ mutex_m (0.3.0)
39
44
  parallel (1.26.3)
40
- parser (3.3.5.0)
45
+ parser (3.3.6.0)
41
46
  ast (~> 2.4.1)
42
47
  racc
43
- pry (0.14.2)
48
+ pry (0.15.2)
44
49
  coderay (~> 1.1)
45
50
  method_source (~> 1.0)
46
51
  racc (1.8.1)
47
- rack (3.1.7)
52
+ rack (3.1.8)
48
53
  rainbow (3.1.1)
49
54
  rake (13.2.1)
50
- regexp_parser (2.9.2)
51
- rexml (3.3.7)
55
+ regexp_parser (2.10.0)
52
56
  rspec (3.13.0)
53
57
  rspec-core (~> 3.13.0)
54
58
  rspec-expectations (~> 3.13.0)
55
59
  rspec-mocks (~> 3.13.0)
56
- rspec-core (3.13.1)
60
+ rspec-core (3.13.2)
57
61
  rspec-support (~> 3.13.0)
58
62
  rspec-expectations (3.13.3)
59
63
  diff-lcs (>= 1.2.0, < 2.0)
60
64
  rspec-support (~> 3.13.0)
61
- rspec-mocks (3.13.1)
65
+ rspec-mocks (3.13.2)
62
66
  diff-lcs (>= 1.2.0, < 2.0)
63
67
  rspec-support (~> 3.13.0)
64
- rspec-support (3.13.1)
65
- rubocop (1.63.5)
68
+ rspec-support (3.13.2)
69
+ rubocop (1.69.2)
66
70
  json (~> 2.3)
67
71
  language_server-protocol (>= 3.17.0)
68
72
  parallel (~> 1.10)
69
73
  parser (>= 3.3.0.2)
70
74
  rainbow (>= 2.2.2, < 4.0)
71
- regexp_parser (>= 1.8, < 3.0)
72
- rexml (>= 3.2.5, < 4.0)
73
- rubocop-ast (>= 1.31.1, < 2.0)
75
+ regexp_parser (>= 2.9.3, < 3.0)
76
+ rubocop-ast (>= 1.36.2, < 2.0)
74
77
  ruby-progressbar (~> 1.7)
75
- unicode-display_width (>= 2.4.0, < 3.0)
76
- rubocop-ast (1.32.3)
78
+ unicode-display_width (>= 2.4.0, < 4.0)
79
+ rubocop-ast (1.37.0)
77
80
  parser (>= 3.3.1.0)
78
- rubocop-capybara (2.21.0)
79
- rubocop (~> 1.41)
80
- rubocop-config-umbrellio (1.63.0.93)
81
- rubocop (~> 1.63.0)
82
- rubocop-performance (~> 1.21.0)
83
- rubocop-rails (~> 2.24.0)
81
+ rubocop-config-umbrellio (1.69.0.101)
82
+ rubocop (~> 1.69.0)
83
+ rubocop-factory_bot (~> 2.26.0)
84
+ rubocop-performance (~> 1.23.0)
85
+ rubocop-rails (~> 2.28.0)
84
86
  rubocop-rake (~> 0.6.0)
85
- rubocop-rspec (~> 2.29.0)
86
- rubocop-sequel (~> 0.3.3)
87
+ rubocop-rspec (~> 3.3.0)
88
+ rubocop-sequel (~> 0.3.0)
87
89
  rubocop-factory_bot (2.26.1)
88
90
  rubocop (~> 1.61)
89
- rubocop-performance (1.21.1)
91
+ rubocop-performance (1.23.1)
90
92
  rubocop (>= 1.48.1, < 2.0)
91
93
  rubocop-ast (>= 1.31.1, < 2.0)
92
- rubocop-rails (2.24.1)
94
+ rubocop-rails (2.28.0)
93
95
  activesupport (>= 4.2.0)
94
96
  rack (>= 1.1)
95
- rubocop (>= 1.33.0, < 2.0)
97
+ rubocop (>= 1.52.0, < 2.0)
96
98
  rubocop-ast (>= 1.31.1, < 2.0)
97
99
  rubocop-rake (0.6.0)
98
100
  rubocop (~> 1.0)
99
- rubocop-rspec (2.29.2)
100
- rubocop (~> 1.40)
101
- rubocop-capybara (~> 2.17)
102
- rubocop-factory_bot (~> 2.22)
103
- rubocop-rspec_rails (~> 2.28)
104
- rubocop-rspec_rails (2.29.1)
101
+ rubocop-rspec (3.3.0)
105
102
  rubocop (~> 1.61)
106
- rubocop-sequel (0.3.4)
103
+ rubocop-sequel (0.3.8)
107
104
  rubocop (~> 1.0)
108
105
  ruby-progressbar (1.13.0)
106
+ securerandom (0.3.2)
109
107
  simplecov (0.22.0)
110
108
  docile (~> 1.1)
111
109
  simplecov-html (~> 0.11)
@@ -115,7 +113,9 @@ GEM
115
113
  simplecov_json_formatter (0.1.4)
116
114
  tzinfo (2.0.6)
117
115
  concurrent-ruby (~> 1.0)
118
- unicode-display_width (2.5.0)
116
+ unicode-display_width (3.1.3)
117
+ unicode-emoji (~> 4.0, >= 4.0.4)
118
+ unicode-emoji (4.0.4)
119
119
 
120
120
  PLATFORMS
121
121
  ruby
@@ -134,4 +134,4 @@ DEPENDENCIES
134
134
  simplecov-lcov
135
135
 
136
136
  BUNDLED WITH
137
- 2.4.22
137
+ 2.5.23
data/README.md CHANGED
@@ -190,6 +190,36 @@ a.memoized?(:call) # => true
190
190
  a.memoized?(:execute) # => false
191
191
  ```
192
192
 
193
+ ### Marshal-compatible Memoization
194
+
195
+ In order for objects to be marshaled and loaded in a different Ruby process,
196
+ hashed arguments must be disabled in order for memoized values to be retained.
197
+ Note that this can have a performance impact if the memoized method contains
198
+ arguments.
199
+
200
+ ```ruby
201
+ Memery.use_hashed_arguments = false
202
+
203
+ class A
204
+ include Memery
205
+
206
+ memoize def call
207
+ puts "calculating"
208
+ 42
209
+ end
210
+ end
211
+
212
+ a = A.new
213
+ a.call
214
+
215
+ Marshal.dump(a)
216
+ # => "\x04\bo:\x06A\x06:\x1D@_memery_memoized_values{\x06:\tcallS:3Memery::ClassMethods::MemoizationModule::Cache\a:\vresulti/:\ttimef\x14663237.14822323"
217
+
218
+ # ...in another Ruby process:
219
+ a = Marshal.load("\x04\bo:\x06A\x06:\x1D@_memery_memoized_values{\x06:\tcallS:3Memery::ClassMethods::MemoizationModule::Cache\a:\vresulti/:\ttimef\x14663237.14822323")
220
+ a.call # => 42
221
+ ```
222
+
193
223
  ## Differences from Other Gems
194
224
 
195
225
  Memery is similar to [Memoist](https://github.com/matthewrudy/memoist), but it doesn't override methods. Instead, it uses Ruby 2's `Module.prepend` feature. This approach is cleaner, allowing you to inspect the original method body with `method(:x).super_method.source`, and it ensures that subclasses' methods function properly. If you redefine a memoized method in a subclass, it won't be memoized by default. You can memoize it normally without needing an awkward `identifier: ` argument, and it will just work:
data/benchmark.rb CHANGED
@@ -32,6 +32,10 @@ class Foo
32
32
  memoize def find_new(char)
33
33
  base_find(char)
34
34
  end
35
+
36
+ memoize def find_optional(*)
37
+ base_find("z")
38
+ end
35
39
  end
36
40
  end
37
41
 
@@ -43,6 +47,10 @@ def test_with_args
43
47
  Foo.find_new("d")
44
48
  end
45
49
 
50
+ def test_empty_args
51
+ Foo.find_optional
52
+ end
53
+
46
54
  Benchmark.ips do |x|
47
55
  x.report("test_no_args") { test_no_args }
48
56
  end
@@ -51,6 +59,14 @@ Benchmark.memory do |x|
51
59
  x.report("test_no_args") { 100.times { test_no_args } }
52
60
  end
53
61
 
62
+ Benchmark.ips do |x|
63
+ x.report("test_empty_args") { test_empty_args }
64
+ end
65
+
66
+ Benchmark.memory do |x|
67
+ x.report("test_empty_args") { 100.times { test_empty_args } }
68
+ end
69
+
54
70
  Benchmark.ips do |x|
55
71
  x.report("test_with_args") { test_with_args }
56
72
  end
@@ -59,4 +75,14 @@ Benchmark.memory do |x|
59
75
  x.report("test_with_args") { 100.times { test_with_args } }
60
76
  end
61
77
 
78
+ Memery.use_hashed_arguments = false
79
+ Benchmark.ips do |x|
80
+ x.report("test_with_args_no_hash") { test_with_args }
81
+ end
82
+
83
+ Benchmark.memory do |x|
84
+ x.report("test_with_args_no_hash") { 100.times { test_with_args } }
85
+ end
86
+ Memery.use_hashed_arguments = true
87
+
62
88
  puts "```"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Memery
4
- VERSION = "1.6.0"
4
+ VERSION = "1.7.0"
5
5
  end
data/lib/memery.rb CHANGED
@@ -4,11 +4,15 @@ require "memery/version"
4
4
 
5
5
  module Memery
6
6
  class << self
7
+ attr_accessor :use_hashed_arguments
8
+
7
9
  def monotonic_clock
8
10
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
9
11
  end
10
12
  end
11
13
 
14
+ @use_hashed_arguments = true
15
+
12
16
  OUR_BLOCK = lambda do
13
17
  extend(ClassMethods)
14
18
  include(InstanceMethods)
@@ -68,11 +72,12 @@ module Memery
68
72
  end
69
73
  end
70
74
 
75
+ # rubocop:disable Metrics/MethodLength
71
76
  def define_memoized_method!(klass, method_name, condition: nil, ttl: nil)
72
- method_key = "#{method_name}_#{object_id}"
73
-
77
+ # Include a suffix in the method key to differentiate between methods of the same name
78
+ # being memoized throughout a class inheritance hierarchy
79
+ method_key = "#{method_name}_#{klass.name || object_id}"
74
80
  original_visibility = method_visibility(klass, method_name)
75
- original_arity = klass.instance_method(method_name).arity
76
81
 
77
82
  define_method(method_name) do |*args, &block|
78
83
  if block || (condition && !instance_exec(&condition))
@@ -80,7 +85,12 @@ module Memery
80
85
  end
81
86
 
82
87
  cache_store = (@_memery_memoized_values ||= {})
83
- cache_key = original_arity.zero? ? method_key : [method_key, *args].hash
88
+ cache_key = if args.empty?
89
+ method_key
90
+ else
91
+ key_parts = [method_key, *args]
92
+ Memery.use_hashed_arguments ? key_parts.hash : key_parts
93
+ end
84
94
  cache = cache_store[cache_key]
85
95
 
86
96
  return cache.result if cache&.fresh?(ttl)
@@ -95,6 +105,7 @@ module Memery
95
105
  ruby2_keywords(method_name)
96
106
  send(original_visibility, method_name)
97
107
  end
108
+ # rubocop:enable Metrics/MethodLength
98
109
 
99
110
  private
100
111
 
data/memery.gemspec CHANGED
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "memery/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.required_ruby_version = ">= 2.7.0"
8
+ spec.required_ruby_version = ">= 3.0.0"
9
9
 
10
10
  spec.name = "memery"
11
11
  spec.version = Memery::VERSION
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memery
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuri Smirnov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-12 00:00:00.000000000 Z
11
+ date: 2025-03-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Memery is a gem for memoization.
14
14
  email:
@@ -43,14 +43,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 2.7.0
46
+ version: 3.0.0
47
47
  required_rubygems_version: !ruby/object:Gem::Requirement
48
48
  requirements:
49
49
  - - ">="
50
50
  - !ruby/object:Gem::Version
51
51
  version: '0'
52
52
  requirements: []
53
- rubygems_version: 3.1.6
53
+ rubygems_version: 3.5.23
54
54
  signing_key:
55
55
  specification_version: 4
56
56
  summary: A gem for memoization.