memo_wise 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://img.shields.io/gem/v/memo_wise.svg)](https://rubygems.org/gems/memo_wise)
|
13
13
|
[![Gem Downloads](https://img.shields.io/gem/dt/memo_wise.svg)](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
|