toys 0.2.2 → 0.3.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 +5 -5
- data/CHANGELOG.md +5 -0
- data/README.md +8 -0
- data/lib/toys.rb +6 -8
- data/lib/toys/builder.rb +95 -30
- data/lib/toys/builtins/do.rb +44 -0
- data/lib/toys/builtins/system.rb +5 -5
- data/lib/toys/cli.rb +46 -18
- data/lib/toys/context.rb +109 -21
- data/lib/toys/helpers.rb +41 -0
- data/lib/toys/helpers/exec.rb +211 -201
- data/lib/toys/helpers/file_utils.rb +7 -5
- data/lib/toys/{lookup.rb → loader.rb} +29 -18
- data/lib/toys/middleware.rb +41 -0
- data/lib/toys/middleware/base.rb +45 -0
- data/lib/toys/middleware/group_default.rb +57 -0
- data/lib/toys/middleware/set_verbosity.rb +51 -0
- data/lib/toys/middleware/show_tool_help.rb +57 -0
- data/lib/toys/middleware/show_usage_errors.rb +51 -0
- data/lib/toys/templates.rb +41 -0
- data/lib/toys/templates/clean.rb +28 -26
- data/lib/toys/templates/gem_build.rb +51 -49
- data/lib/toys/templates/minitest.rb +48 -42
- data/lib/toys/templates/rubocop.rb +28 -26
- data/lib/toys/templates/yardoc.rb +39 -37
- data/lib/toys/tool.rb +200 -294
- data/lib/toys/utils/module_lookup.rb +101 -0
- data/lib/toys/utils/usage.rb +119 -0
- data/lib/toys/version.rb +1 -1
- metadata +20 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e1303b77289f7e37c45866ec22513df6187556c2d7188b97d2706731b73377c5
|
4
|
+
data.tar.gz: 31c4013f235e7fb83575c9b031798dc410ab0bdee2395303f3f54e54fc870c05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8389b529719c6135483a52a65ec2521e90964be02fac0da56fa7016672da8f4f9a8f7ad24c8a0493db8558040c3c80e47553656f3a567524f4a7e310669cd05a
|
7
|
+
data.tar.gz: 708270b18a969b0adb5aa16c9b517966d82a3531a4a88604b7ee3cae27ecb67c839ef40318378c89d6a3347658c6d3fe590a6482177d0a899d96eaf0847f6366
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -27,6 +27,14 @@ guidelines will be provided when the software stabilizes further.
|
|
27
27
|
The source can be found on Github at
|
28
28
|
[https://github.com/dazuma/toys](https://github.com/dazuma/toys)
|
29
29
|
|
30
|
+
### TODO items
|
31
|
+
|
32
|
+
* Document methods
|
33
|
+
* Write overall documentation
|
34
|
+
* Decide about highline integration
|
35
|
+
* Output formats middleware
|
36
|
+
* System paths tool
|
37
|
+
|
30
38
|
## License
|
31
39
|
|
32
40
|
Copyright 2018 Daniel Azuma
|
data/lib/toys.rb
CHANGED
@@ -35,21 +35,19 @@
|
|
35
35
|
#
|
36
36
|
module Toys
|
37
37
|
##
|
38
|
-
# Namespace for common
|
38
|
+
# Namespace for common utility classes
|
39
39
|
#
|
40
|
-
module
|
41
|
-
|
42
|
-
##
|
43
|
-
# Namespace for common templates
|
44
|
-
#
|
45
|
-
module Templates; end
|
40
|
+
module Utils; end
|
46
41
|
end
|
47
42
|
|
48
43
|
require "toys/builder"
|
49
44
|
require "toys/cli"
|
50
45
|
require "toys/context"
|
51
46
|
require "toys/errors"
|
52
|
-
require "toys/
|
47
|
+
require "toys/helpers"
|
48
|
+
require "toys/loader"
|
49
|
+
require "toys/middleware"
|
53
50
|
require "toys/template"
|
51
|
+
require "toys/templates"
|
54
52
|
require "toys/tool"
|
55
53
|
require "toys/version"
|
data/lib/toys/builder.rb
CHANGED
@@ -32,17 +32,18 @@ module Toys
|
|
32
32
|
# The object context in effect in a toys configuration file
|
33
33
|
#
|
34
34
|
class Builder
|
35
|
-
def initialize(path, tool, remaining_words, priority,
|
35
|
+
def initialize(path, tool, remaining_words, priority, loader, type)
|
36
36
|
@path = path
|
37
37
|
@tool = tool
|
38
38
|
@remaining_words = remaining_words
|
39
39
|
@priority = priority
|
40
|
-
@
|
40
|
+
@loader = loader
|
41
|
+
@type = type
|
41
42
|
end
|
42
43
|
|
43
|
-
def
|
44
|
+
def tool(word, alias_of: nil, &block)
|
44
45
|
word = word.to_s
|
45
|
-
subtool = @
|
46
|
+
subtool = @loader.get_tool(@tool.full_name + [word], @priority, assume_parent: true)
|
46
47
|
return self if subtool.nil?
|
47
48
|
if alias_of
|
48
49
|
if block
|
@@ -51,8 +52,26 @@ module Toys
|
|
51
52
|
subtool.make_alias_of_word(alias_of.to_s)
|
52
53
|
return self
|
53
54
|
end
|
54
|
-
next_remaining =
|
55
|
-
Builder.build(@path, subtool, next_remaining, @priority, @
|
55
|
+
next_remaining = Loader.next_remaining_words(@remaining_words, word)
|
56
|
+
Builder.build(@path, subtool, next_remaining, @priority, @loader, block, :tool)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
alias name tool
|
60
|
+
|
61
|
+
def append(word, &block)
|
62
|
+
word = word.to_s
|
63
|
+
subtool = @loader.get_tool(@tool.full_name + [word], nil, assume_parent: true)
|
64
|
+
next_remaining = Loader.next_remaining_words(@remaining_words, word)
|
65
|
+
Builder.build(@path, subtool, next_remaining, @priority, @loader, block, :append)
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def group(word, &block)
|
70
|
+
word = word.to_s
|
71
|
+
subtool = @loader.get_tool(@tool.full_name + [word], @priority, assume_parent: true)
|
72
|
+
return self if subtool.nil?
|
73
|
+
next_remaining = Loader.next_remaining_words(@remaining_words, word)
|
74
|
+
Builder.build(@path, subtool, next_remaining, @priority, @loader, block, :group)
|
56
75
|
self
|
57
76
|
end
|
58
77
|
|
@@ -60,34 +79,40 @@ module Toys
|
|
60
79
|
if @tool.root?
|
61
80
|
raise ToolDefinitionError, "Cannot make an alias of the root tool"
|
62
81
|
end
|
82
|
+
if @type == :group || @type == :append
|
83
|
+
raise ToolDefinitionError, "Cannot make an alias of a group"
|
84
|
+
end
|
63
85
|
alias_name = @tool.full_name.slice(0..-2) + [word.to_s]
|
64
|
-
alias_tool = @
|
86
|
+
alias_tool = @loader.get_tool(alias_name, @priority)
|
65
87
|
alias_tool.make_alias_of(@tool.simple_name) if alias_tool
|
66
88
|
self
|
67
89
|
end
|
68
90
|
|
69
91
|
def alias_of(word)
|
92
|
+
if @tool.root?
|
93
|
+
raise ToolDefinitionError, "Cannot make the root tool an alias"
|
94
|
+
end
|
95
|
+
if @type == :group || @type == :append
|
96
|
+
raise ToolDefinitionError, "Cannot make a group an alias"
|
97
|
+
end
|
70
98
|
@tool.make_alias_of(word.to_s)
|
71
99
|
self
|
72
100
|
end
|
73
101
|
|
74
102
|
def include(path)
|
75
103
|
@tool.yield_definition do
|
76
|
-
@
|
104
|
+
@loader.include_path(path, @tool.full_name, @remaining_words, @priority)
|
77
105
|
end
|
78
106
|
self
|
79
107
|
end
|
80
108
|
|
81
109
|
def expand(template_class, *args)
|
82
110
|
unless template_class.is_a?(::Class)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
require "toys/templates/#{file_name}"
|
89
|
-
const_name = template_class.gsub(/(^|_)([a-zA-Z0-9])/) { |_m| $2.upcase }
|
90
|
-
template_class = Templates.const_get(const_name)
|
111
|
+
name = template_class.to_s
|
112
|
+
template_class = Templates.lookup(name)
|
113
|
+
if template_class.nil?
|
114
|
+
raise ToolDefinitionError, "Template not found: #{name.inspect}"
|
115
|
+
end
|
91
116
|
end
|
92
117
|
template = template_class.new(*args)
|
93
118
|
yield template if block_given?
|
@@ -96,46 +121,77 @@ module Toys
|
|
96
121
|
end
|
97
122
|
|
98
123
|
def long_desc(desc)
|
124
|
+
if @type == :append
|
125
|
+
raise ToolDefinitionError, "Cannot set the description when appending"
|
126
|
+
end
|
99
127
|
@tool.long_desc = desc
|
100
128
|
self
|
101
129
|
end
|
102
130
|
|
103
|
-
def
|
104
|
-
@
|
131
|
+
def desc(desc)
|
132
|
+
if @type == :append
|
133
|
+
raise ToolDefinitionError, "Cannot set the description when appending"
|
134
|
+
end
|
135
|
+
@tool.desc = desc
|
105
136
|
self
|
106
137
|
end
|
138
|
+
alias short_desc desc
|
107
139
|
|
108
|
-
def switch(key, *switches,
|
109
|
-
|
140
|
+
def switch(key, *switches,
|
141
|
+
accept: nil, default: nil, doc: nil, only_unique: false, handler: nil)
|
142
|
+
if @type == :append
|
143
|
+
raise ToolDefinitionError, "Cannot add a switch when appending"
|
144
|
+
end
|
145
|
+
@tool.add_switch(key, *switches,
|
146
|
+
accept: accept, default: default, doc: doc,
|
147
|
+
only_unique: only_unique, handler: handler)
|
110
148
|
self
|
111
149
|
end
|
112
150
|
|
113
151
|
def required_arg(key, accept: nil, doc: nil)
|
152
|
+
if @type == :append
|
153
|
+
raise ToolDefinitionError, "Cannot add an argument when appending"
|
154
|
+
end
|
114
155
|
@tool.add_required_arg(key, accept: accept, doc: doc)
|
115
156
|
self
|
116
157
|
end
|
117
158
|
|
118
159
|
def optional_arg(key, accept: nil, default: nil, doc: nil)
|
160
|
+
if @type == :append
|
161
|
+
raise ToolDefinitionError, "Cannot add an argument when appending"
|
162
|
+
end
|
119
163
|
@tool.add_optional_arg(key, accept: accept, default: default, doc: doc)
|
120
164
|
self
|
121
165
|
end
|
122
166
|
|
123
167
|
def remaining_args(key, accept: nil, default: [], doc: nil)
|
168
|
+
if @type == :append
|
169
|
+
raise ToolDefinitionError, "Cannot add an argument when appending"
|
170
|
+
end
|
124
171
|
@tool.set_remaining_args(key, accept: accept, default: default, doc: doc)
|
125
172
|
self
|
126
173
|
end
|
127
174
|
|
128
175
|
def execute(&block)
|
176
|
+
if @type == :group || @type == :append
|
177
|
+
raise ToolDefinitionError, "Cannot set the executor of a group"
|
178
|
+
end
|
129
179
|
@tool.executor = block
|
130
180
|
self
|
131
181
|
end
|
132
182
|
|
133
183
|
def helper(name, &block)
|
184
|
+
if @type == :group || @type == :append
|
185
|
+
raise ToolDefinitionError, "Cannot define a helper method to a group"
|
186
|
+
end
|
134
187
|
@tool.add_helper(name, &block)
|
135
188
|
self
|
136
189
|
end
|
137
190
|
|
138
191
|
def use(mod)
|
192
|
+
if @type == :group || @type == :append
|
193
|
+
raise ToolDefinitionError, "Cannot use a helper module in a group"
|
194
|
+
end
|
139
195
|
@tool.use_module(mod)
|
140
196
|
self
|
141
197
|
end
|
@@ -144,19 +200,28 @@ module Toys
|
|
144
200
|
binding
|
145
201
|
end
|
146
202
|
|
147
|
-
def self.build(path, tool, remaining_words, priority,
|
148
|
-
builder = new(path, tool, remaining_words, priority,
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
when ::Proc
|
156
|
-
builder.instance_eval(&source)
|
203
|
+
def self.build(path, tool, remaining_words, priority, loader, source, type)
|
204
|
+
builder = new(path, tool, remaining_words, priority, loader, type)
|
205
|
+
if type == :append
|
206
|
+
eval_source(builder, path, source)
|
207
|
+
else
|
208
|
+
tool.defining_from(path) do
|
209
|
+
eval_source(builder, path, source)
|
210
|
+
tool.finish_definition
|
157
211
|
end
|
158
212
|
end
|
159
213
|
tool
|
160
214
|
end
|
215
|
+
|
216
|
+
def self.eval_source(builder, path, source)
|
217
|
+
case source
|
218
|
+
when String
|
219
|
+
# rubocop:disable Security/Eval
|
220
|
+
eval(source, builder._binding, path, 1)
|
221
|
+
# rubocop:enable Security/Eval
|
222
|
+
when ::Proc
|
223
|
+
builder.instance_eval(&source)
|
224
|
+
end
|
225
|
+
end
|
161
226
|
end
|
162
227
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Copyright 2018 Daniel Azuma
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
14
|
+
# contributors to this software, may be used to endorse or promote products
|
15
|
+
# derived from this software without specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
21
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
22
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
23
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
25
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
;
|
29
|
+
|
30
|
+
desc "Run multiple tools in order"
|
31
|
+
|
32
|
+
switch(:delim, "-d", "--delim=VALUE", default: ",", doc: "Set the delimiter")
|
33
|
+
|
34
|
+
remaining_args(:args)
|
35
|
+
|
36
|
+
execute do
|
37
|
+
delim = self[:delim]
|
38
|
+
self[:args]
|
39
|
+
.chunk { |arg| arg == delim ? :_separator : true }
|
40
|
+
.each do |_, action|
|
41
|
+
code = run(action)
|
42
|
+
exit(code) unless code.zero?
|
43
|
+
end
|
44
|
+
end
|
data/lib/toys/builtins/system.rb
CHANGED
@@ -27,18 +27,18 @@
|
|
27
27
|
# POSSIBILITY OF SUCH DAMAGE.
|
28
28
|
;
|
29
29
|
|
30
|
-
|
30
|
+
desc "A group of system commands for toys"
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
tool "version" do
|
33
|
+
desc "Print current toys version."
|
34
34
|
|
35
35
|
execute do
|
36
36
|
puts ::Toys::VERSION
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
tool "update" do
|
41
|
+
desc "Update toys if a newer version is available."
|
42
42
|
|
43
43
|
use :exec
|
44
44
|
|
data/lib/toys/cli.rb
CHANGED
@@ -64,34 +64,50 @@ module Toys
|
|
64
64
|
#
|
65
65
|
DEFAULT_BINARY_NAME = "toys".freeze
|
66
66
|
|
67
|
+
##
|
68
|
+
# Default help text for the root tool
|
69
|
+
# @return [String]
|
70
|
+
#
|
71
|
+
DEFAULT_ROOT_DESC =
|
72
|
+
"Toys is your personal command line tool. You can add to the list of" \
|
73
|
+
" commands below by writing scripts in Ruby using a simple DSL, and" \
|
74
|
+
" toys will organize and document them, and make them available" \
|
75
|
+
" globally or scoped to specific directories that you choose." \
|
76
|
+
" For detailed information, see https://www.rubydoc.info/gems/toys".freeze
|
77
|
+
|
67
78
|
def initialize(
|
68
79
|
binary_name: nil,
|
69
80
|
logger: nil,
|
70
81
|
config_dir_name: nil,
|
71
82
|
config_file_name: nil,
|
72
83
|
index_file_name: nil,
|
73
|
-
preload_file_name: nil
|
84
|
+
preload_file_name: nil,
|
85
|
+
middleware: [],
|
86
|
+
root_desc: nil
|
74
87
|
)
|
75
|
-
|
88
|
+
logger ||= self.class.default_logger
|
89
|
+
@loader = Loader.new(
|
76
90
|
config_dir_name: config_dir_name,
|
77
91
|
config_file_name: config_file_name,
|
78
92
|
index_file_name: index_file_name,
|
79
|
-
preload_file_name: preload_file_name
|
93
|
+
preload_file_name: preload_file_name,
|
94
|
+
middleware: middleware,
|
95
|
+
root_desc: root_desc
|
80
96
|
)
|
81
|
-
@context_base = Context::Base.new(@
|
97
|
+
@context_base = Context::Base.new(@loader, binary_name, logger)
|
82
98
|
end
|
83
99
|
|
84
|
-
def
|
85
|
-
@
|
100
|
+
def add_config_paths(paths)
|
101
|
+
@loader.add_config_paths(paths)
|
86
102
|
self
|
87
103
|
end
|
88
104
|
|
89
|
-
def
|
90
|
-
@
|
105
|
+
def add_paths(paths)
|
106
|
+
@loader.add_paths(paths)
|
91
107
|
self
|
92
108
|
end
|
93
109
|
|
94
|
-
def
|
110
|
+
def add_path_hierarchy(path = nil, base = "/")
|
95
111
|
path ||= ::Dir.pwd
|
96
112
|
paths = []
|
97
113
|
loop do
|
@@ -101,21 +117,22 @@ module Toys
|
|
101
117
|
break if next_path == path
|
102
118
|
path = next_path
|
103
119
|
end
|
104
|
-
@
|
120
|
+
@loader.add_paths(paths)
|
105
121
|
self
|
106
122
|
end
|
107
123
|
|
108
|
-
def
|
124
|
+
def add_standard_paths
|
109
125
|
toys_path = ::ENV["TOYS_PATH"].to_s.split(::File::PATH_SEPARATOR)
|
110
126
|
if toys_path.empty?
|
111
127
|
toys_path << ::ENV["HOME"] if ::ENV["HOME"]
|
112
|
-
toys_path << "/etc" if File.directory?("/etc") && ::File.readable?("/etc")
|
128
|
+
toys_path << "/etc" if ::File.directory?("/etc") && ::File.readable?("/etc")
|
113
129
|
end
|
114
|
-
@
|
130
|
+
@loader.add_paths(toys_path)
|
131
|
+
self
|
115
132
|
end
|
116
133
|
|
117
134
|
def run(*args)
|
118
|
-
@context_base.run(
|
135
|
+
exit(@context_base.run(args.flatten, verbosity: 0))
|
119
136
|
end
|
120
137
|
|
121
138
|
class << self
|
@@ -125,14 +142,25 @@ module Toys
|
|
125
142
|
config_dir_name: DEFAULT_DIR_NAME,
|
126
143
|
config_file_name: DEFAULT_FILE_NAME,
|
127
144
|
index_file_name: DEFAULT_FILE_NAME,
|
128
|
-
preload_file_name: DEFAULT_PRELOAD_NAME
|
145
|
+
preload_file_name: DEFAULT_PRELOAD_NAME,
|
146
|
+
middleware: default_middleware_stack,
|
147
|
+
root_desc: DEFAULT_ROOT_DESC
|
129
148
|
)
|
130
|
-
cli.
|
131
|
-
cli.
|
132
|
-
cli.
|
149
|
+
cli.add_path_hierarchy
|
150
|
+
cli.add_standard_paths
|
151
|
+
cli.add_config_paths(BUILTINS_PATH)
|
133
152
|
cli
|
134
153
|
end
|
135
154
|
|
155
|
+
def default_middleware_stack
|
156
|
+
[
|
157
|
+
Middleware.lookup(:show_usage_errors).new,
|
158
|
+
Middleware.lookup(:group_default).new,
|
159
|
+
Middleware.lookup(:show_tool_help).new,
|
160
|
+
Middleware.lookup(:set_verbosity).new
|
161
|
+
]
|
162
|
+
end
|
163
|
+
|
136
164
|
def default_logger
|
137
165
|
logger = ::Logger.new(::STDERR)
|
138
166
|
logger.formatter = proc do |severity, time, _progname, msg|
|