toys 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4090b70821f47975fbfd82cd40651b3ee93e43ecf77cb7a820f20322524a3447
4
- data.tar.gz: 70440b824c11d8c7b14e0cda8bfd57f8a74df0aa084c5f47b63efbd3047a7706
3
+ metadata.gz: 7744684eb5fd0d03f650315fad4bb84bc433d0ce4e0529c82f6bf2ebcb60f9f5
4
+ data.tar.gz: 26c4d2e48917887441bd6bc03986110f7269bdd2b1f0098d1b9cd3a19a5b0248
5
5
  SHA512:
6
- metadata.gz: e2a58b4eea98ed65f797dcccdef7bc5abbb3df45aa9771263e9c69bc809b3d15507521cfc012753285dc9464c441db0d08e7a31c15c098e610fffe959888e621
7
- data.tar.gz: 41a9dbfee92b60d34cb74b07ac8599a8bf01da0203d386dcfd73a3dac8711030d97c6548ff40caa3dd63dc9fb123c14eb590dbb6a5809679978ebc081328141d
6
+ metadata.gz: 61445d45a25a6d64f9f2fc547e38589b7f49d8cdf08a07e7bff33b3687307bbeed4b7aa1f8528c2c91a6abf52c3bea86a79392d3d0bbf98652fe5fd2d526f693
7
+ data.tar.gz: a08b400babfecc9c6fd119447d37f62df645986b3d23e5ef381cbf7e05d766b3d1eebd97d0947bb7a8c7cd5b5f53c59aaca329f4bfbb4a8c0463520b11ca1dca
@@ -1,5 +1,14 @@
1
1
  # Release History
2
2
 
3
+ ### 0.3.7 / 2018-05-30
4
+
5
+ * CHANGED: Execution runs in the same scope as the DSL, which lets us use normal methods instead of helper-blocks.
6
+ * CHANGED: Renamed "script" to "run", and allow setting of runnable by defining a "run" method
7
+ * CHANGED: Set up a constant scope for each config file, to make constant lookup make sense.
8
+ * CHANGED: Removed run_toys and dropped EXIT_ON_NONZERO_STATUS key in favor of using cli directly.
9
+ * CHANGED: Removed spinner helper and added terminal helper.
10
+ * ADDED: Helper modules scoped to the tool hierarchy
11
+
3
12
  ### 0.3.6 / 2018-05-21
4
13
 
5
14
  * CHANGED: Removed Context#new_cli and exposed Context#cli instead.
data/README.md CHANGED
@@ -69,8 +69,8 @@ current directory. Copy the following into the file, and save it:
69
69
  tool "greet" do
70
70
  desc "My first tool!"
71
71
  flag :whom, default: "world"
72
- script do
73
- puts "Hello, #{options[:whom]}!"
72
+ def run
73
+ puts "Hello, #{option(:whom)}!"
74
74
  end
75
75
  end
76
76
 
@@ -107,9 +107,10 @@ various subtools, such as "version", are available under that namespace.
107
107
 
108
108
  Toys provides a rich set of useful libraries for writing tools. It gives you a
109
109
  logger and automatically provides flags to control verbosity of log output. It
110
- includes the Highline library, which you can use to produce styled output,
111
- console-based interfaces, and special effects. It also includes a library that
112
- makes it easy to control subprocesses.
110
+ includes a simple library that you can use to produce styled output and basic
111
+ console-based interfaces, and another library that makes it easy to spawn and
112
+ control subprocesses. You can also take advantage of a variety of third-party
113
+ libraries such as Highline and TTY.
113
114
 
114
115
  For a more detailed look at Toys, see the
115
116
  {file:docs/tutorial.md Extended Tutorial} and the
data/bin/toys CHANGED
@@ -29,6 +29,8 @@
29
29
  # POSSIBILITY OF SUCH DAMAGE.
30
30
  ;
31
31
 
32
+ ::ENV["TOYS_BIN_PATH"] ||= ::File.absolute_path(__FILE__)
33
+
32
34
  $LOAD_PATH.unshift(::File.absolute_path(::File.join(::File.dirname(__dir__), "lib")))
33
35
  require "toys"
34
36
 
