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