memery 1.6.0 → 1.8.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: 47e227e027370bf461105392a87a9b241419c634c3cb2f179698a3d7791b85d8
4
+ data.tar.gz: 9600d9e22380f28b46ca445d235f8bd7e0d788ab26ac6daf9836b3f5de2d8908
5
5
  SHA512:
6
- metadata.gz: fe66f7ef175fae643de7382ad2b311a546c079f9f105118f2907437a439ccde57b86143b46d063f868805921d72a33eb790625610c43f111268eeb21b8b5821c
7
- data.tar.gz: 28120e605bbf3627d09376f081ba1071745e0d8d0a32ccef9675012c12596baf695aaa37275bcce27bbf6998e4b22b92c0787e2b973decd87f15e201a6fa1294
6
+ metadata.gz: 1bcb999f11bf7bcdc1c6f670725b1800314ab73fca49e42dd27b4764998a211576a5ca0326f1e0b0576e563152dc515d8d91ff7e76d193af14867ecd9af2584e
7
+ data.tar.gz: 3921a52eaa2709ec13872c0c3eb12e0b3d38d9511605a52f34b3bce78de318b1ac2015c56d08c157f2f5b3d157d0802ab52605bb1ccdba9e1ab399b9d64bfd87
@@ -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.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.2
7
7
 
8
8
  Naming/MethodParameterName:
9
9
  AllowedNames: ["x", "y", "z"]
data/Gemfile.lock CHANGED
@@ -1,121 +1,131 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- memery (1.6.0)
4
+ memery (1.8.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- activesupport (7.1.4)
9
+ activesupport (8.0.2.1)
10
10
  base64
11
+ benchmark (>= 0.3)
11
12
  bigdecimal
12
- concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ concurrent-ruby (~> 1.0, >= 1.3.1)
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
- mutex_m
18
- tzinfo (~> 2.0)
19
- ast (2.4.2)
20
- base64 (0.2.0)
19
+ securerandom (>= 0.3)
20
+ tzinfo (~> 2.0, >= 2.0.5)
21
+ uri (>= 0.13.1)
22
+ ast (2.4.3)
23
+ base64 (0.3.0)
24
+ benchmark (0.4.1)
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.2.3)
25
29
  coderay (1.1.3)
26
- concurrent-ruby (1.3.4)
27
- connection_pool (2.4.1)
28
- diff-lcs (1.5.1)
30
+ concurrent-ruby (1.3.5)
31
+ connection_pool (2.5.4)
32
+ diff-lcs (1.6.2)
29
33
  docile (1.4.1)
30
- drb (2.2.1)
31
- i18n (1.14.5)
34
+ drb (2.2.3)
35
+ i18n (1.14.7)
32
36
  concurrent-ruby (~> 1.0)
33
- json (2.7.2)
34
- language_server-protocol (3.17.0.3)
35
- memory_profiler (1.0.2)
37
+ json (2.13.2)
38
+ language_server-protocol (3.17.0.5)
39
+ lint_roller (1.1.0)
40
+ logger (1.7.0)
41
+ memory_profiler (1.1.0)
36
42
  method_source (1.1.0)
37
- minitest (5.25.1)
38
- mutex_m (0.2.0)
39
- parallel (1.26.3)
40
- parser (3.3.5.0)
43
+ minitest (5.25.5)
44
+ parallel (1.27.0)
45
+ parser (3.3.9.0)
41
46
  ast (~> 2.4.1)
42
47
  racc
43
- pry (0.14.2)
48
+ prism (1.4.0)
49
+ pry (0.15.2)
44
50
  coderay (~> 1.1)
45
51
  method_source (~> 1.0)
46
52
  racc (1.8.1)
47
- rack (3.1.7)
53
+ rack (3.2.1)
48
54
  rainbow (3.1.1)
49
- rake (13.2.1)
50
- regexp_parser (2.9.2)
51
- rexml (3.3.7)
52
- rspec (3.13.0)
55
+ rake (13.3.0)
56
+ regexp_parser (2.11.2)
57
+ rspec (3.13.1)
53
58
  rspec-core (~> 3.13.0)
54
59
  rspec-expectations (~> 3.13.0)
55
60
  rspec-mocks (~> 3.13.0)
56
- rspec-core (3.13.1)
61
+ rspec-core (3.13.5)
57
62
  rspec-support (~> 3.13.0)
58
- rspec-expectations (3.13.3)
63
+ rspec-expectations (3.13.5)
59
64
  diff-lcs (>= 1.2.0, < 2.0)
