memo_wise 1.6.0 → 1.7.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/main.yml +11 -2
- data/CHANGELOG.md +10 -2
- data/Gemfile +7 -2
- data/Gemfile.lock +40 -38
- data/README.md +20 -21
- data/benchmarks/Gemfile +4 -2
- data/benchmarks/benchmarks.rb +67 -37
- data/lib/memo_wise/internal_api.rb +2 -5
- data/lib/memo_wise/version.rb +1 -1
- data/lib/memo_wise.rb +69 -16
- 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: '009e350b06faaa529d704c4386b7443719d9a1faa2a58d9532e33028545ae938'
|
|
4
|
+
data.tar.gz: b7c41458ffb2ff88afc3f731c6c9e04e5133e2ac8830a24dfc1d78409802831d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72500c89882f08671756f564205aef35e8546edb24d416e98444d5368c5e531c9e815791ba7ece1385e7e1405aaf1395a9c930dd8c711c2a70563818c2d1d4f6
|
|
7
|
+
data.tar.gz: 95418a3b09950182d433b037250afcd5142c323fa23dad4be256984a76bb4ebe0c3a831b0ba1fd8205767a0b3ee4566685a3687cb0042e59bd9bc03030654fbe
|
data/.github/workflows/main.yml
CHANGED
|
@@ -12,10 +12,12 @@ jobs:
|
|
|
12
12
|
strategy:
|
|
13
13
|
fail-fast: false
|
|
14
14
|
matrix:
|
|
15
|
-
|
|
15
|
+
# Due to https://github.com/actions/runner/issues/849, we have to use
|
|
16
|
+
# quotes for '3.0' -- without quotes, CI sees '3' and runs the latest.
|
|
17
|
+
ruby: [2.4, 2.5, 2.6, 2.7, '3.0', 3.1, jruby, truffleruby-head]
|
|
16
18
|
runs-on: ubuntu-latest
|
|
17
19
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
20
|
+
- uses: actions/checkout@v3
|
|
19
21
|
|
|
20
22
|
# Conditionally configure bundler via environment variables as advised
|
|
21
23
|
# * https://github.com/ruby/setup-ruby#bundle-config
|
|
@@ -33,6 +35,13 @@ jobs:
|
|
|
33
35
|
|
|
34
36
|
- run: bundle exec rspec
|
|
35
37
|
|
|
38
|
+
- uses: codecov/codecov-action@v2
|
|
39
|
+
with:
|
|
40
|
+
files: ./coverage/coverage.xml
|
|
41
|
+
fail_ci_if_error: true # optional (default = false)
|
|
42
|
+
verbose: true # optional (default = false)
|
|
43
|
+
if: matrix.ruby == 3.1
|
|
44
|
+
|
|
36
45
|
- run: bundle exec rubocop
|
|
37
46
|
if: matrix.ruby == 3.1
|
|
38
47
|
|
data/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
-
Nothing yet!
|
|
10
|
+
- Nothing yet!
|
|
11
|
+
|
|
12
|
+
## [1.7.0] - 2022-04-04
|
|
13
|
+
|
|
14
|
+
### Updated
|
|
15
|
+
|
|
16
|
+
- Optimize memoized lookups for methods with multiple required arguments
|
|
17
|
+
([#276](https://github.com/panorama-ed/memo_wise/pull/276))
|
|
11
18
|
|
|
12
19
|
## [1.6.0] - 2022-01-24
|
|
13
20
|
|
|
@@ -131,7 +138,8 @@ Nothing yet!
|
|
|
131
138
|
- Panolint
|
|
132
139
|
- Dependabot setup
|
|
133
140
|
|
|
134
|
-
[Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v1.
|
|
141
|
+
[Unreleased]: https://github.com/panorama-ed/memo_wise/compare/v1.7.0...HEAD
|
|
142
|
+
[1.6.0]: https://github.com/panorama-ed/memo_wise/compare/v1.6.0...v1.7.0
|
|
135
143
|
[1.6.0]: https://github.com/panorama-ed/memo_wise/compare/v1.5.0...v1.6.0
|
|
136
144
|
[1.5.0]: https://github.com/panorama-ed/memo_wise/compare/v1.4.0...v1.5.0
|
|
137
145
|
[1.4.0]: https://github.com/panorama-ed/memo_wise/compare/v1.3.0...v1.4.0
|
data/Gemfile
CHANGED
|
@@ -7,14 +7,19 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
|
|
7
7
|
gemspec
|
|
8
8
|
|
|
9
9
|
group :test do
|
|
10
|
-
gem "rspec", "~> 3.
|
|
10
|
+
gem "rspec", "~> 3.11"
|
|
11
11
|
gem "values", "~> 1"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Excluded from CI except on latest MRI Ruby, to reduce compatibility burden
|
|
15
15
|
group :checks do
|
|
16
|
-
gem "codecov"
|
|
17
16
|
gem "panolint", github: "panorama-ed/panolint", branch: "main"
|
|
17
|
+
|
|
18
|
+
# Simplecov to generate coverage info
|
|
19
|
+
gem "simplecov", require: false
|
|
20
|
+
|
|
21
|
+
# Simplecov-cobertura to generate an xml coverage file to upload to Codecov
|
|
22
|
+
gem "simplecov-cobertura", require: false
|
|
18
23
|
end
|
|
19
24
|
|
|
20
25
|
# Excluded from CI except on latest MRI Ruby, to reduce compatibility burden
|
data/Gemfile.lock
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
GIT
|
|
2
2
|
remote: https://github.com/panorama-ed/panolint.git
|
|
3
|
-
revision:
|
|
3
|
+
revision: 32da31ae800b7e16068b6495397cd98aa04c68a3
|
|
4
4
|
branch: main
|
|
5
5
|
specs:
|
|
6
6
|
panolint (0.1.4)
|
|
@@ -14,82 +14,84 @@ GIT
|
|
|
14
14
|
PATH
|
|
15
15
|
remote: .
|
|
16
16
|
specs:
|
|
17
|
-
memo_wise (1.
|
|
17
|
+
memo_wise (1.7.0)
|
|
18
18
|
|
|
19
19
|
GEM
|
|
20
20
|
remote: https://rubygems.org/
|
|
21
21
|
specs:
|
|
22
|
-
activesupport (
|
|
22
|
+
activesupport (7.0.2.2)
|
|
23
23
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
24
24
|
i18n (>= 1.6, < 2)
|
|
25
25
|
minitest (>= 5.1)
|
|
26
26
|
tzinfo (~> 2.0)
|
|
27
|
-
zeitwerk (~> 2.3)
|
|
28
27
|
ansi (1.5.0)
|
|
29
28
|
ast (2.4.2)
|
|
30
|
-
brakeman (5.1
|
|
31
|
-
codecov (0.6.0)
|
|
32
|
-
simplecov (>= 0.15, < 0.22)
|
|
29
|
+
brakeman (5.2.1)
|
|
33
30
|
concurrent-ruby (1.1.9)
|
|
34
|
-
diff-lcs (1.
|
|
35
|
-
docile (1.
|
|
31
|
+
diff-lcs (1.5.0)
|
|
32
|
+
docile (1.4.0)
|
|
36
33
|
dokaz (0.0.4)
|
|
37
34
|
ansi
|
|
38
35
|
rouge
|
|
39
36
|
slop (~> 3)
|
|
40
|
-
i18n (1.
|
|
37
|
+
i18n (1.10.0)
|
|
41
38
|
concurrent-ruby (~> 1.0)
|
|
42
|
-
minitest (5.
|
|
39
|
+
minitest (5.15.0)
|
|
43
40
|
parallel (1.21.0)
|
|
44
|
-
parser (3.1.
|
|
41
|
+
parser (3.1.1.0)
|
|
45
42
|
ast (~> 2.4.1)
|
|
46
43
|
rack (2.2.3)
|
|
47
|
-
rainbow (3.
|
|
44
|
+
rainbow (3.1.1)
|
|
48
45
|
rake (13.0.6)
|
|
49
46
|
redcarpet (3.5.1)
|
|
50
|
-
regexp_parser (2.2.
|
|
47
|
+
regexp_parser (2.2.1)
|
|
51
48
|
rexml (3.2.5)
|
|
52
|
-
rouge (3.
|
|
53
|
-
rspec (3.
|
|
54
|
-
rspec-core (~> 3.
|
|
55
|
-
rspec-expectations (~> 3.
|
|
56
|
-
rspec-mocks (~> 3.
|
|
57
|
-
rspec-core (3.
|
|
58
|
-
rspec-support (~> 3.
|
|
59
|
-
rspec-expectations (3.
|
|
49
|
+
rouge (3.28.0)
|
|
50
|
+
rspec (3.11.0)
|
|
51
|
+
rspec-core (~> 3.11.0)
|
|
52
|
+
rspec-expectations (~> 3.11.0)
|
|
53
|
+
rspec-mocks (~> 3.11.0)
|
|
54
|
+
rspec-core (3.11.0)
|
|
55
|
+
rspec-support (~> 3.11.0)
|
|
56
|
+
rspec-expectations (3.11.0)
|
|
60
57
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
61
|
-
rspec-support (~> 3.
|
|
62
|
-
rspec-mocks (3.
|
|
58
|
+
rspec-support (~> 3.11.0)
|
|
59
|
+
rspec-mocks (3.11.0)
|
|
63
60
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
64
|
-
rspec-support (~> 3.
|
|
65
|
-
rspec-support (3.
|
|
66
|
-
rubocop (1.
|
|
61
|
+
rspec-support (~> 3.11.0)
|
|
62
|
+
rspec-support (3.11.0)
|
|
63
|
+
rubocop (1.25.1)
|
|
67
64
|
parallel (~> 1.10)
|
|
68
|
-
parser (>= 3.
|
|
65
|
+
parser (>= 3.1.0.0)
|
|
69
66
|
rainbow (>= 2.2.2, < 4.0)
|
|
70
67
|
regexp_parser (>= 1.8, < 3.0)
|
|
71
68
|
rexml
|
|
72
69
|
rubocop-ast (>= 1.15.1, < 2.0)
|
|
73
70
|
ruby-progressbar (~> 1.7)
|
|
74
71
|
unicode-display_width (>= 1.4.0, < 3.0)
|
|
75
|
-
rubocop-ast (1.
|
|
76
|
-
parser (>= 3.
|
|
77
|
-
rubocop-performance (1.
|
|
72
|
+
rubocop-ast (1.16.0)
|
|
73
|
+
parser (>= 3.1.1.0)
|
|
74
|
+
rubocop-performance (1.13.2)
|
|
78
75
|
rubocop (>= 1.7.0, < 2.0)
|
|
79
76
|
rubocop-ast (>= 0.4.0)
|
|
80
|
-
rubocop-rails (2.
|
|
77
|
+
rubocop-rails (2.13.2)
|
|
81
78
|
activesupport (>= 4.2.0)
|
|
82
79
|
rack (>= 1.1)
|
|
83
80
|
rubocop (>= 1.7.0, < 2.0)
|
|
84
81
|
rubocop-rake (0.6.0)
|
|
85
82
|
rubocop (~> 1.0)
|
|
86
|
-
rubocop-rspec (2.
|
|
83
|
+
rubocop-rspec (2.9.0)
|
|
87
84
|
rubocop (~> 1.19)
|
|
88
85
|
ruby-progressbar (1.11.0)
|
|
89
|
-
simplecov (0.
|
|
86
|
+
simplecov (0.21.2)
|
|
90
87
|
docile (~> 1.1)
|
|
91
88
|
simplecov-html (~> 0.11)
|
|
89
|
+
simplecov_json_formatter (~> 0.1)
|
|
90
|
+
simplecov-cobertura (2.1.0)
|
|
91
|
+
rexml
|
|
92
|
+
simplecov (~> 0.19)
|
|
92
93
|
simplecov-html (0.12.3)
|
|
94
|
+
simplecov_json_formatter (0.1.4)
|
|
93
95
|
slop (3.6.0)
|
|
94
96
|
tzinfo (2.0.4)
|
|
95
97
|
concurrent-ruby (~> 1.0)
|
|
@@ -101,22 +103,22 @@ GEM
|
|
|
101
103
|
yard-doctest (0.1.17)
|
|
102
104
|
minitest
|
|
103
105
|
yard
|
|
104
|
-
zeitwerk (2.5.1)
|
|
105
106
|
|
|
106
107
|
PLATFORMS
|
|
107
108
|
ruby
|
|
108
109
|
|
|
109
110
|
DEPENDENCIES
|
|
110
|
-
codecov
|
|
111
111
|
dokaz
|
|
112
112
|
memo_wise!
|
|
113
113
|
panolint!
|
|
114
114
|
rake
|
|
115
115
|
redcarpet (~> 3.5)
|
|
116
|
-
rspec (~> 3.
|
|
116
|
+
rspec (~> 3.11)
|
|
117
|
+
simplecov
|
|
118
|
+
simplecov-cobertura
|
|
117
119
|
values (~> 1)
|
|
118
120
|
yard (~> 0.9)
|
|
119
121
|
yard-doctest (~> 0.1)
|
|
120
122
|
|
|
121
123
|
BUNDLED WITH
|
|
122
|
-
2.
|
|
124
|
+
2.3.8
|
data/README.md
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
[](https://github.com/panorama-ed/memo_wise/actions?query=workflow%3AMain)
|
|
9
9
|
[](https://codecov.io/gh/panorama-ed/memo_wise/branches/main)
|
|
10
10
|
[](http://rubydoc.info/github/panorama-ed/memo_wise)
|
|
11
|
-
[](http://inch-ci.org/github/panorama-ed/memo_wise)
|
|
12
11
|
[](https://rubygems.org/gems/memo_wise)
|
|
13
12
|
[](https://rubygems.org/gems/memo_wise)
|
|
14
13
|
|
|
@@ -115,19 +114,19 @@ For more usage details, see our detailed [documentation](#documentation).
|
|
|
115
114
|
|
|
116
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).
|
|
117
116
|
|
|
118
|
-
Results using Ruby 3.1.
|
|
117
|
+
Results using Ruby 3.1.1:
|
|
119
118
|
|
|
120
|
-
|Method arguments|`Dry::Core
|
|
119
|
+
|Method arguments|`Dry::Core`\* (0.7.1)|`Memery` (1.4.0)|
|
|
121
120
|
|--|--|--|
|
|
122
|
-
|`()` (none)|1.
|
|
123
|
-
|`(a)`|1.
|
|
124
|
-
|`(a, b)`|
|
|
125
|
-
|`(a:)`|1.
|
|
126
|
-
|`(a:, b:)`|
|
|
127
|
-
|`(a, b:)`|
|
|
128
|
-
|`(a, *args)`|0.
|
|
129
|
-
|`(a:, **kwargs)`|0.
|
|
130
|
-
|`(a, *args, b:, **kwargs)`|0.
|
|
121
|
+
|`()` (none)|1.11x|12.24x|
|
|
122
|
+
|`(a)`|1.71x|9.55x|
|
|
123
|
+
|`(a, b)`|1.27x|6.95x|
|
|
124
|
+
|`(a:)`|1.58x|18.25x|
|
|
125
|
+
|`(a:, b:)`|1.19x|13.31x|
|
|
126
|
+
|`(a, b:)`|1.22x|13.29x|
|
|
127
|
+
|`(a, *args)`|0.86x|1.84x|
|
|
128
|
+
|`(a:, **kwargs)`|0.83x|3.15x|
|
|
129
|
+
|`(a, *args, b:, **kwargs)`|0.76x|1.92x|
|
|
131
130
|
|
|
132
131
|
\* `Dry::Core`
|
|
133
132
|
[may cause incorrect behavior caused by hash collisions](https://github.com/dry-rb/dry-core/issues/63).
|
|
@@ -136,15 +135,15 @@ Results using Ruby 2.7.5 (because these gems raise errors in Ruby 3.x):
|
|
|
136
135
|
|
|
137
136
|
|Method arguments|`DDMemoize` (1.0.0)|`Memoist` (0.16.2)|`Memoized` (1.0.2)|`Memoizer` (1.0.3)|
|
|
138
137
|
|--|--|--|--|--|
|
|
139
|
-
|`()` (none)|24.
|
|
140
|
-
|`(a)`|
|
|
141
|
-
|`(a, b)`|
|
|
142
|
-
|`(a:)`|
|
|
143
|
-
|`(a:, b:)`|
|
|
144
|
-
|`(a, b:)`|
|
|
145
|
-
|`(a, *args)`|3.
|
|
146
|
-
|`(a:, **kwargs)`|2.
|
|
147
|
-
|`(a, *args, b:, **kwargs)`|2.
|
|
138
|
+
|`()` (none)|24.22x|2.48x|1.22x|3.08x|
|
|
139
|
+
|`(a)`|20.38x|14.06x|10.85x|12.26x|
|
|
140
|
+
|`(a, b)`|17.48x|12.67x|10.07x|11.32x|
|
|
141
|
+
|`(a:)`|29.72x|24.26x|21.04x|21.72x|
|
|
142
|
+
|`(a:, b:)`|24.17x|20.17x|17.81x|18.85x|
|
|
143
|
+
|`(a, b:)`|24.20x|20.15x|17.51x|18.05x|
|
|
144
|
+
|`(a, *args)`|3.11x|2.23x|1.95x|2.03x|
|
|
145
|
+
|`(a:, **kwargs)`|2.96x|2.46x|2.17x|2.28x|
|
|
146
|
+
|`(a, *args, b:, **kwargs)`|2.17x|1.86x|1.76x|1.76x|
|
|
148
147
|
|
|
149
148
|
You can run benchmarks yourself with:
|
|
150
149
|
|
data/benchmarks/Gemfile
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
|
6
|
+
|
|
5
7
|
ruby ">= 2.7.5"
|
|
6
8
|
|
|
7
|
-
gem "benchmark-ips", "2.
|
|
9
|
+
gem "benchmark-ips", "2.10.0"
|
|
8
10
|
|
|
9
11
|
if RUBY_VERSION > "3"
|
|
10
12
|
gem "dry-core", "0.7.1"
|
|
@@ -16,4 +18,4 @@ else
|
|
|
16
18
|
gem "memoizer", "1.0.3"
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
gem "memo_wise",
|
|
21
|
+
gem "memo_wise", github: "panorama-ed/memo_wise", branch: "main"
|
data/benchmarks/benchmarks.rb
CHANGED
|
@@ -3,7 +3,26 @@
|
|
|
3
3
|
require "benchmark/ips"
|
|
4
4
|
|
|
5
5
|
require "tempfile"
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
github_memo_wise_path = Gem.loaded_specs["memo_wise"].full_gem_path
|
|
8
|
+
|
|
9
|
+
# This string is both used for temp filepaths necessary to separate the GitHub
|
|
10
|
+
# version of MemoWise and the local version, and used for the reported results
|
|
11
|
+
GITHUB_MAIN = "MemoWise_GitHubMain"
|
|
12
|
+
|
|
13
|
+
# We download a the main branch of MemoWise on GitHub into a tmp directory to
|
|
14
|
+
# compare against the local version when we run benchmarks
|
|
15
|
+
Dir.mktmpdir do |directory|
|
|
16
|
+
Dir["#{github_memo_wise_path}/lib/**/*.rb"].each do |file|
|
|
17
|
+
Tempfile.open([File.basename(file)[0..-4], ".rb"], directory) do |tempfile|
|
|
18
|
+
tempfile.write(File.read(file).gsub("MemoWise", GITHUB_MAIN))
|
|
19
|
+
tempfile.rewind
|
|
20
|
+
require tempfile.path
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
require_relative "../lib/memo_wise"
|
|
7
26
|
|
|
8
27
|
# Some gems do not yet work in Ruby 3 so we only require them if they're loaded
|
|
9
28
|
# in the Gemfile.
|
|
@@ -51,6 +70,7 @@ end
|
|
|
51
70
|
# NOTE: Some gems do not yet work in Ruby 3 so we only test with them if they've
|
|
52
71
|
# been `require`d.
|
|
53
72
|
BENCHMARK_GEMS = [
|
|
73
|
+
BenchmarkGem.new(MemoWise_GitHubMain, "prepend #{GITHUB_MAIN}", :memo_wise),
|
|
54
74
|
BenchmarkGem.new(MemoWise, "prepend MemoWise", :memo_wise),
|
|
55
75
|
(BenchmarkGem.new(DDMemoize, "DDMemoize.activate(self)", :memoize) if defined?(DDMemoize)),
|
|
56
76
|
(BenchmarkGem.new(Dry::Core, "include Dry::Core::Memoizable", :memoize) if defined?(Dry::Core)),
|
|
@@ -187,7 +207,7 @@ benchmark_lambdas = [
|
|
|
187
207
|
|
|
188
208
|
# We benchmark different cases separately, to ensure that slow performance in
|
|
189
209
|
# one method or code path isn't hidden by fast performance in another.
|
|
190
|
-
benchmark_lambdas.map do |benchmark|
|
|
210
|
+
benchmark_jsons = benchmark_lambdas.map do |benchmark|
|
|
191
211
|
json_file = Tempfile.new
|
|
192
212
|
|
|
193
213
|
Benchmark.ips do |x|
|
|
@@ -203,42 +223,52 @@ benchmark_lambdas.map do |benchmark|
|
|
|
203
223
|
end
|
|
204
224
|
|
|
205
225
|
JSON.parse(json_file.read)
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
[true, false].each do |github_comparison|
|
|
229
|
+
benchmark_jsons.each_with_index do |benchmark_json, i|
|
|
230
|
+
# We print a comparison table after we run each benchmark to copy into our
|
|
231
|
+
# README.md
|
|
232
|
+
|
|
233
|
+
# MemoWise will not appear in the comparison table, but we will use it to
|
|
234
|
+
# compare against other gems' benchmarks
|
|
235
|
+
memo_wise = benchmark_json.find { |json| json["name"].split.first == "MemoWise" }
|
|
236
|
+
benchmark_json -= [memo_wise]
|
|
237
|
+
|
|
238
|
+
github_main = benchmark_json.find { |json| json["name"].split.first == GITHUB_MAIN }
|
|
239
|
+
benchmark_json = github_comparison ? [github_main] : benchmark_json - [github_main]
|
|
240
|
+
|
|
241
|
+
# Sort benchmarks by gem name to alphabetize our final output table.
|
|
242
|
+
benchmark_json.sort_by! { |json| json["name"] }
|
|
243
|
+
|
|
244
|
+
# Print headers based on the first benchmark_json
|
|
245
|
+
if i.zero?
|
|
246
|
+
benchmark_headers = benchmark_json.map do |benchmark_gem|
|
|
247
|
+
# Gem name is of the form:
|
|
248
|
+
# "MemoWise (1.1.0): ()"
|
|
249
|
+
# We use this mapping to get a header of the form
|
|
250
|
+
# "`MemoWise` (1.1.0)
|
|
251
|
+
gem_name_parts = benchmark_gem["name"].split
|
|
252
|
+
"`#{gem_name_parts[0]}` #{gem_name_parts[1][...-1]}"
|
|
253
|
+
end.join("|")
|
|
254
|
+
puts "|Method arguments|#{benchmark_headers}|"
|
|
255
|
+
puts "#{'|--' * (benchmark_json.size + 1)}|"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
output_str = benchmark_json.map do |bgem|
|
|
259
|
+
# "%.2f" % 12.345 => "12.34" (instead of "12.35")
|
|
260
|
+
# See: https://bugs.ruby-lang.org/issues/12548
|
|
261
|
+
# 1.00.round(2).to_s => "1.0" (instead of "1.00")
|
|
262
|
+
#
|
|
263
|
+
# So to round and format correctly, we first use Float#round and then %
|
|
264
|
+
"%.#{N_RESULT_DECIMAL_DIGITS}fx" %
|
|
265
|
+
(memo_wise["central_tendency"] / bgem["central_tendency"]).round(N_RESULT_DECIMAL_DIGITS)
|
|
227
266
|
end.join("|")
|
|
228
|
-
|
|
229
|
-
|
|
267
|
+
|
|
268
|
+
name = memo_wise["name"].partition(": ").last
|
|
269
|
+
puts "|`#{name}`#{' (none)' if name == '()'}|#{output_str}|"
|
|
230
270
|
end
|
|
231
271
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
# See: https://bugs.ruby-lang.org/issues/12548
|
|
235
|
-
# 1.00.round(2).to_s => "1.0" (instead of "1.00")
|
|
236
|
-
#
|
|
237
|
-
# So to round and format correctly, we first use Float#round and then %
|
|
238
|
-
"%.#{N_RESULT_DECIMAL_DIGITS}fx" %
|
|
239
|
-
(memo_wise["central_tendency"] / bgem["central_tendency"]).round(N_RESULT_DECIMAL_DIGITS)
|
|
240
|
-
end.join("|")
|
|
241
|
-
|
|
242
|
-
name = memo_wise["name"].partition(": ").last
|
|
243
|
-
puts "|`#{name}`#{' (none)' if name == '()'}|#{output_str}|"
|
|
272
|
+
# Output a blank line between sections
|
|
273
|
+
puts ""
|
|
244
274
|
end
|
|
@@ -17,8 +17,8 @@ module MemoWise
|
|
|
17
17
|
# zero_arg_method_name: :memoized_result,
|
|
18
18
|
# single_arg_method_name: { arg1 => :memoized_result, ... },
|
|
19
19
|
#
|
|
20
|
-
# #
|
|
21
|
-
# multi_arg_method_name: {
|
|
20
|
+
# # This is faster than a single top-level hash key of: [:multi_arg_method_name, arg1, arg2]
|
|
21
|
+
# multi_arg_method_name: { arg1 => { arg2 => :memoized_result, ... }, ... }
|
|
22
22
|
# }
|
|
23
23
|
obj.instance_variable_set(:@_memo_wise, {}) unless obj.instance_variable_defined?(:@_memo_wise)
|
|
24
24
|
|
|
@@ -70,7 +70,6 @@ module MemoWise
|
|
|
70
70
|
case method_arguments(method)
|
|
71
71
|
when SPLAT then "*args"
|
|
72
72
|
when DOUBLE_SPLAT then "**kwargs"
|
|
73
|
-
when SPLAT_AND_DOUBLE_SPLAT then "*args, **kwargs"
|
|
74
73
|
when ONE_REQUIRED_POSITIONAL, ONE_REQUIRED_KEYWORD, MULTIPLE_REQUIRED
|
|
75
74
|
method.parameters.map do |type, name|
|
|
76
75
|
"#{name}#{':' if type == :keyreq}"
|
|
@@ -105,8 +104,6 @@ module MemoWise
|
|
|
105
104
|
case method_arguments(method)
|
|
106
105
|
when SPLAT then "args"
|
|
107
106
|
when DOUBLE_SPLAT then "kwargs"
|
|
108
|
-
when SPLAT_AND_DOUBLE_SPLAT then "[args, kwargs]"
|
|
109
|
-
when MULTIPLE_REQUIRED then "[#{method.parameters.map(&:last).join(', ')}]"
|
|
110
107
|
else
|
|
111
108
|
raise ArgumentError, "Unexpected arguments for #{method.name}"
|
|
112
109
|
end
|
data/lib/memo_wise/version.rb
CHANGED
data/lib/memo_wise.rb
CHANGED
|
@@ -195,9 +195,40 @@ module MemoWise
|
|
|
195
195
|
end
|
|
196
196
|
end
|
|
197
197
|
HEREDOC
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
when MemoWise::InternalAPI::MULTIPLE_REQUIRED
|
|
199
|
+
# When we have multiple required params, we store the memoized values in a deeply nested hash, like:
|
|
200
|
+
# { method_name: { arg1 => { arg2 => { arg3 => memoized_value } } } }
|
|
201
|
+
last_index = method.parameters.size
|
|
202
|
+
layers = method.parameters.map.with_index(1) do |(_, name), index|
|
|
203
|
+
prev_hash = "_memo_wise_hash#{index - 1 if index > 1}"
|
|
204
|
+
fallback = if index == last_index
|
|
205
|
+
"#{original_memo_wised_name}(#{MemoWise::InternalAPI.call_str(method)})"
|
|
206
|
+
else
|
|
207
|
+
"{}"
|
|
208
|
+
end
|
|
209
|
+
"_memo_wise_hash#{index} = #{prev_hash}.fetch(#{name}) { #{prev_hash}[#{name}] = #{fallback} }"
|
|
210
|
+
end
|
|
211
|
+
klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
|
|
212
|
+
def #{method_name}(#{MemoWise::InternalAPI.args_str(method)})
|
|
213
|
+
_memo_wise_hash = (@_memo_wise[:#{method_name}] ||= {})
|
|
214
|
+
#{layers.join("\n ")}
|
|
215
|
+
end
|
|
216
|
+
HEREDOC
|
|
217
|
+
when MemoWise::InternalAPI::SPLAT_AND_DOUBLE_SPLAT
|
|
218
|
+
# When we have both *args and **kwargs, we store the memoized values in a deeply nested hash, like:
|
|
219
|
+
# { method_name: { args => { kwargs => memoized_value } } }
|
|
220
|
+
klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
|
|
221
|
+
def #{method_name}(*args, **kwargs)
|
|
222
|
+
_memo_wise_hash = (@_memo_wise[:#{method_name}] ||= {})
|
|
223
|
+
_memo_wise_kwargs_hash = _memo_wise_hash.fetch(args) do
|
|
224
|
+
_memo_wise_hash[args] = {}
|
|
225
|
+
end
|
|
226
|
+
_memo_wise_kwargs_hash.fetch(kwargs) do
|
|
227
|
+
_memo_wise_kwargs_hash[kwargs] = #{original_memo_wised_name}(#{MemoWise::InternalAPI.call_str(method)})
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
HEREDOC
|
|
231
|
+
else # MemoWise::InternalAPI::SPLAT, MemoWise::InternalAPI::DOUBLE_SPLAT
|
|
201
232
|
klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
|
|
202
233
|
def #{method_name}(#{MemoWise::InternalAPI.args_str(method)})
|
|
203
234
|
_memo_wise_hash = (@_memo_wise[:#{method_name}] ||= {})
|
|
@@ -430,12 +461,23 @@ module MemoWise
|
|
|
430
461
|
when MemoWise::InternalAPI::SPLAT then hash[args] = yield
|
|
431
462
|
when MemoWise::InternalAPI::DOUBLE_SPLAT then hash[kwargs] = yield
|
|
432
463
|
when MemoWise::InternalAPI::MULTIPLE_REQUIRED
|
|
433
|
-
|
|
434
|
-
|
|
464
|
+
n_parameters = method.parameters.size
|
|
465
|
+
method.parameters.each_with_index do |(type, name), index|
|
|
466
|
+
val = type == :req ? args[index] : kwargs[name]
|
|
467
|
+
|
|
468
|
+
# Walk through the layers of nested hashes. When we get to the final
|
|
469
|
+
# layer, yield to the block to set its value.
|
|
470
|
+
if index < n_parameters - 1
|
|
471
|
+
hash = (hash[val] ||= {})
|
|
472
|
+
else
|
|
473
|
+
hash[val] = yield
|
|
474
|
+
end
|
|
435
475
|
end
|
|
436
|
-
hash[key] = yield
|
|
437
476
|
else # MemoWise::InternalAPI::SPLAT_AND_DOUBLE_SPLAT
|
|
438
|
-
|
|
477
|
+
# When we have both *args and **kwargs, we store the memoized values like:
|
|
478
|
+
# { method_name: { args => { kwargs => memoized_value } } }
|
|
479
|
+
# so we need to initialize `hash[args]`` if it does not already exist.
|
|
480
|
+
(hash[args] ||= {})[kwargs] = yield
|
|
439
481
|
end
|
|
440
482
|
end
|
|
441
483
|
|
|
@@ -530,15 +572,26 @@ module MemoWise
|
|
|
530
572
|
when MemoWise::InternalAPI::ONE_REQUIRED_KEYWORD then method_hash&.delete(kwargs.first.last)
|
|
531
573
|
when MemoWise::InternalAPI::SPLAT then method_hash&.delete(args)
|
|
532
574
|
when MemoWise::InternalAPI::DOUBLE_SPLAT then method_hash&.delete(kwargs)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
575
|
+
when MemoWise::InternalAPI::SPLAT_AND_DOUBLE_SPLAT
|
|
576
|
+
# Here, memoized values are stored like:
|
|
577
|
+
# { method_name: { args => { kwargs => memoized_value } } }
|
|
578
|
+
# so we need to delete the innermost value (because the same args array
|
|
579
|
+
# may have multiple memoized values for different kwargs hashes).
|
|
580
|
+
method_hash&.[](args)&.delete(kwargs)
|
|
581
|
+
else # MemoWise::InternalAPI::MULTIPLE_REQUIRED
|
|
582
|
+
n_parameters = method.parameters.size
|
|
583
|
+
method.parameters.each_with_index do |(type, name), index|
|
|
584
|
+
val = type == :req ? args[index] : kwargs[name]
|
|
585
|
+
|
|
586
|
+
# Walk through the layers of nested hashes. When we get to the final
|
|
587
|
+
# layer, delete its value. We use the safe navigation operator to
|
|
588
|
+
# gracefully handle any layer not yet existing.
|
|
589
|
+
if index < n_parameters - 1
|
|
590
|
+
method_hash = method_hash&.[](val)
|
|
591
|
+
else
|
|
592
|
+
method_hash&.delete(val)
|
|
593
|
+
end
|
|
594
|
+
end
|
|
542
595
|
end
|
|
543
596
|
end
|
|
544
597
|
end
|
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: 1.
|
|
4
|
+
version: 1.7.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: 2022-
|
|
14
|
+
date: 2022-04-04 00:00:00.000000000 Z
|
|
15
15
|
dependencies: []
|
|
16
16
|
description:
|
|
17
17
|
email:
|
|
@@ -70,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
70
70
|
- !ruby/object:Gem::Version
|
|
71
71
|
version: '0'
|
|
72
72
|
requirements: []
|
|
73
|
-
rubygems_version: 3.3.
|
|
73
|
+
rubygems_version: 3.3.7
|
|
74
74
|
signing_key:
|
|
75
75
|
specification_version: 4
|
|
76
76
|
summary: The wise choice for Ruby memoization
|