toys-core 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|