@@ -54,12 +54,11 @@ flag :delim, "-d", "--delim=VALUE",
54
54
 
55
55
  remaining_args :args, desc: "A series of tools to run, separated by the delimiter"
56
56
 
57
- script do
58
- delim = self[:delim]
59
- self[:args]
60
- .chunk { |arg| arg == delim ? :_separator : true }
57
+ def run
58
+ option(:args)
59
+ .chunk { |arg| arg == option(:delim) ? :_separator : true }
61
60
  .each do |_, action|
62
- code = run(action)
61
+ code = cli.run(action)
63
62
  exit(code) unless code.zero?
64
63
  end
65
64
  end
@@ -32,42 +32,56 @@ desc "A set of system commands for Toys"
32
32
  long_desc "Contains tools that inspect, configure, and update Toys itself."
33
33
 
34
34
  tool "version" do
35
- desc "Print current Toys version."
35
+ desc "Print the current Toys version"
36
36
 
37
- script do
37
+ def run
38
38
  puts ::Toys::VERSION
39
39
  end
40
40
  end
41
41
 
42
42
  tool "update" do
43
- desc "Update Toys if a newer version is available."
43
+ desc "Update Toys if a newer version is available"
44
44
 
45
45
  long_desc "Checks rubygems for a newer version of Toys. If one is available, downloads" \
46
46
  " and installs it."
47
47
 
48
48
  flag :yes, "-y", "--yes", desc: "Do not ask for interactive confirmation"
49
49
 
50
- use :exec
51
- use :highline
50
+ include :exec
51
+ include :terminal
52
52
 
53
- script do
54
- logger.info "Checking rubygems for the latest Toys release..."
55
- version_info = capture("gem query -q -r -e toys")
53
+ def run
54
+ configure_exec(exit_on_nonzero_status: true)
55
+ version_info = terminal.spinner(leading_text: "Checking rubygems for the latest release... ",
56
+ final_text: "Done.\n") do
57
+ capture(["gem", "query", "-q", "-r", "-e", "toys"])
58
+ end
56
59
  if version_info =~ /toys\s\((.+)\)/
57
60
  latest_version = ::Gem::Version.new($1)
58
61
  cur_version = ::Gem::Version.new(::Toys::VERSION)
59
62
  if latest_version > cur_version
60
- exit(1) unless options[:yes] ||
61
- agree("Update toys from #{cur_version} to #{latest_version}? (y/n) ")
62
- sh("gem install toys")
63
+ prompt = "Update toys from #{cur_version} to #{latest_version}?"
64
+ exit(1) unless option(:yes) || confirm(prompt)
65
+ result = terminal.spinner(leading_text: "Installing Toys version #{latest_version}... ",
66
+ final_text: "Done.\n") do
67
+ exec(["gem", "install", "toys", "--version", latest_version],
68
+ out_to: :capture, err_to: :capture)
69
+ end
70
+ if result.error?
71
+ puts(result.captured_out + result.captured_err)
72
+ puts("Toys failed to install version #{latest_version}", :red, :bold)
73
+ exit(1)
74
+ end
75
+ puts("Toys successfully installed version #{latest_version}", :green, :bold)
63
76
  elsif latest_version < cur_version
64
- logger.warn("Toys is already at experimental version #{cur_version}, which is later than" \
65
- " the latest released version #{latest_version}")
77
+ puts("Toys is already at experimental version #{cur_version}, which is later than" \
78
+ " the latest released version #{latest_version}",
79
+ :yellow, :bold)
66
80
  else
67
- logger.warn("Toys is already at the latest version: #{latest_version}")
81
+ puts("Toys is already at the latest version: #{latest_version}", :green, :bold)
68
82
  end
69
83
  else
70
- logger.error("Could not get latest Toys version")
84
+ puts("Could not get latest Toys version", :red, :bold)
71
85
  exit(1)
72
86
  end
73
87
  end
@@ -14,34 +14,34 @@ This user's guide covers everything you need to know to use Toys effectively.
14
14
 
15
15
  Toys is a command line *framework*. It provides a binary called `toys` along
16
16
  with basic functions such as argument parsing and online help. You provide the
