Class: Railstart::CommandBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/railstart/command_builder.rb

Overview

Translates configuration and user answers into a rails new command string.

This class provides deterministic, side-effect-free command construction.

Examples:

Build a command from answers

config = { "questions" => [{ "id" => "database", "type" => "select", "rails_flag" => "--database=%{value}" }] }
answers = { "database" => "postgresql" }
Railstart::CommandBuilder.build("blog", config, answers)
# => "rails new blog --database=postgresql"

Class Method Summary collapse

Class Method Details

.add_flags(flags, source, value) ⇒ Object (private)



94
95
96
97
98
99
100
101
# File 'lib/railstart/command_builder.rb', line 94

def add_flags(flags, source, value)
  flag_list = source["rails_flags"] || [source["rails_flag"]].compact

  flag_list.each do |flag|
    interpolated = Config.interpolate_flag(flag, value)
    flags << interpolated
  end
end

.arguments(app_name, config, answers) ⇒ Array<String>

Build process arguments for rails new without shell interpretation.

Parameters:

  • app_name (String)

    target Rails app name

  • config (Hash)

    merged configuration from Railstart::Config.load

  • answers (Hash)

    user answers keyed by question id

Returns:

  • (Array<String>)

    executable and arguments suitable for system(*arguments)



37
38
39
# File 'lib/railstart/command_builder.rb', line 37

def arguments(app_name, config, answers)
  ["rails", "new", app_name.to_s, *collect_flags(config["questions"], answers)]
end

.build(app_name, config, answers) ⇒ String

Build a rails new command string using config metadata and answers.

Examples:

Railstart::CommandBuilder.build("todo", config, answers)

Parameters:

  • app_name (String)

    target Rails app name

  • config (Hash)

    merged configuration from Railstart::Config.load

  • answers (Hash)

    user answers keyed by question id

Returns:

  • (String)

    fully assembled CLI command

Raises:



27
28
29
# File 'lib/railstart/command_builder.rb', line 27

def build(app_name, config, answers)
  arguments(app_name, config, answers).map { |argument| display_argument(argument) }.join(" ")
end

.collect_flags(questions, answers) ⇒ Object (private)



50
51
52
53
54
55
56
57
58
59
# File 'lib/railstart/command_builder.rb', line 50

def collect_flags(questions, answers)
  flags = []
  Array(questions).each do |question|
    answer = answers[question["id"]]
    next unless answer

    process_question_flags(flags, question, answer)
  end
  flags
end

.display_argument(argument) ⇒ Object (private)



43
44
45
46
47
48
# File 'lib/railstart/command_builder.rb', line 43

def display_argument(argument)
  value = argument.to_s
  return value if value.match?(%r{\A[\w@%+=:,./-]+\z})

  Shellwords.escape(value)
end

.process_multi_select(flags, question, answer) ⇒ Object (private)



86
87
88
89
90
91
92
# File 'lib/railstart/command_builder.rb', line 86

def process_multi_select(flags, question, answer)
  Array(question["choices"]).each do |choice|
    next unless Array(answer).include?(choice["value"])

    add_flags(flags, choice, choice["value"])
  end
end

.process_question_flags(flags, question, answer) ⇒ Object (private)



61
62
63
64
65
66
67
68
69
70
# File 'lib/railstart/command_builder.rb', line 61

def process_question_flags(flags, question, answer)
  case question["type"]
  when "select"
    process_select(flags, question, answer)
  when "yes_no", "input"
    add_flags(flags, question, answer)
  when "multi_select"
    process_multi_select(flags, question, answer)
  end
end

.process_select(flags, question, answer) ⇒ Object (private)



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/railstart/command_builder.rb', line 72

def process_select(flags, question, answer)
  # Check if the selected choice has a choice-level rails_flag
  selected_choice = Array(question["choices"]).find { |choice| choice["value"] == answer }

  if selected_choice && (selected_choice["rails_flag"] || selected_choice["rails_flags"])
    # Use choice-level flag
    add_flags(flags, selected_choice, answer)
  elsif question["rails_flag"] || question["rails_flags"]
    # Fall back to question-level flag
    add_flags(flags, question, answer)
  end
  # If neither exists, no flag is added (e.g., for choices that don't need flags)
end