card 1.107.0 → 1.108.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/environments/development.rb +1 -9
  4. data/config/environments/test.rb +4 -4
  5. data/config/initializers/01_core_extensions/integer.rb +13 -0
  6. data/config/initializers/01_core_extensions/{persistent_identifiers.rb → persistent_identifier.rb} +0 -5
  7. data/config/initializers/01_core_extensions/symbol.rb +11 -0
  8. data/config/initializers/core_extensions.rb +2 -2
  9. data/db/schema.rb +9 -5
  10. data/lib/card/auth/token.rb +1 -1
  11. data/lib/card/cache/all.rb +30 -7
  12. data/lib/card/cache/card_class.rb +12 -6
  13. data/lib/card/cache/class_methods.rb +122 -0
  14. data/lib/card/cache/populate.rb +64 -0
  15. data/lib/card/cache/{persistent.rb → shared.rb} +22 -16
  16. data/lib/card/cache/{persistent_class.rb → shared_class.rb} +2 -2
  17. data/lib/card/cache/temporary.rb +40 -8
  18. data/lib/card/cache.rb +65 -130
  19. data/lib/card/codename.rb +66 -54
  20. data/lib/card/director/class_methods.rb +13 -13
  21. data/lib/card/director/stages.rb +1 -1
  22. data/lib/card/error.rb +8 -0
  23. data/lib/card/fetch/card_class.rb +5 -24
  24. data/lib/card/fetch/retrieve.rb +1 -1
  25. data/lib/card/fetch/store.rb +4 -18
  26. data/lib/card/format/nesting.rb +1 -1
  27. data/lib/card/format/registration.rb +15 -7
  28. data/lib/card/format/render.rb +16 -15
  29. data/lib/card/format.rb +11 -4
  30. data/lib/card/lexicon.rb +37 -23
  31. data/lib/card/mark.rb +2 -34
  32. data/lib/card/name/all.rb +3 -7
  33. data/lib/card/name/card_class.rb +2 -2
  34. data/lib/card/name/name_variants.rb +7 -1
  35. data/lib/card/name.rb +60 -12
  36. data/lib/card/query/card_class.rb +1 -1
  37. data/lib/card/query/card_query/match_attributes.rb +14 -4
  38. data/lib/card/query/card_query/relational_attributes.rb +2 -0
  39. data/lib/card/query/card_query/run.rb +9 -3
  40. data/lib/card/query/sql_statement.rb +1 -1
  41. data/lib/card/reference/all.rb +8 -3
  42. data/lib/card/reference.rb +4 -9
  43. data/lib/card/rule/cache.rb +2 -0
  44. data/lib/card/rule/read_rule_cache.rb +2 -0
  45. data/lib/card/set/event.rb +1 -4
  46. data/lib/card/set/format/abstract_format/view_opts.rb +1 -1
  47. data/lib/card/set/format/abstract_format.rb +20 -3
  48. data/lib/card/set/inheritance.rb +2 -3
  49. data/lib/card/set/pattern/all.rb +12 -0
  50. data/lib/card/subcards/add.rb +1 -1
  51. data/lib/card/subcards/remove.rb +1 -1
  52. data/lib/card/view/cache/cache_action.rb +24 -7
  53. data/lib/card/view/cache.rb +34 -6
  54. data/lib/card/view/options/voo_api.rb +1 -1
  55. data/lib/card/view.rb +1 -0
  56. data/lib/cardio/cli.rb +1 -1
  57. data/lib/cardio/command/rake_command.rb +10 -2
  58. data/lib/cardio/command/rspec_command/parser.rb +9 -11
  59. data/lib/cardio/command/rspec_command.rb +7 -3
  60. data/lib/cardio/generators/deck_helper.rb +7 -7
  61. data/lib/cardio/migration/port.rb +37 -0
  62. data/lib/cardio/migration.rb +5 -36
  63. data/lib/cardio/mod/class_methods.rb +1 -0
  64. data/lib/cardio/mod.rb +1 -1
  65. data/lib/cardio/railtie.rb +5 -4
  66. data/lib/cardio/utils.rb +1 -1
  67. data/lib/generators/deck/deck_generator.rb +5 -11
  68. data/lib/generators/deck/templates/Gemfile.erb +2 -2
  69. data/lib/generators/deck/templates/config/puma.rb +0 -6
  70. data/lib/generators/mod/mod_generator.rb +7 -0
  71. data/lib/generators/set/set_generator.rb +2 -1
  72. data/mod/core/config/locales/en.yml +1 -0
  73. data/mod/core/data/schema/20200805200729_add_unique_pair_indices.rb +1 -1
  74. data/mod/core/data/schema/20240628212556_add_trash_index.rb +11 -0
  75. data/mod/core/data/schema/20241017160402_unique_codename.rb +13 -0
  76. data/mod/core/data/transform/20140317035504_account_requests_to_signups.rb +4 -6
  77. data/mod/core/data/transform/20150724123438_update_file_and_image_cards.rb +1 -1
  78. data/mod/core/data/transform/20190320091257_upgrade_recaptcha_to_v3.rb +3 -3
  79. data/mod/core/data/transform/20190502130029_add_shark_and_help_desk_role.rb +1 -1
  80. data/mod/core/data/transform/20190822093633_move_help_text_to_code.rb +2 -2
  81. data/mod/core/data/transform/20190829205148_remove_add_help.rb +1 -1
  82. data/mod/core/lib/tasks/card/migrate.rake +6 -5
  83. data/mod/core/lib/tasks/card/mod.rake +3 -0
  84. data/mod/core/lib/tasks/card/seed.rake +1 -0
  85. data/mod/core/lib/tasks/card.rake +6 -2
  86. data/mod/core/set/all/autoname.rb +1 -1
  87. data/mod/core/set/all/codename.rb +6 -8
  88. data/mod/core/set/all/name_events.rb +7 -5
  89. data/mod/core/set/all/result.rb +1 -1
  90. data/mod/core/set/all/trash.rb +2 -4
  91. data/mod/core/set/all/type.rb +1 -1
  92. data/mod/core/set/self/mod.rb +1 -1
  93. data/mod/core/set/self/trash.rb +1 -1
  94. data/mod/core/spec/set/all/trash_spec.rb +3 -3
  95. metadata +29 -23
  96. data/lib/card/cache/prepopulate.rb +0 -48
