card 1.101.3 → 1.101.4

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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/initializers/02_patches/active_record.rb +1 -1
  4. data/config/locales/en.yml +155 -378
  5. data/db/migrate_core_cards/20150202143810_import_bootstrap_layout.rb +1 -1
  6. data/lib/card.rb +15 -2
  7. data/lib/card/auth.rb +5 -2
  8. data/lib/card/auth/current.rb +39 -100
  9. data/lib/card/auth/proxy.rb +36 -16
  10. data/lib/card/auth/token.rb +6 -0
  11. data/lib/card/cache/all.rb +83 -0
  12. data/lib/card/cache/card_class.rb +41 -0
  13. data/lib/card/cache/persistent.rb +3 -34
  14. data/lib/card/cache/persistent_class.rb +28 -0
  15. data/lib/card/codename.rb +1 -1
  16. data/lib/card/content.rb +16 -2
  17. data/lib/card/content/all.rb +59 -0
  18. data/lib/card/director/act_direction.rb +4 -0
  19. data/lib/card/director/all.rb +61 -0
  20. data/lib/card/director/card_class.rb +18 -0
  21. data/lib/card/director/phases.rb +0 -1
  22. data/lib/card/dirty.rb +13 -3
  23. data/lib/card/env/success.rb +14 -14
  24. data/lib/card/env/success/target.rb +9 -11
  25. data/lib/card/error.rb +1 -1
  26. data/lib/card/fetch/all.rb +32 -0
  27. data/lib/card/fetch/card_class.rb +147 -0
  28. data/lib/card/format.rb +1 -1
  29. data/lib/card/format/error.rb +3 -3
  30. data/lib/card/format/nest.rb +1 -1
  31. data/lib/card/format/nest/fetch.rb +1 -1
  32. data/lib/card/lexicon.rb +2 -2
  33. data/lib/card/name/all.rb +8 -0
  34. data/lib/card/name/all/descendants.rb +6 -3
  35. data/lib/card/name/card_class.rb +26 -0
  36. data/lib/card/reference/all.rb +131 -0
  37. data/lib/card/rule/all.rb +75 -0
  38. data/lib/card/set/event/all.rb +95 -0
  39. data/lib/card/set/event/skip_and_trigger.rb +89 -0
  40. data/lib/card/set/pattern/all.rb +63 -0
  41. data/lib/card/subcards/all.rb +103 -0
  42. data/lib/cardio/migration/import.rb +1 -1
  43. data/lib/cardio/utils.rb +5 -3
  44. data/mod/admin/set/self/admin_info.rb +3 -5
  45. data/mod/admin/set/self/trash.rb +2 -2
  46. data/mod/core/set/all/autoname.rb +17 -0
  47. data/mod/core/set/all/codename.rb +2 -2
  48. data/mod/core/set/all/content.rb +52 -97
  49. data/mod/core/set/all/name_events.rb +69 -58
  50. data/mod/core/set/all/reference_events.rb +67 -0
  51. data/mod/core/set/all/states.rb +2 -2
  52. data/mod/core/set/all/subcards.rb +0 -100
  53. data/mod/core/set/all/trash.rb +11 -13
  54. data/mod/core/set/all/type.rb +7 -9
  55. data/mod/core/set/all/utils.rb +3 -0
  56. data/mod/core/set/type/cardtype.rb +3 -3
  57. data/mod/core/set_pattern/06_rule.rb +1 -1
  58. data/mod/core/spec/set/all/{rules2_spec.rb → clean_me_spec.rb} +0 -0
  59. data/mod/core/spec/set/all/name_events_spec.rb +204 -0
  60. metadata +30 -37
  61. data/lib/card/mod_inflector.rb +0 -16
  62. data/lib/card/name/all/class_methods.rb +0 -28
  63. data/mod/core/set/all/actify.rb +0 -68
  64. data/mod/core/set/all/cache.rb +0 -109
  65. data/mod/core/set/all/event_conditions.rb +0 -172
  66. data/mod/core/set/all/fetch.rb +0 -122
  67. data/mod/core/set/all/fetch_helper.rb +0 -35
  68. data/mod/core/set/all/i18n.rb +0 -9
  69. data/mod/core/set/all/pattern.rb +0 -54
  70. data/mod/core/set/all/references.rb +0 -191
  71. data/mod/core/set/all/rename.rb +0 -33
  72. data/mod/core/set/all/rules.rb +0 -81
  73. data/mod/core/spec/set/all/actify_spec.rb +0 -58
  74. data/mod/core/spec/set/all/content_spec.rb +0 -15
  75. data/mod/core/spec/set/all/event_conditions_spec.rb +0 -217
  76. data/mod/core/spec/set/all/fetch_helper_spec.rb +0 -65
  77. data/mod/core/spec/set/all/fetch_spec.rb +0 -338
  78. data/mod/core/spec/set/all/i18n_spec.rb +0 -17
  79. data/mod/core/spec/set/all/pattern_spec.rb +0 -101
  80. data/mod/core/spec/set/all/permissions/reader_rules_spec.rb +0 -166
  81. data/mod/core/spec/set/all/references_spec.rb +0 -62
  82. data/mod/core/spec/set/all/rename_spec.rb +0 -189
  83. data/mod/core/spec/set/all/rules_spec.rb +0 -100
  84. data/mod/core/spec/set/all/subcards_spec.rb +0 -102
