toys 0.9.4 → 0.10.4
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 +4 -4
- data/.yardopts +2 -1
- data/CHANGELOG.md +33 -0
- data/LICENSE.md +1 -1
- data/README.md +3 -3
- data/bin/toys +3 -22
- data/builtins/do.rb +0 -20
- data/builtins/system.rb +1 -20
- data/docs/guide.md +332 -57
- data/lib/toys.rb +24 -32
- data/lib/toys/standard_cli.rb +0 -23
- data/lib/toys/templates/clean.rb +27 -26
- data/lib/toys/templates/gem_build.rb +127 -53
- data/lib/toys/templates/minitest.rb +148 -36
- data/lib/toys/templates/rake.rb +99 -28
- data/lib/toys/templates/rdoc.rb +193 -50
- data/lib/toys/templates/rspec.rb +190 -41
- data/lib/toys/templates/rubocop.rb +107 -32
- data/lib/toys/templates/yardoc.rb +294 -59
- data/lib/toys/version.rb +1 -22
- data/share/bash-completion-remove.sh +0 -20
- data/share/bash-completion.sh +0 -20
- metadata +5 -145
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2df55870f3530617a4961bb0cfa09d0752bb13e99f7642a4156ab4b7ffea3a8c
|
4
|
+
data.tar.gz: 74131a75411c11703347193f167c916e351fa3582401d0505036cd74dbb9911c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff5a5e3e2c2fea1bebdcfbeef064bd51d5a587a48077b7ee6c6b4befe926433d0318ce5c4b8c63a067e8b4e6dbd21f191c86b11844e8e1ff9d8c6096cffad996
|
7
|
+
data.tar.gz: 464d5d87896965c77182d6f7f3793b23bbf9797439619c01b9142516bb71077f44a5c53e81492017890e8fd9db1cb7d5c9e83bed1ea68741f716d94833e7e3b6
|
data/.yardopts
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,38 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 0.10.4 / 2020-07-11
|
4
|
+
|
5
|
+
* IMPROVED: Bundler integration can now handle Toys itself being in the bundle, as long as the version requirements cover the running Toys version.
|
6
|
+
* IMPROVED: Passing `static: true` to the `:bundler` mixin installs the bundle at definition rather than execution time.
|
7
|
+
|
8
|
+
### 0.10.3 / 2020-07-04
|
9
|
+
|
10
|
+
* FIXED: The `exec_separate_tool` method in the `:exec` mixin no longer throws ENOEXEC on Windows.
|
11
|
+
|
12
|
+
### 0.10.2 / 2020-07-03
|
13
|
+
|
14
|
+
* FIXED: The load path no longer loses the toys and toys-core directories after a bundle install.
|
15
|
+
|
16
|
+
### 0.10.1 / 2020-03-07
|
17
|
+
|
18
|
+
* FIXED: Setting `:exit_on_nonzero_status` explicitly to false now works as expected.
|
19
|
+
|
20
|
+
### 0.10.0 / 2020-02-24
|
21
|
+
|
22
|
+
* ADDED: `:bundler` mixin that installs and sets up a bundle for the tool
|
23
|
+
* ADDED: `bundler` options in the standard templates, to run those tools in a bundle
|
24
|
+
* ADDED: `subtool_apply` directive which applies a block to all subtools.
|
25
|
+
* ADDED: Add `.lib` directories to the Ruby load path when executing a tool.
|
26
|
+
* ADDED: `toys_version?` and `toys_version!` directives that check against version requirements.
|
27
|
+
* ADDED: `exec_separate_tool` and `capture_separate_tool` methods in the `:exec` mixin, to support executing tools in a separate process without forking
|
28
|
+
* IMPROVED: `long_desc` directive can now read the description from a text file.
|
29
|
+
* IMPROVED: The `tool` directive can take delimited strings as tool names.
|
30
|
+
* IMPROVED: Subtool blocks aren't actually executed unless the tool is needed.
|
31
|
+
* CHANGED: Added `on_missing` and `on_conflict` arguments to `Toys::Utils::Gems` constructor (which also affects the `:gems` mixin), and deprecated `suppress_confirm` and `default_confirm`.
|
32
|
+
* CHANGED: Tightened `rdoc` template's default gem version to `~> 6.1.0`.
|
33
|
+
* FIXED: `rdoc` template crashed if any nonstandard options were given.
|
34
|
+
* FIXED: `rubocop` template would abort prematurely if standard streams were redirected.
|
35
|
+
|
3
36
|
### 0.9.4 / 2020-01-26
|
4
37
|
|
5
38
|
* FIXED: Crash in the loader when a non-ruby file appears in a toys directory
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -91,7 +91,7 @@ automatically generates a full help screen, which you can view using the
|
|
91
91
|
Toys searches up the directory hierarchy for Toys files. So it will find this
|
92
92
|
`.toys.rb` if you are located in this directory or any subdirectory. It will
|
93
93
|
also read multiple files if it finds them, so you can "scope" your tools more
|
94
|
-
specifically or generally by locating them in your directory hierarchy.
|
94
|
+
specifically or generally by locating them in your directory hierarchy.
|
95
95
|
|
96
96
|
If you want to define "global" tools that apply anywhere, write a Toys file
|
97
97
|
either in your home directory, or in the system configuration directory
|
@@ -204,7 +204,7 @@ You'll notice some diagnostic log output. Toys provides a standard Ruby Logger
|
|
204
204
|
for each tool, and you can use it to emit diagnostic logs directly as
|
205
205
|
demonstrated in the example. Some other Toys features might also emit log
|
206
206
|
entries: the `:exec` mixin, for example, by default logs every external command
|
207
|
-
it runs (although this can be customized).
|
207
|
+
it runs (although this can be customized).
|
208
208
|
|
209
209
|
By default, only warnings and higher severity logs are displayed, but you can
|
210
210
|
change that by applying the `--verbose` or `--quiet` flags as we have done
|
@@ -318,7 +318,7 @@ Toys scripts instead of Rakefiles.
|
|
318
318
|
|
319
319
|
## License
|
320
320
|
|
321
|
-
Copyright 2019 Daniel Azuma
|
321
|
+
Copyright 2019-2020 Daniel Azuma and the Toys contributors
|
322
322
|
|
323
323
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
324
324
|
of this software and associated documentation files (the "Software"), to deal
|
data/bin/toys
CHANGED
@@ -1,30 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
# Copyright 2019 Daniel Azuma
|
5
|
-
#
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
# of this software and associated documentation files (the "Software"), to deal
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
11
|
-
# furnished to do so, subject to the following conditions:
|
12
|
-
#
|
13
|
-
# The above copyright notice and this permission notice shall be included in
|
14
|
-
# all copies or substantial portions of the Software.
|
15
|
-
#
|
16
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
22
|
-
# IN THE SOFTWARE.
|
23
|
-
;
|
24
|
-
|
25
4
|
::ENV["TOYS_BIN_PATH"] ||= ::File.absolute_path(__FILE__)
|
5
|
+
::ENV["TOYS_LIB_PATH"] ||= ::File.absolute_path(::File.join(::File.dirname(__dir__), "lib"))
|
26
6
|
|
27
|
-
$LOAD_PATH.
|
7
|
+
$LOAD_PATH.delete(::ENV["TOYS_LIB_PATH"])
|
8
|
+
$LOAD_PATH.unshift(::ENV["TOYS_LIB_PATH"])
|
28
9
|
require "toys"
|
29
10
|
|
30
11
|
exit(::Toys::StandardCLI.new.run(::ARGV))
|
data/builtins/do.rb
CHANGED
@@ -1,25 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
|
23
3
|
desc "Run multiple tools in order"
|
24
4
|
|
25
5
|
long_desc \
|
data/builtins/system.rb
CHANGED
@@ -1,25 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
|
23
3
|
desc "A set of system commands for Toys"
|
24
4
|
|
25
5
|
long_desc "Contains tools that inspect, configure, and update Toys itself."
|
@@ -44,6 +24,7 @@ tool "update" do
|
|
44
24
|
include :terminal
|
45
25
|
|
46
26
|
def run
|
27
|
+
require "rubygems"
|
47
28
|
configure_exec(exit_on_nonzero_status: true)
|
48
29
|
version_info = spinner(leading_text: "Checking rubygems for the latest release... ",
|
49
30
|
final_text: "Done.\n") do
|
data/docs/guide.md
CHANGED
@@ -1698,7 +1698,7 @@ the module.
|
|
1698
1698
|
|
1699
1699
|
### Templates
|
1700
1700
|
|
1701
|
-
|
1701
|
+
Another way to share code is to expand a **template**.
|
1702
1702
|
|
1703
1703
|
A template is a class that inserts a bunch of lines into a Toys file. It is
|
1704
1704
|
often used to "instantiate" prefabricated tools. For instance, Toys comes with
|
@@ -1841,15 +1841,102 @@ following in their Toys file:
|
|
1841
1841
|
require "my_analysis"
|
1842
1842
|
expand MyAnalysis::ToysTemplate
|
1843
1843
|
|
1844
|
-
###
|
1844
|
+
### Loading from a lib directory
|
1845
1845
|
|
1846
1846
|
For more complicated tools, you might want to write normal Ruby modules and
|
1847
1847
|
classes as helpers. Toys provides a way to write Ruby code outside of its DSL
|
1848
|
-
and
|
1848
|
+
and `require` the code from your tool, using `.lib` directories.
|
1849
|
+
|
1850
|
+
To use `.lib` directories, you must define your tools inside a
|
1851
|
+
[Toys directory](#Toys_directories). When a tool is executed, it looks for
|
1852
|
+
directories called `.lib` in the Toys directory, and adds them to the Ruby load
|
1853
|
+
path. Your tool can thus call `require` to load helpers from any Ruby files in
|
1854
|
+
a `.lib` directory.
|
1855
|
+
|
1856
|
+
For example, take the following directory structure:
|
1857
|
+
|
1858
|
+
(current directory)
|
1859
|
+
|
|
1860
|
+
+- .toys/
|
1861
|
+
|
|
1862
|
+
+- .lib/ <-- available when a tool is executed
|
1863
|
+
| |
|
1864
|
+
| +- greeting_helper.rb
|
1865
|
+
|
|
1866
|
+
+- greet.rb
|
1867
|
+
|
1868
|
+
The `greeting_helper.rb` file can contain any Ruby code.
|
1869
|
+
|
1870
|
+
# .toys/.lib/greeting_helper.rb
|
1871
|
+
|
1872
|
+
module GreetingHelper
|
1873
|
+
def self.make_greeting(whom)
|
1874
|
+
"Hello, #{whom}!"
|
1875
|
+
end
|
1876
|
+
end
|
1877
|
+
|
1878
|
+
Now you can `require "greeting_helper"` in your `greet` tool.
|
1879
|
+
|
1880
|
+
# .toys/greet.rb
|
1881
|
+
|
1882
|
+
tool "greet" do
|
1883
|
+
optional_arg :whom, default: "world", desc: "Whom to greet."
|
1884
|
+
def run
|
1885
|
+
require "greeting_helper"
|
1886
|
+
puts GreetingHelper.make_greeting(whom)
|
1887
|
+
end
|
1888
|
+
end
|
1889
|
+
|
1890
|
+
Note that `.lib` directories are available only when your tool is being *run*,
|
1891
|
+
not when it is being defined. So any `require` statements should be located
|
1892
|
+
*inside* your `run` method.
|
1893
|
+
|
1894
|
+
tool "greet" do
|
1895
|
+
# Do not try to require the file here. Toys will not find it because
|
1896
|
+
# the tool is not yet being run.
|
1897
|
+
# require "greeting_helper" # ERRORS!
|
1898
|
+
|
1899
|
+
optional_arg :whom, default: "world", desc: "Whom to greet."
|
1900
|
+
def run
|
1901
|
+
# Require a helper file here, so it is loaded during tool execution.
|
1902
|
+
require "greeting_helper"
|
1903
|
+
# Now you can use classes defined in the helper
|
1904
|
+
puts GreetingHelper.make_greeting(whom)
|
1905
|
+
end
|
1906
|
+
end
|
1907
|
+
|
1908
|
+
If your Toys directory has subdirectories, lib directories will be prioritized
|
1909
|
+
by how close they are to the tool being executed. For example:
|
1910
|
+
|
1911
|
+
(current directory)
|
1912
|
+
|
|
1913
|
+
+- .toys/
|
1914
|
+
|
|
1915
|
+
+- .lib/ <-- available when any tool defined in this directory
|
1916
|
+
| | is executed
|
1917
|
+
| |
|
1918
|
+
| +- helper.rb <-- visible to "greet" but not "test unit"
|
1919
|
+
| |
|
1920
|
+
| +- helper2.rb <-- visible to both "greet" and "test unit"
|
1921
|
+
|
|
1922
|
+
+- greet.rb
|
1923
|
+
|
|
1924
|
+
+- test/
|
1925
|
+
|
|
1926
|
+
+- .lib/ <-- available only when tools under "test" are executed
|
1927
|
+
| |
|
1928
|
+
| +- helper.rb <-- overrides the other helper.rb when
|
1929
|
+
| "test unit" is executed
|
1930
|
+
|
|
1931
|
+
+- unit.rb
|
1932
|
+
|
1933
|
+
### Preloading Ruby files
|
1849
1934
|
|
1850
|
-
|
1851
|
-
|
1852
|
-
|
1935
|
+
You may also provide Ruby files that are "preloaded" before tools are defined.
|
1936
|
+
This is useful if those Ruby files are required by the tool definitions
|
1937
|
+
themselves. Like files in the `.lib` directory, preloaded files can define Ruby
|
1938
|
+
classes, modules, and other code. But preloaded files *automatically* loaded
|
1939
|
+
(i.e. you do not `require` them explicitly) *before* your tools are defined.
|
1853
1940
|
|
1854
1941
|
To use preloaded files, you must define your tools inside a
|
1855
1942
|
[Toys directory](#Toys_directories). Before any tools inside a directory are
|
@@ -1899,58 +1986,174 @@ loaded first before the `.preload` directory contents.
|
|
1899
1986
|
|
1900
1987
|
## Using third-party gems
|
1901
1988
|
|
1902
|
-
The
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1989
|
+
The toys executable itself uses only two gems: **toys** and **toys-core**. It
|
1990
|
+
has no other gem dependencies. However, the Ruby community has developed many
|
1991
|
+
resources for building command line tools, including a variety of gems that
|
1992
|
+
provide alternate command line parsing, control of the ANSI terminal, formatted
|
1993
|
+
output such as trees and tables, and effects such as hidden input, progress
|
1994
|
+
bars, various ways to spawn and control subprocesses, and so forth. You may
|
1995
|
+
find some of these gems useful when writing your tools. Additionally, if you
|
1996
|
+
are using Toys for your project's build scripts, it might be necessary to
|
1997
|
+
install your bundle when running some tools.
|
1907
1998
|
|
1908
|
-
This section describes how to use
|
1999
|
+
This section describes how to manage and use external gems with Toys. Note that
|
2000
|
+
running Toys with `bundle exec` is generally *not* recommended. We'll discuss
|
2001
|
+
the reasons for this, and what you can do instead.
|
1909
2002
|
|
1910
|
-
###
|
2003
|
+
### Why not "bundle exec toys"
|
1911
2004
|
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
|
1935
|
-
|
2005
|
+
[Bundler](https://bundler.io) is often used when a command-line program depends
|
2006
|
+
on external gems. You specify the gem dependencies in a `Gemfile`, use bundler
|
2007
|
+
to resolve and install those dependencies, and then run the program prefixed by
|
2008
|
+
`bundle exec` to ensure those dependencies are in the Ruby load path. When
|
2009
|
+
running a Rake task, for example, it is almost automatic for many Ruby
|
2010
|
+
developers to run `bundle exec rake my-task`.
|
2011
|
+
|
2012
|
+
So why not simply run `bundle exec toys my-tool`?
|
2013
|
+
|
2014
|
+
In simple cases, this will work just fine. However, Toys is a much more
|
2015
|
+
flexible tool than Rake, and it covers two cases that are not well served by
|
2016
|
+
`bundle exec`.
|
2017
|
+
|
2018
|
+
First, Toys lets you define *global tools* that are defined in your home
|
2019
|
+
directory or system config directory. (See the previous section on
|
2020
|
+
[the Toys search path](#The_Toys_search_path).) These tools are global, and can
|
2021
|
+
be called from anywhere. But if they have gem dependencies, it might not be
|
2022
|
+
feasible for their Gemfiles to be present in every directory from which you
|
2023
|
+
might want to run them.
|
2024
|
+
|
2025
|
+
Second, it's possible for a variety of tools to be available together,
|
2026
|
+
including both locally and globally defined, with potentially different sets of
|
2027
|
+
dependencies. With `bundle exec`, you must choose beforehand which bundle to
|
2028
|
+
use.
|
2029
|
+
|
2030
|
+
Although traditional `bundle exec` doesn't always work, Toys provides ways for
|
2031
|
+
individual tools to manage their own gem dependencies.
|
2032
|
+
|
2033
|
+
### Using bundler with a tool
|
2034
|
+
|
2035
|
+
The recommended way for a Toys tool to depend on third-party gems is for the
|
2036
|
+
tool to set up Bundler when it runs. The tool can load a bundle from an
|
2037
|
+
appropriate `Gemfile` at runtime, by including the `:bundler` mixin.
|
2038
|
+
|
2039
|
+
Here's an example. Suppose you are writing a tool in a Rails app. It might, for
|
2040
|
+
example, load the Rails environment and populate some data into the database.
|
2041
|
+
Hence, it needs to run with your app's bundle, represented by your app's
|
2042
|
+
`Gemfile`.
|
2043
|
+
|
2044
|
+
Simply `include :bundler` in your tool definition:
|
2045
|
+
|
2046
|
+
tool "populate-data" do
|
2047
|
+
include :bundler
|
1936
2048
|
|
1937
|
-
tool "highline-styles-demo" do
|
1938
|
-
include :gems
|
1939
|
-
gem "highline", "~> 2.0"
|
1940
|
-
require "highline"
|
1941
|
-
HighLine::BuiltinStyles::STYLES.each do |style|
|
1942
|
-
style = style.downcase
|
1943
|
-
flag style.to_sym, "--#{style}", "Apply #{style} to the text"
|
1944
|
-
end
|
1945
2049
|
def run
|
1946
|
-
#
|
2050
|
+
# The bundle will be set up before the tool is run,
|
2051
|
+
# so you can now run code that depends on rails:
|
2052
|
+
require "./config/environment.rb"
|
2053
|
+
# ... etc.
|
1947
2054
|
end
|
1948
2055
|
end
|
1949
2056
|
|
2057
|
+
When the `:bundler` mixin is included in a tool, it installs a
|
2058
|
+
[mixin initializer](#Mixin_initializers) that calls `Bundler.setup` when the
|
2059
|
+
tool is *executed*. This assumes the bundle is already installed, and brings
|
2060
|
+
the appropriate gems into the Ruby load path. That is, it's basically the same
|
2061
|
+
as `bundle exec`, but it applies only to the running tool.
|
2062
|
+
|
2063
|
+
In many cases, you might find that bundler is needed for many or most of the
|
2064
|
+
tools you write for a particular project. In this case, you might find it
|
2065
|
+
convenient to use
|
2066
|
+
[Toys::DSL::Tool#subtool_apply](https://dazuma.github.io/toys/gems/toys-core/latest/Toys/DSL/Tool#subtool_apply-instance_method)
|
2067
|
+
to include the bundle in all your tools. For example:
|
2068
|
+
|
2069
|
+
# Include bundler in every tool under this one
|
2070
|
+
subtool_apply do
|
2071
|
+
include :bundler
|
2072
|
+
end
|
2073
|
+
|
2074
|
+
tool "one-tool" do
|
2075
|
+
# This tool will run with the bundle
|
2076
|
+
# ...
|
2077
|
+
end
|
2078
|
+
|
2079
|
+
tool "another-tool" do
|
2080
|
+
# So will this tool
|
2081
|
+
# ...
|
2082
|
+
end
|
2083
|
+
|
2084
|
+
See the section on
|
2085
|
+
[applying directives to multiple tools](#Applying_directives_to_multiple_tools)
|
2086
|
+
for more information on `subtool_apply`.
|
2087
|
+
|
2088
|
+
#### Bundler options
|
2089
|
+
|
2090
|
+
By default, the `:bundler` mixin will look for a `Gemfile` within the `.toys`
|
2091
|
+
directory (if your tool is defined in one), and if one is not found there,
|
2092
|
+
within the [context directory](#The_context_directory) (the directory
|
2093
|
+
containing your `.toys` directory or `.toys.rb`file), and if one still is not
|
2094
|
+
found, in the current working directory. You can change this behavior by
|
2095
|
+
passing an option to the `:bundler` mixin. For example, you can search only the
|
2096
|
+
current working directory by passing `search_dirs: :current` as such:
|
2097
|
+
|
2098
|
+
tool "populate-data" do
|
2099
|
+
include :bundler, search_dirs: :current
|
2100
|
+
# etc...
|
2101
|
+
end
|
2102
|
+
|
2103
|
+
You can also pass a specific directory path to this option.
|
2104
|
+
|
2105
|
+
If the bundle is not installed, or is out of date, Toys will ask you whether
|
2106
|
+
you want it to install the bundle first before running the tool. A tool can
|
2107
|
+
also choose to install the bundle without prompting, or simply to raise an
|
2108
|
+
error, by passing another option to the `:bundler` mixin. For example, to
|
2109
|
+
simply install the bundle without asking for confirmation:
|
2110
|
+
|
2111
|
+
tool "populate-data" do
|
2112
|
+
include :bundler, on_missing: :install
|
2113
|
+
# etc...
|
2114
|
+
end
|
2115
|
+
|
2116
|
+
See the documentation for
|
2117
|
+
[Toys::StandardMixins::Bundler](https://dazuma.github.io/toys/gems/toys-core/latest/Toys/StandardMixins/Bundler)
|
2118
|
+
for more information about bundler options.
|
2119
|
+
|
2120
|
+
#### Solving bundle conflicts
|
2121
|
+
|
2122
|
+
It is important to understand that the `:bundler` mixin installs the bundle
|
2123
|
+
when the tool *executes*, rather than when the tool is defined. Gems in the
|
2124
|
+
bundle will not be available during tool definition, so for example you
|
2125
|
+
*cannot* reference bundled gems when you are setting up the tool's flags,
|
2126
|
+
description, or other directives. This is so that Toys can define tools with
|
2127
|
+
competing bundles. Your Rails app's tools can use that app's bundle, while your
|
2128
|
+
global tools can use a different bundle. They will not conflict because Toys
|
2129
|
+
will not actually load a bundle until one or the other tool is executed. (This
|
2130
|
+
is of course different from using `bundle exec`, which chooses and loads a
|
2131
|
+
bundle before even starting Toys.)
|
2132
|
+
|
2133
|
+
If a *different* bundle (i.e. a different `Gemfile`) is already in effect when
|
2134
|
+
a tool is run, then the `:bundler` mixin will raise an error. Ruby will not let
|
2135
|
+
you set up two different bundles at the same time. This might happen, for
|
2136
|
+
example, if you use `bundle exec` to run Toys, but the tool you are running
|
2137
|
+
asks for a different bundle---one more reason not to use `bundle exec` with
|
2138
|
+
Toys.
|
2139
|
+
|
2140
|
+
It might also happen if one tool that uses one bundle, *calls* a tool that uses
|
2141
|
+
a different bundle. If you need to do this, use the
|
2142
|
+
[Toys::StandardMixins::Exec#exec_separate_tool](https://dazuma.github.io/toys/gems/toys-core/latest/Toys/StandardMixins/Exec#exec_separate_tool-instance_method)
|
2143
|
+
method from the `:exec` mixin, to call the tool. This method spawns a separate
|
2144
|
+
process with a clean Bundler setup for running the tool.
|
2145
|
+
|
2146
|
+
### Activating gems directly
|
2147
|
+
|
2148
|
+
Although we recommend the `:bundler` mixin for most cases, it is also possible
|
2149
|
+
for a tool to install individual gems, using the `:gems` mixin. This mixin
|
2150
|
+
provides a way for a tool to install individual gems without using Bundler.
|
2151
|
+
|
1950
2152
|
Here's an example tool that just runs `rake`. Because it requires rake to be
|
1951
|
-
installed in order to
|
2153
|
+
installed in order to run the tool, we call the
|
1952
2154
|
[Toys::StandardMixins::Gems#gem](https://dazuma.github.io/toys/gems/toys-core/latest/Toys/StandardMixins/Gems#gem-instance_method)
|
1953
|
-
method provided by the `:gems` mixin
|
2155
|
+
method (which is provided by the `:gems` mixin) at the beginning of the `run`
|
2156
|
+
method:
|
1954
2157
|
|
1955
2158
|
tool "rake" do
|
1956
2159
|
include :gems
|
@@ -1961,10 +2164,39 @@ method provided by the `:gems` mixin when running.
|
|
1961
2164
|
end
|
1962
2165
|
end
|
1963
2166
|
|
2167
|
+
The `gem` method takes the name of the gem, and an optional set of version
|
2168
|
+
requirements. If a gem matching the given version requirements is installed, it
|
2169
|
+
is activated. If not, the gem is installed (which the user can confirm or
|
2170
|
+
abort). Or, if Toys is being run in a bundle, a message is printed informing
|
2171
|
+
the user that they need to add the gem to their Gemfile.
|
2172
|
+
|
1964
2173
|
If a gem satisfying the given version constraints is already activated, it
|
1965
2174
|
remains active. If a gem with a conflicting version is already activated, an
|
1966
2175
|
exception is raised.
|
1967
2176
|
|
2177
|
+
The `:gems` mixin also provides a `gem` *directive* that ensures a gem is
|
2178
|
+
installed while the tool is being defined. In general, we recommend avoiding
|
2179
|
+
doing this, because it could make your tool incompatible with another tool that
|
2180
|
+
might need a competing gem during its definition. Toys would not be able to
|
2181
|
+
define both tools together. However, occasionally it might be useful.
|
2182
|
+
|
2183
|
+
Here's an example tool with flags for each of the HighLine styles. Because
|
2184
|
+
highline is needed to decide what flags to define, we use the `gem` directive
|
2185
|
+
to ensure highline is installed while the tool is being defined.
|
2186
|
+
|
2187
|
+
tool "highline-styles-demo" do
|
2188
|
+
include :gems
|
2189
|
+
gem "highline", "~> 2.0"
|
2190
|
+
require "highline"
|
2191
|
+
HighLine::BuiltinStyles::STYLES.each do |style|
|
2192
|
+
style = style.downcase
|
2193
|
+
flag style.to_sym, "--#{style}", "Apply #{style} to the text"
|
2194
|
+
end
|
2195
|
+
def run
|
2196
|
+
# ...
|
2197
|
+
end
|
2198
|
+
end
|
2199
|
+
|
1968
2200
|
If you are not in the Toys DSL context—for example from a class-based
|
1969
2201
|
mixin—you should use
|
1970
2202
|
[Toys::Utils::Gems.activate](https://dazuma.github.io/toys/gems/toys-core/latest/Toys/Utils/Gems#activate-class_method)
|
@@ -1984,8 +2216,9 @@ you, whereas Rubygems will just throw an exception.
|
|
1984
2216
|
|
1985
2217
|
### Useful gems
|
1986
2218
|
|
1987
|
-
Now that you know how to ensure a gem is installed,
|
1988
|
-
party gems that you might find
|
2219
|
+
Now that you know how to ensure a gem is installed, either individually or as
|
2220
|
+
part of a bundle, let's look at some third-party gems that you might find
|
2221
|
+
useful when writing tools.
|
1989
2222
|
|
1990
2223
|
We already saw how to use the **highline** gem. Highline generally provides two
|
1991
2224
|
features: terminal styling, and prompts. For these capabilities and many more,
|
@@ -1998,7 +2231,6 @@ To produce styled output, consider
|
|
1998
2231
|
|
1999
2232
|
tool "fancy-output" do
|
2000
2233
|
def run
|
2001
|
-
gem "pastel", "~> 0.7"
|
2002
2234
|
require "pastel"
|
2003
2235
|
pastel = Pastel.new
|
2004
2236
|
puts pastel.red("Rubies!")
|
@@ -2010,7 +2242,6 @@ To create rich user prompts, consider
|
|
2010
2242
|
|
2011
2243
|
tool "favorite-language" do
|
2012
2244
|
def run
|
2013
|
-
gem "tty-prompt", "~> 0.16"
|
2014
2245
|
require "tty-prompt"
|
2015
2246
|
prompt = TTY::Prompt.new
|
2016
2247
|
lang = prompt.select("What is your favorite language?",
|
@@ -2024,7 +2255,6 @@ To create tabular output, consider
|
|
2024
2255
|
|
2025
2256
|
tool "matrix" do
|
2026
2257
|
def run
|
2027
|
-
gem "tty-table", "~> 0.10"
|
2028
2258
|
require "tty-table"
|
2029
2259
|
table = TTY::Table.new(["Language", "Creator"],
|
2030
2260
|
[["Ruby", "Matz"],
|
@@ -2042,7 +2272,6 @@ non-deterministic.
|
|
2042
2272
|
|
2043
2273
|
tool "waiting" do
|
2044
2274
|
def run
|
2045
|
-
gem "tty-progressbar", "~> 0.15"
|
2046
2275
|
require "tty-progressbar"
|
2047
2276
|
bar = TTY::ProgressBar.new("Waiting [:bar]", total: 30)
|
2048
2277
|
30.times do
|
@@ -2418,6 +2647,52 @@ a namespace to delegate to one of its subtools:
|
|
2418
2647
|
|
2419
2648
|
Now `toys test` delegates to, and thus has the same effect as `toys test unit`.
|
2420
2649
|
|
2650
|
+
### Applying directives to multiple tools
|
2651
|
+
|
2652
|
+
Sometimes a group of tools are set up similarly or share a set of flags,
|
2653
|
+
mixins, or other directives. You can apply a set of directives to all subtools
|
2654
|
+
(recursively) of the current tool, using the
|
2655
|
+
[Toys::DSL::Tool#subtool_apply](https://dazuma.github.io/toys/gems/toys-core/latest/Toys/DSL/Tool#subtool_apply-instance_method)
|
2656
|
+
directive.
|
2657
|
+
|
2658
|
+
For example, it is common for tools to use the `:exec` built-in mixin to invoke
|
2659
|
+
external programs. You can use `subtool_apply` to ensure that the mixin is
|
2660
|
+
included in all subtools, so that you do not need to repeat the `include`
|
2661
|
+
directive in every tool.
|
2662
|
+
|
2663
|
+
subtool_apply do
|
2664
|
+
# Include the mixin only if the tool hasn't already done so
|
2665
|
+
unless include?(:exec)
|
2666
|
+
include :exec, exit_on_nonzero_status: true
|
2667
|
+
end
|
2668
|
+
end
|
2669
|
+
|
2670
|
+
tool "my-tool" do
|
2671
|
+
def run
|
2672
|
+
# This tool has access to methods defined by the :exec mixin
|
2673
|
+
# because the above block is applied to the tool
|
2674
|
+
sh "echo hello"
|
2675
|
+
end
|
2676
|
+
end
|
2677
|
+
|
2678
|
+
Importantly, `subtool_apply` blocks are "applied" at the *end* of a tool's
|
2679
|
+
definition. Therefore, when using `subtool_apply`, you have the ability to look
|
2680
|
+
at the current definition of the tool to decide whether to apply further
|
2681
|
+
changes. The `subtool_apply` block in the above example uses this technique; it
|
2682
|
+
checks whether the `:exec` mixin has already been included before attempting to
|
2683
|
+
include it. Thus, it is possible for a tool to "override" the inclusion, say,
|
2684
|
+
to use a different configuration:
|
2685
|
+
|
2686
|
+
tool "another-tool" do
|
2687
|
+
# Use a different configuration for the :exec mixin.
|
2688
|
+
# This "overrides" the subtool_apply block above.
|
2689
|
+
include :exec, exit_on_nonzero_status: false
|
2690
|
+
def run
|
2691
|
+
# This is run with exit_on_nonzero_status: false
|
2692
|
+
sh "echo hello"
|
2693
|
+
end
|
2694
|
+
end
|
2695
|
+
|
2421
2696
|
### Custom acceptors
|
2422
2697
|
|
2423
2698
|
We saw earlier that flags and positional arguments can have acceptors, which
|
@@ -2827,8 +3102,8 @@ subdirectory:
|
|
2827
3102
|
|
2828
3103
|
Rake handles this by actually changing the current working directory to the
|
2829
3104
|
directory containing the active Rakefile. Toys, however, does not change the
|
2830
|
-
working directory unless you tell it. You can make the `list-tests` tool
|
2831
|
-
correctly by changing the directory to the context directory (which is the
|
3105
|
+
working directory unless you tell it to. You can make the `list-tests` tool
|
3106
|
+
work correctly by changing the directory to the context directory (which is the
|
2832
3107
|
directory containing the `.toys.rb` file, i.e. the `my-project` directory.)
|
2833
3108
|
|
2834
3109
|
tool "list-tests" do
|
@@ -2856,7 +3131,7 @@ the entire toys directory structure. So if your tool definition is inside a
|
|
2856
3131
|
|
|
2857
3132
|
etc...
|
2858
3133
|
|
2859
|
-
This
|
3134
|
+
This technique is particularly useful for build tools. Indeed, all the build
|
2860
3135
|
tools described in the section on
|
2861
3136
|
[Toys as a Rake Replacement](#Toys_as_a_Rake_replacement) automatically move
|
2862
3137
|
into the context directory when they execute.
|