From d62154057bffd2f2f0da62fb0a5e1ba727620f07 Mon Sep 17 00:00:00 2001 From: Jacob Evelyn Date: Tue, 17 Jan 2023 15:21:39 -0500 Subject: [PATCH] Update benchmark gems and test on Ruby 3.2 --- .github/workflows/main.yml | 14 +++---- .ruby-version | 2 +- CHANGELOG.md | 4 +- Gemfile | 4 +- Gemfile.lock | 34 ++++++++-------- README.md | 42 ++++++++++---------- benchmarks/Gemfile | 6 +-- lib/memo_wise.rb | 13 +++--- spec/memo_wise_spec.rb | 3 +- spec/prepending_initializer_spec.rb | 6 +-- spec/proxying_original_method_params_spec.rb | 2 +- 11 files changed, 67 insertions(+), 63 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6df000a3..b9a9c62c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: matrix: # Due to https://github.com/actions/runner/issues/849, we have to use # quotes for '3.0' -- without quotes, CI sees '3' and runs the latest. - ruby: [2.4, 2.5, 2.6, 2.7, '3.0', 3.1, jruby, truffleruby-head] + ruby: [2.4, 2.5, 2.6, 2.7, '3.0', 3.1, 3.2, jruby, truffleruby-head] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -24,7 +24,7 @@ jobs: - name: Set bundler environment variables run: | echo "BUNDLE_WITHOUT=checks:docs" >> $GITHUB_ENV - if: matrix.ruby != 3.1 + if: matrix.ruby != 3.2 # Use 'bundler-cache: true' instead of actions/cache as advised: # * https://github.com/actions/cache/blob/main/examples.md#ruby---bundler @@ -40,18 +40,18 @@ jobs: files: ./coverage/coverage.xml fail_ci_if_error: true # optional (default = false) verbose: true # optional (default = false) - if: matrix.ruby == 3.1 + if: matrix.ruby == 3.2 - run: bundle exec rubocop - if: matrix.ruby == 3.1 + if: matrix.ruby == 3.2 - run: | bundle exec yard doctest bundle exec dokaz - if: matrix.ruby == 3.1 + if: matrix.ruby == 3.2 - - name: Run benchmarks on Ruby 2.7 or 3.1 + - name: Run benchmarks on Ruby 2.7 or 3.2 run: | BUNDLE_GEMFILE=benchmarks/Gemfile bundle install --jobs 4 --retry 3 BUNDLE_GEMFILE=benchmarks/Gemfile bundle exec ruby benchmarks/benchmarks.rb - if: matrix.ruby == '2.7' || matrix.ruby == '3.1' + if: matrix.ruby == '2.7' || matrix.ruby == '3.2' diff --git a/.ruby-version b/.ruby-version index ef538c28..e4604e3a 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.1.2 +3.2.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 572a4ae2..c03d8472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,9 @@ _No breaking changes!_ **Project enhancements:** -- Updated benchmark results in `README.md` to Ruby 3.1.2 and 2.7.6 +- Updated benchmark results in `README.md` to Ruby 3.2.1 and 2.7.7 +- Updated `Dry::Core` gem version to 1.0.0 in benchmarks +- Updated `Memery` gem version to 1.4.1 in benchmarks - Updated `Memoized` gem version to 1.1.1 in benchmarks - Reorganized `CHANGELOG.md` for improved clarity and completeness [[#282](https://github.com/panorama-ed/memo_wise/pull/282)] diff --git a/Gemfile b/Gemfile index 4cb64584..11a812c2 100644 --- a/Gemfile +++ b/Gemfile @@ -24,8 +24,8 @@ end # Excluded from CI except on latest MRI Ruby, to reduce compatibility burden group :docs do - gem "dokaz" - gem "redcarpet", "~> 3.5" + gem "dokaz", "~> 0.0.5" + gem "redcarpet", "~> 3.6" gem "yard", "~> 0.9" gem "yard-doctest", "~> 0.1" end diff --git a/Gemfile.lock b/Gemfile.lock index c1171251..eb3a6310 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,23 +30,24 @@ GEM concurrent-ruby (1.1.9) diff-lcs (1.5.0) docile (1.4.0) - dokaz (0.0.4) + dokaz (0.0.5) ansi - rouge + rouge (~> 4) slop (~> 3) i18n (1.10.0) concurrent-ruby (~> 1.0) + json (2.6.3) minitest (5.15.0) - parallel (1.21.0) - parser (3.1.1.0) + parallel (1.22.1) + parser (3.2.0.0) ast (~> 2.4.1) rack (3.0.0) rainbow (3.1.1) rake (13.0.6) - redcarpet (3.5.1) - regexp_parser (2.2.1) + redcarpet (3.6.0) + regexp_parser (2.6.1) rexml (3.2.5) - rouge (3.28.0) + rouge (4.1.0) rspec (3.11.0) rspec-core (~> 3.11.0) rspec-expectations (~> 3.11.0) @@ -60,16 +61,17 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.11.0) rspec-support (3.11.0) - rubocop (1.25.1) + rubocop (1.43.0) + json (~> 2.3) parallel (~> 1.10) - parser (>= 3.1.0.0) + parser (>= 3.2.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.15.1, < 2.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.24.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.16.0) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.24.1) parser (>= 3.1.1.0) rubocop-performance (1.13.2) rubocop (>= 1.7.0, < 2.0) @@ -95,7 +97,7 @@ GEM slop (3.6.0) tzinfo (2.0.4) concurrent-ruby (~> 1.0) - unicode-display_width (2.1.0) + unicode-display_width (2.4.2) values (1.8.0) webrick (1.7.0) yard (0.9.28) @@ -108,11 +110,11 @@ PLATFORMS ruby DEPENDENCIES - dokaz + dokaz (~> 0.0.5) memo_wise! panolint! rake - redcarpet (~> 3.5) + redcarpet (~> 3.6) rspec (~> 3.11) simplecov simplecov-cobertura diff --git a/README.md b/README.md index c399d834..e13f2294 100644 --- a/README.md +++ b/README.md @@ -114,36 +114,36 @@ For more usage details, see our detailed [documentation](#documentation). 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). -Results using Ruby 3.1.2: +Results using Ruby 3.2.1: -|Method arguments|`Dry::Core`\* (0.7.1)|`Memery` (1.4.0)| +|Method arguments|`Dry::Core`\* (1.0.0)|`Memery` (1.4.1)| |--|--|--| -|`()` (none)|1.14x|13.06x| -|`(a)`|1.22x|7.24x| -|`(a, b)`|1.17x|6.79x| -|`(a:)`|1.33x|16.68x| -|`(a:, b:)`|1.24x|13.73x| -|`(a, b:)`|1.16x|13.58x| -|`(a, *args)`|0.84x|1.95x| -|`(a:, **kwargs)`|0.84x|3.41x| -|`(a, *args, b:, **kwargs)`|0.75x|2.08x| +|`()` (none)|0.55x|3.66x| +|`(a)`|1.55x|8.09x| +|`(a, b)`|1.21x|6.09x| +|`(a:)`|1.42x|13.29x| +|`(a:, b:)`|1.17x|10.04x| +|`(a, b:)`|1.18x|10.32x| +|`(a, *args)`|0.78x|1.54x| +|`(a:, **kwargs)`|0.80x|2.22x| +|`(a, *args, b:, **kwargs)`|0.71x|1.38x| \* `Dry::Core` [may cause incorrect behavior caused by hash collisions](https://github.com/dry-rb/dry-core/issues/63). -Results using Ruby 2.7.6 (because these gems raise errors in Ruby 3.x): +Results using Ruby 2.7.7 (because these gems raise errors in Ruby 3.x): |Method arguments|`DDMemoize` (1.0.0)|`Memoist` (0.16.2)|`Memoized` (1.1.1)|`Memoizer` (1.0.3)| |--|--|--|--|--| -|`()` (none)|24.72x|2.36x|27.25x|2.88x| -|`(a)`|22.13x|14.22x|23.37x|12.54x| -|`(a, b)`|17.70x|12.04x|17.69x|10.66x| -|`(a:)`|31.24x|24.94x|26.47x|22.97x| -|`(a:, b:)`|25.76x|20.78x|21.41x|19.47x| -|`(a, b:)`|23.97x|19.53x|19.91x|18.01x| -|`(a, *args)`|3.23x|2.21x|3.34x|1.98x| -|`(a:, **kwargs)`|2.92x|2.45x|2.57x|2.24x| -|`(a, *args, b:, **kwargs)`|2.22x|1.88x|1.99x|1.78x| +|`()` (none)|23.65x|2.38x|27.26x|2.71x| +|`(a)`|22.27x|15.66x|22.82x|13.61x| +|`(a, b)`|18.72x|13.85x|18.79x|12.42x| +|`(a:)`|31.54x|25.56x|26.57x|23.88x| +|`(a:, b:)`|27.56x|22.78x|23.67x|21.43x| +|`(a, b:)`|26.16x|21.75x|22.45x|20.63x| +|`(a, *args)`|3.10x|2.32x|3.25x|2.02x| +|`(a:, **kwargs)`|2.82x|2.37x|2.59x|2.23x| +|`(a, *args, b:, **kwargs)`|2.14x|1.84x|1.97x|1.75x| You can run benchmarks yourself with: diff --git a/benchmarks/Gemfile b/benchmarks/Gemfile index 985a2daf..8bdd132e 100644 --- a/benchmarks/Gemfile +++ b/benchmarks/Gemfile @@ -4,13 +4,13 @@ source "https://rubygems.org" git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby ">= 2.7.6" +ruby ">= 2.7.7" gem "benchmark-ips", "2.10.0" if RUBY_VERSION > "3" - gem "dry-core", "0.7.1" - gem "memery", "1.4.0" + gem "dry-core", "1.0.0" + gem "memery", "1.4.1" else gem "ddmemoize", "1.0.0" gem "memoist", "0.16.2" diff --git a/lib/memo_wise.rb b/lib/memo_wise.rb index 2cbfca89..3cc94731 100644 --- a/lib/memo_wise.rb +++ b/lib/memo_wise.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true -require "set" +# Disable RuboCop here because Ruby < 3.2 does not load `set` by default. +require "set" # rubocop:disable Lint/RedundantRequireStatement require "memo_wise/internal_api" require "memo_wise/version" @@ -30,12 +31,12 @@ module MemoWise # [calling the original](https://medium.com/@jeremy_96642/ruby-method-auditing-using-module-prepend-4f4e69aacd95) # constructor. # - # - **Q:** Why is [Module#prepend](https://ruby-doc.org/core-3.1.0/Module.html#method-i-prepend) + # - **Q:** Why is [Module#prepend](https://ruby-doc.org/3.2.1/Module.html#method-i-prepend) # important here # ([more info](https://medium.com/@leo_hetsch/ruby-modules-include-vs-prepend-vs-extend-f09837a5b073))? # - **A:** To set up *mutable state* inside the instance, even if the original # constructor will then call - # [Object#freeze](https://ruby-doc.org/core-3.1.0/Object.html#method-i-freeze). + # [Object#freeze](https://ruby-doc.org/3.2.1/Object.html#method-i-freeze). # # This approach supports memoization on frozen (immutable) objects -- for # example, classes created by the @@ -84,7 +85,7 @@ def initialize(#{all_args}) # @param target [Class] # The `Class` into to prepend the MemoWise methods e.g. `memo_wise` # - # @see https://ruby-doc.org/core-3.1.0/Module.html#method-i-prepended + # @see https://ruby-doc.org/3.2.1/Module.html#method-i-prepend # # @example # class Example @@ -99,7 +100,7 @@ class << target # # This is necessary in addition to the `#initialize` method definition # above because - # [`Class#allocate`](https://ruby-doc.org/core-3.1.0/Class.html#method-i-allocate) + # [`Class#allocate`](https://ruby-doc.org/3.2.1/Class.html#method-i-allocate) # bypasses `#initialize`, and when it's used (e.g., # [in ActiveRecord](https://github.com/rails/rails/blob/a395c3a6af1e079740e7a28994d77c8baadd2a9d/activerecord/lib/active_record/persistence.rb#L411)) # we still need to be able to access MemoWise's instance variable. Despite @@ -254,7 +255,7 @@ def #{method_name}(#{MemoWise::InternalAPI.args_str(method)}) ) end - # Override [Module#instance_method](https://ruby-doc.org/core-3.1.0/Module.html#method-i-instance_method) + # Override [Module#instance_method](https://ruby-doc.org/3.2.1/Module.html#method-i-instance_method) # to proxy the original `UnboundMethod#parameters` results. We want the # parameters to reflect the original method in order to support callers # who want to use Ruby reflection to process the method parameters, diff --git a/spec/memo_wise_spec.rb b/spec/memo_wise_spec.rb index f68631c7..924f65d6 100644 --- a/spec/memo_wise_spec.rb +++ b/spec/memo_wise_spec.rb @@ -143,8 +143,7 @@ end end - shared_examples "handles memoized/non-memoized methods with the same name at different "\ - "scopes" do + shared_examples "handles memoized/non-memoized methods with the same name at different scopes" do context "with non-memoized method with same name as memoized method" do context "when methods have no arguments" do it "does not memoize the non-memoized method" do diff --git a/spec/prepending_initializer_spec.rb b/spec/prepending_initializer_spec.rb index 49c82f8e..1af01e9f 100644 --- a/spec/prepending_initializer_spec.rb +++ b/spec/prepending_initializer_spec.rb @@ -7,7 +7,7 @@ Class.new do prepend MemoWise - def initialize(arg); end + def initialize(arg); end # rubocop:disable Style/RedundantInitialize end end @@ -21,7 +21,7 @@ def initialize(arg); end Class.new do prepend MemoWise - def initialize(kwarg:); end + def initialize(kwarg:); end # rubocop:disable Style/RedundantInitialize end end @@ -35,7 +35,7 @@ def initialize(kwarg:); end Class.new do prepend MemoWise - def initialize(arg, kwarg:); end + def initialize(arg, kwarg:); end # rubocop:disable Style/RedundantInitialize end end diff --git a/spec/proxying_original_method_params_spec.rb b/spec/proxying_original_method_params_spec.rb index 9d1b0355..c0bd3558 100644 --- a/spec/proxying_original_method_params_spec.rb +++ b/spec/proxying_original_method_params_spec.rb @@ -10,7 +10,7 @@ Class.new do prepend MemoWise - def initialize(foo, bar:); end + def initialize(foo, bar:); end # rubocop:disable Style/RedundantInitialize DefineMethodsForTestingMemoWise.define_methods_for_testing_memo_wise( target: self,