toys-core 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/lib/toys-core.rb +20 -5
  4. data/lib/toys/cli.rb +39 -32
  5. data/lib/toys/core_version.rb +1 -1
  6. data/lib/toys/{tool → definition}/acceptor.rb +21 -15
  7. data/lib/toys/{utils/line_output.rb → definition/alias.rb} +47 -59
  8. data/lib/toys/{tool/arg_definition.rb → definition/arg.rb} +17 -7
  9. data/lib/toys/{tool/flag_definition.rb → definition/flag.rb} +19 -9
  10. data/lib/toys/definition/tool.rb +574 -0
  11. data/lib/toys/dsl/arg.rb +118 -0
  12. data/lib/toys/dsl/flag.rb +132 -0
  13. data/lib/toys/dsl/tool.rb +521 -0
  14. data/lib/toys/errors.rb +2 -2
  15. data/lib/toys/helpers.rb +3 -3
  16. data/lib/toys/helpers/exec.rb +31 -25
  17. data/lib/toys/helpers/fileutils.rb +8 -2
  18. data/lib/toys/helpers/highline.rb +8 -1
  19. data/lib/toys/{alias.rb → helpers/terminal.rb} +44 -53
  20. data/lib/toys/input_file.rb +61 -0
  21. data/lib/toys/loader.rb +87 -77
  22. data/lib/toys/middleware.rb +3 -3
  23. data/lib/toys/middleware/add_verbosity_flags.rb +22 -20
  24. data/lib/toys/middleware/base.rb +53 -5
  25. data/lib/toys/middleware/handle_usage_errors.rb +9 -12
  26. data/lib/toys/middleware/set_default_descriptions.rb +6 -7
  27. data/lib/toys/middleware/show_help.rb +71 -67
  28. data/lib/toys/middleware/show_root_version.rb +9 -9
  29. data/lib/toys/runner.rb +157 -0
  30. data/lib/toys/template.rb +4 -3
  31. data/lib/toys/templates.rb +2 -2
  32. data/lib/toys/templates/clean.rb +2 -2
  33. data/lib/toys/templates/gem_build.rb +5 -5
  34. data/lib/toys/templates/minitest.rb +2 -2
  35. data/lib/toys/templates/rubocop.rb +2 -2
  36. data/lib/toys/templates/yardoc.rb +2 -2
  37. data/lib/toys/tool.rb +168 -625
  38. data/lib/toys/utils/exec.rb +19 -18
  39. data/lib/toys/utils/gems.rb +140 -0
  40. data/lib/toys/utils/help_text.rb +25 -20
  41. data/lib/toys/utils/terminal.rb +412 -0
  42. data/lib/toys/utils/wrappable_string.rb +3 -1
  43. metadata +15 -24
  44. data/lib/toys/config_dsl.rb +0 -699
  45. data/lib/toys/context.rb +0 -290
  46. data/lib/toys/helpers/spinner.rb +0 -142
