cache_keeper 0.3.0 → 0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 167f1cc0d9fdfca15b5882a90dde733b9d74b65f3adfad47f71ef34606b6e9d0
4
- data.tar.gz: 278285596e0e0bdcbab9a687c07244c0c2f57d19e588b275ccb3e3281a8f3f78
3
+ metadata.gz: bc9efe0608912e0c97f6f89659ad73e64588e33eb384701afe0c52afb981c568
4
+ data.tar.gz: 22b645e8a15de837f4d72de70bc64a1d966c9ce96f9ada07a6fb2f7ba6a0d32f
5
5
  SHA512:
6
- metadata.gz: 62d8e87244040101cb4f345c1e11a6b857c23bd7d7074877e0358d18e44c8acf7b76182ce0a922fa2998699ea74ede71484430c4f701cd12978710e7420b3022
7
- data.tar.gz: 72a3207e7df9c92dcaf5764ba3055bed5cba3e943c406f824e6087d741c245301b7b11f05c00091cd8c77ed6a5739e31a843134f08d6856f9d677ee54a2f645d
6
+ metadata.gz: e60f463b994d17a08f047cd00cd7ef7114940cf5458a6c42d25efacf1968d93a01b2b9cbd6c1bad23252a9b357f88cae5909b291b24756a566ebe95efb0cf578
7
+ data.tar.gz: 25e87146ea75af98f0112aa8ba6acb730d6314962357589e4b8c0a540a728e9e59c2ebecb4764612f1eba375a6ad45069686ad5e3934bec05cbe31781522eee6
@@ -4,13 +4,20 @@ jobs:
4
4
  tests:
5
5
  strategy:
6
6
  matrix:
7
- ruby-version:
8
- - "2.7"
9
- - "3.0"
10
7
  rails-version:
11
8
  - "6.1"
12
9
  - "7.0"
10
+ - "7.1"
13
11
  - "main"
12
+ include:
13
+ - rails-version: "6.1"
14
+ ruby-version: "2.5"
15
+ - rails-version: "7.0"
16
+ ruby-version: "2.7"
17
+ - rails-version: "7.1"
18
+ ruby-version: "2.7"
19
+ - rails-version: "main"
20
+ ruby-version: "3.2"
14
21
 
15
22
  env:
16
23
  RAILS_VERSION: "${{ matrix.rails-version }}"
data/.gitignore CHANGED
@@ -1,5 +1,7 @@
1
1
  *.gem
2
+ Gemfile.lock
2
3
  .byebug_history
4
+ TAGS
3
5
 
