card 1.108.1 → 1.109.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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/environments/development.rb +1 -1
  4. data/config/environments/production.rb +5 -2
  5. data/config/initializers/01_core_extensions/array.rb +1 -0
  6. data/config/initializers/01_core_extensions/hash.rb +4 -0
  7. data/config/initializers/02_patches/active_record.rb +1 -1
  8. data/config/initializers/core_extensions.rb +0 -1
  9. data/config/initializers/deck_config.rb +3 -3
  10. data/config/initializers/patches.rb +6 -6
  11. data/lib/card/auth/current.rb +8 -6
  12. data/lib/card/auth.rb +7 -6
  13. data/lib/card/cache/class_methods.rb +2 -4
  14. data/lib/card/cache/shared.rb +1 -1
  15. data/lib/card/cache/temporary.rb +2 -2
  16. data/lib/card/codename.rb +0 -1
  17. data/lib/card/content/chunk/abstract.rb +1 -0
  18. data/lib/card/content/chunk.rb +0 -1
  19. data/lib/card/content/clean.rb +4 -2
  20. data/lib/card/content/diff/l_c_s.rb +1 -2
  21. data/lib/card/content/diff/result.rb +2 -1
  22. data/lib/card/content/diff.rb +2 -1
  23. data/lib/card/content/parser.rb +8 -7
  24. data/lib/card/content.rb +1 -1
  25. data/lib/card/director/subdirector_array.rb +1 -0
  26. data/lib/card/director.rb +1 -1
  27. data/lib/card/dirty/method_factory.rb +1 -0
  28. data/lib/card/env/location.rb +3 -3
  29. data/lib/card/env/location_history.rb +12 -11
  30. data/lib/card/env/success/target.rb +4 -4
  31. data/lib/card/env/support.rb +24 -2
  32. data/lib/card/error.rb +1 -0
  33. data/lib/card/fetch/store.rb +1 -1
  34. data/lib/card/format/error.rb +1 -0
  35. data/lib/card/format/method_delegation.rb +6 -4
  36. data/lib/card/format/registration.rb +5 -3
  37. data/lib/card/format/wrapper.rb +1 -0
  38. data/lib/card/mailer.rb +1 -14
  39. data/lib/card/name/all/parts.rb +1 -1
  40. data/lib/card/name/all.rb +1 -0
  41. data/lib/card/name/name_variants.rb +1 -0
  42. data/lib/card/query/abstract_query/query_helper.rb +1 -2
  43. data/lib/card/query/abstract_query/tie.rb +1 -1
  44. data/lib/card/query/abstract_query.rb +3 -3
  45. data/lib/card/query/card_class.rb +1 -0
  46. data/lib/card/query/clause.rb +1 -0
  47. data/lib/card/query/join.rb +3 -3
  48. data/lib/card/reference/all.rb +6 -7
  49. data/lib/card/rule/cache.rb +1 -0
  50. data/lib/card/rule/preference_cache.rb +2 -0
  51. data/lib/card/rule/read_rule_cache.rb +3 -0
  52. data/lib/card/set/event/all.rb +6 -4
  53. data/lib/card/set/event/callbacks.rb +1 -0
  54. data/lib/card/set/event/options.rb +3 -2
  55. data/lib/card/set/event/skip_and_trigger.rb +1 -1
  56. data/lib/card/set/event.rb +2 -2
  57. data/lib/card/set/format/abstract_format/view_definition.rb +1 -1
  58. data/lib/card/set/format/haml_paths.rb +1 -1
  59. data/lib/card/set/format.rb +4 -4
  60. data/lib/card/set/helpers.rb +4 -4
  61. data/lib/card/set/i18n_scanner.rb +23 -22
  62. data/lib/card/set/i18n_scope.rb +4 -3
  63. data/lib/card/set/pattern/all.rb +1 -1
  64. data/lib/card/set/pattern/base.rb +6 -3
  65. data/lib/card/set/pattern/class_methods.rb +1 -1
  66. data/lib/card/set/pattern.rb +1 -1
  67. data/lib/card/set/required_field.rb +3 -0
  68. data/lib/card/set/trait.rb +6 -1
  69. data/lib/card/subcards/all.rb +12 -4
  70. data/lib/card/view/cache/cache_action.rb +1 -1
  71. data/lib/card/view/cache.rb +1 -1
  72. data/lib/card/view/classy.rb +5 -5
  73. data/lib/card/view/options/key_lists.rb +1 -0
  74. data/lib/card/view/options/voo_api.rb +1 -1
  75. data/lib/cardio/command/application.rb +1 -1
  76. data/lib/cardio/command/custom.rb +7 -6
  77. data/lib/cardio/command/rake_command.rb +3 -2
  78. data/lib/cardio/command/rspec_command.rb +1 -0
  79. data/lib/cardio/generators/deck_generator_loader.rb +1 -1
  80. data/lib/cardio/generators.rb +4 -3
  81. data/lib/cardio/migration/port.rb +2 -0
  82. data/lib/cardio/migration/stamp.rb +1 -0
  83. data/lib/cardio/migration/transform.rb +1 -0
  84. data/lib/cardio/migration.rb +2 -0
  85. data/lib/cardio/mod/class_methods.rb +1 -2
  86. data/lib/cardio/mod/dirs.rb +2 -4
  87. data/lib/cardio/mod/eat/edibles.rb +8 -6
  88. data/lib/cardio/mod/eat.rb +6 -5
  89. data/lib/cardio/mod/load_strategy/set_binding_magic.rb +1 -1
  90. data/lib/cardio/mod/load_strategy/tmp_files.rb +3 -2
  91. data/lib/cardio/mod/load_strategy.rb +1 -0
  92. data/lib/cardio/mod/loader/set_pattern_loader.rb +4 -0
  93. data/lib/cardio/mod/loader/set_template.rb +14 -4
  94. data/lib/cardio/mod/loader.rb +2 -2
  95. data/lib/cardio/mod/sow/card_source.rb +1 -1
  96. data/lib/cardio/mod/sow/remote_source.rb +32 -0
  97. data/lib/cardio/mod/sow.rb +10 -10
  98. data/lib/cardio/railtie.rb +1 -0
  99. data/lib/cardio/script_loader.rb +1 -1
  100. data/lib/cardio/seed.rb +1 -1
  101. data/lib/cardio/utils.rb +1 -1
  102. data/lib/cardio/version.rb +2 -1
  103. data/lib/cardio.rb +3 -0
  104. data/lib/generators/deck/templates/config.ru.erb +1 -1
  105. data/mod/core/config/locales/en.yml +1 -0
  106. data/mod/core/data/schema/20141001105348_move_revisions_to_actions.rb +2 -2
  107. data/mod/core/data/schema/20241017160402_unique_codename.rb +8 -0
  108. data/mod/core/data/transform/20150724123438_update_file_and_image_cards.rb +1 -1
  109. data/mod/core/lib/tasks/card/export.rake +28 -0
  110. data/mod/core/lib/tasks/card/migrate.rake +3 -3
  111. data/mod/core/lib/tasks/card/seed.rake +2 -1
  112. data/mod/core/lib/tasks/card.rake +47 -16
  113. data/mod/core/set/all/admin.rb +1 -2
  114. data/mod/core/set/all/assign_attributes.rb +3 -2
  115. data/mod/core/set/all/codename.rb +7 -0
  116. data/mod/core/set/all/debug.rb +3 -3
  117. data/mod/core/set/all/initialize.rb +1 -0
  118. data/mod/core/set/all/states.rb +7 -6
  119. data/mod/core/set/all/type.rb +2 -0
  120. data/mod/core/set/all/utils.rb +0 -1
  121. data/mod/core/set/self/admin.rb +2 -1
  122. data/mod/core/set/self/autoname.rb +1 -1
  123. data/mod/core/set/self/mod.rb +4 -4
  124. data/mod/core/set/self/trash.rb +1 -1
  125. data/mod/core/set/type/mod.rb +18 -15
  126. data/mod/core/set_pattern/09_self.rb +4 -0
  127. data/mod/core/spec/set/all/trash_spec.rb +7 -7
  128. metadata +42 -29
