memo_wise 1.6.0 → 1.8.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.
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