memo_wise 0.4.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 634bee32d07ccd97dc7670c67521a4091ebc0df0deae1479cc054aaa7a246e6c
4
- data.tar.gz: 59523369b3373389481388962039486b4f0f5cf002d24091ad2244048f100bbc
3
+ metadata.gz: 4ff51bfee4fcc634d50588005e79c4a74702fd0d8deb8ab23dd917134cedf42f
4
+ data.tar.gz: 1cb14df9bcef27a3442b48cf1aee370835bbf9070b1f44bb3d8ec8266158bdab
5
5
  SHA512:
6
- metadata.gz: 3896bf8b001ad52afda6b14c5170d902d85a88c9faaa60d6c9097a01045e0ef90a379c130834b2a2fcbec356b51346f975fc96493dcb3d3c04943200eb7274a3
7
- data.tar.gz: 72718456d986ed21d593a6a99117ee74a0a385f94ba0b1a00fadb38cbad977202cea5d8e32325bdaa2e5eb273808a52ca9d62997cd927a6a98ffd31174bdcc6f
6
+ metadata.gz: 36a3f525833af24f076568ed9bdb43a06e90441788f2f8e8d26c0303ec7e0697a56c8401a3e24c06300cb3f2df199768ae00d8cf95cc90808fb4d9940ab9a931
7
+ data.tar.gz: f60569c63d693272856137c179b826a598c63a5762fedd76faf630b26fd3301d6ca37756f99cb7940501d5bcfd4c375094176a617610c35fc8788b67580159ce
data/.dokaz ADDED
@@ -0,0 +1,2 @@
1
+ README.md
2
+ --require ./spec/dokaz_helpers.rb
@@ -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/)
@@ -0,0 +1,20 @@
1
+ version: 2
2
+
3
+ updates:
4
+ # Maintain dependencies for Ruby's Bundler
5
+ - package-ecosystem: bundler
6
+ directory: "/"
7
+ schedule:
8
+ interval: daily
9
+
10
+ # Maintain dependencies for Ruby's Bundler (for Benchmarks!)
11
+ - package-ecosystem: bundler
12
+ directory: "/benchmarks"
13
+ schedule:
14
+ interval: daily
15
+
16
+ # Maintain dependencies for GitHub Actions
17
+ - package-ecosystem: "github-actions"
18
+ directory: "/"
19
+ schedule:
20
+ interval: "daily"
@@ -15,26 +15,34 @@ jobs:
15
15
  ruby: [jruby, 2.4, 2.5, 2.6, 2.7, 3.0]
16
16
  runs-on: ubuntu-latest
17
17
  steps:
18
- - uses: actions/checkout@main
18
+ - uses: actions/checkout@v2
19
+
20
+ # Conditionally configure bundler via environment variables as advised
21
+ # * https://github.com/ruby/setup-ruby#bundle-config
22
+ - name: Set bundler environment variables
23
+ run: |
24
+ echo "BUNDLE_WITHOUT=checks:docs" >> $GITHUB_ENV
25
+ if: matrix.ruby != 3.0
26
+
27
+ # Use 'bundler-cache: true' instead of actions/cache as advised:
28
+ # * https://github.com/actions/cache/blob/main/examples.md#ruby---bundler
19
29
  - uses: ruby/setup-ruby@v1
20
30
  with:
21
31
  ruby-version: ${{ matrix.ruby }}
22
- - uses: actions/cache@v1
23
- with:
24
- path: vendor/bundle
25
- key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
26
- restore-keys: |
27
- ${{ runner.os }}-gems-
28
- - run: bundle config path vendor/bundle
29
- - run: bundle config set without 'checks:docs'
30
- if: matrix.ruby != 3.0
31
- - run: bundle install --jobs 4 --retry 3
32
+ bundler-cache: true
33
+
32
34
  - run: bundle exec rspec
35
+
33
36
  - run: bundle exec rubocop