17
- actual behavior of the toys binary by writing *configuration files*.
17
+ actual behavior of the toys binary by writing **configuration files**.
18
18
 
19
19
  Toys is a multi-command binary. You may define a collection of commands, called
20
- *tools*, which can be invoked by passing the tool name as an argument to the
21
- `toys` binary. Tools are arranged in a hierarchy; a tool may be a *namespace*
20
+ **tools**, which can be invoked by passing the tool name as an argument to the
21
+ `toys` binary. Tools are arranged in a hierarchy; a tool may be a **namespace**
22
22
  that has *subtools*.
23
23
 
24
- Tools may recognize command line arguments in the form of *flags* and
25
- *positional arguments*. Flags can optionally take *values*, while positional
26
- arguments may be *required* or *optional*.
24
+ Tools may recognize command line arguments in the form of **flags** and
25
+ **positional arguments**. Flags can optionally take **values**, while
26
+ positional arguments may be **required** or **optional**.
27
27
 
28
- The configuration of a tool may define *descriptions*, for the tool itself, and
29
- for each command line argument. These descriptions are displayed in the tool's
30
- *online help* screen. Descriptions come in *long* and *short* forms, which
31
- appear in different styles of help.
28
+ The configuration of a tool may define **descriptions**, for the tool itself,
29
+ and for each command line argument. These descriptions are displayed in the
30
+ tool's **online help** screen. Descriptions come in **long** and **short**
31
+ forms, which appear in different styles of help.
32
32
 
33
- Toys searches for configuration in specifically-named *configuration files* and
34
- *configuration directories*. It searches for these in the current directory,
35
- and in a *configuration search path*.
33
+ Toys searches for configuration in specifically-named **configuration files**
34
+ and **configuration directories**. It searches for these in the current
35
+ directory, its ancestors, and in a **configuration search path**.
36
36
 
37
37
  Toys provides various features to help you write tools. This includes providing
38
- a *logger* for each tool, *helper modules* that provide common functions a tool
39
- can call, and *templates* which are prefabricated tools you can add to your
40
- configuration.
38
+ a **logger** for each tool, **helper modules** that provide common functions a
39
+ tool can call, and **templates** which are prefabricated tools you can add to
40
+ your configuration.
41
41
 
42
- Finally, Toys provides certain *built-in behavior*, including automatically
42
+ Finally, Toys provides certain **built-in behavior**, including automatically
43
43
  providing flags to display help screens and set verbosity. It also includes a
44
- built-in namespace of *system tools* that let you inspect and configure the
44
+ built-in namespace of **system tools** that let you inspect and configure the
45
45
  Toys system itself.
46
46
 
47
47
  ## The Toys Command Line
@@ -76,7 +76,7 @@ In the following command:
76
76
  toys system blah
77
77
 
78
78
  There is no subtool `blah` under the `system` namespace, so Toys works backward
79
- until it finds a legitimate tool. In this case, the `system` namespace itself
79
+ until it finds an existing tool. In this case, the `system` namespace itself
80
80
  does exist, so it is interpreted as the tool, and `blah` is interpreted as an
81
81
  argument passed to it.
82
82
 
@@ -152,8 +152,8 @@ That will cause `--recursive` to be treated as a positional argument. (In this
152
152
  case, as we saw earlier, the root tool will respond by printing an error
153
153
  message that no subtool named `--recursive` exists.)
154
154
 
155
- Note that a single hyphen by itself `-` is not considered a flag and is treated
156
- as a positional argument.
155
+ Note that a single hyphen by itself `-` is not considered a flag, nor does it
156
+ disable flag parsing. It is treated as a normal positional argument.
157
157
 
158
158
  #### Standard Flags
159
159
 
@@ -224,16 +224,192 @@ like so:
224
224
 
225
225
  ## Defining Tools
226
226
 