data/lib/card/mailer.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "open-uri"
4
4
 
5
5
  class Card
6
+ # extends ActionMailer with card config
6
7
  class Mailer < ActionMailer::Base
7
8
  class << self
8
9
  def new_mail *args, &block
@@ -14,20 +15,6 @@ class Card
14
15
  end
15
16
  end
16
17
 
17
- def layout message
18
- <<-HTML
19
- <!DOCTYPE html>
20
- <html>
21
- <head>
22
- <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
23
- </head>
24
- <body>
25
- #{message}
26
- </body>
27
- </html>
28
- HTML
29
- end
30
-
31
18
  def defaults_from_config
32
19
  (Card.config.email_defaults || {}).symbolize_keys.tap do |defaults|
33
20
  defaults[:return_path] ||= defaults[:from] if defaults[:from]
@@ -5,7 +5,7 @@ class Card
5
5
  module Parts
6
6
  def left *args
7
7
  case
8
- when simple? then nil
8
+ when simple? then nil
9
9
  when superleft then superleft
10
10
  when name_is_changing? && name.to_name.trunk_name == name_before_act.to_name
11
11
  nil # prevent recursion when, eg, renaming A+B to A+B+C
data/lib/card/name/all.rb CHANGED
@@ -8,6 +8,7 @@ class Card
8
8
  # TODO: use delegations and include more name functions