@@ -0,0 +1,147 @@
1
+ class Card
2
+ class Fetch
3
+ # = Card#fetch
4
+ #
5
+ # A multipurpose retrieval operator that integrates caching, database lookups,
6
+ # and "virtual" card construction
7
+ module CardClass
8
+ # Look for cards in
9
+ # * cache
10
+ # * database
11
+ # * virtual cards
12
+ #
13
+ # @param args [Integer, String, Card::Name, Symbol, Array]
14
+ # one or more of the three unique identifiers
15
+ # 1. a numeric id (Integer)
16
+ # 2. a name/key (String or Card::Name)
17
+ # 3. a codename (Symbol)
18
+ # If you pass more then one mark or an array of marks they get joined with a '+'.
19
+ # The final argument can be a hash to set the following options
20
+ # :skip_virtual Real cards only
21
+ # :skip_modules Don't load Set modules
22
+ # :look_in_trash Return trashed card objects
23
+ # :local_only Use only local cache for lookup and storing
24
+ # new: { opts for Card#new } Return a new card when not found
25
+ # @return [Card]
26
+ def fetch *args
27
+ Card::Fetch.new(*args)&.retrieve_or_new
28
+ rescue ActiveModel::RangeError => _e
29
+ return Card.new name: "card id out of range: #{f.mark}"
30
+ end
31
+
32
+ # fetch only real (no virtual) cards
33
+ #
34
+ # @param mark - see #fetch
35
+ # @return [Card]
36
+ def [] *mark
37
+ fetch(*mark, skip_virtual: true)
38
+ end
39
+
40
+ # fetch real cards without set modules loaded. Should only be used for
41
+ # simple attributes
42
+ #
43
+ # @example
44
+ # quick_fetch "A", :self, :structure
45
+ #
46
+ # @param mark - see #fetch
47
+ # @return [Card]
48
+ def quick_fetch *mark
49
+ fetch(*mark, skip_virtual: true, skip_modules: true)
50
+ end
51
+
52
+ # @return [Card]
53
+ def fetch_from_cast cast
54
+ fetch_args = cast[:id] ? [cast[:id].to_i] : [cast[:name], { new: cast }]
55
+ fetch(*fetch_args)
56
+ end
57
+
58
+ #----------------------------------------------------------------------
59
+ # ATTRIBUTE FETCHING
60
+ # The following methods optimize fetching of specific attributes
61
+
62
+ def id cardish
63
+ case cardish
64
+ when Integer then cardish
65
+ when Card then cardish.id
66
+ when Symbol then Card::Codename.id cardish
67
+ else fetch_id cardish
68
+ end
69
+ end
70
+
71
+ # @param mark_parts - see #fetch
72
+ # @return [Integer]
73
+ def fetch_id *mark_parts
74
+ mark = Card::Fetch.new(*mark_parts)&.mark
75
+ mark.is_a?(Integer) ? mark : quick_fetch(mark.to_s)&.id
76
+ end
77
+
78
+ # @param mark - see #fetch
79
+ # @return [Card::Name]
80
+ def fetch_name *mark, &block
81
+ if (card = quick_fetch(*mark))
82
+ card.name
83
+ elsif block_given?
84
+ yield.to_name
85
+ end
86
+ rescue => error
87
+ rescue_fetch_name error, &block
88
+ end
89
+
90
+ # @param mark - see #fetch
91
+ # @return [Integer]
92
+ def fetch_type_id *mark
93
+ fetch(*mark, skip_modules: true)&.type_id
94
+ end
95
+
96
+ # a fetch method to support the needs of the card controller.
97
+ # should be in Decko?
98
+ def controller_fetch args
99
+ card_opts = controller_fetch_opts args
100
+ if args[:action] == "create"
101
+ # FIXME: we currently need a "new" card to catch duplicates
102
+ # (otherwise save will just act like a normal update)
103
+ # We may need a "#create" instance method to handle this checking?
104
+ Card.new card_opts
105
+ else
106
+ standard_controller_fetch args, card_opts
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def standard_controller_fetch args, card_opts
113
+ mark = args[:mark] || card_opts[:name]
114
+ card = Card.fetch mark, skip_modules: true,
115
+ look_in_trash: args[:look_in_trash],
116
+ new: card_opts
117
+ card.assign_attributes card_opts if args[:assign] && card&.real?
118
+ card&.include_set_modules
119
+ card
120
+ end
121
+
122
+ def controller_fetch_opts args
123
+ opts = Env.hash args[:card]
124
+ opts[:type] ||= args[:type] if args[:type]
125
+ # for /new/:type shortcut. we should handle in routing and deprecate this
126
+ opts[:name] ||= Name.url_key_to_standard args[:mark]
127
+ opts
128
+ end
129
+
130
+ def rescue_fetch_name error, &block
131
+ if rescued_fetch_name_to_name? error, &block
132
+ yield.to_name
133
+ elsif error.is_a? ActiveModel::RangeError
134
+ nil
135
+ else
136
+ raise error
137
+ end
138
+ end
139
+
140
+ def rescued_fetch_name_to_name? error
141
+ return unless block_given?
142
+
143
+ error.is_a?(ActiveModel::RangeError) || error.is_a?(Error::CodenameNotFound)
144
+ end
145
+ end
146
+ end
147
+ end
data/lib/card/format.rb CHANGED
@@ -47,7 +47,7 @@ class Card
47
47
  def require_card_to_initialize!