@@ -69,9 +69,10 @@ class Card
69
69
  '\1: ')}:#{source_location.second}"
70
70
  end
71
71
 
72
- # :standard, :always, :never
72
+ # see {Abstract::Format}
73
+ # (:default), :yes, :deep, :always, :never
73
74
  def view_cache_setting view
74
- voo&.cache || view_setting(:cache, view) || :standard
75
+ voo&.cache || view_setting(:cache, view) || :default
75
76
  end
76
77
 
77
78
  def view_setting setting_name, view
@@ -79,19 +80,19 @@ class Card
79
80
  end
80
81
 
81
82
  def stub_render cached_content
82
- stub_debugging do
83
- expand_stubs cached_content
84
- end
85
- end
86
-
87
- def stub_debugging
88
- result = yield
89
- if Rails.env.development? && result =~ /stub/
90
- Rails.logger.debug "STUB IN RENDERED VIEW: #{card.name}: " \
91
- "#{voo.ok_view}\n#{result}"
92
- end
93
- result
94
- end
83
+ # stub_debugging do
84
+ expand_stubs cached_content
85
+ # end
86
+ end
87
+
88
+ # def stub_debugging
89
+ # result = yield
90
+ # if Rails.env.development? && result.is_a?(String) && result =~ /StUb/
91
+ # Rails.logger.debug "STUB IN RENDERED VIEW: #{card.name}: " \
92
+ # "#{voo.ok_view}\n#{result}"
93
+ # end
94
+ # result
95
+ # end
95
96
 