9
9
  delegate :simple?, :compound?, :junction?, to: :name
10
10
  attr_reader :supercard
11
+
11
12
  def name
12
13
  @name ||= left_id ? Lexicon.lex_to_name([left_id, right_id]) : super.to_name
13
14
  end
@@ -1,5 +1,6 @@
1
1
  class Card
2
2
  class Name
3
+ # variants of card names
3
4
  module NameVariants
4
5
  @@variant_methods = %i[capitalize singularize pluralize titleize
5
6
  downcase upcase swapcase reverse succ]
@@ -19,13 +19,12 @@ class Card
19
19
  end
20
20
 
21
21
  def table_alias
22
- @table_alias ||= begin
22
+ @table_alias ||=
23
23
  if fasten == :direct
24
24
  @superquery.table_alias
25
25
  else
26
26
  "#{table_prefix}#{root.table_seq}#{@table_suffix}"
27
27
  end
28
- end
29
28
  end
30
29
 
31
30
  def table_seq
@@ -107,7 +107,7 @@ class Card
107
107
  end
108
108
 
109
109
  def list_of_ids? val
110
- return unless val.is_a? Array
110
+ return false unless val.is_a? Array
111
111
 
112
112
  !val.find { |v| !id_from_val v }
113
113
  end
@@ -71,10 +71,10 @@ class Card
71
71
  end
72
72
 
73
73
  def context
74
- if !@context.nil?
75
- @context
76
- else
74
+ if @context.nil?
77
75
  @context = superquery ? superquery.context : ""
76
+ else
77
+ @context
78
78
  end
79
79
  end
80
80
 
@@ -1,5 +1,6 @@
1
1
  class Card
2
2
  module Query
3
+ # query-related methods with which to extend Card class
3
4
  module CardClass
4
5
  def search spec, comment=nil, &block
5
6
  results = ::Card::Query.run(spec, comment)
@@ -1,5 +1,6 @@
1
1
  class Card
2
2
  module Query
3
+ # shared methods for query clauses
3
4
  module Clause
4
5
  # attr_accessor :clause
5
6
 
@@ -44,10 +44,10 @@ class Card
44
44
  end
45
45
 
46
46
  def side
