toys 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,9 +29,11 @@
29
29
 
30
30
  require "fileutils"
31
31
 
32
- module Toys::Helpers
33
- ##
34
- # File system utilities. See the "fileutils" standard library.
35
- #
36
- FileUtils = ::FileUtils
32
+ module Toys
33
+ module Helpers
34
+ ##
35
+ # File system utilities. See the "fileutils" standard library.
36
+ #
37
+ FileUtils = ::FileUtils
38
+ end
37
39
  end
@@ -31,45 +31,49 @@ module Toys
31
31
  ##
32
32
  # The lookup service that finds a tool given a set of arguments
33
33
  #
34
- class Lookup
34
+ class Loader
35
35
  def initialize(config_dir_name: nil, config_file_name: nil,
36
- index_file_name: nil, preload_file_name: nil)
36
+ index_file_name: nil, preload_file_name: nil,
37
+ middleware: [], root_desc: nil)
37
38
  @config_dir_name = config_dir_name
38
39
  @config_file_name = config_file_name
39
40
  @index_file_name = index_file_name
40
41
  @preload_file_name = preload_file_name
42
+ @middleware = middleware
41
43
  check_init_options
42
44
  @load_worklist = []
43
- @tools = {[] => [Tool.new(self, []), nil]}
45
+ root_tool = Tool.new([], middleware)
46
+ root_tool.long_desc = root_desc if root_desc
47
+ @tools = {[] => [root_tool, nil]}
44
48
  @max_priority = @min_priority = 0
45
49
  end
46
50
 
47
- def add_paths(paths, high_priority: false)
51
+ def add_config_paths(paths, high_priority: false)
48
52
  paths = Array(paths)
49
53
  paths = paths.reverse if high_priority
50
54
  paths.each do |path|
51
- add_path(path, high_priority: high_priority)
55
+ add_config_path(path, high_priority: high_priority)
52
56
  end
53
57
  self
54
58
  end
55
59
 
56
- def add_path(path, high_priority: false)
60
+ def add_config_path(path, high_priority: false)
57
61
  path = check_path(path)
58
62
  priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
59
63
  @load_worklist << [path, [], priority]
60
64
  self
61
65
  end
62
66
 
63
- def add_config_paths(paths, high_priority: false)
67
+ def add_paths(paths, high_priority: false)
64
68
  paths = Array(paths)
65
69
  paths = paths.reverse if high_priority
66
70
  paths.each do |path|
67
- add_config_path(path, high_priority: high_priority)
71
+ add_path(path, high_priority: high_priority)
68
72
  end
69
73
  self
70
74
  end
71
75
 
72
- def add_config_path(path, high_priority: false)
76
+ def add_path(path, high_priority: false)
73
77
  path = check_path(path, type: :dir)
74
78
  priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
75
79
  if @config_file_name
@@ -101,9 +105,9 @@ module Toys
101
105
  end
102
106
  end
103
107
 
104
- def execute(context_base, args)
108
+ def execute(context_base, args, verbosity: 0)
105
109
  tool = lookup(args)
106
- tool.execute(context_base, args.slice(tool.full_name.length..-1))
110
+ tool.execute(context_base, args.slice(tool.full_name.length..-1), verbosity: verbosity)
107
111
  end
108
112
 
109
113
  def exact_tool(words)
@@ -111,19 +115,26 @@ module Toys
111
115
  @tools[words].first
112
116
  end
113
117
 
114
- def get_tool(words, priority)
118
+ def get_tool(words, priority, assume_parent: false)
115
119
  if tool_defined?(words)
116
120
  tool, tool_priority = @tools[words]
117
- return tool if tool_priority.nil? || tool_priority == priority
121
+ return tool if priority.nil? || tool_priority.nil? || tool_priority == priority
118
122
  return nil if tool_priority > priority
119
123
  end
120
- parent = get_tool(words[0..-2], priority)
121
- return nil if parent.nil?
122
- tool = Tool.new(self, words)
124
+ unless assume_parent
125
+ parent = get_tool(words[0..-2], priority)
126
+ return nil if parent.nil?
127
+ end
128
+ tool = Tool.new(words, @middleware)
123
129
  @tools[words] = [tool, priority]
124
130
  tool
125
131
  end
126
132
 
133
+ def put_tool!(tool, priority = nil)
134
+ @tools[tool.full_name] = [tool, priority]
135
+ self
136
+ end
137
+
127
138
  def tool_defined?(words)
