toys 0.3.0 → 0.3.1

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.
@@ -30,19 +30,45 @@
30
30
  module Toys
31
31
  module Utils
32
32
  ##
33
- # Helper that generates usage text
33
+ # A helper class that generates usage documentation for a tool.
34
+ #
35
+ # This class generates full usage documentation, including description,
36
+ # switches, and arguments. It is used by middleware that implements help
37
+ # and related options.
34
38
  #
35
39
  class Usage
40
+ ##
41
+ # Create a usage helper given an execution context.
42
+ #
43
+ # @param [Toys::Context] context The current execution context.
44
+ # @return [Toys::Utils::Usage]
45
+ #
36
46
  def self.from_context(context)
37
47
  new(context[Context::TOOL], context[Context::BINARY_NAME], context[Context::LOADER])
38
48
  end
39
49
 
50
+ ##
51
+ # Create a usage helper.
52
+ #
53
+ # @param [Toys::Tool] tool The tool for which to generate documentation.
54
+ # @param [String] binary_name The name of the binary. e.g. `"toys"`.
55
+ # @param [Toys::Loader] loader A loader that can provide subcommands.
56
+ #
57
+ # @return [Toys::Utils::Usage]
58
+ #
40
59
  def initialize(tool, binary_name, loader)
41
60
  @tool = tool
42
61
  @binary_name = binary_name
43
62
  @loader = loader
44
63
  end
45
64
 
65
+ ##
66
+ # Generate a usage string.
67
+ #
68
+ # @param [Boolean] recursive If true, and the tool is a group tool,
69
+ # display all subcommands recursively. Defaults to false.
70
+ # @return [String] A usage string.
71
+ #
46
72
  def string(recursive: false)
47
73
  optparse = ::OptionParser.new
48
74
  optparse.banner = @tool.includes_executor? ? tool_banner : group_banner
@@ -61,37 +87,51 @@ module Toys
61
87
 
62
88
  private
63
89
 
90
+ #
91
+ # Returns the banner string for a normal tool
92
+ #
64
93
  def tool_banner
65
94
  banner = ["Usage:", @binary_name] + @tool.full_name
66
- banner << "[<options...>]" unless @tool.switches.empty?
67
- @tool.required_args.each do |arg_info|
95
+ banner << "[<options...>]" unless @tool.switch_definitions.empty?
96
+ @tool.required_arg_definitions.each do |arg_info|
68
97
  banner << "<#{arg_info.canonical_name}>"
69
98
  end
70
- @tool.optional_args.each do |arg_info|
99
+ @tool.optional_arg_definitions.each do |arg_info|
71
100
  banner << "[<#{arg_info.canonical_name}>]"
72
101
  end
73
- if @tool.remaining_args
74
- banner << "[<#{@tool.remaining_args.canonical_name}...>]"
102
+ if @tool.remaining_args_definition
103
+ banner << "[<#{@tool.remaining_args_definition.canonical_name}...>]"
75
104
  end
76
105
  banner.join(" ")
77
106
  end
78
107
 
108
+ #
109
+ # Returns the banner string for a group
110
+ #
79
111
  def group_banner
80
112
  (["Usage:", @binary_name] + @tool.full_name + ["<command>", "[<options...>]"]).join(" ")
81
113
  end
82
114
 
115
+ #
116
+ # Add switches from the tool to the given optionparser. Causes the
117
+ # optparser to generate documentation for those switches.
118
+ #
83
119
  def add_switches(optparse)
84
- return if @tool.switches.empty?
120
+ return if @tool.switch_definitions.empty?
85
121
  optparse.separator("")
86
122
  optparse.separator("Options:")
87
- @tool.switches.each do |switch|
123
+ @tool.switch_definitions.each do |switch|
88
124
  optparse.on(*switch.optparse_info)
89
125
  end
90
126
  end
91
127
 
128
+ #
129
+ # Add documentation for the tool's positional arguments, to the given
130
+ # option parser.
131
+ #
92
132
  def add_positional_arguments(optparse)
93
- args_to_display = @tool.required_args + @tool.optional_args
94
- args_to_display << @tool.remaining_args if @tool.remaining_args
133
+ args_to_display = @tool.required_arg_definitions + @tool.optional_arg_definitions
134
+ args_to_display << @tool.remaining_args_definition if @tool.remaining_args_definition
95
135
  return if args_to_display.empty?
96
136
  optparse.separator("")
97
137
  optparse.separator("Positional arguments:")
@@ -103,9 +143,13 @@ module Toys
103
143
  end
104
144
  end
105
145
 
146
+ #
147
+ # Add documentation for the tool's subcommands, to the given option
148
+ # parser.
149
+ #
106
150
  def add_command_list(optparse, recursive)
107
151
  name_len = @tool.full_name.length
108
- subtools = @loader.list_subtools(@tool.full_name, recursive)
152
+ subtools = @loader.list_subtools(@tool.full_name, recursive: recursive)
109
153
  return if subtools.empty?
110
154
  optparse.separator("")
111
155
  optparse.separator("Commands:")
@@ -32,5 +32,5 @@ module Toys
32
32
  # Current version of Toys
33
33
  # @return [String]
34
34
  #
