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.
@@ -32,5 +32,5 @@ module Toys
32
32
  # Current version of Toys core
33
33
  # @return [String]
34
34
  #
35
- CORE_VERSION = "0.3.5".freeze
35
+ CORE_VERSION = "0.3.6".freeze
36
36
  end
@@ -62,7 +62,7 @@ module Toys
62
62
  # configuration options in the {Toys::Utils::Exec} docs.
63
63
  #
64
64
  def configure_exec(opts = {})
65
- self[Exec].config_defaults(opts)
65
+ self[Exec].configure_defaults(opts)
66
66
  end
67
67
 
68
68
  ##
@@ -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.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
- desc: "Increase verbosity",
93
- long_desc: long_desc,
92
+ report_collisions: false,
94
93
  handler: ->(_val, cur) { cur + 1 },
95
- only_unique: true)
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
- desc: "Decrease verbosity",
106
- long_desc: long_desc,
105
+ report_collisions: false,
107
106
  handler: ->(_val, cur) { cur - 1 },
108
- only_unique: true)
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 that do not
36
- # have them set otherwise. You can set separate descriptions for tools,
37
- # namespaces, and the root.
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
- " https://www.rubydoc.info/gems/toys-core for more info. To replace this message," \
65
- " configure the SetDefaultDescriptions middleware.".freeze
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
- # The default description for remaining args.
87
- # @return [String]
72
+ # A mapping of names for acceptable types
73
+ # @return [Hash]
88
74
  #
89
- DEFAULT_REMAINING_ARG_DESC = "(Remaining arguments - no description available)".freeze
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, _loader)
169
- if tool.root?
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
- config_descs(flag, @default_flag_desc, @default_flag_long_desc)
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
- config_args(tool)
132
+ config_desc(tool, generate_tool_desc(tool, data), generate_tool_long_desc(tool, data))
180
133
  yield
181
134
  end
182
135
 
183
- private
136
+ protected
184
137
 
185
- def config_args(tool)
186
- tool.required_arg_definitions.each do |arg|
187
- config_descs(arg, @default_required_arg_desc, @default_required_arg_long_desc)
188
- end
189
- tool.optional_arg_definitions.each do |arg|
190
- config_descs(arg, @default_optional_arg_desc, @default_optional_arg_long_desc)
191
- end
192
- if tool.remaining_args_definition
193
- config_descs(tool.remaining_args_definition,
194
- @default_remaining_arg_desc, @default_remaining_arg_long_desc)
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
- def config_descs(object, default_desc, default_long_desc)
199
- if default_desc && object.desc.empty?
200
- object.desc = default_desc
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
- if default_long_desc && object.long_desc.empty?
203
- object.long_desc = default_long_desc
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", only_unique: true)
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
- desc: "Display a brief usage string for this tool", only_unique: true)
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
- desc: "Search subtools for the given regular expression",
264
- only_unique: true)
269
+ report_collisions: false,
270
+ desc: "Search subtools for the given regular expression")
265
271
  end
266
272
  end
267
273
  end