memo_wise 0.3.0 → 0.4.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/CHANGELOG.md +8 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +13 -12
- data/README.md +26 -8
- data/lib/memo_wise.rb +49 -15
- data/lib/memo_wise/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 634bee32d07ccd97dc7670c67521a4091ebc0df0deae1479cc054aaa7a246e6c
|
|
4
|
+
data.tar.gz: 59523369b3373389481388962039486b4f0f5cf002d24091ad2244048f100bbc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3896bf8b001ad52afda6b14c5170d902d85a88c9faaa60d6c9097a01045e0ef90a379c130834b2a2fcbec356b51346f975fc96493dcb3d3c04943200eb7274a3
|
|
7
|
+
data.tar.gz: 72718456d986ed21d593a6a99117ee74a0a385f94ba0b1a00fadb38cbad977202cea5d8e32325bdaa2e5eb273808a52ca9d62997cd927a6a98ffd31174bdcc6f
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
(nothing yet!)
|
|
10
10
|
|
|
11
|
+
## [0.4.0] - 2021-04-30
|
|
12
|
+
### Added
|
|
13
|
+
- Documentation of confusing module test behavior
|
|
14
|
+
- Support using MemoWise in classes with keyword arguments in the initializer
|
|
15
|
+
- Support Marshal dump/load of classes using MemoWise
|
|
16
|
+
|
|
11
17
|
## [0.3.0] - 2021-02-11
|
|
12
18
|
### Added
|
|
13
19
|
- Changelog and tags
|
|
@@ -48,7 +54,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
48
54
|
- Panolint
|
|
49
55
|
- Dependabot setup
|
|
50
56
|
|
|
51
|
-
[Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v0.
|
|
57
|
+
[Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v0.4.0...HEAD
|
|
58
|
+
[0.4.0]: https://github.com/panorama-ed/memo_wise/compare/v0.3.0...v0.4.0
|
|
52
59
|
[0.3.0]: https://github.com/panorama-ed/memo_wise/compare/v0.2.0...v0.3.0
|
|
53
60
|
[0.2.0]: https://github.com/panorama-ed/memo_wise/compare/v0.1.2...v0.2.0
|
|
54
61
|
[0.1.2]: https://github.com/panorama-ed/memo_wise/compare/v0.1.1...v0.1.2
|
data/Gemfile
CHANGED
|
@@ -14,7 +14,7 @@ end
|
|
|
14
14
|
# Excluded from CI except on latest MRI Ruby, to reduce compatibility burden
|
|
15
15
|
group :checks do
|
|
16
16
|
gem "codecov"
|
|
17
|
-
gem "panolint", github: "panorama-ed/panolint"
|
|
17
|
+
gem "panolint", github: "panorama-ed/panolint", branch: "main"
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
# Excluded from CI except on latest MRI Ruby, to reduce compatibility burden
|
data/Gemfile.lock
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
GIT
|
|
2
2
|
remote: https://github.com/panorama-ed/panolint.git
|
|
3
|
-
revision:
|
|
3
|
+
revision: e2f76aa2482f02e68826eb8643a41998a09fc7ab
|
|
4
|
+
branch: main
|
|
4
5
|
specs:
|
|
5
|
-
panolint (0.1.
|
|
6
|
+
panolint (0.1.3)
|
|
6
7
|
brakeman (>= 4.8, < 6.0)
|
|
7
8
|
rubocop (>= 0.83, < 2.0)
|
|
8
9
|
rubocop-performance (~> 1.5)
|
|
@@ -13,35 +14,35 @@ GIT
|
|
|
13
14
|
PATH
|
|
14
15
|
remote: .
|
|
15
16
|
specs:
|
|
16
|
-
memo_wise (0.
|
|
17
|
+
memo_wise (0.4.0)
|
|
17
18
|
|
|
18
19
|
GEM
|
|
19
20
|
remote: https://rubygems.org/
|
|
20
21
|
specs:
|
|
21
|
-
activesupport (5.2.
|
|
22
|
+
activesupport (5.2.5)
|
|
22
23
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
23
24
|
i18n (>= 0.7, < 2)
|
|
24
25
|
minitest (~> 5.1)
|
|
25
26
|
tzinfo (~> 1.1)
|
|
26
27
|
ast (2.4.2)
|
|
27
28
|
brakeman (5.0.0)
|
|
28
|
-
codecov (0.
|
|
29
|
+
codecov (0.5.2)
|
|
29
30
|
simplecov (>= 0.15, < 0.22)
|
|
30
31
|
concurrent-ruby (1.1.8)
|
|
31
32
|
diff-lcs (1.4.4)
|
|
32
33
|
docile (1.3.5)
|
|
33
|
-
i18n (1.8.
|
|
34
|
+
i18n (1.8.10)
|
|
34
35
|
concurrent-ruby (~> 1.0)
|
|
35
|
-
minitest (5.14.
|
|
36
|
+
minitest (5.14.4)
|
|
36
37
|
parallel (1.20.1)
|
|
37
|
-
parser (3.0.
|
|
38
|
+
parser (3.0.1.0)
|
|
38
39
|
ast (~> 2.4.1)
|
|
39
40
|
rack (2.2.3)
|
|
40
41
|
rainbow (3.0.0)
|
|
41
42
|
rake (13.0.3)
|
|
42
43
|
redcarpet (3.5.1)
|
|
43
|
-
regexp_parser (2.
|
|
44
|
-
rexml (3.2.
|
|
44
|
+
regexp_parser (2.1.1)
|
|
45
|
+
rexml (3.2.5)
|
|
45
46
|
rspec (3.10.0)
|
|
46
47
|
rspec-core (~> 3.10.0)
|
|
47
48
|
rspec-expectations (~> 3.10.0)
|
|
@@ -55,7 +56,7 @@ GEM
|
|
|
55
56
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
56
57
|
rspec-support (~> 3.10.0)
|
|
57
58
|
rspec-support (3.10.0)
|
|
58
|
-
rubocop (1.
|
|
59
|
+
rubocop (1.12.1)
|
|
59
60
|
parallel (~> 1.10)
|
|
60
61
|
parser (>= 3.0.0.0)
|
|
61
62
|
rainbow (>= 2.2.2, < 4.0)
|
|
@@ -66,7 +67,7 @@ GEM
|
|
|
66
67
|
unicode-display_width (>= 1.4.0, < 3.0)
|
|
67
68
|
rubocop-ast (1.4.1)
|
|
68
69
|
parser (>= 2.7.1.5)
|
|
69
|
-
rubocop-performance (1.
|
|
70
|
+
rubocop-performance (1.10.2)
|
|
70
71
|
rubocop (>= 0.90.0, < 2.0)
|
|
71
72
|
rubocop-ast (>= 0.4.0)
|
|
72
73
|
rubocop-rails (2.9.1)
|
data/README.md
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
[](https://rubygems.org/gems/memo_wise)
|
|
13
13
|
[](https://rubygems.org/gems/memo_wise)
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
## Why `MemoWise`?
|
|
17
16
|
|
|
18
17
|
`MemoWise` is **the wise choice for Ruby memoization**, featuring:
|
|
@@ -85,13 +84,13 @@ run in GitHub Actions and updated in every PR that changes code.
|
|
|
85
84
|
|
|
86
85
|
|Method arguments|**`memo_wise` (0.1.0)**|`memery` (1.3.0)|`memoist`\* (0.16.2)|`memoized`\* (1.0.2)|`memoizer`\* (1.0.3)|
|
|
87
86
|
|--|--|--|--|--|--|
|
|
88
|
-
|`()` (none)|**baseline**|
|
|
89
|
-
|`(a, b)`|**baseline**|1.93x slower|2.20x slower|1.
|
|
90
|
-
|`(a:, b:)`|**baseline**|3.
|
|
91
|
-
|`(a, b:)`|**baseline**|1.
|
|
92
|
-
|`(a, *args)`|**baseline**|1.
|
|
93
|
-
|`(a:, **kwargs)`|**baseline**|3.08x slower|2.
|
|
94
|
-
|`(a, *args, b:, **kwargs)`|**baseline**|1.
|
|
87
|
+
|`()` (none)|**baseline**|13.17x slower|2.85x slower|1.30x slower|3.05x slower|
|
|
88
|
+
|`(a, b)`|**baseline**|1.93x slower|2.20x slower|1.97x slower|1.86x slower|
|
|
89
|
+
|`(a:, b:)`|**baseline**|3.05x slower|2.34x slower|2.27x slower|2.14x slower|
|
|
90
|
+
|`(a, b:)`|**baseline**|1.50x slower|1.63x slower|1.56x slower|1.48x slower|
|
|
91
|
+
|`(a, *args)`|**baseline**|1.91x slower|2.13x slower|1.90x slower|1.88x slower|
|
|
92
|
+
|`(a:, **kwargs)`|**baseline**|3.08x slower|2.37x slower|2.24x slower|2.09x slower|
|
|
93
|
+
|`(a, *args, b:, **kwargs)`|**baseline**|1.72x slower|1.61x slower|1.56x slower|1.67x slower|
|
|
95
94
|
|
|
96
95
|
_\*Indicates a benchmark run on Ruby 2.7.2 because the gem raises errors in Ruby
|
|
97
96
|
3.0.0 due to its incorrect handling of keyword arguments._
|
|
@@ -141,6 +140,25 @@ code examples in our YARD documentation. To run `doctest` locally:
|
|
|
141
140
|
bundle exec yard doctest
|
|
142
141
|
```
|
|
143
142
|
|
|
143
|
+
### A Note on Testing
|
|
144
|
+
|
|
145
|
+
When testing memoized *module* methods, note that some testing setups will
|
|
146
|
+
reuse the same instance (which `include`s/`extend`s/`prepend`s the module)
|
|
147
|
+
across tests, which can result in confusing test failures when this differs from
|
|
148
|
+
how you use the code in production.
|
|
149
|
+
|
|
150
|
+
For example, Rails view helpers are modules that are commonly tested with a
|
|
151
|
+
[shared `view` instance](https://github.com/rails/rails/blob/291a3d2ef29a3842d1156ada7526f4ee60dd2b59/actionview/lib/action_view/test_case.rb#L203-L214). Rails initializes a new view instance for each web request so any view helper
|
|
152
|
+
methods would only be memoized for the duration of that web request, but in
|
|
153
|
+
tests (such as when using
|
|
154
|
+
[`rspec-rails`'s `helper`](https://github.com/rspec/rspec-rails/blob/main/lib/rspec/rails/example/helper_example_group.rb#L22-L27)),
|
|
155
|
+
the memoization may persist across tests. In this case, simply reset the
|
|
156
|
+
memoization between your tests with something like:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
after(:each) { helper.reset_memo_wise }
|
|
160
|
+
```
|
|
161
|
+
|
|
144
162
|
## Logo
|
|
145
163
|
|
|
146
164
|
`MemoWise`'s logo was created by [Luci Cooke](https://www.lucicooke.com/). The
|
data/lib/memo_wise.rb
CHANGED
|
@@ -39,10 +39,40 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
39
39
|
# [Values](https://github.com/tcrayford/Values)
|
|
40
40
|
# [gem](https://rubygems.org/gems/values).
|
|
41
41
|
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
# To support syntax differences with keyword and positional arguments starting
|
|
43
|
+
# with ruby 2.7, we have to set up the initializer with some slightly
|
|
44
|
+
# different syntax for the different versions. This variance in syntax is not
|
|
45
|
+
# included in coverage reports since the branch chosen will never differ
|
|
46
|
+
# within a single ruby version. This means it is impossible for us to get
|
|
47
|
+
# 100% coverage of this line within a single CI run.
|
|
48
|
+
#
|
|
49
|
+
# See
|
|
50
|
+
# [this article](https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/)
|
|
51
|
+
# for more information.
|
|
52
|
+
#
|
|
53
|
+
# :nocov:
|
|
54
|
+
all_args = RUBY_VERSION < "2.7" ? "*" : "..."
|
|
55
|
+
# :nocov:
|
|
56
|
+
class_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
|
|
57
|
+
# On Ruby 2.7 or greater:
|
|
58
|
+
#
|
|
59
|
+
# def initialize(...)
|
|
60
|
+
# MemoWise.create_memo_wise_state!(self)
|
|
61
|
+
# super
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# On Ruby 2.6 or lower:
|
|
65
|
+
#
|
|
66
|
+
# def initialize(*)
|
|
67
|
+
# MemoWise.create_memo_wise_state!(self)
|
|
68
|
+
# super
|
|
69
|
+
# end
|
|
70
|
+
|
|
71
|
+
def initialize(#{all_args})
|
|
72
|
+
MemoWise.create_memo_wise_state!(self)
|
|
73
|
+
super
|
|
74
|
+
end
|
|
75
|
+
END_OF_METHOD
|
|
46
76
|
|
|
47
77
|
# @private
|
|
48
78
|
#
|
|
@@ -182,10 +212,7 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
182
212
|
# @return [Object] the passed-in obj
|
|
183
213
|
def self.create_memo_wise_state!(obj)
|
|
184
214
|
unless obj.instance_variables.include?(:@_memo_wise)
|
|
185
|
-
obj.instance_variable_set(
|
|
186
|
-
:@_memo_wise,
|
|
187
|
-
Hash.new { |h, k| h[k] = {} }
|
|
188
|
-
)
|
|
215
|
+
obj.instance_variable_set(:@_memo_wise, {})
|
|
189
216
|
end
|
|
190
217
|
|
|
191
218
|
obj
|
|
@@ -269,7 +296,7 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
269
296
|
if method.arity.zero?
|
|
270
297
|
klass.module_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
|
|
271
298
|
# def foo
|
|
272
|
-
# @_memo_wise.fetch(:foo
|
|
299
|
+
# @_memo_wise.fetch(:foo) do
|
|
273
300
|
# @_memo_wise[:foo] = _memo_wise_original_foo
|
|
274
301
|
# end
|
|
275
302
|
# end
|
|
@@ -303,14 +330,18 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
303
330
|
# because Ruby always copies argument arrays when splatted.
|
|
304
331
|
klass.module_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
|
|
305
332
|
# def foo(*args, **kwargs)
|
|
306
|
-
# hash = @_memo_wise
|
|
333
|
+
# hash = @_memo_wise.fetch(:foo) do
|
|
334
|
+
# @_memo_wise[:foo] = {}
|
|
335
|
+
# end
|
|
307
336
|
# hash.fetch([args, kwargs].freeze) do
|
|
308
337
|
# hash[[args, kwargs].freeze] = _memo_wise_original_foo(*args, **kwargs)
|
|
309
338
|
# end
|
|
310
339
|
# end
|
|
311
340
|
|
|
312
341
|
def #{method_name}#{args_str}
|
|
313
|
-
hash = @_memo_wise
|
|
342
|
+
hash = @_memo_wise.fetch(:#{method_name}) do
|
|
343
|
+
@_memo_wise[:#{method_name}] = {}
|
|
344
|
+
end
|
|
314
345
|
hash.fetch(#{fetch_key}) do
|
|
315
346
|
hash[#{fetch_key}] = #{original_memo_wised_name}#{args_str}
|
|
316
347
|
end
|
|
@@ -373,7 +404,7 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
373
404
|
# valid for the given method.
|
|
374
405
|
#
|
|
375
406
|
# @param method_name [Symbol]
|
|
376
|
-
# Name of a method previously
|
|
407
|
+
# Name of a method previously set up with `#memo_wise`.
|
|
377
408
|
#
|
|
378
409
|
# @param args [Array]
|
|
379
410
|
# (Optional) If the method takes positional args, these are the values of
|
|
@@ -424,7 +455,10 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
424
455
|
if method(method_name).arity.zero?
|
|
425
456
|
@_memo_wise[method_name] = yield
|
|
426
457
|
else
|
|
427
|
-
@_memo_wise
|
|
458
|
+
hash = @_memo_wise.fetch(method_name) do
|
|
459
|
+
@_memo_wise[method_name] = {}
|
|
460
|
+
end
|
|
461
|
+
hash[fetch_key(method_name, *args, **kwargs)] = yield
|
|
428
462
|
end
|
|
429
463
|
end
|
|
430
464
|
|
|
@@ -449,7 +483,7 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
449
483
|
# - Resets all memoized results of calling *all methods*.
|
|
450
484
|
#
|
|
451
485
|
# @param method_name [Symbol, nil]
|
|
452
|
-
# (Optional) Name of a method previously
|
|
486
|
+
# (Optional) Name of a method previously set up with `#memo_wise`. If not
|
|
453
487
|
# given, will reset *all* memoized results for *all* methods.
|
|
454
488
|
#
|
|
455
489
|
# @param args [Array]
|
|
@@ -521,7 +555,7 @@ module MemoWise # rubocop:disable Metrics/ModuleLength
|
|
|
521
555
|
if args.empty? && kwargs.empty?
|
|
522
556
|
@_memo_wise.delete(method_name)
|
|
523
557
|
else
|
|
524
|
-
@_memo_wise[method_name]
|
|
558
|
+
@_memo_wise[method_name]&.delete(fetch_key(method_name, *args, **kwargs))
|
|
525
559
|
end
|
|
526
560
|
end
|
|
527
561
|
|
data/lib/memo_wise/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: memo_wise
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Panorama Education
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date: 2021-
|
|
14
|
+
date: 2021-04-30 00:00:00.000000000 Z
|
|
15
15
|
dependencies: []
|
|
16
16
|
description:
|
|
17
17
|
email:
|
|
@@ -69,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
69
69
|
- !ruby/object:Gem::Version
|
|
70
70
|
version: '0'
|
|
71
71
|
requirements: []
|
|
72
|
-
rubygems_version: 3.
|
|
72
|
+
rubygems_version: 3.1.4
|
|
73
73
|
signing_key:
|
|
74
74
|
specification_version: 4
|
|
75
75
|
summary: The wise choice for Ruby memoization
|