Module: Ace::Support::Cli::Help::Banner

Defined in:
lib/ace/support/cli/help/banner.rb

Constant Summary collapse

COLUMN_WIDTH =
34

Class Method Summary collapse

Class Method Details

.argument_desc(argument) ⇒ Object



162
163
164
# File 'lib/ace/support/cli/help/banner.rb', line 162

def self.argument_desc(argument)
  argument.respond_to?(:desc) ? argument.desc : nil
end

.argument_required?(argument) ⇒ Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/ace/support/cli/help/banner.rb', line 158

def self.argument_required?(argument)
  argument.respond_to?(:required?) ? argument.required? : !!argument.required
end

.arguments(command) ⇒ Object



151
152
153
154
155
156
# File 'lib/ace/support/cli/help/banner.rb', line 151

def self.arguments(command)
  return command.arguments if command.respond_to?(:arguments)
  return [] unless command.respond_to?(:required_arguments) && command.respond_to?(:optional_arguments)

  command.required_arguments + command.optional_arguments
end

.arguments_synopsis(command) ⇒ Object



127
128
129
130
131
132
# File 'lib/ace/support/cli/help/banner.rb', line 127

def self.arguments_synopsis(command)
  required = arguments(command).select { |arg| argument_required?(arg) }.map { |arg| arg.name.to_s.upcase }
  optional = arguments(command).reject { |arg| argument_required?(arg) }.map { |arg| "[#{arg.name.to_s.upcase}]" }
  values = required + optional
  values.empty? ? "" : " #{values.join(" ")}"
end

.call(command, name) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
# File 'lib/ace/support/cli/help/banner.rb', line 10

def self.call(command, name)
  [
    section_name(command, name),
    section_usage(command, name),
    section_description(command),
    section_subcommands(command),
    section_arguments(command),
    section_options(command),
    section_examples(command, name)
  ].compact.join("\n\n")
end

.dasherize(value) ⇒ Object



231
232
233
# File 'lib/ace/support/cli/help/banner.rb', line 231

def self.dasherize(value)
  value.to_s.tr("_", "-")
end

.description(command) ⇒ Object



134
135
136
# File 'lib/ace/support/cli/help/banner.rb', line 134

def self.description(command)
  command.respond_to?(:description) ? command.description : nil
end

.examples(command) ⇒ Object



170
171
172
# File 'lib/ace/support/cli/help/banner.rb', line 170

def self.examples(command)
  command.respond_to?(:examples) ? command.examples : []
end

.first_line(text) ⇒ Object



225
226
227
228
229
# File 'lib/ace/support/cli/help/banner.rb', line 225

def self.first_line(text)
  return nil if text.nil?

  text.to_s.strip.split("\n").first&.strip
end

.format_option(option) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/ace/support/cli/help/banner.rb', line 95

def self.format_option(option)
  rendered = option_name(option)
  rendered = "#{rendered}, #{option_aliases(option).join(", ")}" if option_aliases(option).any?
  label = "  --#{rendered}"

  details = []
  desc = option_desc(option)
  details << desc unless desc.to_s.empty?
  values = option_values(option)
  details << "(values: #{Array(values).join(", ")})" if values && !Array(values).empty?
  default = option_default(option)
  details << "(default: #{default.inspect})" unless default.nil?
  details << "(required)" if option_required?(option)

  return label if details.empty?

  "#{label.ljust(COLUMN_WIDTH + 2)}#{details.join(" ")}"
end

.hidden?(command) ⇒ Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/ace/support/cli/help/banner.rb', line 147

def self.hidden?(command)
  command.respond_to?(:hidden) && command.hidden
end

.option_aliases(option) ⇒ Object



181
182
183
184
185
186
# File 'lib/ace/support/cli/help/banner.rb', line 181

def self.option_aliases(option)
  return option.alias_names if option.respond_to?(:alias_names)
  return option.aliases if option.respond_to?(:aliases)

  []
end

.option_array?(option) ⇒ Boolean

Returns:

  • (Boolean)


213
214
215
216
217
# File 'lib/ace/support/cli/help/banner.rb', line 213

def self.option_array?(option)
  return option.array? if option.respond_to?(:array?)

  option.respond_to?(:type) && option.type.to_sym == :array
end

.option_boolean?(option) ⇒ Boolean

Returns:

  • (Boolean)


207
208
209
210
211
# File 'lib/ace/support/cli/help/banner.rb', line 207

def self.option_boolean?(option)
  return option.boolean? if option.respond_to?(:boolean?)

  option.respond_to?(:type) && option.type.to_sym == :boolean
end

.option_default(option) ⇒ Object



192
193
194
# File 'lib/ace/support/cli/help/banner.rb', line 192

def self.option_default(option)
  option.respond_to?(:default) ? option.default : nil
end

.option_desc(option) ⇒ Object



188
189
190
# File 'lib/ace/support/cli/help/banner.rb', line 188

def self.option_desc(option)
  option.respond_to?(:desc) ? option.desc : nil
end

.option_flag?(option) ⇒ Boolean