96
97
  def prepare_stub_nest stub_hash
97
98
  stub_card = Card.fetch_from_cast stub_hash[:cast]
data/lib/card/format.rb CHANGED
@@ -36,8 +36,14 @@ class Card
36
36
  delegate :basket, to: Set
37
37
  delegate :session, :params, to: Env
38
38
 
39
- def self.view_caching?
40
- true
39
+ @symbol = :base
40
+
41
+ class << self
42
+ attr_writer :symbol
43
+
44
+ def view_caching?
45
+ true
46
+ end
41
47
  end
42
48
 
43
49
  def initialize card, opts={}
@@ -85,8 +91,9 @@ class Card
85
91
  literal
86
92
  end
87
93
 
88
- def to_sym
89
- Card::Format.format_sym self
94
+ def symbol
95
+ self.class.symbol
90
96
  end
97
+ alias_method :to_sym, :symbol
91
98
  end
92
99
  end
data/lib/card/lexicon.rb CHANGED
@@ -2,9 +2,8 @@ class Card
2
2
  # Translates names to ids and vice versa via a cached "lex" representation:
3
3
  # name for simple cards, [left_id, right_id] for compound cards.
4
4
  #
5
- # Note, unlike Card::Fetch, Card::Lexicon:
6
- # 1. does NOT distinguish between trashed and untrashed cards.
7
- # 2. does NOT respect local name changes
5
+ # Note, unlike Card::Fetch, Card::Lexicon: does NOT return local name changes
6
+ # until stored
8
7
  module Lexicon
9
8
  class << self
10
9
  # param id [Integer]
@@ -33,10 +32,10 @@ class Card
33
32
  expire_lex card.lex_before_act
34
33
  end
35
34
 
36
- # def delete card
37
- # cache.delete card.id.to_s
38
- # cache.delete cache_key(card.lex_before_act)
39
- # end
35
+ def delete card
36
+ cache.delete card.id.to_s
37
+ cache.delete cache_key(card.lex_before_act)
38
+ end
40
39
 
41
40
  def lex_to_name lex
42
41
  return lex unless lex.is_a? Array
@@ -44,6 +43,18 @@ class Card
44
43
  lex.map { |side_id| name side_id or return }.join(Card::Name.joint).to_name
45
44
  end
46
45
 
46
+ def cache_key lex
47
+ "L-#{lex.is_a?(Array) ? lex.join('-') : lex.to_name.key}"
48
+ end
49
+
50
+ def lex_query lex
51
+ if lex.is_a?(Array)
52
+ { left_id: lex.first, right_id: lex.last }
53
+ else
54
+ { key: lex.to_name.key }
55
+ end
56
+ end
57
+
47
58
  # this is to address problems whereby renaming errors leave the lexicon broken.
48
59
  # NEEDS TESTING
49
60
  def rescuing
@@ -57,14 +68,23 @@ class Card
57
68
  raise e
58
69
  end
59
70
 
71
+ def write_to_temp_cache id, name, lex
72
+ cache.temp.write id.to_s, name if id.present?
73
+ cache.temp.write cache_key(lex), id if lex
74
+ end
75
+
76
+ def write id, name, lex
77
+ cache.write id.to_s, name
78
+ cache.write cache_key(lex), id
79
+ end
80
+
60
81
  private
61
82
 
62
83
  def add card
63
84
  lex = card.lex
64
85
  @act_lexes << lex
65
86
  @act_ids << card.id
66
- cache.write card.id.to_s, lex
67
- cache.write cache_key(lex), card.id
87
+ write card.id, card.name, card.lex
68
88
  end
69
89
 
70
90
  def expire_lex lex
@@ -80,7 +100,9 @@ class Card
80
100
  result = Card.where(id: id).pluck(:name, :left_id, :right_id).first
81
101
  return unless result
82
102
 
