card 1.105.6 → 1.107.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 (131) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/environments/development.rb +0 -3
  4. data/config/environments/production.rb +0 -3
  5. data/config/environments/test.rb +0 -2
  6. data/config/initializers/02_patches/active_record.rb +2 -2
  7. data/db/schema.rb +5 -13
  8. data/lib/card/auth/current.rb +1 -1
  9. data/lib/card/auth/permissions.rb +1 -9
  10. data/lib/card/codename.rb +8 -0
  11. data/lib/card/director/store.rb +1 -1
  12. data/lib/card/fetch/all.rb +1 -1
  13. data/lib/card/model/save_helper/save_helper_helper.rb +6 -2
  14. data/lib/card/query/abstract_query/tie.rb +16 -2
  15. data/lib/card/query/card_query/interpretation.rb +26 -3
  16. data/lib/card/query/reference_query.rb +4 -4
  17. data/lib/card/set.rb +27 -0
  18. data/lib/card/view/permission.rb +1 -1
  19. data/lib/cardio/command/rspec_command/parser.rb +1 -9
  20. data/lib/cardio/command.rb +1 -0
  21. data/lib/cardio/generators/base.rb +1 -1
  22. data/lib/cardio/migration/assumption.rb +29 -0
  23. data/lib/cardio/migration/schema.rb +12 -0
  24. data/lib/cardio/migration/stamp.rb +31 -0
  25. data/lib/cardio/migration/transform.rb +44 -0
  26. data/lib/cardio/migration.rb +64 -73
  27. data/lib/cardio/mod/dirs.rb +6 -5
  28. data/lib/cardio/mod/eat/edibles.rb +9 -3
  29. data/lib/cardio/mod/eat.rb +2 -1
  30. data/lib/cardio/mod/sow/card_source.rb +48 -0
  31. data/lib/cardio/mod/sow/yaml_dump.rb +25 -0
  32. data/lib/cardio/mod/sow.rb +22 -62
  33. data/lib/cardio/mod.rb +8 -4
  34. data/lib/cardio/railtie.rb +6 -6
  35. data/lib/cardio/seed.rb +3 -6
  36. data/lib/generators/deck/templates/cypress.json.erb +1 -1
  37. data/lib/generators/migration/USAGE +10 -11
  38. data/lib/generators/migration/migration_generator.rb +26 -24
  39. data/lib/generators/migration/templates/card_migration.erb +1 -3
  40. data/mod/core/config/admin.yml +10 -0
  41. data/mod/core/data/fixtures/real/transform_migrations.yml +351 -0
  42. data/mod/core/data/real.yml +0 -1
  43. data/mod/core/data/recode.yml +7 -0
  44. data/{db/migrate → mod/core/data/schema}/20110511221913_require_earlier_migrations.rb +3 -3
  45. data/{db/migrate → mod/core/data/schema}/20120105203350_require_1_8_migrations.rb +1 -1
  46. data/{db/migrate → mod/core/data/schema}/20121111025347_require_1_10_migrations.rb +1 -1
  47. data/{db/migrate → mod/core/data/schema}/20121118114000_split_link_type.rb +1 -1
  48. data/{db/migrate → mod/core/data/schema}/20121118115000_update_link_type.rb +1 -1
  49. data/{db/migrate → mod/core/data/schema}/20130106052640_table_cleanup.rb +1 -1
  50. data/{db/migrate → mod/core/data/schema}/20130109015336_trunk_left.rb +1 -1
  51. data/{db/migrate → mod/core/data/schema}/20140822073704_create_new_revision_tables.rb +1 -1
  52. data/mod/core/data/schema/20141001105348_move_revisions_to_actions.rb +87 -0
  53. data/{db/migrate → mod/core/data/schema}/20141216053032_better_index_names.rb +10 -4
  54. data/{db/migrate → mod/core/data/schema}/20150724210803_add_comment_to_actions.rb +1 -1
  55. data/{db/migrate → mod/core/data/schema}/20151105225559_more_space_for_db_content.rb +1 -1
  56. data/{db/migrate → mod/core/data/schema}/20160122153608_new_indices.rb +1 -1
  57. data/{db/migrate → mod/core/data/schema}/20170908114442_create_delayed_jobs.rb +1 -1
  58. data/{db/migrate → mod/core/data/schema}/20170908114452_increase_text_size_for_delayed_jobs.rb +1 -1
  59. data/{db/migrate → mod/core/data/schema}/20180514152037_add_card_virtuals_table.rb +1 -1
  60. data/{db/migrate → mod/core/data/schema}/20190116170824_add_left_key_to_card_virtuals.rb +1 -1
  61. data/{db/migrate → mod/core/data/schema}/20190131223248_add_codename_index.rb +1 -1
  62. data/{db/migrate → mod/core/data/schema}/20190929202325_rename_present_in_reference_table.rb +1 -1
  63. data/{db/migrate → mod/core/data/schema}/20200718051236_compound_names_do_not_store_name_and_key.rb +1 -1
  64. data/{db/migrate → mod/core/data/schema}/20200805200729_add_unique_pair_indices.rb +1 -3
  65. data/{db/migrate → mod/core/data/schema}/20211128040849_virtuals_updated_at.rb +1 -1
  66. data/{db/migrate → mod/core/data/schema}/20221031182227_remove_referee_key_requirement.rb +1 -1
  67. data/mod/core/data/test.yml +4 -4
  68. data/{db/migrate_core_cards → mod/core/data/transform}/20120611203506_rails_inflection_updates.rb +10 -6
  69. data/mod/core/data/transform/20130411191151_renaming_for_menu.rb +17 -0
  70. data/mod/core/data/transform/20130920214038_jsonize_tinymce.rb +28 -0
  71. data/{db/migrate_core_cards → mod/core/data/transform}/20130920291703_update_stylesheets.rb +1 -1
  72. data/mod/core/data/transform/20140307231621_user_data_to_cards.rb +40 -0
  73. data/{db/migrate_core_cards → mod/core/data/transform}/20140317035504_account_requests_to_signups.rb +1 -1
  74. data/{db/migrate_core_cards → mod/core/data/transform}/20141204061304_watchers_to_following.rb +2 -2
  75. data/{db/migrate_core_cards → mod/core/data/transform}/20141208132416_partial_reference_type.rb +1 -1
  76. data/{db/migrate_core_cards → mod/core/data/transform}/20150220134731_following_to_follow_rule.rb +1 -1
  77. data/{db/migrate_core_cards → mod/core/data/transform}/20150429090551_search_card_context.rb +1 -1
  78. data/{db/migrate_core_cards → mod/core/data/transform}/20150510031118_fix_skin_codenames.rb +2 -2
  79. data/{db/migrate_core_cards → mod/core/data/transform}/20150724123438_update_file_and_image_cards.rb +2 -2
  80. data/{db/migrate_core_cards → mod/core/data/transform}/20150807205221_create_references_for_search_cards.rb +1 -1
  81. data/mod/core/data/transform/20150824135418_update_file_history.rb +33 -0
  82. data/{db/migrate_core_cards → mod/core/data/transform}/20160811115836_rename_stats_to_admin.rb +1 -1
  83. data/{db/migrate_core_cards → mod/core/data/transform}/20160914132636_fix_mod_files.rb +1 -1
  84. data/{db/migrate_core_cards → mod/core/data/transform}/20161103154836_update_keys.rb +3 -3
  85. data/{db/migrate_core_cards → mod/core/data/transform}/20170830210517_correct_signup_success_message.rb +1 -1
  86. data/{db/migrate_core_cards → mod/core/data/transform}/20180905061537_migrate_layouts.rb +1 -1
  87. data/{db/migrate_core_cards → mod/core/data/transform}/20190125125150_add_script_rules_card.rb +1 -1
  88. data/{db/migrate_core_cards → mod/core/data/transform}/20190320091257_upgrade_recaptcha_to_v3.rb +1 -1
  89. data/{db/migrate_core_cards → mod/core/data/transform}/20190322095534_remove_toolbar_cards.rb +1 -1
  90. data/{db/migrate_core_cards → mod/core/data/transform}/20190502130029_add_shark_and_help_desk_role.rb +2 -1
  91. data/{db/migrate_core_cards → mod/core/data/transform}/20190528131330_enabled_roles.rb +1 -1
  92. data/{db/migrate_core_cards → mod/core/data/transform}/20190625153616_pointer_overhaul.rb +1 -1
  93. data/{db/migrate_core_cards → mod/core/data/transform}/20190718140126_add_guides.rb +1 -1
  94. data/{db/migrate_core_cards → mod/core/data/transform}/20190822093633_move_help_text_to_code.rb +3 -1
  95. data/{db/migrate_core_cards → mod/core/data/transform}/20190829205148_remove_add_help.rb +1 -1
  96. data/mod/core/data/transform/20190902193208_input_type.rb +10 -0
  97. data/{db/migrate_core_cards → mod/core/data/transform}/20190904174403_token_upgrade.rb +2 -2
  98. data/{db/migrate_core_cards → mod/core/data/transform}/20190909104250_add_cardtype_input_types.rb +2 -2
  99. data/{db/migrate_core_cards → mod/core/data/transform}/20191115160748_history_cleanup.rb +1 -1
  100. data/mod/core/data/transform/20230502094848_repair_all_references.rb +7 -0
  101. data/mod/core/lib/admin_item.rb +21 -0
  102. data/mod/core/lib/tasks/card/migrate.rake +79 -114
  103. data/mod/core/lib/tasks/card/seed.rake +1 -1
  104. data/mod/core/lib/tasks/card.rake +57 -28
  105. data/mod/core/set/abstract/task_table.rb +16 -0
  106. data/mod/core/set/all/admin.rb +108 -0
  107. data/mod/core/set/self/admin.rb +3 -12
  108. data/mod/core/set/self/mod.rb +39 -0
  109. data/mod/core/set/self/version.rb +1 -1
  110. data/mod/core/set/type/mod.rb +227 -0
  111. data/mod/core/spec/set/all/admin_spec.rb +34 -0
  112. data/mod/core/spec/set/type/mod_spec.rb +30 -0
  113. data/mod/core/spec/shared_examples/mod_admin_config.rb +10 -0
  114. metadata +78 -72
  115. data/db/migrate/20130411210957_update_codenames.rb +0 -15
  116. data/db/migrate/20141001105348_move_revisions_to_actions.rb +0 -70
  117. data/db/migrate/20141121172918_rename_card_migration_table.rb +0 -15
  118. data/db/migrate/20141208132159_remove_present_from_reference_table.rb +0 -9
  119. data/db/migrate_core_cards/20130411191151_renaming_for_menu.rb +0 -47
  120. data/db/migrate_core_cards/20130920214038_jsonize_tinymce.rb +0 -15
  121. data/db/migrate_core_cards/20140307231621_user_data_to_cards.rb +0 -28
  122. data/db/migrate_core_cards/20150824135418_update_file_history.rb +0 -24
  123. data/db/migrate_core_cards/20190902193208_input_type.rb +0 -15
  124. data/db/migrate_core_cards/20230502094848_repair_all_references.rb +0 -7
  125. data/lib/cardio/migration/core.rb +0 -11
  126. data/lib/cardio/migration/deck.rb +0 -0
  127. data/lib/cardio/migration/deck_structure.rb +0 -19
  128. data/lib/cardio/schema.rb +0 -96
  129. data/mod/core/data/fixtures/real/schema_migrations_core_cards.yml +0 -347
  130. data/mod/core/data/fixtures/real/schema_migrations_deck.yml +0 -1
  131. data/mod/core/data/fixtures/real/schema_migrations_deck_cards.yml +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19bf849da74214f9ae14d6bc7310c0015209de781b3b9fa89c509a0665167971
