memo_wise 1.6.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,122 +1,109 @@
1
1
  GIT
2
- remote: https://github.com/panorama-ed/panolint.git
3
- revision: 5850a218b96da7dd196438fb65d41169cd6747e5
2
+ remote: https://github.com/panorama-ed/panolint-ruby.git
3
+ revision: a93988ea554177cf0ec9ef636c442f9d3af49a10
4
4
  branch: main
5
5
  specs:
6
- panolint (0.1.4)
7
- brakeman (>= 4.8, < 6.0)
8
- rubocop (>= 0.83, < 2.0)
9
- rubocop-performance (~> 1.5)
10
- rubocop-rails (~> 2.5)
11
- rubocop-rake (~> 0.5)
12
- rubocop-rspec (~> 2.0)
6
+ panolint-ruby (0)
7
+ rubocop (= 1.51.0)
8
+ rubocop-performance (= 1.18.0)
9
+ rubocop-rspec (= 2.22.0)
13
10
 
14
11
  PATH
15
12
  remote: .
16
13
  specs:
17
- memo_wise (1.6.0)
14
+ memo_wise (1.8.0)
18
15
 
19
16
  GEM
20
17
  remote: https://rubygems.org/
21
18
  specs:
22
- activesupport (6.1.4.1)
23
- concurrent-ruby (~> 1.0, >= 1.0.2)
24
- i18n (>= 1.6, < 2)
25
- minitest (>= 5.1)
26
- tzinfo (~> 2.0)
27
- zeitwerk (~> 2.3)
28
19
  ansi (1.5.0)
29
20
  ast (2.4.2)
30
- brakeman (5.1.2)
31
- codecov (0.6.0)
32
- simplecov (>= 0.15, < 0.22)
33
- concurrent-ruby (1.1.9)
34
- diff-lcs (1.4.4)
35
- docile (1.3.5)
36
- dokaz (0.0.4)
21
+ diff-lcs (1.5.0)
22
+ docile (1.4.0)
23
+ dokaz (0.0.5)
37
24
  ansi
38
- rouge
25
+ rouge (~> 4)
39
26
  slop (~> 3)
40
- i18n (1.8.11)
41
- concurrent-ruby (~> 1.0)
42
- minitest (5.14.4)
43
- parallel (1.21.0)
44
- parser (3.1.0.0)
27
+ json (2.6.3)
28
+ minitest (5.18.0)
29
+ parallel (1.23.0)
30
+ parser (3.2.2.1)
45
31
  ast (~> 2.4.1)
46
- rack (2.2.3)
47
- rainbow (3.0.0)
32
+ rainbow (3.1.1)
48
33
  rake (13.0.6)
49
- redcarpet (3.5.1)
50
- regexp_parser (2.2.0)
34
+ redcarpet (3.6.0)
35
+ regexp_parser (2.8.0)
51
36
  rexml (3.2.5)
52
- rouge (3.26.0)
53
- rspec (3.10.0)
54
- rspec-core (~> 3.10.0)
55
- rspec-expectations (~> 3.10.0)
56
- rspec-mocks (~> 3.10.0)
57
- rspec-core (3.10.0)
58
- rspec-support (~> 3.10.0)
59
- rspec-expectations (3.10.0)
37
+ rouge (4.1.0)
38
+ rspec (3.12.0)
39
+ rspec-core (~> 3.12.0)
40
+ rspec-expectations (~> 3.12.0)
41
+ rspec-mocks (~> 3.12.0)
42
+ rspec-core (3.12.1)
43
+ rspec-support (~> 3.12.0)
44
+ rspec-expectations (3.12.2)
60
45
  diff-lcs (>= 1.2.0, < 2.0)
61
- rspec-support (~> 3.10.0)
62
- rspec-mocks (3.10.0)
46
+ rspec-support (~> 3.12.0)
47
+ rspec-mocks (3.12.3)
63
48
  diff-lcs (>= 1.2.0, < 2.0)
64
- rspec-support (~> 3.10.0)
65
- rspec-support (3.10.0)
66
- rubocop (1.24.1)
49
+ rspec-support (~> 3.12.0)
50
+ rspec-support (3.12.0)
51
+ rubocop (1.51.0)
52
+ json (~> 2.3)
67
53
  parallel (~> 1.10)