34
37
  if: matrix.ruby == 3.0
35
- - run: bundle exec yard doctest
36
- if: matrix.ruby == 3.0
38
+
37
39
  - run: |
40
+ bundle exec yard doctest
41
+ bundle exec dokaz
42
+ if: matrix.ruby == 3.0
43
+
44
+ - name: Run benchmarks on Ruby 2.7 or 3.0
45
+ run: |
38
46
  BUNDLE_GEMFILE=benchmarks/Gemfile bundle install --jobs 4 --retry 3
39
47
  BUNDLE_GEMFILE=benchmarks/Gemfile bundle exec ruby benchmarks/benchmarks.rb
40
48
  if: matrix.ruby == '2.7' || matrix.ruby == '3.0'
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
2
  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,7 +6,54 @@ 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.3.0] - 2021-11-22
13
+
14
+ - Fix thread-safety issue in concurrent calls to zero-arg method in unmemoized
15
+ state which resulted in a `nil` value being accidentally returned in one thread
16
+ - Fix bugs related to child classes inheriting from parent classes that use
17
+ `MemoWise`
18
+
19
+ ## [1.2.0] - 2021-11-10
20
+
21
+ ### Updated
22
+ - Improved performance of all methods by using an outer Array instead of a Hash
23
+ - Improved performance for multi-argument methods and simplify internal data
24
+ structures
25
+
26
+ ### Fixed
27
+ - Removed use of #hash due to potential of hash collisions
28
+ - Updated internal local variable names to avoid name collisions with method
29
+ arguments
30
+
31
+ ### Breaking Changes
32
+ - None
33
+
34
+ ## [1.1.0] - 2021-07-29
35
+ ### Updated
36
+ - Improved performance across the board by:
37
+ - removing `Hash#fetch`
38
+ - using `Array#hash`
39
+ - avoiding multi-layer hash lookups for multi-argument methods
40
+ - optimizing for truthy results
41
+ - Add `dry-core` to benchmarks in README
42
+
43
+ ### Fixed
44
+ - Fixed usage on module singleton classes
45
+ - Fixed usage on module which would be extended by other classes
46
+
47
+ ### Breaking Changes
48
+ - None
49
+
50
+ ## [1.0.0] - 2021-06-24
51
+ ### Added
52
+ - Support for `.preset_memo_wise` on class methods
53
+ - Support for `.reset_memo_wise` on class methods
54
+
55
+ ### Updated
56
+ - Improved performance for common cases by reducing array allocations
10
57
 
11
58
  ## [0.4.0] - 2021-04-30
12
59
  ### Added
@@ -54,7 +101,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
54
101
  - Panolint
55
102
  - Dependabot setup
56
103
 
