rimcache 0.1.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.
- checksums.yaml +7 -0
- data/.rubocop.yml +24 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +129 -0
- data/README.rdoc +12 -0
- data/Rakefile +12 -0
- data/lib/rimcache/config.rb +37 -0
- data/lib/rimcache/store.rb +122 -0
- data/lib/rimcache/version.rb +5 -0
- data/lib/rimcache.rb +49 -0
- data/sig/rimcache.rbs +27 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8193c5feead4d6c058e64ba03b94fa863e32d5c9ab29819e3d44458401204914
|
4
|
+
data.tar.gz: 0bcf98dddfe53da75d045cfbd7870e4978b1b793c4f701556871ee04b5652b5c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6226294aca56945946737f0feb4555b3e4d09ae46bba2faebdd9d71afd0afb5b2d4ffd37214fb24eb5d9b8d705f019cf44b7ffc35b2f0bb583607f4b4ace2f60
|
7
|
+
data.tar.gz: 7a1b36e38741f6716de88d51b8dc39f664bea0fac47c4dfa818559a18d9bdcb5e6a3ad65dbe8611d4b0ab4eba0065279977b74713a6655ea98fda70fb379459f
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
plugins:
|
2
|
+
- rubocop-minitest
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
TargetRubyVersion: 3.0
|
6
|
+
NewCops: enable
|
7
|
+
|
8
|
+
Style/StringLiterals:
|
9
|
+
Enabled: true
|
10
|
+
EnforcedStyle: double_quotes
|
11
|
+
|
12
|
+
Style/StringLiteralsInInterpolation:
|
13
|
+
Enabled: true
|
14
|
+
EnforcedStyle: double_quotes
|
15
|
+
|
16
|
+
Layout/LineLength:
|
17
|
+
Max: 120
|
18
|
+
|
19
|
+
Metrics/AbcSize:
|
20
|
+
Exclude:
|
21
|
+
- 'test/**/*'
|
22
|
+
|
23
|
+
Gemspec/RequireMFA:
|
24
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 Duncan McKee
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# Rimcache
|
2
|
+
|
3
|
+
A right-in-memory "cache" for Ruby on Rails.
|
4
|
+
|
5
|
+
Does your Rails app have individual records that most or all of your requests use?
|
6
|
+
They rarely change but it's still handy to have them in the database?
|
7
|
+
|
8
|
+
With Rimcache, you can keep a frozen ActiveRecord object or set of objects in
|
9
|
+
memory and it will automatically refresh from the database when any server worker
|
10
|
+
invalidates it. It avoids the serialization required for caching in Redis/Memcache,
|
11
|
+
so it is usable for situations where Rails low-level caching is not.
|
12
|
+
Associations on a record will stay loaded, so it can save more than one query per
|
13
|
+
cached record.
|
14
|
+
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
Say you have an app where every request is processed in the context one of just a few `Site` records.
|
19
|
+
You could avoid loading it from the database every time like this:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
class Site < ActiveRecord::Base
|
23
|
+
has_many :features
|
24
|
+
|
25
|
+
after_update :expire_rimcache
|
26
|
+
|
27
|
+
def self.find_cached(slug)
|
28
|
+
Rimcache.fetch("site_#{slug}") do
|
29
|
+
# This will only be called if site is not already in cache or was expired
|
30
|
+
Site.eager_load(:features).find_by(slug:)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def expire_rimcache
|
35
|
+
Rimcache.expire("site_#{slug}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
|
41
|
+
## Configuration
|
42
|
+
|
43
|
+
If the record is rarely updated and you'd rather not bother with expiration,
|
44
|
+
you can set a TTL with `Rimcache.config.refresh_interval`:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
Rimcache.config.refresh_interval = 15.minutes
|
48
|
+
```
|
49
|
+
|
50
|
+
This will cause the cache to be refreshed every 15 minutes, even if it has not been explicitly expired.
|
51
|
+
That way, any changes to the record will be reflected by other processes in at most 15 minutes.
|
52
|
+
Keep in mind, however, that using this strategy will lead to inconsistency between processes as they
|
53
|
+
won't all reflect the changes at the same time.
|
54
|
+
|
55
|
+
When you want to edit the record, you can call `Rimcache.fetch` with the `for_update` keyword argument:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class Site < ActiveRecord::Base
|
59
|
+
has_many :features
|
60
|
+
|
61
|
+
after_update :expire_rimcache
|
62
|
+
|
63
|
+
def self.fetch_by_slug(slug, for_update: false)
|
64
|
+
Rimcache.fetch("site_#{slug}", for_update:) do
|
65
|
+
# This will only be called if site is not already in cache or was expired
|
66
|
+
Site.eager_load(:features).find_by(slug:)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def expire_rimcache
|
71
|
+
Rimcache.expire("site_#{slug}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
Then a Site can be updated like this:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
site = Site.fetch_by_slug(:example, for_update: true)
|
80
|
+
site.update!(name: "New Name") # after_update callback expires the rimcache
|
81
|
+
```
|
82
|
+
|
83
|
+
Note that `for_update` does not handle expiration, it just ensures the record is refreshed
|
84
|
+
from the database and not frozen.
|
85
|
+
|
86
|
+
|
87
|
+
### Expiry cache
|
88
|
+
|
89
|
+
Rimcache by default uses Rails' low-level caching to coordinate expiration across processes.
|
90
|
+
If you want to use a different cache store, you can set `Rimcache.config.expiry_cache` to an instance of
|
91
|
+
`ActiveSupport::Cache::Store`.
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
Rimcache.config.expiry_cache # defaults to Rails.cache
|
95
|
+
Rimcache.config.expiry_cache = ActiveSupport::Cache::MemoryStore.new
|
96
|
+
```
|
97
|
+
|
98
|
+
If you want to use the same cache store as Rails but avoid conflicts, such as with
|
99
|
+
another instance of `Rimcache::Store`, you can change `Rimcache.config.expiry_cache_key`:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
alt_rimcache = Rimcache::Store.new
|
103
|
+
alt_rimcache.config.expiry_cache_key = "alt_rimcache"
|
104
|
+
```
|
105
|
+
|
106
|
+
In order to reduce the number of hits to the expiry cache, Rimcache only checks it
|
107
|
+
every 4 seconds by default. This can be changed with `Rimcache.config.check_frequency`:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
Rimcache.config.check_frequency = 30.seconds
|
111
|
+
Rimcache.config.check_frequency = nil # always check the expiry cache
|
112
|
+
```
|
113
|
+
|
114
|
+
|
115
|
+
<!--
|
116
|
+
## Development
|
117
|
+
|
118
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
119
|
+
|
120
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
121
|
+
-->
|
122
|
+
|
123
|
+
## Contributing
|
124
|
+
|
125
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mckeed/rimcache.
|
126
|
+
|
127
|
+
## License
|
128
|
+
|
129
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/README.rdoc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
= Rimcache - the Right-in-Memory Cache
|
2
|
+
|
3
|
+
"Caches" your commonly-used objects by just storing them frozen in a global hash.
|
4
|
+
|
5
|
+
Rimcache.cache(:default_settings) do
|
6
|
+
Settings.default
|
7
|
+
end
|
8
|
+
|
9
|
+
It avoids a round-trip to Redis/memcache and serialization, so associations will stay loaded.
|
10
|
+
|
11
|
+
Expiration is coordinated between processes via `Rails.cache` or a configurable ActiveSupport::Cache::Store.
|
12
|
+
See +Rimcache::Config+ for configuration options.
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
require "active_support/all"
|
5
|
+
|
6
|
+
module Rimcache
|
7
|
+
# Configuration for Rimcache
|
8
|
+
class Config
|
9
|
+
# An instance of ActiveSupport::Cache::Store used to coordinate Rimcache expiry and invalidation
|
10
|
+
# across processes. If not set, defaults to Rails.cache.
|
11
|
+
# @return [ActiveSupport::Cache::Store]
|
12
|
+
attr_accessor :expiry_cache
|
13
|
+
|
14
|
+
# The cache key to use in expiry_cache.
|
15
|
+
# Defaults to "rimcache_expiry" but can be changed to avoid conflicts.
|
16
|
+
# @return [String | Symbol]
|
17
|
+
attr_accessor :expiry_cache_key
|
18
|
+
|
19
|
+
# The expiry cache will only be checked if it has not been in this much time.
|
20
|
+
# A stale cached value can keep being returned for up to this long after another
|
21
|
+
# process invalidates it.
|
22
|
+
# Defaults to 4 seconds
|
23
|
+
# @return [ActiveSupport::Duration] time in seconds
|
24
|
+
attr_accessor :check_frequency
|
25
|
+
|
26
|
+
# If this is set, rimcached values will be refreshed after this much
|
27
|
+
# time even if they have not been explicitly expired.
|
28
|
+
# Default value is +nil+.
|
29
|
+
# @return [ActiveSupport::Duration] time in seconds
|
30
|
+
attr_accessor :refresh_interval
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@check_frequency = 4.seconds
|
34
|
+
@expiry_cache_key = "rimcache_expiry"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "config"
|
4
|
+
require "active_support/all"
|
5
|
+
|
6
|
+
module Rimcache
|
7
|
+
# The core of Rimcache. Stores frozen objects in a Hash while tracking when
|
8
|
+
# they were last stored and when they were last updated by any process connected
|
9
|
+
# to the same cross-process expiry cache.
|
10
|
+
#
|
11
|
+
# Access this via Rimcache.store for a singleton instance.
|
12
|
+
#
|
13
|
+
class Store
|
14
|
+
attr_accessor :config, :cached
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@config = Config.new
|
18
|
+
@cached = {}
|
19
|
+
@written_at = {}
|
20
|
+
@last_check = Time.current
|
21
|
+
|
22
|
+
# @expiry_cache is set on first demand to give the best chance
|
23
|
+
# that Rails.cache is loaded when we try to access it
|
24
|
+
@expiry_cache = nil
|
25
|
+
@expiry = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the value cached under +key+
|
29
|
+
def read(key)
|
30
|
+
cached[key]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns true if no value has been cached for +key+ yet, if +expire+ has been
|
34
|
+
# called from any process with access to the same +expiry_cache+
|
35
|
+
# @return [Boolean] Whether the value under +key+ needs to be refreshed.
|
36
|
+
def expired?(key)
|
37
|
+
last_update = @written_at[key]
|
38
|
+
return true if !cached[key] || needs_refresh?(last_update)
|
39
|
+
|
40
|
+
# Check if another process has changed the value since we read it
|
41
|
+
expired_at = reload_expiry[key]
|
42
|
+
!!expired_at && expired_at > last_update
|
43
|
+
end
|
44
|
+
|
45
|
+
# Update the expiry_cache to notify other processes that the
|
46
|
+
# rimcached object at this key has changed and must be refreshed.
|
47
|
+
def expire(key)
|
48
|
+
cached[key] = nil
|
49
|
+
reload_expiry(force: true)
|
50
|
+
@expiry[key] = Time.current
|
51
|
+
expiry_cache.write(config.expiry_cache_key, @expiry, expires_in: nil)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Fetches or updates data from the rimcache at the given key.
|
55
|
+
# If there's an unexpired stored value it is returned. Otherwise,
|
56
|
+
# the block is called and the result is frozen, stored in the rimcache
|
57
|
+
# under this key, and returned.
|
58
|
+
#
|
59
|
+
# The keyword argument +for_update+ can be set to +true+ to call the block
|
60
|
+
# and return the result unfrozen instead of caching it. You must still call
|
61
|
+
# +expire(key)+ or +update(key, value)+ after updating the record in the database.
|
62
|
+
#
|
63
|
+
def fetch(key, for_update: false)
|
64
|
+
raise(ArgumentError, "Rimcache: tried to store to cache with nil key") if key.nil?
|
65
|
+
|
66
|
+
if for_update
|
67
|
+
cached[key] = nil
|
68
|
+
yield
|
69
|
+
elsif expired?(key) || !cached[key]
|
70
|
+
write(key, yield.freeze) if block_given?
|
71
|
+
else
|
72
|
+
read(key)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Expires the rimcache for this key and saves a frozen clone of +value+
|
77
|
+
# as the new value.
|
78
|
+
def update(key, value)
|
79
|
+
expire(key)
|
80
|
+
write(key, value.clone.freeze)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def needs_refresh?(last_update)
|
86
|
+
return true if last_update.nil?
|
87
|
+
|
88
|
+
!config.refresh_interval.nil? && Time.current - last_update > config.refresh_interval
|
89
|
+
end
|
90
|
+
|
91
|
+
def reload_expiry(force: false)
|
92
|
+
# Only check expiry_cache every few seconds for excessive efficiency
|
93
|
+
now = Time.current
|
94
|
+
return @expiry unless force || @expiry.nil? || now - @last_check > config.check_frequency
|
95
|
+
|
96
|
+
@last_check = now
|
97
|
+
@expiry = expiry_cache.read(config.expiry_cache_key) || {}
|
98
|
+
end
|
99
|
+
|
100
|
+
def write(key, value)
|
101
|
+
@written_at[key] = Time.current
|
102
|
+
cached[key] = value # must return value
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [ActiveSupport::Cache::Store]
|
106
|
+
def expiry_cache
|
107
|
+
@expiry_cache ||= config.expiry_cache || rails_cache || fallback_cache
|
108
|
+
end
|
109
|
+
|
110
|
+
def rails_cache
|
111
|
+
require "rails"
|
112
|
+
Rails.cache
|
113
|
+
rescue LoadError, NoMethodError
|
114
|
+
# return nil if there's no rails or no Rails.cache
|
115
|
+
end
|
116
|
+
|
117
|
+
def fallback_cache
|
118
|
+
puts "[Rimcache] Warning: no expiry cache found. Rimcache will not be invalidated across multiple processes."
|
119
|
+
ActiveSupport::Cache::MemoryStore.new
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/rimcache.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "rimcache/store"
|
4
|
+
require_relative "rimcache/version"
|
5
|
+
|
6
|
+
# The main entry point to Rimcache.
|
7
|
+
# "Caches" commonly-used objects by just storing them frozen in a global hash.
|
8
|
+
# Expiration is handled via Rails low-level caching or a configurable ActiveSupport::Cache::Store.
|
9
|
+
#
|
10
|
+
module Rimcache
|
11
|
+
# A singleton instance of +Rimcache::Store+.
|
12
|
+
def self.store
|
13
|
+
@store ||= Store.include(Singleton).instance
|
14
|
+
end
|
15
|
+
|
16
|
+
# The +Rimcache::Config+ object associated with the singleton +store+
|
17
|
+
def self.config
|
18
|
+
store.config
|
19
|
+
end
|
20
|
+
|
21
|
+
# Fetches or updates data from the rimcache at the given key.
|
22
|
+
# If there's an unexpired stored value it is returned. Otherwise,
|
23
|
+
# the block is called and the result is frozen, stored in the rimcache
|
24
|
+
# under this key, and returned.
|
25
|
+
#
|
26
|
+
# The keyword argument +for_update+ can be set to +true+ to call the block
|
27
|
+
# and return the result unfrozen instead of caching it. You must still call
|
28
|
+
# +expire(key)+ or +update(key, value)+ after updating the record in the database.
|
29
|
+
#
|
30
|
+
def self.fetch(...)
|
31
|
+
store.fetch(...)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.expire(...)
|
35
|
+
store.expire(...)
|
36
|
+
end
|
37
|
+
|
38
|
+
module_function
|
39
|
+
|
40
|
+
# You can include +Rimcache+ in your model to use +rimcache+ instead of +Rimcache.fetch+
|
41
|
+
def rimcache(...)
|
42
|
+
Rimcache.fetch(...)
|
43
|
+
end
|
44
|
+
|
45
|
+
# You can include +Rimcache+ in your model to use +rimcache_expire+ instead of +Rimcache.expire+
|
46
|
+
def rimcache_expire(...)
|
47
|
+
Rimcache.expire(...)
|
48
|
+
end
|
49
|
+
end
|
data/sig/rimcache.rbs
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# The main entry point to Rimcache.
|
2
|
+
# "Caches" commonly-used objects by just storing them frozen in a global hash.
|
3
|
+
# Expiration is handled via Rails low-level caching or a configurable ActiveSupport::Cache::Store.
|
4
|
+
#
|
5
|
+
module Rimcache
|
6
|
+
self.@store: untyped
|
7
|
+
|
8
|
+
# A singleton instance of +Rimcache::Store+.
|
9
|
+
def self.store: () -> Store
|
10
|
+
|
11
|
+
# The +Rimcache::Config+ object associated with the singleton +store+
|
12
|
+
def self.config: () -> Config
|
13
|
+
|
14
|
+
# Fetches or updates data from the rimcache at the given key.
|
15
|
+
# If there's an unexpired stored value it is returned. Otherwise,
|
16
|
+
# the block is called and the result is frozen, stored in the rimcache
|
17
|
+
# under this key, and returned.
|
18
|
+
#
|
19
|
+
# The keyword argument +for_update+ can be set to +true+ to call the block
|
20
|
+
# and return the result unfrozen instead of caching it. You must still call
|
21
|
+
# +expire(key)+ or +update(key, value)+ after updating the record in the database.
|
22
|
+
#
|
23
|
+
def self.fetch: ((String | Symbol | Object) key, ?for_update: bool) { (void) -> T } -> T
|
24
|
+
|
25
|
+
# You can include +Rimcache+ in your model to use +rimcache+ instead of +Rimcache.fetch+
|
26
|
+
def self?.rimcache: ((String | Symbol | Object) key, ?for_update: bool) { (void) -> T } -> T
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rimcache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Duncan McKee
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-05-29 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: activesupport
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '6.1'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '6.1'
|
26
|
+
description: |
|
27
|
+
"Caches" commonly-used objects by just storing them frozen in a global hash.
|
28
|
+
Expiration is handled via Rails low-level caching or an ActiveSupport::Cache
|
29
|
+
email:
|
30
|
+
- mckeed+rubygems@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".rubocop.yml"
|
36
|
+
- CHANGELOG.md
|
37
|
+
- LICENSE.txt
|
38
|
+
- README.md
|
39
|
+
- README.rdoc
|
40
|
+
- Rakefile
|
41
|
+
- lib/rimcache.rb
|
42
|
+
- lib/rimcache/config.rb
|
43
|
+
- lib/rimcache/store.rb
|
44
|
+
- lib/rimcache/version.rb
|
45
|
+
- sig/rimcache.rbs
|
46
|
+
homepage: https://github.com/mckeed/rimcache
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
metadata:
|
50
|
+
homepage_uri: https://github.com/mckeed/rimcache
|
51
|
+
source_code_uri: https://github.com/mckeed/rimcache
|
52
|
+
changelog_uri: https://github.com/mckeed/rimcache/tree/CHANGELOG.md
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 3.0.0
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubygems_version: 3.6.2
|
68
|
+
specification_version: 4
|
69
|
+
summary: Keep commonly-used records in memory with expiration coordinated via the
|
70
|
+
Rails cache.
|
71
|
+
test_files: []
|