card 1.105.6 → 1.107.0

Sign up to get free protection for your applications and to get access to all the features.
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"