47
- if !@side.nil?
48
- @side.to_s.upcase
49
- else
47
+ if @side.nil?
50
48
  @side = inside_or? ? "LEFT" : nil
49
+ else
50
+ @side.to_s.upcase
51
51
  end
52
52
  end
53
53
 
@@ -1,13 +1,12 @@
1
1
  class Card
2
2
  class Reference < Cardio::Record
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.
3
+ # frozen_string_literal: true
10
4
 
5
+ # Cards can refer to other cards in their content, eg via links and nests.
6
+ # The card that refers is the "referer", the card that is referred to is
7
+ # the "referee". The reference itself has its own class (Card::Reference),
8
+ # which handles id-based reference tracking.
9
+ module All
11
10
  PARTIAL_REF_CODE = "P".freeze
12
11
 
13
12
  # cards that refer to self
@@ -1,5 +1,6 @@
1
1
  class Card
2
2
  module Rule
3
+ # a cache of all card rules in the deck
3
4
  class Cache
4
5
  class_attribute :sql, :cache_key
5
6
 
@@ -1,5 +1,7 @@
1
1
  class Card
2
2
  module Rule
3
+ # a preference is a user-specific rule.
4
+ # This caches all preferences in the deck
3
5
  class PreferenceCache < Cache
4
6
  self.sql = %(
5
7
  SELECT
@@ -1,5 +1,8 @@
1
1
  class Card
2
2
  module Rule
3
+ # the read rule cache, unlike the standard rule cache, is optimized for lookups
4
+ # based on the rules' values, because this is needed for high-performance
5
+ # permission-checking
3
6
  class ReadRuleCache < Cache
4
7
  self.sql = %(
5
8
  SELECT
@@ -14,7 +14,9 @@ class Card
14
14
  include SkipAndTrigger
15
15
 
16
16
  def event_applies? event
17
- return unless set_condition_applies? event.set_module, event.opts[:changing]
17
+ unless set_condition_applies? event.set_module, event.opts[:changing]
18
+ return false
19
+ end
18
20
 
19
21
  CONDITIONS.all? { |c| send "#{c}_condition_applies?", event, event.opts[c] }
20
22
  end
@@ -91,10 +93,10 @@ class Card
91
93
  def wrong_stage opts
92
94
  return false if director.stage_ok? opts
93
95
 
94
- if !stage
95
- "phase method #{method} called outside of event phases"
96
- else
96
+ if stage
97
97
  "#{opts.inspect} method #{method} called in stage #{stage}"
98
+ else
99
+ "phase method #{method} called outside of event phases"
98
100
  end
99
101
  end
100
102
 
@@ -1,6 +1,7 @@
1
1
  class Card
2
2
  module Set
3
3
  class Event
4
+ # handle card event callbacks
4
5
  module Callbacks
5
6
  def set_event_callbacks
6
7
  %i[before after around].each do |kind|
@@ -1,6 +1,7 @@
1
1
  class Card
2
2
  module Set
3
3
  class Event
4
+ # handle options available for event definition
4
5
  module Options
5
6
  def validate_conditions
6
7
  @opts.each do |key, val|
@@ -32,8 +33,8 @@ class Card
32
33
  return if invalid.empty?
33
34
 
34
35
  raise ArgumentError,
35
- "invalid option#{'s' if invalid.size > 1} '#{invalid}' "\
36
- "for condition '#{condition}' in event '#{@event}'"
36
+ "invalid option#{'s' if invalid.size > 1} '#{invalid}' " \
37
+ "for condition '#{condition}' in event '#{@event}'"
37
38
  end
38
39
 
39
40
  def invalid_condition_values condition, val
@@ -7,7 +7,7 @@ class Card
7
7
  :skip, # [Array] skip event(s) for all cards in act
8
8
  :skip_in_action, # [Array] skip event for just this card
9
9
  :trigger, # [Array] trigger event(s) for all cards in act
10
- :trigger_in_action, # [Array] trigger event for just this card
10
+ :trigger_in_action # [Array] trigger event for just this card
11
11
  ]
12
12
  attr_reader(*settings)
13
13
 
@@ -165,8 +165,8 @@ class Card
165
165
  end
166
166
 
167
167
  # one failed integration event should not harm others.
168
- def rescuing_integration
169
- Error.rescue_card(self) { yield }
168
+ def rescuing_integration &block
169
+ Error.rescue_card(self, &block)
170
170
  ensure
171
171
  true
172
172
  end
@@ -58,7 +58,7 @@ class Card
58
58
 
59
59
  views[mod][alias_to] || begin
60
60
  raise "cannot find #{alias_to} view in #{mod}; " \
61
- "failed to alias #{view} from #{self}"
61
+ "failed to alias #{view} from #{self}"
62
62
  end
63
63
  end
64
64
  end
@@ -46,7 +46,7 @@ class Card
46
46
  end
47
47
  end
48
48
 
49
- TMPSET_REGEXP = %r{^.*/tmp(sets)?/set/[\w-]+/mod\d{3}-(?<modname>[^/]+)}
49
+ TMPSET_REGEXP = %r{^.*/tmp(?:sets)?/set/[\w-]+/mod\d{3}-(?<modname>[^/]+)}
50
50
 
51
51
  def deep_source source
52
52
  return source unless tmp_files?
@@ -103,14 +103,14 @@ class Card
103
103
 
104
104
  # shortcut for {AbstractFormat#view} for when #view is called outside of a format
105
105
  # block
106
- def view *args, &block
107
- format { view(*args, &block) }
106
+ def view(...)
107
+ format { view(...) }
108
108
  end
109
109
 
110
110
  # shortcut for {AbstractFormat#before} for when #before is called outside of a
111
111
  # format block
112
- def before view, &block
113
- format { before view, &block }
112
+ def before(...)
113
+ format { before(...) }
114
114
  end
115
115
 
116
116
  private
@@ -10,7 +10,7 @@ class Card
10
10
  # Card::Set::Type::User
11
11
  def shortname
12
12
  first = 2 # shortname eliminates Card::Set
13
- last = first + num_set_parts(pattern_code)
13
+ last = pattern_code == :self ? -1 : (first + num_set_parts)
14
14
  set_name_parts[first..last].join "::"
15
15
  end
16
16
 
@@ -88,7 +88,7 @@ class Card
88
88
  end
89
89
 
90
90
  def test_set
91
- # rubocop:disable Lint/Eval
91
+ # rubocop:disable Security/Eval
92
92
  ::Card::Set::Self.const_remove_if_defined :TestSet
93
93
  eval <<-RUBY, binding, __FILE__, __LINE__ + 1
94
94
  class ::Card::Set::Self
@@ -99,7 +99,7 @@ class Card
99
99
  end
100
100
  RUBY
101
101
  ::Card::Set::Self::TestSet
102
- # rubocop:enable Lint/Eval
102
+ # rubocop:enable Security/Eval
103
103
  end
104
104
 
105
105
  def base_format_modules?
@@ -115,7 +115,7 @@ class Card
115
115
  Card::Set.modules[set_format_type_key][format_class][shortname] || []
116
116
  end
117
117
 
118
- def num_set_parts pattern_code
118
+ def num_set_parts
119
119
  return 1 if pattern_code == :abstract
120
120
 
121
121
  Pattern.find(pattern_code).anchor_parts_count
@@ -1,23 +1,24 @@
1
1
  # lib/my_custom_scanner.rb
2
- require "i18n/tasks/scanners/file_scanner"
3
- class Card
4
- module Set
5
- class I18nScanner < ::I18n::Tasks::Scanners::FileScanner
6
- include ::I18n::Tasks::Scanners::RelativeKeys
7
- include ::I18n::Tasks::Scanners::OccurrenceFromPosition
8
-
9
- # @return [Array<[absolute key, Results::Occurrence]>]
10
- def scan_file path
11
- text = read_file(path)
12
-
13
- text.scan(/[^\w._-]tr[( ]\s*["':](\w+)/).map do |_match|
14
- occurrence = occurrence_from_position(
15
- path, text, Regexp.last_match.offset(0).first
16
- )
17
- [absolute_key(".#{_match[0]}", path), occurrence]
18
- end
19
- end
20
- end
21
- ::I18n::Tasks.add_scanner "Card::Set::I18nScanner"
22
- end
23
- end
2
+ # require "i18n/tasks/scanners/file_scanner"
3
+ # class Card
4
+ # module Set
5
+ # class I18nScanner < ::I18n::Tasks::Scanners::FileScanner
6
+ # include ::I18n::Tasks::Scanners::RelativeKeys
7
+ # include ::I18n::Tasks::Scanners::OccurrenceFromPosition
8
+ #
9
+ # # @return [Array<[absolute key, Results::Occurrence]>]
10
+ # def scan_file path
11
+ # text = read_file(path)
12
+ #
13
+ # # tr()
14
+ # text.scan(/[^\w._-]tr[( ]\s*["':](\w+)/).map do |_match|
15
+ # occurrence = occurrence_from_position(
16
+ # path, text, Regexp.last_match.offset(0).first
17
+ # )
18
+ # [absolute_key(".#{_match[0]}", path), occurrence]
19
+ # end
20
+ # end
21
+ # end
22
+ # ::I18n::Tasks.add_scanner "Card::Set::I18nScanner"
23
+ # end
24
+ # end
@@ -1,5 +1,6 @@
1
1
  class Card
2
2
  module Set
3
+ # Adapt Internationalization(i18n) scope handling to infer mod prefixes.
3
4
  module I18nScope
4
5
  delegate :tmp_files?, to: Cardio::Mod::LoadStrategy
5
6
 
@@ -22,7 +23,7 @@ class Card
22
23
 
23
24
  def set_from_parts parts, index
24
25
  start_index = index + (tmp_files? ? 2 : 1)
25
- parts[start_index..-1].join "."
26
+ parts[start_index..].join "."
26
27
  end
27
28
 
28
29
  def mod_from_parts parts, set_index
@@ -55,7 +56,7 @@ class Card
55
56
  # this method returns ["core", "all", "event"]
56
57
  # def set_path_parts backtrace
57
58
  # parts = path_parts backtrace
58
- # res = parts[path_mod_index(parts)..-1]
59
+ # res = parts[path_mod_index(parts)..]
59
60
  # res.delete_at 1
60
61
  # end
61
62
 
@@ -65,7 +66,7 @@ class Card
65
66
  # this method returns ["core", "all", "event"]
66
67
  # def tmp_set_path_parts backtrace
67
68
  # path_parts = find_tmp_set_path(backtrace).split(File::SEPARATOR)
68
- # res = path_parts[tmp_path_mod_index(path_parts)..-1]
69
+ # res = path_parts[tmp_path_mod_index(path_parts)..]
69
70
  # res[0] = mod_name_from_tmp_dir res.first
70
71
  # res[-1] = res.last.split(".").first
71
72
  # res
@@ -25,7 +25,7 @@ class Card
25
25
 
26
26
  # new cards do not
27
27
  def patterns
28
- @patterns ||= (new_card? ? concrete_patterns[1..-1] : concrete_patterns)
28
+ @patterns ||= (new_card? ? concrete_patterns[1..] : concrete_patterns)
29
29
  end
30
30
 
31
31
  def reset_patterns
@@ -4,8 +4,7 @@ class Card
4
4
  # class from which set patterns inherit
5
5
  class Base
6
6
  extend ClassMethods
7
- delegate :pattern_code, :pattern, :anchorless?, :anchor_parts_count,
8
- :assigns_type, to: :class
7
+ delegate :pattern_code, :pattern, :anchorless?, :assigns_type, to: :class
9
8
 
10
9
  def initialize card
11
10
  return if anchorless?
@@ -43,6 +42,10 @@ class Card
43
42
  end
44
43
  end
45
44
 
45
+ def anchor_parts_count
46
+ @anchor_parts_count ||= self.class.anchor_parts_count @anchor_name
47
+ end
48
+
46
49
  def anchor_parts
47
50
  return [@anchor_name] unless anchor_parts_count > 1
48
51
 
@@ -51,7 +54,7 @@ class Card
51
54
  parts
52
55
  else
53
56
  # handles cases where anchor is a compound card, eg A+B+*self
54
- [@anchor_name[0..-anchor_parts_count]] + parts[(-anchor_parts_count + 1)..-1]
57
+ [@anchor_name[0..-anchor_parts_count]] + parts[(-anchor_parts_count + 1)..]
55
58
  end
56
59
  end
57
60
 
@@ -38,7 +38,7 @@ class Card
38
38
  compound_only? ? card.name.compound? : true
39
39
  end
40
40
 
41
- def anchor_parts_count
41
+ def anchor_parts_count _anchor_name=nil
42
42
  @anchor_parts_count ||= (anchorless? ? 0 : 1)
43
43
  end
44
44
 
@@ -39,7 +39,7 @@ class Card
39
39
  # list of codenames of pattern cards
40
40
  # @return [Array <Symbol>]
41
41
  def codes
42
- @codes ||= concrete.map(&:pattern_code).to_set
42
+ @codes ||= concrete.to_set(&:pattern_code)
43
43
  end
44
44
 
45
45
  # list of lists of codenames in pattern load order
@@ -1,5 +1,8 @@
1
1
  class Card
2
2
  module Set
3
+ # supports requiring field cards
4
+ # for example, if A requires a B field, then you cannot create A without also
5
+ # creating A+B
3
6
  class RequiredField
4
7
  attr_reader :parent_set, :field, :options
5
8
 
@@ -53,6 +53,7 @@ class Card
53
53
 
54
54
  def assign_trait_type trait, type
55
55
  return unless type && (parts = trait_module_key_parts trait)
56
+
56
57
  assign_type type, normalize_const(parts)
57
58
  end
58
59
 
@@ -71,7 +72,11 @@ class Card
71
72
  end
72
73
 
73
74
  def define_trait_card trait, opts
74
- define_method "#{trait}_card" do
75
+ define_method "#{trait}_card" do |sub=false|
76
+ if sub && (card = subfield trait)
77
+ return card
78
+ end
79
+
75
80
  # opts = opts.clone.merge supercard: card
76
81
  fetch trait.to_sym, new: opts.clone, eager_cache: true
77
82
  end
@@ -30,7 +30,7 @@ class Card
30
30
  end
31
31
 
32
32
  def field field_name, args={}
33
- if (sf = subcards.field field_name)
33
+ if (sf = subfield field_name)
34
34
  sf.assign_attributes args
35
35
  sf
36
36
  else
@@ -39,11 +39,19 @@ class Card
39
39
  end
40
40
 
41
41
  def field_content field_name
42
- subcards.field(field_name)&.content
42
+ subfield(field_name)&.content
43
43
  end
44
44
 
45
- def field? tag
46
- fetch(tag) || subcards.field(tag).present?
45
+ def subfield field_name
46
+ subcards.field field_name
47
+ end
48
+
49
+ def subfield? field_name
50
+ subfield(field_name).present?
51
+ end
52
+
53
+ def field? field_name
54
+ fetch(field_name) || subfield?(field_name)
47
55
  end
48
56
 
49
57
  def drop_subcard name_or_card
@@ -89,7 +89,7 @@ class Card
89
89
  return true if caching == :deep || parent.present?
90
90
  # a parent voo means we're still in the same card
91
91
 
92
- return unless (superformat_card = format.parent&.card)
92
+ return false unless (superformat_card = format.parent&.card)
93
93
 
94
94
  superformat_card.name == card.name.left_name
95
95
  end
@@ -261,7 +261,7 @@ class Card
261
261
  end
262
262
 
263
263
  def options_for_cache_key
264
- hash_for_cache_key(live_options) + ";" + hash_for_cache_key(viz_hash)
264
+ "#{hash_for_cache_key(live_options)};#{hash_for_cache_key(viz_hash)}"
265
265
  end
266
266
 
267
267
  def hash_for_cache_key hash
@@ -120,18 +120,18 @@ class Card
120
120
  [classes, class_list(:single_use).delete(klass)]
121
121
  end
122
122
 
123
+ OK_TYPES = { ancestor_format: [:public],
124
+ self_format: %i[public format_private],
125
+ self: %i[public format_private private] }.freeze
123
126
  def ok_types space
124
- case space
125
- when :ancestor_format then [:public]
126
- when :self_format then %i[public format_private]
127
- when :self then %i[public format_private private]
128
- end
127
+ OK_TYPES[space]
129
128
  end
130
129
 
131
130
  def class_list type=:private
132
131
  unless type.in? %i[private format_private public single_use]
133
132
  raise ArgumentError, "#{type} not a valid class list"
134
133
  end
134
+
135
135
  @class_list ||= {}
136
136
  @class_list[type] ||= {}
137
137
  end
@@ -1,6 +1,7 @@
1
1
  class Card
2
2
  class View
3
3
  module Options
4
+ # lists of view option keys
4
5
  module KeyLists
5
6
  # all standard option keys
6
7
  # @return [Array]
@@ -197,7 +197,7 @@ class Card
197
197
  # @param opts [Hash] options hash
198
198
  # @return [Hash] options Hash
199
199
  def foreign_options_in opts
200
- foreign_opts = opts.reject { |k, _v| Options.all_keys.include? k }
200
+ foreign_opts = opts.except(*Options.all_keys)
201
201
  foreign_opts.empty? ? nil : foreign_opts
202
202
  end
203
203
  end
@@ -1,5 +1,5 @@
1
1
  require "rails/generators"
2
- require File.expand_path("../../../generators/deck/deck_generator", __FILE__)
2
+ require File.expand_path("../../generators/deck/deck_generator", __dir__)
3
3
  require "cardio/command"
4
4
 
5
5
  Cardio::Command.run_non_deck_command ARGV.first, "cardio/commands"
@@ -8,14 +8,14 @@ module Cardio
8
8
  private
9
9
 
10
10
  def run_new
11
- if !["-h", "--help"].intersection(args).empty?
12
- ARGV.unshift "new"
13
- require "cardio/command/application"
14
- else
11
+ if ["-h", "--help"].intersection(args).empty?
15
12
  puts "Can't initialize a new deck within the directory of another, " \
16
13
  "please change to a non-deck directory first.\n"
17
14
  puts "Type '#{gem}' for help."
18
15
  exit 1
16
+ else
17
+ ARGV.unshift "new"
18
+ require "cardio/command/application"
19
19
  end
20
20
  end
21
21
 
@@ -46,9 +46,10 @@ module Cardio
46
46
 
47
47
  def run_help_for_group group
48
48
  puts
49
- puts "For " + "#{group}s".yellow + ":"
49
+ puts "For #{"#{group}s".yellow}:"
50
50
  map.each do |command, conf|
51
51
  next unless conf[:group] == group
52
+
52
53
  puts command_help(command, conf)
53
54
  end
54
55
  puts
@@ -57,7 +58,7 @@ module Cardio
57
58
  # formats command string for help text
58
59
  def command_help command, conf
59
60
  alt = conf[:alias] ? "(or #{conf[:alias]})" : ""
60
- " " + command.to_s.ljust(12).light_cyan + alt.ljust(10) + conf[:desc]
61
+ " #{command.to_s.ljust(12).light_cyan}#{alt.ljust(10)}#{conf[:desc]}"
61
62
  end
62
63
  end
63
64
  end