-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
formatter.rb
138 lines (115 loc) · 3.37 KB
/
formatter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# frozen_string_literal: true
module TTY
module Option
class Formatter
SHORT_OPT_LENGTH = 4
NEWLINE = "\n"
# @api public
def self.help(parameters, usage)
new(parameters, usage).help
end
# Create a help formatter
#
# @param [Parameters]
#
# @api public
def initialize(parameters, usage)
@parameters = parameters
@usage = usage
end
# A formatted help usage information
#
# @return [String]
#
# @api public
def help
output = []
output << (@usage.banner? ? @usage.banner : format_usage) + NEWLINE
if @usage.desc?
output << @usage.desc + NEWLINE
end
if @parameters.options?
output << "Options:"
output << format_options
end
formatted = output.join(NEWLINE)
formatted.end_with?(NEWLINE) ? formatted : formatted + NEWLINE
end
private
# @api private
def format_usage
output = []
output << "Usage: "
output << @usage.program
output << " [OPTIONS]" if @parameters.options?
output << " #{format_arguments}" if @parameters.arguments?
output.join
end
# @api private
def format_arguments
return "" unless @parameters.arguments?
@parameters.arguments.reduce([]) do |acc, arg|
arg_name = arg.name.to_s.upcase
if 0 < arg.arity
args = []
args << "[" if arg.optional?
args << arg_name
(arg.arity - 1).times { args << " #{arg_name}" }
args << "]" if arg.optional?
acc << args.join
else
(arg.arity.abs - 1).times { acc << arg_name }
acc << "[#{arg_name}...]"
end
acc
end.join(" ")
end
# Returns all the options formatted to fit 80 columns
#
# @return [String]
#
# @api private
def format_options
return "" if @parameters.options.empty?
output = []
longest_option = @parameters.options.map(&:long)
.compact.max_by(&:length).length
ordered_options = @parameters.options.sort
ordered_options.each do |option|
output << format_option(option, longest_option)
end
output.join(NEWLINE)
end
# Format an option
#
# @api private
def format_option(option, longest_length)
line = []
short_option = option.short? ? option.short_name : " "
line << format("%#{SHORT_OPT_LENGTH}s", short_option)
# short & long option separator
line << ((option.short? && option.long?) ? ", " : " ")
if option.long?
if option.desc?
line << format("%-#{longest_length}s", option.long)
else
line << option.long
end
else
line << format("%-#{longest_length}s", " ")
end
if option.desc?
line << " #{option.desc}"
end
if option.default? && ![true, false].include?(option.default)
if option.default.is_a?(String)
line << format(" (default %p)", option.default)
else
line << format(" (default %s)", option.default)
end
end
line.join
end
end # Formatter
end # Option
end # TTY