memo_wise 1.0.0 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4c330faa7d0718ac3b4873dae8fb1933949481747f639fd6fe050724a2ce8dd
4
- data.tar.gz: 52777a008d6b5b41a37cec36f1b9fe0198b85df97fb11329d73bac71ad22b600
3
+ metadata.gz: 3b26ef1a44fd13498359282c6d47923ecf90bdfd4e8ac487d389dd1d5c9c5d59
4
+ data.tar.gz: 51d2ddc7b1d0e7d770afcf081f566059e67b07867c10803db693fd2ec848f4d1
5
5
  SHA512:
6
- metadata.gz: 17a0e939940e73826fbca1876317bcd772e1cd07f16383a9d3e9c973c2545b4b8539c42110de98d8a8c8c4c4a4aa6a666b29cc40c6351001b2b9a7c6964918a3
7
- data.tar.gz: fd4a09fe2dab6dbae43fae753c15530982d1cc26c0ef7b47cdff40f0bff603d7c7c9d0c7d0509b7eb98c0e15b2bd2ca7c005900a00d97201e44a9fd49603d4b0
6
+ metadata.gz: ca1c06be2c7d0368e7708349563a0a79f93922d491ffe43448793bd6364938ea063bc3910d67ca7ce04c6cb409d784d23d19d5e97fea6430fcb20ebbb0819ab3
7
+ data.tar.gz: 93fc8811a80bd7f4d88517e0c3cd21f3b6ef29daea6e0578e734abecdc0067f5f9451261f5c47ad80106332075a4072a4a3e7322fe6181f2d61782d63c42caa0
@@ -1,4 +1,4 @@
1
1
  **Before merging:**
2
2
 