60
65
  rspec-support (~> 3.13.0)
61
- rspec-mocks (3.13.1)
66
+ rspec-mocks (3.13.5)
62
67
  diff-lcs (>= 1.2.0, < 2.0)
63
68
  rspec-support (~> 3.13.0)
64
- rspec-support (3.13.1)
65
- rubocop (1.63.5)
69
+ rspec-support (3.13.5)
70
+ rubocop (1.75.8)
66
71
  json (~> 2.3)
67
- language_server-protocol (>= 3.17.0)
72
+ language_server-protocol (~> 3.17.0.2)
73
+ lint_roller (~> 1.1.0)
68
74
  parallel (~> 1.10)
69
75
  parser (>= 3.3.0.2)
70
76
  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)
77
+ regexp_parser (>= 2.9.3, < 3.0)
78
+ rubocop-ast (>= 1.44.0, < 2.0)
74
79
  ruby-progressbar (~> 1.7)
75
- unicode-display_width (>= 2.4.0, < 3.0)
76
- rubocop-ast (1.32.3)
77
- 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)
84
- rubocop-rake (~> 0.6.0)
85
- rubocop-rspec (~> 2.29.0)
86
- rubocop-sequel (~> 0.3.3)
87
- rubocop-factory_bot (2.26.1)
88
- rubocop (~> 1.61)
89
- rubocop-performance (1.21.1)
90
- rubocop (>= 1.48.1, < 2.0)
91
- rubocop-ast (>= 1.31.1, < 2.0)
92
- rubocop-rails (2.24.1)
80
+ unicode-display_width (>= 2.4.0, < 4.0)
81
+ rubocop-ast (1.46.0)
82
+ parser (>= 3.3.7.2)
83
+ prism (~> 1.4)
84
+ rubocop-config-umbrellio (1.75.0.104)
85
+ rubocop (~> 1.75.0)
86
+ rubocop-factory_bot (~> 2.27.0)
87
+ rubocop-performance (~> 1.25.0)
88
+ rubocop-rails (~> 2.32.0)
89
+ rubocop-rake (~> 0.7.0)
90
+ rubocop-rspec (~> 3.6.0)
91
+ rubocop-sequel (~> 0.4.0)
92
+ rubocop-factory_bot (2.27.1)
93
+ lint_roller (~> 1.1)
94
+ rubocop (~> 1.72, >= 1.72.1)
95
+ rubocop-performance (1.25.0)
96
+ lint_roller (~> 1.1)
97
+ rubocop (>= 1.75.0, < 2.0)
98
+ rubocop-ast (>= 1.38.0, < 2.0)
99
+ rubocop-rails (2.32.0)
93
100
  activesupport (>= 4.2.0)
101
+ lint_roller (~> 1.1)
94
102
  rack (>= 1.1)
95
- rubocop (>= 1.33.0, < 2.0)
96
- rubocop-ast (>= 1.31.1, < 2.0)
97
- rubocop-rake (0.6.0)
98
- 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)
105
- rubocop (~> 1.61)
106
- rubocop-sequel (0.3.4)
107
- rubocop (~> 1.0)
103
+ rubocop (>= 1.75.0, < 2.0)
104
+ rubocop-ast (>= 1.44.0, < 2.0)
105
+ rubocop-rake (0.7.1)
106
+ lint_roller (~> 1.1)
107
+ rubocop (>= 1.72.1)
108
+ rubocop-rspec (3.6.0)
109
+ lint_roller (~> 1.1)
110
+ rubocop (~> 1.72, >= 1.72.1)
111
+ rubocop-sequel (0.4.1)
112
+ lint_roller (~> 1.1)
113
+ rubocop (>= 1.72.1, < 2)
108
114
  ruby-progressbar (1.13.0)
115
+ securerandom (0.4.1)
109
116
  simplecov (0.22.0)
110
117
  docile (~> 1.1)
111
118
  simplecov-html (~> 0.11)
112
119
  simplecov_json_formatter (~> 0.1)
113
- simplecov-html (0.13.1)
114
- simplecov-lcov (0.8.0)
120
+ simplecov-html (0.13.2)
121
+ simplecov-lcov (0.9.0)
115
122
  simplecov_json_formatter (0.1.4)
116
123
  tzinfo (2.0.6)
117
124
  concurrent-ruby (~> 1.0)
118
- unicode-display_width (2.5.0)
125
+ unicode-display_width (3.1.5)
126
+ unicode-emoji (~> 4.0, >= 4.0.4)
127
+ unicode-emoji (4.0.4)
128
+ uri (1.0.3)
119
129
 