4
- data.tar.gz: 83e55e8f3b6b6791f861938f594dd897fb0ac817fd0be4b922dbe71b707fa435
3
+ metadata.gz: df537d34eb8d348b41930c7ce3e6de5ed600b4d7e8df87ba2d935b2e259ae8e6
4
+ data.tar.gz: e108f9e1f0833c0aac0248c6ec59bf41c18aef70e09e42ea8bd364f94705fe7c
5
5
  SHA512:
6
- metadata.gz: ed6f5f0ecd5bfcbf75efeb9f3d9c152e33433e0b6581a3b81971932ef819099cd3157fedb2ad752e3509fe5a4298cec4d9bbfed823fbd5a57d29e71ea0252b90
7
- data.tar.gz: b661938ed367e6f58818107288baf4e248c2ce0725a2c777da2ee30b02b33902a441844aeb1ba81cd677c0774473010b2a241d6e320a2b094b50eb48dc147ba3
6
+ metadata.gz: ec38c34b70331bf7a919963b7337682e1456286ec5007db1d6d5408f270bb326bb6c55cd2c8af455bb7ed2794d8bd7ae1012dc3eb741d89ba2ce575a63c804bd
7
+ data.tar.gz: 901b1dc8198578fac3b59040919c02520b177ff8e240c4cebb0a1adb6c978054491b62aa4cc44a3a3514b114645b914a23515ffb36d71ab39b36054fe31c7cd7
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.15.6
1
+ 0.17.0
@@ -38,9 +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
- # if false, application will raise errors that make it to controller.
42
- config.rescue_all_in_controller = false
43
-
44
41
  # config.performance_logger = {