4
6
  test/dummy/db/*.sqlite3
5
7
  test/dummy/db/*.sqlite3*
data/.rubocop.yml ADDED
@@ -0,0 +1,122 @@
1
+ require:
2
+ - rubocop-rails
3
+ - rubocop-performance
4
+
5
+ AllCops:
6
+ Exclude:
7
+ - '**/db/**/*'
8
+ - '**/config/**/*'
9
+ - '**/tmp/**/*'
10
+ - '**/templates/**/*'
11
+ - '**/vendor/**/*'
12
+ - '**/node_modules/**/*'
13
+ TargetRubyVersion: 3.2.2
14
+
15
+ # Relaxed Ruby Style
16
+ Style/Alias:
17
+ Enabled: false
18
+ StyleGuide: https://relaxed.ruby.style/#stylealias
19
+
20
+ Style/AsciiComments:
21
+ Enabled: false
22
+ StyleGuide: https://relaxed.ruby.style/#styleasciicomments
23
+
24
+ Style/BeginBlock:
25
+ Enabled: false
26
+ StyleGuide: https://relaxed.ruby.style/#stylebeginblock
27
+
28
+ Style/BlockDelimiters:
29
+ Enabled: false
30
+ StyleGuide: https://relaxed.ruby.style/#styleblockdelimiters
31
+
32
+ Style/Documentation:
33
+ Enabled: false
34
+ StyleGuide: https://relaxed.ruby.style/#styledocumentation
35
+
36
+ Style/EndBlock:
37
+ Enabled: false
38
+ StyleGuide: https://relaxed.ruby.style/#styleendblock
39
+
40
+ Style/GuardClause:
41
+ Enabled: false
42
+
43
+ Style/IfUnlessModifier:
44
+ Enabled: false
45
+ StyleGuide: https://relaxed.ruby.style/#styleifunlessmodifier
46
+
47
+ Style/ModuleFunction:
48
+ Enabled: false
49
+ StyleGuide: https://relaxed.ruby.style/#stylemodulefunction
50
+
51
+ Style/MultilineBlockChain:
52
+ Enabled: false
53
+ StyleGuide: https://relaxed.ruby.style/#stylemultilineblockchain
54
+
55
+ Style/NegatedIf:
56
+ Enabled: false
57
+ StyleGuide: https://relaxed.ruby.style/#stylenegatedif
58
+
59
+ Style/NegatedWhile:
60
+ Enabled: false
61
+ StyleGuide: https://relaxed.ruby.style/#stylenegatedwhile
62
+
63
+ Style/NumericPredicate:
64
+ Enabled: false
65
+ StyleGuide: https://relaxed.ruby.style/#stylenumericpredicate
66
+
67
+ Style/PercentLiteralDelimiters:
68
+ Enabled: false
69
+ StyleGuide: https://relaxed.ruby.style/#stylepercentliteraldelimiters
70
+
71
+ Style/WhileUntilModifier:
72
+ Enabled: false
73
+ StyleGuide: https://relaxed.ruby.style/#stylewhileuntilmodifier
74
+
75
+ Style/WordArray:
76
+ Enabled: false
77
+ StyleGuide: https://relaxed.ruby.style/#stylewordarray
78
+
79
+ Lint/AmbiguousRegexpLiteral:
80
+ Enabled: false
81
+ StyleGuide: https://relaxed.ruby.style/#lintambiguousregexpliteral
82
+
83
+ Lint/AssignmentInCondition:
84
+ Enabled: false
85
+ StyleGuide: https://relaxed.ruby.style/#lintassignmentincondition
86
+
87
+ Layout/LineLength:
88
+ Enabled: false
89
+
90
+ Metrics:
91
+ Enabled: false
92
+
93
+ # Custom
94
+ Performance:
95
+ Exclude:
96
+ - '**/spec/**/*'
97
+
98
+ Style/FrozenStringLiteralComment:
99
+ Enabled: false
100
+
101
+ Style/AndOr:
102
+ Enabled: true
103
+ EnforcedStyle: conditionals
104
+
105
+ Style/ClassAndModuleChildren:
106
+ Enabled: false
107
+
108
+ Style/HashSyntax:
109
+ Enabled: false
110
+
111
+ Style/MixinGrouping:
112
+ Enabled: false
113
+
114
+ Style/RegexpLiteral:
115
+ Enabled: false
116
+
117
+ Style/StringConcatenation:
118
+ Enabled: false
119
+
120
+ Style/StringLiterals:
121
+ Enabled: true
122
+ EnforcedStyle: double_quotes
data/Gemfile CHANGED
@@ -2,8 +2,22 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem "rake"
6
- gem "byebug"
5
+ rails_version = ENV.fetch("RAILS_VERSION", "7.1")
7
6
 
8
- gem "rails", ">= 6.1"
7
+ rails_constraint =
8
+ if rails_version == "main"
9
+ { github: "rails/rails" }
10
+ else
11
+ "~> #{rails_version}.0"
12
+ end
13
+
14
+ gem "rails", rails_constraint
9
15
  gem "sqlite3"
16
+
17
+ group :debug do
18
+ gem "byebug"
19
+
20
+ gem "rubocop"
21
+ gem "rubocop-performance"
22
+ gem "rubocop-rails"
23
+ end
data/README.md CHANGED
@@ -29,8 +29,22 @@ bundle add cache_keeper
29
29
  CacheKeeper provides a `caches` method that will cache the result of the methods you give it:
30
30
 
31
31
  ```ruby
32
- caches :slow_method, :really_slow_method, expires_in: 1.hour
33
- caches :incredibly_slow_method, expires_in: 2.hours, must_revalidate: true
32
+ class Recording < ApplicationRecord
33
+ caches :slow_method, :really_slow_method, expires_in: 1.hour
34
+ caches :incredibly_slow_method, expires_in: 2.hours, must_revalidate: true
35
+
36
+ def slow_method
37
+ ...
38
+ end
39
+
40
+ def really_slow_method
41
+ ...
42
+ end
43
+
44
+ def incredibly_slow_method
45
+ ...
46
+ end
47
+ end
34
48
  ```
35
49
 
36
50
  It's automatically available in your ActiveRecord models and in your controllers. You can also use it in any other class by including `CacheKeeper::Caching`.