83
- result[0] || [result[1], result[2]]
103
+ (result[0] || [result[1], result[2]]).tap do |lex|
104
+ cache.write cache_key(lex), id
105
+ end
84
106
  end
85
107
  end
86
108
 
@@ -94,21 +116,13 @@ class Card
94
116
 
95
117
  def lex_to_id lex
96
118
  cache.fetch cache_key(lex) do
97
- Card.where(lex_query(lex)).pluck(:id).first
98
- end
99
- end
100
-
101
- def lex_query lex
102
- if lex.is_a?(Array)
103
- { left_id: lex.first, right_id: lex.last }
104
- else
105
- { key: lex.to_name.key }
119
+ query = lex_query(lex).merge trash: false
120
+ Card.where(query).pluck(:id).first.tap do |id|
121
+ # don't store name, because lex might not be the canonical name
122
+ cache.write id.to_s, lex if lex.is_a?(Array)
123
+ end
106
124
  end
107
125
  end
108
-
109
- def cache_key lex
110
- "L-#{lex.is_a?(Array) ? lex.join('-') : lex.to_name.key}"
111
- end
112
126
  end
113
127
  end
114
128
  end
data/lib/card/mark.rb CHANGED
@@ -2,9 +2,6 @@ class Card
2
2
  # Card::Mark provides class methods for Card to translate all different kind
3
3
  # of card identifiers to card objects.
4
4
  module Mark
5
- ID_MARK_RE = /^~(?<id>\d+)$/.freeze
6
- CODENAME_MARK_RE = /^:(?<codename>\w+)$/.freeze
7
-
8
5
  # translates marks (and other inputs) into a Card
9
6
  #
10
7
  # @param cardish [Card, Card::Name, String, Symbol, Integer]
@@ -26,42 +23,13 @@ class Card
26
23
  id_from_mark(mark) || Card::Name[mark]
27
24
  end
28
25
 
29
- # translates string identifiers into an id:
30
- # - string id notation (eg "~75")
31
- # - string codename notation (eg ":options")
32
- #
33
- # @param mark [String]
34
- # @return [Integer or nil]
35
- def id_from_string mark
36
- case mark
37
- when ID_MARK_RE then Regexp.last_match[:id].to_i
38
- when CODENAME_MARK_RE then Card::Codename.id! Regexp.last_match[:codename]
39
- end
40
- end
41
-
42
- def name_from_id_from_string id, string
43
- fetch_name(id) { bad_mark string }
44
- end
45
-
46
26
  private
47
27
 
48
- def bad_mark string
49
- case string
50
- when ID_MARK_RE
51
- raise Card::Error::NotFound, "id doesn't exist: #{Regexp.last_match[:id]}"
52
- when CODENAME_MARK_RE
53
- raise Card::Error::CodenameNotFound,
54
- "codename doesn't exist: #{Regexp.last_match[:codename]}"
55
- else
56
- raise Card::Error, "invalid mark: #{string}"
57
- end
58
- end
59
-
60
28
  def id_from_mark mark
61
29
  case mark
62
30
  when Integer then mark
63
- when Symbol then Card::Codename.id! mark
64
- when String then id_from_string mark
31
+ when Symbol then Codename.id! mark
32
+ when String then Name.id_from_string! mark
65
33
  when Card then mark.id
66
34
  end
67
35
  end
data/lib/card/name/all.rb CHANGED
@@ -36,12 +36,8 @@ class Card
36
36
  end
37
37
  end
38
38
 
39
- def lex
40
- simple? ? name : [left_id, right_id]
41
- end
42
-
43
39
  def autoname name
44
- if Card.exists?(name) || Director.include?(name)
40
+ if Card.exist?(name) || Director.include?(name)
45
41
  autoname name.next
46
42
  else
47
43
  name
@@ -107,8 +103,8 @@ class Card
107
103
 
108
104
  def update_cache_key oldkey
109
105
  yield