45
42
  # methods: [:event, :search, :fetch, :view], # choose methods to log
46
43
  # min_time: 100, # show only method calls that are slower than 100ms
@@ -69,7 +69,4 @@ Cardio.application.class.configure do
69
69
 
70
70
  # cache the list of set module objects on card objects
71
71
  config.cache_set_module_list = true
72
-
73
- # if false, application will raise errors that make it to controller.
74
- config.rescue_all_in_controller = true
75
72
  end
@@ -59,6 +59,4 @@ Cardio.application.class.configure do
59
59
  config.active_support.deprecation = :stderr
60
60
 
61
61
  config.raise_all_rendering_errors = true
62
-
63
- config.rescue_all_in_controller = false
64
62
  end
@@ -121,8 +121,8 @@ module Patches
121
121
  module Migration
122
122
  module ClassMethods
123
123
  def check_pending! connection=::ActiveRecord::Base.connection
124
- %i[structure core_cards deck deck_cards].each do |migration_type|
125
- Cardio::Schema.mode(migration_type) do |paths|
124
+ %i[schema transform].each do |migration_type|
125
+ Cardio::Migration.new_for(migration_type).mode do |paths|
126
126
  ::ActiveRecord::Migrator.migrations_paths = paths
127
127
  super
128
128
  end
