Class: Statecraft::Generators::FromStatesmanGenerator

Inherits:
Rails::Generators::NamedBase
  • Object
show all
Includes:
ActiveRecord::Generators::Migration
Defined in:
lib/generators/statecraft/from_statesman/from_statesman_generator.rb

Overview

rails generate statecraft:from_statesman Order [OrderStateMachine] — the migration path off statesman. Reads the live statesman machine through reflection (states, initial state, transition graph, guard locations), generates the in-place conversion migration that turns the statesman transitions table into this gem's log, a machine skeleton whose events and guards are left for the human, and mounts the machine into the model. The statesman class itself is never loaded by name magic beyond the optional second argument's default.

Instance Method Summary collapse

Instance Method Details

#create_application_machineObject



33
34
35
36
37
38
# File 'lib/generators/statecraft/from_statesman/from_statesman_generator.rb', line 33

def create_application_machine
  application_machine_path = "app/state_machines/application_machine.rb"
  return if File.exist?(File.join(destination_root, application_machine_path))

  template "application_machine.rb.tt", application_machine_path
end

#create_conversion_migrationsObject

Three migrations, strong-migrations style: instant DDL, a batched backfill outside any DDL transaction, and a short-lock finalize. migration_template numbers them monotonically, so they run in order.



56
57
58
59
60
61
62
63
# File 'lib/generators/statecraft/from_statesman/from_statesman_generator.rb', line 56

def create_conversion_migrations
  migration_template "convert_transitions_ddl.rb.tt",
                     "#{migration_directory}/convert_#{migration_slug}_transitions_ddl.rb"
  migration_template "convert_transitions_backfill.rb.tt",
                     "#{migration_directory}/convert_#{migration_slug}_transitions_backfill.rb"
  migration_template "convert_transitions_finalize.rb.tt",
                     "#{migration_directory}/convert_#{migration_slug}_transitions_finalize.rb"
end

#create_machine_skeletonObject



40
41
42
# File 'lib/generators/statecraft/from_statesman/from_statesman_generator.rb', line 40

def create_machine_skeleton
  template "machine_from_statesman.rb.tt", "app/state_machines/#{file_path}_flow.rb"
end

#load_statesman_machineObject

Raises:

  • (Thor::Error)


24
25
26
27
28
29
30
31
# File 'lib/generators/statecraft/from_statesman/from_statesman_generator.rb', line 24

def load_statesman_machine
  @statesman_machine = resolve_statesman_machine
  @initial_state = @statesman_machine.initial_state
  return unless @initial_state.nil?

  raise Thor::Error, "#{statesman_class_name} declares no initial state; " \
                     "statecraft requires exactly one — declare `state ..., initial: true` first"
end

#mount_modelObject



44
45
46
47
48
49
50
51
# File 'lib/generators/statecraft/from_statesman/from_statesman_generator.rb', line 44

def mount_model
  unless File.exist?(File.join(destination_root, model_file))
    say_status :skip, "#{model_file} not found — mount the machine yourself: #{mounting_line.strip}", :yellow
    return
  end

  inject_into_class model_file, class_name, mounting_line
end


65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/generators/statecraft/from_statesman/from_statesman_generator.rb', line 65

def print_cleanup_instructions
  say "\nThe conversion is three migrations — run them per the README runbook:", :green
  say "  1. _ddl now (instant); 2. _backfill any time (batched, no long locks;"
  say "     rerun it to catch up rows statesman wrote in between);"
  say "  3. _finalize after switching the code to statecraft."
  say "\nAfter finalize, finish the move by hand:", :green
  say "  * #{log_class_name}: drop `include Statesman::Adapters::ActiveRecordTransition` and"
  say "    the `after_destroy :update_most_recent` callback (they read dropped columns);"
  say "    consider adding `def readonly? = persisted?` — the pipeline inserts around it."
  say "  * #{class_name}: drop `include Statesman::Adapters::ActiveRecordQueries` and the"
  say "    state_machine/transition helper methods that wrapped statesman."
  say "  * Delete the `Statesman.configure` initializer once no machine is left."
  say "  * Name your events in app/state_machines/#{file_path}_flow.rb — statesman had none."
end