@@ -39,13 +53,27 @@ By default, it will immediately run the method call if it hasn't been cached bef
39
53
 
40
54
  It's important to note that it will only work with methods that don't take any arguments.
41
55
 
56
+ ### Cache key
57
+
58
+ CacheKeeper will compose cache keys from the name of the method and the instance's `cache_key` if it's defined or the name of the class otherwise. You can pass a `key` option to customize the cache key if you need it. It accepts [the same values](https://guides.rubyonrails.org/caching_with_rails.html#cache-keys) as `Rails.cache.fetch`, as well as procs or lambdas in case you need access to the instance:
59
+
60
+ ```ruby
61
+ class NebulaNoodleTwister
62
+ caches :twist_noodles, :dish_of_the_day, key: ->(method_name) { [:recoding, id, method_name] }
63
+ caches :synchronize_taste_buds, key: -> { [:recoding, id, :synchronize_taste_buds] }
64
+ caches :space_soup_simulation, key: :space_soup_simulation
65
+
66
+ ...
67
+ end
68
+ ```
69
+
42
70
  ### Serialization
43
71
 
44
72
  CacheKeeper needs to pass the instance on which the cached method is called along to the refresh job. As any other job argument, ActiveJob requires it to be serializable. ActiveRecord instances are serializable by default, but controllers, POROs and other classes are not. CacheKeeper provides a `serializer` option that will work in most cases:
45
73
 
46
74
  ```ruby
47
- class Example
48
- # Generate a new instance using an empty initializer (Example.new)
75
+ class QuantumQuackerator
76
+ # Generate a new instance using an empty initializer (QuantumQuackerator.new)
49
77
  # Useful for controllers and for POROs with no arguments
50
78
  caches :slow_method, serializer: :new_instance
51
79
 
@@ -55,7 +83,7 @@ class Example
55
83
  end
56
84
  ```
57
85
 
58
- If those options don't work for you, you can always [write custom serializer](https://guides.rubyonrails.org/active_job_basics.html#serializers) for your classes.
86
+ If those options don't work for you, you can always [write custom serializers](https://guides.rubyonrails.org/active_job_basics.html#serializers) for your classes.
59
87
 
60
88
 
61
89
  ## Configuration
@@ -1,6 +1,6 @@
1
1
  module CacheKeeper::CachedMethod::Refreshable
2
2
  def refresh(target)
3
- Rails.cache.fetch(cache_key, expires_in: expires_in) do
3
+ Rails.cache.fetch(cache_key(target), expires_in: expires_in) do
4
4
  target.send alias_for_original_method
5
5
  end
6
6
  end
@@ -14,11 +14,9 @@ class CacheKeeper::CachedMethod
14
14
  :"__#{method_name}__hooked__"
15
15
  end
16
16
 
17
- def stale?
18
- cache_entry.blank? || cache_entry.expired?
19
- end
20
-
21
17
  def call(target)
18
+ cache_entry = cache_entry(target)
19
+
22
20
  if cache_entry.blank?
23
21
  refresh target
24
22
  elsif cache_entry.expired?
@@ -36,12 +34,22 @@ class CacheKeeper::CachedMethod
36
34
 
37
35
  private
38
36
 
39
- def cache_entry
40
- Rails.cache.send :read_entry, Rails.cache.send(:normalize_key, cache_key, {})
37
+ def cache_entry(target)
38
+ Rails.cache.send :read_entry, Rails.cache.send(:normalize_key, cache_key(target), {})
41
39
  end
42
40
 
43
- def cache_key
44
- ["CacheKeeper", klass, method_name]
41
+ def cache_key(target)
42
+ if options[:key].is_a?(Proc)
43
+ if options[:key].arity == 1
44
+ target.instance_exec(method_name, &options[:key])
45
+ else
46
+ target.instance_exec(&options[:key])
47
+ end
48
+ elsif options[:key].present?
49
+ options[:key]
50
+ else
51
+ target.respond_to?(:cache_key) ? ["CacheKeeper", target, method_name] : ["CacheKeeper", klass, method_name]
52
+ end
45
53
  end
46
54
 
47
55
  def expires_in
data/bin/rails CHANGED
@@ -2,12 +2,12 @@
2
2
  # This command will automatically be run when you run "rails" with Rails gems
3
3
  # installed from the root of your application.
4
4
 
5
- ENGINE_ROOT = File.expand_path('..', __dir__)
6
- APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
5
+ ENGINE_ROOT = File.expand_path("..", __dir__)
6
+ APP_PATH = File.expand_path("../test/dummy/config/application", __dir__)
7
7
 
8
8
  # Set up gems listed in the Gemfile.
9
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
10
- require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
9
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
10
+ require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
11
11
 
12
- require 'rails/all'
13
- require 'rails/engine/commands'
12
+ require "rails/all"
13
+ require "rails/engine/commands"
@@ -1,7 +1,7 @@
1
1
  module CacheKeeper
2
2
  class Configuration
3
3
  DEFAULT_MUST_REVALIDATE = false
4
- DEFAULT_QUEUES = {}
4
+ DEFAULT_QUEUES = {}.freeze
5
5
 
6
6
  def must_revalidate
7
7
  return rails_config.must_revalidate unless rails_config.must_revalidate.nil?
@@ -7,13 +7,13 @@ module CacheKeeper
7
7
  config.cache_keeper = ActiveSupport::OrderedOptions.new
8
8
  config.cache_keeper.queues = ActiveSupport::OrderedOptions.new
9
9
 
10
- initializer "cache_keeper.active_job_serializer" do |app|
10
+ initializer "cache_keeper.active_job_serializer" do
11
11
  config.to_prepare do
12
12
  Rails.application.config.active_job.custom_serializers << CacheKeeper::CachedMethodSerializer
13
13
  end
14
14
  end
15
15
 
16
- initializer "cache_keeper.caching_methods" do |app|
16
+ initializer "cache_keeper.caching_methods" do
17
17
  ActiveSupport.on_load :action_controller do
18
18
  ActionController::Base.send :include, CacheKeeper::Caching
19
19
  end
@@ -1,3 +1,3 @@
1
1
  module CacheKeeper
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -3,11 +3,12 @@ require "test_helper"
3
3
  class CacheKeeper::RefreshJobTest < ActiveSupport::TestCase
4
4
  include ActiveJob::TestHelper
5
5
 
6
- test "calls #refresh" do
6
+ test "uses the correct queue" do
7
+ CacheKeeper.configuration.queues[:refresh] = "refresh"
7
8
  recording = Recording.create(number: 5)
8
9
  cached_method = CacheKeeper.manager.cached_methods.first
9
10
 
10
- assert_performed_with(queue: :default) do
11
+ assert_performed_with(queue: "refresh") do
11
12
  CacheKeeper::RefreshJob.perform_later cached_method, recording
12
13
  end
13
14
  end
@@ -7,7 +7,7 @@ class CacheKeeper::CachedMethod::RefreshableTest < ActiveSupport::TestCase
7
7
  recording = Recording.create(number: 5)
8
8
  cached_method = CacheKeeper.manager.cached_methods.first
9
9
 
10
- assert_enqueued_with(job: CacheKeeper::RefreshJob, queue: :default) do
10
+ assert_enqueued_with(job: CacheKeeper::RefreshJob) do
11
11
  cached_method.refresh_later recording
12
12
  end
13
13
  end
@@ -2,14 +2,49 @@ require "test_helper"
2
2
 
3
3
  class CacheKeeper::CachedMethodTest < ActiveSupport::TestCase
4
4
  test "#call caches the result of the original method" do
5
- recording = Recording.new(number: 5)
5
+ recording = Recording.create(number: 5)
6
6
  cached_method = manager.handle(Recording, :another_method, expires_in: 1.hour)
7
7
  manager.activate_if_handling(Recording, :another_method)
8
8
 
9
9
  result = cached_method.call(recording)
10
10
 
11
11
  assert_equal 5, result
12
- assert cache_has_key? "CacheKeeper/Recording/another_method"
12
+ assert cache_has_key? "CacheKeeper/recordings/#{recording.id}/another_method"
13
+ end
14
+
15
+ test ":key option accepts arrays" do
16
+ cached_method = manager.handle(Recording, :another_method, key: ["QuantumQuackerator", "dimensional_duckling"])
17
+ cache_key = cached_method.send :cache_key, Recording.new
18
+
19
+ assert_equal ["QuantumQuackerator", "dimensional_duckling"], cache_key
20
+ end
21
+
22
+ test ":key option accepts procs with no arguments" do
23
+ cached_method = manager.handle(Recording, :another_method, key: proc { 123 })
24
+ cache_key = cached_method.send :cache_key, Recording.new
25
+
26
+ assert_equal 123, cache_key
27
+ end
28
+
29
+ test ":key option accepts procs with an argument" do
30
+ cached_method = manager.handle(Recording, :another_method, key: proc { |method_name| [method_name, 123] })
31
+ cache_key = cached_method.send :cache_key, Recording.new
32
+
33
+ assert_equal [:another_method, 123], cache_key
34
+ end
35
+
36
+ test ":key option accepts lambdas with no arguments" do
37
+ cached_method = manager.handle(Recording, :another_method, key: -> { 123 })
38
+ cache_key = cached_method.send :cache_key, Recording.new
39
+
40
+ assert_equal 123, cache_key
41
+ end
42
+
43
+ test ":key option accepts lambdas with an argument" do
44
+ cached_method = manager.handle(Recording, :another_method, key: ->(method_name) { [method_name, 123] })
45
+ cache_key = cached_method.send :cache_key, Recording.new
46
+
47
+ assert_equal [:another_method, 123], cache_key
13
48
  end
14
49
 
15
50
  private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cache_keeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Zamuner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-24 00:00:00.000000000 Z
11
+ date: 2023-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -32,8 +32,8 @@ extra_rdoc_files: []
32
32
  files:
33
33
  - ".github/workflows/ci.yml"
34
34
  - ".gitignore"
35
+ - ".rubocop.yml"
35
36
  - Gemfile
36
- - Gemfile.lock
37
37
  - MIT-LICENSE
38
38
  - README.md
39
39
  - app/jobs/cache_keeper/base_job.rb
data/Gemfile.lock DELETED
@@ -1,199 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- cache_keeper (0.3.0)
5
- rails (>= 6.1.0)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- actioncable (7.1.1)
11
- actionpack (= 7.1.1)
12
- activesupport (= 7.1.1)
13
- nio4r (~> 2.0)
14
- websocket-driver (>= 0.6.1)
15
- zeitwerk (~> 2.6)
16
- actionmailbox (7.1.1)
17
- actionpack (= 7.1.1)
18
- activejob (= 7.1.1)
19
- activerecord (= 7.1.1)
20
- activestorage (= 7.1.1)
21
- activesupport (= 7.1.1)
22
- mail (>= 2.7.1)
23
- net-imap
24
- net-pop
25
- net-smtp
26
- actionmailer (7.1.1)
27
- actionpack (= 7.1.1)
28
- actionview (= 7.1.1)
29
- activejob (= 7.1.1)
30
- activesupport (= 7.1.1)
31
- mail (~> 2.5, >= 2.5.4)
32
- net-imap
33
- net-pop
34
- net-smtp
35
- rails-dom-testing (~> 2.2)
36
- actionpack (7.1.1)
37
- actionview (= 7.1.1)
38
- activesupport (= 7.1.1)
39
- nokogiri (>= 1.8.5)
40
- rack (>= 2.2.4)
41
- rack-session (>= 1.0.1)
42
- rack-test (>= 0.6.3)
43
- rails-dom-testing (~> 2.2)
44
- rails-html-sanitizer (~> 1.6)
45
- actiontext (7.1.1)
46
- actionpack (= 7.1.1)
47
- activerecord (= 7.1.1)
48
- activestorage (= 7.1.1)
49
- activesupport (= 7.1.1)
50
- globalid (>= 0.6.0)
51
- nokogiri (>= 1.8.5)
52
- actionview (7.1.1)
53
- activesupport (= 7.1.1)
54
- builder (~> 3.1)
55
- erubi (~> 1.11)
56
- rails-dom-testing (~> 2.2)
57
- rails-html-sanitizer (~> 1.6)
58
- activejob (7.1.1)
59
- activesupport (= 7.1.1)
60
- globalid (>= 0.3.6)
61
- activemodel (7.1.1)
62
- activesupport (= 7.1.1)
63
- activerecord (7.1.1)
64
- activemodel (= 7.1.1)
65
- activesupport (= 7.1.1)
66
- timeout (>= 0.4.0)
67
- activestorage (7.1.1)
68
- actionpack (= 7.1.1)
69
- activejob (= 7.1.1)
70
- activerecord (= 7.1.1)
71
- activesupport (= 7.1.1)
72
- marcel (~> 1.0)
73
- activesupport (7.1.1)
74
- base64
75
- bigdecimal
76
- concurrent-ruby (~> 1.0, >= 1.0.2)
77
- connection_pool (>= 2.2.5)
78
- drb
79
- i18n (>= 1.6, < 2)
80
- minitest (>= 5.1)
81
- mutex_m
82
- tzinfo (~> 2.0)
83
- base64 (0.1.1)
84
- bigdecimal (3.1.4)
85
- builder (3.2.4)
86
- byebug (11.1.3)
87
- concurrent-ruby (1.2.2)
88
- connection_pool (2.4.1)
89
- crass (1.0.6)
90
- date (3.3.3)
91
- drb (2.1.1)
92
- ruby2_keywords
93
- erubi (1.12.0)
94
- globalid (1.2.1)
95
- activesupport (>= 6.1)
96
- i18n (1.14.1)
97
- concurrent-ruby (~> 1.0)
98
- io-console (0.6.0)
99
- irb (1.8.3)
100
- rdoc
101
- reline (>= 0.3.8)
102
- loofah (2.21.4)
103
- crass (~> 1.0.2)
104
- nokogiri (>= 1.12.0)
105
- mail (2.8.1)
106
- mini_mime (>= 0.1.1)
107
- net-imap
108
- net-pop
109
- net-smtp
110
- marcel (1.0.2)
111
- mini_mime (1.1.5)
112
- minitest (5.20.0)
113
- mutex_m (0.1.2)
114
- net-imap (0.4.2)
115
- date
116
- net-protocol
117
- net-pop (0.1.2)
118
- net-protocol
119
- net-protocol (0.2.1)
120
- timeout
121
- net-smtp (0.4.0)
122
- net-protocol
123
- nio4r (2.5.9)
124
- nokogiri (1.15.4-arm64-darwin)
125
- racc (~> 1.4)
126
- nokogiri (1.15.4-x86_64-linux)
127
- racc (~> 1.4)
128
- psych (5.1.1.1)
129
- stringio
130
- racc (1.7.1)
131
- rack (3.0.8)
132
- rack-session (2.0.0)
133
- rack (>= 3.0.0)
134
- rack-test (2.1.0)
135
- rack (>= 1.3)
136
- rackup (2.1.0)
137
- rack (>= 3)
138
- webrick (~> 1.8)
139
- rails (7.1.1)
140
- actioncable (= 7.1.1)
141
- actionmailbox (= 7.1.1)
142
- actionmailer (= 7.1.1)
143
- actionpack (= 7.1.1)
144
- actiontext (= 7.1.1)
145
- actionview (= 7.1.1)
146
- activejob (= 7.1.1)
147
- activemodel (= 7.1.1)
148
- activerecord (= 7.1.1)
149
- activestorage (= 7.1.1)
150
- activesupport (= 7.1.1)
151
- bundler (>= 1.15.0)
152
- railties (= 7.1.1)
153
- rails-dom-testing (2.2.0)
154
- activesupport (>= 5.0.0)
155
- minitest
156
- nokogiri (>= 1.6)
157
- rails-html-sanitizer (1.6.0)
158
- loofah (~> 2.21)
159
- nokogiri (~> 1.14)
160
- railties (7.1.1)
161
- actionpack (= 7.1.1)
162
- activesupport (= 7.1.1)
163
- irb
164
- rackup (>= 1.0.0)
165
- rake (>= 12.2)
166
- thor (~> 1.0, >= 1.2.2)
167
- zeitwerk (~> 2.6)
168
- rake (13.0.6)
169
- rdoc (6.5.0)
170
- psych (>= 4.0.0)
171
- reline (0.3.9)
172
- io-console (~> 0.5)
173
- ruby2_keywords (0.0.5)
174
- sqlite3 (1.6.7-arm64-darwin)
175
- sqlite3 (1.6.7-x86_64-linux)
176
- stringio (3.0.8)
177
- thor (1.3.0)
178
- timeout (0.4.0)
179
- tzinfo (2.0.6)
180
- concurrent-ruby (~> 1.0)
181
- webrick (1.8.1)
182
- websocket-driver (0.7.6)
183
- websocket-extensions (>= 0.1.0)
184
- websocket-extensions (0.1.5)
185
- zeitwerk (2.6.12)
186
-
187
- PLATFORMS
188
- arm64-darwin-22
189
- x86_64-linux
190
-
191
- DEPENDENCIES
192
- byebug
193
- cache_keeper!
194
- rails (>= 6.1)
195
- rake
196
- sqlite3
197
-
198
- BUNDLED WITH
199
- 2.4.19