data/db/schema.rb CHANGED
@@ -114,19 +114,6 @@ ActiveRecord::Schema.define(version: 2022_10_31_182227) do
114
114
  t.index ["priority", "run_at"], name: "delayed_jobs_priority"
115
115
  end
116
116
 
117
- create_table "schema_migrations_core_cards", id: false, charset: "utf8mb3", force: :cascade do |t|
118
- t.string "version", null: false
119
- t.index ["version"], name: "unique_schema_migrations_cards", unique: true
120
- end
121
-
122
- create_table "schema_migrations_deck", primary_key: "version", id: :string, charset: "utf8mb3", force: :cascade do |t|
123
- end
124
-
125
- create_table "schema_migrations_deck_cards", id: false, charset: "utf8mb3", force: :cascade do |t|
126
- t.string "version", null: false
127
- t.index ["version"], name: "unique_schema_migrations_deck_cards", unique: true
128
- end
129
-
130
117
  create_table "sessions", id: :integer, charset: "utf8mb3", force: :cascade do |t|
131
118
  t.string "session_id"
132
119
  t.text "data"
@@ -134,6 +121,11 @@ ActiveRecord::Schema.define(version: 2022_10_31_182227) do
134
121
  t.index ["session_id"], name: "sessions_session_id_index"
135
122
  end
136
123
 
124
+ create_table "transform_migrations", id: false, charset: "utf8mb3", force: :cascade do |t|
125
+ t.string "version", null: false
126
+ t.index ["version"], name: "unique_schema_migrations_cards", unique: true
127
+ end
128
+
137
129
  create_table "users", id: :integer, charset: "utf8mb3", force: :cascade do |t|
138
130
  t.string "login", limit: 40
139
131
  t.string "email", limit: 100
@@ -56,7 +56,7 @@ class Card
56
56
  # get :user id from session and set Auth.current_id
57
57
  def signin_with_session
58
58
  card_id = session[session_user_key]
59
- card_id = nil unless Card.exists? card_id
59
+ card_id = nil unless card_id.card&.account?
60
60
  signin card_id
61
61
  end
62
62
 
@@ -34,15 +34,7 @@ class Card
34
34
  # @param user_mark [Cardish]
35
35
  # @return [true/false]
36
36
  def admin? user_mark=nil
37
- user_mark ||= as_id
38
- has_role? Card::AdministratorID, user_mark
39
- end
40
-
41
- def has_role? role_mark, user_mark=nil
42
- user_mark ||= as_id
43
- return false unless (role_id = role_mark&.card_id)
44
-
45
- Card[user_mark].all_enabled_roles.include? role_id
37
+ (user_mark || as_id).card&.admin?
46
38
  end
47
39
 
48
40
  def update_always_cache value
data/lib/card/codename.rb CHANGED
@@ -95,6 +95,14 @@ class Card
95
95
  end
96
96
  end
97
97
 
98
+ def recode oldcode, newcode
99
+ return unless id(oldcode) && !id(newcode)
100
+
101
+ puts "recode #{oldcode}, #{newcode}"
102
+ Card.where(codename: oldcode).take.update_column :codename, newcode
103
+ reset_cache
104
+ end
105
+
98
106
  private
99
107
 
100
108
  # iterate through every card with a codename
@@ -7,7 +7,7 @@ class Card
7
7
  @after_store << block
8
8
  end
9
9
 
10
- protected
10
+ # protected
11
11
 
12
12
  def after_store?
13
13
  @after_store.present?
