brew icon indicating copy to clipboard operation
brew copied to clipboard

Add `Cached` module to simplify caching code.

Open reitermarkus opened this issue 4 months ago • 6 comments

  • [x] Have you followed the guidelines in our Contributing document?
  • [x] Have you checked to ensure there aren't other open Pull Requests for the same change?
  • [x] Have you added an explanation of what your changes do and why you'd like us to include them?
  • [ ] Have you written new tests for your changes? Here's an example.
  • [x] Have you successfully run brew style with your changes locally?
  • [x] Have you successfully run brew typecheck with your changes locally?
  • [x] Have you successfully run brew tests with your changes locally?

Also added a separate version of Cachable#cache which takes a block and automatically freezes the cached value.

reitermarkus avatar Feb 15 '24 20:02 reitermarkus

I'm not sure that it's intuitive to include and extend the same module in different places in the codebase especially if we're planning on doing both in the same class. It might be worth thinking up some way of differentiating the instance cache from the class/module cache.

Interestingly enough we do have this pattern in a few places in the codebase but it's never truly an instance cache.

$ cd $(brew --repo)
$ git grep --no-index -C 4 'include Cachable'
Library/Homebrew/api/cask.rb-    #
Library/Homebrew/api/cask.rb-    # @api private
Library/Homebrew/api/cask.rb-    module Cask
Library/Homebrew/api/cask.rb-      class << self
Library/Homebrew/api/cask.rb:        include Cachable
Library/Homebrew/api/cask.rb-
Library/Homebrew/api/cask.rb-        private :cache
Library/Homebrew/api/cask.rb-
Library/Homebrew/api/cask.rb-        sig { params(token: String).returns(Hash) }
--
Library/Homebrew/api/formula.rb-    #
Library/Homebrew/api/formula.rb-    # @api private
Library/Homebrew/api/formula.rb-    module Formula
Library/Homebrew/api/formula.rb-      class << self
Library/Homebrew/api/formula.rb:        include Cachable
Library/Homebrew/api/formula.rb-
Library/Homebrew/api/formula.rb-        private :cache
Library/Homebrew/api/formula.rb-
Library/Homebrew/api/formula.rb-        sig { params(name: String).returns(Hash) }
--
Library/Homebrew/readall.rb-#
Library/Homebrew/readall.rb-# @api private
Library/Homebrew/readall.rb-module Readall
Library/Homebrew/readall.rb-  class << self
Library/Homebrew/readall.rb:    include Cachable
Library/Homebrew/readall.rb-    include SystemCommand::Mixin
Library/Homebrew/readall.rb-
Library/Homebrew/readall.rb-    # TODO: remove this once the `MacOS` module is undefined on Linux
Library/Homebrew/readall.rb-    MACOS_MODULE_REGEX = /\b(MacOS|OS::Mac)(\.|::)\b/

apainintheneck avatar Feb 16 '24 04:02 apainintheneck

not sure that it's intuitive to include and extend the same module

I disagree, that's just how Ruby works, but it is actually quite surprising that all existing usages so far are class-level caches.

reitermarkus avatar Feb 16 '24 07:02 reitermarkus

not sure that it's intuitive to include and extend the same module

I disagree, that's just how Ruby works, but it is actually quite surprising that all existing usages so far are class-level caches.

Fair enough. Maybe I'm overthinking this.

apainintheneck avatar Feb 17 '24 18:02 apainintheneck

There are a few places in the code that use cache.fetch(:key) { logic } and those can probably be cleaned up after this change too.

apainintheneck avatar Feb 17 '24 23:02 apainintheneck

restrict this to methods without arguments with method.arity.zero?

I tried this in the beginning, but that actually only works when not using Sorbet at runtime because Sorbet will always wrap all methods with *args.

reitermarkus avatar Feb 23 '24 12:02 reitermarkus

restrict this to methods without arguments with method.arity.zero?

I tried this in the beginning, but that actually only works when not using Sorbet at runtime because Sorbet will always wrap all methods with *args.

Lovely... it sometimes feels like I'm fighting Sorbet when I propose generic solutions.

apainintheneck avatar Feb 24 '24 04:02 apainintheneck

I'll throw another tangentially related idea out there. Maybe it'd be good to somehow programmatically collect all classes and modules that mix in Cachable and then clear those caches in-between tests. That would make it harder to forget to clear the cache of some module. This probably doesn't need to happen at the instance level though. To be clear, I'm not suggesting that this should be included in this PR. I'm just thinking out loud.

apainintheneck avatar Feb 25 '24 18:02 apainintheneck

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

github-actions[bot] avatar Mar 18 '24 00:03 github-actions[bot]

Passing on this, sorry.

MikeMcQuaid avatar Mar 18 '24 12:03 MikeMcQuaid