toys-core 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/lib/toys/config_dsl.rb +26 -23
- data/lib/toys/core_version.rb +1 -1
- data/lib/toys/helpers.rb +3 -1
- data/lib/toys/helpers/{file_utils.rb → fileutils.rb} +7 -2
- data/lib/toys/helpers/highline.rb +127 -0
- data/lib/toys/helpers/spinner.rb +136 -0
- data/lib/toys/middleware/add_verbosity_switches.rb +2 -2
- data/lib/toys/middleware/handle_usage_errors.rb +5 -1
- data/lib/toys/middleware/show_usage.rb +11 -7
- data/lib/toys/middleware/show_version.rb +1 -1
- data/lib/toys/templates/clean.rb +1 -1
- data/lib/toys/templates/gem_build.rb +3 -1
- data/lib/toys/templates/minitest.rb +2 -2
- data/lib/toys/tool.rb +258 -99
- data/lib/toys/utils/module_lookup.rb +17 -5
- data/lib/toys/utils/usage.rb +101 -47
- data/lib/toys/utils/wrappable_string.rb +92 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ebb136d89b19617cfdaf8de9c870cce070857748abd208ab8faa4896b7e7b36
|
4
|
+
data.tar.gz: eb079b488d1da544e5f31ab0fe0f9730d77d6878549c673bc6ba4711a5d6c295
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 864c7bc16399227e29e013372611ed70df77339185593d3830a31a5092e7dea6540d62ed83704e23ce5d78410ce2b4e34ae5ce9f709d67d8bb82e5075ed09cc3
|
7
|
+
data.tar.gz: 5eb3e60cefb50d7a289ef2283a91574ede820bf1d2bb5769d8038d60d760e999f36e49882899c06f2de6dd37a23d828ee25bd1e2a0764e11cc0e31553764368c
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 0.3.3 / 2018-05-09
|
4
|
+
|
5
|
+
* CHANGED: Renamed file_utils helper to fileutils.
|
6
|
+
* CHANGED: Renamed doc: parameter to docs:
|
7
|
+
* CHANGED: SwitchDefinition has separate fields for acceptor and docs.
|
8
|
+
* CHANGED: Description and long description are now arrays of strings.
|
9
|
+
* FIXED: Documentation strings that begin with "--" no longer cause problems.
|
10
|
+
* ADDED: Highline helper
|
11
|
+
* ADDED: Spinner helper
|
12
|
+
* ADDED: WrappableString for descriptions and docs
|
13
|
+
* IMPROVED: Usage can now customize the left column width and indent
|
14
|
+
* IMPROVED: Newlines in documentation are properly indented
|
15
|
+
|
3
16
|
### 0.3.2 / 2018-05-07
|
4
17
|
|
5
18
|
* CHANGED: Split core engine out into "toys-core" from the "toys" gem.
|
data/lib/toys/config_dsl.rb
CHANGED
@@ -164,12 +164,12 @@ module Toys
|
|
164
164
|
# Set the long description for the current tool. The long description is
|
165
165
|
# displayed in the usage documentation for the tool itself.
|
166
166
|
#
|
167
|
-
# @param [String]
|
167
|
+
# @param [String,Toys::Utils::WrappableString...] strs The long description
|
168
168
|
#
|
169
|
-
def long_desc(
|
169
|
+
def long_desc(*strs)
|
170
170
|
return self if _cur_tool.nil?
|
171
171
|
_cur_tool.definition_path = @path
|
172
|
-
_cur_tool.long_desc =
|
172
|
+
_cur_tool.long_desc = strs
|
173
173
|
self
|
174
174
|
end
|
175
175
|
|
@@ -178,12 +178,12 @@ module Toys
|
|
178
178
|
# displayed with the tool in a command list. You may also use the
|
179
179
|
# equivalent method `short_desc`.
|
180
180
|
#
|
181
|
-
# @param [String]
|
181
|
+
# @param [String,Toys::Utils::WrappableString...] strs The short description
|
182
182
|
#
|
183
|
-
def desc(
|
183
|
+
def desc(*strs)
|
184
184
|
return self if _cur_tool.nil?
|
185
185
|
_cur_tool.definition_path = @path
|
186
|
-
_cur_tool.desc =
|
186
|
+
_cur_tool.desc = strs
|
187
187
|
self
|
188
188
|
end
|
189
189
|
alias short_desc desc
|
@@ -200,8 +200,9 @@ module Toys
|
|
200
200
|
# @param [Object] default The default value. This is the value that will
|
201
201
|
# be set in the context if this switch is not provided on the command
|
202
202
|
# line. Defaults to `nil`.
|
203
|
-
# @param [String,
|
204
|
-
#
|
203
|
+
# @param [String,Toys::Utils::WrappableString,
|
204
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for
|
205
|
+
# the switch. Defaults to empty array.
|
205
206
|
# @param [Boolean] only_unique If true, any switches that are already
|
206
207
|
# defined in this tool are removed from this switch. For example, if
|
207
208
|
# an earlier switch uses `-a`, and this switch wants to use both
|
@@ -214,11 +215,11 @@ module Toys
|
|
214
215
|
# value. i.e. the default is effectively `-> (val, _prev) { val }`.
|
215
216
|
#
|
216
217
|
def switch(key, *switches,
|
217
|
-
accept: nil, default: nil,
|
218
|
+
accept: nil, default: nil, docs: nil, only_unique: false, handler: nil)
|
218
219
|
return self if _cur_tool.nil?
|
219
220
|
_cur_tool.definition_path = @path
|
220
221
|
_cur_tool.add_switch(key, *switches,
|
221
|
-
accept: accept, default: default,
|
222
|
+
accept: accept, default: default, docs: docs,
|
222
223
|
only_unique: only_unique, handler: handler)
|
223
224
|
self
|
224
225
|
end
|
@@ -231,13 +232,14 @@ module Toys
|
|
231
232
|
# @param [Symbol] key The key to use to retrieve the value from the
|
232
233
|
# execution context.
|
233
234
|
# @param [Object,nil] accept An OptionParser acceptor. Optional.
|
234
|
-
# @param [String,
|
235
|
-
#
|
235
|
+
# @param [String,Toys::Utils::WrappableString,
|
236
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for the
|
237
|
+
# arg. Defaults to empty array.
|
236
238
|
#
|
237
|
-
def required_arg(key, accept: nil,
|
239
|
+
def required_arg(key, accept: nil, docs: nil)
|
238
240
|
return self if _cur_tool.nil?
|
239
241
|
_cur_tool.definition_path = @path
|
240
|
-
_cur_tool.add_required_arg(key, accept: accept,
|
242
|
+
_cur_tool.add_required_arg(key, accept: accept, docs: docs)
|
241
243
|
self
|
242
244
|
end
|
243
245
|
|
@@ -253,13 +255,14 @@ module Toys
|
|
253
255
|
# @param [Object] default The default value. This is the value that will
|
254
256
|
# be set in the context if this argument is not provided on the command
|
255
257
|
# line. Defaults to `nil`.
|
256
|
-
# @param [String,
|
257
|
-
#
|
258
|
+
# @param [String,Toys::Utils::WrappableString,
|
259
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for the
|
260
|
+
# arg. Defaults to empty array.
|
258
261
|
#
|
259
|
-
def optional_arg(key, accept: nil, default: nil,
|
262
|
+
def optional_arg(key, accept: nil, default: nil, docs: nil)
|
260
263
|
return self if _cur_tool.nil?
|
261
264
|
_cur_tool.definition_path = @path
|
262
|
-
_cur_tool.add_optional_arg(key, accept: accept, default: default,
|
265
|
+
_cur_tool.add_optional_arg(key, accept: accept, default: default, docs: docs)
|
263
266
|
self
|
264
267
|
end
|
265
268
|
|
@@ -274,14 +277,14 @@ module Toys
|
|
274
277
|
# @param [Object] default The default value. This is the value that will
|
275
278
|
# be set in the context if no unmatched arguments are provided on the
|
276
279
|
# command line. Defaults to the empty array `[]`.
|
277
|
-
# @param [String,
|
278
|
-
#
|
279
|
-
#
|
280
|
+
# @param [String,Toys::Utils::WrappableString,
|
281
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for the
|
282
|
+
# args. Defaults to empty array.
|
280
283
|
#
|
281
|
-
def remaining_args(key, accept: nil, default: [],
|
284
|
+
def remaining_args(key, accept: nil, default: [], docs: nil)
|
282
285
|
return self if _cur_tool.nil?
|
283
286
|
_cur_tool.definition_path = @path
|
284
|
-
_cur_tool.set_remaining_args(key, accept: accept, default: default,
|
287
|
+
_cur_tool.set_remaining_args(key, accept: accept, default: default, docs: docs)
|
285
288
|
self
|
286
289
|
end
|
287
290
|
|
data/lib/toys/core_version.rb
CHANGED
data/lib/toys/helpers.rb
CHANGED
@@ -40,7 +40,9 @@ module Toys
|
|
40
40
|
# Currently recognized module names are:
|
41
41
|
#
|
42
42
|
# * `:exec` : Methods to help execute subcommands.
|
43
|
-
# * `:
|
43
|
+
# * `:fileutils` : The FileUtils standard library methods.
|
44
|
+
# * `:highline` : Methods from the highline gem.
|
45
|
+
# * `:spinner` : Displays a spinner on the terminal.
|
44
46
|
#
|
45
47
|
# @param [String,Symbol] name Name of the helper module to return
|
46
48
|
# @return [Module,nil] The module, or `nil` if not found
|
@@ -32,8 +32,13 @@ require "fileutils"
|
|
32
32
|
module Toys
|
33
33
|
module Helpers
|
34
34
|
##
|
35
|
-
#
|
35
|
+
# A module that provides all methods in the "fileutils" standard library.
|
36
36
|
#
|
37
|
-
|
37
|
+
module Fileutils
|
38
|
+
## @private
|
39
|
+
def self.extend_object(obj)
|
40
|
+
obj.extend(::FileUtils)
|
41
|
+
end
|
42
|
+
end
|
38
43
|
end
|
39
44
|
end
|
@@ -0,0 +1,127 @@
|
|
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
|
+
gem "highline", "~> 1.7"
|
31
|
+
|
32
|
+
require "highline"
|
33
|
+
|
34
|
+
module Toys
|
35
|
+
module Helpers
|
36
|
+
##
|
37
|
+
# A module that provides access to highline.
|
38
|
+
#
|
39
|
+
module Highline
|
40
|
+
##
|
41
|
+
# Returns a global highline instance
|
42
|
+
# @return [::HighLine]
|
43
|
+
#
|
44
|
+
def self.highline
|
45
|
+
@highline ||= ::HighLine.new
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Returns a global highline instance
|
50
|
+
# @return [::HighLine]
|
51
|
+
#
|
52
|
+
def highline
|
53
|
+
Highline.highline
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine:agree HighLine#agree
|
58
|
+
#
|
59
|
+
def agree(*args, &block)
|
60
|
+
highline.agree(*args, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine:ask HighLine#ask
|
65
|
+
#
|
66
|
+
def ask(*args, &block)
|
67
|
+
highline.ask(*args, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine:choose HighLine#choose
|
72
|
+
#
|
73
|
+
def choose(*args, &block)
|
74
|
+
highline.choose(*args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine:list HighLine#list
|
79
|
+
#
|
80
|
+
def list(*args, &block)
|
81
|
+
highline.list(*args, &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine:say HighLine#say
|
86
|
+
#
|
87
|
+
def say(*args, &block)
|
88
|
+
highline.say(*args, &block)
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine.color HighLine.color
|
93
|
+
#
|
94
|
+
def color(*args, &block)
|
95
|
+
::HighLine.color(*args, &block)
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine.color_code HighLine.color_code
|
100
|
+
#
|
101
|
+
def color_code(*args, &block)
|
102
|
+
::HighLine.color_code(*args, &block)
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine.uncolor HighLine.uncolor
|
107
|
+
#
|
108
|
+
def uncolor(*args, &block)
|
109
|
+
::HighLine.uncolor(*args, &block)
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine:indent HighLine#indent
|
114
|
+
#
|
115
|
+
def indent(*args, &block)
|
116
|
+
highline.indent(*args, &block)
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# @see https://www.rubydoc.info/gems/highline/HighLine:newline HighLine#newline
|
121
|
+
#
|
122
|
+
def newline(*args, &block)
|
123
|
+
highline.newline(*args, &block)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,136 @@
|
|
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
|
+
|
32
|
+
module Toys
|
33
|
+
module Helpers
|
34
|
+
##
|
35
|
+
# A module that provides a spinner output.
|
36
|
+
#
|
37
|
+
module Spinner
|
38
|
+
##
|
39
|
+
# Default length of a single frame, in seconds.
|
40
|
+
# @return [Float]
|
41
|
+
#
|
42
|
+
DEFAULT_FRAME_LENGTH = 0.1
|
43
|
+
|
44
|
+
##
|
45
|
+
# Default set of frames.
|
46
|
+
# @return [Array<String,Array(String,Integer)>]
|
47
|
+
#
|
48
|
+
DEFAULT_FRAMES = ["-", "\\", "|", "/"].freeze
|
49
|
+
|
50
|
+
##
|
51
|
+
# Display a spinner during a task. You should provide a block that
|
52
|
+
# performs the long-running task. While the block is executing, a
|
53
|
+
# spinner will be displayed.
|
54
|
+
#
|
55
|
+
# @param [String] leading_text Optional leading string to display to the
|
56
|
+
# left of the spinner.
|
57
|
+
# @param [Float] frame_length Length of a single frame, in seconds.
|
58
|
+
# Defaults to {DEFAULT_FRAME_LENGTH}.
|
59
|
+
# @param [Array<String,Array<String>>] frames An array of frames. Each
|
60
|
+
# frame should be either a string, or a two-element array of string
|
61
|
+
# and integer, where the integer is the visible length of the frame
|
62
|
+
# on screen. The latter form should be used if the frame string
|
63
|
+
# contains non-printing characters such as ANSI escape codes.
|
64
|
+
# Defaults to {DEFAULT_FRAMES}.
|
65
|
+
# @param [IO] stream Stream to output the spinner to. Defaults to STDOUT.
|
66
|
+
# Note the spinner will be disabled if this stream is not a tty.
|
67
|
+
# @param [String] final_text Optional final string to display when the
|
68
|
+
# spinner is complete.
|
69
|
+
#
|
70
|
+
def spinner(leading_text: "",
|
71
|
+
frame_length: DEFAULT_FRAME_LENGTH,
|
72
|
+
frames: DEFAULT_FRAMES,
|
73
|
+
stream: $stdout,
|
74
|
+
final_text: "")
|
75
|
+
return nil unless block_given?
|
76
|
+
unless leading_text.empty?
|
77
|
+
stream.write(leading_text)
|
78
|
+
stream.flush
|
79
|
+
end
|
80
|
+
spin = SpinDriver.new(stream, frames, frame_length)
|
81
|
+
begin
|
82
|
+
yield
|
83
|
+
ensure
|
84
|
+
spin.stop
|
85
|
+
unless final_text.empty?
|
86
|
+
stream.write(final_text)
|
87
|
+
stream.flush
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
## @private
|
93
|
+
class SpinDriver
|
94
|
+
include ::MonitorMixin
|
95
|
+
|
96
|
+
def initialize(stream, frames, frame_length)
|
97
|
+
@stream = stream
|
98
|
+
@frames = frames.map { |f| f.is_a?(::Array) ? f : [f, f.size] }
|
99
|
+
@frame_length = frame_length
|
100
|
+
@cur_frame = 0
|
101
|
+
@stopping = false
|
102
|
+
@cond = new_cond
|
103
|
+
super()
|
104
|
+
@thread = @stream.tty? ? start_thread : nil
|
105
|
+
end
|
106
|
+
|
107
|
+
def stop
|
108
|
+
synchronize do
|
109
|
+
@stopping = true
|
110
|
+
@cond.broadcast
|
111
|
+
end
|
112
|
+
@thread.join if @thread
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def start_thread
|
119
|
+
::Thread.new do
|
120
|
+
synchronize do
|
121
|
+
until @stopping
|
122
|
+
@stream.write(@frames[@cur_frame][0])
|
123
|
+
@stream.flush
|
124
|
+
@cond.wait(@frame_length)
|
125
|
+
size = @frames[@cur_frame][1]
|
126
|
+
@stream.write("\b" * size + " " * size + "\b" * size)
|
127
|
+
@cur_frame += 1
|
128
|
+
@cur_frame = 0 if @cur_frame >= @frames.size
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|