data/lib/toys/context.rb DELETED
@@ -1,290 +0,0 @@
1
- # Copyright 2018 Daniel Azuma
2
- #
3
- # All rights reserved.
4
- #
5
- # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions are met:
7
- #
8
- # * Redistributions of source code must retain the above copyright notice,
9
- # this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # * Neither the name of the copyright holder, nor the names of any other
14
- # contributors to this software, may be used to endorse or promote products
15
- # derived from this software without specific prior written permission.
16
- #
17
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
- # POSSIBILITY OF SUCH DAMAGE.
28
- ;
29
-
30
- require "logger"
31
-
32
- module Toys
33
- ##
34
- # This class manages the object context in effect during the execution of a
35
- # tool. The context is a hash of key-value pairs.
36
- #
37
- # Flags and arguments defined by your tool normally report their values in
38
- # the context, using keys that are strings or symbols.
39
- #
40
- # Keys that are neither strings nor symbols are by convention used for other
41
- # context information, including:
42
- # * Common information such as the {Toys::Tool} object being executed, the
43
- # arguments originally passed to it, or the usage error string. These
44
- # well-known keys can be accessed via constants in the {Toys::Context}
45
- # module.
46
- # * Common settings such as the verbosity level, and whether to exit
47
- # immediately if a subprocess exits with a nonzero result. These keys are
48
- # also present as {Toys::Context} constants.
49
- # * Private information used internally by middleware and helpers.
50
- #
51
- # This class provides convenience accessors for common keys and settings, and
52
- # you can retrieve argument-set keys using the {#options} hash.
53
- #
54
- class Context
55
- ##
56
- # Context key for the currently running CLI.
57
- # @return [Object]
58
- #
59
- CLI = ::Object.new.freeze
60
-
61
- ##
62
- # Context key for the verbosity value. Verbosity is an integer defaulting
63
- # to 0, with higher values meaning more verbose and lower meaning quieter.
64
- # @return [Object]
65
- #
66
- VERBOSITY = ::Object.new.freeze
67
-
68
- ##
69
- # Context key for the `Toys::Tool` object being executed.
70
- # @return [Object]
71
- #
72
- TOOL = ::Object.new.freeze
73
-
74
- ##
75
- # Context key for the full name of the tool being executed. Value is an
76
- # array of strings.
77
- # @return [Object]
78
- #
79
- TOOL_NAME = ::Object.new.freeze
80
-
81
- ##
82
- # Context key for the active `Toys::Loader` object.
83
- # @return [Object]
84
- #
85
- LOADER = ::Object.new.freeze
86
-
87
- ##
88
- # Context key for the active `Logger` object.
89
- # @return [Object]
90
- #
91
- LOGGER = ::Object.new.freeze
92
-
93
- ##
94
- # Context key for the name of the toys binary. Value is a string.
95
- # @return [Object]
96
- #
97
- BINARY_NAME = ::Object.new.freeze
98
-
99
- ##
100
- # Context key for the argument list passed to the current tool. Value is
101
- # an array of strings.
102
- # @return [Object]
103
- #
104
- ARGS = ::Object.new.freeze
105
-
106
- ##
107
- # Context key for the usage error raised. Value is a string if there was
108
- # an error, or nil if there was no error.
109
- # @return [Object]
110
- #
111
- USAGE_ERROR = ::Object.new.freeze
112
-
113
- ##
114
- # Context key for whether nonzero exit codes from subprocesses should cause
115
- # an immediate exit. Value is a truthy or falsy value.
116
- # @return [Object]
117
- #
118
- EXIT_ON_NONZERO_STATUS = ::Object.new.freeze
119
-
120
- ##
121
- # Create a Context object. Applications generally will not need to create
122
- # these objects directly; they are created by the tool when it is preparing
123
- # for execution.
124
- # @private
125
- #
126
- # @param [Toys::CLI] cli
127
- # @param [Hash] data
128
- #
129
- def initialize(cli, data)
130
- @_data = data
131
- @_data[CLI] = cli
132
- @_data[LOADER] = cli.loader
133
- @_data[BINARY_NAME] = cli.binary_name
134
- @_data[LOGGER] = cli.logger
135
- end
136
-
137
- ##
138
- # Return the currently running CLI.
139
- # @return [Toys::CLI]
140
- #
141
- def cli
142
- @_data[CLI]
143
- end
144
-
145
- ##
146
- # Return the current verbosity setting as an integer.
147
- # @return [Integer]
148
- #
149
- def verbosity
150
- @_data[VERBOSITY]
151
- end
152
-
153
- ##
154
- # Return the tool being executed.
155
- # @return [Toys::Tool]
156
- #
157
- def tool
158
- @_data[TOOL]
159
- end
160
-
161
- ##
162
- # Return the name of the tool being executed, as an array of strings.
163
- # @return [Array[String]]
164
- #
165
- def tool_name
166
- @_data[TOOL_NAME]
167
- end
168
-
169
- ##
170
- # Return the raw arguments passed to the tool, as an array of strings.
171
- # This does not include the tool name itself.
172
- # @return [Array[String]]
173
- #
174
- def args
175
- @_data[ARGS]
176
- end
177
-
178
- ##
179
- # Return any usage error detected during argument parsing, or `nil` if
180
- # no error was detected.
181
- # @return [String,nil]
182
- #
183
- def usage_error
184
- @_data[USAGE_ERROR]
185
- end
186
-
187
- ##
188
- # Return the logger for this execution.
189
- # @return [Logger]
190
- #
191
- def logger
192
- @_data[LOGGER]
193
- end
194
-
195
- ##
196
- # Return the active loader that can be used to get other tools.
197
- # @return [Toys::Loader]
198
- #
199
- def loader
200
- @_data[LOADER]
201
- end
202
-
203
- ##
204
- # Return the name of the binary that was executed.
205
- # @return [String]
206
- #
207
- def binary_name
208
- @_data[BINARY_NAME]
209
- end
210
-
211
- ##
212
- # Return an option or other piece of data by key.
213
- #
214
- # @param [Symbol] key
215
- # @return [Object]
216
- #
217
- def [](key)
218
- @_data[key]
219
- end
220
- alias get []
221
-
222
- ##
223
- # Set an option or other piece of context data by key.
224
- #
225
- # @param [Symbol] key
226
- # @param [Object] value
227
- #
228
- def []=(key, value)
229
- @_data[key] = value
230
- end
231
-
232
- ##
233
- # Set an option or other piece of context data by key.
234
- #
235
- # @param [Symbol] key
236
- # @param [Object] value
237
- #
238
- def set(key, value = nil)
239
- if key.is_a?(::Hash)
240
- @_data.merge!(key)
241
- else
242
- @_data[key] = value
243
- end
244
- self
245
- end
246
-
247
- ##
248
- # Returns the subset of the context that uses string or symbol keys. By
249
- # convention, this includes keys that are set by tool flags and arguments,
250
- # but does not include well-known context values such as verbosity or
251
- # private context values used by middleware or helpers.
252
- #
253
- # @return [Hash]
254
- #
255
- def options
256
- @_data.select do |k, _v|
257
- k.is_a?(::Symbol) || k.is_a?(::String)
258
- end
259
- end
260
-
261
- ##
262
- # Execute another tool, given by the provided arguments.
263
- #
264
- # @param [String...] args The name of the tool to run along with its
265
- # command line arguments and flags.
266
- # @param [Toys::CLI,nil] cli The CLI to use to execute the tool. If `nil`
267
- # (the default), uses the current CLI.
268
- # @param [Boolean] exit_on_nonzero_status If true, exit immediately if the
269
- # run returns a nonzero error code.
270
- # @return [Integer] The resulting status code
271
- #
272
- def run(*args, cli: nil, exit_on_nonzero_status: nil)
273
- cli ||= @_data[CLI]
274
- exit_on_nonzero_status = @_data[EXIT_ON_NONZERO_STATUS] if exit_on_nonzero_status.nil?
275
- code = cli.run(args.flatten, verbosity: @_data[VERBOSITY])
276
- exit(code) if exit_on_nonzero_status && !code.zero?
277
- code
278
- end
279
-
280
- ##
281
- # Exit immediately with the given status code
282
- #
283
- # @param [Integer] code The status code, which should be 0 for no error,
284
- # or nonzero for an error condition.
285
- #
286
- def exit(code)
287
- throw :result, code
288
- end
289
- end
290
- end
@@ -1,142 +0,0 @@
1
- # Copyright 2018 Daniel Azuma
2
- #
3
- # All rights reserved.
4
- #
5
- # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions are met:
7
- #
8
- # * Redistributions of source code must retain the above copyright notice,
9
- # this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # * Neither the name of the copyright holder, nor the names of any other
14
- # contributors to this software, may be used to endorse or promote products
15
- # derived from this software without specific prior written permission.
16
- #
17
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
- # POSSIBILITY OF SUCH DAMAGE.
28
- ;
29
-
30
- require "monitor"
31
- require "highline"
32
-
33
- module Toys
34
- module Helpers
35
- ##
36
- # A module that provides a spinner output.
37
- #
38
- module Spinner
39
- ##
40
- # Default length of a single frame, in seconds.
41
- # @return [Float]
42
- #
43
- DEFAULT_FRAME_LENGTH = 0.1
44
-
45
- ##
46
- # Default set of frames.
47
- # @return [Array<String,Array(String,Integer)>]
48
- #
49
- DEFAULT_FRAMES = ["-", "\\", "|", "/"].freeze
50
-
51
- ##
52
- # Display a spinner during a task. You should provide a block that
53
- # performs the long-running task. While the block is executing, a
54
- # spinner will be displayed.
55
- #
56
- # @param [String] leading_text Optional leading string to display to the
57
- # left of the spinner. Default is the empty string.
58
- # @param [Float] frame_length Length of a single frame, in seconds.
59
- # Defaults to {DEFAULT_FRAME_LENGTH}.
60
- # @param [Array<String>] frames An array of frames. Defaults to
61
- # {DEFAULT_FRAMES}.
62
- # @param [Symbol,Array<Symbol>] style A HighLine style or array of styles
63
- # to apply to all frames in the spinner. Defaults to empty,
64
- # @param [IO] stream Stream to output the spinner to. Defaults to STDOUT.
65
- # Note the spinner will be disabled if this stream is not a tty.
66
- # @param [String] final_text Optional final string to display when the
67
- # spinner is complete. Default is the empty string. A common practice
68
- # is to set this to newline.
69
- #
70
- def spinner(leading_text: "",
71
- frame_length: DEFAULT_FRAME_LENGTH,
72
- frames: DEFAULT_FRAMES,
73
- style: nil,
74
- stream: $stdout,
75
- final_text: "")
76
- return nil unless block_given?
77
- unless leading_text.empty?
78
- stream.write(leading_text)
79
- stream.flush
80
- end
81
- spin = SpinDriver.new(stream, frames, Array(style), frame_length)
82
- begin
83
- yield
84
- ensure
85
- spin.stop
86
- unless final_text.empty?
87
- stream.write(final_text)
88
- stream.flush
89
- end
90
- end
91
- end
92
-
93
- ## @private
94
- class SpinDriver
95
- include ::MonitorMixin
96
-
97
- def initialize(stream, frames, style, frame_length)
98
- @stream = stream
99
- @frames = frames.map do |f|
100
- [
101
- style.empty? ? f : ::HighLine.color(f, *style),
102
- ::HighLine.uncolor(f).size
103
- ]
104
- end
105
- @frame_length = frame_length
106
- @cur_frame = 0
107
- @stopping = false
108
- @cond = new_cond
109
- super()
110
- @thread = @stream.tty? ? start_thread : nil
111
- end
112
-
113
- def stop
114
- synchronize do
115
- @stopping = true
116
- @cond.broadcast
117
- end
118
- @thread.join if @thread
119
- self
120
- end
121
-
122
- private
123
-
124
- def start_thread
125
- ::Thread.new do
126
- synchronize do
127
- until @stopping
128
- @stream.write(@frames[@cur_frame][0])
129
- @stream.flush
130
- @cond.wait(@frame_length)
131
- size = @frames[@cur_frame][1]
132
- @stream.write("\b" * size + " " * size + "\b" * size)
133
- @cur_frame += 1
134
- @cur_frame = 0 if @cur_frame >= @frames.size
135
- end
136
- end
137
- end
138
- end
139
- end
140
- end
141
- end
142
- end