@@ -6,7 +6,7 @@ class Card
6
6
  def fetch field_marks, opts={}
7
7
  opts[:new][:supercard] = self if opts[:new]
8
8
  Array.wrap(field_marks).inject(self) do |card, mark|
9
- Card.fetch card.name.field(mark.cardname), opts
9
+ Card.fetch (card.id || card.name), mark, opts
10
10
  end
11
11
  end
12
12
 
@@ -21,8 +21,12 @@ class Card
21
21
  method_name, cardtype_card = extract_cardtype_from_method_name method
22
22
  return super unless method_name
23
23
 
24
- sargs = standardize_args(*args)
25
- send "#{method_name}_card", sargs.merge(type_id: cardtype_card.id)
24
+ sargs = standardize_args(*args).merge(type_id: cardtype_card.id)
25
+ if method_name == "ensure"
26
+ Card.ensure sargs
27
+ else
28
+ send "#{method_name}_card", sargs
29
+ end
26
30
  end
27
31
 
28
32
  def respond_to_missing? method, _include_private=false
@@ -2,9 +2,9 @@ class Card
2
2
  module Query
3
3
  class AbstractQuery
4
4
  # The "Tie" methods support tying two queries (CardQuery, ReferenceQuery, etc)
5
- # together. The "fasten" variable determines which tying strategy is used.
5
+ # together. The "subquery_type" variable determines which tying strategy is used.
6
6
  #
7
- # We currently support three values for "fasten": :join, :exist, and :in
7
+ # We currently support three values for "subquery_type": :join, :exist, and :in
8
8
  #
9
9
  # In concept, here's how the different strategies would tie table A to table B
10
10
  # in SQL assuming A.id = B.a_id
@@ -97,6 +97,20 @@ class Card
97
97
  when String, Symbol then val.card_id || -999
98
98
  end
99
99
  end
100
+
101
+ def op_and_id_or_ids_from_val val
102
+ if (single_id = id_from_val val)
103
+ "= #{single_id}"
104
+ elsif list_of_ids? val
105
+ "in (#{val.map { |v| id_from_val v }.join ', '})"
106
+ end
107
+ end
108
+
109
+ def list_of_ids? val
110
+ return unless val.is_a? Array
111
+
112
+ !val.find { |v| !id_from_val v }
113
+ end
100
114
  end
101
115
  end
102
116
  end
@@ -80,6 +80,7 @@ class Card
80
80
  def relate key, val, opts={}
81
81
  multiple = opts[:multiple].nil? ? val.is_a?(Array) : opts[:multiple]
82
82
  method = opts[:method] || :send
83
+
83
84
  if multiple
84
85
  relate_multi_value method, key, val
85
86
  else
@@ -87,15 +88,37 @@ class Card
87
88
  end
88
89
  end
89
90
 
91
+ private
92
+
90
93
  def relate_multi_value method, key, val
91
94
  conj = conjunction(val.first) ? conjunction(val.shift) : :and
92
- if conj == current_conjunction
95
+ if as_list_of_ids?(conj, key, val)
96
+ relate key, val, multiple: false
97
+ elsif conj == current_conjunction
93
98
  # same conjunction as container, no need for subcondition
94
- val.each { |v| send method, key, v }
99
+ relate_multi_value_without_subcondition method, key, val
95
100
  else
96
- send conj, (val.map { |v| { key => v } })
101
+ relate_multi_value_with_subcondition key, conj, val
97
102
  end
98
103
  end
104
+
105
+ def relate_multi_value_with_subcondition key, conj, val
106
+ send conj, (val.map { |v| { key => v } })
107
+ end
108
+
109
+ def relate_multi_value_without_subcondition method, key, val
110
+ val.each { |v| send method, key, v }
111
+ end
112
+
113
+ # the #list_of_ids optimization is intended to avoid unnecessary joins and
114
+ # can probably be applied more broadly, but in the name of caution, we went
115
+ # with an initial implementation that would only apply to reference attributes
116
+ # (because reference_query can handle lists of values)
117
+ def as_list_of_ids? conj, key, val
118
+ (conj == :or) &&
119
+ key.to_s.start_with?(/refer|nest|include|link|member/) &&
120
+ list_of_ids?(val)
121
+ end
99
122
  end
100
123
  end
101
124
  end
@@ -26,8 +26,8 @@ class Card
26
26
  def add_outfield_condition outfield, outcard
27
27
  if outcard == "_none"
28
28
  non_outfield
29
- elsif (id = id_from_val(outcard))
30
- outfield_id outfield, id
29
+ elsif (op_and_id = op_and_id_or_ids_from_val(outcard))
30
+ outfield_id outfield, op_and_id
31
31
  else