110
- was_in_cache = Card.cache.soft.delete oldkey
111
- Card.write_to_soft_cache self if was_in_cache
106
+ was_in_cache = Card.cache.temp.delete oldkey
107
+ Card.write_to_temp_cache self if was_in_cache
112
108
  end
113
109
 
114
110
  def update_subcard_name subcard, new_name, name_to_replace
@@ -8,7 +8,7 @@ class Card
8
8
 
9
9
  def uniquify_name name, rename=:new
10
10
  name = name.to_name
11
- return name unless Card.exists? name
11
+ return name unless Card.exist? name
12
12
 
13
13
  uniq_name = generate_alternative_name name
14
14
  return uniq_name unless rename == :old
@@ -19,7 +19,7 @@ class Card
19
19
 
20
20
  def generate_alternative_name name
21
21
  uniq_name = "#{name} 1"
22
- uniq_name.next! while Card.exists?(uniq_name)
22
+ uniq_name.next! while Card.exist?(uniq_name)
23
23
  uniq_name
24
24
  end
25
25
  end
@@ -15,7 +15,13 @@ class Card
15
15
 
16
16
  # @return [Card::Name] standardized based on card names
17
17
  def standard
18
- self.class.compose(parts.map { |part| Card.fetch_name(part) || part })
18
+ if simple?
19
+ id = Lexicon.id self
20
+ std = Lexicon.name id
21
+ std.present? ? std : self
22
+ else
23
+ self.class.compose(parts.map { |part| part.cardname.standard })
24
+ end
19
25
  end
20
26
 
21
27
  def card
data/lib/card/name.rb CHANGED
@@ -13,16 +13,13 @@ class Card
13
13
  include NameVariants
14
14
 
15
15
  class << self
16
+ ID_MARK_RE = /^~(?<id>\d+)$/
17
+ CODENAME_MARK_RE = /^:(?<codename>\w+)$/
18
+
19
+ # @return [Card::Name]
16
20
  def [] *cardish
17
21
  cardish = cardish.first if cardish.size <= 1
18
- case cardish
19
- when Card then cardish.name
20
- when Symbol, Integer then Card.fetch_name(cardish)
21
- when Array then compose cardish
22
- when String, NilClass then new cardish
23
- else
24
- raise ArgumentError, "#{cardish.class} not supported as name identifier"
25
- end
22
+ from_cardish(cardish) || unsupported_class!(cardish)
26
23
  end
27
24
 
28
25
  def session
@@ -39,9 +36,9 @@ class Card
39
36
  str = str.to_s
40
37
 
41
38
  if !validated_parts && str.include?(joint)
42
- string_compose Cardname.split_parts(str)
43
- elsif (id = Card.id_from_string str) # handles ~[id] and :[codename]
44
- Card.name_from_id_from_string id, str
39
+ new_from_compound_string str
40
+ elsif (id = id_from_string str) # handles ~[id] and :[codename]
41
+ from_id_from_string id, str
45
42
  else
46
43
  super str
47
44
  end
@@ -52,9 +49,43 @@ class Card
52
49
  new_from_parts(parts) { |part| self[part] }
53
50
  end
54
51
 
52
+ # translates string identifiers into an id:
53
+ # - string id notation (eg "~75")
54
+ # - string codename notation (eg ":options")
55
+ #
56
+ # @param string [String]
57
+ # @return [Integer or nil]
58
+ def id_from_string string
59
+ case string
60
+ when ID_MARK_RE then Regexp.last_match[:id].to_i
61
+ when CODENAME_MARK_RE then Card::Codename.id! Regexp.last_match[:codename]
62
+ end
63
+ end
64
+
65
+ def id_from_string! string
66
+ return unless (id = id_from_string string)
67
+
68
+ Lexicon.name(id) ? id : bad_mark(string)
69
+ end
70
+
55
71
  private
56
72
 
