thermos 0.2.1 → 0.5.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 +4 -4
- data/lib/thermos.rb +4 -4
- data/lib/thermos/beverage.rb +41 -8
- data/lib/thermos/dependency.rb +5 -6
- data/lib/thermos/notifier.rb +1 -1
- data/lib/thermos/refill_job.rb +5 -3
- data/lib/thermos/version.rb +1 -1
- data/test/dummy/config/application.rb +0 -4
- data/test/dummy/db/schema.rb +5 -5
- data/test/thermos_test.rb +65 -0
- metadata +51 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87ceed3d0f1b54b2cd9e9b0afde15e90252fcbc9f575c5bf11a66e414045c5d5
|
4
|
+
data.tar.gz: dc3bc76cd808f474b80676c5f2d1f2e50681c6028c09412e12eb565b4494cfc4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d86ada3f6a3b07ed8bbf35c481e73ac4563a0aced184f6e47a986847287f0bf4a3c02c42e5d7600db1f5d8c2358f5ba4975fd20c4ccceee8fc3ec0cfcaae7811
|
7
|
+
data.tar.gz: 51f90cb754d381d81293e433261e09cb4e184dc1dcddd05fbfcbf7baacb577330f6a4cc6a0621cc8cd9964d7677e499554a8dd533d65762adb421d56cef58458
|
data/lib/thermos.rb
CHANGED
@@ -8,14 +8,14 @@ require 'thermos/refill_job'
|
|
8
8
|
require 'thermos/rebuild_cache_job'
|
9
9
|
|
10
10
|
module Thermos
|
11
|
-
def self.keep_warm(key:, model:, id:, deps: [], lookup_key: nil, &block)
|
12
|
-
fill(key: key, model: model, deps: deps, lookup_key: lookup_key, &block)
|
11
|
+
def self.keep_warm(key:, model:, id:, deps: [], lookup_key: nil, filter: nil, &block)
|
12
|
+
fill(key: key, model: model, deps: deps, lookup_key: lookup_key, filter: filter, &block)
|
13
13
|
drink(key: key, id: id)
|
14
14
|
end
|
15
15
|
|
16
|
-
def self.fill(key:, model:, deps: [], lookup_key: nil, &block)
|
16
|
+
def self.fill(key:, model:, deps: [], lookup_key: nil, filter: nil, &block)
|
17
17
|
BeverageStorage.instance.add_beverage(
|
18
|
-
Beverage.new(key: key, model: model, deps: deps, action: block, lookup_key: lookup_key)
|
18
|
+
Beverage.new(key: key, model: model, deps: deps, action: block, lookup_key: lookup_key, filter: filter)
|
19
19
|
)
|
20
20
|
end
|
21
21
|
|
data/lib/thermos/beverage.rb
CHANGED
@@ -2,29 +2,33 @@
|
|
2
2
|
|
3
3
|
module Thermos
|
4
4
|
class Beverage
|
5
|
-
attr_reader :key, :model, :deps, :action, :lookup_key
|
5
|
+
attr_reader :key, :model, :deps, :action, :lookup_key, :filter
|
6
6
|
|
7
|
-
def initialize(key:, model:, deps:, action:, lookup_key: nil)
|
7
|
+
def initialize(key:, model:, deps:, action:, lookup_key: nil, filter: nil)
|
8
8
|
@key = key
|
9
9
|
@model = model
|
10
10
|
@lookup_key = lookup_key || :id
|
11
|
-
@
|
12
|
-
|
13
|
-
end
|
11
|
+
@filter = filter || nil
|
12
|
+
@deps = generate_deps(model, deps)
|
14
13
|
@action = action
|
15
14
|
|
16
15
|
set_observers
|
17
16
|
end
|
18
17
|
|
19
18
|
def lookup_keys_for_dep_model(dep_model)
|
20
|
-
@deps.
|
21
|
-
|
22
|
-
|
19
|
+
@deps.select do |dep|
|
20
|
+
dep.klass == dep_model.class
|
21
|
+
end.flat_map do |dep|
|
22
|
+
@model.joins(dep.path)
|
23
23
|
.where(dep.table => { id: dep_model.id })
|
24
24
|
.pluck(@lookup_key)
|
25
25
|
end.uniq
|
26
26
|
end
|
27
27
|
|
28
|
+
def should_fill?(model)
|
29
|
+
@filter.class == Proc ? !!@filter.call(model) : true
|
30
|
+
end
|
31
|
+
|
28
32
|
private
|
29
33
|
|
30
34
|
def set_observers
|
@@ -35,5 +39,34 @@ module Thermos
|
|
35
39
|
def observe(model)
|
36
40
|
model.include(Notifier) unless model.included_modules.include?(Notifier)
|
37
41
|
end
|
42
|
+
|
43
|
+
def generate_deps(model, deps, root = nil, path = nil)
|
44
|
+
deps.reduce([]) do |acc, dep|
|
45
|
+
if dep.is_a? Symbol
|
46
|
+
acc << Dependency.new(
|
47
|
+
model: root || model,
|
48
|
+
ref: model.reflect_on_association(dep),
|
49
|
+
path: path || dep)
|
50
|
+
elsif dep.is_a? Array
|
51
|
+
dep.each do |d|
|
52
|
+
acc << Dependency.new(
|
53
|
+
model: root || model,
|
54
|
+
ref: model.reflect_on_association(d),
|
55
|
+
path: path || d)
|
56
|
+
end
|
57
|
+
elsif dep.is_a? Hash
|
58
|
+
dep.each do |k,v|
|
59
|
+
ref = model.reflect_on_association(k)
|
60
|
+
acc << Dependency.new(
|
61
|
+
model: root || model,
|
62
|
+
ref: ref,
|
63
|
+
path: path || k
|
64
|
+
)
|
65
|
+
acc.concat(generate_deps(ref.class_name.constantize, v, model, dep))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
acc
|
69
|
+
end
|
70
|
+
end
|
38
71
|
end
|
39
72
|
end
|
data/lib/thermos/dependency.rb
CHANGED
@@ -2,14 +2,13 @@
|
|
2
2
|
|
3
3
|
module Thermos
|
4
4
|
class Dependency
|
5
|
-
attr_reader :model, :
|
5
|
+
attr_reader :model, :path, :klass, :table
|
6
6
|
|
7
|
-
def initialize(model:,
|
7
|
+
def initialize(model:, ref:, path: nil)
|
8
8
|
@model = model
|
9
|
-
@
|
10
|
-
|
11
|
-
@
|
12
|
-
@klass = reflection.class_name.constantize
|
9
|
+
@path = path
|
10
|
+
@table = ref.table_name
|
11
|
+
@klass = ref.class_name.constantize
|
13
12
|
end
|
14
13
|
end
|
15
14
|
end
|
data/lib/thermos/notifier.rb
CHANGED
data/lib/thermos/refill_job.rb
CHANGED
@@ -9,7 +9,7 @@ module Thermos
|
|
9
9
|
|
10
10
|
def refill_primary_caches(model)
|
11
11
|
BeverageStorage.instance.beverages.each do |beverage|
|
12
|
-
if beverage.model == model.class
|
12
|
+
if beverage.model == model.class && beverage.should_fill?(model)
|
13
13
|
Thermos::RebuildCacheJob.perform_later(beverage.key, model.send(beverage.lookup_key))
|
14
14
|
end
|
15
15
|
end
|
@@ -17,8 +17,10 @@ module Thermos
|
|
17
17
|
|
18
18
|
def refill_dependency_caches(model)
|
19
19
|
BeverageStorage.instance.beverages.each do |beverage|
|
20
|
-
beverage.
|
21
|
-
|
20
|
+
if beverage.should_fill?(model)
|
21
|
+
beverage.lookup_keys_for_dep_model(model).each do |lookup_key|
|
22
|
+
Thermos::RebuildCacheJob.perform_later(beverage.key, lookup_key)
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
data/lib/thermos/version.rb
CHANGED
@@ -18,10 +18,6 @@ module Dummy
|
|
18
18
|
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
19
19
|
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
20
20
|
# config.i18n.default_locale = :de
|
21
|
-
|
22
|
-
if Rails.version >= "5.2.0"
|
23
|
-
Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
|
24
|
-
end
|
25
21
|
end
|
26
22
|
end
|
27
23
|
|
data/test/dummy/db/schema.rb
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
# of editing this file, please use the migrations feature of Active Record to
|
3
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# from scratch.
|
9
|
-
#
|
5
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
6
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
7
|
+
# be faster and is potentially less error prone than running all of your
|
8
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
9
|
+
# migrations use external dependencies or application code.
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
data/test/thermos_test.rb
CHANGED
@@ -65,6 +65,30 @@ class ThermosTest < ActiveSupport::TestCase
|
|
65
65
|
assert_raises(MockExpectationError) { mock.verify }
|
66
66
|
end
|
67
67
|
|
68
|
+
test "does not rebuild the cache on rolled back primary model change" do
|
69
|
+
mock = Minitest::Mock.new
|
70
|
+
category = categories(:baseball)
|
71
|
+
|
72
|
+
Thermos.fill(key: "key", model: Category) do |id|
|
73
|
+
mock.call(id)
|
74
|
+
end
|
75
|
+
|
76
|
+
mock.expect(:call, 1, [category.id])
|
77
|
+
assert_equal 1, Thermos.drink(key: "key", id: category.id)
|
78
|
+
mock.verify
|
79
|
+
|
80
|
+
mock.expect(:call, 2, [category.id])
|
81
|
+
ActiveRecord::Base.transaction do
|
82
|
+
category.update!(name: "foo")
|
83
|
+
raise ActiveRecord::Rollback
|
84
|
+
end
|
85
|
+
assert_raises(MockExpectationError) { mock.verify }
|
86
|
+
|
87
|
+
mock.expect(:call, 3, [category.id])
|
88
|
+
assert_equal 1, Thermos.drink(key: "key", id: category.id)
|
89
|
+
assert_raises(MockExpectationError) { mock.verify }
|
90
|
+
end
|
91
|
+
|
68
92
|
test "does not rebuild the cache for an unrelated primary model change" do
|
69
93
|
mock = Minitest::Mock.new
|
70
94
|
category = categories(:baseball)
|
@@ -102,6 +126,23 @@ class ThermosTest < ActiveSupport::TestCase
|
|
102
126
|
assert_equal 1, Thermos.drink(key: "key", id: "foo")
|
103
127
|
assert_raises(MockExpectationError) { mock.verify }
|
104
128
|
end
|
129
|
+
|
130
|
+
test "allows filtering for which records should be rebuilt" do
|
131
|
+
mock = Minitest::Mock.new
|
132
|
+
category = categories(:baseball)
|
133
|
+
filter = ->(model) { model.name.match("ball") }
|
134
|
+
Thermos.fill(key: "key", model: Category, lookup_key: "name", filter: filter) do |name|
|
135
|
+
mock.call(name)
|
136
|
+
end
|
137
|
+
|
138
|
+
mock.expect(:call, 1, ["basketball"])
|
139
|
+
category.update!(name: "basketball")
|
140
|
+
mock.verify
|
141
|
+
|
142
|
+
mock.expect(:call, 1, ["hockey"])
|
143
|
+
category.update!(name: "hockey")
|
144
|
+
assert_raises(MockExpectationError) { mock.verify }
|
145
|
+
end
|
105
146
|
|
106
147
|
# has_many model changes
|
107
148
|
test "rebuilds the cache on has_many model change" do
|
@@ -290,6 +331,30 @@ class ThermosTest < ActiveSupport::TestCase
|
|
290
331
|
assert_raises(MockExpectationError) { mock.verify }
|
291
332
|
end
|
292
333
|
|
334
|
+
test "handles indirect associations" do
|
335
|
+
mock = Minitest::Mock.new
|
336
|
+
category = categories(:baseball)
|
337
|
+
store = category.store
|
338
|
+
|
339
|
+
Thermos.fill(key: "key", model: Store, deps: [categories: [:products]]) do |id|
|
340
|
+
mock.call(id)
|
341
|
+
end
|
342
|
+
|
343
|
+
mock.expect(:call, 1, [store.id])
|
344
|
+
category.update!(name: "foo")
|
345
|
+
mock.verify
|
346
|
+
|
347
|
+
mock.expect(:call, 2, [store.id])
|
348
|
+
assert_equal 1, Thermos.drink(key: "key", id: store.id)
|
349
|
+
assert_raises(MockExpectationError) { mock.verify }
|
350
|
+
Product.create!(categories: [category])
|
351
|
+
mock.verify
|
352
|
+
|
353
|
+
mock.expect(:call, 3, [store.id])
|
354
|
+
assert_equal 2, Thermos.drink(key: "key", id: store.id)
|
355
|
+
assert_raises(MockExpectationError) { mock.verify }
|
356
|
+
end
|
357
|
+
|
293
358
|
test "only rebuilds cache for stated dependencies, even if another cache has an associated model of the primary" do
|
294
359
|
category_mock = Minitest::Mock.new
|
295
360
|
product_mock = Minitest::Mock.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thermos
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Thal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,14 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.
|
19
|
+
version: 5.2.4
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 6.2.0
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.
|
29
|
+
version: 5.2.4
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 6.2.0
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: rake
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,64 +140,67 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
140
|
- - ">="
|
135
141
|
- !ruby/object:Gem::Version
|
136
142
|
version: 2.5.0
|
143
|
+
- - "<"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 2.8.0
|
137
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
147
|
requirements:
|
139
148
|
- - ">="
|
140
149
|
- !ruby/object:Gem::Version
|
141
150
|
version: '0'
|
142
151
|
requirements: []
|
143
|
-
rubygems_version: 3.0.3
|
152
|
+
rubygems_version: 3.0.3.1
|
144
153
|
signing_key:
|
145
154
|
specification_version: 4
|
146
155
|
summary: Always-warm, auto-rebuilding rails caching without timers or touching.
|
147
156
|
test_files:
|
148
|
-
- test/
|
157
|
+
- test/thermos_test.rb
|
149
158
|
- test/fixtures/categories.yml
|
150
|
-
- test/fixtures/stores.yml
|
151
159
|
- test/fixtures/products.yml
|
160
|
+
- test/fixtures/stores.yml
|
161
|
+
- test/fixtures/category_items.yml
|
162
|
+
- test/dummy/README.rdoc
|
163
|
+
- test/dummy/config.ru
|
164
|
+
- test/dummy/Rakefile
|
165
|
+
- test/dummy/db/schema.rb
|
166
|
+
- test/dummy/db/migrate/20160325214744_create_categories.rb
|
167
|
+
- test/dummy/db/migrate/20160326174530_create_stores.rb
|
168
|
+
- test/dummy/db/migrate/20160325214849_create_products.rb
|
169
|
+
- test/dummy/db/migrate/20160325220006_create_category_items.rb
|
170
|
+
- test/dummy/config/environment.rb
|
171
|
+
- test/dummy/config/secrets.yml
|
152
172
|
- test/dummy/config/application.rb
|
173
|
+
- test/dummy/config/environments/test.rb
|
174
|
+
- test/dummy/config/environments/development.rb
|
175
|
+
- test/dummy/config/environments/production.rb
|
153
176
|
- test/dummy/config/boot.rb
|
154
|
-
- test/dummy/config/routes.rb
|
155
177
|
- test/dummy/config/locales/en.yml
|
156
|
-
- test/dummy/config/
|
178
|
+
- test/dummy/config/database.yml
|
157
179
|
- test/dummy/config/initializers/cookies_serializer.rb
|
158
|
-
- test/dummy/config/initializers/
|
180
|
+
- test/dummy/config/initializers/assets.rb
|
181
|
+
- test/dummy/config/initializers/backtrace_silencers.rb
|
182
|
+
- test/dummy/config/initializers/mime_types.rb
|
159
183
|
- test/dummy/config/initializers/session_store.rb
|
184
|
+
- test/dummy/config/initializers/wrap_parameters.rb
|
160
185
|
- test/dummy/config/initializers/filter_parameter_logging.rb
|
161
|
-
- test/dummy/config/initializers/assets.rb
|
162
186
|
- test/dummy/config/initializers/inflections.rb
|
163
|
-
- test/dummy/config/
|
164
|
-
- test/dummy/
|
165
|
-
- test/dummy/
|
166
|
-
- test/dummy/
|
167
|
-
- test/dummy/
|
168
|
-
- test/dummy/config/environments/production.rb
|
169
|
-
- test/dummy/config/environments/test.rb
|
170
|
-
- test/dummy/bin/setup
|
171
|
-
- test/dummy/bin/rails
|
172
|
-
- test/dummy/bin/bundle
|
173
|
-
- test/dummy/bin/rake
|
174
|
-
- test/dummy/app/views/layouts/application.html.erb
|
175
|
-
- test/dummy/app/models/store.rb
|
176
|
-
- test/dummy/app/models/category.rb
|
177
|
-
- test/dummy/app/models/product.rb
|
187
|
+
- test/dummy/config/routes.rb
|
188
|
+
- test/dummy/public/500.html
|
189
|
+
- test/dummy/public/404.html
|
190
|
+
- test/dummy/public/422.html
|
191
|
+
- test/dummy/public/favicon.ico
|
178
192
|
- test/dummy/app/models/category_item.rb
|
179
|
-
- test/dummy/app/
|
180
|
-
- test/dummy/app/
|
193
|
+
- test/dummy/app/models/product.rb
|
194
|
+
- test/dummy/app/models/category.rb
|
195
|
+
- test/dummy/app/models/store.rb
|
196
|
+
- test/dummy/app/helpers/application_helper.rb
|
197
|
+
- test/dummy/app/views/layouts/application.html.erb
|
181
198
|
- test/dummy/app/assets/javascripts/application.js
|
199
|
+
- test/dummy/app/assets/stylesheets/application.css
|
200
|
+
- test/dummy/app/assets/config/manifest.js
|
182
201
|
- test/dummy/app/controllers/application_controller.rb
|
183
|
-
- test/dummy/
|
184
|
-
- test/dummy/
|
185
|
-
- test/dummy/
|
186
|
-
- test/dummy/
|
187
|
-
- test/dummy/db/migrate/20160325214744_create_categories.rb
|
188
|
-
- test/dummy/db/migrate/20160326174530_create_stores.rb
|
189
|
-
- test/dummy/public/404.html
|
190
|
-
- test/dummy/public/favicon.ico
|
191
|
-
- test/dummy/public/500.html
|
192
|
-
- test/dummy/public/422.html
|
193
|
-
- test/dummy/config.ru
|
194
|
-
- test/dummy/Rakefile
|
195
|
-
- test/dummy/README.rdoc
|
196
|
-
- test/thermos_test.rb
|
202
|
+
- test/dummy/bin/setup
|
203
|
+
- test/dummy/bin/bundle
|
204
|
+
- test/dummy/bin/rake
|
205
|
+
- test/dummy/bin/rails
|
197
206
|
- test/test_helper.rb
|