128
139
  @tools.key?(words)
129
140
  end
@@ -194,7 +205,7 @@ module Toys
194
205
  if ::File.extname(path) == ".rb"
195
206
  tool = get_tool(words, priority)
196
207
  if tool
197
- Builder.build(path, tool, remaining_words, priority, self, ::IO.read(path))
208
+ Builder.build(path, tool, remaining_words, priority, self, ::IO.read(path), :tool)
198
209
  end
199
210
  else
200
211
  require_preload_in(path)
@@ -225,7 +236,7 @@ module Toys
225
236
  child_path = check_path(::File.join(path, child))
226
237
  child_word = ::File.basename(child, ".rb")
227
238
  next_words = words + [child_word]
228
- next_remaining = Lookup.next_remaining_words(remaining_words, child_word)
239
+ next_remaining = Loader.next_remaining_words(remaining_words, child_word)
229
240
  handle_path(child_path, next_words, next_remaining, priority)
230
241
  end
231
242
 
@@ -0,0 +1,41 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/utils/module_lookup"
31
+
32
+ module Toys
33
+ ##
34
+ # Namespace for common middleware
35
+ #
36
+ module Middleware
37
+ def self.lookup(name)
38
+ Utils::ModuleLookup.lookup(:middleware, name)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ module Toys
31
+ module Middleware
32
+ ##
33
+ # A base middleware with a no-op implementation
34
+ #
35
+ class Base
36
+ def config(_tool)
37
+ yield
38
+ end
39
+
40
+ def execute(_context)
41
+ yield
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+ require "toys/utils/usage"
32
+
33
+ module Toys
34
+ module Middleware
35
+ ##
36
+ # A middleware that provides a default implementation for groups
37
+ #
38
+ class GroupDefault < Base
39
+ def config(tool)
40
+ if tool.includes_executor?
41
+ yield
42
+ else
43
+ tool.add_switch(:_recursive, "-r", "--[no-]recursive",
44
+ doc: "Show all subcommands recursively")
45
+ end
46
+ end
47
+
48
+ def execute(context)
49
+ if context[Context::TOOL].includes_executor?
50
+ yield
51
+ else
52
+ puts(Utils::Usage.from_context(context).string(recursive: context[:_recursive]))
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+
32
+ module Toys
33
+ module Middleware
34
+ ##
35
+ # A middleware that provides switches for editing the verbosity
36
+ #
37
+ class SetVerbosity < Base
38
+ def config(tool)
39
+ tool.add_switch(Context::VERBOSITY, "-v", "--verbose",
40
+ doc: "Increase verbosity",
41
+ handler: ->(_val, cur) { cur + 1 },
42
+ only_unique: true)
43
+ tool.add_switch(Context::VERBOSITY, "-q", "--quiet",
44
+ doc: "Decrease verbosity",
45
+ handler: ->(_val, cur) { cur - 1 },
46
+ only_unique: true)
47
+ yield
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+ require "toys/utils/usage"
32
+
33
+ module Toys
34
+ module Middleware
35
+ ##
36
+ # A middleware that shows usage documentation
37
+ #
38
+ class ShowToolHelp < Base
39
+ def config(tool)
40
+ if tool.includes_executor?
41
+ tool.add_switch(:_help, "-?", "--help",
42
+ doc: "Show help message",
43
+ only_unique: true)
44
+ end
45
+ yield
46
+ end
47
+
48
+ def execute(context)
49
+ if context[:_help]
50
+ puts(Utils::Usage.from_context(context).string(recursive: context[:_recursive]))
51
+ else
52
+ yield
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+ require "toys/utils/usage"
32
+
33
+ module Toys
34
+ module Middleware
35
+ ##
36
+ # A middleware that shows usage errors
37
+ #
38
+ class ShowUsageErrors < Base
39
+ def execute(context)
40
+ if context[Context::USAGE_ERROR]
41
+ puts(context[Context::USAGE_ERROR])
42
+ puts("")
43
+ puts(Utils::Usage.from_context(context).string)
44
+ context.exit(-1)
45
+ else
46
+ yield
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/utils/module_lookup"
31
+
32
+ module Toys
33
+ ##
34
+ # Namespace for common templates
35
+ #
36
+ module Templates
37
+ def self.lookup(name)
38
+ Utils::ModuleLookup.lookup(:templates, name)
39
+ end
40
+ end
41
+ end