120
130
  PLATFORMS
121
131
  ruby
@@ -134,4 +144,4 @@ DEPENDENCIES
134
144
  simplecov-lcov
135
145
 
136
146
  BUNDLED WITH
137
- 2.4.22
147
+ 2.7.1
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.8.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)
@@ -34,6 +38,10 @@ module Memery
34
38
 
35
39
  module ClassMethods
36
40
  def memoize(*method_names, condition: nil, ttl: nil)
41
+ if method_names.empty?
42
+ @_memery_memoize_next_method = { condition: condition, ttl: ttl }
43
+ return
44
+ end
37
45
  prepend_memery_module!
38
46
  method_names.each do |method_name|
39
47
  define_memoized_method!(method_name, condition: condition, ttl: ttl)
@@ -48,6 +56,15 @@ module Memery
48
56
  @_memery_module.private_method_defined?(method_name)
49
57
  end
50
58
 
59
+ def method_added(name)
60
+ super
61
+
62
+ return unless @_memery_memoize_next_method
63
+
64
+ memoize(name, **@_memery_memoize_next_method)
65
+ @_memery_memoize_next_method = nil
66
+ end
67
+
51
68
  private
52
69
 
53
70
  def prepend_memery_module!
@@ -56,8 +73,8 @@ module Memery
56
73
  prepend(@_memery_module)
57
74
  end
58
75
 
59
- def define_memoized_method!(method_name, **options)
60
- @_memery_module.define_memoized_method!(self, method_name, **options)
76
+ def define_memoized_method!(method_name, **)
77
+ @_memery_module.define_memoized_method!(self, method_name, **)
61
78
  end
62
79
 
63
80
  module MemoizationModule
@@ -68,11 +85,12 @@ module Memery
68
85
  end
69
86
  end
70
87
 
88
+ # rubocop:disable Metrics/MethodLength
71
89
  def define_memoized_method!(klass, method_name, condition: nil, ttl: nil)
72
- method_key = "#{method_name}_#{object_id}"
73
-
90
+ # Include a suffix in the method key to differentiate between methods of the same name
91
+ # being memoized throughout a class inheritance hierarchy
92
+ method_key = "#{method_name}_#{klass.name || object_id}"
74
93
  original_visibility = method_visibility(klass, method_name)
75
- original_arity = klass.instance_method(method_name).arity
76
94
 
77
95
  define_method(method_name) do |*args, &block|
78
96
  if block || (condition && !instance_exec(&condition))
@@ -80,7 +98,12 @@ module Memery
80
98
  end
81
99
 
82
100
  cache_store = (@_memery_memoized_values ||= {})
83
- cache_key = original_arity.zero? ? method_key : [method_key, *args].hash
101
+ cache_key = if args.empty?
102
+ method_key
103
+ else
104
+ key_parts = [method_key, *args]
105
+ Memery.use_hashed_arguments ? key_parts.hash : key_parts
106
+ end
84
107
  cache = cache_store[cache_key]
85
108
 
86
109
  return cache.result if cache&.fresh?(ttl)
@@ -95,6 +118,7 @@ module Memery
95
118
  ruby2_keywords(method_name)
96
119
  send(original_visibility, method_name)
97
120
  end
121
+ # rubocop:enable Metrics/MethodLength
98
122
 
99
123
  private
100
124
 
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.2.0"
9
9
 
10
10
  spec.name = "memery"
11
11
  spec.version = Memery::VERSION
metadata CHANGED
@@ -1,14 +1,13 @@
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.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuri Smirnov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-09-12 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: Memery is a gem for memoization.
14
13
  email:
@@ -35,7 +34,6 @@ homepage: https://github.com/tycooon/memery
35
34
  licenses:
36
35
  - MIT
37
36
  metadata: {}
38
- post_install_message:
39
37
  rdoc_options: []
40
38
  require_paths:
41
39
  - lib
@@ -43,15 +41,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
43
41
  requirements:
44
42
  - - ">="
45
43
  - !ruby/object:Gem::Version
46
- version: 2.7.0
44
+ version: 3.2.0
47
45
  required_rubygems_version: !ruby/object:Gem::Requirement
48
46
  requirements:
49
47
  - - ">="
50
48
  - !ruby/object:Gem::Version
51
49
  version: '0'
52
50
  requirements: []
53
- rubygems_version: 3.1.6
54
- signing_key:
51
+ rubygems_version: 3.7.1
55
52
  specification_version: 4
56
53
  summary: A gem for memoization.
57
54
  test_files: []