card 1.107.0 → 1.108.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 +4 -4
- data/VERSION +1 -1
- data/config/environments/development.rb +1 -9
- data/config/environments/test.rb +4 -4
- data/config/initializers/01_core_extensions/integer.rb +13 -0
- data/config/initializers/01_core_extensions/{persistent_identifiers.rb → persistent_identifier.rb} +0 -5
- data/config/initializers/01_core_extensions/symbol.rb +11 -0
- data/config/initializers/core_extensions.rb +2 -2
- data/db/schema.rb +9 -5
- data/lib/card/auth/token.rb +1 -1
- data/lib/card/cache/all.rb +30 -7
- data/lib/card/cache/card_class.rb +12 -6
- data/lib/card/cache/class_methods.rb +122 -0
- data/lib/card/cache/populate.rb +64 -0
- data/lib/card/cache/{persistent.rb → shared.rb} +22 -16
- data/lib/card/cache/{persistent_class.rb → shared_class.rb} +2 -2
- data/lib/card/cache/temporary.rb +40 -8
- data/lib/card/cache.rb +65 -130
- data/lib/card/codename.rb +66 -54
- data/lib/card/director/class_methods.rb +13 -13
- data/lib/card/director/stages.rb +1 -1
- data/lib/card/error.rb +8 -0
- data/lib/card/fetch/card_class.rb +5 -24
- data/lib/card/fetch/retrieve.rb +1 -1
- data/lib/card/fetch/store.rb +4 -18
- data/lib/card/format/nesting.rb +1 -1
- data/lib/card/format/registration.rb +15 -7
- data/lib/card/format/render.rb +16 -15
- data/lib/card/format.rb +11 -4
- data/lib/card/lexicon.rb +37 -23
- data/lib/card/mark.rb +2 -34
- data/lib/card/name/all.rb +3 -7
- data/lib/card/name/card_class.rb +2 -2
- data/lib/card/name/name_variants.rb +7 -1
- data/lib/card/name.rb +60 -12
- data/lib/card/query/card_class.rb +1 -1
- data/lib/card/query/card_query/match_attributes.rb +14 -4
- data/lib/card/query/card_query/relational_attributes.rb +2 -0
- data/lib/card/query/card_query/run.rb +9 -3
- data/lib/card/query/sql_statement.rb +1 -1
- data/lib/card/reference/all.rb +8 -3
- data/lib/card/reference.rb +4 -9
- data/lib/card/rule/cache.rb +2 -0
- data/lib/card/rule/read_rule_cache.rb +2 -0
- data/lib/card/set/event.rb +1 -4
- data/lib/card/set/format/abstract_format/view_opts.rb +1 -1
- data/lib/card/set/format/abstract_format.rb +20 -3
- data/lib/card/set/inheritance.rb +2 -3
- data/lib/card/set/pattern/all.rb +12 -0
- data/lib/card/subcards/add.rb +1 -1
- data/lib/card/subcards/remove.rb +1 -1
- data/lib/card/view/cache/cache_action.rb +24 -7
- data/lib/card/view/cache.rb +34 -6
- data/lib/card/view/options/voo_api.rb +1 -1
- data/lib/card/view.rb +1 -0
- data/lib/cardio/cli.rb +1 -1
- data/lib/cardio/command/rake_command.rb +10 -2
- data/lib/cardio/command/rspec_command/parser.rb +9 -11
- data/lib/cardio/command/rspec_command.rb +7 -3
- data/lib/cardio/generators/deck_helper.rb +7 -7
- data/lib/cardio/migration/port.rb +37 -0
- data/lib/cardio/migration.rb +5 -36
- data/lib/cardio/mod/class_methods.rb +1 -0
- data/lib/cardio/mod.rb +1 -1
- data/lib/cardio/railtie.rb +5 -4
- data/lib/cardio/utils.rb +1 -1
- data/lib/generators/deck/deck_generator.rb +5 -11
- data/lib/generators/deck/templates/Gemfile.erb +2 -2
- data/lib/generators/deck/templates/config/puma.rb +0 -6
- data/lib/generators/mod/mod_generator.rb +7 -0
- data/lib/generators/set/set_generator.rb +2 -1
- data/mod/core/config/locales/en.yml +1 -0
- data/mod/core/data/schema/20200805200729_add_unique_pair_indices.rb +1 -1
- data/mod/core/data/schema/20240628212556_add_trash_index.rb +11 -0
- data/mod/core/data/schema/20241017160402_unique_codename.rb +13 -0
- data/mod/core/data/transform/20140317035504_account_requests_to_signups.rb +4 -6
- data/mod/core/data/transform/20150724123438_update_file_and_image_cards.rb +1 -1
- data/mod/core/data/transform/20190320091257_upgrade_recaptcha_to_v3.rb +3 -3
- data/mod/core/data/transform/20190502130029_add_shark_and_help_desk_role.rb +1 -1
- data/mod/core/data/transform/20190822093633_move_help_text_to_code.rb +2 -2
- data/mod/core/data/transform/20190829205148_remove_add_help.rb +1 -1
- data/mod/core/lib/tasks/card/migrate.rake +6 -5
- data/mod/core/lib/tasks/card/mod.rake +3 -0
- data/mod/core/lib/tasks/card/seed.rake +1 -0
- data/mod/core/lib/tasks/card.rake +6 -2
- data/mod/core/set/all/autoname.rb +1 -1
- data/mod/core/set/all/codename.rb +6 -8
- data/mod/core/set/all/name_events.rb +7 -5
- data/mod/core/set/all/result.rb +1 -1
- data/mod/core/set/all/trash.rb +2 -4
- data/mod/core/set/all/type.rb +1 -1
- data/mod/core/set/self/mod.rb +1 -1
- data/mod/core/set/self/trash.rb +1 -1
- data/mod/core/spec/set/all/trash_spec.rb +3 -3
- metadata +29 -23
- data/lib/card/cache/prepopulate.rb +0 -48
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae50e986081ed9e3618c1b92ccfbedfc19a9076529cb17360700506fd8acb054
|
|
4
|
+
data.tar.gz: c383ab4419aee1792ff33d7e667858a40f3063d6132d03f5bd9530725b56ac78
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1241479974329e34712f63ef0b3e00942a7a775a87c7e397bca3540114e1ef4a1757be95ee3dd7e8511963db768990e02b14dae74b8c31f1aea8b52ebffb948f
|
|
7
|
+
data.tar.gz: ea15daab38b40f7a41a272459f4c197724f22d9d7d37582ca30c70b01ad73b3140ade6fde2d990b6877fbc8beab9158e351622a2d8f7dd02029d5f8c32875a10
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.18.1
|
|
@@ -4,7 +4,7 @@ Cardio.application.class.configure do
|
|
|
4
4
|
# Settings specified here will take precedence over those in config/application.rb
|
|
5
5
|
|
|
6
6
|
config.view_cache = false
|
|
7
|
-
|
|
7
|
+
# config.cache_log_level = :debug
|
|
8
8
|
config.eager_load = false
|
|
9
9
|
|
|
10
10
|
config.asset_refresh = :eager
|
|
@@ -38,14 +38,6 @@ Cardio.application.class.configure do
|
|
|
38
38
|
# in the nest where the error occurred
|
|
39
39
|
config.raise_all_rendering_errors = true
|
|
40
40
|
|
|
41
|
-
# config.performance_logger = {
|
|
42
|
-
# methods: [:event, :search, :fetch, :view], # choose methods to log
|
|
43
|
-
# min_time: 100, # show only method calls that are slower than 100ms
|
|
44
|
-
# max_depth: 3, # show nested method calls only up to depth 3
|
|
45
|
-
# details: true # show method arguments and sql
|
|
46
|
-
# log_level: :info
|
|
47
|
-
# }
|
|
48
|
-
|
|
49
41
|
# Only use best-standards-support built into browsers
|
|
50
42
|
config.action_dispatch.best_standards_support = :builtin
|
|
51
43
|
|
data/config/environments/test.rb
CHANGED
|
@@ -16,8 +16,8 @@ Cardio.application.class.configure do
|
|
|
16
16
|
|
|
17
17
|
config.assets.enabled = true if Object.const_defined?(:JasmineRails)
|
|
18
18
|
|
|
19
|
-
config.
|
|
20
|
-
config.
|
|
19
|
+
config.shared_cache = false
|
|
20
|
+
config.seed_cache_from_stash = true
|
|
21
21
|
|
|
22
22
|
# Configure static asset server for tests with Cache-Control for performance
|
|
23
23
|
config.serve_static_files = true
|
|
@@ -46,13 +46,13 @@ Cardio.application.class.configure do
|
|
|
46
46
|
# config.action_mailer.delivery_method = :smtp
|
|
47
47
|
# config.action_mailer.smtp_settings = { address: "localhost", port: 1025 }
|
|
48
48
|
|
|
49
|
-
# Use SQL instead of
|
|
49
|
+
# Use SQL instead of ActiveRecord's schema dumper when creating the test database.
|
|
50
50
|
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
|
51
51
|
# like if you have constraints or database-specific column types
|
|
52
52
|
# config.active_record.schema_format = :sql
|
|
53
53
|
|
|
54
54
|
# FIXME: - add back the next one when we go back to 3.2
|
|
55
|
-
# Raise exception on mass assignment protection for
|
|
55
|
+
# Raise exception on mass assignment protection for ActiveRecord models
|
|
56
56
|
# config.active_record.mass_assignment_sanitizer = :strict
|
|
57
57
|
|
|
58
58
|
# Print deprecation notices to the stderr
|
|
@@ -9,8 +9,8 @@ module CoreExtensions
|
|
|
9
9
|
::String.include String
|
|
10
10
|
::Array.include Array
|
|
11
11
|
::Hash.include Hash::Merging
|
|
12
|
-
::Symbol.include
|
|
13
|
-
::Integer.include
|
|
12
|
+
::Symbol.include Symbol
|
|
13
|
+
::Integer.include Integer
|
|
14
14
|
::Hash.extend Hash::ClassMethods::Nesting
|
|
15
15
|
::MatchData.include MatchData
|
|
16
16
|
end
|
data/db/schema.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# This file is auto-generated from the current state of the database. Instead
|
|
2
|
-
# of editing this file, please use the migrations feature of
|
|
2
|
+
# of editing this file, please use the migrations feature of ActiveRecord to
|
|
3
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
|
4
4
|
#
|
|
5
5
|
# This file is the source Rails uses to define your schema when running `bin/rails
|
|
@@ -9,6 +9,10 @@
|
|
|
9
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
|
+
#
|
|
13
|
+
# Remark: We used to use size: medium for text columns. This option is supported by mysql but not by postgres.
|
|
14
|
+
# limit: 16.megabytes - 1 translates to the same size in mysql databases.
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
ActiveRecord::Schema.define(version: 2022_10_31_182227) do
|
|
14
18
|
|
|
@@ -36,7 +40,7 @@ ActiveRecord::Schema.define(version: 2022_10_31_182227) do
|
|
|
36
40
|
create_table "card_changes", id: :integer, charset: "utf8mb3", force: :cascade do |t|
|
|
37
41
|
t.integer "card_action_id"
|
|
38
42
|
t.integer "field"
|
|
39
|
-
t.text "value",
|
|
43
|
+
t.text "value", limit: 16.megabytes - 1
|
|
40
44
|
t.index ["card_action_id"], name: "card_changes_card_action_id_index"
|
|
41
45
|
end
|
|
42
46
|
|
|
@@ -65,7 +69,7 @@ ActiveRecord::Schema.define(version: 2022_10_31_182227) do
|
|
|
65
69
|
t.integer "left_id"
|
|
66
70
|
t.integer "right_id"
|
|
67
71
|
t.string "left_key"
|
|
68
|
-
t.text "content",
|
|
72
|
+
t.text "content", limit: 16.megabytes - 1
|
|
69
73
|
t.datetime "updated_at"
|
|
70
74
|
t.index ["left_id"], name: "right_id_index"
|
|
71
75
|
t.index ["right_id"], name: "left_id_index"
|
|
@@ -87,7 +91,7 @@ ActiveRecord::Schema.define(version: 2022_10_31_182227) do
|
|
|
87
91
|
t.integer "references_expired"
|
|
88
92
|
t.boolean "trash", null: false
|
|
89
93
|
t.integer "type_id", null: false
|
|
90
|
-
t.text "db_content",
|
|
94
|
+
t.text "db_content", limit: 16.megabytes - 1
|
|
91
95
|
t.index ["codename"], name: "cards_codename_index"
|
|
92
96
|
t.index ["created_at"], name: "cards_created_at_index"
|
|
93
97
|
t.index ["key"], name: "cards_key_index", unique: true
|
|
@@ -102,7 +106,7 @@ ActiveRecord::Schema.define(version: 2022_10_31_182227) do
|
|
|
102
106
|
create_table "delayed_jobs", charset: "utf8mb3", force: :cascade do |t|
|
|
103
107
|
t.integer "priority", default: 0, null: false
|
|
104
108
|
t.integer "attempts", default: 0, null: false
|
|
105
|
-
t.text "handler",
|
|
109
|
+
t.text "handler", limit: 16.megabytes - 1, null: false
|
|
106
110
|
t.text "last_error"
|
|
107
111
|
t.datetime "run_at"
|
|
108
112
|
t.datetime "locked_at"
|
data/lib/card/auth/token.rb
CHANGED
data/lib/card/cache/all.rb
CHANGED
|
@@ -2,12 +2,25 @@ class Card
|
|
|
2
2
|
class Cache
|
|
3
3
|
# cache-related instance methods available to all Cards
|
|
4
4
|
module All
|
|
5
|
+
def write_lexicon
|
|
6
|
+
Lexicon.write_to_temp_cache id, name, lex
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def lex
|
|
10
|
+
if simple?
|
|
11
|
+
name
|
|
12
|
+
elsif left_id && right_id
|
|
13
|
+
[left_id, right_id]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
5
17
|
def expire cache_type=nil
|
|
6
18
|
return unless (cache_class = cache_class_from_type cache_type)
|
|
7
19
|
|
|
8
20
|
expire_views
|
|
9
21
|
expire_names cache_class
|
|
10
22
|
expire_id cache_class
|
|
23
|
+
expire_left cache_type
|
|
11
24
|
end
|
|
12
25
|
|
|
13
26
|
def view_cache_clean?
|
|
@@ -18,18 +31,28 @@ class Card
|
|
|
18
31
|
return if view_cache_keys.include? cache_key
|
|
19
32
|
|
|
20
33
|
view_cache_keys << cache_key
|
|
21
|
-
|
|
34
|
+
shared_write_view_cache_keys
|
|
22
35
|
end
|
|
23
36
|
|
|
24
37
|
private
|
|
25
38
|
|
|
26
|
-
def
|
|
27
|
-
|
|
39
|
+
def expire_left cache_type
|
|
40
|
+
return unless name.compound? && expire_left?
|
|
41
|
+
|
|
42
|
+
Card.cache.read(name.left_name.key)&.expire cache_type
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def expire_left?
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def shared_read_view_cache_keys key_root=key
|
|
50
|
+
Card.cache.shared&.read_attribute key_root, :view_cache_keys
|
|
28
51
|
end
|
|
29
52
|
|
|
30
|
-
def
|
|
53
|
+
def shared_write_view_cache_keys
|
|
31
54
|
# puts "WRITE VIEW CACHE KEYS (#{name}): #{view_cache_keys}"
|
|
32
|
-
Card.cache.
|
|
55
|
+
Card.cache.shared&.write_attribute key, :view_cache_keys, view_cache_keys
|
|
33
56
|
end
|
|
34
57
|
|
|
35
58
|
def cache_class_from_type cache_type
|
|
@@ -37,7 +60,7 @@ class Card
|
|
|
37
60
|
end
|
|
38
61
|
|
|
39
62
|
def view_cache_keys
|
|
40
|
-
@view_cache_keys ||=
|
|
63
|
+
@view_cache_keys ||= shared_read_view_cache_keys(key) || []
|
|
41
64
|
end
|
|
42
65
|
|
|
43
66
|
def expire_names cache
|
|
@@ -58,7 +81,7 @@ class Card
|
|
|
58
81
|
def expire_views
|
|
59
82
|
each_key_version do |key|
|
|
60
83
|
# puts "EXPIRE VIEW CACHE (#{name}): #{view_cache_keys}"
|
|
61
|
-
view_keys =
|
|
84
|
+
view_keys = shared_read_view_cache_keys key
|
|
62
85
|
next unless view_keys.present?
|
|
63
86
|
|
|
64
87
|
expire_view_cache_keys view_keys
|
|
@@ -2,10 +2,16 @@ class Card
|
|
|
2
2
|
class Cache
|
|
3
3
|
# cache-related class methods
|
|
4
4
|
module CardClass
|
|
5
|
-
def
|
|
6
|
-
|
|
5
|
+
def cache
|
|
6
|
+
Card::Cache[Card]
|
|
7
|
+
end
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
def after_write_to_temp_cache card
|
|
10
|
+
card.write_lexicon if card.is_a? Card
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def retrieve_from_cache cache_key, local_only=false
|
|
14
|
+
local_only ? cache.temp.read(cache_key) : cache.read(cache_key)
|
|
9
15
|
end
|
|
10
16
|
|
|
11
17
|
def retrieve_from_cache_by_id id, local_only=false
|
|
@@ -21,16 +27,16 @@ class Card
|
|
|
21
27
|
|
|
22
28
|
def write_to_cache card, local_only=false
|
|
23
29
|
if local_only
|
|
24
|
-
|
|
30
|
+
write_to_temp_cache card
|
|
25
31
|
elsif cache
|
|
26
32
|
cache.write card.key, card
|
|
27
33
|
end
|
|
28
34
|
end
|
|
29
35
|
|
|
30
|
-
def
|
|
36
|
+
def write_to_temp_cache card
|
|
31
37
|
return unless cache
|
|
32
38
|
|
|
33
|
-
cache.
|
|
39
|
+
cache.temp.write card.key, card, callback: false
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
def expire name
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
|
|
2
|
+
class Card
|
|
3
|
+
class Cache
|
|
4
|
+
# class methods for Card::Cache
|
|
5
|
+
module ClassMethods
|
|
6
|
+
include Populate
|
|
7
|
+
|
|
8
|
+
attr_accessor :no_renewal
|
|
9
|
+
attr_accessor :counter
|
|
10
|
+
|
|
11
|
+
# create a new cache for the ruby class provided
|
|
12
|
+
# @param klass [Class]
|
|
13
|
+
# @return [{Card::Cache}]
|
|
14
|
+
def [] klass
|
|
15
|
+
raise "nil klass" if klass.nil?
|
|
16
|
+
|
|
17
|
+
cache_by_class[klass] ||= new class: klass, store: (shared_cache || nil)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# clear the temporary caches and ensure we're using the latest stamp
|
|
21
|
+
# on the shared caches.
|
|
22
|
+
def renew
|
|
23
|
+
# Cardio.config.cache_log_level = :debug
|
|
24
|
+
# Cardio.config.view_cache = true
|
|
25
|
+
# Cardio.config.asset_refresh = :cautious
|
|
26
|
+
# Cache.reset_all
|
|
27
|
+
|
|
28
|
+
Card::Cache.counter = nil
|
|
29
|
+
return if no_renewal
|
|
30
|
+
|
|
31
|
+
renew_shared
|
|
32
|
+
cache_by_class.each_value do |cache|
|
|
33
|
+
cache.temp.reset
|
|
34
|
+
cache.shared&.renew
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
populate_temp_cache
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def renew_shared
|
|
41
|
+
Card::Cache::Shared.renew if shared_cache
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# reset standard cached for all classes
|
|
45
|
+
def reset
|
|
46
|
+
reset_shared
|
|
47
|
+
reset_temp
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# reset all caches for all classes
|
|
51
|
+
def reset_all
|
|
52
|
+
reset_shared
|
|
53
|
+
reset_temp
|
|
54
|
+
reset_other
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# completely wipe out all caches, often including the Shared cache of
|
|
58
|
+
# other decks using the same mechanism.
|
|
59
|
+
# Generally prefer {.reset_all}
|
|
60
|
+
# @see .reset_all
|
|
61
|
+
def reset_global
|
|
62
|
+
cache_by_class.each_value do |cache|
|
|
63
|
+
cache.temp.reset
|
|
64
|
+
cache.shared&.annihilate
|
|
65
|
+
end
|
|
66
|
+
reset_other
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# reset the Shared cache for all classes
|
|
70
|
+
def reset_shared
|
|
71
|
+
Card::Cache::Shared.reset if shared_cache
|
|
72
|
+
cache_by_class.each_value do |cache|
|
|
73
|
+
cache.shared&.reset
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# reset the Temporary cache for all classes
|
|
78
|
+
def reset_temp
|
|
79
|
+
cache_by_class.each_value { |cache| cache.temp.reset }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# reset Codename cache and delete tmp files
|
|
83
|
+
# (the non-standard caches)
|
|
84
|
+
def reset_other
|
|
85
|
+
Card::Codename.reset_cache
|
|
86
|
+
Cardio::Utils.delete_tmp_files!
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def restore
|
|
90
|
+
reset_temp
|
|
91
|
+
seed_from_stash
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def shared_on!
|
|
95
|
+
return if @shared_cache
|
|
96
|
+
|
|
97
|
+
@cache_by_class = {}
|
|
98
|
+
@shared_cache = Cardio.config.shared_cache && Cardio.cache
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def cache_by_class
|
|
102
|
+
@cache_by_class ||= {}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def shared_cache
|
|
106
|
+
return @shared_cache unless @shared_cache.nil?
|
|
107
|
+
|
|
108
|
+
@shared_cache = (ENV["NO_RAILS_CACHE"] != "true") && shared_on!
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def tallies
|
|
112
|
+
"#{tally_total} Cache calls (" + counter.map { |k, v| "#{k}=#{v} " }.join + ")"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def tally_total
|
|
118
|
+
counter.values.map(&:values).flatten.sum
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
class Card
|
|
2
|
+
class Cache
|
|
3
|
+
# population-related class methods for Card::Cache
|
|
4
|
+
module Populate
|
|
5
|
+
def populate_ids ids
|
|
6
|
+
# use ids to look up names
|
|
7
|
+
results = Lexicon.cache.read_multi(ids.map(&:to_s)).values
|
|
8
|
+
names = []
|
|
9
|
+
pairs = []
|
|
10
|
+
results.each do |result|
|
|
11
|
+
result.is_a?(String) ? (names << result) : (pairs << result)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
if pairs.any?
|
|
15
|
+
populate_ids pairs.flatten
|
|
16
|
+
names += pairs.map(&:cardname)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# use keys to look up
|
|
20
|
+
populate_names names
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def populate_names names
|
|
24
|
+
keys = names.map { |n| n.to_name.key }
|
|
25
|
+
Card.cache.read_multi keys
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def populate_fields list, *fields
|
|
29
|
+
name_arrays = list.each_with_object([]) do |item, arrays|
|
|
30
|
+
fields.flatten.each do |field|
|
|
31
|
+
arrays << [item, field]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
populate_names name_arrays
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def populate_temp_cache
|
|
40
|
+
return unless shared_cache
|
|
41
|
+
|
|
42
|
+
populate_ids Codename.ids
|
|
43
|
+
# Codename.process_codenames if result.blank?
|
|
44
|
+
Card.cache.read_multi Set.basket[:cache_seed_strings]
|
|
45
|
+
populate_names Set.basket[:cache_seed_names]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# for testing, stash rules in variable and use that to re-seed cache
|
|
49
|
+
def seed_from_stash
|
|
50
|
+
return unless Cardio.config.seed_cache_from_stash
|
|
51
|
+
|
|
52
|
+
stash_to_cache("RULES") { Card::Rule.rule_cache }
|
|
53
|
+
stash_to_cache("READRULES") { Card::Rule.read_rule_cache }
|
|
54
|
+
stash_to_cache("PREFERENCES") { Card::Rule.preference_cache }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def stash_to_cache variable
|
|
58
|
+
@stash ||= {}
|
|
59
|
+
value = @stash[variable] ||= yield
|
|
60
|
+
Card.cache.temp.write variable, value.clone
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -2,23 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
class Card
|
|
4
4
|
class Cache
|
|
5
|
-
#
|
|
5
|
+
# _Shared_ caches closely mirror the database and are
|
|
6
6
|
# intended to be altered only upon database alterations.
|
|
7
7
|
#
|
|
8
|
-
# Unlike the database, the
|
|
8
|
+
# Unlike the database, the shared cache stores records of records that
|
|
9
9
|
# have been requested but are missing or, in the case of some {Card cards},
|
|
10
10
|
# "virtual", meaning that they follow known patterns but do not exist in the
|
|
11
11
|
# database.
|
|
12
12
|
#
|
|
13
|
-
# Most
|
|
13
|
+
# Most shared cache implementations cannot store objects with singleton
|
|
14
14
|
# classes, therefore {Card cards} generally must have set_modules
|
|
15
|
-
# re-included after retrieval from the
|
|
15
|
+
# re-included after retrieval from the shared cache.
|
|
16
16
|
#
|
|
17
|
-
class
|
|
18
|
-
extend
|
|
19
|
-
|
|
20
|
-
attr_accessor :prefix
|
|
21
|
-
|
|
17
|
+
class Shared
|
|
18
|
+
extend SharedClass
|
|
22
19
|
# @param opts [Hash]
|
|
23
20
|
# @option opts [Rails::Cache] :store
|
|
24
21
|
# @option opts [ruby Class] :class, typically ActiveRecord descendant
|
|
@@ -82,27 +79,36 @@ class Card
|
|
|
82
79
|
@store.read full_key(key)
|
|
83
80
|
end
|
|
84
81
|
|
|
82
|
+
def read_multi keys
|
|
83
|
+
map = keys.each_with_object({}) { |k, h| h[full_key k] = k }
|
|
84
|
+
raw = @store.read_multi(*map.keys)
|
|
85
|
+
raw.each_with_object({}) { |(k, v), h| h[map[k]] = v }
|
|
86
|
+
end
|
|
87
|
+
|
|
85
88
|
# update an attribute of an object already in the cache
|
|
86
89
|
# @param key [String]
|
|
87
90
|
# @param attribute [String, Symbol]
|
|
88
91
|
def write_attribute key, attribute, value
|
|
89
92
|
return value unless @store
|
|
90
93
|
|
|
91
|
-
if (object = deep_read key)
|
|
94
|
+
# if (object = deep_read key)
|
|
95
|
+
if (object = read key)
|
|
92
96
|
object.instance_variable_set "@#{attribute}", value
|
|
93
97
|
write key, object
|
|
94
98
|
end
|
|
95
99
|
value
|
|
96
100
|
end
|
|
97
101
|
|
|
98
|
-
def deep_read key
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
# def deep_read key
|
|
103
|
+
# binding.pry
|
|
104
|
+
# # local_cache = @store.send :local_cache
|
|
105
|
+
# # local_cache&.clear
|
|
106
|
+
# read key
|
|
107
|
+
# end
|
|
103
108
|
|
|
104
109
|
def read_attribute key, attribute
|
|
105
|
-
object = deep_read key
|
|
110
|
+
# object = deep_read key
|
|
111
|
+
object = read key
|
|
106
112
|
object.instance_variable_get "@#{attribute}"
|
|
107
113
|
end
|
|
108
114
|
|
data/lib/card/cache/temporary.rb
CHANGED
|
@@ -8,30 +8,47 @@ class Card
|
|
|
8
8
|
# In practice, it's a set of Cache-like methods for using a
|
|
9
9
|
# simple Hash.
|
|
10
10
|
#
|
|
11
|
-
# Unlike the
|
|
11
|
+
# Unlike the Shared cache, the Temporary cache can handle objects with
|
|
12
12
|
# singleton classes.
|
|
13
13
|
class Temporary
|
|
14
|
+
MAX_KEYS = 10_000
|
|
14
15
|
attr_reader :store
|
|
15
16
|
|
|
16
|
-
def initialize
|
|
17
|
+
def initialize klass
|
|
18
|
+
@klass = klass
|
|
17
19
|
@store = {}
|
|
20
|
+
@reps = 0
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
# @param key [String]
|
|
21
24
|
def read key
|
|
22
|
-
return unless @store.key? key
|
|
23
|
-
|
|
24
25
|
@store[key]
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
# @param key [String]
|
|
28
|
-
def write key, value
|
|
29
|
-
|
|
29
|
+
def write key, value, callback: true
|
|
30
|
+
within_key_counts do
|
|
31
|
+
@store[key] = value.tap do
|
|
32
|
+
@reps += 1
|
|
33
|
+
@klass.try :after_write_to_temp_cache, value if callback
|
|
34
|
+
end
|
|
35
|
+
end
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
# @param key [String]
|
|
33
|
-
def fetch key
|
|
34
|
-
read(key) || write(key, yield)
|
|
39
|
+
def fetch key
|
|
40
|
+
# read(key) || write(key, yield)
|
|
41
|
+
exist?(key) ? read(key) : write(key, yield)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def fetch_multi keys
|
|
45
|
+
@store.slice(*keys).tap do |found|
|
|
46
|
+
missing = keys - found.keys
|
|
47
|
+
if (newfound = missing.present? && yield(missing))
|
|
48
|
+
found.merge! newfound
|
|
49
|
+
newfound.each { |key, value| write key, value }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
35
52
|
end
|
|
36
53
|
|
|
37
54
|
# @param key [String]
|
|
@@ -46,6 +63,7 @@ class Card
|
|
|
46
63
|
end
|
|
47
64
|
|
|
48
65
|
def reset
|
|
66
|
+
@reps = 0
|
|
49
67
|
@store = {}
|
|
50
68
|
end
|
|
51
69
|
|
|
@@ -53,6 +71,20 @@ class Card
|
|
|
53
71
|
def exist? key
|
|
54
72
|
@store.key? key
|
|
55
73
|
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# enforces MAX_KEYS. The @reps count increments with each write but may
|
|
78
|
+
# overestimate the store size, because of multiple writes to the same key.
|
|
79
|
+
# (but this approach avoids recounting each time)
|
|
80
|
+
def within_key_counts
|
|
81
|
+
if @reps >= MAX_KEYS && (@reps = @store.size) > MAX_KEYS
|
|
82
|
+
Rails.logger.info "RESETTING temporary #{@klass} cache. " \
|
|
83
|
+
"MAX_KEYS (#{MAX_KEYS}) exceeded"
|
|
84
|
+
reset
|
|
85
|
+
end
|
|
86
|
+
yield
|
|
87
|
+
end
|
|
56
88
|
end
|
|
57
89
|
end
|
|
58
90
|
end
|