32
32
  tie :card, outcard, from: outfield
33
33
  end
@@ -37,8 +37,8 @@ class Card
37
37
  add_condition "#{fld :is_present} = 0"
38
38
  end
39
39
 
40
- def outfield_id outfield, id
41
- add_condition "#{fld(outfield)} = #{id}"
40
+ def outfield_id outfield, op_and_id
41
+ add_condition "#{fld(outfield)} #{op_and_id}"
42
42
  end
43
43
 
44
44
  def add_reftype_condition reftype
data/lib/card/set.rb CHANGED
@@ -90,7 +90,34 @@ class Card
90
90
  # ...then mycard will include the set modules associated with each of those sets in the
91
91
  # above order.
92
92
  #
93
+ # ### Abstract set modules
93
94
  #
95
+ # Suppose you have code that you'd like to reuse in more than one set.
96
+ #
97
+ # Well, set modules are just ruby, so it's possible to just define a standard ruby
98
+ # module (eg `module MySimpleModule...`) in a lib directory and then include that
99
+ # set (`include MySimpleModule`). That will work just fine so long as you only want
100
+ # to add simple ruby code and include it in the base ruby module. But what if you
101
+ # want the reusable code to use the DSL? What if you want to define reusable events,
102
+ # for example? Or if you want to define reusable views on formats?
103
+ #
104
+ # For this purpose, you can use _abstract set modules_. These are modules that use
105
+ # the set DSL but are not defined directly onto a specific set. Instead, they can
106
+ # be included in a set using the `include_set` command.
107
+ #
108
+ # For example, suppose you create a file at `mod/biz/set/abstract/special_views.rb`.
109
+ # And within that file you define a view such as the following:
110
+ #
111
+ # format :html do
112
+ # view :bizzy do
113
+ # "I'm so busy"
114
+ # end
115
+ # end
116
+ #
117
+ # This will create an abstract set that can be included in any other set by invoking
118
+ # `include_set Card::Set::Abstract::SpecialViews`. Or just `include_set
119
+ # Abstract::SpecialViews` for short. And then the including set will have access to the
120
+ # "bizzy" view.
94
121
  module Set
95
122
  include Event::Api
96
123
  include Trait
@@ -46,7 +46,7 @@ class Card
46
46
  def denial
47
47
  return unless (task = denied_task)
48
48
 
49
- format.view_for_denial requested_view, task
49
+ format.view_for_denial requested_view, (crud?(task) && task)
50
50
  end
51
51
 
52
52
  def crud? task
@@ -24,12 +24,10 @@ module Cardio
24
24
 
25
25
  RSPEC ARGS
26
26
 
27
- See https://relishapp.com/rspec/rspec-core/docs/command-line
27
+ See https://rspec.info/features/3-12/rspec-core/command-line/ or run card rspec -- -hbe
28
28
  BANNER
29
29
 
30
30
  DESC = {
31
- d: "Run spec for a Decko deck file",
32
- c: "Run spec for a Decko core file",
33
31
  m: "Run all specs for a mod or matching a mod"
34
32
  }.freeze
35
33
 
@@ -47,15 +45,9 @@ module Cardio
47
45
  private
48
46
 
49
47
  def file_options parser, opts
50
- parser.on("-d", "--spec FILENAME(:LINE)", DESC[:d]) do |file|
51
- opts[:files] = find_spec_file(file, "#{Decko.root}/mod")
52
- end
53
48
  parser.on("-m", "--mod MODNAME", DESC[:m]) do |file|
54
49
  opts[:files] = find_mod_file(file, Cardio.gem_root)
55
50
  end
56
- parser.on("-c", "--core-spec FILENAME(:LINE)", DESC[:c]) do |file|
57
- opts[:files] = find_spec_file(file, Cardio.gem_root)
58
- end
59
51
  end
60
52
 
61
53
  def other_options parser, opts
@@ -38,6 +38,7 @@ module Cardio
38
38
  runner: { desc: "run code in app environment", group: :monkey, alias: :r },
39
39
  rspec: { desc: "run rspec tests", group: :monkey, alias: :rs, via: :call },
40
40
  generate: { desc: "generate templated code", group: :monkey, alias: :g },
41
+ reset: { desc: "reset cache and tmpfiles", group: :monkey, via: :rake },
41
42
  sow: { desc: "export card data to mod yaml", group: :monkey, via: :rake },
42
43
  eat: { desc: "ingest card data from mod yaml", group: :monkey, via: :rake }