57
- def string_compose parts
73
+ def from_cardish cardish
74
+ case cardish
75
+ when Card then cardish.name
76
+ when Integer then Lexicon.name cardish
77
+ when Symbol then Codename.name! cardish
78
+ when Array then compose cardish
79
+ when String, NilClass then new cardish
80
+ end
81
+ end
82
+
83
+ def unsupported_class! cardish
84
+ raise ArgumentError, "#{cardish.class} not supported as name identifier"
85
+ end
86
+
87
+ def new_from_compound_string string
88
+ parts = Cardname.split_parts string
58
89
  new_from_parts(parts) { |part| new part }
59
90
  end
60
91
 
@@ -62,6 +93,23 @@ class Card
62
93
  name_parts = parts.flatten.map(&block)
63
94
  new name_parts.join(joint), true
64
95
  end
96
+
97
+ def from_id_from_string id, str
98
+ name = Lexicon.name id
99
+ name.present? ? name : bad_mark(str)
100
+ end
101
+
102
+ def bad_mark string
103
+ case string
104
+ when ID_MARK_RE
105
+ raise Card::Error::NotFound, "id doesn't exist: #{Regexp.last_match[:id]}"
106
+ when CODENAME_MARK_RE
107
+ raise Card::Error::CodenameNotFound,
108
+ "codename doesn't exist: #{Regexp.last_match[:codename]}"
109
+ else
110
+ raise Card::Error, "invalid mark: #{string}"
111
+ end
112
+ end
65
113
  end
66
114
 
67
115
  def star?
@@ -25,7 +25,7 @@ class Card
25
25
  if block_given?
26
26
  super do |records|
27
27
  yield(records)
28
- Card::Cache.reset_soft
28
+ Card::Cache.reset_temp
29
29
  end
30
30
  else
31
31
  super
@@ -21,21 +21,31 @@ class Card
21
21
  def complete val
22
22
  val = val.to_name
23
23
  if val.compound?
24
- interpret left: val.left
25
- interpret right: { complete: val.right } if val.right.present?
24
+ complete_compound val
26
25
  else
27
- add_condition "#{table_alias}.key LIKE '#{val.to_name.key}%'"
26
+ add_condition "#{table_alias}.key LIKE '#{val.to_name.key}%'" if val.present?
27
+ name_not_null
28
28
  end
29
29
  end
30
30
 
31
31
  # match term anywhere in name
32
32
  # DEPRECATE - move handling to name: ["match", val]
33
33
  def name_match val
34
- interpret name: [:match, val]
34
+ interpret name: [:match, val] if val.present?
35
+ name_not_null
35
36
  end
36
37
 
37
38
  private
38
39
 
40
+ def complete_compound val
41
+ interpret left: val.left
42
+ interpret right: { complete: val.right } if val.right.present?
43
+ end
44
+
45
+ def name_not_null
46
+ add_condition "#{table_alias}.key IS NOT NULL"
47
+ end
48
+
39
49
  def or_join conditions
40
50
  "(#{Array(conditions).join ' OR '})"
41
51
  end
@@ -67,6 +67,8 @@ class Card
67
67
  junction val, :right, :left_id
68
68
  end
69
69
 
70
+ # DEPRECATED - do not use until/unless optimized, especially with large dbs
71
+ # Multiple joins of cards to cards makes this difficult to scale
70
72
  def plus val
71
73
  any(left_plus: val, right_plus: val.deep_clone)
72
74
  end
@@ -19,11 +19,17 @@ class Card
19
19
  # @return [Array]
20
20
  def return_list sql_results, retrn
21
21
  large_list sql_results.length if sql_results.length > 1000
22
+ seed_cache sql_results, retrn
22
23
  sql_results.map do |record|
23
24
  return_simple record, retrn
24
25
  end
25
26
  end
26
27
 
28
+ def seed_cache sql_results, retrn
29
+ id_field = retrn.match?(/id$/) ? retrn : "id"
30
+ Cache.populate_ids(sql_results.map { |record| record[id_field] })
31
+ end
32
+
27
33
  def large_list length
28
34
  Rails.logger.info "#{length} records returned by #{@statement}"
