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 +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/.rubocop.yml +1 -1
- data/Gemfile.lock +80 -70
- data/README.md +30 -0
- data/benchmark.rb +26 -0
- data/lib/memery/version.rb +1 -1
- data/lib/memery.rb +30 -6
- data/memery.gemspec +1 -1
- metadata +4 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47e227e027370bf461105392a87a9b241419c634c3cb2f179698a3d7791b85d8
|
4
|
+
data.tar.gz: 9600d9e22380f28b46ca445d235f8bd7e0d788ab26ac6daf9836b3f5de2d8908
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1bcb999f11bf7bcdc1c6f670725b1800314ab73fca49e42dd27b4764998a211576a5ca0326f1e0b0576e563152dc515d8d91ff7e76d193af14867ecd9af2584e
|
7
|
+
data.tar.gz: 3921a52eaa2709ec13872c0c3eb12e0b3d38d9511605a52f34b3bce78de318b1ac2015c56d08c157f2f5b3d157d0802ab52605bb1ccdba9e1ab399b9d64bfd87
|
data/.github/workflows/ci.yml
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,121 +1,131 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
memery (1.
|
4
|
+
memery (1.8.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
activesupport (
|
9
|
+
activesupport (8.0.2.1)
|
10
10
|
base64
|
11
|
+
benchmark (>= 0.3)
|
11
12
|
bigdecimal
|
12
|
-
concurrent-ruby (~> 1.0, >= 1.
|
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
|
-
|
18
|
-
tzinfo (~> 2.0)
|
19
|
-
|
20
|
-
|
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.
|
28
|
+
bigdecimal (3.2.3)
|
25
29
|
coderay (1.1.3)
|
26
|
-
concurrent-ruby (1.3.
|
27
|
-
connection_pool (2.4
|
28
|
-
diff-lcs (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.
|
31
|
-
i18n (1.14.
|
34
|
+
drb (2.2.3)
|
35
|
+
i18n (1.14.7)
|
32
36
|
concurrent-ruby (~> 1.0)
|
33
|
-
json (2.
|
34
|
-
language_server-protocol (3.17.0.
|
35
|
-
|
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.
|
38
|
-
|
39
|
-
|
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
|
-
|
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
|
53
|
+
rack (3.2.1)
|
48
54
|
rainbow (3.1.1)
|
49
|
-
rake (13.
|
50
|
-
regexp_parser (2.
|
51
|
-
|
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.
|
61
|
+
rspec-core (3.13.5)
|
57
62
|
rspec-support (~> 3.13.0)
|
58
|
-
rspec-expectations (3.13.
|
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.
|
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.
|
65
|
-
rubocop (1.
|
69
|
+
rspec-support (3.13.5)
|
70
|
+
rubocop (1.75.8)
|
66
71
|
json (~> 2.3)
|
67
|
-
language_server-protocol (
|
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 (>=
|
72
|
-
|
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, <
|
76
|
-
rubocop-ast (1.
|
77
|
-
parser (>= 3.3.
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
rubocop (~>
|
82
|
-
rubocop-performance (~> 1.
|
83
|
-
rubocop-rails (~> 2.
|
84
|
-
rubocop-rake (~> 0.
|
85
|
-
rubocop-rspec (~>
|
86
|
-
rubocop-sequel (~> 0.
|
87
|
-
rubocop-factory_bot (2.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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.
|
96
|
-
rubocop-ast (>= 1.
|
97
|
-
rubocop-rake (0.
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
rubocop
|
103
|
-
|
104
|
-
|
105
|
-
rubocop (
|
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.
|
114
|
-
simplecov-lcov (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 (
|
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.
|
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 "```"
|
data/lib/memery/version.rb
CHANGED
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, **
|
60
|
-
@_memery_module.define_memoized_method!(self, method_name, **
|
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
|
-
|
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 =
|
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
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.
|
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:
|
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.
|
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
|
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: []
|