48
48
  return if @card
49
49
 
50
- raise Card::Error, Cardio.t(:exception_init_without_card)
50
+ raise Card::Error, Cardio.t(:lib_exception_init_without_card)
51
51
  end
52
52
 
53
53
  def include_set_format_modules
@@ -29,7 +29,7 @@ class Card
29
29
  end
30
30
 
31
31
  def monitor_depth
32
- raise Card::Error::UserError, tr(:too_deep) if depth >= Card.config.max_depth
32
+ raise Card::Error::UserError, t(:format_too_deep) if depth >= Card.config.max_depth
33
33
  yield
34
34
  end
35
35
 
@@ -42,7 +42,7 @@ class Card
42
42
  if card&.name.present?
43
43
  safe_name
44
44
  else
45
- Cardio.tr :no_cardname
45
+ Cardio.t :lib_no_cardname
46
46
  end
47
47
  end
48
48
 
@@ -71,7 +71,7 @@ class Card
71
71
  if exception.is_a? Card::Error::UserError
72
72
  exception.message
73
73
  else
74
- tr :error_rendering, cardname: error_cardname(exception), view: view
74
+ t :lib_error_rendering, cardname: error_cardname(exception), view: view
75
75
  end
76
76
  end
77
77
  end
@@ -2,7 +2,7 @@ class Card
2
2
  class Format
3
3
  # processing nests
4
4
  class Nest
5
- include Fetch
5
+ include Nest::Fetch
6
6
 
7
7
  attr_accessor :format, :card, :view, :view_opts, :format_opts
8
8
  def initialize format, cardish, view_opts={}, format_opts={}
@@ -24,7 +24,7 @@ class Card
24
24
  end
25
25
 
26
26
  def not_found_codename_error codename
27
- Cardio.tr :exception_unknown_codename, codename: codename
27
+ Cardio.t :lib_exception_unknown_codename, codename: codename
28
28
  end
29
29
 
30
30
  def new_card cardish
data/lib/card/lexicon.rb CHANGED
@@ -36,12 +36,12 @@ class Card
36
36
 
37
37
  def update card
38
38
  add card
39
- cache.delete cache_key(card.old_lex)
39
+ cache.delete cache_key(card.lex_before_act)
40
40
  end
41
41
 
42
42
  # def delete card
43
43
  # cache.delete card.id.to_s
44
- # cache.delete cache_key(card.old_lex)
44
+ # cache.delete cache_key(card.lex_before_act)
45
45
  # end
46
46
 
47
47
  def lex_to_name lex
data/lib/card/name/all.rb CHANGED
@@ -35,6 +35,10 @@ class Card
35
35
  end
36
36
  end
37
37
 