35
- VERSION = "0.3.0".freeze
35
+ VERSION = "0.3.1".freeze
36
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toys
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
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-05-01 00:00:00.000000000 Z
11
+ date: 2018-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -88,15 +88,16 @@ executables:
88
88
  extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
+ - ".yardopts"
91
92
  - CHANGELOG.md
92
93
  - LICENSE.md
93
94
  - README.md
94
95
  - bin/toys
95
96
  - lib/toys.rb
96
- - lib/toys/builder.rb
97
97
  - lib/toys/builtins/do.rb
98
98
  - lib/toys/builtins/system.rb
99
99
  - lib/toys/cli.rb
100
+ - lib/toys/config_dsl.rb
100
101
  - lib/toys/context.rb
101
102
  - lib/toys/errors.rb
102
103
  - lib/toys/helpers.rb
@@ -105,9 +106,9 @@ files:
105
106
  - lib/toys/loader.rb
106
107
  - lib/toys/middleware.rb
107
108
  - lib/toys/middleware/base.rb
108
- - lib/toys/middleware/group_default.rb
109
109
  - lib/toys/middleware/set_verbosity.rb
110
- - lib/toys/middleware/show_tool_help.rb
110
+ - lib/toys/middleware/show_group_usage.rb
111
+ - lib/toys/middleware/show_tool_usage.rb
111
112
  - lib/toys/middleware/show_usage_errors.rb
112
113
  - lib/toys/template.rb
113
114
  - lib/toys/templates.rb
@@ -1,227 +0,0 @@
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
- ##
32
- # The object context in effect in a toys configuration file
33
- #
34
- class Builder
35
- def initialize(path, tool, remaining_words, priority, loader, type)
36
- @path = path
37
- @tool = tool
38
- @remaining_words = remaining_words
39
- @priority = priority
40
- @loader = loader
41
- @type = type
42
- end
43
-
44
- def tool(word, alias_of: nil, &block)
45
- word = word.to_s
46
- subtool = @loader.get_tool(@tool.full_name + [word], @priority, assume_parent: true)
47
- return self if subtool.nil?
48
- if alias_of
49
- if block
50
- raise ToolDefinitionError, "Cannot take a block with alias_of"
51
- end
52
- subtool.make_alias_of_word(alias_of.to_s)
53
- return self
54
- end
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)
75
- self
76
- end
77
-
78
- def alias_as(word)
79
- if @tool.root?
80
- raise ToolDefinitionError, "Cannot make an alias of the root tool"
81
- end
82
- if @type == :group || @type == :append
83
- raise ToolDefinitionError, "Cannot make an alias of a group"
84
- end
85
- alias_name = @tool.full_name.slice(0..-2) + [word.to_s]
86
- alias_tool = @loader.get_tool(alias_name, @priority)
87
- alias_tool.make_alias_of(@tool.simple_name) if alias_tool
88
- self
89
- end
90
-
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
98
- @tool.make_alias_of(word.to_s)
99
- self
100
- end
101
-
102
- def include(path)
103
- @tool.yield_definition do
104
- @loader.include_path(path, @tool.full_name, @remaining_words, @priority)
105
- end
106
- self
107
- end
108
-
109
- def expand(template_class, *args)
110
- unless template_class.is_a?(::Class)
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
116
- end
117
- template = template_class.new(*args)
118
- yield template if block_given?
119
- instance_exec(template, &template_class.expander)
120
- self
121
- end
122
-
123
- def long_desc(desc)
124
- if @type == :append
125
- raise ToolDefinitionError, "Cannot set the description when appending"
126
- end
127
- @tool.long_desc = desc
128
- self
129
- end
130
-
131
- def desc(desc)
132
- if @type == :append
133
- raise ToolDefinitionError, "Cannot set the description when appending"
134
- end
135
- @tool.desc = desc
136
- self
137
- end
138
- alias short_desc desc
139
-
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)
148
- self
149
- end
150
-
151
- def required_arg(key, accept: nil, doc: nil)
152
- if @type == :append
153
- raise ToolDefinitionError, "Cannot add an argument when appending"
154
- end
155
- @tool.add_required_arg(key, accept: accept, doc: doc)
156
- self
157
- end
158
-
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
163
- @tool.add_optional_arg(key, accept: accept, default: default, doc: doc)
164
- self
165
- end
166
-
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
171
- @tool.set_remaining_args(key, accept: accept, default: default, doc: doc)
172
- self
173
- end
174
-
175
- def execute(&block)
176
- if @type == :group || @type == :append
177
- raise ToolDefinitionError, "Cannot set the executor of a group"
178
- end
179
- @tool.executor = block
180
- self
181
- end
182
-
183
- def helper(name, &block)
184
- if @type == :group || @type == :append
185
- raise ToolDefinitionError, "Cannot define a helper method to a group"
186
- end
187
- @tool.add_helper(name, &block)
188
- self
189
- end
190
-
191
- def use(mod)
192
- if @type == :group || @type == :append
193
- raise ToolDefinitionError, "Cannot use a helper module in a group"
194
- end
195
- @tool.use_module(mod)
196
- self
197
- end
198
-
199
- def _binding
200
- binding
201
- end
202
-
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
211
- end
212
- end
213
- tool
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
226
- end
227
- end