toys-core 0.5.0 → 0.6.0
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/CHANGELOG.md +9 -0
- data/lib/toys-core.rb +1 -1
- data/lib/toys/cli.rb +6 -6
- data/lib/toys/core_version.rb +1 -1
- data/lib/toys/definition/source_info.rb +190 -0
- data/lib/toys/definition/tool.rb +46 -20
- data/lib/toys/dsl/tool.rb +43 -14
- data/lib/toys/input_file.rb +3 -2
- data/lib/toys/loader.rb +78 -84
- data/lib/toys/runner.rb +1 -0
- data/lib/toys/standard_middleware/show_help.rb +67 -22
- data/lib/toys/tool.rb +29 -1
- data/lib/toys/utils/help_text.rb +24 -15
- metadata +5 -5
- data/lib/toys/definition/data_finder.rb +0 -108
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0202fa141dcee7d96aacdec2092ace8041f5498e367596d8e2a5aa893fa64d36
|
4
|
+
data.tar.gz: 20ea445f7ad7a5ab964ad23434e57f4acb6ee567e6dc38837751246d32940ca5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 704d70fc544435c23cf3d0e88550fa3a3951bbb9b3611eabdc89c3c9871d3ad67098cce21fa54ffb130aa4da6d0901729471b9e698ae78a394f8ff750392205f
|
7
|
+
data.tar.gz: 57d9cacc5646fd39e0399bb2729d0a936d70f5d67a1f7a7e3d4b19a5d38ab699dc6b0e5044ae455fea3cdb0d46e44406bfc898074e71e2d9b3cc7882981886d7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 0.6.0 / 2018-10-22
|
4
|
+
|
5
|
+
* CHANGED: Replaced Toys::Definition::DataFinder with Toys::Definition::SourceInfo.
|
6
|
+
* CHANGED: Removed Toys::Definition#find_data. Use Toys::Definition#source_info and call find_data.
|
7
|
+
* ADDED: Context directory is kept in SourceInfo and available in the DSL and the tool runtime.
|
8
|
+
* IMPROVED: Optionally omit hidden subtools (i.e. names beginning with underscore)
|
9
|
+
from subtool lists.
|
10
|
+
* IMPROVED: Optionally omit non-runnable namespaces from recursive subtool lists.
|
11
|
+
|
3
12
|
### 0.5.0 / 2018-10-07
|
4
13
|
|
5
14
|
* FIXED: Template instantiation was failing if the hosting tool was priority-masked.
|
data/lib/toys-core.rb
CHANGED
@@ -68,8 +68,8 @@ require "toys/core_version"
|
|
68
68
|
require "toys/definition/acceptor"
|
69
69
|
require "toys/definition/alias"
|
70
70
|
require "toys/definition/arg"
|
71
|
-
require "toys/definition/data_finder"
|
72
71
|
require "toys/definition/flag"
|
72
|
+
require "toys/definition/source_info"
|
73
73
|
require "toys/definition/tool"
|
74
74
|
require "toys/dsl/arg"
|
75
75
|
require "toys/dsl/flag"
|
data/lib/toys/cli.rb
CHANGED
@@ -173,12 +173,12 @@ module Toys
|
|
173
173
|
#
|
174
174
|
# @param [Boolean] high_priority Add the config at the head of the priority
|
175
175
|
# list rather than the tail.
|
176
|
-
# @param [String]
|
177
|
-
# tools defined in this block. If omitted, a default unique string
|
178
|
-
# be generated.
|
176
|
+
# @param [String] name The source name that will be shown in documentation
|
177
|
+
# for tools defined in this block. If omitted, a default unique string
|
178
|
+
# will be generated.
|
179
179
|
#
|
180
|
-
def add_config_block(high_priority: false,
|
181
|
-
@loader.add_block(high_priority: high_priority,
|
180
|
+
def add_config_block(high_priority: false, name: nil, &block)
|
181
|
+
@loader.add_block(high_priority: high_priority, name: name, &block)
|
182
182
|
self
|
183
183
|
end
|
184
184
|
|
@@ -251,7 +251,7 @@ module Toys
|
|
251
251
|
@loader.lookup(args.flatten)
|
252
252
|
end
|
253
253
|
ContextualError.capture_path(
|
254
|
-
"Error during tool execution!", tool_definition.source_path,
|
254
|
+
"Error during tool execution!", tool_definition.source_info&.source_path,
|
255
255
|
tool_name: tool_definition.full_name, tool_args: remaining
|
256
256
|
) do
|
257
257
|
Runner.new(self, tool_definition).run(remaining, verbosity: verbosity)
|
data/lib/toys/core_version.rb
CHANGED
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
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.
|
30
|
+
;
|
31
|
+
|
32
|
+
module Toys
|
33
|
+
module Definition
|
34
|
+
##
|
35
|
+
# Information about source toys directories and files.
|
36
|
+
#
|
37
|
+
class SourceInfo
|
38
|
+
##
|
39
|
+
# Create a SourceInfo.
|
40
|
+
# @private
|
41
|
+
#
|
42
|
+
def initialize(parent, context_directory, source, source_type, source_name, data_dir_name)
|
43
|
+
@parent = parent
|
44
|
+
@context_directory = context_directory
|
45
|
+
@source = source
|
46
|
+
@source_type = source_type
|
47
|
+
@source_path = source if source.is_a?(::String)
|
48
|
+
@source_proc = source if source.is_a?(::Proc)
|
49
|
+
@source_name = source_name
|
50
|
+
@data_dir =
|
51
|
+
if data_dir_name && @source_path
|
52
|
+
dir = ::File.join(::File.dirname(@source_path), data_dir_name)
|
53
|
+
dir if ::File.directory?(dir) && ::File.readable?(dir)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Return the parent SourceInfo, or nil if this is the root.
|
59
|
+
# @return [Toys::Definition::SourceInfo,nil]
|
60
|
+
#
|
61
|
+
attr_reader :parent
|
62
|
+
|
63
|
+
##
|
64
|
+
# Return the context directory path (normally the directory containing
|
65
|
+
# the toplevel toys file or directory). May return nil if there is no
|
66
|
+
# context (e.g. the tool is being defined from a block).
|
67
|
+
# @return [String,nil]
|
68
|
+
#
|
69
|
+
attr_reader :context_directory
|
70
|
+
|
71
|
+
##
|
72
|
+
# Return the source, which may be a path or a proc.
|
73
|
+
# @return [String,Proc]
|
74
|
+
#
|
75
|
+
attr_reader :source
|
76
|
+
|
77
|
+
##
|
78
|
+
# Return the type of source.
|
79
|
+
# @return [:file,:directory,:proc]
|
80
|
+
#
|
81
|
+
attr_reader :source_type
|
82
|
+
|
83
|
+
##
|
84
|
+
# Return the path of the current source file or directory, or nil if this
|
85
|
+
# source is not a file system path.
|
86
|
+
# @return [String,nil]
|
87
|
+
#
|
88
|
+
attr_reader :source_path
|
89
|
+
|
90
|
+
##
|
91
|
+
# Return the source proc, or nil if this source is not a proc.
|
92
|
+
# @return [Proc,nil]
|
93
|
+
#
|
94
|
+
attr_reader :source_proc
|
95
|
+
|
96
|
+
##
|
97
|
+
# Return the user-visible name of this source.
|
98
|
+
# @return [String]
|
99
|
+
#
|
100
|
+
attr_reader :source_name
|
101
|
+
alias to_s source_name
|
102
|
+
|
103
|
+
##
|
104
|
+
# Return the absolute path to the given data file or directory.
|
105
|
+
#
|
106
|
+
# @param [String] path The relative path to find
|
107
|
+
# @param [nil,:file,:directory] type Type of file system object to find,
|
108
|
+
# or nil to return any type.
|
109
|
+
# @return [String,nil] Absolute path of the result, or nil if not found.
|
110
|
+
#
|
111
|
+
def find_data(path, type: nil)
|
112
|
+
if @data_dir
|
113
|
+
full_path = ::File.join(@data_dir, path)
|
114
|
+
case type
|
115
|
+
when :file
|
116
|
+
return full_path if ::File.file?(full_path)
|
117
|
+
when :directory
|
118
|
+
return full_path if ::File.directory?(full_path)
|
119
|
+
else
|
120
|
+
return full_path if ::File.readable?(full_path)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
parent&.find_data(path, type: type)
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Create a child SourceInfo relative to the parent path.
|
128
|
+
# @private
|
129
|
+
#
|
130
|
+
def relative_child(filename, data_dir_name)
|
131
|
+
raise "Cannot create relative child of a proc" unless source_path
|
132
|
+
child_path = ::File.join(source_path, filename)
|
133
|
+
child_path, type = SourceInfo.check_path(child_path, true)
|
134
|
+
return nil unless child_path
|
135
|
+
SourceInfo.new(self, context_directory, child_path, type, child_path, data_dir_name)
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Create a child SourceInfo with an absolute path.
|
140
|
+
# @private
|
141
|
+
#
|
142
|
+
def absolute_child(child_path)
|
143
|
+
child_path, type = SourceInfo.check_path(child_path, false)
|
144
|
+
SourceInfo.new(self, context_directory, child_path, type, child_path, nil)
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Create a root source info for a file path.
|
149
|
+
# @private
|
150
|
+
#
|
151
|
+
def self.create_path_root(source_path)
|
152
|
+
source_path, type = check_path(source_path, false)
|
153
|
+
context_directory = ::File.dirname(source_path)
|
154
|
+
new(nil, context_directory, source_path, type, source_path, nil)
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Create a root source info for a proc.
|
159
|
+
# @private
|
160
|
+
#
|
161
|
+
def self.create_proc_root(source_proc, source_name)
|
162
|
+
new(nil, nil, source_proc, :proc, source_name, nil)
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Check a path and determine the canonical path and type.
|
167
|
+
# @private
|
168
|
+
#
|
169
|
+
def self.check_path(path, lenient)
|
170
|
+
path = ::File.expand_path(path)
|
171
|
+
unless ::File.readable?(path)
|
172
|
+
raise LoaderError, "Cannot read: #{path}" unless lenient
|
173
|
+
return [nil, nil]
|
174
|
+
end
|
175
|
+
if ::File.file?(path)
|
176
|
+
unless ::File.extname(path) == ".rb"
|
177
|
+
raise LoaderError, "File is not a ruby file: #{path}" unless lenient
|
178
|
+
return [nil, nil]
|
179
|
+
end
|
180
|
+
[path, :file]
|
181
|
+
elsif ::File.directory?(path)
|
182
|
+
[path, :directory]
|
183
|
+
else
|
184
|
+
raise LoaderError, "Unknown type: #{path}" unless lenient
|
185
|
+
[nil, nil]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
data/lib/toys/definition/tool.rb
CHANGED
@@ -91,8 +91,7 @@ module Toys
|
|
91
91
|
def reset_definition(loader)
|
92
92
|
@tool_class = DSL::Tool.new_class(@full_name, @priority, loader)
|
93
93
|
|
94
|
-
@
|
95
|
-
@data_finder = nil
|
94
|
+
@source_info = nil
|
96
95
|
@definition_finished = false
|
97
96
|
|
98
97
|
@desc = Utils::WrappableString.new("")
|
@@ -109,6 +108,7 @@ module Toys
|
|
109
108
|
|
110
109
|
@disable_argument_parsing = false
|
111
110
|
@includes_modules = false
|
111
|
+
@custom_context_directory = nil
|
112
112
|
end
|
113
113
|
|
114
114
|
##
|
@@ -186,10 +186,18 @@ module Toys
|
|
186
186
|
attr_reader :middleware_stack
|
187
187
|
|
188
188
|
##
|
189
|
-
# Returns the
|
190
|
-
#
|
189
|
+
# Returns info on the source of this tool, or nil if the source is not
|
190
|
+
# defined.
|
191
|
+
# @return [Toys::Definition::SourceInfo,nil]
|
192
|
+
#
|
193
|
+
attr_reader :source_info
|
194
|
+
|
195
|
+
##
|
196
|
+
# Returns the custom context directory set for this tool, or nil if none
|
197
|
+
# is set.
|
198
|
+
# @return [String,nil]
|
191
199
|
#
|
192
|
-
attr_reader :
|
200
|
+
attr_reader :custom_context_directory
|
193
201
|
|
194
202
|
##
|
195
203
|
# Returns the local name of this tool.
|
@@ -366,17 +374,15 @@ module Toys
|
|
366
374
|
# A tool may be defined from at most one path. If a different path is
|
367
375
|
# already set, raises {Toys::ToolDefinitionError}
|
368
376
|
#
|
369
|
-
# @param [
|
370
|
-
# @param [Toys::Definition::DataFinder] data_finder Data finder
|
377
|
+
# @param [Toys::Definition::SourceInfo] source Source info
|
371
378
|
#
|
372
|
-
def
|
373
|
-
if
|
379
|
+
def lock_source(source)
|
380
|
+
if source_info && source_info.source != source.source
|
374
381
|
raise ToolDefinitionError,
|
375
|
-
"Cannot redefine tool #{display_name.inspect} in #{
|
376
|
-
" (already defined in #{
|
382
|
+
"Cannot redefine tool #{display_name.inspect} in #{source.source_name}" \
|
383
|
+
" (already defined in #{source_info.source_name})"
|
377
384
|
end
|
378
|
-
@
|
379
|
-
@data_finder = data_finder
|
385
|
+
@source_info = source
|
380
386
|
end
|
381
387
|
|
382
388
|
##
|
@@ -671,15 +677,35 @@ module Toys
|
|
671
677
|
end
|
672
678
|
|
673
679
|
##
|
674
|
-
#
|
680
|
+
# Set the custom context directory.
|
675
681
|
#
|
676
|
-
# @param [String]
|
677
|
-
#
|
678
|
-
|
679
|
-
|
682
|
+
# @param [String] dir
|
683
|
+
#
|
684
|
+
def custom_context_directory=(dir)
|
685
|
+
check_definition_state
|
686
|
+
@custom_context_directory = dir
|
687
|
+
end
|
688
|
+
|
689
|
+
##
|
690
|
+
# Return the effective context directory.
|
691
|
+
# If there is a custom context directory, uses that. Otherwise, looks for
|
692
|
+
# a custom context directory up the tool ancestor chain. If none is
|
693
|
+
# found, uses the default context directory from the source info. It is
|
694
|
+
# possible for there to be no context directory at all, in which case,
|
695
|
+
# returns nil.
|
696
|
+
#
|
697
|
+
# @return [String,nil]
|
698
|
+
#
|
699
|
+
def context_directory
|
700
|
+
lookup_custom_context_directory || source_info&.context_directory
|
701
|
+
end
|
702
|
+
|
703
|
+
##
|
704
|
+
# Lookup the custom context directory in this tool and its ancestors.
|
705
|
+
# @private
|
680
706
|
#
|
681
|
-
def
|
682
|
-
|
707
|
+
def lookup_custom_context_directory
|
708
|
+
custom_context_directory || @parent&.lookup_custom_context_directory
|
683
709
|
end
|
684
710
|
|
685
711
|
##
|
data/lib/toys/dsl/tool.rb
CHANGED
@@ -203,7 +203,7 @@ module Toys
|
|
203
203
|
end
|
204
204
|
end
|
205
205
|
subtool_class = subtool.tool_class
|
206
|
-
DSL::Tool.prepare(subtool_class, next_remaining,
|
206
|
+
DSL::Tool.prepare(subtool_class, next_remaining, source_info) do
|
207
207
|
subtool_class.class_eval(&block)
|
208
208
|
end
|
209
209
|
self
|
@@ -230,7 +230,7 @@ module Toys
|
|
230
230
|
# @return [Toys::DSL::Tool] self, for chaining.
|
231
231
|
#
|
232
232
|
def load(path)
|
233
|
-
@__loader.load_path(path, @__words, @__remaining_words, @__priority)
|
233
|
+
@__loader.load_path(source_info, path, @__words, @__remaining_words, @__priority)
|
234
234
|
self
|
235
235
|
end
|
236
236
|
|
@@ -650,6 +650,15 @@ module Toys
|
|
650
650
|
super(DSL::Tool.resolve_mixin(mod, cur_tool, @__loader))
|
651
651
|
end
|
652
652
|
|
653
|
+
##
|
654
|
+
# Return the current source info object.
|
655
|
+
#
|
656
|
+
# @return [Toys::Definition::SourceInfo] Source info.
|
657
|
+
#
|
658
|
+
def source_info
|
659
|
+
@__source.last
|
660
|
+
end
|
661
|
+
|
653
662
|
##
|
654
663
|
# Find the given data path (file or directory)
|
655
664
|
#
|
@@ -659,7 +668,32 @@ module Toys
|
|
659
668
|
# @return [String,nil] Absolute path of the result, or nil if not found.
|
660
669
|
#
|
661
670
|
def find_data(path, type: nil)
|
662
|
-
|
671
|
+
source_info.find_data(path, type: type)
|
672
|
+
end
|
673
|
+
|
674
|
+
##
|
675
|
+
# Return the context directory for this tool. Generally, this defaults
|
676
|
+
# to the directory containing the toys config directory structure being
|
677
|
+
# read, but it may be changed by setting a different context directory
|
678
|
+
# for the tool.
|
679
|
+
# May return nil if there is no context.
|
680
|
+
#
|
681
|
+
# @return [String,nil] Context directory
|
682
|
+
#
|
683
|
+
def context_directory
|
684
|
+
DSL::Tool.current_tool(self, false)&.context_directory || source_info.context_directory
|
685
|
+
end
|
686
|
+
|
687
|
+
##
|
688
|
+
# Set a custom context directory for this tool.
|
689
|
+
#
|
690
|
+
# @param [String] dir Context directory
|
691
|
+
#
|
692
|
+
def set_context_directory(dir)
|
693
|
+
cur_tool = DSL::Tool.current_tool(self, false)
|
694
|
+
return if cur_tool.nil?
|
695
|
+
cur_tool.custom_context_directory = dir
|
696
|
+
self
|
663
697
|
end
|
664
698
|
|
665
699
|
## @private
|
@@ -670,8 +704,7 @@ module Toys
|
|
670
704
|
tool_class.instance_variable_set(:@__priority, priority)
|
671
705
|
tool_class.instance_variable_set(:@__loader, loader)
|
672
706
|
tool_class.instance_variable_set(:@__remaining_words, nil)
|
673
|
-
tool_class.instance_variable_set(:@
|
674
|
-
tool_class.instance_variable_set(:@__data_finder, nil)
|
707
|
+
tool_class.instance_variable_set(:@__source, [])
|
675
708
|
tool_class
|
676
709
|
end
|
677
710
|
|
@@ -697,23 +730,19 @@ module Toys
|
|
697
730
|
tool_class.instance_variable_set(memoize_var, cur_tool)
|
698
731
|
end
|
699
732
|
if cur_tool && activate
|
700
|
-
|
701
|
-
|
702
|
-
cur_tool.lock_source_path(path, data_finder)
|
733
|
+
source = tool_class.instance_variable_get(:@__source).last
|
734
|
+
cur_tool.lock_source(source)
|
703
735
|
end
|
704
736
|
cur_tool
|
705
737
|
end
|
706
738
|
|
707
739
|
## @private
|
708
|
-
def self.prepare(tool_class, remaining_words,
|
740
|
+
def self.prepare(tool_class, remaining_words, source)
|
709
741
|
tool_class.instance_variable_set(:@__remaining_words, remaining_words)
|
710
|
-
tool_class.
|
711
|
-
tool_class.instance_variable_set(:@__data_finder, data_finder)
|
742
|
+
tool_class.instance_variable_get(:@__source).push(source)
|
712
743
|
yield
|
713
744
|
ensure
|
714
|
-
tool_class.
|
715
|
-
tool_class.instance_variable_set(:@__path, nil)
|
716
|
-
tool_class.instance_variable_set(:@__data_finder, nil)
|
745
|
+
tool_class.instance_variable_get(:@__source).pop
|
717
746
|
end
|
718
747
|
|
719
748
|
## @private
|
data/lib/toys/input_file.rb
CHANGED
@@ -40,18 +40,19 @@ module Toys::InputFile # rubocop:disable Style/ClassAndModuleChildren
|
|
40
40
|
end
|
41
41
|
|
42
42
|
## @private
|
43
|
-
def self.evaluate(tool_class, remaining_words,
|
43
|
+
def self.evaluate(tool_class, remaining_words, source)
|
44
44
|
namespace = ::Module.new
|
45
45
|
namespace.module_eval do
|
46
46
|
include ::Toys::Tool::Keys
|
47
47
|
@tool_class = tool_class
|
48
48
|
end
|
49
|
+
path = source.source_path
|
49
50
|
basename = ::File.basename(path).tr(".-", "_").gsub(/\W/, "")
|
50
51
|
name = "M#{namespace.object_id}_#{basename}"
|
51
52
|
str = build_eval_string(name, ::IO.read(path))
|
52
53
|
if str
|
53
54
|
const_set(name, namespace)
|
54
|
-
::Toys::DSL::Tool.prepare(tool_class, remaining_words,
|
55
|
+
::Toys::DSL::Tool.prepare(tool_class, remaining_words, source) do
|
55
56
|
::Toys::ContextualError.capture_path("Error while loading Toys config!", path) do
|
56
57
|
# rubocop:disable Security/Eval
|
57
58
|
eval(str, __binding, path, 0)
|
data/lib/toys/loader.rb
CHANGED
@@ -89,7 +89,7 @@ module Toys
|
|
89
89
|
@index_file_name = index_file_name
|
90
90
|
@preload_file_name = preload_file_name
|
91
91
|
@preload_directory_name = preload_directory_name
|
92
|
-
@
|
92
|
+
@data_directory_name = data_directory_name
|
93
93
|
@middleware_stack = middleware_stack
|
94
94
|
@worklist = []
|
95
95
|
@tool_data = {}
|
@@ -101,16 +101,17 @@ module Toys
|
|
101
101
|
##
|
102
102
|
# Add a configuration file/directory to the loader.
|
103
103
|
#
|
104
|
-
# @param [String,Array<String>]
|
104
|
+
# @param [String,Array<String>] paths One or more paths to add.
|
105
105
|
# @param [Boolean] high_priority If true, add this path at the top of the
|
106
106
|
# priority list. Defaults to false, indicating the new path should be
|
107
107
|
# at the bottom of the priority list.
|
108
108
|
#
|
109
|
-
def add_path(
|
110
|
-
paths = Array(
|
109
|
+
def add_path(paths, high_priority: false)
|
110
|
+
paths = Array(paths)
|
111
111
|
priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
|
112
|
-
paths.each do |
|
113
|
-
|
112
|
+
paths.each do |path|
|
113
|
+
source = Definition::SourceInfo.create_path_root(path)
|
114
|
+
@worklist << [source, [], priority]
|
114
115
|
end
|
115
116
|
self
|
116
117
|
end
|
@@ -121,14 +122,15 @@ module Toys
|
|
121
122
|
# @param [Boolean] high_priority If true, add this block at the top of the
|
122
123
|
# priority list. Defaults to false, indicating the block should be at
|
123
124
|
# the bottom of the priority list.
|
124
|
-
# @param [String]
|
125
|
-
# tools defined in this block. If omitted, a default unique string
|
126
|
-
# be generated.
|
125
|
+
# @param [String] name The source name that will be shown in documentation
|
126
|
+
# for tools defined in this block. If omitted, a default unique string
|
127
|
+
# will be generated.
|
127
128
|
#
|
128
|
-
def add_block(high_priority: false,
|
129
|
-
|
129
|
+
def add_block(high_priority: false, name: nil, &block)
|
130
|
+
name ||= "(Code block #{block.object_id})"
|
130
131
|
priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
|
131
|
-
|
132
|
+
source = Definition::SourceInfo.create_proc_root(block, name)
|
133
|
+
@worklist << [source, [], priority]
|
132
134
|
self
|
133
135
|
end
|
134
136
|
|
@@ -173,9 +175,11 @@ module Toys
|
|
173
175
|
# @param [Array<String>] words The name of the parent tool
|
174
176
|
# @param [Boolean] recursive If true, return all subtools recursively
|
175
177
|
# rather than just the immediate children (the default)
|
178
|
+
# @param [Boolean] include_hidden If true, include hidden subtools,
|
179
|
+
# e.g. names beginning with underscores.
|
176
180
|
# @return [Array<Toys::Definition::Tool,Toys::Definition::Alias>]
|
177
181
|
#
|
178
|
-
def list_subtools(words, recursive: false)
|
182
|
+
def list_subtools(words, recursive: false, include_hidden: false)
|
179
183
|
load_for_prefix(words)
|
180
184
|
found_tools = []
|
181
185
|
len = words.length
|
@@ -190,6 +194,7 @@ module Toys
|
|
190
194
|
found_tools << tool unless tool.nil?
|
191
195
|
end
|
192
196
|
sort_tools_by_name(found_tools)
|
197
|
+
include_hidden ? found_tools : filter_hidden_subtools(found_tools)
|
193
198
|
end
|
194
199
|
|
195
200
|
##
|
@@ -309,30 +314,14 @@ module Toys
|
|
309
314
|
end
|
310
315
|
|
311
316
|
##
|
312
|
-
# Load configuration from the given path.
|
317
|
+
# Load configuration from the given path. This is called from the `load`
|
318
|
+
# directive in the DSL.
|
313
319
|
#
|
314
320
|
# @private
|
315
321
|
#
|
316
|
-
def load_path(path, words, remaining_words, priority)
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
##
|
321
|
-
# Load configuration from the given proc.
|
322
|
-
#
|
323
|
-
# @private
|
324
|
-
#
|
325
|
-
def load_proc(proc, words, remaining_words, priority, path)
|
326
|
-
if remaining_words
|
327
|
-
tool_class = get_tool_definition(words, priority).tool_class
|
328
|
-
::Toys::DSL::Tool.prepare(tool_class, remaining_words, path, @empty_data_finder) do
|
329
|
-
::Toys::ContextualError.capture("Error while loading Toys config!") do
|
330
|
-
tool_class.class_eval(&proc)
|
331
|
-
end
|
332
|
-
end
|
333
|
-
else
|
334
|
-
@worklist << [proc, path, words, @empty_data_finder, priority]
|
335
|
-
end
|
322
|
+
def load_path(parent_source, path, words, remaining_words, priority)
|
323
|
+
source = parent_source.absolute_child(path)
|
324
|
+
load_validated_path(source, words, remaining_words, priority)
|
336
325
|
end
|
337
326
|
|
338
327
|
##
|
@@ -441,59 +430,71 @@ module Toys
|
|
441
430
|
def load_for_prefix(prefix)
|
442
431
|
cur_worklist = @worklist
|
443
432
|
@worklist = []
|
444
|
-
cur_worklist.each do |source,
|
433
|
+
cur_worklist.each do |source, words, priority|
|
445
434
|
remaining_words = calc_remaining_words(prefix, words)
|
446
|
-
if source.
|
447
|
-
load_proc(source, words, remaining_words, priority
|
448
|
-
elsif source
|
449
|
-
load_validated_path(
|
435
|
+
if source.source_proc
|
436
|
+
load_proc(source, words, remaining_words, priority)
|
437
|
+
elsif source.source_path
|
438
|
+
load_validated_path(source, words, remaining_words, priority)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
def load_proc(source, words, remaining_words, priority)
|
444
|
+
if remaining_words
|
445
|
+
tool_class = get_tool_definition(words, priority).tool_class
|
446
|
+
DSL::Tool.prepare(tool_class, remaining_words, source) do
|
447
|
+
ContextualError.capture("Error while loading Toys config!") do
|
448
|
+
tool_class.class_eval(&source.source_proc)
|
449
|
+
end
|
450
450
|
end
|
451
|
+
else
|
452
|
+
@worklist << [source, words, priority]
|
451
453
|
end
|
452
454
|
end
|
453
455
|
|
454
|
-
def load_validated_path(
|
456
|
+
def load_validated_path(source, words, remaining_words, priority)
|
455
457
|
if remaining_words
|
456
|
-
load_relevant_path(
|
458
|
+
load_relevant_path(source, words, remaining_words, priority)
|
457
459
|
else
|
458
|
-
@worklist << [
|
460
|
+
@worklist << [source, words, priority]
|
459
461
|
end
|
460
462
|
end
|
461
463
|
|
462
|
-
def load_relevant_path(
|
463
|
-
if
|
464
|
+
def load_relevant_path(source, words, remaining_words, priority)
|
465
|
+
if source.source_type == :file
|
464
466
|
tool_class = get_tool_definition(words, priority).tool_class
|
465
|
-
InputFile.evaluate(tool_class, remaining_words,
|
467
|
+
InputFile.evaluate(tool_class, remaining_words, source)
|
466
468
|
else
|
467
|
-
do_preload(
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
load_child_in(path, child, words, remaining_words, data_finder, priority)
|
469
|
+
do_preload(source.source_path)
|
470
|
+
load_index_in(source, words, remaining_words, priority)
|
471
|
+
::Dir.entries(source.source_path).each do |child|
|
472
|
+
load_child_in(source, child, words, remaining_words, priority)
|
472
473
|
end
|
473
474
|
end
|
474
475
|
end
|
475
476
|
|
476
|
-
def load_index_in(
|
477
|
+
def load_index_in(source, words, remaining_words, priority)
|
477
478
|
return unless @index_file_name
|
478
|
-
|
479
|
-
|
480
|
-
load_relevant_path(index_path, words, remaining_words, data_finder, priority) if index_path
|
479
|
+
index_source = source.relative_child(@index_file_name, @data_directory_name)
|
480
|
+
load_relevant_path(index_source, words, remaining_words, priority) if index_source
|
481
481
|
end
|
482
482
|
|
483
|
-
def load_child_in(
|
484
|
-
return if child.start_with?(".")
|
485
|
-
|
486
|
-
|
483
|
+
def load_child_in(source, child, words, remaining_words, priority)
|
484
|
+
return if child.start_with?(".") || child == @index_file_name ||
|
485
|
+
child == @preload_file_name || child == @preload_directory_name ||
|
486
|
+
child == @data_directory_name
|
487
|
+
child_source = source.relative_child(child, @data_directory_name)
|
487
488
|
child_word = ::File.basename(child, ".rb")
|
488
489
|
next_words = words + [child_word]
|
489
490
|
next_remaining = Loader.next_remaining_words(remaining_words, child_word)
|
490
|
-
load_validated_path(
|
491
|
+
load_validated_path(child_source, next_words, next_remaining, priority)
|
491
492
|
end
|
492
493
|
|
493
494
|
def do_preload(path)
|
494
495
|
if @preload_file_name
|
495
496
|
preload_file = ::File.join(path, @preload_file_name)
|
496
|
-
if
|
497
|
+
if ::File.file?(preload_file) && ::File.readable?(preload_file)
|
497
498
|
require preload_file
|
498
499
|
end
|
499
500
|
end
|
@@ -501,37 +502,17 @@ module Toys
|
|
501
502
|
preload_dir = ::File.join(path, @preload_directory_name)
|
502
503
|
if ::File.directory?(preload_dir) && ::File.readable?(preload_dir)
|
503
504
|
::Dir.entries(preload_dir).each do |child|
|
505
|
+
next unless ::File.extname(child) == ".rb"
|
504
506
|
preload_file = ::File.join(preload_dir, child)
|
505
|
-
if !::File.
|
506
|
-
|
507
|
-
end
|
507
|
+
next if !::File.file?(preload_file) || !::File.readable?(preload_file)
|
508
|
+
require preload_file
|
508
509
|
end
|
509
510
|
end
|
510
511
|
end
|
511
512
|
end
|
512
513
|
|
513
|
-
def check_path(path, lenient: false, type: nil)
|
514
|
-
path = ::File.expand_path(path)
|
515
|
-
type ||= ::File.extname(path) == ".rb" ? :file : :dir
|
516
|
-
case type
|
517
|
-
when :file
|
518
|
-
if ::File.directory?(path) || !::File.readable?(path)
|
519
|
-
return nil if lenient
|
520
|
-
raise LoaderError, "Cannot read file #{path}"
|
521
|
-
end
|
522
|
-
when :dir
|
523
|
-
if !::File.directory?(path) || !::File.readable?(path)
|
524
|
-
return nil if lenient
|
525
|
-
raise LoaderError, "Cannot read directory #{path}"
|
526
|
-
end
|
527
|
-
else
|
528
|
-
raise ::ArgumentError, "Illegal type #{type}"
|
529
|
-
end
|
530
|
-
path
|
531
|
-
end
|
532
|
-
|
533
514
|
def sort_tools_by_name(tools)
|
534
|
-
tools.sort do |a, b|
|
515
|
+
tools.sort! do |a, b|
|
535
516
|
a = a.full_name
|
536
517
|
b = b.full_name
|
537
518
|
while !a.empty? && !b.empty? && a.first == b.first
|
@@ -542,6 +523,19 @@ module Toys
|
|
542
523
|
end
|
543
524
|
end
|
544
525
|
|
526
|
+
def filter_hidden_subtools(tools)
|
527
|
+
result = []
|
528
|
+
tools.each_with_index do |tool, index|
|
529
|
+
next if tool.full_name.any? { |n| n.start_with?("_") }
|
530
|
+
unless tool.runnable?
|
531
|
+
next_tool = tools[index + 1]
|
532
|
+
next if next_tool && next_tool.full_name.slice(0..-2) == tool.full_name
|
533
|
+
end
|
534
|
+
result << tool
|
535
|
+
end
|
536
|
+
result
|
537
|
+
end
|
538
|
+
|
545
539
|
def calc_remaining_words(words1, words2)
|
546
540
|
index = 0
|
547
541
|
lengths = [words1.length, words2.length]
|
data/lib/toys/runner.rb
CHANGED
@@ -79,6 +79,7 @@ module Toys
|
|
79
79
|
def create_data(args, base_verbosity)
|
80
80
|
data = @tool_definition.default_data.dup
|
81
81
|
data[Tool::Keys::TOOL_DEFINITION] = @tool_definition
|
82
|
+
data[Tool::Keys::TOOL_SOURCE] = @tool_definition.source_info
|
82
83
|
data[Tool::Keys::TOOL_NAME] = @tool_definition.full_name
|
83
84
|
data[Tool::Keys::VERBOSITY] = base_verbosity
|
84
85
|
data[Tool::Keys::ARGS] = args
|
@@ -74,6 +74,12 @@ module Toys
|
|
74
74
|
#
|
75
75
|
DEFAULT_SEARCH_FLAGS = ["-s WORD", "--search=WORD"].freeze
|
76
76
|
|
77
|
+
##
|
78
|
+
# Default show-all-subtools flags
|
79
|
+
# @return [Array<String>]
|
80
|
+
#
|
81
|
+
DEFAULT_SHOW_ALL_SUBTOOLS_FLAGS = ["--all"].freeze
|
82
|
+
|
77
83
|
##
|
78
84
|
# Key set when the show help flag is present
|
79
85
|
# @return [Object]
|
@@ -104,6 +110,12 @@ module Toys
|
|
104
110
|
#
|
105
111
|
SEARCH_STRING_KEY = Object.new.freeze
|
106
112
|
|
113
|
+
##
|
114
|
+
# Key for the show-all-subtools setting
|
115
|
+
# @return [Object]
|
116
|
+
#
|
117
|
+
SHOW_ALL_SUBTOOLS_KEY = Object.new.freeze
|
118
|
+
|
107
119
|
##
|
108
120
|
# Key for the tool name
|
109
121
|
# @return [Object]
|
@@ -155,8 +167,19 @@ module Toys
|
|
155
167
|
# * The `false` value for no flags. (Default)
|
156
168
|
# * A proc that takes a tool and returns any of the above.
|
157
169
|
#
|
170
|
+
# @param [Boolean,Array<String>,Proc] show_all_subtools_flags Specify
|
171
|
+
# flags to show all subtools, including hidden tools and non-runnable
|
172
|
+
# namespaces. The value may be any of the following:
|
173
|
+
#
|
174
|
+
# * An array of flags.
|
175
|
+
# * The `true` value to use {DEFAULT_SHOW_ALL_SUBTOOLS_FLAGS}.
|
176
|
+
# * The `false` value for no flags. (Default)
|
177
|
+
# * A proc that takes a tool and returns any of the above.
|
178
|
+
#
|
158
179
|
# @param [Boolean] default_recursive Whether to search recursively for
|
159
180
|
# subtools by default. Default is `false`.
|
181
|
+
# @param [Boolean] default_show_all_subtools Whether to show all subtools
|
182
|
+
# by default. Default is `false`.
|
160
183
|
# @param [Boolean] fallback_execution Cause the tool to display its own
|
161
184
|
# help text if it is not otherwise runnable. This is mostly useful
|
162
185
|
# for namespaces, which have children are not runnable. Default is
|
@@ -179,7 +202,9 @@ module Toys
|
|
179
202
|
list_flags: false,
|
180
203
|
recursive_flags: false,
|
181
204
|
search_flags: false,
|
205
|
+
show_all_subtools_flags: false,
|
182
206
|
default_recursive: false,
|
207
|
+
default_show_all_subtools: false,
|
183
208
|
fallback_execution: false,
|
184
209
|
allow_root_args: false,
|
185
210
|
show_source_path: false,
|
@@ -191,7 +216,9 @@ module Toys
|
|
191
216
|
@list_flags = list_flags
|
192
217
|
@recursive_flags = recursive_flags
|
193
218
|
@search_flags = search_flags
|
219
|
+
@show_all_subtools_flags = show_all_subtools_flags
|
194
220
|
@default_recursive = default_recursive ? true : false
|
221
|
+
@default_show_all_subtools = default_show_all_subtools ? true : false
|
195
222
|
@fallback_execution = fallback_execution
|
196
223
|
@allow_root_args = allow_root_args
|
197
224
|
@show_source_path = show_source_path
|
@@ -212,6 +239,7 @@ module Toys
|
|
212
239
|
if (!help_flags.empty? || !list_flags.empty? || @fallback_execution) && has_subtools
|
213
240
|
add_recursive_flags(tool_definition)
|
214
241
|
add_search_flags(tool_definition)
|
242
|
+
add_show_all_subtools_flags(tool_definition)
|
215
243
|
end
|
216
244
|
if !help_flags.empty? || !usage_flags.empty? || !list_flags.empty?
|
217
245
|
add_root_args(tool_definition)
|
@@ -223,16 +251,18 @@ module Toys
|
|
223
251
|
##
|
224
252
|
# Display help text if requested.
|
225
253
|
#
|
226
|
-
def run(tool)
|
254
|
+
def run(tool) # rubocop:disable Metrics/AbcSize
|
227
255
|
if tool[SHOW_USAGE_KEY]
|
228
256
|
terminal.puts(get_help_text(tool).usage_string(wrap_width: terminal.width))
|
229
257
|
elsif tool[SHOW_LIST_KEY]
|
230
258
|
terminal.puts(get_help_text(tool).list_string(recursive: tool[RECURSIVE_SUBTOOLS_KEY],
|
231
259
|
search: tool[SEARCH_STRING_KEY],
|
260
|
+
include_hidden: tool[SHOW_ALL_SUBTOOLS_KEY],
|
232
261
|
wrap_width: terminal.width))
|
233
262
|
elsif should_show_help(tool)
|
234
263
|
output_help(get_help_text(tool).help_string(recursive: tool[RECURSIVE_SUBTOOLS_KEY],
|
235
264
|
search: tool[SEARCH_STRING_KEY],
|
265
|
+
include_hidden: tool[SHOW_ALL_SUBTOOLS_KEY],
|
236
266
|
show_source_path: @show_source_path,
|
237
267
|
wrap_width: terminal.width))
|
238
268
|
else
|
@@ -288,67 +318,82 @@ module Toys
|
|
288
318
|
end
|
289
319
|
|
290
320
|
def add_help_flags(tool_definition)
|
291
|
-
|
292
|
-
unless
|
321
|
+
flags = resolve_flags_spec(@help_flags, tool_definition, DEFAULT_HELP_FLAGS)
|
322
|
+
unless flags.empty?
|
293
323
|
tool_definition.add_flag(
|
294
|
-
SHOW_HELP_KEY,
|
324
|
+
SHOW_HELP_KEY, flags,
|
295
325
|
report_collisions: false,
|
296
326
|
desc: "Display help for this tool"
|
297
327
|
)
|
298
328
|
end
|
299
|
-
|
329
|
+
flags
|
300
330
|
end
|
301
331
|
|
302
332
|
def add_usage_flags(tool_definition)
|
303
|
-
|
304
|
-
unless
|
333
|
+
flags = resolve_flags_spec(@usage_flags, tool_definition, DEFAULT_USAGE_FLAGS)
|
334
|
+
unless flags.empty?
|
305
335
|
tool_definition.add_flag(
|
306
|
-
SHOW_USAGE_KEY,
|
336
|
+
SHOW_USAGE_KEY, flags,
|
307
337
|
report_collisions: false,
|
308
338
|
desc: "Display a brief usage string for this tool"
|
309
339
|
)
|
310
340
|
end
|
311
|
-
|
341
|
+
flags
|
312
342
|
end
|
313
343
|
|
314
344
|
def add_list_flags(tool_definition)
|
315
|
-
|
316
|
-
unless
|
345
|
+
flags = resolve_flags_spec(@list_flags, tool_definition, DEFAULT_LIST_FLAGS)
|
346
|
+
unless flags.empty?
|
317
347
|
tool_definition.add_flag(
|
318
|
-
SHOW_LIST_KEY,
|
348
|
+
SHOW_LIST_KEY, flags,
|
319
349
|
report_collisions: false,
|
320
350
|
desc: "List the subtools under this tool"
|
321
351
|
)
|
322
352
|
end
|
323
|
-
|
353
|
+
flags
|
324
354
|
end
|
325
355
|
|
326
356
|
def add_recursive_flags(tool_definition)
|
327
|
-
|
328
|
-
|
329
|
-
if recursive_flags.empty?
|
357
|
+
flags = resolve_flags_spec(@recursive_flags, tool_definition, DEFAULT_RECURSIVE_FLAGS)
|
358
|
+
if flags.empty?
|
330
359
|
tool_definition.default_data[RECURSIVE_SUBTOOLS_KEY] = @default_recursive
|
331
360
|
else
|
332
361
|
tool_definition.add_flag(
|
333
|
-
RECURSIVE_SUBTOOLS_KEY,
|
362
|
+
RECURSIVE_SUBTOOLS_KEY, flags,
|
334
363
|
report_collisions: false, default: @default_recursive,
|
335
364
|
desc: "List all subtools recursively when displaying help" \
|
336
365
|
" (default is #{@default_recursive})"
|
337
366
|
)
|
338
367
|
end
|
339
|
-
|
368
|
+
flags
|
340
369
|
end
|
341
370
|
|
342
371
|
def add_search_flags(tool_definition)
|
343
|
-
|
344
|
-
unless
|
372
|
+
flags = resolve_flags_spec(@search_flags, tool_definition, DEFAULT_SEARCH_FLAGS)
|
373
|
+
unless flags.empty?
|
345
374
|
tool_definition.add_flag(
|
346
|
-
SEARCH_STRING_KEY,
|
375
|
+
SEARCH_STRING_KEY, flags,
|
347
376
|
report_collisions: false,
|
348
377
|
desc: "Search subtools for the given regular expression when displaying help"
|
349
378
|
)
|
350
379
|
end
|
351
|
-
|
380
|
+
flags
|
381
|
+
end
|
382
|
+
|
383
|
+
def add_show_all_subtools_flags(tool_definition)
|
384
|
+
flags = resolve_flags_spec(@show_all_subtools_flags, tool_definition,
|
385
|
+
DEFAULT_SHOW_ALL_SUBTOOLS_FLAGS)
|
386
|
+
if flags.empty?
|
387
|
+
tool_definition.default_data[SHOW_ALL_SUBTOOLS_KEY] = @default_show_all_subtools
|
388
|
+
else
|
389
|
+
tool_definition.add_flag(
|
390
|
+
SHOW_ALL_SUBTOOLS_KEY, flags,
|
391
|
+
report_collisions: false, default: @default_show_all_subtools,
|
392
|
+
desc: "List all subtools including hidden subtools and namespaces" \
|
393
|
+
" (default is #{@default_show_all_subtools})"
|
394
|
+
)
|
395
|
+
end
|
396
|
+
flags
|
352
397
|
end
|
353
398
|
|
354
399
|
def add_root_args(tool_definition)
|
data/lib/toys/tool.rb
CHANGED
@@ -78,6 +78,13 @@ module Toys
|
|
78
78
|
#
|
79
79
|
TOOL_DEFINITION = ::Object.new.freeze
|
80
80
|
|
81
|
+
##
|
82
|
+
# Context key for the `Toys::Definition::SourceInfo` describing the
|
83
|
+
# source of this tool.
|
84
|
+
# @return [Object]
|
85
|
+
#
|
86
|
+
TOOL_SOURCE = ::Object.new.freeze
|
87
|
+
|
81
88
|
##
|
82
89
|
# Context key for the full name of the tool being executed. Value is an
|
83
90
|
# array of strings.
|
@@ -159,6 +166,14 @@ module Toys
|
|
159
166
|
@__data[Keys::TOOL_DEFINITION]
|
160
167
|
end
|
161
168
|
|
169
|
+
##
|
170
|
+
# Return the source of the tool being executed.
|
171
|
+
# @return [Toys::Definition::SourceInfo]
|
172
|
+
#
|
173
|
+
def tool_source
|
174
|
+
@__data[Keys::TOOL_SOURCE]
|
175
|
+
end
|
176
|
+
|
162
177
|
##
|
163
178
|
# Return the name of the tool being executed, as an array of strings.
|
164
179
|
# @return [Array[String]]
|
@@ -268,7 +283,20 @@ module Toys
|
|
268
283
|
# @return [String,nil] Absolute path of the result, or nil if not found.
|
269
284
|
#
|
270
285
|
def find_data(path, type: nil)
|
271
|
-
@__data[Keys::
|
286
|
+
@__data[Keys::TOOL_SOURCE].find_data(path, type: type)
|
287
|
+
end
|
288
|
+
|
289
|
+
##
|
290
|
+
# Return the context directory for this tool. Generally, this defaults
|
291
|
+
# to the directory containing the toys config directory structure being
|
292
|
+
# read, but it may be changed by setting a different context directory
|
293
|
+
# for the tool.
|
294
|
+
# May return nil if there is no context.
|
295
|
+
#
|
296
|
+
# @return [String,nil] Context directory
|
297
|
+
#
|
298
|
+
def context_directory
|
299
|
+
@__data[Keys::TOOL_DEFINITION].context_directory
|
272
300
|
end
|
273
301
|
|
274
302
|
##
|
data/lib/toys/utils/help_text.rb
CHANGED
@@ -83,7 +83,9 @@ module Toys
|
|
83
83
|
# Generate a short usage string.
|
84
84
|
#
|
85
85
|
# @param [Boolean] recursive If true, and the tool is a namespace,
|
86
|
-
# display all
|
86
|
+
# display all subtools recursively. Defaults to false.
|
87
|
+
# @param [Boolean] include_hidden Include hidden subtools (i.e. whose
|
88
|
+
# names begin with underscore.) Default is false.
|
87
89
|
# @param [Integer] left_column_width Width of the first column. Default
|
88
90
|
# is {DEFAULT_LEFT_COLUMN_WIDTH}.
|
89
91
|
# @param [Integer] indent Indent width. Default is {DEFAULT_INDENT}.
|
@@ -92,10 +94,11 @@ module Toys
|
|
92
94
|
#
|
93
95
|
# @return [String] A usage string.
|
94
96
|
#
|
95
|
-
def usage_string(recursive: false,
|
97
|
+
def usage_string(recursive: false, include_hidden: false,
|
98
|
+
left_column_width: nil, indent: nil, wrap_width: nil)
|
96
99
|
left_column_width ||= DEFAULT_LEFT_COLUMN_WIDTH
|
97
100
|
indent ||= DEFAULT_INDENT
|
98
|
-
subtools = find_subtools(recursive, nil)
|
101
|
+
subtools = find_subtools(recursive, nil, include_hidden)
|
99
102
|
assembler = UsageStringAssembler.new(@tool, @binary_name, subtools,
|
100
103
|
indent, left_column_width, wrap_width)
|
101
104
|
assembler.result
|
@@ -105,9 +108,11 @@ module Toys
|
|
105
108
|
# Generate a long help string.
|
106
109
|
#
|
107
110
|
# @param [Boolean] recursive If true, and the tool is a namespace,
|
108
|
-
# display all
|
111
|
+
# display all subtools recursively. Defaults to false.
|
109
112
|
# @param [String,nil] search An optional string to search for when
|
110
|
-
# listing
|
113
|
+
# listing subtools. Defaults to `nil` which finds all subtools.
|
114
|
+
# @param [Boolean] include_hidden Include hidden subtools (i.e. whose
|
115
|
+
# names begin with underscore.) Default is false.
|
111
116
|
# @param [Boolean] show_source_path If true, shows the source path
|
112
117
|
# section. Defaults to false.
|
113
118
|
# @param [Integer] indent Indent width. Default is {DEFAULT_INDENT}.
|
@@ -119,11 +124,12 @@ module Toys
|
|
119
124
|
#
|
120
125
|
# @return [String] A usage string.
|
121
126
|
#
|
122
|
-
def help_string(recursive: false, search: nil,
|
127
|
+
def help_string(recursive: false, search: nil, include_hidden: false,
|
128
|
+
show_source_path: false,
|
123
129
|
indent: nil, indent2: nil, wrap_width: nil, styled: true)
|
124
130
|
indent ||= DEFAULT_INDENT
|
125
131
|
indent2 ||= DEFAULT_INDENT
|
126
|
-
subtools = find_subtools(recursive, search)
|
132
|
+
subtools = find_subtools(recursive, search, include_hidden)
|
127
133
|
assembler = HelpStringAssembler.new(@tool, @binary_name, subtools, search, show_source_path,
|
128
134
|
indent, indent2, wrap_width, styled)
|
129
135
|
assembler.result
|
@@ -133,9 +139,11 @@ module Toys
|
|
133
139
|
# Generate a subtool list string.
|
134
140
|
#
|
135
141
|
# @param [Boolean] recursive If true, and the tool is a namespace,
|
136
|
-
# display all
|
142
|
+
# display all subtools recursively. Defaults to false.
|
137
143
|
# @param [String,nil] search An optional string to search for when
|
138
|
-
# listing
|
144
|
+
# listing subtools. Defaults to `nil` which finds all subtools.
|
145
|
+
# @param [Boolean] include_hidden Include hidden subtools (i.e. whose
|
146
|
+
# names begin with underscore.) Default is false.
|
139
147
|
# @param [Integer] indent Indent width. Default is {DEFAULT_INDENT}.
|
140
148
|
# @param [Integer,nil] wrap_width Wrap width of the column, or `nil` to
|
141
149
|
# disable wrap. Default is `nil`.
|
@@ -143,10 +151,10 @@ module Toys
|
|
143
151
|
#
|
144
152
|
# @return [String] A usage string.
|
145
153
|
#
|
146
|
-
def list_string(recursive: false, search: nil,
|
154
|
+
def list_string(recursive: false, search: nil, include_hidden: false,
|
147
155
|
indent: nil, wrap_width: nil, styled: true)
|
148
156
|
indent ||= DEFAULT_INDENT
|
149
|
-
subtools = find_subtools(recursive, search)
|
157
|
+
subtools = find_subtools(recursive, search, include_hidden)
|
150
158
|
assembler = ListStringAssembler.new(@tool, subtools, recursive, search,
|
151
159
|
indent, wrap_width, styled)
|
152
160
|
assembler.result
|
@@ -154,8 +162,9 @@ module Toys
|
|
154
162
|
|
155
163
|
private
|
156
164
|
|
157
|
-
def find_subtools(recursive, search)
|
158
|
-
subtools = @loader.list_subtools(@tool.full_name,
|
165
|
+
def find_subtools(recursive, search, include_hidden)
|
166
|
+
subtools = @loader.list_subtools(@tool.full_name,
|
167
|
+
recursive: recursive, include_hidden: include_hidden)
|
159
168
|
return subtools if search.nil? || search.empty?
|
160
169
|
regex = ::Regexp.new(search, ::Regexp::IGNORECASE)
|
161
170
|
subtools.find_all do |tool|
|
@@ -387,10 +396,10 @@ module Toys
|
|
387
396
|
end
|
388
397
|
|
389
398
|
def add_source_section
|
390
|
-
return unless @
|
399
|
+
return unless @show_source_path && @tool.source_info&.source_name
|
391
400
|
@lines << ""
|
392
401
|
@lines << bold("SOURCE")
|
393
|
-
@lines << indent_str("Defined in #{@tool.
|
402
|
+
@lines << indent_str("Defined in #{@tool.source_info.source_name}")
|
394
403
|
end
|
395
404
|
|
396
405
|
def add_description_section
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: toys-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
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-10-
|
11
|
+
date: 2018-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.59.
|
89
|
+
version: 0.59.2
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.59.
|
96
|
+
version: 0.59.2
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: yard
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -127,8 +127,8 @@ files:
|
|
127
127
|
- lib/toys/definition/acceptor.rb
|
128
128
|
- lib/toys/definition/alias.rb
|
129
129
|
- lib/toys/definition/arg.rb
|
130
|
-
- lib/toys/definition/data_finder.rb
|
131
130
|
- lib/toys/definition/flag.rb
|
131
|
+
- lib/toys/definition/source_info.rb
|
132
132
|
- lib/toys/definition/tool.rb
|
133
133
|
- lib/toys/dsl/arg.rb
|
134
134
|
- lib/toys/dsl/flag.rb
|
@@ -1,108 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
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.
|
30
|
-
;
|
31
|
-
|
32
|
-
module Toys
|
33
|
-
module Definition
|
34
|
-
##
|
35
|
-
# Finds data files.
|
36
|
-
#
|
37
|
-
class DataFinder
|
38
|
-
##
|
39
|
-
# Create a new finder.
|
40
|
-
#
|
41
|
-
# @param [String,nil] data_name Name of the data directory, or nil if
|
42
|
-
# data directories are disabled.
|
43
|
-
# @param [Toys::Definition::DataFinder,nil] parent The parent, or nil if
|
44
|
-
# this is the root.
|
45
|
-
# @param [String,nil] directory The data directory, or nil for none.
|
46
|
-
# @private
|
47
|
-
#
|
48
|
-
def initialize(data_name, parent, directory)
|
49
|
-
@data_name = data_name
|
50
|
-
@parent = parent
|
51
|
-
@directory = directory
|
52
|
-
end
|
53
|
-
|
54
|
-
##
|
55
|
-
# Create a new finder for the given directory.
|
56
|
-
#
|
57
|
-
# @param [String] directory Toys directory path
|
58
|
-
# @return [Toys::Definition::DataFinder] The finder
|
59
|
-
#
|
60
|
-
def finder_for(directory)
|
61
|
-
return self if @data_name.nil?
|
62
|
-
directory = ::File.join(directory, @data_name)
|
63
|
-
return self unless ::File.directory?(directory)
|
64
|
-
DataFinder.new(@data_name, self, directory)
|
65
|
-
end
|
66
|
-
|
67
|
-
##
|
68
|
-
# Return the absolute path to the given data file or directory.
|
69
|
-
#
|
70
|
-
# @param [String] path The relative path to find
|
71
|
-
# @param [nil,:file,:directory] type Type of file system object to find,
|
72
|
-
# or nil to return any type.
|
73
|
-
# @return [String,nil] Absolute path of the result, or nil if not found.
|
74
|
-
#
|
75
|
-
def find_data(path, type: nil)
|
76
|
-
return nil if @directory.nil?
|
77
|
-
full_path = ::File.join(@directory, path)
|
78
|
-
case type
|
79
|
-
when :file
|
80
|
-
return full_path if ::File.file?(full_path)
|
81
|
-
when :directory
|
82
|
-
return full_path if ::File.directory?(full_path)
|
83
|
-
else
|
84
|
-
return full_path if ::File.readable?(full_path)
|
85
|
-
end
|
86
|
-
@parent.find_data(path, type: type)
|
87
|
-
end
|
88
|
-
|
89
|
-
##
|
90
|
-
# Create an empty finder.
|
91
|
-
#
|
92
|
-
# @param [String,nil] data_name Name of the data directory, or nil if
|
93
|
-
# data directories are disabled.
|
94
|
-
# @return [Toys::Definition::DataFinder]
|
95
|
-
#
|
96
|
-
def self.create_empty(data_name)
|
97
|
-
new(data_name, nil, nil)
|
98
|
-
end
|
99
|
-
|
100
|
-
##
|
101
|
-
# A default empty finder.
|
102
|
-
#
|
103
|
-
# @return [Toys::Definition::DataFinder]
|
104
|
-
#
|
105
|
-
EMPTY = create_empty(nil)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|