3
- - [ ] Copy the latest benchmark results into the `README.md` and update this PR
4
- - [ ] If this change merits an update to `CHANGELOG.md`, add an entry following Keep a Changelog [guidelines](https://keepachangelog.com/en/1.0.0/) with [semantic versioning](https://semver.org/)
3
+ - [ ] Copy the table printed at the end of the latest benchmark results into the `README.md` and update this PR
4
+ - [ ] If this change merits an update to `CHANGELOG.md`, add an entry following Keep a Changelog [guidelines](https://keepachangelog.com/en/1.0.0/) with [semantic versioning](https://semver.org/)
@@ -12,7 +12,7 @@ jobs:
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- ruby: [jruby, 2.4, 2.5, 2.6, 2.7, 3.0]
15
+ ruby: [jruby, 2.4, 2.5, 2.6, 2.7, 3.0, truffleruby-head]
16
16
  runs-on: ubuntu-latest
17
17
  steps:
18
18
  - uses: actions/checkout@v2
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  /.bundle/
2
2
  /benchmarks/.bundle/
3
+ /benchmarks/Gemfile.lock
3
4
  /.yardoc
4
5
  /_yardoc/
5
6
  /coverage/
data/.rubocop.yml CHANGED
@@ -1,2 +1,17 @@
1
1
  inherit_gem:
2
- panolint: rubocop.yml
2
+ panolint: panolint-rubocop.yml
3
+
4
+ Layout/LineLength:
5
+ Max: 120
6
+
7
+ Metrics/ModuleLength:
8
+ Enabled: false
9
+
10
+ Metrics/PerceivedComplexity:
11
+ Enabled: false
12
+
13
+ Style/DocumentDynamicEvalDefinition:
14
+ Enabled: false
15
+
16
+ Style/MultipleComparison:
17
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -6,12 +6,61 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
- (nothing yet!)
9
+
10
+ - Nothing yet!
11
+
12
+ ## [1.4.0] - 2021-12-10
13
+
14
+ ### Fixed
15
+
16
+ - Fix several bugs related to classes inheriting memoized methods
17
+ from multiple modules or a parent class ([#241](https://github.com/panorama-ed/memo_wise/pull/241))
18
+
19
+ ## [1.3.0] - 2021-11-22
20
+
21
+ ### Fixed
22
+
23
+ - Fix thread-safety issue in concurrent calls to zero-arg method in unmemoized
24
+ state which resulted in a `nil` value being accidentally returned in one thread
25
+ - Fix bugs related to child classes inheriting from parent classes that use
26
+ `MemoWise`
27
+
28
+ ## [1.2.0] - 2021-11-10
29
+
30
+ ### Updated
31
+ - Improved performance of all methods by using an outer Array instead of a Hash
32
+ - Improved performance for multi-argument methods and simplify internal data
33
+ structures
34
+
35
+ ### Fixed
36
+ - Removed use of #hash due to potential of hash collisions
37
+ - Updated internal local variable names to avoid name collisions with method
38
+ arguments
39
+
40
+ ### Breaking Changes
41
+ - None
42
+
43
+ ## [1.1.0] - 2021-07-29
44
+ ### Updated
45
+ - Improved performance across the board by:
46
+ - removing `Hash#fetch`
47
+ - using `Array#hash`
48
+ - avoiding multi-layer hash lookups for multi-argument methods
49
+ - optimizing for truthy results
50
+ - Add `dry-core` to benchmarks in README
51
+
52
+ ### Fixed
53
+ - Fixed usage on module singleton classes
54
+ - Fixed usage on module which would be extended by other classes
55
+
56
+ ### Breaking Changes
57
+ - None
10
58
 
11
59
  ## [1.0.0] - 2021-06-24
12
60
  ### Added
13
61
  - Support for `.preset_memo_wise` on class methods
14
62
  - Support for `.reset_memo_wise` on class methods
63
+
15
64
  ### Updated
16
65
  - Improved performance for common cases by reducing array allocations
17
66
 
@@ -61,7 +110,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
61
110
  - Panolint
62
111
  - Dependabot setup
63
112
 
64
- [Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v1.0.0...HEAD
113
+ [Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v1.4.0...HEAD
114
+ [1.4.0]: https://github.com/panorama-ed/memo_wise/compare/v1.3.0...v1.4.0
115
+ [1.3.0]: https://github.com/panorama-ed/memo_wise/compare/v1.2.0...v1.3.0
116
+ [1.2.0]: https://github.com/panorama-ed/memo_wise/compare/v1.1.0...v1.2.0
117
+ [1.1.0]: https://github.com/panorama-ed/memo_wise/compare/v1.0.0...v1.1.0
65
118
  [1.0.0]: https://github.com/panorama-ed/memo_wise/compare/v0.4.0...v1.0.0
66
119
  [0.4.0]: https://github.com/panorama-ed/memo_wise/compare/v0.3.0...v0.4.0
67
120
  [0.3.0]: https://github.com/panorama-ed/memo_wise/compare/v0.2.0...v0.3.0
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  GIT
2
2
  remote: https://github.com/panorama-ed/panolint.git
3
- revision: 6f38f73dafdc25370ecc367dc87d7e6340ae664d
3
+ revision: 5850a218b96da7dd196438fb65d41169cd6747e5
4
4
  branch: main
5
5
  specs:
6
- panolint (0.1.3)
6
+ panolint (0.1.4)
7
7
  brakeman (>= 4.8, < 6.0)
8
8
  rubocop (>= 0.83, < 2.0)
9
9
  rubocop-performance (~> 1.5)
@@ -14,20 +14,21 @@ GIT
14
14
  PATH
15
15
  remote: .
16
16
  specs:
17
- memo_wise (1.0.0)
17
+ memo_wise (1.4.0)
18
18
 
19
19
  GEM
20
20
  remote: https://rubygems.org/
21
21
  specs:
22
- activesupport (5.2.6)
22
+ activesupport (6.1.4.1)
23
23
  concurrent-ruby (~> 1.0, >= 1.0.2)
24
- i18n (>= 0.7, < 2)
25
- minitest (~> 5.1)
26
- tzinfo (~> 1.1)
24
+ i18n (>= 1.6, < 2)
25
+ minitest (>= 5.1)
26
+ tzinfo (~> 2.0)
27
+ zeitwerk (~> 2.3)
27
28
  ansi (1.5.0)
28
29
  ast (2.4.2)
29
- brakeman (5.0.4)
30
- codecov (0.5.2)
30
+ brakeman (5.1.2)
31
+ codecov (0.6.0)
31
32
  simplecov (>= 0.15, < 0.22)
32
33
  concurrent-ruby (1.1.9)
33
34
  diff-lcs (1.4.4)
@@ -36,15 +37,15 @@ GEM
36
37
  ansi
37
38
  rouge
38
39
  slop (~> 3)
39
- i18n (1.8.10)
40
+ i18n (1.8.11)
40
41
  concurrent-ruby (~> 1.0)
41
42
  minitest (5.14.4)
42
- parallel (1.20.1)
43
- parser (3.0.1.1)
43
+ parallel (1.21.0)
44
+ parser (3.0.3.1)
44
45
  ast (~> 2.4.1)
45
46
  rack (2.2.3)
46
47
  rainbow (3.0.0)
47
- rake (13.0.3)
48
+ rake (13.0.6)
48
49
  redcarpet (3.5.1)
49
50
  regexp_parser (2.1.1)
50
51
  rexml (3.2.5)
@@ -62,44 +63,43 @@ GEM
62
63
  diff-lcs (>= 1.2.0, < 2.0)
63
64
  rspec-support (~> 3.10.0)
64
65
  rspec-support (3.10.0)
65
- rubocop (1.12.1)
66
+ rubocop (1.23.0)
66
67
  parallel (~> 1.10)
67
68
  parser (>= 3.0.0.0)
68
69
  rainbow (>= 2.2.2, < 4.0)
69
70
  regexp_parser (>= 1.8, < 3.0)
70
71
  rexml
71
- rubocop-ast (>= 1.2.0, < 2.0)
72
+ rubocop-ast (>= 1.12.0, < 2.0)
72
73
  ruby-progressbar (~> 1.7)
73
74
  unicode-display_width (>= 1.4.0, < 3.0)
74
- rubocop-ast (1.4.1)
75
- parser (>= 2.7.1.5)
76
- rubocop-performance (1.10.2)
77
- rubocop (>= 0.90.0, < 2.0)
75
+ rubocop-ast (1.13.0)
76
+ parser (>= 3.0.1.1)
77
+ rubocop-performance (1.12.0)
78
+ rubocop (>= 1.7.0, < 2.0)
78
79
  rubocop-ast (>= 0.4.0)
79
- rubocop-rails (2.9.1)
80
+ rubocop-rails (2.12.4)
80
81
  activesupport (>= 4.2.0)
81
82
  rack (>= 1.1)
82
- rubocop (>= 0.90.0, < 2.0)
83
- rubocop-rake (0.5.1)
84
- rubocop
85
- rubocop-rspec (2.2.0)
83
+ rubocop (>= 1.7.0, < 2.0)
84
+ rubocop-rake (0.6.0)
86
85
  rubocop (~> 1.0)
87
- rubocop-ast (>= 1.1.0)
86
+ rubocop-rspec (2.6.0)
87
+ rubocop (~> 1.19)
88
88
  ruby-progressbar (1.11.0)
89
89
  simplecov (0.18.5)
90
90
  docile (~> 1.1)
91
91
  simplecov-html (~> 0.11)
92
92
  simplecov-html (0.12.3)
93
93
  slop (3.6.0)
94
- thread_safe (0.3.6)
95
- tzinfo (1.2.9)
96
- thread_safe (~> 0.1)
97
- unicode-display_width (2.0.0)
94
+ tzinfo (2.0.4)
95
+ concurrent-ruby (~> 1.0)
96
+ unicode-display_width (2.1.0)
98
97
  values (1.8.0)
99
98
  yard (0.9.26)
100
99
  yard-doctest (0.1.17)
101
100
  minitest
102
101
  yard
102
+ zeitwerk (2.5.1)
103
103
 
104
104
  PLATFORMS
105
105
  ruby
@@ -117,4 +117,4 @@ DEPENDENCIES
117
117
  yard-doctest (~> 0.1)
118
118
 
119
119
  BUNDLED WITH
120
- 2.2.3
120
+ 2.2.32
data/README.md CHANGED
@@ -20,6 +20,7 @@
20
20
  * Support for [resetting](https://rubydoc.info/github/panorama-ed/memo_wise/MemoWise#reset_memo_wise-instance_method) and [presetting](https://rubydoc.info/github/panorama-ed/memo_wise/MemoWise#preset_memo_wise-instance_method) memoized values
21
21
  * Support for memoization on frozen objects
22
22
  * Support for memoization of class and module methods
23
+ * Support for inheritance of memoized class and instance methods
23
24
  * Full [documentation](https://rubydoc.info/github/panorama-ed/memo_wise/MemoWise) and [test coverage](https://codecov.io/gh/panorama-ed/memo_wise)!
24
25
 
25
26
  ## Installation
@@ -56,6 +57,15 @@ class Example
56
57
  x
57
58
  end
58
59
  memo_wise :slow_value
60
+
61
+ private
62
+
63
+ # maintains privacy of the memoized method
64
+ def private_slow_method(x)
65
+ sleep x
66
+ x
67
+ end
68
+ memo_wise :private_slow_method
59
69
  end
60
70
 
61
71
  ex = Example.new
@@ -102,28 +112,38 @@ For more usage details, see our detailed [documentation](#documentation).
102
112
 
103
113
  ## Benchmarks
104
114
 
105
- Benchmarks measure memoized value retrieval time using
106
- [`benchmark-ips`](https://github.com/evanphx/benchmark-ips). All benchmarks are
107
- run on Ruby 3.0.1, except as indicated below for specific gems. Benchmarks are
108
- run in GitHub Actions and updated in every PR that changes code.
115
+ Benchmarks are run in GitHub Actions, and the tables below are updated with every code change. **Values >1.00x represent how much _slower_ each gem’s memoized value retrieval is than the latest commit of `MemoWise`**, according to [`benchmark-ips`](https://github.com/evanphx/benchmark-ips) (2.9.2).
109
116
 
110
- **Values >1.00x represent how much _slower_ each gem’s memoized value retrieval
111
- is than the latest commit of `memo_wise`.**
117
+ Results using Ruby 3.0.3:
112
118
 
113
- |Method arguments|`memery` (1.4.0)|`memoist`\* (0.16.2)|`memoized`\* (1.0.2)|`memoizer`\* (1.0.3)|
119
+ |Method arguments|`Dry::Core`\* (0.7.1)|`Memery` (1.4.0)|
120
+ |--|--|--|
121
+ |`()` (none)|1.36x|19.42x|
122
+ |`(a)`|2.47x|11.39x|
123
+ |`(a, b)`|0.44x|2.16x|
124
+ |`(a:)`|2.30x|22.89x|
125
+ |`(a:, b:)`|0.47x|4.54x|
126
+ |`(a, b:)`|0.47x|4.33x|
127
+ |`(a, *args)`|0.83x|2.09x|
128
+ |`(a:, **kwargs)`|0.76x|2.85x|
129
+ |`(a, *args, b:, **kwargs)`|0.61x|1.55x|
130
+
131
+ \* `Dry::Core`
132
+ [may cause incorrect behavior caused by hash collisions](https://github.com/dry-rb/dry-core/issues/63).
133
+
134
+ Results using Ruby 2.7.5 (because these gems raise errors in Ruby 3.x):
135
+
136
+ |Method arguments|`DDMemoize` (1.0.0)|`Memoist` (0.16.2)|`Memoized` (1.0.2)|`Memoizer` (1.0.3)|
114
137
  |--|--|--|--|--|
115
- |`()` (none)|13.17x|2.64x|1.46x|3.10x|
116
- |`(a)`|9.76x|15.44x|11.98x|13.12x|
117
- |`(a, b)`|1.98x|2.25x|1.82x|1.98x|
118
- |`(a:)`|17.65x|23.64x|20.69x|21.61x|
119
- |`(a:, b:)`|4.16x|3.94x|3.53x|3.67x|
120
- |`(a, b:)`|3.96x|3.72x|3.27x|3.42x|
121
- |`(a, *args)`|1.93x|2.25x|1.93x|1.95x|
122
- |`(a:, **kwargs)`|3.06x|2.38x|2.10x|2.20x|
123
- |`(a, *args, b:, **kwargs)`|1.52x|1.79x|1.65x|1.65x|
124
-
125
- _\*Indicates a benchmark run on Ruby 2.7.3 because the gem raises errors in Ruby
126
- 3.0.1 due to its incorrect handling of keyword arguments._
138
+ |`()` (none)|36.84x|3.56x|1.68x|4.19x|
139
+ |`(a)`|27.50x|18.85x|13.97x|15.99x|
140
+ |`(a, b)`|3.27x|2.34x|1.85x|2.05x|
141
+ |`(a:)`|37.22x|30.09x|25.57x|27.28x|
142
+ |`(a:, b:)`|5.25x|4.38x|3.80x|4.02x|
143
+ |`(a, b:)`|5.08x|4.15x|3.56x|3.78x|
144
+ |`(a, *args)`|3.17x|2.32x|1.96x|2.01x|
145
+ |`(a:, **kwargs)`|2.87x|2.42x|2.10x|2.21x|
146
+ |`(a, *args, b:, **kwargs)`|2.05x|1.76x|1.63x|1.65x|
127
147
 
128
148
  You can run benchmarks yourself with:
129
149
 
@@ -136,6 +156,24 @@ $ bundle exec ruby benchmarks.rb
136
156
  If your results differ from what's posted here,
137
157
  [let us know](https://github.com/panorama-ed/memo_wise/issues/new)!
138
158
 
159
+ ## Thread Safety
160
+
161
+ MemoWise makes the following **thread safety** guarantees on all supported Ruby
162
+ versions:
163
+
164
+ 1. **Before** a value has been memoized
165
+
166
+ * Contended calls from multiple threads...
167
+ * May each call the original method
168
+ * May return different valid results (when the method is nondeterministic,
169
+ like `rand`)
170
+ * Will memoize exactly one valid return value
171
+
172
+ 2. **After** a value has been memoized
173
+
174
+ * Contended calls from multiple threads...
175
+ * Always return the same memoized value
176
+
139
177
  ## Documentation
140
178
 
141
179
  ### Documentation is Automatically Generated
@@ -185,6 +223,20 @@ memoization between your tests with something like:
185
223
  after(:each) { helper.reset_memo_wise }
186
224
  ```
187
225
 
226
+ ## Further Reading
227
+
228
+ We presented at RubyConf 2021:
229
+
230
+ - Achieving Fast Method Metaprogramming: Lessons from `MemoWise`
231
+ ([slides](https://docs.google.com/presentation/d/1XgERQ0YHplwJKM3wNQwZn584d_9szYZp2WsDEXoY_7Y/edit?usp=sharing) /
232
+ [benchmarks](https://gist.github.com/JacobEvelyn/17b7b000e50151c30eaea928f1fcdc11))
233
+
234
+ And we've written more about `MemoWise` in a series of blog posts:
235
+
236
+ - [Introducing: MemoWise](https://medium.com/building-panorama-education/introducing-memowise-51a5f0523489)
237
+ - [Optimizing MemoWise Performance](https://ja.cob.land/optimizing-memowise-performance)
238
+ - [Esosteric Ruby in MemoWise](https://jemma.dev/blog/esoteric-ruby-in-memowise)
239
+
188
240
  ## Logo
189
241
 
190
242
  `MemoWise`'s logo was created by [Luci Cooke](https://www.lucicooke.com/). The
@@ -214,11 +266,14 @@ Then carry out these steps:
214
266
 
215
267
  1. Update `CHANGELOG.md`:
216
268
  - Add an entry for the upcoming version _x.y.z_
269
+ - Add a link for this version's comparison to the bottom of `CHANGELOG.md`
217
270
  - Move content from _Unreleased_ to the upcoming version _x.y.z_
271
+ - Change _Unreleased_ section to say `- Nothing yet!`
218
272
  - Commit with title `Update CHANGELOG.md for x.y.z`
219
273
 
220
274
  2. Update `lib/memo_wise/version.rb`
221
275
  - Replace with upcoming version _x.y.z_
276
+ - Run `bundle install` to update `Gemfile.lock`
222
277
  - Commit with title `Bump version to x.y.z`
223
278
 
224
279
  3. `bundle exec rake release`
data/benchmarks/Gemfile CHANGED
@@ -2,13 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- ruby ">= 2.7.2"
5
+ ruby ">= 2.7.5"
6
6
 
7
- gem "benchmark-ips", "2.9.1"
7
+ gem "benchmark-ips", "2.9.2"
8
8
 
9
9
  if RUBY_VERSION > "3"
10
+ gem "dry-core", "0.7.1"
10
11
  gem "memery", "1.4.0"
11
12
  else
13
+ gem "ddmemoize", "1.0.0"
12
14
  gem "memoist", "0.16.2"
13
15
  gem "memoized", "1.0.2"
14
16
  gem "memoizer", "1.0.3"