43
44
  }
@@ -3,7 +3,7 @@
3
3
  module Cardio
4
4
  module Generators
5
5
  # adds Cardio::Generators::ClassMethods to standard rails generator base class.
6
- class Base < ::ActiveRecord::Generators::Base
6
+ class Base < ::Rails::Generators::Base
7
7
  extend ClassMethods
8
8
  end
9
9
  end
@@ -0,0 +1,29 @@
1
+ module Cardio
2
+ class Migration
3
+ # methods for assuming migration states
4
+ module Assumption
5
+ def assume_current
6
+ context do |mc|
7
+ versions = mc.migrations.map(&:version)
8
+ migrated = mc.get_all_versions
9
+ to_mark = versions - migrated
10
+ mark_as_migrated to_mark if to_mark.present?
11
+ end
12
+ end
13
+
14
+ def assume_migrated_upto_version version=nil
15
+ mode do |_paths|
16
+ version ||= self.version
17
+ ActiveRecord::Schema.assume_migrated_upto_version version
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def mark_as_migrated versions
24
+ sql = connection.send :insert_versions_sql, versions
25
+ connection.execute sql
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ require "cardio/migration"
2
+
3
+ module Cardio
4
+ class Migration
5
+ # for migrations involving database schema definitions
6
+ class Schema < Migration
7
+ @migration_type = :schema
8
+ @old_tables = []
9
+ @old_deck_table = "schema_migrations_deck"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ module Cardio
2
+ class Migration
3
+ # methods for stamping migration versions to files
4
+ module Stamp
5
+ def stamp
6
+ mode do
7
+ return unless (version = stampable_version) && (file = stamp_file)
8
+ puts ">> writing version: #{version} to #{file.path}"
9
+ file.puts version
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def stamp_file
16
+ ::File.open stamp_path, "w"
17
+ end
18
+
19
+ def stampable_version
20
+ version = ActiveRecord::Migrator.current_version
21
+ version.to_i.positive? && version
22
+ end
23
+
24
+ def stamp_path
25
+ stamp_dir = ENV["SCHEMA_STAMP_PATH"] || File.join(Cardio.root, "db")
26
+
27
+ File.join stamp_dir, "version_#{migration_type}.txt"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ require "cardio/migration"
2
+
3
+ module Cardio
4
+ class Migration
5
+ # for migrations involving data transformations (but not schema changes)
6
+ class Transform < Migration
7
+ include Card::Model::SaveHelper unless ENV["NO_CARD_LOAD"]
8
+
9
+ @migration_type = :transform
10
+ @old_tables = %w[schema_migrations_core_cards schema_migrations_cards]
11
+ @old_deck_table = "schema_migrations_deck_cards"
12
+
13
+ private
14
+
15
+ def with_migration_table
16
+ self.table_name = "transform_migrations"
17
+ yield
18
+ ensure
19
+ self.table_name = "schema_migrations"
20
+ end
21
+
22
+ # Execute this migration in the named direction
23
+ # override ActiveRecord to wrap 'up' in 'contentedly'
24
+ def exec_migration conn, direction
25
+ return super if respond_to? :change
26
+
27
+ @connection = conn
28
+ contentedly { send direction }
29
+ ensure
30
+ @connection = nil
31
+ end
32
+
33
+ def contentedly
34
+ return yield if ENV["NO_CARD_LOAD"]
35
+ Card::Cache.reset_all
36
+ Card::Auth.as_bot do
37
+ yield
38
+ ensure
39
+ ::Card::Cache.reset_all
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -2,113 +2,104 @@
2
2
 
3
3
  module Cardio
4
4
  class Migration < ActiveRecord::Migration[6.1]
5
- include Card::Model::SaveHelper unless ENV["NO_CARD_LOAD"]
6
- @type = :deck_cards
5
+ include Assumption
6
+ include Stamp
7
7
 
8
8
  class << self
9
- # Rake tasks use class methods, migrations use instance methods.
10
- # To avoid repetition a lot of instance methods here just call class
11
- # methods.
12
- # The subclass Card::CoreMigration needs a different @type so we can't use a
13
- # class variable @@type. It has to be a class instance variable.
14
- # Migrations are subclasses of Cardio::Migration or Card::CoreMigration
15
- # but they don't inherit the @type. The method below solves this problem.
16
- def type
17
- @type || ancestors[1]&.type
18
- end
9
+ attr_reader :migration_type, :old_tables, :old_deck_table
19
10
 