68
- parser (>= 3.0.0.0)
54
+ parser (>= 3.2.0.0)
69
55
  rainbow (>= 2.2.2, < 4.0)
70
56
  regexp_parser (>= 1.8, < 3.0)
71
- rexml
72
- rubocop-ast (>= 1.15.1, < 2.0)
57
+ rexml (>= 3.2.5, < 4.0)
58
+ rubocop-ast (>= 1.28.0, < 2.0)
73
59
  ruby-progressbar (~> 1.7)
74
- unicode-display_width (>= 1.4.0, < 3.0)
75
- rubocop-ast (1.15.1)
76
- parser (>= 3.0.1.1)
77
- rubocop-performance (1.12.0)
60
+ unicode-display_width (>= 2.4.0, < 3.0)
61
+ rubocop-ast (1.28.1)
62
+ parser (>= 3.2.1.0)
63
+ rubocop-capybara (2.18.0)
64
+ rubocop (~> 1.41)
65
+ rubocop-factory_bot (2.23.1)
66
+ rubocop (~> 1.33)
67
+ rubocop-performance (1.18.0)
78
68
  rubocop (>= 1.7.0, < 2.0)
79
69
  rubocop-ast (>= 0.4.0)
80
- rubocop-rails (2.12.4)
81
- activesupport (>= 4.2.0)
82
- rack (>= 1.1)
83
- rubocop (>= 1.7.0, < 2.0)
84
- rubocop-rake (0.6.0)
85
- rubocop (~> 1.0)
86
- rubocop-rspec (2.6.0)
87
- rubocop (~> 1.19)
88
- ruby-progressbar (1.11.0)
89
- simplecov (0.18.5)
70
+ rubocop-rspec (2.22.0)
71
+ rubocop (~> 1.33)
72
+ rubocop-capybara (~> 2.17)
73
+ rubocop-factory_bot (~> 2.22)
74
+ ruby-progressbar (1.13.0)
75
+ simplecov (0.22.0)
90
76
  docile (~> 1.1)
91
77
  simplecov-html (~> 0.11)
78
+ simplecov_json_formatter (~> 0.1)
79
+ simplecov-cobertura (2.1.0)
80
+ rexml
81
+ simplecov (~> 0.19)
92
82
  simplecov-html (0.12.3)
83
+ simplecov_json_formatter (0.1.4)
93
84
  slop (3.6.0)
94
- tzinfo (2.0.4)
95
- concurrent-ruby (~> 1.0)
96
- unicode-display_width (2.1.0)
85
+ unicode-display_width (2.4.2)
97
86
  values (1.8.0)
98
- webrick (1.7.0)
99
- yard (0.9.27)
100
- webrick (~> 1.7.0)
87
+ yard (0.9.34)
101
88
  yard-doctest (0.1.17)
102
89
  minitest
103
90
  yard
104
- zeitwerk (2.5.1)
105
91
 
106
92
  PLATFORMS
107
93
  ruby
108
94
 
109
95
  DEPENDENCIES
110
- codecov
111
- dokaz
96
+ dokaz (~> 0.0.5)
112
97
  memo_wise!
113
- panolint!
98
+ panolint-ruby!
114
99
  rake
115
- redcarpet (~> 3.5)
116
- rspec (~> 3.10)
100
+ redcarpet (~> 3.6)
101
+ rspec (~> 3.12)
102
+ simplecov
103
+ simplecov-cobertura
117
104
  values (~> 1)
118
105
  yard (~> 0.9)
119
106
  yard-doctest (~> 0.1)
120
107
 
121
108
  BUNDLED WITH
122
- 2.2.32
109
+ 2.3.8
data/README.md CHANGED
@@ -6,9 +6,8 @@
6
6
  # `MemoWise`
7
7
 
