toys-core 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 87e34f50eb16af11bc970c170e7750509e026b237ec37352be05198860bfdeae
4
+ data.tar.gz: 6bdaeaa6577d75c25b0efd17406792c24e3f6dd57326a52badd60495dc9170cc
5
+ SHA512:
6
+ metadata.gz: ee18128015b86041547bcdab1e7ec4bea05a41e0eff06c30a4003f032cc1ca335c7e7b593236ea140e65f43b4f31a752ceee5c57c787227b88d3144eac22b147
7
+ data.tar.gz: e4c7b13f825d6b4131db5e08a56a306652e2f532de1095758fde3be3fe509635629cc7725241b4bd3206ce1b414ed0cc4bd09aa480bbe4f335e8b3abd4ffc7c7
@@ -0,0 +1,9 @@
1
+ --no-private
2
+ --title=Toys Core
3
+ --markup=markdown
4
+ --main=README.md
5
+ ./lib/**/*.rb
6
+ -
7
+ README.md
8
+ LICENSE.md
9
+ CHANGELOG.md
@@ -0,0 +1,21 @@
1
+ # Release History
2
+
3
+ ### 0.3.2 / 2018-05-07
4
+
5
+ * CHANGED: Split core engine out into "toys-core" from the "toys" gem.
6
+ * CHANGED: Renamed path types to "search" and "config" paths, and restricted the former to the CLI.
7
+ * CHANGED: Removed aliasing from the Tool interface and reimplemented in the Loader.
8
+ * CHANGED: Default descriptions are now set via a middleware rather than in the Tool.
9
+ * CHANGED: Renamed most of the middleware classes.
10
+ * CHANGED: Combined usage-displaying middleware.
11
+ * CHANGED: Standard paths logic moved from CLI to StandardCLI.
12
+ * ADDED: Middleware that responds to the "--version" switch.
13
+ * ADDED: Context#new_cli that lets you run sub-instances of toys.
14
+ * IMPROVED: Middleware can now be referenced by class and constructed implicitly.
15
+ * IMPROVED: Usage error handler can now have its exit code configured.
16
+ * IMPROVED: Help and verbosity middlewares can have their switches configured.
17
+ * IMPROVED: Help middleware can search for keywords in subcommands.
18
+ * IMPROVED: Help middleware displays the config path in verbose mode.
19
+ * IMPROVED: Context::EXIT_ON_NONZERO_STATUS controls Context#run behavior.
20
+ * DOCS: Expanded middleware documentation
21
+ * INTERNAL: Removed Context::Base and just used CLI as base context
@@ -0,0 +1,29 @@
1
+ # License
2
+
3
+ Copyright 2018 Daniel Azuma
4
+
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ * Redistributions of source code must retain the above copyright notice,
11
+ this list of conditions and the following disclaimer.
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+ * Neither the name of the copyright holder, nor the names of any other
16
+ contributors to this software, may be used to endorse or promote products
17
+ derived from this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,30 @@
1
+ # Toys
2
+
3
+ Toys is a command line binary that lets you build your own suite of command
4
+ line tools (with commands and subcommands) using a Ruby DSL. Commands can be
5
+ defined globally or scoped to directories.
6
+
7
+ Toys-Core is the command line tool framework underlying Toys. It can be used
8
+ to create command line binaries using the Toys DSL.
9
+
10
+ ## Quick Start
11
+
12
+ (TODO)
13
+
14
+ ## Contributing
15
+
16
+ While we appreciate contributions, please note that this software is currently
17
+ highly experimental, and the code is evolving very rapidly. Please contact the
18
+ author before embarking on a major pull request. More detailed contribution
19
+ guidelines will be provided when the software stabilizes further.
20
+
21
+ The source can be found on Github at
22
+ [https://github.com/dazuma/toys](https://github.com/dazuma/toys)
23
+
24
+ ## License
25
+
26
+ Copyright 2018 Daniel Azuma
27
+
28
+ This software is licensed under the 3-clause BSD license.
29
+
30
+ See the LICENSE.md file for more information.
@@ -0,0 +1,54 @@
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
+ ##
31
+ # Toys is a Ruby library and command line tool that lets you build your own
32
+ # command line suite of tools (with commands and subcommands) using a Ruby DSL.
33
+ # You can define commands globally or configure special commands scoped to
34
+ # individual directories.
35
+ #
36
+ module Toys
37
+ ##
38
+ # Namespace for common utility classes.
39
+ #
40
+ module Utils; end
41
+ end
42
+
43
+ require "toys/alias"
44
+ require "toys/cli"
45
+ require "toys/config_dsl"
46
+ require "toys/context"
47
+ require "toys/core_version"
48
+ require "toys/errors"
49
+ require "toys/helpers"
50
+ require "toys/loader"
51
+ require "toys/middleware"
52
+ require "toys/template"
53
+ require "toys/templates"
54
+ require "toys/tool"
@@ -0,0 +1,94 @@
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
+ module Toys
31
+ ##
32
+ # An alias is a name that refers to another name.
33
+ #
34
+ class Alias
35
+ ##
36
+ # Create a new alias.
37
+ #
38
+ # @param [Array<String>] full_name The name of the alias.
39
+ # @param [String,Array<String>] target The name of the target. May either
40
+ # be a local reference (a single string) or a global reference (an
41
+ # array of strings)
42
+ #
43
+ def initialize(full_name, target)
44
+ @target_name =
45
+ if target.is_a?(::String)
46
+ full_name[0..-2] + [target]
47
+ else
48
+ target.dup
49
+ end
50
+ @target_name.freeze
51
+ @full_name = full_name.dup.freeze
52
+ end
53
+
54
+ ##
55
+ # Return the name of the tool as an array of strings.
56
+ # This array may not be modified.
57
+ # @return [Array<String>]
58
+ #
59
+ attr_reader :full_name
60
+
61
+ ##
62
+ # Return the name of the target as an array of strings.
63
+ # This array may not be modified.
64
+ # @return [Array<String>]
65
+ #
66
+ attr_reader :target_name
67
+
68
+ ##
69
+ # Returns the local name of this tool.
70
+ # @return [String]
71
+ #
72
+ def simple_name
73
+ full_name.last
74
+ end
75
+
76
+ ##
77
+ # Returns a displayable name of this tool, generally the full name
78
+ # delimited by spaces.
79
+ # @return [String]
80
+ #
81
+ def display_name
82
+ full_name.join(" ")
83
+ end
84
+
85
+ ##
86
+ # Returns a displayable name of the target, generally the full name
87
+ # delimited by spaces.
88
+ # @return [String]
89
+ #
90
+ def display_target
91
+ target_name.join(" ")
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,268 @@
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
+ # A Toys-based CLI.
35
+ #
36
+ # Use this class to implement a CLI using Toys.
37
+ #
38
+ class CLI
39
+ ##
40
+ # Create a CLI
41
+ #
42
+ # @param [String,nil] binary_name The binary name displayed in help text.
43
+ # Optional. Defaults to the ruby program name.
44
+ # @param [String,nil] config_dir_name A directory with this name that
45
+ # appears in the loader path, is treated as a configuration directory
46
+ # whose contents are loaded into the toys configuration. Optional.
47
+ # If not provided, toplevel configuration directories are disabled.
48
+ # The default toys CLI sets this to `".toys"`.
49
+ # @param [String,nil] config_file_name A file with this name that appears
50
+ # in the loader path, is treated as a toplevel configuration file
51
+ # whose contents are loaded into the toys configuration. Optional.
52
+ # If not provided, toplevel configuration files are disabled.
53
+ # The default toys CLI sets this to `".toys.rb"`.
54
+ # @param [String,nil] index_file_name A file with this name that appears
55
+ # in any configuration directory (not just a toplevel directory) is
56
+ # loaded first as a standalone configuration file. If not provided,
57
+ # standalone configuration files are disabled.
58
+ # The default toys CLI sets this to `".toys.rb"`.
59
+ # @param [String,nil] preload_file_name A file with this name that appears
60
+ # in any configuration directory (not just a toplevel directory) is
61
+ # loaded before any configuration files. It is not treated as a
62
+ # configuration file in that the configuration DSL is not honored. You
63
+ # may use such a file to define auxiliary Ruby modules and classes that
64
+ # used by the tools defined in that directory.
65
+ # @param [Array] middleware_stack An array of middleware that will be used
66
+ # by default for all tools loaded by this CLI.
67
+ # @param [Logger,nil] logger The logger to use. If not provided, a default
68
+ # logger that writes to `STDERR` is used.
69
+ # @param [Integer,nil] base_level The logger level that should correspond
70
+ # to zero verbosity. If not provided, will default to the current level
71
+ # of the logger.
72
+ #
73
+ def initialize(
74
+ binary_name: nil,
75
+ config_dir_name: nil,
76
+ config_file_name: nil,
77
+ index_file_name: nil,
78
+ preload_file_name: nil,
79
+ middleware_stack: nil,
80
+ logger: nil,
81
+ base_level: nil
82
+ )
83
+ @logger = logger || self.class.default_logger
84
+ @base_level = base_level || @logger.level
85
+ @middleware_stack = middleware_stack || self.class.default_middleware_stack
86
+ @binary_name = binary_name || ::File.basename($PROGRAM_NAME)
87
+ @config_dir_name = config_dir_name
88
+ @config_file_name = config_file_name
89
+ @index_file_name = index_file_name
90
+ @preload_file_name = preload_file_name
91
+ @loader = Loader.new(
92
+ index_file_name: index_file_name,
93
+ preload_file_name: preload_file_name,
94
+ middleware_stack: middleware_stack
95
+ )
96
+ end
97
+
98
+ ##
99
+ # Return the current loader for this CLI
100
+ # @return [Toys::Loader]
101
+ #
102
+ attr_reader :loader
103
+
104
+ ##
105
+ # Return the effective binary name used for usage text in this CLI
106
+ # @return [String]
107
+ #
108
+ attr_reader :binary_name
109
+
110
+ ##
111
+ # Return the logger used by this CLI
112
+ # @return [Logger]
113
+ #
114
+ attr_reader :logger
115
+
116
+ ##
117
+ # Return the initial logger level in this CLI, used as the level for
118
+ # verbosity 0.
119
+ # @return [Integer]
120
+ #
121
+ attr_reader :base_level
122
+
123
+ ##
124
+ # Add a configuration file or directory to the loader.
125
+ #
126
+ # If a CLI has a default tool set, it might use this to point to the
127
+ # directory that defines those tools. For example, the default Toys CLI
128
+ # uses this to load the builtin tools from the "builtins" directory.
129
+ #
130
+ # @param [String] path A path to add.
131
+ # @param [Boolean] high_priority Add the config at the head of the priority
132
+ # list rather than the tail.
133
+ #
134
+ def add_config_path(path, high_priority: false)
135
+ @loader.add_path(path, high_priority: high_priority)
136
+ self
137
+ end
138
+
139
+ ##
140
+ # Searches the given directory for a well-known config directory and/or
141
+ # config file. If found, these are added to the loader.
142
+ #
143
+ # Typically, a CLI will use this to find toys configs in the current
144
+ # working directory, the user's home directory, or some other well-known
145
+ # general configuration-oriented directory such as "/etc".
146
+ #
147
+ # @param [String] search_path A path to search for configs.
148
+ # @param [Boolean] high_priority Add the configs at the head of the
149
+ # priority list rather than the tail.
150
+ #
151
+ def add_search_path(search_path, high_priority: false)
152
+ paths = []
153
+ if @config_file_name
154
+ file_path = ::File.join(search_path, @config_file_name)
155
+ paths << file_path if !::File.directory?(file_path) && ::File.readable?(file_path)
156
+ end
157
+ if @config_dir_name
158
+ dir_path = ::File.join(search_path, @config_dir_name)
159
+ paths << dir_path if ::File.directory?(dir_path) && ::File.readable?(dir_path)
160
+ end
161
+ @loader.add_path(paths, high_priority: high_priority)
162
+ self
163
+ end
164
+
165
+ ##
166
+ # A convenience method that searches the current working directory, and all
167
+ # ancestor directories, for configs to add to the loader.
168
+ #
169
+ # @param [String] start The first directory to add. Defaults to the current
170
+ # working directory.
171
+ # @param [String] base The last directory to add. Defaults to `"/"`.
172
+ # @param [Boolean] high_priority Add the configs at the head of the
173
+ # priority list rather than the tail.
174
+ #
175
+ def add_search_path_hierarchy(start: nil, base: "/", high_priority: false)
176
+ path = start || ::Dir.pwd
177
+ paths = []
178
+ loop do
179
+ paths << path
180
+ break if path == base
181
+ next_path = ::File.dirname(path)
182
+ break if next_path == path
183
+ path = next_path
184
+ end
185
+ paths.reverse! if high_priority
186
+ paths.each do |p|
187
+ add_search_path(p, high_priority: high_priority)
188
+ end
189
+ self
190
+ end
191
+
192
+ ##
193
+ # Run the CLI with the given command line arguments.
194
+ #
195
+ # @param [String...] args Command line arguments specifying which tool to
196
+ # run and what arguments to pass to it. You may pass either a single
197
+ # array of strings, or a series of string arguments.
198
+ # @param [Integer] verbosity Initial verbosity. Default is 0.
199
+ #
200
+ # @return [Integer] The resulting status code
201
+ #
202
+ def run(*args, verbosity: 0)
203
+ @loader.execute(self, args.flatten, verbosity: verbosity)
204
+ end
205
+
206
+ ##
207
+ # Make a clone with the same settings but no paths in the loader.
208
+ #
209
+ # @return [Toys::CLI]
210
+ #
211
+ def empty_clone
212
+ CLI.new(binary_name: @binary_name,
213
+ config_dir_name: @config_dir_name,
214
+ config_file_name: @config_file_name,
215
+ index_file_name: @index_file_name,
216
+ preload_file_name: @preload_file_name,
217
+ middleware_stack: @middleware_stack,
218
+ logger: @logger,
219
+ base_level: @base_level)
220
+ end
221
+
222
+ class << self
223
+ ##
224
+ # Returns a default set of middleware that may be used as a starting
225
+ # point for a typical CLI. This set includes:
226
+ #
227
+ # * {Toys::Middleware::HandleUsageErrors}
228
+ # * {Toys::Middleware::ShowUsage} adding the `--help` switch and
229
+ # providing default behavior for groups
230
+ # * {Toys::Middleware::AddVerbositySwitches} adding the `--verbose` and
231
+ # `--quiet` switches for managing the logger level
232
+ #
233
+ # @return [Array]
234
+ #
235
+ def default_middleware_stack
236
+ [
237
+ :handle_usage_errors,
238
+ :show_usage,
239
+ :add_verbosity_switches
240
+ ]
241
+ end
242
+
243
+ ##
244
+ # Returns a default logger that logs to `STDERR`.
245
+ #
246
+ # @return [Logger]
247
+ #
248
+ def default_logger
249
+ logger = ::Logger.new(::STDERR)
250
+ logger.formatter = proc do |severity, time, _progname, msg|
251
+ msg_str =
252
+ case msg
253
+ when ::String
254
+ msg
255
+ when ::Exception
256
+ "#{msg.message} (#{msg.class})\n" << (msg.backtrace || []).join("\n")
257
+ else
258
+ msg.inspect
259
+ end
260
+ timestr = time.strftime("%Y-%m-%d %H:%M:%S")
261
+ format("[%s %5s] %s\n", timestr, severity, msg_str)
262
+ end
263
+ logger.level = ::Logger::WARN
264
+ logger
265
+ end
266
+ end
267
+ end
268
+ end