38
+ def lex
39
+ simple? ? name : [left_id, right_id]
40
+ end
41
+
38
42
  def autoname name
39
43
  if Card.exists?(name) || Director.include?(name)
40
44
  autoname name.next
@@ -64,6 +68,10 @@ class Card
64
68
  @key
65
69
  end
66
70
 
71
+ def field tag, opts={}
72
+ Card.fetch name.field(tag), opts
73
+ end
74
+
67
75
  private
68
76
 
69
77
  def assign_side_ids
@@ -19,9 +19,12 @@ class Card
19
19
  end
20
20
 
21
21
  def each_child
22
- child_ids.each do |id|
23
- (child = Card[id]) && yield(child)
24
- # check should not be needed (remove after fixing data problems)
22
+ return unless id
23
+
24
+ Card.where(
25
+ "(left_id = #{id} or right_id = #{id}) and trash is false"
26
+ ).each do |child|
27
+ yield child
25
28
  end
26
29
  end
27
30
 
@@ -0,0 +1,26 @@
1
+ class Card
2
+ class Name
3
+ # Name-related Card class methods
4
+ module CardClass
5
+ def rename! oldname, newname
6
+ Card[oldname].update! name: newname, update_referers: true
7
+ end
8
+
9
+ def uniquify_name name, rename=:new
10
+ return name unless Card.exists? name
11
+ uniq_name = generate_alternative_name name
12
+ return uniq_name unless rename == :old
13
+ rename!(name, uniq_name)
14
+ name
15
+ end
16
+
17
+ private
18
+
19
+ def generate_alternative_name name
20
+ uniq_name = "#{name} 1"
21
+ uniq_name.next! while Card.exists?(uniq_name)
22
+ uniq_name
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,131 @@
1
+ class Card
2
+ class Reference < ApplicationRecord
3
+ module All
4
+ # frozen_string_literal: true
5
+
6
+ # Cards can refer to other cards in their content, eg via links and nests.
7
+ # The card that refers is the "referer", the card that is referred to is
8
+ # the "referee". The reference itself has its own class (Card::Reference),
9
+ # which handles id-based reference tracking.
10
+
11
+ PARTIAL_REF_CODE = "P".freeze
12
+
13
+ # cards that refer to self
14
+ def referers
15
+ referer_cards_from_references references_in
16
+ end
17
+
18
+ # cards that include self
19
+ def nesters
20
+ referer_cards_from_references references_in.where(ref_type: "I")
21
+ end
22
+
23
+ def referer_cards_from_references references
24
+ references.map(&:referer_id).uniq.map(&Card.method(:fetch)).compact
25
+ end
26
+
27
+ # cards that self refers to
28
+ def referees
29
+ referees_from_references references_out
30
+ end
31
+
32
+ # cards that self includes
33
+ def nestees
34
+ referees_from_references references_out.where(ref_type: "I")
35
+ end
36
+
37
+ def referees_from_references references
38
+ references.map(&:referee_key).uniq.map { |key| Card.fetch key, new: {} }
39
+ end
40
+
41
+ # cards that refer to self by name
42
+ # (finds cards not yet linked by id)
43
+ def name_referers
44
+ Card.joins(:references_out).where card_references: { referee_key: key }
45
+ end
46
+
47
+ # delete old references from this card's content, create new ones
48
+ def update_references_out
49
+ delete_references_out
50
+ create_references_out
51
+ end
52
+
53
+ # interpret references from this card's content and
54
+ # insert entries in reference table
55
+ def create_references_out
56
+ ref_hash = {}
57
+ each_reference_out do |referee_name, ref_type|
58
+ interpret_reference ref_hash, referee_name, ref_type
59
+ end
60
+ return if ref_hash.empty?
61
+ Reference.mass_insert reference_values_array(ref_hash)
62
+ end
63
+
64
+ # delete references from this card
65
+ def delete_references_out
66
+ raise "id required to delete references" if id.nil?
67
+ Reference.where(referer_id: id).delete_all
68
+ end
69
+
70
+ private
71
+
72
+ def with_normalized_referee referee_name
73
+ return unless referee_name # eg commented nest has no referee_name
74
+ referee_name = referee_name.to_name
75
+ referee_key = referee_name.key
76
+ return if referee_key == key # don't create self reference
77
+ yield referee_name, referee_key, Lexicon.id(referee_name)
78
+ end
79
+
80
+ # interpretation phase helps to prevent duplicate references
81
+ # results in hash like:
82
+ # { referee1_key: [referee1_id, referee1_type2],
83
+ # referee2_key...
84
+ # }
85
+ def interpret_reference ref_hash, raw_referee_name, ref_type
86
+ with_normalized_referee raw_referee_name do |name, key, id|
87
+ ref_hash[key] ||= [id]
88
+ ref_hash[key] << ref_type
89
+ interpret_partial_references ref_hash, name unless id
90
+ end
91
+ end
92
+
93
+ # translate interpreted reference hash into values array,
94
+ # removing duplicate and unnecessary ref_types
95
+ def reference_values_array ref_hash
96
+ [].tap do |values|
97
+ ref_hash.each do |referee_key, hash_val|
98
+ referee_id = hash_val.shift || "null"
99
+ each_reference_type hash_val.uniq do |ref_type|
100
+ values << [id, referee_id, "'#{referee_key}'", "'#{ref_type}'"]
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def each_reference_type ref_types
107
+ ref_types.delete PARTIAL_REF_CODE if ref_types.size > 1
108
+ # partial references are not necessary if there are explicit references
109
+ ref_types.each { |ref_type| yield ref_type }
110
+ end
111
+
112
+ # invokes the given block for each reference in content with
113
+ # the reference name and reference type
114
+ def each_reference_out
115
+ content_object.find_chunks(:Reference).each do |chunk|
116
+ yield chunk.referee_name, chunk.reference_code
117
+ end
118
+ end
119
+
120
+ # Partial references are needed to track references to virtual cards.
121
+ # For example a link to virual card [[A+*self]] won't have a referee_id,
122
+ # but when A's name is changed we have to find and update that link.
123
+ def interpret_partial_references ref_hash, referee_name
124
+ return if referee_name.simple?
125
+ [referee_name.left, referee_name.right].each do |sidename|
126
+ interpret_reference ref_hash, sidename, PARTIAL_REF_CODE
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,75 @@
1
+ class Card
2
+ module Rule
3
+ # rule-related Card instance methods
4
+ module All
5
+ def rule setting_code
6
+ rule_card(setting_code, skip_modules: true)&.db_content
7
+ end
8
+
9
+ def rule_card setting_code, options={}
10
+ Card.fetch rule_card_id(setting_code), options
11
+ end
12
+
13
+ def rule_card_id setting_code
14
+ rule_id_lookup Card::Rule.rule_cache, setting_code
15
+ end
16
+
17
+ def preference setting_code, user=nil
18
+ preference_card(setting_code, user, skip_modules: true)&.db_content
19
+ end
20
+
21
+ def preference_card setting_code, user=nil, options={}
22
+ Card.fetch preference_card_id(setting_code, user), options
23
+ end
24
+
25
+ def preference_card_id setting_code, user=nil
26
+ return unless (user_id = preference_user_id user)
27
+ rule_id_lookup Card::Rule.preference_cache,
28
+ "#{setting_code}+#{user_id}",
29
+ "#{setting_code}+#{AllID}"
30
+ end
31
+
32
+ def rule?
33
+ standard_rule? || preference?
34
+ end
35
+
36
+ def standard_rule?
37
+ (Card.fetch_type_id(name.right) == SettingID) &&
38
+ (Card.fetch_type_id(name.left) == SetID)
39
+ end
40
+
41
+ def preference?
42
+ name.parts.length > 2 &&
43
+ (Card.fetch_type_id(name.right) == SettingID) &&
44
+ (Card.fetch_type_id(name[0..-3]) == SetID) &&
45
+ valid_preferer?
46
+ end
47
+
48
+ private
49
+
50
+ def valid_preferer?
51
+ preferer = self[-2, skip_modules: true]
52
+ (preferer.type_id == UserID) || (preferer.codename == :all)
53
+ end
54
+
55
+ def preference_user_id user
56
+ case user
57
+ when Integer then user
58
+ when Card then user.id
59
+ when nil then Auth.current_id
60
+ else
61
+ raise Card::ServerError, "invalid preference user"
62
+ end
63
+ end
64
+
65
+ def rule_id_lookup lookup_hash, cache_suffix, fallback_suffix=nil
66
+ rule_set_keys.each do |rule_set_key|
67
+ rule_id = lookup_hash["#{rule_set_key}+#{cache_suffix}"]
68
+ rule_id ||= fallback_suffix && lookup_hash["#{rule_set_key}+#{fallback_suffix}"]
69
+ return rule_id if rule_id
70
+ end
71
+ nil
72
+ end
73
+ end
74
+ end
75
+ end