20
- def find_unused_name base_name
21
- test_name = base_name
22
- add = 1
23
- while Card.exists?(test_name)
24
- test_name = "#{base_name}#{add}"
25
- add += 1
26
- end
27
- test_name
11
+ def migration_class type
12
+ type == :schema ? Migration::Schema : Migration::Transform
28
13
  end
29
14
 
30
- def migration_paths mig_type=type
31
- Schema.migration_paths mig_type
15
+ def new_for type
16
+ migration_class(type).new
32
17
  end
33
18
 
34
- def schema_suffix mig_type=type
35
- Schema.suffix mig_type
19
+ def port_all
20
+ %i[schema transform].each do |type|
21
+ migration_class(type).port
22
+ end
36
23
  end
37
24
 
38
- def schema_mode mig_type=type, &block
39
- Schema.mode mig_type, &block
25
+ def port
26
+ return unless connection.table_exists? old_deck_table
27
+ rename_old_tables
28
+ connection.execute "INSERT INTO #{table} (#{select_nonduplicate_versions})"
29
+ connection.drop_table old_deck_table
40
30
  end
41
31
 
42
- def assume_migrated_upto_version
43
- Schema.assume_migrated_upto_version type
32
+ private
33
+
34
+ def select_nonduplicate_versions
35
+ "SELECT * FROM #{old_deck_table} o WHERE NOT EXISTS " \
36
+ "(SELECT * FROM #{table} n WHERE o.version = n.version)"
44
37
  end
45
38
 
46
- def assume_current
47
- migration_context do |mc|
48
- versions = mc.migrations.map(&:version)
49
- migrated = mc.get_all_versions
50
- to_mark = versions - migrated
51
- mark_as_migrated to_mark if to_mark.present?
39
+ def rename_old_tables
40
+ old_tables.each do |old_table_name|
41
+ next unless connection.table_exists? old_table_name
42
+ connection.rename_table old_table_name, table
52
43
  end
53
44
  end
54
45
 
55
- def data_path filename=nil
56
- File.join([migration_paths.first, "data", filename].compact)
57
- end
58
-
59
- private
60
-
61
- def mark_as_migrated versions
62
- sql = connection.send :insert_versions_sql, versions
63
- connection.execute sql
46
+ def table
47
+ "#{migration_type}_migrations"
64
48
  end
65
49
 
66
50
  def connection
67
51
  ActiveRecord::Base.connection
68
52
  end
53
+ end
69
54
 
70
- def migration_context &block
71
- Schema.migration_context type, &block
72
- end
55
+ def migration_type
56
+ self.class.migration_type || :schema
73
57
  end
74
58
 
75
- def contentedly
76
- return yield if ENV["NO_CARD_LOAD"]
77
- Card::Cache.reset_all
78
- Schema.mode "" do
79
- Card::Auth.as_bot do
80
- yield
81
- ensure
82
- ::Card::Cache.reset_all
83
- end
59
+ def run version=nil, verbose=true
60
+ context do |mc|
61
+ ActiveRecord::Migration.verbose = verbose
62
+ mc.migrate version
84
63
  end
85
64
  end
86
65
 
87
- def data_path filename=nil
88
- self.class.data_path filename
66
+ def version
67
+ path = stamp_path
68
+ File.exist?(path) ? File.read(path).strip : nil
89
69
  end
90
70
 
91
- # Execute this migration in the named direction
92
- # copied from ActiveRecord to wrap 'up' in 'contentedly'
93
- def exec_migration conn, direction
94
- @connection = conn
95
- if respond_to?(:change)
96
- if direction == :down
97
- revert { change }
98
- else
99
- change
100
- end
101
- else
102
- contentedly { send(direction) }
71
+ def migration_paths
72
+ Cardio.paths["data/#{migration_type}"].existent.to_a
73
+ end
74
+
75
+ def context
76
+ mode do |paths|
77
+ yield ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration)
103
78
  end
104
- ensure
105
- @connection = nil
79
+ end
80
+
81
+ def mode
82
+ with_migration_table { yield migration_paths }
106
83
  end
107
84
 
108
85
  def down
109
86
  raise ActiveRecord::IrreversibleMigration
110
87
  end
88
+
89
+ private
90
+
91
+ def connection
92
+ Cardio::Migration.connection
93
+ end
94
+
95
+ def with_migration_table
96
+ yield
97
+ end
98
+
99
+ def table_name= table_name
100
+ ActiveRecord::Base.schema_migrations_table_name = table_name
101
+ ActiveRecord::SchemaMigration.table_name = table_name
102
+ ActiveRecord::SchemaMigration.reset_column_information
103
+ end
111
104
  end
112
105
  end
113
-
114
- require "cardio/migration/core"