29
35
  end
@@ -31,9 +37,9 @@ class Card
31
37
  def result_method retrn
32
38
  case
33
39
  when respond_to?(:"#{retrn}_result") then :"#{retrn}_result"
34
- when (retrn =~ /id$/) then :id_result
35
- when (retrn =~ /_\w+/) then :name_result
36
- when (retrn == "key") then :key_result
40
+ when retrn.match?(/id$/) then :id_result
41
+ when retrn.match?(/_\w+/) then :name_result
42
+ when retrn == "key" then :key_result
37
43
  else :default_result
38
44
  end
39
45
  end
@@ -38,7 +38,7 @@ class Card
38
38
  end
39
39
 
40
40
  def select
41
- "#{leading_space}SELECT DISTINCT #{@fields}"
41
+ "#{leading_space}SELECT #{'DISTINCT' if @joins.present?} #{@fields}"
42
42
  end
43
43
 
44
44
  def from
@@ -59,7 +59,7 @@ class Card
59
59
  end
60
60
  return if ref_hash.empty?
61
61
 
62
- Reference.mass_insert reference_values_array(ref_hash)
62
+ Reference.insert_in_slices reference_values_array(ref_hash)
63
63
  end
64
64
 
65
65
  # replace references in card content
@@ -101,9 +101,14 @@ class Card
101
101
  def reference_values_array ref_hash
102
102
  [].tap do |values|
103
103
  ref_hash.each do |referee_key, hash_val|
104
- referee_id = hash_val.shift || "null"
104
+ referee_id = hash_val.shift
105
105
  each_reference_type hash_val.uniq do |ref_type|
106
- values << [id, referee_id, "'#{referee_key}'", "'#{ref_type}'"]
106
+ values << {
107
+ referer_id: id,
108
+ referee_id: referee_id,
109
+ referee_key: referee_key,
110
+ ref_type: ref_type
111
+ }
107
112
  end
108
113
  end
109
114
  end
@@ -16,9 +16,10 @@ class Card
16
16
 
17
17
  class << self
18
18
  # bulk insert improves performance considerably
19
- # array takes form [ [referer_id, referee_id, referee_key, ref_type], ...]
20
- def mass_insert array
21
- Card.connection.execute mass_insert_sql(array) if array.present?
19
+ def insert_in_slices array
20
+ array.each_slice(5000) do |slice|
21
+ insert_all slice
22
+ end
22
23
  end
23
24
 
24
25
  # map existing reference to name to card via id
@@ -69,12 +70,6 @@ class Card
69
70
  yield card.include_set_modules
70
71
  end
71
72
  end
72
-
73
- def mass_insert_sql array
74
- value_statements = array.map { |values| "\n(#{values.join ', '})" }
75
- "INSERT into card_references (referer_id, referee_id, referee_key, ref_type) " \
76
- "VALUES #{value_statements.join ', '}"
77
- end
78
73
  end
79
74
  end
80
75
  end
@@ -36,6 +36,8 @@ class Card
36
36
  Card.cache.write cache_key, nil
37
37
  end
38
38
 
39
+ private
40
+
39
41
  def lookup_hash
40
42
  rows.each_with_object({}) do |row, hash|
41
43
  next unless (key = lookup_key row)
@@ -17,6 +17,8 @@ class Card
17
17
  self.cache_key = "READRULES".freeze
18
18
 
19
19
  class << self
20
+ private
21
+
20
22
  def lookup_hash
21
23
  rows.each_with_object({}) do |row, h|
22
24
  party_id = row["party_id"].to_i
@@ -166,10 +166,7 @@ class Card
166
166
 
167
167
  # one failed integration event should not harm others.
168
168
  def rescuing_integration
169
- yield
170
- rescue StandardError => e
171
- # puts "integration error: #{e.message}".red
172
- Card::Error.report e, self
169
+ Error.rescue_card(self) { yield }
173
170
  ensure
174
171
  true
175
172
  end
@@ -14,7 +14,7 @@ class Card
14
14
 
15
15
  # view setting values can be accessed from Format objects (eg within format
16
16
  # blocks in set modules) using #view_setting(:setting_name, :view_name)
17
- VIEW_SETTINGS = %i[cache compact denial perms unknown wrap].freeze
17
+ VIEW_SETTINGS = %i[cache compact denial perms unknown wrap expire].freeze
18
18
 
19
19
  # view def opts are used in defining views but are not available
20
20
  # at any later point
@@ -42,14 +42,31 @@ class Card
42
42
  # and then completing a request. Only applies to HtmlFormat
43
43
  #
44
44
  # * __:cache__ directs how to handle caching for this view. Supported values:
45
- # * *:standard* - (default)
45
+ # * *:default* - (default) do not independently cache this view. However, if
46
+ # this view is rendered by another view of the same card, and that view is
47
+ # cached, it's ok to cache it.
48
+ # * *:yes* - cache this view whenever it's safe to do so. Do NOT start
49
+ # a new caching when this view is rendered inside another view of the same
50
+ # card. And do NOT include
51
+ # nested cards in your cache. (Instead, stub them and process them
52
+ # separately)
46
53
  # * *:always* - cache even when rendered within another cached view
47
- # * *:never* - don't ever cache this view. Frequently used to prevent caching
48
- # problems
54
+ # * *:deep* cache this view and include nested cards
55
+ # * *:never* - don't ever cache this view, even if it's rendered by another
56
+ # view of the same card. Frequently used to prevent caching problems, when
57
+ # dynamic context (eg params) can alter the view.
49
58
  #
50
59
  # You should certainly {Card::View::Cache learn more about caching} if you want
51
60
  # to develop mods that are safe in a caching environment.
52
61
  #
62
+ # * __:expire__ handles cache expiration. (can only apply when cache setting is
63
+ # yes, always, or deep)
64
+ #
65
+ # * *:hour* - expire when the hour next changes
66
+ # * *:day* - expire when the day next changes
67
+ # * *:week* - expire when the week next changes
68
+ # * *:month* - expire when the month next changes
69
+ #
53
70
  # * __:compact__ [True/False]. Is view acceptable for rendering inside `compact`
54
71
  # view? Default is false.
55
72
  #
@@ -49,7 +49,7 @@ class Card
49
49
  # include_set_formats Type::Basic, except: :css
50
50
  def include_set_formats set, opts={}
51
51
  each_format set do |format, format_mods|
52
- format_sym = Card::Format.format_sym format
52
+ format_sym = format.to_sym
53
53
  next unless applicable_format?(format_sym, opts[:except], opts[:only])
54
54
 
55
55
  format_mods.each do |format_mod|
@@ -77,8 +77,7 @@ class Card
77
77
  Set.modules[format_type].each_pair { |*args| yield(*args) }
78
78
  end
79
79
 
80
- def applicable_format? format, except, only
81
- format_sym = Card::Format.format_sym format
80
+ def applicable_format? format_sym, except, only
82
81
  return false if except && Array(except).include?(format_sym)
83
82
  return false if only && !Array(only).include?(format_sym)
84
83
 
@@ -3,6 +3,18 @@ class Card
3
3
  module Pattern
4
4
  # pattern-related Card instance methods
5
5
  module All
6
+ # Because Card works by including set-specific ruby modules on singleton classes,
7
+ # and singleton classes generally can't be cached, we can never cache the cards
8
+ # in a completely ready-to-roll form.
9
+ #
10
+ # However, we can optimize considerably by saving the list of ruby modules in
11
+ # environments where they won't be changing (eg production) or at least the list
12
+ # of matching set patterns
13
+ def prep_modules_for_caching
14
+ patterns
15
+ set_modules if Cardio.config.cache_set_module_list
16
+ end
17
+
6
18
  def patterns?
7
19
  defined? @patterns
8
20
  end