57
- [Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v0.4.0...HEAD
104
+ [Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v1.3.0...HEAD
105
+ [1.3.0]: https://github.com/panorama-ed/memo_wise/compare/v1.2.0...v1.3.0
106
+ [1.2.0]: https://github.com/panorama-ed/memo_wise/compare/v1.1.0...v1.2.0
107
+ [1.1.0]: https://github.com/panorama-ed/memo_wise/compare/v1.0.0...v1.1.0
108
+ [1.0.0]: https://github.com/panorama-ed/memo_wise/compare/v0.4.0...v1.0.0
58
109
  [0.4.0]: https://github.com/panorama-ed/memo_wise/compare/v0.3.0...v0.4.0
59
110
  [0.3.0]: https://github.com/panorama-ed/memo_wise/compare/v0.2.0...v0.3.0
60
111
  [0.2.0]: https://github.com/panorama-ed/memo_wise/compare/v0.1.2...v0.2.0
data/Gemfile CHANGED
@@ -19,6 +19,7 @@ end
19
19
 
20
20
  # Excluded from CI except on latest MRI Ruby, to reduce compatibility burden
21
21
  group :docs do
22
+ gem "dokaz"
22
23
  gem "redcarpet", "~> 3.5"
23
24
  gem "yard", "~> 0.9"
24
25
  gem "yard-doctest", "~> 0.1"
data/Gemfile.lock CHANGED
@@ -1,6 +1,6 @@
1
1
  GIT
2
2
  remote: https://github.com/panorama-ed/panolint.git
3
- revision: e2f76aa2482f02e68826eb8643a41998a09fc7ab
3
+ revision: c709ebcc5fd9593db959df4a92c12cae1d1fb9af
4
4
  branch: main
5
5
  specs:
6
6
  panolint (0.1.3)
@@ -14,35 +14,41 @@ GIT
14
14
  PATH
15
15
  remote: .
16
16
  specs:
17
- memo_wise (0.4.0)
17
+ memo_wise (1.3.0)
18
18
 
19
19
  GEM
20
20
  remote: https://rubygems.org/
21
21
  specs:
22
- activesupport (5.2.5)
22
+ activesupport (5.2.6)
23
23
  concurrent-ruby (~> 1.0, >= 1.0.2)
24
24
  i18n (>= 0.7, < 2)
25
25
  minitest (~> 5.1)
26
26
  tzinfo (~> 1.1)
27
+ ansi (1.5.0)
27
28
  ast (2.4.2)
28
- brakeman (5.0.0)
29
- codecov (0.5.2)
29
+ brakeman (5.1.1)
30
+ codecov (0.6.0)
30
31
  simplecov (>= 0.15, < 0.22)
31
- concurrent-ruby (1.1.8)
32
+ concurrent-ruby (1.1.9)
32
33
  diff-lcs (1.4.4)
33
34
  docile (1.3.5)
35
+ dokaz (0.0.4)
36
+ ansi
37
+ rouge
38
+ slop (~> 3)
34
39
  i18n (1.8.10)
35
40
  concurrent-ruby (~> 1.0)
36
41
  minitest (5.14.4)
37
42
  parallel (1.20.1)
38
- parser (3.0.1.0)
43
+ parser (3.0.2.0)
39
44
  ast (~> 2.4.1)
40
45
  rack (2.2.3)
41
46
  rainbow (3.0.0)
42
- rake (13.0.3)
47
+ rake (13.0.6)
43
48
  redcarpet (3.5.1)
44
49
  regexp_parser (2.1.1)
45
50
  rexml (3.2.5)
51
+ rouge (3.26.0)
46
52
  rspec (3.10.0)
47
53
  rspec-core (~> 3.10.0)
48
54
  rspec-expectations (~> 3.10.0)
@@ -84,6 +90,7 @@ GEM
84
90
  docile (~> 1.1)
85
91
  simplecov-html (~> 0.11)
86
92
  simplecov-html (0.12.3)
93
+ slop (3.6.0)
87
94
  thread_safe (0.3.6)
88
95
  tzinfo (1.2.9)
89
96
  thread_safe (~> 0.1)
@@ -99,6 +106,7 @@ PLATFORMS
99
106
 
100
107
  DEPENDENCIES
101
108
  codecov
109
+ dokaz
102
110
  memo_wise!
103
111
  panolint!
104
112
  rake
@@ -109,4 +117,4 @@ DEPENDENCIES
109
117
  yard-doctest (~> 0.1)
110
118
 
111
119
  BUNDLED WITH
112
- 2.2.3
120
+ 2.2.28
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020 Panorama Education
3
+ Copyright (c) 2020-2021 Panorama Education
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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
@@ -50,11 +51,21 @@ methods:
50
51
  ```ruby
51
52
  class Example
52
53
  prepend MemoWise
54
+
53
55
  def slow_value(x)
54
56
  sleep x
55
57
  x
56
58
  end
57
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
58
69
  end
59
70
 
60
71
  ex = Example.new
@@ -71,29 +82,68 @@ ex.slow_value(3) # => 4 # Returns immediately because the result is memoized
71
82
  ex.reset_memo_wise # Resets all memoized results for all methods on ex
72
83
  ```
73
84
 
74
- Methods which take implicit or explicit block arguments cannot be memoized.
85
+ The same three methods are exposed for class methods as well:
75
86
 
76
- For more usage details, see our detailed [documentation](#documentation).
87
+ ```ruby
88
+ class Example
89
+ prepend MemoWise
77
90
 
78
- ## Benchmarks
91
+ def self.class_slow_value(x)
92
+ sleep x
93
+ x
94
+ end
95
+ memo_wise self: :class_slow_value
96
+ end
97
+
98
+ Example.class_slow_value(2) # => 2 # Sleeps for 2 seconds before returning
99
+ Example.class_slow_value(2) # => 2 # Returns immediately because the result is memoized
100
+
101
+ Example.reset_memo_wise(:class_slow_value) # Resets all memoized results for class_slow_value
79
102
 
80
- Benchmarks measure memoized value retrieval time using
81
- [`benchmark-ips`](https://github.com/evanphx/benchmark-ips). All benchmarks are
82
- run on Ruby 3.0.0, except as indicated below for specific gems. Benchmarks are
83
- run in GitHub Actions and updated in every PR that changes code.
103
+ Example.preset_memo_wise(:class_slow_value, 3) { 4 } # Store 4 as the result for slow_value(3)
104
+ Example.class_slow_value(3) # => 4 # Returns immediately because the result is memoized
105
+ Example.reset_memo_wise # Resets all memoized results for all methods on class
106
+ ```
107
+
108
+ **NOTE:** Methods which take implicit or explicit block arguments cannot be
109
+ memoized.
84
110
 
85
- |Method arguments|**`memo_wise` (0.1.0)**|`memery` (1.3.0)|`memoist`\* (0.16.2)|`memoized`\* (1.0.2)|`memoizer`\* (1.0.3)|
86
- |--|--|--|--|--|--|
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|
111
+ For more usage details, see our detailed [documentation](#documentation).
112
+
113
+ ## Benchmarks
94
114
 
95
- _\*Indicates a benchmark run on Ruby 2.7.2 because the gem raises errors in Ruby
96
- 3.0.0 due to its incorrect handling of keyword arguments._
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.1).
116
+
117
+ Results using Ruby 3.0.2:
118
+
119
+ |Method arguments|`Dry::Core`\* (0.7.1)|`Memery` (1.4.0)|
120
+ |--|--|--|
121
+ |`()` (none)|1.42x|17.84x|
122
+ |`(a)`|2.48x|11.48x|
123
+ |`(a, b)`|0.46x|2.05x|
124
+ |`(a:)`|2.18x|20.50x|
125
+ |`(a:, b:)`|0.48x|4.22x|
126
+ |`(a, b:)`|0.48x|4.08x|
127
+ |`(a, *args)`|0.90x|1.97x|
128
+ |`(a:, **kwargs)`|0.80x|3.02x|
129
+ |`(a, *args, b:, **kwargs)`|0.61x|1.54x|
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.4 (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)|
137
+ |--|--|--|--|--|
138
+ |`()` (none)|33.90x|3.44x|1.56x|4.03x|
139
+ |`(a)`|24.56x|17.02x|12.94x|14.91x|
140
+ |`(a, b)`|3.14x|2.35x|1.84x|2.03x|
141
+ |`(a:)`|34.42x|28.14x|23.83x|25.26x|
142
+ |`(a:, b:)`|5.13x|4.28x|3.77x|3.97x|
143
+ |`(a, b:)`|4.83x|4.08x|3.50x|3.66x|
144
+ |`(a, *args)`|3.03x|2.25x|1.95x|1.95x|
145
+ |`(a:, **kwargs)`|2.90x|2.44x|2.14x|2.24x|
146
+ |`(a, *args, b:, **kwargs)`|2.05x|1.77x|1.65x|1.64x|
97
147
 
98
148
  You can run benchmarks yourself with:
99
149
 
@@ -106,18 +156,6 @@ $ bundle exec ruby benchmarks.rb
106
156
  If your results differ from what's posted here,
107
157
  [let us know](https://github.com/panorama-ed/memo_wise/issues/new)!
108
158
 
109
- ## Development
110
-
111
- After checking out the repo, run `bin/setup` to install dependencies. Then, run
112
- `rake spec` to run the tests. You can also run `bin/console` for an interactive
113
- prompt that will allow you to experiment.
114
-
115
- To install this gem onto your local machine, run `bundle exec rake install`. To
116
- release a new version, update the version number in `version.rb`, and then run
117
- `bundle exec rake release`, which will create a git tag for the version, push
118
- git commits and tags, and push the `.gem` file to
119
- [rubygems.org](https://rubygems.org).
120
-
121
159
  ## Documentation
122
160
 
123
161
  ### Documentation is Automatically Generated
@@ -140,6 +178,14 @@ code examples in our YARD documentation. To run `doctest` locally:
140
178
  bundle exec yard doctest
141
179
  ```
142
180
 
181
+ We use [dokaz](https://github.com/zverok/dokaz) to test all code examples in
182
+ this README.md file, and all other non-code documentation. To run `dokaz`
183
+ locally:
184
+
185
+ ```bash
186
+ bundle exec dokaz
187
+ ```
188
+
143
189
  ### A Note on Testing
144
190
 
145
191
  When testing memoized *module* methods, note that some testing setups will
@@ -159,6 +205,20 @@ memoization between your tests with something like:
159
205
  after(:each) { helper.reset_memo_wise }
160
206
  ```
161
207
 
208
+ ## Further Reading
209
+
210
+ We presented at RubyConf 2021:
211
+
212
+ - Achieving Fast Method Metaprogramming: Lessons from `MemoWise`
213
+ ([slides](https://docs.google.com/presentation/d/1XgERQ0YHplwJKM3wNQwZn584d_9szYZp2WsDEXoY_7Y/edit?usp=sharing) /
214
+ [benchmarks](https://gist.github.com/JacobEvelyn/17b7b000e50151c30eaea928f1fcdc11))
215
+
216
+ And we've written more about `MemoWise` in a series of blog posts:
217
+
218
+ - [Introducing: MemoWise](https://medium.com/building-panorama-education/introducing-memowise-51a5f0523489)
219
+ - [Optimizing MemoWise Performance](https://ja.cob.land/optimizing-memowise-performance)
220
+ - [Esosteric Ruby in MemoWise](https://jemma.dev/blog/esoteric-ruby-in-memowise)
221
+
162
222
  ## Logo
163
223
 
164
224
  `MemoWise`'s logo was created by [Luci Cooke](https://www.lucicooke.com/). The
@@ -180,7 +240,7 @@ To make a new release of `MemoWise` to
180
240
  dependencies (e.g. `rake`) as follows:
181
241
 
182
242
  ```shell
183
- bundle config set --local with 'release'
243
+ bundle config --local with 'release'
184
244
  bundle install
185
245
  ```
186
246
 
@@ -188,6 +248,7 @@ Then carry out these steps:
188
248
 
189
249
  1. Update `CHANGELOG.md`:
190
250
  - Add an entry for the upcoming version _x.y.z_
251
+ - Add a link for this version's comparison to the bottom of `CHANGELOG.md`
191
252
  - Move content from _Unreleased_ to the upcoming version _x.y.z_
192
253
  - Commit with title `Update CHANGELOG.md for x.y.z`
193
254
 
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.4"
6
6
 
7
- gem "benchmark-ips", "2.8.4"
7
+ gem "benchmark-ips", "2.9.1"
8
8
 
9
9
  if RUBY_VERSION > "3"
10
- gem "memery", "1.3.0"
10
+ gem "dry-core", "0.7.1"
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"