227
+ Tools are defined by writing Toys *configuration files*. The simplest form of a
228
+ configuration file is a file named `.toys.rb` (note the leading period) in the
229
+ current working directory. Such a file may define tools that are available in
230
+ the current directory, and for this section we will assume we are writing such
231
+ a file. The following section on "Understanding Configurations" will cover the
232
+ larger concerns of how configuration files are looked up and how multiple
233
+ configurations interact.
234
+
235
+ ### Basic Config Syntax
236
+
237
+ The format of a Toys configuration file is a Ruby DSL including method calls
238
+ and nested blocks. The actual DSL is specified in the
239
+ [Toys::DSL::Tool class](https://www.rubydoc.info/gems/toys-core/Toys/DSL/Tool).
240
+
241
+ To create a tool, write a `tool` block, giving the tool a name. Within the
242
+ block, set the properties of the tool, including a description, the flags and
243
+ arguments recognized by the tool, and the actual functionality of the tool.
244
+
245
+ Consider the following example:
246
+
247
+ tool "greet" do
248
+ desc "Print a friendly greeting."
249
+ long_desc "Prints a friendly greeting. You may customize whom to" \
250
+ " greet, and how friendly it should be.",
251
+ "",
252
+ "Example:",
253
+ [" toys greet --shout ruby"]
254
+
255
+ optional_arg :whom, default: "world", desc: "Whom to greet."
256
+ flag :shout, "-s", "--shout", desc: "Greet loudly."
257
+
258
+ def run
259
+ greeting = "Hello, #{option(:whom)}!"
260
+ greeting.upcase! if option(:shout)
261
+ puts greeting
262
+ end
263
+ end
264
+
265
+ Its results should be mostly self-evident. We'll take a look at some of the
266
+ details below.
267
+
268
+ ### Descriptions
269
+
270
+ Each tool may have a short and a long description. The short description is a
271
+ generally a single string that is displayed with the tool name at the top of
272
+ its help page, or in a subtool list. The long description can include multiple
273
+ strings, which are displayed in multiple lines in the "description" section of
274
+ the tool's help page. Long descriptions may include blank lines to separate
275
+ paragraphs visually.
276
+
277
+ Each description string/line is word-wrapped by default when displayed. In the
278
+ long description above, the first line is a bit longer than 80 characters, and
279
+ may be word-wrapped if displayed on an 80-character terminal.
280
+
281
+ If you need to control the wrapping behavior, pass an array of strings for that
282
+ line. Each array element will be considered a unit for wrapping purposes, and
283
+ will not be split. The example command in the long description above
284
+ illustrates how to prevent a line from being word-wrapped. This is also a
285
+ useful technique for preserving spaces and indentation.
286
+
287
+ For more details, see the reference documentation for
288
+ [DSL::Tool#desc](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:desc)
289
+ and
290
+ [DSL::Tool#long_desc](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:long_desc).
291
+
292
+ ### Positional Arguments
293
+
294
+ Tools may recognize required and optional positional arguments. Each argument
295
+ must provide a name, which defines how the argument value is exposed to the
296
+ tool at execution time. The above example uses the DSL method
297
+ [DSL::Tool#optional_arg](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:optional_arg)
298
+ to declare an optional argument named `:whom`. If the argument is provided on
299
+ the command line e.g.
300
+
301
+ toys greet ruby
302
+
303
+ Then the option `:whom` is set to the string `"ruby"`. The value is made
304
+ available via the `options` hash in the tools's script. Otherwise, if the
305
+ argument is omitted, e.g.
306
+
307
+ toys greet
308
+
309
+ Then the option `:whom` is set to the default value `"world"`.
310
+
311
+ Arguments may also be **required** which means they must be provided on the
312
+ command line; otherwise the tool will report a usage error. You may declare a
313
+ required argument using the DSL method
314
+ [DSL::Tool#required_arg](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:required_arg).
315
+
316
+ When command line arguments are parsed, the required arguments are matched
317
+ first, in order, followed by the optional arguments. For example:
318
+
319
+ tool "arguments" do
320
+ optional_arg :arg2
321
+ required_arg :arg1
322
+ # ...
323
+
324
+ If a user runs
325
+
326
+ toys arguments foo
327
+
328
+ Then the required argument `:arg1` will be set to `"foo"`, and the optional
329
+ argument `:arg2` will not be set (i.e. it will remain `nil`).
330
+
331
+ If the user runs:
332
+
333
+ toys arguments foo bar
334
+
335
+ Then `:arg1` is set to `"foo"`, and `:arg2` is set to `"bar"`.
336
+
337
+ Running the following:
338
+
339
+ toys arguments
340
+
341
+ Will produce a usage error, because no value is set for the required argument
342
+ `:arg1`. Similarly, running:
343
+
344
+ toys arguments foo bar baz
345
+
346
+ Will also produce an error, since the tool does not provide an argument to
347
+ match `"baz"`.
348
+
349
+ You can also provide an "argument" to match all remaining unmatched arguments
350
+ at the end, using the DSL method
351
+ [DSL::Tool#remaining_args](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:remaining_args). For example:
352
+
353
+ tool "arguments" do
354
+ optional_arg :arg2
355
+ required_arg :arg1
356
+ remaining_args :arg3
357
+ # ...
358
+
359
+ Now, running:
360
+
361
+ toys arguments foo bar baz bey
362
+
363
+ Sets the following option data:
364
+
365
+ {arg1: "foo", arg2: "bar", arg3: ["baz", "bey"]}
366
+
367
+ Positional arguments may also have short and long descriptions, which are
368
+ displayed in online help.
369
+
370
+ ### Flags
371
+
372
+ Tools may also recognize flags on the command line. In our "greet" example, we
373
+ declared a flag named `:shout`:
374
+
375
+ flag :shout, "-s", "--shout", desc: "Greet loudly."
376
+
377
+ (guid is still incomplete)
378
+
379
+ ### The Execution Script
380
+
381
+ ### Namespaces
382
+
227
383
  ## Understanding Configurations
228
384
 
229
385
  ## Helper Methods and Modules
230
386
 
231
- ## The Standard Helpers
387
+ ### The Standard Helpers
388
+
389
+ ## The Execution Environment
390
+
391
+ ### Built-in Context
392
+
393
+ ### Logging and Verbosity
394
+
395
+ ### Running Tools from Tools
396
+
397
+ ### Executing Subprocesses
398
+
399
+ ### Formatting Output
232
400
 
233
401
  ## Prefabricated Tools with Templates
234
402
 
235
- ## Defining Templates
403
+ ### Defining Templates
236
404
 
237
405
  ## Advanced Tool Definition Techniques
238
406
 
407
+ ### Aliases
408
+
409
+ ### Includes
410
+
411
+ ### Controlling Built-in Flags
412
+
413
+ ## The System Tools
414
+
239
415
  ## Embedding Toys
@@ -34,6 +34,11 @@
34
34
  # individual directories.
35
35
  #
36
36
  module Toys
37
+ ##
38
+ # Path to the Toys binary
39
+ # @return [String]
40
+ #
41
+ BINARY_PATH = ::ENV["TOYS_BIN_PATH"] || "toys"
37
42
  end
38
43
 
39
44
  require "toys/version"
@@ -75,7 +75,7 @@ module Toys
75
75
  # Short description for the standard root tool
76
76
  # @return [String]
77
77
  #
78
- DEFAULT_ROOT_DESC = "Your personal command line tool.".freeze
78
+ DEFAULT_ROOT_DESC = "Your personal command line tool".freeze
79
79
 
80
80
  ##
81
81
  # Help text for the standard root tool
@@ -125,9 +125,9 @@ module Toys
125
125
  # `$HOME:/etc` by default.
126
126
  # * The builtins for the standard toys binary.
127
127
  #
128
+ # @param [Toys::CLI] cli Add paths to this CLI
128
129
  # @param [String,nil] directory Starting search directory for configs.
129
130
  # Defaults to the current working directory.
130
- # @param [Toys::CLI] cli Add paths to this CLI
131
131
  #
132
132
  def self.add_standard_paths(cli, directory: nil)
133
133
  cli.add_search_path_hierarchy(start: directory)
@@ -32,5 +32,5 @@ module Toys
32
32
  # Current version of the Toys command line binary
33
33
  # @return [String]
34
34
  #
35
- VERSION = "0.3.6".freeze
35
+ VERSION = "0.3.7".freeze
36
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toys
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-21 00:00:00.000000000 Z
11
+ date: 2018-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: toys-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.6
19
+ version: 0.3.7
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.6
26
+ version: 0.3.7
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement