toys-core 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/toys/cli.rb +15 -10
- data/lib/toys/config_dsl.rb +103 -17
- data/lib/toys/context.rb +60 -48
- data/lib/toys/core_version.rb +1 -1
- data/lib/toys/helpers/exec.rb +1 -1
- data/lib/toys/helpers/highline.rb +4 -9
- data/lib/toys/middleware/add_verbosity_flags.rb +6 -6
- data/lib/toys/middleware/set_default_descriptions.rb +162 -92
- data/lib/toys/middleware/show_help.rb +12 -6
- data/lib/toys/middleware/{show_version.rb → show_root_version.rb} +14 -23
- data/lib/toys/tool.rb +122 -372
- data/lib/toys/tool/acceptor.rb +190 -0
- data/lib/toys/tool/arg_definition.rb +130 -0
- data/lib/toys/tool/flag_definition.rb +322 -0
- data/lib/toys/utils/exec.rb +1 -1
- data/lib/toys/utils/help_text.rb +21 -15
- data/lib/toys/utils/line_output.rb +29 -12
- data/lib/toys/utils/wrappable_string.rb +23 -0
- metadata +6 -3
data/lib/toys/core_version.rb
CHANGED
data/lib/toys/helpers/exec.rb
CHANGED
@@ -35,20 +35,15 @@ module Toys
|
|
35
35
|
# A module that provides access to highline.
|
36
36
|
#
|
37
37
|
module Highline
|
38
|
-
##
|
39
|
-
# Returns a global highline instance
|
40
|
-
# @return [::HighLine]
|
41
|
-
#
|
42
|
-
def self.highline
|
43
|
-
@highline ||= ::HighLine.new
|
44
|
-
end
|
45
|
-
|
46
38
|
##
|
47
39
|
# Returns a global highline instance
|
48
40
|
# @return [::HighLine]
|
49
41
|
#
|
50
42
|
def highline
|
51
|
-
Highline
|
43
|
+
self[Highline] ||= begin
|
44
|
+
::HighLine.use_color = $stdout.tty?
|
45
|
+
::HighLine.new
|
46
|
+
end
|
52
47
|
end
|
53
48
|
|
54
49
|
##
|
@@ -89,10 +89,10 @@ module Toys
|
|
89
89
|
unless verbose_flags.empty?
|
90
90
|
long_desc = "Increase verbosity, causing additional logging levels to display."
|
91
91
|
tool.add_flag(Context::VERBOSITY, verbose_flags,
|
92
|
-
|
93
|
-
long_desc: long_desc,
|
92
|
+
report_collisions: false,
|
94
93
|
handler: ->(_val, cur) { cur + 1 },
|
95
|
-
|
94
|
+
desc: "Increase verbosity",
|
95
|
+
long_desc: long_desc)
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
@@ -102,10 +102,10 @@ module Toys
|
|
102
102
|
unless quiet_flags.empty?
|
103
103
|
long_desc = "Decrease verbosity, causing fewer logging levels to display."
|
104
104
|
tool.add_flag(Context::VERBOSITY, quiet_flags,
|
105
|
-
|
106
|
-
long_desc: long_desc,
|
105
|
+
report_collisions: false,
|
107
106
|
handler: ->(_val, cur) { cur - 1 },
|
108
|
-
|
107
|
+
desc: "Decrease verbosity",
|
108
|
+
long_desc: long_desc)
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
@@ -32,9 +32,12 @@ require "toys/middleware/base"
|
|
32
32
|
module Toys
|
33
33
|
module Middleware
|
34
34
|
##
|
35
|
-
# This middleware sets default description fields for tools
|
36
|
-
#
|
37
|
-
#
|
35
|
+
# This middleware sets default description fields for tools and command
|
36
|
+
# line arguments and flags that do not have them set otherwise.
|
37
|
+
#
|
38
|
+
# You can modify the static descriptions for tools, namespaces, and the
|
39
|
+
# root tool by passing parameters to this middleware. For finer control,
|
40
|
+
# you can override methods to modify the description generation logic.
|
38
41
|
#
|
39
42
|
class SetDefaultDescriptions < Base
|
40
43
|
##
|
@@ -59,34 +62,25 @@ module Toys
|
|
59
62
|
# The default long description for the root tool.
|
60
63
|
# @return [String]
|
61
64
|
#
|
62
|
-
DEFAULT_ROOT_LONG_DESC =
|
65
|
+
DEFAULT_ROOT_LONG_DESC = [
|
63
66
|
"This command line tool was built using the toys-core gem. See" \
|
64
|
-
|
65
|
-
" configure the SetDefaultDescriptions middleware."
|
66
|
-
|
67
|
-
##
|
68
|
-
# The default description for flags.
|
69
|
-
# @return [String]
|
70
|
-
#
|
71
|
-
DEFAULT_FLAG_DESC = "(No flag description available)".freeze
|
72
|
-
|
73
|
-
##
|
74
|
-
# The default description for required args.
|
75
|
-
# @return [String]
|
76
|
-
#
|
77
|
-
DEFAULT_REQUIRED_ARG_DESC = "(Required argument - no description available)".freeze
|
78
|
-
|
79
|
-
##
|
80
|
-
# The default description for optional args.
|
81
|
-
# @return [String]
|
82
|
-
#
|
83
|
-
DEFAULT_OPTIONAL_ARG_DESC = "(Optional argument - no description available)".freeze
|
67
|
+
" https://www.rubydoc.info/gems/toys-core for more info.",
|
68
|
+
"To replace this message, configure the SetDefaultDescriptions middleware."
|
69
|
+
].freeze
|
84
70
|
|
85
71
|
##
|
86
|
-
#
|
87
|
-
# @return [
|
72
|
+
# A mapping of names for acceptable types
|
73
|
+
# @return [Hash]
|
88
74
|
#
|
89
|
-
|
75
|
+
ACCEPTABLE_NAMES = {
|
76
|
+
nil => "string",
|
77
|
+
::String => "nonempty string",
|
78
|
+
::TrueClass => "boolean",
|
79
|
+
::FalseClass => "boolean",
|
80
|
+
::OptionParser::DecimalInteger => "decimal integer",
|
81
|
+
::OptionParser::OctalInteger => "octal integer",
|
82
|
+
::OptionParser::DecimalNumeric => "decimal numeric"
|
83
|
+
}.freeze
|
90
84
|
|
91
85
|
##
|
92
86
|
# Create a SetDefaultDescriptions middleware given default descriptions.
|
@@ -109,100 +103,176 @@ module Toys
|
|
109
103
|
# @param [String,nil] default_root_long_desc The default long description
|
110
104
|
# for the root tool, or `nil` not to set one. Defaults to
|
111
105
|
# {DEFAULT_ROOT_LONG_DESC}.
|
112
|
-
# @param [String,nil] default_flag_desc The default short description for
|
113
|
-
# flags, or `nil` not to set one. Defaults to {DEFAULT_FLAG_DESC}.
|
114
|
-
# @param [String,nil] default_flag_long_desc The default long description
|
115
|
-
# for flags, or `nil` not to set one. Defaults to `nil`.
|
116
|
-
# @param [String,nil] default_required_arg_desc The default short
|
117
|
-
# description for required args, or `nil` not to set one. Defaults to
|
118
|
-
# {DEFAULT_REQUIRED_ARG_DESC}.
|
119
|
-
# @param [String,nil] default_required_arg_long_desc The default long
|
120
|
-
# description for required args, or `nil` not to set one. Defaults to
|
121
|
-
# `nil`.
|
122
|
-
# @param [String,nil] default_optional_arg_desc The default short
|
123
|
-
# description for optional args, or `nil` not to set one. Defaults to
|
124
|
-
# {DEFAULT_OPTIONAL_ARG_DESC}.
|
125
|
-
# @param [String,nil] default_optional_arg_long_desc The default long
|
126
|
-
# description for optional args, or `nil` not to set one. Defaults to
|
127
|
-
# `nil`.
|
128
|
-
# @param [String,nil] default_remaining_arg_desc The default short
|
129
|
-
# description for remaining args, or `nil` not to set one. Defaults
|
130
|
-
# to {DEFAULT_REMAINING_ARG_DESC}.
|
131
|
-
# @param [String,nil] default_remaining_arg_long_desc The default long
|
132
|
-
# description for remaining args, or `nil` not to set one. Defaults
|
133
|
-
# to `nil`.
|
134
106
|
#
|
135
107
|
def initialize(default_tool_desc: DEFAULT_TOOL_DESC,
|
136
108
|
default_tool_long_desc: nil,
|
137
109
|
default_namespace_desc: DEFAULT_NAMESPACE_DESC,
|
138
110
|
default_namespace_long_desc: nil,
|
139
111
|
default_root_desc: DEFAULT_ROOT_DESC,
|
140
|
-
default_root_long_desc: DEFAULT_ROOT_LONG_DESC
|
141
|
-
default_flag_desc: DEFAULT_FLAG_DESC,
|
142
|
-
default_flag_long_desc: nil,
|
143
|
-
default_required_arg_desc: DEFAULT_REQUIRED_ARG_DESC,
|
144
|
-
default_required_arg_long_desc: nil,
|
145
|
-
default_optional_arg_desc: DEFAULT_OPTIONAL_ARG_DESC,
|
146
|
-
default_optional_arg_long_desc: nil,
|
147
|
-
default_remaining_arg_desc: DEFAULT_REMAINING_ARG_DESC,
|
148
|
-
default_remaining_arg_long_desc: nil)
|
112
|
+
default_root_long_desc: DEFAULT_ROOT_LONG_DESC)
|
149
113
|
@default_tool_desc = default_tool_desc
|
150
114
|
@default_tool_long_desc = default_tool_long_desc
|
151
115
|
@default_namespace_desc = default_namespace_desc
|
152
116
|
@default_namespace_long_desc = default_namespace_long_desc
|
153
117
|
@default_root_desc = default_root_desc
|
154
118
|
@default_root_long_desc = default_root_long_desc
|
155
|
-
@default_flag_desc = default_flag_desc
|
156
|
-
@default_flag_long_desc = default_flag_long_desc
|
157
|
-
@default_required_arg_desc = default_required_arg_desc
|
158
|
-
@default_required_arg_long_desc = default_required_arg_long_desc
|
159
|
-
@default_optional_arg_desc = default_optional_arg_desc
|
160
|
-
@default_optional_arg_long_desc = default_optional_arg_long_desc
|
161
|
-
@default_remaining_arg_desc = default_remaining_arg_desc
|
162
|
-
@default_remaining_arg_long_desc = default_remaining_arg_long_desc
|
163
119
|
end
|
164
120
|
|
165
121
|
##
|
166
122
|
# Add default description text to tools.
|
167
123
|
#
|
168
|
-
def config(tool,
|
169
|
-
|
170
|
-
config_descs(tool, @default_root_desc, @default_root_long_desc)
|
171
|
-
elsif tool.includes_script?
|
172
|
-
config_descs(tool, @default_tool_desc, @default_tool_long_desc)
|
173
|
-
else
|
174
|
-
config_descs(tool, @default_namespace_desc, @default_namespace_long_desc)
|
175
|
-
end
|
124
|
+
def config(tool, loader)
|
125
|
+
data = {tool: tool, loader: loader}
|
176
126
|
tool.flag_definitions.each do |flag|
|
177
|
-
|
127
|
+
config_desc(flag, generate_flag_desc(flag, data), generate_flag_long_desc(flag, data))
|
128
|
+
end
|
129
|
+
tool.arg_definitions.each do |arg|
|
130
|
+
config_desc(arg, generate_arg_desc(arg, data), generate_arg_long_desc(arg, data))
|
178
131
|
end
|
179
|
-
|
132
|
+
config_desc(tool, generate_tool_desc(tool, data), generate_tool_long_desc(tool, data))
|
180
133
|
yield
|
181
134
|
end
|
182
135
|
|
183
|
-
|
136
|
+
protected
|
184
137
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
138
|
+
##
|
139
|
+
# This method implements the logic for generating a tool description.
|
140
|
+
# By default, it uses the parameters given to the middleware object.
|
141
|
+
# Override this method to provide different logic.
|
142
|
+
#
|
143
|
+
# @param [Toys::Tool] tool The tool to document.
|
144
|
+
# @param [Hash] data Additional data that might be useful. Currently,
|
145
|
+
# the {Toys::Loader} is passed with key `:loader`. Future versions
|
146
|
+
# of Toys may provide additional information.
|
147
|
+
# @return [String,Array<String>,Toys::Utils::WrappableString,nil] The
|
148
|
+
# default description, or `nil` not to set a default. See
|
149
|
+
# {Toys::Tool#desc=} for info on the format.
|
150
|
+
#
|
151
|
+
def generate_tool_desc(tool, data)
|
152
|
+
if tool.root?
|
153
|
+
@default_root_desc
|
154
|
+
elsif !tool.includes_script? && data[:loader].has_subtools?(tool.full_name)
|
155
|
+
@default_namespace_desc
|
156
|
+
else
|
157
|
+
@default_tool_desc
|
195
158
|
end
|
196
159
|
end
|
197
160
|
|
198
|
-
|
199
|
-
|
200
|
-
|
161
|
+
##
|
162
|
+
# This method implements logic for generating a tool long description.
|
163
|
+
# By default, it uses the parameters given to the middleware object.
|
164
|
+
# Override this method to provide different logic.
|
165
|
+
#
|
166
|
+
# @param [Toys::Tool] tool The tool to document
|
167
|
+
# @param [Hash] data Additional data that might be useful. Currently,
|
168
|
+
# the {Toys::Loader} is passed with key `:loader`. Future versions
|
169
|
+
# of Toys may provide additional information.
|
170
|
+
# @return [Array<Toys::Utils::WrappableString,String,Array<String>>,nil]
|
171
|
+
# The default long description, or `nil` not to set a default. See
|
172
|
+
# {Toys::Tool#long_desc=} for info on the format.
|
173
|
+
#
|
174
|
+
def generate_tool_long_desc(tool, data)
|
175
|
+
if tool.root?
|
176
|
+
@default_root_long_desc
|
177
|
+
elsif !tool.includes_script? && data[:loader].has_subtools?(tool.full_name)
|
178
|
+
@default_namespace_long_desc
|
179
|
+
else
|
180
|
+
@default_tool_long_desc
|
201
181
|
end
|
202
|
-
|
203
|
-
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# This method implements the logic for generating a flag description.
|
186
|
+
# Override this method to provide different logic.
|
187
|
+
#
|
188
|
+
# @param [Toys::Tool::FlagDefinition] flag The flag to document
|
189
|
+
# @param [Hash] data Additional data that might be useful. Currently,
|
190
|
+
# the {Toys::Tool} is passed with key `:tool`. Future versions of
|
191
|
+
# Toys may provide additional information.
|
192
|
+
# @return [String,Array<String>,Toys::Utils::WrappableString,nil] The
|
193
|
+
# default description, or `nil` not to set a default. See
|
194
|
+
# {Toys::Tool#desc=} for info on the format.
|
195
|
+
#
|
196
|
+
def generate_flag_desc(flag, data) # rubocop:disable Lint/UnusedMethodArgument
|
197
|
+
name = flag.key.to_s.tr("_", "-").gsub(/[^\w-]/, "").downcase.inspect
|
198
|
+
acceptable = flag.flag_type == :value ? acceptable_name(flag.accept) : "boolean flag"
|
199
|
+
default_clause = flag.default ? " (default is #{flag.default.inspect})" : ""
|
200
|
+
"Sets the #{name} option as type #{acceptable}#{default_clause}."
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# This method implements logic for generating a flag long description.
|
205
|
+
# Override this method to provide different logic.
|
206
|
+
#
|
207
|
+
# @param [Toys::Tool::FlagDefinition] flag The flag to document
|
208
|
+
# @param [Hash] data Additional data that might be useful. Currently,
|
209
|
+
# the {Toys::Tool} is passed with key `:tool`. Future versions of
|
210
|
+
# Toys may provide additional information.
|
211
|
+
# @return [Array<Toys::Utils::WrappableString,String,Array<String>>,nil]
|
212
|
+
# The default long description, or `nil` not to set a default. See
|
213
|
+
# {Toys::Tool#long_desc=} for info on the format.
|
214
|
+
#
|
215
|
+
def generate_flag_long_desc(flag, data) # rubocop:disable Lint/UnusedMethodArgument
|
216
|
+
nil
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# This method implements the logic for generating an arg description.
|
221
|
+
# Override this method to provide different logic.
|
222
|
+
#
|
223
|
+
# @param [Toys::Tool::ArgDefinition] arg The arg to document
|
224
|
+
# @param [Hash] data Additional data that might be useful. Currently,
|
225
|
+
# the {Toys::Tool} is passed with key `:tool`. Future versions of
|
226
|
+
# Toys may provide additional information.
|
227
|
+
# @return [String,Array<String>,Toys::Utils::WrappableString,nil] The
|
228
|
+
# default description, or `nil` not to set a default. See
|
229
|
+
# {Toys::Tool#desc=} for info on the format.
|
230
|
+
#
|
231
|
+
def generate_arg_desc(arg, data) # rubocop:disable Lint/UnusedMethodArgument
|
232
|
+
acceptable = acceptable_name(arg.accept)
|
233
|
+
default_clause = arg.default ? " (default is #{arg.default.inspect})" : ""
|
234
|
+
case arg.type
|
235
|
+
when :required
|
236
|
+
"Required #{acceptable} argument."
|
237
|
+
when :optional
|
238
|
+
"Optional #{acceptable} argument#{default_clause}."
|
239
|
+
else
|
240
|
+
"Remaining arguments are type #{acceptable}#{default_clause}."
|
204
241
|
end
|
205
242
|
end
|
243
|
+
|
244
|
+
##
|
245
|
+
# This method implements logic for generating an arg long description.
|
246
|
+
# Override this method to provide different logic.
|
247
|
+
#
|
248
|
+
# @param [Toys::Tool::ArgDefinition] arg The arg to document
|
249
|
+
# @param [Hash] data Additional data that might be useful. Currently,
|
250
|
+
# the {Toys::Tool} is passed with key `:tool`. Future versions of
|
251
|
+
# Toys may provide additional information.
|
252
|
+
# @return [Array<Toys::Utils::WrappableString,String,Array<String>>,nil]
|
253
|
+
# The default long description, or `nil` not to set a default. See
|
254
|
+
# {Toys::Tool#long_desc=} for info on the format.
|
255
|
+
#
|
256
|
+
def generate_arg_long_desc(arg, data) # rubocop:disable Lint/UnusedMethodArgument
|
257
|
+
nil
|
258
|
+
end
|
259
|
+
|
260
|
+
##
|
261
|
+
# Return a reasonable name for an acceptor
|
262
|
+
#
|
263
|
+
# @param [Object] accept An acceptor to name
|
264
|
+
# @return [String]
|
265
|
+
#
|
266
|
+
def acceptable_name(accept)
|
267
|
+
ACCEPTABLE_NAMES[accept] || accept.to_s.downcase
|
268
|
+
end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
def config_desc(object, desc, long_desc)
|
273
|
+
object.desc = desc if desc && object.desc.empty?
|
274
|
+
object.long_desc = long_desc if long_desc && object.long_desc.empty?
|
275
|
+
end
|
206
276
|
end
|
207
277
|
end
|
208
278
|
end
|
@@ -110,6 +110,8 @@ module Toys
|
|
110
110
|
# help or usage, and doesn't otherwise use positional arguments,
|
111
111
|
# then a tool name can be passed as arguments to display help for
|
112
112
|
# that tool.
|
113
|
+
# @param [Boolean] show_source_path Show the source path section. Default
|
114
|
+
# is `false`.
|
113
115
|
# @param [Boolean] use_less If the `less` tool is available, and the
|
114
116
|
# output stream is a tty, then use `less` to display help text.
|
115
117
|
# @param [IO] stream Output stream to write to. Default is stdout.
|
@@ -124,6 +126,7 @@ module Toys
|
|
124
126
|
default_recursive: false,
|
125
127
|
fallback_execution: false,
|
126
128
|
allow_root_args: false,
|
129
|
+
show_source_path: false,
|
127
130
|
use_less: false,
|
128
131
|
stream: $stdout,
|
129
132
|
styled_output: nil)
|
@@ -134,6 +137,7 @@ module Toys
|
|
134
137
|
@default_recursive = default_recursive ? true : false
|
135
138
|
@fallback_execution = fallback_execution
|
136
139
|
@allow_root_args = allow_root_args
|
140
|
+
@show_source_path = show_source_path
|
137
141
|
@stream = stream
|
138
142
|
@styled_output = styled_output
|
139
143
|
@use_less = use_less
|
@@ -171,6 +175,7 @@ module Toys
|
|
171
175
|
help_text = get_help_text(context)
|
172
176
|
str = help_text.help_string(recursive: context[:_recursive_subtools],
|
173
177
|
search: context[:_search_subtools],
|
178
|
+
show_source_path: @show_source_path,
|
174
179
|
wrap_width: output_cols)
|
175
180
|
output_help(str)
|
176
181
|
else
|
@@ -229,7 +234,7 @@ module Toys
|
|
229
234
|
DEFAULT_HELP_FLAGS)
|
230
235
|
unless help_flags.empty?
|
231
236
|
tool.add_flag(:_show_help, help_flags,
|
232
|
-
desc: "Display help for this tool"
|
237
|
+
report_collisions: false, desc: "Display help for this tool")
|
233
238
|
end
|
234
239
|
help_flags
|
235
240
|
end
|
@@ -239,7 +244,8 @@ module Toys
|
|
239
244
|
DEFAULT_USAGE_FLAGS)
|
240
245
|
unless usage_flags.empty?
|
241
246
|
tool.add_flag(:_show_usage, usage_flags,
|
242
|
-
|
247
|
+
report_collisions: false,
|
248
|
+
desc: "Display a brief usage string for this tool")
|
243
249
|
end
|
244
250
|
usage_flags
|
245
251
|
end
|
@@ -249,9 +255,9 @@ module Toys
|
|
249
255
|
DEFAULT_RECURSIVE_FLAGS)
|
250
256
|
unless recursive_flags.empty?
|
251
257
|
tool.add_flag(:_recursive_subtools, recursive_flags,
|
258
|
+
report_collisions: false,
|
252
259
|
default: @default_recursive,
|
253
|
-
desc: "Show all subtools recursively (default is #{@default_recursive})"
|
254
|
-
only_unique: true)
|
260
|
+
desc: "Show all subtools recursively (default is #{@default_recursive})")
|
255
261
|
end
|
256
262
|
end
|
257
263
|
|
@@ -260,8 +266,8 @@ module Toys
|
|
260
266
|
DEFAULT_SEARCH_FLAGS)
|
261
267
|
unless search_flags.empty?
|
262
268
|
tool.add_flag(:_search_subtools, search_flags,
|
263
|
-
|
264
|
-
|
269
|
+
report_collisions: false,
|
270
|
+
desc: "Search subtools for the given regular expression")
|
265
271
|
end
|
266
272
|
end
|
267
273
|
end
|