groovenauts-thor 0.19.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 50bf117f0d68ddcfe5e636f1870b2fbd2dad3fef
4
+ data.tar.gz: 855428579e458e1ea6a90b31af2241225b2df5f1
5
+ SHA512:
6
+ metadata.gz: e972d72e4fb95c8d2ec7eeb7778c7ec827061712134202fb762aaca9e406d0fde272dd736cc2a141f32ea9ee46e7e4c8568bffc0ff45f2cea359d75a7df62d53
7
+ data.tar.gz: 5765b1f7284d310098ffcb9f2e7a76ff077d15ab85aec4e1a6fc9595d883b09f50fd8d2645de7c8823b59bf023fd147085b407392cb720459de3be692ba3be2c
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/*.rb
2
+ lib/**/*.rb
3
+ -
4
+ CHANGELOG.rdoc
5
+ LICENSE.md
data/CHANGELOG.md ADDED
@@ -0,0 +1,163 @@
1
+ ## 0.19.1, release 2014-03-24
2
+ * Fix `say` non-String break regression
3
+
4
+ ## 0.19.0, release 2014-03-22
5
+ * Add support for a default to #ask
6
+ * Avoid @namespace not initialized warning
7
+ * Avoid private attribute? warning
8
+ * Fix initializing with unknown options
9
+ * Loosen required_rubygems_version for compatibility with Ubuntu 10.04
10
+ * Shell#ask: support a noecho option for stdin
11
+ * Shell#ask: change API to be :echo => false
12
+ * Display a message without a stack trace for ambiguous commands
13
+ * Make say and say_status thread safe
14
+ * Dependency for console io version check
15
+ * Alias --help to help on subcommands
16
+ * Use mime-types 1.x for Ruby 1.8.7 compatibility for Ruby 1.8 only
17
+ * Accept .tt files as templates
18
+ * Check if numeric value is in enum
19
+ * Use Readline for user input
20
+ * Fix dispatching of subcommands (concerning :help and *args)
21
+ * Fix warnings when running specs with `$VERBOSE = true`
22
+ * Make subcommand help more consistent
23
+ * Make the current command chain accessible in command
24
+
25
+ ## 0.18.1, release 2013-03-30
26
+ * Revert regressions found in 0.18.0
27
+
28
+ ## 0.18.0, release 2013-03-26
29
+ * Remove rake2thor
30
+ * Only display colors if output medium supports colors
31
+ * Pass parent_options to subcommands
32
+ * Fix non-dash-prefixed aliases
33
+ * Make error messages more helpful
34
+ * Rename "task" to "command"
35
+ * Add the method to allow for custom package name
36
+
37
+ ## 0.17.0, release 2013-01-24
38
+ * Add better support for tasks that accept arbitrary additional arguments (e.g. things like `bundle exec`)
39
+ * Add #stop_on_unknown_option!
40
+ * Only strip from stdin.gets if it wasn't ended with EOF
41
+ * Allow "send" as a task name
42
+ * Allow passing options as arguments after "--"
43
+ * Autoload Thor::Group
44
+
45
+ ## 0.16.0, release 2012-08-14
46
+ * Add enum to string arguments
47
+
48
+ ## 0.15.4, release 2012-06-29
49
+ * Fix regression when destination root contains reserved regexp characters
50
+
51
+ ## 0.15.3, release 2012-06-18
52
+ * Support strict_args_position! for backwards compatibility
53
+ * Escape Dir glob characters in paths
54
+
55
+ ## 0.15.2, released 2012-05-07
56
+ * Added print_in_columns
57
+ * Exposed terminal_width as a public API
58
+
59
+ ## 0.15.1, release 2012-05-06
60
+ * Fix Ruby 1.8 truncation bug with unicode chars
61
+ * Fix shell delegate methods to pass their block
62
+ * Don't output trailing spaces when printing the last column in a table
63
+
64
+ ## 0.15, released 2012-04-29
65
+ * Alias method_options to options
66
+ * Refactor say to allow multiple colors
67
+ * Exposed error as a public API
68
+ * Exposed file_collision as a public API
69
+ * Exposed print_wrapped as a public API
70
+ * Exposed set_color as a public API
71
+ * Fix number-formatting bugs in print_table
72
+ * Fix "indent" typo in print_table
73
+ * Fix Errno::EPIPE when piping tasks to `head`
74
+ * More friendly error messages
75
+
76
+ ## 0.14, released 2010-07-25
77
+ * Added CreateLink class and #link_file method
78
+ * Made Thor::Actions#run use system as default method for system calls
79
+ * Allow use of private methods from superclass as tasks
80
+ * Added mute(&block) method which allows to run block without any output
81
+ * Removed config[:pretend]
82
+ * Enabled underscores for command line switches
83
+ * Added Thor::Base.basename which is used by both Thor.banner and Thor::Group.banner
84
+ * Deprecated invoke() without arguments
85
+ * Added :only and :except to check_unknown_options
86
+
87
+ ## 0.13, released 2010-02-03
88
+ * Added :lazy_default which is only triggered if a switch is given
89
+ * Added Thor::Shell::HTML
90
+ * Added subcommands
91
+ * Decoupled Thor::Group and Thor, so it's easier to vendor
92
+ * Added check_unknown_options! in case you want error messages to be raised in valid switches
93
+ * run(command) should return the results of command
94
+
95
+ ## 0.12, released 2010-01-02
96
+ * Methods generated by attr_* are automatically not marked as tasks
97
+ * inject_into_file does not add the same content twice, unless :force is set
98
+ * Removed rr in favor to rspec mock framework
99
+ * Improved output for thor -T
100
+ * [#7] Do not force white color on status
101
+ * [#8] Yield a block with the filename on directory
102
+
103
+ ## 0.11, released 2009-07-01
104
+ * Added a rake compatibility layer. It allows you to use spec and rdoc tasks on
105
+ Thor classes.
106
+ * BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
107
+ since it may cause wrong behavior in the invocation system.
108
+ * thor help now show information about any class/task. All those calls are
109
+ possible:
110
+
111
+ thor help describe
112
+ thor help describe:amazing
113
+ Or even with default namespaces:
114
+
115
+ thor help :spec
116
+ * Thor::Runner now invokes the default task if none is supplied:
117
+
118
+ thor describe # invokes the default task, usually help
119
+ * Thor::Runner now works with mappings:
120
+
121
+ thor describe -h
122
+ * Added some documentation and code refactoring.
123
+
124
+ ## 0.9.8, released 2008-10-20
125
+ * Fixed some tiny issues that were introduced lately.
126
+
127
+ ## 0.9.7, released 2008-10-13
128
+ * Setting global method options on the initialize method works as expected:
129
+ All other tasks will accept these global options in addition to their own.
130
+ * Added 'group' notion to Thor task sets (class Thor); by default all tasks
131
+ are in the 'standard' group. Running 'thor -T' will only show the standard
132
+ tasks - adding --all will show all tasks. You can also filter on a specific
133
+ group using the --group option: thor -T --group advanced
134
+
135
+ ## 0.9.6, released 2008-09-13
136
+ * Generic improvements
137
+
138
+ ## 0.9.5, released 2008-08-27
139
+ * Improve Windows compatibility
140
+ * Update (incorrect) README and task.thor sample file
141
+ * Options hash is now frozen (once returned)
142
+ * Allow magic predicates on options object. For instance: `options.force?`
143
+ * Add support for :numeric type
144
+ * BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f])
145
+ * Allow specifying optional args with default values: method_options(:user => "mislav")
146
+ * Don't write options for nil or false values. This allows, for example, turning color off when running specs.
147
+ * Exit with the status of the spec command to help CI stuff out some.
148
+
149
+ ## 0.9.4, released 2008-08-13
150
+ * Try to add Windows compatibility.
151
+ * BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore
152
+ * Allow options at the beginning of the argument list as well as the end.
153
+ * Make options available with symbol keys in addition to string keys.
154
+ * Allow true to be passed to Thor#method_options to denote a boolean option.
155
+ * If loading a thor file fails, don't give up, just print a warning and keep going.
156
+ * Make sure that we re-raise errors if they happened further down the pipe than we care about.
157
+ * Only delete the old file on updating when the installation of the new one is a success
158
+ * Make it Ruby 1.8.5 compatible.
159
+ * Don't raise an error if a boolean switch is defined multiple times.
160
+ * Thor::Options now doesn't parse through things that look like options but aren't.
161
+ * Add URI detection to install task, and make sure we don't append ".thor" to URIs
162
+ * Add rake2thor to the gem binfiles.
163
+ * Make sure local Thorfiles override system-wide ones.
data/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Yehuda Katz, Eric Hodel, et al.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ Thor
2
+ ====
3
+
4
+ [![Gem Version](http://img.shields.io/gem/v/thor.svg)][gem]
5
+ [![Build Status](http://img.shields.io/travis/erikhuda/thor.svg)][travis]
6
+ [![Dependency Status](http://img.shields.io/gemnasium/erikhuda/thor.svg)][gemnasium]
7
+ [![Code Climate](http://img.shields.io/codeclimate/github/erikhuda/thor.svg)][codeclimate]
8
+ [![Coverage Status](http://img.shields.io/coveralls/erikhuda/thor.svg)][coveralls]
9
+
10
+ [gem]: https://rubygems.org/gems/thor
11
+ [travis]: http://travis-ci.org/erikhuda/thor
12
+ [gemnasium]: https://gemnasium.com/erikhuda/thor
13
+ [codeclimate]: https://codeclimate.com/github/erikhuda/thor
14
+ [coveralls]: https://coveralls.io/r/erikhuda/thor
15
+
16
+ Description
17
+ -----------
18
+ Thor is a simple and efficient tool for building self-documenting command line
19
+ utilities. It removes the pain of parsing command line options, writing
20
+ "USAGE:" banners, and can also be used as an alternative to the [Rake][rake]
21
+ build tool. The syntax is Rake-like, so it should be familiar to most Rake
22
+ users.
23
+
24
+ [rake]: https://github.com/jimweirich/rake
25
+
26
+ Installation
27
+ ------------
28
+ gem install thor
29
+
30
+ Usage and documentation
31
+ -----------------------
32
+ Please see the [wiki][] for basic usage and other documentation on using Thor. You can also checkout the [official homepage][homepage].
33
+
34
+ [wiki]: https://github.com/erikhuda/thor/wiki
35
+ [homepage]: http://whatisthor.com/
36
+
37
+ License
38
+ -------
39
+ Released under the MIT License. See the [LICENSE][] file for further details.
40
+
41
+ [license]: LICENSE.md
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+
4
+ require "thor/runner"
5
+ $thor_runner = true
6
+ Thor::Runner.start
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib/", __FILE__)
3
+ $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
4
+ require "thor/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.add_development_dependency "bundler", "~> 1.0"
8
+ # spec.authors = ["Yehuda Katz", "José Valim"]
9
+ spec.authors = ["Takeshi Akima"]
10
+ spec.description = "Thor is a toolkit for building powerful command-line interfaces."
11
+ # spec.email = "ruby-thor@googlegroups.com"
12
+ spec.email = "t-akima@groovenauts.jp"
13
+ # spec.executables = %w[thor]
14
+ spec.executables = %w[groovenauts-thor]
15
+ spec.files = %w[.document groovenauts-thor.gemspec] + Dir['*.md', 'bin/*', 'lib/**/*.rb']
16
+ # spec.homepage = "http://whatisthor.com/"
17
+ spec.homepage = "https://github.com/groovenauts/thor"
18
+ spec.licenses = %w[MIT]
19
+ spec.name = "groovenauts-thor"
20
+ spec.require_paths = %w[lib]
21
+ spec.required_rubygems_version = ">= 1.3.5"
22
+ spec.summary = spec.description
23
+ spec.version = Thor::VERSION
24
+ end
data/lib/thor.rb ADDED
@@ -0,0 +1,487 @@
1
+ require "set"
2
+ require "thor/base"
3
+
4
+ class Thor # rubocop:disable ClassLength
5
+ class << self
6
+ # Allows for custom "Command" package naming.
7
+ #
8
+ # === Parameters
9
+ # name<String>
10
+ # options<Hash>
11
+ #
12
+ def package_name(name, options = {})
13
+ @package_name = name.nil? || name == "" ? nil : name
14
+ end
15
+
16
+ # Sets the default command when thor is executed without an explicit command to be called.
17
+ #
18
+ # ==== Parameters
19
+ # meth<Symbol>:: name of the default command
20
+ #
21
+ def default_command(meth = nil)
22
+ if meth
23
+ @default_command = meth == :none ? "help" : meth.to_s
24
+ else
25
+ @default_command ||= from_superclass(:default_command, "help")
26
+ end
27
+ end
28
+ alias_method :default_task, :default_command
29
+
30
+ # Registers another Thor subclass as a command.
31
+ #
32
+ # ==== Parameters
33
+ # klass<Class>:: Thor subclass to register
34
+ # command<String>:: Subcommand name to use
35
+ # usage<String>:: Short usage for the subcommand
36
+ # description<String>:: Description for the subcommand
37
+ def register(klass, subcommand_name, usage, description, options = {})
38
+ if klass <= Thor::Group
39
+ desc usage, description, options
40
+ define_method(subcommand_name) { |*args| invoke(klass, args) }
41
+ else
42
+ desc usage, description, options
43
+ subcommand subcommand_name, klass
44
+ end
45
+ end
46
+
47
+ # Defines the usage and the description of the next command.
48
+ #
49
+ # ==== Parameters
50
+ # usage<String>
51
+ # description<String>
52
+ # options<String>
53
+ #
54
+ def desc(usage, description, options = {})
55
+ if options[:for]
56
+ command = find_and_refresh_command(options[:for])
57
+ command.usage = usage if usage
58
+ command.description = description if description
59
+ else
60
+ @usage, @desc, @hide = usage, description, options[:hide] || false
61
+ end
62
+ end
63
+
64
+ # Defines the long description of the next command.
65
+ #
66
+ # ==== Parameters
67
+ # long description<String>
68
+ #
69
+ def long_desc(long_description, options = {})
70
+ if options[:for]
71
+ command = find_and_refresh_command(options[:for])
72
+ command.long_description = long_description if long_description
73
+ else
74
+ @long_desc = long_description
75
+ end
76
+ end
77
+
78
+ # Maps an input to a command. If you define:
79
+ #
80
+ # map "-T" => "list"
81
+ #
82
+ # Running:
83
+ #
84
+ # thor -T
85
+ #
86
+ # Will invoke the list command.
87
+ #
88
+ # ==== Parameters
89
+ # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
90
+ #
91
+ def map(mappings = nil)
92
+ @map ||= from_superclass(:map, {})
93
+
94
+ if mappings
95
+ mappings.each do |key, value|
96
+ if key.respond_to?(:each)
97
+ key.each { |subkey| @map[subkey] = value }
98
+ else
99
+ @map[key] = value
100
+ end
101
+ end
102
+ end
103
+
104
+ @map
105
+ end
106
+
107
+ # Declares the options for the next command to be declared.
108
+ #
109
+ # ==== Parameters
110
+ # Hash[Symbol => Object]:: The hash key is the name of the option and the value
111
+ # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
112
+ # or :required (string). If you give a value, the type of the value is used.
113
+ #
114
+ def method_options(options = nil)
115
+ @method_options ||= {}
116
+ build_options(options, @method_options) if options
117
+ @method_options
118
+ end
119
+
120
+ alias_method :options, :method_options
121
+
122
+ # Adds an option to the set of method options. If :for is given as option,
123
+ # it allows you to change the options from a previous defined command.
124
+ #
125
+ # def previous_command
126
+ # # magic
127
+ # end
128
+ #
129
+ # method_option :foo => :bar, :for => :previous_command
130
+ #
131
+ # def next_command
132
+ # # magic
133
+ # end
134
+ #
135
+ # ==== Parameters
136
+ # name<Symbol>:: The name of the argument.
137
+ # options<Hash>:: Described below.
138
+ #
139
+ # ==== Options
140
+ # :desc - Description for the argument.
141
+ # :required - If the argument is required or not.
142
+ # :default - Default value for this argument. It cannot be required and have default values.
143
+ # :aliases - Aliases for this option.
144
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
145
+ # :banner - String to show on usage notes.
146
+ # :hide - If you want to hide this option from the help.
147
+ #
148
+ def method_option(name, options = {})
149
+ scope = if options[:for]
150
+ find_and_refresh_command(options[:for]).options
151
+ else
152
+ method_options
153
+ end
154
+
155
+ build_option(name, options, scope)
156
+ end
157
+ alias_method :option, :method_option
158
+
159
+ # Prints help information for the given command.
160
+ #
161
+ # ==== Parameters
162
+ # shell<Thor::Shell>
163
+ # command_name<String>
164
+ #
165
+ def command_help(shell, command_name)
166
+ meth = normalize_command_name(command_name)
167
+ command = all_commands[meth]
168
+ handle_no_command_error(meth) unless command
169
+
170
+ shell.say "Usage:"
171
+ shell.say " #{banner(command)}"
172
+ shell.say
173
+ class_options_help(shell, nil => command.options.map { |_, o| o })
174
+ if command.long_description
175
+ shell.say "Description:"
176
+ shell.print_wrapped(command.long_description, :indent => 2)
177
+ else
178
+ shell.say command.description
179
+ end
180
+ end
181
+ alias_method :task_help, :command_help
182
+
183
+ # Prints help information for this class.
184
+ #
185
+ # ==== Parameters
186
+ # shell<Thor::Shell>
187
+ #
188
+ def help(shell, subcommand = false)
189
+ list = printable_commands(true, subcommand)
190
+ Thor::Util.thor_classes_in(self).each do |klass|
191
+ list += klass.printable_commands(false)
192
+ end
193
+ list.sort! { |a, b| a[0] <=> b[0] }
194
+
195
+ if defined?(@package_name) && @package_name
196
+ shell.say "#{@package_name} commands:"
197
+ else
198
+ shell.say "Commands:"
199
+ end
200
+
201
+ shell.print_table(list, :indent => 2, :truncate => true)
202
+ shell.say
203
+ class_options_help(shell)
204
+ end
205
+
206
+ # Returns commands ready to be printed.
207
+ def printable_commands(all = true, subcommand = false)
208
+ (all ? all_commands : commands).map do |_, command|
209
+ next if command.hidden?
210
+ item = []
211
+ item << banner(command, false, subcommand)
212
+ item << (command.description ? "# #{command.description.gsub(/\s+/m, ' ')}" : "")
213
+ item
214
+ end.compact
215
+ end
216
+ alias_method :printable_tasks, :printable_commands
217
+
218
+ def subcommands
219
+ @subcommands ||= from_superclass(:subcommands, [])
220
+ end
221
+ alias_method :subtasks, :subcommands
222
+
223
+ def subcommand_classes
224
+ @subcommand_classes ||= {}
225
+ end
226
+
227
+ def subcommand(subcommand, subcommand_class)
228
+ subcommands << subcommand.to_s
229
+ subcommand_class.subcommand_help subcommand
230
+ subcommand_classes[subcommand.to_s] = subcommand_class
231
+
232
+ define_method(subcommand) do |*args|
233
+ args, opts = Thor::Arguments.split(args)
234
+ args.unshift("help") if opts.include? "--help" or opts.include? "-h"
235
+ invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
236
+ end
237
+ subcommand_class.commands.each do |meth, command|
238
+ command.ancestor_name = subcommand
239
+ end
240
+ end
241
+ alias_method :subtask, :subcommand
242
+
243
+ # Extend check unknown options to accept a hash of conditions.
244
+ #
245
+ # === Parameters
246
+ # options<Hash>: A hash containing :only and/or :except keys
247
+ def check_unknown_options!(options = {})
248
+ @check_unknown_options ||= {}
249
+ options.each do |key, value|
250
+ if value
251
+ @check_unknown_options[key] = Array(value)
252
+ else
253
+ @check_unknown_options.delete(key)
254
+ end
255
+ end
256
+ @check_unknown_options
257
+ end
258
+
259
+ # Overwrite check_unknown_options? to take subcommands and options into account.
260
+ def check_unknown_options?(config) #:nodoc:
261
+ options = check_unknown_options
262
+ return false unless options
263
+
264
+ command = config[:current_command]
265
+ return true unless command
266
+
267
+ name = command.name
268
+
269
+ if subcommands.include?(name)
270
+ false
271
+ elsif options[:except]
272
+ !options[:except].include?(name.to_sym)
273
+ elsif options[:only]
274
+ options[:only].include?(name.to_sym)
275
+ else
276
+ true
277
+ end
278
+ end
279
+
280
+ # Stop parsing of options as soon as an unknown option or a regular
281
+ # argument is encountered. All remaining arguments are passed to the command.
282
+ # This is useful if you have a command that can receive arbitrary additional
283
+ # options, and where those additional options should not be handled by
284
+ # Thor.
285
+ #
286
+ # ==== Example
287
+ #
288
+ # To better understand how this is useful, let's consider a command that calls
289
+ # an external command. A user may want to pass arbitrary options and
290
+ # arguments to that command. The command itself also accepts some options,
291
+ # which should be handled by Thor.
292
+ #
293
+ # class_option "verbose", :type => :boolean
294
+ # stop_on_unknown_option! :exec
295
+ # check_unknown_options! :except => :exec
296
+ #
297
+ # desc "exec", "Run a shell command"
298
+ # def exec(*args)
299
+ # puts "diagnostic output" if options[:verbose]
300
+ # Kernel.exec(*args)
301
+ # end
302
+ #
303
+ # Here +exec+ can be called with +--verbose+ to get diagnostic output,
304
+ # e.g.:
305
+ #
306
+ # $ thor exec --verbose echo foo
307
+ # diagnostic output
308
+ # foo
309
+ #
310
+ # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead:
311
+ #
312
+ # $ thor exec echo --verbose foo
313
+ # --verbose foo
314
+ #
315
+ # ==== Parameters
316
+ # Symbol ...:: A list of commands that should be affected.
317
+ def stop_on_unknown_option!(*command_names)
318
+ stop_on_unknown_option.merge(command_names)
319
+ end
320
+
321
+ def stop_on_unknown_option?(command) #:nodoc:
322
+ command && stop_on_unknown_option.include?(command.name.to_sym)
323
+ end
324
+
325
+ protected
326
+ def stop_on_unknown_option #:nodoc:
327
+ @stop_on_unknown_option ||= Set.new
328
+ end
329
+
330
+ # The method responsible for dispatching given the args.
331
+ def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
332
+ meth ||= retrieve_command_name(given_args)
333
+ command = all_commands[normalize_command_name(meth)]
334
+
335
+ if !command && config[:invoked_via_subcommand]
336
+ # We're a subcommand and our first argument didn't match any of our
337
+ # commands. So we put it back and call our default command.
338
+ given_args.unshift(meth)
339
+ command = all_commands[normalize_command_name(default_command)]
340
+ end
341
+
342
+ if command
343
+ args, opts = Thor::Options.split(given_args)
344
+ if stop_on_unknown_option?(command) && !args.empty?
345
+ # given_args starts with a non-option, so we treat everything as
346
+ # ordinary arguments
347
+ args.concat opts
348
+ opts.clear
349
+ end
350
+ else
351
+ args, opts = given_args, nil
352
+ command = dynamic_command_class.new(meth)
353
+ end
354
+
355
+ opts = given_opts || opts || []
356
+ config.merge!(:current_command => command, :command_options => command.options)
357
+
358
+ instance = new(args, opts, config)
359
+ yield instance if block_given?
360
+ args = instance.args
361
+ trailing = args[Range.new(arguments.size, -1)]
362
+ instance.invoke_command(command, trailing || [])
363
+ end
364
+
365
+ # The banner for this class. You can customize it if you are invoking the
366
+ # thor class by another ways which is not the Thor::Runner. It receives
367
+ # the command that is going to be invoked and a boolean which indicates if
368
+ # the namespace should be displayed as arguments.
369
+ #
370
+ def banner(command, namespace = nil, subcommand = false)
371
+ "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
372
+ end
373
+
374
+ def baseclass #:nodoc:
375
+ Thor
376
+ end
377
+
378
+ def dynamic_command_class #:nodoc:
379
+ Thor::DynamicCommand
380
+ end
381
+
382
+ def create_command(meth) #:nodoc:
383
+ @usage ||= nil
384
+ @desc ||= nil
385
+ @long_desc ||= nil
386
+
387
+ if @usage && @desc
388
+ base_class = @hide ? Thor::HiddenCommand : Thor::Command
389
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
390
+ @usage, @desc, @long_desc, @method_options, @hide = nil
391
+ true
392
+ elsif all_commands[meth] || meth == "method_missing"
393
+ true
394
+ else
395
+ puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " <<
396
+ "Call desc if you want this method to be available as command or declare it inside a " <<
397
+ "no_commands{} block. Invoked from #{caller[1].inspect}."
398
+ false
399
+ end
400
+ end
401
+ alias_method :create_task, :create_command
402
+
403
+ def initialize_added #:nodoc:
404
+ class_options.merge!(method_options)
405
+ @method_options = nil
406
+ end
407
+
408
+ # Retrieve the command name from given args.
409
+ def retrieve_command_name(args) #:nodoc:
410
+ meth = args.first.to_s unless args.empty?
411
+ if meth && (map[meth] || meth !~ /^\-/)
412
+ args.shift
413
+ else
414
+ nil
415
+ end
416
+ end
417
+ alias_method :retrieve_task_name, :retrieve_command_name
418
+
419
+ # receives a (possibly nil) command name and returns a name that is in
420
+ # the commands hash. In addition to normalizing aliases, this logic
421
+ # will determine if a shortened command is an unambiguous substring of
422
+ # a command or alias.
423
+ #
424
+ # +normalize_command_name+ also converts names like +animal-prison+
425
+ # into +animal_prison+.
426
+ def normalize_command_name(meth) #:nodoc:
427
+ return default_command.to_s.gsub("-", "_") unless meth
428
+
429
+ possibilities = find_command_possibilities(meth)
430
+ if possibilities.size > 1
431
+ fail AmbiguousTaskError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
432
+ elsif possibilities.size < 1
433
+ meth = meth || default_command
434
+ elsif map[meth]
435
+ meth = map[meth]
436
+ else
437
+ meth = possibilities.first
438
+ end
439
+
440
+ meth.to_s.gsub("-", "_") # treat foo-bar as foo_bar
441
+ end
442
+ alias_method :normalize_task_name, :normalize_command_name
443
+
444
+ # this is the logic that takes the command name passed in by the user
445
+ # and determines whether it is an unambiguous substrings of a command or
446
+ # alias name.
447
+ def find_command_possibilities(meth)
448
+ len = meth.to_s.length
449
+ possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
450
+ unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
451
+
452
+ if possibilities.include?(meth)
453
+ [meth]
454
+ elsif unique_possibilities.size == 1
455
+ unique_possibilities
456
+ else
457
+ possibilities
458
+ end
459
+ end
460
+ alias_method :find_task_possibilities, :find_command_possibilities
461
+
462
+ def subcommand_help(cmd)
463
+ desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
464
+ class_eval "
465
+ def help(command = nil, subcommand = true); super; end
466
+ "
467
+ end
468
+ alias_method :subtask_help, :subcommand_help
469
+ end
470
+
471
+ include Thor::Base
472
+
473
+ map HELP_MAPPINGS => :help
474
+
475
+ desc "help [COMMAND]", "Describe available commands or one specific command"
476
+ def help(command = nil, subcommand = false)
477
+ if command
478
+ if self.class.subcommands.include? command
479
+ self.class.subcommand_classes[command].help(shell, true)
480
+ else
481
+ self.class.command_help(shell, command)
482
+ end
483
+ else
484
+ self.class.help(shell, subcommand)
485
+ end
486
+ end
487
+ end