Returns:

  • (Boolean)


219
220
221
222
223
# File 'lib/ace/support/cli/help/banner.rb', line 219

def self.option_flag?(option)
  return option.flag? if option.respond_to?(:flag?)

  false
end

.option_name(option) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/ace/support/cli/help/banner.rb', line 114

def self.option_name(option)
  name = dasherize(option_name_raw(option))
  if option_boolean?(option)
    "[no-]#{name}"
  elsif option_array?(option)
    "#{name}=VALUE1,VALUE2,.."
  elsif option_flag?(option)
    name
  else
    "#{name}=VALUE"
  end
end

.option_name_raw(option) ⇒ Object



174
175
176
177
178
179
# File 'lib/ace/support/cli/help/banner.rb', line 174

def self.option_name_raw(option)
  return option.name if option.respond_to?(:name)
  return option.option_name if option.respond_to?(:option_name)

  "option"
end

.option_required?(option) ⇒ Boolean

Returns:

  • (Boolean)


200
201
202
203
204
205
# File 'lib/ace/support/cli/help/banner.rb', line 200

def self.option_required?(option)
  return option.required if option.respond_to?(:required)
  return option.required? if option.respond_to?(:required?)

  false
end

.option_values(option) ⇒ Object



196
197
198
# File 'lib/ace/support/cli/help/banner.rb', line 196

def self.option_values(option)
  option.respond_to?(:values) ? option.values : nil
end

.options(command) ⇒ Object



166
167
168
# File 'lib/ace/support/cli/help/banner.rb', line 166

def self.options(command)
  command.respond_to?(:options) ? command.options : []
end

.section_arguments(command) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/ace/support/cli/help/banner.rb', line 63

def self.section_arguments(command)
  args = arguments(command)
  return nil if args.empty?

  lines = args.map do |arg|
    label = arg.name.to_s.upcase
    label = "[#{label}]" unless argument_required?(arg)
    details = []
    details << argument_desc(arg) unless argument_desc(arg).to_s.empty?
    details << "(required)" if argument_required?(arg)
    "  #{label.ljust(COLUMN_WIDTH)}#{details.join(" ")}"
  end
  "ARGUMENTS\n#{lines.join("\n")}"
end

.section_description(command) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/ace/support/cli/help/banner.rb', line 35

def self.section_description(command)
  text = description(command)
  return nil if text.nil?

  lines = text.to_s.strip.split("\n")
  return nil if lines.size <= 1

  rest = lines.drop(1).drop_while { |line| line.strip.empty? }
  return nil if rest.empty?

  "DESCRIPTION\n#{rest.map { |line| "  #{line.strip}" }.join("\n")}"
end

.section_examples(command, name) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# File 'lib/ace/support/cli/help/banner.rb', line 84

def self.section_examples(command, name)
  items = examples(command)
  return nil if items.empty?

  lines = items.map do |item|
    cleaned = item.to_s.sub(/\A#{Regexp.escape(name)}\s*/, "")
    "  $ #{name} #{cleaned}".rstrip
  end
  "EXAMPLES\n#{lines.join("\n")}"
end

.section_name(command, name) ⇒ Object



22
23
24
25
26
# File 'lib/ace/support/cli/help/banner.rb', line 22

def self.section_name(command, name)
  summary = first_line(description(command))
  line = summary ? "#{name} - #{summary}" : name.to_s
  "NAME\n  #{line}"
end

.section_options(command) ⇒ Object



78
79
80
81
82
# File 'lib/ace/support/cli/help/banner.rb', line 78

def self.section_options(command)
  lines = options(command).map { |option| format_option(option) }
  lines << "  #{"--help, -h".ljust(COLUMN_WIDTH)}Show this help"
  "OPTIONS\n#{lines.join("\n")}"
end

.section_subcommands(command) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ace/support/cli/help/banner.rb', line 48

def self.section_subcommands(command)
  entries = subcommands(command)
  return nil if entries.empty?

  lines = entries.filter_map do |name, subcommand|
    next if hidden?(subcommand)

    desc = description(subcommand)
    "  #{name.to_s.ljust(COLUMN_WIDTH)}#{first_line(desc)}"
  end
  return nil if lines.empty?

  "SUBCOMMANDS\n#{lines.join("\n")}"
end

.section_usage(command, name) ⇒ Object



28
29
30
31
32
33
# File 'lib/ace/support/cli/help/banner.rb', line 28

def self.section_usage(command, name)
  usage = "#{name}#{arguments_synopsis(command)}"
  usage += " [OPTIONS]" if options(command).any?
  usage += " | #{name} SUBCOMMAND" if subcommands(command).any?
  "USAGE\n  #{usage}"
end

.subcommands(command) ⇒ Object



138
139
140
141
142
143
144
145
# File 'lib/ace/support/cli/help/banner.rb', line 138

def self.subcommands(command)
  return [] unless command.respond_to?(:subcommands)

  value = command.subcommands
  return value.to_a if value.respond_to?(:to_a)

  []
end