8
8
  [![Tests](https://github.com/panorama-ed/memo_wise/workflows/Main/badge.svg)](https://github.com/panorama-ed/memo_wise/actions?query=workflow%3AMain)
9
- [![Code Coverage](https://codecov.io/gh/panorama-ed/memo_wise/branch/main/graph/badge.svg)](https://codecov.io/gh/panorama-ed/memo_wise/branches/main)
10
- [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/panorama-ed/memo_wise)
11
- [![Inline docs](http://inch-ci.org/github/panorama-ed/memo_wise.svg?branch=main)](http://inch-ci.org/github/panorama-ed/memo_wise)
9
+ [![Code Coverage](https://codecov.io/gh/panorama-ed/memo_wise/branch/main/graph/badge.svg)](https://codecov.io/gh/panorama-ed/memo_wise)
10
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/gems/memo_wise)
12
11
  [![Gem Version](https://img.shields.io/gem/v/memo_wise.svg)](https://rubygems.org/gems/memo_wise)
13
12
  [![Gem Downloads](https://img.shields.io/gem/dt/memo_wise.svg)](https://rubygems.org/gems/memo_wise)
14
13
 
@@ -113,38 +112,38 @@ For more usage details, see our detailed [documentation](#documentation).
113
112
 
114
113
  ## Benchmarks
115
114
 
116
- 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).
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.11.0).
117
116
 
118
- Results using Ruby 3.1.0:
117
+ Results using Ruby 3.2.2:
119
118
 
120
- |Method arguments|`Dry::Core` (0.7.1)|`Memery` (1.4.0)|
119
+ |Method arguments|`Dry::Core`\* (1.0.1)|`Memery` (1.5.0)|
121
120
  |--|--|--|
122
- |`()` (none)|1.09x|11.80x|
123
- |`(a)`|1.64x|9.74x|
124
- |`(a, b)`|0.34x|2.00x|
125
- |`(a:)`|1.49x|18.84x|
126
- |`(a:, b:)`|0.35x|4.26x|
127
- |`(a, b:)`|0.35x|4.18x|
128
- |`(a, *args)`|0.83x|1.89x|
129
- |`(a:, **kwargs)`|0.84x|3.30x|
130
- |`(a, *args, b:, **kwargs)`|0.54x|1.47x|
121
+ |`()` (none)|0.54x|3.62x|
122
+ |`(a)`|1.54x|7.74x|
123
+ |`(a, b)`|1.29x|5.58x|
124
+ |`(a:)`|1.55x|12.37x|
125
+ |`(a:, b:)`|1.15x|8.76x|
126
+ |`(a, b:)`|1.15x|8.75x|
127
+ |`(a, *args)`|0.84x|1.54x|
128
+ |`(a:, **kwargs)`|0.79x|2.13x|
129
+ |`(a, *args, b:, **kwargs)`|0.69x|1.38x|
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).
134
133
 
135
- Results using Ruby 2.7.5 (because these gems raise errors in Ruby 3.x):
134
+ Results using Ruby 2.7.8 (because these gems raise errors in Ruby 3.x):
136
135
 
137
- |Method arguments|`DDMemoize` (1.0.0)|`Memoist` (0.16.2)|`Memoized` (1.0.2)|`Memoizer` (1.0.3)|
136
+ |Method arguments|`DDMemoize` (1.0.0)|`Memoist` (0.16.2)|`Memoized` (1.1.1)|`Memoizer` (1.0.3)|
138
137
  |--|--|--|--|--|
139
- |`()` (none)|24.30x|2.57x|1.19x|2.98x|
140
- |`(a)`|21.68x|14.63x|11.13x|12.71x|
141
- |`(a, b)`|3.18x|2.36x|1.86x|2.06x|
142
- |`(a:)`|30.62x|24.52x|21.44x|22.61x|
143
- |`(a:, b:)`|5.25x|4.40x|3.80x|4.04x|
144
- |`(a, b:)`|4.91x|4.06x|3.55x|3.83x|
145
- |`(a, *args)`|3.10x|2.31x|1.96x|1.98x|
146
- |`(a:, **kwargs)`|2.87x|2.40x|2.09x|2.20x|
147
- |`(a, *args, b:, **kwargs)`|2.08x|1.82x|1.67x|1.70x|
138
+ |`()` (none)|24.22x|2.42x|26.43x|2.70x|
139
+ |`(a)`|22.08x|15.19x|22.03x|13.67x|
140
+ |`(a, b)`|19.12x|14.01x|18.60x|12.80x|
141
+ |`(a:)`|30.21x|24.29x|26.43x|23.11x|
142
+ |`(a:, b:)`|27.73x|22.97x|25.11x|21.89x|
143
+ |`(a, b:)`|26.87x|22.76x|23.71x|21.26x|
144
+ |`(a, *args)`|3.15x|2.30x|3.18x|2.11x|
145
+ |`(a:, **kwargs)`|2.89x|2.40x|2.69x|2.28x|
146
+ |`(a, *args, b:, **kwargs)`|2.12x|1.82x|1.96x|1.74x|
148
147
 
149
148
  You can run benchmarks yourself with:
150
149
 
@@ -181,7 +180,7 @@ versions:
181
180
 
182
181
  We maintain API documentation using [YARD](https://yardoc.org/), which is
183
182
  published automatically at
184
- [RubyDoc.info](https://rubydoc.info/github/panorama-ed/memo_wise/MemoWise). To
183
+ [RubyDoc.info](https://rubydoc.info/gems/memo_wise). To
185
184
  edit documentation locally and see it rendered in your browser, run:
186
185
 
187
186
  ```bash
@@ -236,7 +235,7 @@ And we've written more about `MemoWise` in a series of blog posts:
236
235
 
237
236
  - [Introducing: MemoWise](https://medium.com/building-panorama-education/introducing-memowise-51a5f0523489)
238
237
  - [Optimizing MemoWise Performance](https://ja.cob.land/optimizing-memowise-performance)
239
- - [Esosteric Ruby in MemoWise](https://jemma.dev/blog/esoteric-ruby-in-memowise)
238
+ - [Esoteric Ruby in MemoWise](https://jemma.dev/blog/esoteric-ruby-in-memowise)
240
239
 
241
240
  ## Logo
242
241
 
@@ -267,9 +266,16 @@ Then carry out these steps:
267
266
 
268
267
  1. Update `CHANGELOG.md`:
269
268
  - Add an entry for the upcoming version _x.y.z_
270
- - Add a link for this version's comparison to the bottom of `CHANGELOG.md`
271
269
  - Move content from _Unreleased_ to the upcoming version _x.y.z_
272
- - Change _Unreleased_ section to say `- Nothing yet!`
270
+ - Update the diff links for this version and _Unreleased_ in `CHANGELOG.md`
271
+ - Change _Unreleased_ section to say:
272
+ ```
273
+ **Gem enhancements:** none
274
+
275
+ _No breaking changes!_
276
+
277
+ **Project enhancements:** none
278
+ ```
273
279
  - Commit with title `Update CHANGELOG.md for x.y.z`
274
280
 
275
281
  2. Update `lib/memo_wise/version.rb`
data/benchmarks/Gemfile CHANGED
@@ -2,18 +2,20 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- ruby ">= 2.7.5"
5
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
6
6
 
7
- gem "benchmark-ips", "2.9.2"
7
+ ruby ">= 2.7.7"
8
+
9
+ gem "benchmark-ips", "2.12.0"
8
10
 
9
11
  if RUBY_VERSION > "3"
10
- gem "dry-core", "0.7.1"
11
- gem "memery", "1.4.0"
12
+ gem "dry-core", "1.0.1"
13
+ gem "memery", "1.5.0"
12
14
  else
13
15
  gem "ddmemoize", "1.0.0"
14
16
  gem "memoist", "0.16.2"
15
- gem "memoized", "1.0.2"
17
+ gem "memoized", "1.1.1"
16
18
  gem "memoizer", "1.0.3"
17
19
  end
18
20
 
19
- gem "memo_wise", path: ".."
21
+ gem "memo_wise", github: "panorama-ed/memo_wise", branch: "main"
@@ -3,7 +3,26 @@
3
3
  require "benchmark/ips"
4
4
 
5
5
  require "tempfile"
6
- require "memo_wise"
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,11 +207,11 @@ 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|
194
- x.config(suite: suite) # rubocop:disable Style/HashSyntax
214
+ x.config(suite: suite)
195
215
  BENCHMARK_GEMS.each do |benchmark_gem|
196
216
  instance = Object.const_get("#{benchmark_gem.klass}Example").new
197
217
 
@@ -203,42 +223,52 @@ benchmark_lambdas.map do |benchmark|
203
223
  end
204
224
 
205
225
  JSON.parse(json_file.read)
206
- end.each_with_index do |benchmark_json, i|
207
- # We print a comparison table after we run each benchmark to copy into our
208
- # README.md
209
-
210
- # MemoWise will not appear in the comparison table, but we will use it to
211
- # compare against other gems' benchmarks
212
- memo_wise = benchmark_json.find { _1["name"].include?("MemoWise") }
213
- benchmark_json.delete(memo_wise)
214
-
215
- # Sort benchmarks by gem name to alphabetize our final output table.
216
- benchmark_json.sort_by! { _1["name"] }
217
-
218
- # Print headers based on the first benchmark_json
219
- if i.zero?
220
- benchmark_headers = benchmark_json.map do |benchmark_gem|
221
- # Gem name is of the form:
222
- # "MemoWise (1.1.0): ()"
223
- # We use this mapping to get a header of the form
224
- # "`MemoWise` (1.1.0)
225
- gem_name_parts = benchmark_gem["name"].split
226
- "`#{gem_name_parts[0]}` #{gem_name_parts[1][...-1]}"
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
- puts "|Method arguments|#{benchmark_headers}|"
229
- puts "#{'|--' * (benchmark_json.size + 1)}|"
267
+
268
+ name = memo_wise["name"].partition(": ").last
269
+ puts "|`#{name}`#{' (none)' if name == '()'}|#{output_str}|"
230
270
  end
231
271
 
232
- output_str = benchmark_json.map do |bgem|
233
- # "%.2f" % 12.345 => "12.34" (instead of "12.35")
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
- # # Surprisingly, 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, ... }
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
@@ -129,18 +126,7 @@ module MemoWise
129
126
  def self.original_class_from_singleton(klass)
130
127
  raise ArgumentError, "Must be a singleton class: #{klass.inspect}" unless klass.singleton_class?
131
128
 
132
- # Since we call this method a lot, we memoize the results. This can have a
133
- # huge impact; for example, in our test suite this drops our test times
134
- # from over five minutes to just a few seconds.
135
- @original_class_from_singleton ||= {}
136
-
137
- # Search ObjectSpace
138
- # * 1:1 relationship of singleton class to original class is documented
139
- # * Performance concern: searches all Class objects
140
- # But, only runs at load time and results are memoized
141
- @original_class_from_singleton[klass] ||= ObjectSpace.each_object(Module).find do |cls|
142
- cls.singleton_class == klass
143
- end
129
+ find_attached_object(klass)
144
130
  end
145
131
 
146
132
  # Convention we use for renaming the original method when we replace with
@@ -211,5 +197,42 @@ module MemoWise
211
197
  end
212
198
  end
213
199
  private_class_method :target_class
200
+
201
+ if Module.singleton_class.respond_to?(:attached_object)
202
+ # In Ruby3.2+, for singleton classes, `#attached_object` returns the object this class is for
203
+ # https://bugs.ruby-lang.org/issues/12084
204
+ #
205
+ # @param klass [Class]
206
+ # Singleton class to find the original class of
207
+ #
208
+ # @return Class
209
+ # Original class for which `klass` is the singleton class.
210
+ def self.find_attached_object(klass)
211
+ klass.attached_object
212
+ end
213
+ else
214
+ # :nocov:
215
+ # @param klass [Class]
216
+ # Singleton class to find the original class of
217
+ #
218
+ # @return Class
219
+ # Original class for which `klass` is the singleton class.
220
+ def self.find_attached_object(klass)
221
+ # Since we call this method a lot, we memoize the results. This can have a
222
+ # huge impact; for example, in our test suite this drops our test times
223
+ # from over five minutes to just a few seconds.
224
+ @original_class_from_singleton ||= {}
225
+
226
+ # Search ObjectSpace
227
+ # * 1:1 relationship of singleton class to original class is documented
228
+ # * Performance concern: searches all Class objects
229
+ # But, only runs at load time and results are memoized
230
+ @original_class_from_singleton[klass] ||= ObjectSpace.each_object(Module).find do |cls|
231
+ cls.singleton_class == klass
232
+ end
233
+ end
234
+ # :nocov:
235
+ end
236
+ private_class_method :find_attached_object
214
237
  end
215
238
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MemoWise
4
- VERSION = "1.6.0"
4
+ VERSION = "1.8.0"
5
5
  end