thor-exclude_pattern 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/CHANGELOG.md +130 -0
  4. data/LICENSE.md +20 -0
  5. data/README.md +34 -0
  6. data/Thorfile +30 -0
  7. data/bin/rake2thor +86 -0
  8. data/bin/thor +6 -0
  9. data/lib/thor.rb +458 -0
  10. data/lib/thor/actions.rb +318 -0
  11. data/lib/thor/actions/create_file.rb +105 -0
  12. data/lib/thor/actions/create_link.rb +60 -0
  13. data/lib/thor/actions/directory.rb +119 -0
  14. data/lib/thor/actions/empty_directory.rb +153 -0
  15. data/lib/thor/actions/file_manipulation.rb +314 -0
  16. data/lib/thor/actions/inject_into_file.rb +109 -0
  17. data/lib/thor/base.rb +649 -0
  18. data/lib/thor/command.rb +136 -0
  19. data/lib/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  20. data/lib/thor/core_ext/io_binary_read.rb +12 -0
  21. data/lib/thor/core_ext/ordered_hash.rb +100 -0
  22. data/lib/thor/error.rb +32 -0
  23. data/lib/thor/exclude_pattern/version.rb +5 -0
  24. data/lib/thor/group.rb +287 -0
  25. data/lib/thor/invocation.rb +172 -0
  26. data/lib/thor/parser.rb +4 -0
  27. data/lib/thor/parser/argument.rb +74 -0
  28. data/lib/thor/parser/arguments.rb +171 -0
  29. data/lib/thor/parser/option.rb +121 -0
  30. data/lib/thor/parser/options.rb +218 -0
  31. data/lib/thor/rake_compat.rb +72 -0
  32. data/lib/thor/runner.rb +322 -0
  33. data/lib/thor/shell.rb +88 -0
  34. data/lib/thor/shell/basic.rb +393 -0
  35. data/lib/thor/shell/color.rb +148 -0
  36. data/lib/thor/shell/html.rb +127 -0
  37. data/lib/thor/util.rb +270 -0
  38. data/lib/thor/version.rb +3 -0
  39. data/spec/actions/create_file_spec.rb +170 -0
  40. data/spec/actions/create_link_spec.rb +95 -0
  41. data/spec/actions/directory_spec.rb +169 -0
  42. data/spec/actions/empty_directory_spec.rb +130 -0
  43. data/spec/actions/file_manipulation_spec.rb +382 -0
  44. data/spec/actions/inject_into_file_spec.rb +135 -0
  45. data/spec/actions_spec.rb +331 -0
  46. data/spec/base_spec.rb +294 -0
  47. data/spec/command_spec.rb +80 -0
  48. data/spec/core_ext/hash_with_indifferent_access_spec.rb +48 -0
  49. data/spec/core_ext/ordered_hash_spec.rb +115 -0
  50. data/spec/exit_condition_spec.rb +19 -0
  51. data/spec/fixtures/application.rb +2 -0
  52. data/spec/fixtures/app{1}/README +3 -0
  53. data/spec/fixtures/bundle/execute.rb +6 -0
  54. data/spec/fixtures/bundle/main.thor +1 -0
  55. data/spec/fixtures/command.thor +10 -0
  56. data/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  57. data/spec/fixtures/doc/COMMENTER +11 -0
  58. data/spec/fixtures/doc/README +3 -0
  59. data/spec/fixtures/doc/block_helper.rb +3 -0
  60. data/spec/fixtures/doc/config.rb +1 -0
  61. data/spec/fixtures/doc/config.yaml.tt +1 -0
  62. data/spec/fixtures/doc/excluding/%file_name%.rb.tt +1 -0
  63. data/spec/fixtures/enum.thor +10 -0
  64. data/spec/fixtures/group.thor +128 -0
  65. data/spec/fixtures/invoke.thor +112 -0
  66. data/spec/fixtures/path with spaces b/data/spec/fixtures/path with → spaces +0 -0
  67. data/spec/fixtures/preserve/script.sh +3 -0
  68. data/spec/fixtures/script.thor +199 -0
  69. data/spec/fixtures/subcommand.thor +17 -0
  70. data/spec/group_spec.rb +216 -0
  71. data/spec/helper.rb +67 -0
  72. data/spec/invocation_spec.rb +100 -0
  73. data/spec/parser/argument_spec.rb +53 -0
  74. data/spec/parser/arguments_spec.rb +66 -0
  75. data/spec/parser/option_spec.rb +202 -0
  76. data/spec/parser/options_spec.rb +400 -0
  77. data/spec/rake_compat_spec.rb +72 -0
  78. data/spec/register_spec.rb +197 -0
  79. data/spec/runner_spec.rb +241 -0
  80. data/spec/sandbox/application.rb +2 -0
  81. data/spec/sandbox/app{1}/README +3 -0
  82. data/spec/sandbox/bundle/execute.rb +6 -0
  83. data/spec/sandbox/bundle/main.thor +1 -0
  84. data/spec/sandbox/command.thor +10 -0
  85. data/spec/sandbox/doc/%file_name%.rb.tt +1 -0
  86. data/spec/sandbox/doc/COMMENTER +11 -0
  87. data/spec/sandbox/doc/README +4 -0
  88. data/spec/sandbox/doc/block_helper.rb +3 -0
  89. data/spec/sandbox/doc/config.rb +1 -0
  90. data/spec/sandbox/doc/config.yaml.tt +1 -0
  91. data/spec/sandbox/doc/excluding/%file_name%.rb.tt +1 -0
  92. data/spec/sandbox/enum.thor +10 -0
  93. data/spec/sandbox/group.thor +128 -0
  94. data/spec/sandbox/invoke.thor +112 -0
  95. data/spec/sandbox/path with spaces b/data/spec/sandbox/path with → spaces +0 -0
  96. data/spec/sandbox/preserve/script.sh +3 -0
  97. data/spec/sandbox/script.thor +199 -0
  98. data/spec/sandbox/subcommand.thor +17 -0
  99. data/spec/shell/basic_spec.rb +311 -0
  100. data/spec/shell/color_spec.rb +95 -0
  101. data/spec/shell/html_spec.rb +32 -0
  102. data/spec/shell_spec.rb +47 -0
  103. data/spec/subcommand_spec.rb +30 -0
  104. data/spec/thor_spec.rb +469 -0
  105. data/spec/util_spec.rb +196 -0
  106. data/thor.gemspec +24 -0
  107. metadata +232 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bca235a33ea1da0e66ade94053dcc06ecf023834
4
+ data.tar.gz: 23542b8124bf8d5fc94df1d2314f176837886dcd
5
+ SHA512:
6
+ metadata.gz: f215dcddc3918634188e7c926d47c375e33d655ce4639df69e5ab605b7b8ba1558948317082d6d8381aa70b8127133979a3fa2b282f1bae09bf6a008518e27e0
7
+ data.tar.gz: 21b949470809c576cc0b17fa74455b7645f2d0c1fb15516ba4e05657b868276889a2db310a2ecf6c9d893a5ae48ca46dd069e656aa5f7b4b8235adbba624ac88
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,130 @@
1
+ ## In git
2
+ * Add directory() config[:exclude_pattern] to prevent copying files that match certain regexp
3
+
4
+ ## 0.17.0, release 2013-01-24
5
+ * Add better support for tasks that accept arbitrary additional arguments (e.g. things like `bundle exec`)
6
+ * Add #stop_on_unknown_option!
7
+ * Only strip from stdin.gets if it wasn't ended with EOF
8
+ * Allow "send" as a task name
9
+ * Allow passing options as arguments after "--"
10
+ * Autoload Thor::Group
11
+
12
+ ## 0.16.0, release 2012-08-14
13
+ * Add enum to string arguments
14
+
15
+ ## 0.15.4, release 2012-06-29
16
+ * Fix regression when destination root contains reserved regexp characters
17
+
18
+ ## 0.15.3, release 2012-06-18
19
+ * Support strict_args_position! for backwards compatibility
20
+ * Escape Dir glob characters in paths
21
+
22
+ ## 0.15.2, released 2012-05-07
23
+ * Added print_in_columns
24
+ * Exposed terminal_width as a public API
25
+
26
+ ## 0.15.1, release 2012-05-06
27
+ * Fix Ruby 1.8 truncation bug with unicode chars
28
+ * Fix shell delegate methods to pass their block
29
+ * Don't output trailing spaces when printing the last column in a table
30
+
31
+ ## 0.15, released 2012-04-29
32
+ * Alias method_options to options
33
+ * Refactor say to allow multiple colors
34
+ * Exposed error as a public API
35
+ * Exposed file_collision as a public API
36
+ * Exposed print_wrapped as a public API
37
+ * Exposed set_color as a public API
38
+ * Fix number-formatting bugs in print_table
39
+ * Fix "indent" typo in print_table
40
+ * Fix Errno::EPIPE when piping tasks to `head`
41
+ * More friendly error messages
42
+
43
+ ## 0.14, released 2010-07-25
44
+ * Added CreateLink class and #link_file method
45
+ * Made Thor::Actions#run use system as default method for system calls
46
+ * Allow use of private methods from superclass as tasks
47
+ * Added mute(&block) method which allows to run block without any output
48
+ * Removed config[:pretend]
49
+ * Enabled underscores for command line switches
50
+ * Added Thor::Base.basename which is used by both Thor.banner and Thor::Group.banner
51
+ * Deprecated invoke() without arguments
52
+ * Added :only and :except to check_unknown_options
53
+
54
+ ## 0.13, released 2010-02-03
55
+ * Added :lazy_default which is only triggered if a switch is given
56
+ * Added Thor::Shell::HTML
57
+ * Added subcommands
58
+ * Decoupled Thor::Group and Thor, so it's easier to vendor
59
+ * Added check_unknown_options! in case you want error messages to be raised in valid switches
60
+ * run(command) should return the results of command
61
+
62
+ ## 0.12, released 2010-01-02
63
+ * Methods generated by attr_* are automatically not marked as tasks
64
+ * inject_into_file does not add the same content twice, unless :force is set
65
+ * Removed rr in favor to rspec mock framework
66
+ * Improved output for thor -T
67
+ * [#7] Do not force white color on status
68
+ * [#8] Yield a block with the filename on directory
69
+
70
+ ## 0.11, released 2009-07-01
71
+ * Added a rake compatibility layer. It allows you to use spec and rdoc tasks on
72
+ Thor classes.
73
+ * BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
74
+ since it may cause wrong behavior in the invocation system.
75
+ * thor help now show information about any class/task. All those calls are
76
+ possible:
77
+
78
+ thor help describe
79
+ thor help describe:amazing
80
+ Or even with default namespaces:
81
+
82
+ thor help :spec
83
+ * Thor::Runner now invokes the default task if none is supplied:
84
+
85
+ thor describe # invokes the default task, usually help
86
+ * Thor::Runner now works with mappings:
87
+
88
+ thor describe -h
89
+ * Added some documentation and code refactoring.
90
+
91
+ ## 0.9.8, released 2008-10-20
92
+ * Fixed some tiny issues that were introduced lately.
93
+
94
+ ## 0.9.7, released 2008-10-13
95
+ * Setting global method options on the initialize method works as expected:
96
+ All other tasks will accept these global options in addition to their own.
97
+ * Added 'group' notion to Thor task sets (class Thor); by default all tasks
98
+ are in the 'standard' group. Running 'thor -T' will only show the standard
99
+ tasks - adding --all will show all tasks. You can also filter on a specific
100
+ group using the --group option: thor -T --group advanced
101
+
102
+ ## 0.9.6, released 2008-09-13
103
+ * Generic improvements
104
+
105
+ ## 0.9.5, released 2008-08-27
106
+ * Improve Windows compatibility
107
+ * Update (incorrect) README and task.thor sample file
108
+ * Options hash is now frozen (once returned)
109
+ * Allow magic predicates on options object. For instance: `options.force?`
110
+ * Add support for :numeric type
111
+ * BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f])
112
+ * Allow specifying optional args with default values: method_options(:user => "mislav")
113
+ * Don't write options for nil or false values. This allows, for example, turning color off when running specs.
114
+ * Exit with the status of the spec command to help CI stuff out some.
115
+
116
+ ## 0.9.4, released 2008-08-13
117
+ * Try to add Windows compatibility.
118
+ * BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore
119
+ * Allow options at the beginning of the argument list as well as the end.
120
+ * Make options available with symbol keys in addition to string keys.
121
+ * Allow true to be passed to Thor#method_options to denote a boolean option.
122
+ * If loading a thor file fails, don't give up, just print a warning and keep going.
123
+ * Make sure that we re-raise errors if they happened further down the pipe than we care about.
124
+ * Only delete the old file on updating when the installation of the new one is a success
125
+ * Make it Ruby 1.8.5 compatible.
126
+ * Don't raise an error if a boolean switch is defined multiple times.
127
+ * Thor::Options now doesn't parse through things that look like options but aren't.
128
+ * Add URI detection to install task, and make sure we don't append ".thor" to URIs
129
+ * Add rake2thor to the gem binfiles.
130
+ * 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,34 @@
1
+ [![Gem Version](https://badge.fury.io/rb/thor.png)](https://rubygems.org/gems/thor)
2
+ [![Build Status](https://secure.travis-ci.org/wycats/thor.png?branch=master)](http://travis-ci.org/wycats/thor)
3
+ [![Dependency Status](https://gemnasium.com/wycats/thor.png?travis)](https://gemnasium.com/wycats/thor)
4
+ [![Code Climate](https://codeclimate.com/github/wycats/thor.png)](https://codeclimate.com/github/wycats/thor)
5
+ [![Coverage Status](https://coveralls.io/repos/wycats/thor/badge.png?branch=master)](https://coveralls.io/r/wycats/thor)
6
+
7
+ Thor
8
+ ====
9
+
10
+ Description
11
+ -----------
12
+ Thor is a simple and efficient tool for building self-documenting command line
13
+ utilities. It removes the pain of parsing command line options, writing
14
+ "USAGE:" banners, and can also be used as an alternative to the [Rake][rake]
15
+ build tool. The syntax is Rake-like, so it should be familiar to most Rake
16
+ users.
17
+
18
+ [rake]: https://github.com/jimweirich/rake
19
+
20
+ Installation
21
+ ------------
22
+ gem install thor
23
+
24
+ Usage and documentation
25
+ -----------------------
26
+ Please see the [wiki][] for basic usage and other documentation on using Thor.
27
+
28
+ [wiki]: https://github.com/wycats/thor/wiki
29
+
30
+ License
31
+ -------
32
+ Released under the MIT License. See the [LICENSE][] file for further details.
33
+
34
+ [license]: LICENSE.md
data/Thorfile ADDED
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ $:.unshift File.expand_path("../lib", __FILE__)
3
+
4
+ require 'bundler'
5
+ require 'thor/rake_compat'
6
+
7
+ class Default < Thor
8
+ include Thor::RakeCompat
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ desc "build", "Build thor-#{Thor::VERSION}.gem into the pkg directory"
12
+ def build
13
+ Rake::Task["build"].execute
14
+ end
15
+
16
+ desc "install", "Build and install thor-#{Thor::VERSION}.gem into system gems"
17
+ def install
18
+ Rake::Task["install"].execute
19
+ end
20
+
21
+ desc "release", "Create tag v#{Thor::VERSION} and build and push thor-#{Thor::VERSION}.gem to Rubygems"
22
+ def release
23
+ Rake::Task["release"].execute
24
+ end
25
+
26
+ desc "spec", "Run RSpec code examples"
27
+ def spec
28
+ exec "rspec --color --format=documentation spec"
29
+ end
30
+ end
data/bin/rake2thor ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ruby2ruby'
4
+ require 'parse_tree'
5
+ if Ruby2Ruby::VERSION >= "1.2.0"
6
+ require 'parse_tree_extensions'
7
+ end
8
+ require 'rake'
9
+
10
+ input = ARGV[0] || 'Rakefile'
11
+ output = ARGV[1] || 'Thorfile'
12
+
13
+ $requires = []
14
+
15
+ module Kernel
16
+ def require_with_record(file)
17
+ $requires << file if caller[1] =~ /rake2thor:/
18
+ require_without_record file
19
+ end
20
+ alias_method :require_without_record, :require
21
+ alias_method :require, :require_with_record
22
+ end
23
+
24
+ load input
25
+
26
+ @private_methods = []
27
+
28
+ def file_task_name(name)
29
+ "compile_" + name.gsub('/', '_slash_').gsub('.', '_dot_').gsub(/\W/, '_')
30
+ end
31
+
32
+ def method_for_task(task)
33
+ file_task = task.is_a?(Rake::FileTask)
34
+ comment = task.instance_variable_get('@comment')
35
+ prereqs = task.instance_variable_get('@prerequisites').select(&Rake::Task.method(:task_defined?))
36
+ actions = task.instance_variable_get('@actions')
37
+ name = task.name.gsub(/^([^:]+:)+/, '')
38
+ name = file_task_name(name) if file_task
39
+ meth = ''
40
+
41
+ meth << "desc #{name.inspect}, #{comment.inspect}\n" if comment
42
+ meth << "def #{name}\n"
43
+
44
+ meth << prereqs.map do |pre|
45
+ pre = pre.to_s
46
+ pre = file_task_name(pre) if Rake::Task[pre].is_a?(Rake::FileTask)
47
+ ' ' + pre
48
+ end.join("\n")
49
+
50
+ meth << "\n\n" unless prereqs.empty? || actions.empty?
51
+
52
+ meth << actions.map do |act|
53
+ act = act.to_ruby
54
+ unless act.gsub!(/^proc \{ \|(\w+)\|\n/,
55
+ " \\1 = Struct.new(:name).new(#{name.inspect}) # A crude mock Rake::Task object\n")
56
+ act.gsub!(/^proc \{\n/, '')
57
+ end
58
+ act.gsub(/\n\}$/, '')
59
+ end.join("\n")
60
+
61
+ meth << "\nend"
62
+
63
+ if file_task
64
+ @private_methods << meth
65
+ return
66
+ end
67
+
68
+ meth
69
+ end
70
+
71
+ body = Rake::Task.tasks.map(&method(:method_for_task)).compact.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n")
72
+
73
+ unless @private_methods.empty?
74
+ body << "\n\n private\n\n"
75
+ body << @private_methods.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n")
76
+ end
77
+
78
+ requires = $requires.map { |r| "require #{r.inspect}" }.join("\n")
79
+
80
+ File.open(output, 'w') { |f| f.write(<<END.lstrip) }
81
+ #{requires}
82
+
83
+ class Default < Thor
84
+ #{body}
85
+ end
86
+ END
data/bin/thor ADDED
@@ -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
data/lib/thor.rb ADDED
@@ -0,0 +1,458 @@
1
+ require 'set'
2
+ require 'thor/base'
3
+
4
+ class Thor
5
+ class << self
6
+ # Sets the default command when thor is executed without an explicit command to be called.
7
+ #
8
+ # ==== Parameters
9
+ # meth<Symbol>:: name of the default command
10
+ #
11
+ def default_command(meth=nil)
12
+ @default_command = case meth
13
+ when :none
14
+ 'help'
15
+ when nil
16
+ @default_command || from_superclass(:default_command, 'help')
17
+ else
18
+ meth.to_s
19
+ end
20
+ end
21
+ alias default_task default_command
22
+
23
+ # Registers another Thor subclass as a command.
24
+ #
25
+ # ==== Parameters
26
+ # klass<Class>:: Thor subclass to register
27
+ # command<String>:: Subcommand name to use
28
+ # usage<String>:: Short usage for the subcommand
29
+ # description<String>:: Description for the subcommand
30
+ def register(klass, subcommand_name, usage, description, options={})
31
+ if klass <= Thor::Group
32
+ desc usage, description, options
33
+ define_method(subcommand_name) { |*args| invoke(klass, args) }
34
+ else
35
+ desc usage, description, options
36
+ subcommand subcommand_name, klass
37
+ end
38
+ end
39
+
40
+ # Defines the usage and the description of the next command.
41
+ #
42
+ # ==== Parameters
43
+ # usage<String>
44
+ # description<String>
45
+ # options<String>
46
+ #
47
+ def desc(usage, description, options={})
48
+ if options[:for]
49
+ command = find_and_refresh_command(options[:for])
50
+ command.usage = usage if usage
51
+ command.description = description if description
52
+ else
53
+ @usage, @desc, @hide = usage, description, options[:hide] || false
54
+ end
55
+ end
56
+
57
+ # Defines the long description of the next command.
58
+ #
59
+ # ==== Parameters
60
+ # long description<String>
61
+ #
62
+ def long_desc(long_description, options={})
63
+ if options[:for]
64
+ command = find_and_refresh_command(options[:for])
65
+ command.long_description = long_description if long_description
66
+ else
67
+ @long_desc = long_description
68
+ end
69
+ end
70
+
71
+ # Maps an input to a command. If you define:
72
+ #
73
+ # map "-T" => "list"
74
+ #
75
+ # Running:
76
+ #
77
+ # thor -T
78
+ #
79
+ # Will invoke the list command.
80
+ #
81
+ # ==== Parameters
82
+ # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given command.
83
+ #
84
+ def map(mappings=nil)
85
+ @map ||= from_superclass(:map, {})
86
+
87
+ if mappings
88
+ mappings.each do |key, value|
89
+ if key.respond_to?(:each)
90
+ key.each {|subkey| @map[subkey] = value}
91
+ else
92
+ @map[key] = value
93
+ end
94
+ end
95
+ end
96
+
97
+ @map
98
+ end
99
+
100
+ # Declares the options for the next command to be declared.
101
+ #
102
+ # ==== Parameters
103
+ # Hash[Symbol => Object]:: The hash key is the name of the option and the value
104
+ # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
105
+ # or :required (string). If you give a value, the type of the value is used.
106
+ #
107
+ def method_options(options=nil)
108
+ @method_options ||= {}
109
+ build_options(options, @method_options) if options
110
+ @method_options
111
+ end
112
+
113
+ alias options method_options
114
+
115
+ # Adds an option to the set of method options. If :for is given as option,
116
+ # it allows you to change the options from a previous defined command.
117
+ #
118
+ # def previous_command
119
+ # # magic
120
+ # end
121
+ #
122
+ # method_option :foo => :bar, :for => :previous_command
123
+ #
124
+ # def next_command
125
+ # # magic
126
+ # end
127
+ #
128
+ # ==== Parameters
129
+ # name<Symbol>:: The name of the argument.
130
+ # options<Hash>:: Described below.
131
+ #
132
+ # ==== Options
133
+ # :desc - Description for the argument.
134
+ # :required - If the argument is required or not.
135
+ # :default - Default value for this argument. It cannot be required and have default values.
136
+ # :aliases - Aliases for this option.
137
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
138
+ # :banner - String to show on usage notes.
139
+ # :hide - If you want to hide this option from the help.
140
+ #
141
+ def method_option(name, options={})
142
+ scope = if options[:for]
143
+ find_and_refresh_command(options[:for]).options
144
+ else
145
+ method_options
146
+ end
147
+
148
+ build_option(name, options, scope)
149
+ end
150
+ alias option method_option
151
+
152
+ # Prints help information for the given command.
153
+ #
154
+ # ==== Parameters
155
+ # shell<Thor::Shell>
156
+ # command_name<String>
157
+ #
158
+ def command_help(shell, command_name)
159
+ meth = normalize_command_name(command_name)
160
+ command = all_commands[meth]
161
+ handle_no_command_error(meth) unless command
162
+
163
+ shell.say "Usage:"
164
+ shell.say " #{banner(command)}"
165
+ shell.say
166
+ class_options_help(shell, nil => command.options.map { |_, o| o })
167
+ if command.long_description
168
+ shell.say "Description:"
169
+ shell.print_wrapped(command.long_description, :indent => 2)
170
+ else
171
+ shell.say command.description
172
+ end
173
+ end
174
+ alias task_help command_help
175
+
176
+ # Prints help information for this class.
177
+ #
178
+ # ==== Parameters
179
+ # shell<Thor::Shell>
180
+ #
181
+ def help(shell, subcommand = false)
182
+ list = printable_commands(true, subcommand)
183
+ Thor::Util.thor_classes_in(self).each do |klass|
184
+ list += klass.printable_commands(false)
185
+ end
186
+ list.sort!{ |a,b| a[0] <=> b[0] }
187
+
188
+ shell.say "Commands:"
189
+ shell.print_table(list, :indent => 2, :truncate => true)
190
+ shell.say
191
+ class_options_help(shell)
192
+ end
193
+
194
+ # Returns commands ready to be printed.
195
+ def printable_commands(all = true, subcommand = false)
196
+ (all ? all_commands : commands).map do |_, command|
197
+ next if command.hidden?
198
+ item = []
199
+ item << banner(command, false, subcommand)
200
+ item << (command.description ? "# #{command.description.gsub(/\s+/m,' ')}" : "")
201
+ item
202
+ end.compact
203
+ end
204
+ alias printable_tasks printable_commands
205
+
206
+ def subcommands
207
+ @subcommands ||= from_superclass(:subcommands, [])
208
+ end
209
+ alias subtasks subcommands
210
+
211
+ def subcommand(subcommand, subcommand_class)
212
+ self.subcommands << subcommand.to_s
213
+ subcommand_class.subcommand_help subcommand
214
+
215
+ define_method(subcommand) do |*args|
216
+ args, opts = Thor::Arguments.split(args)
217
+ invoke subcommand_class, args, opts, :invoked_via_subcommand => true, :class_options => options
218
+ end
219
+ end
220
+ alias subtask subcommand
221
+
222
+ # Extend check unknown options to accept a hash of conditions.
223
+ #
224
+ # === Parameters
225
+ # options<Hash>: A hash containing :only and/or :except keys
226
+ def check_unknown_options!(options={})
227
+ @check_unknown_options ||= Hash.new
228
+ options.each do |key, value|
229
+ if value
230
+ @check_unknown_options[key] = Array(value)
231
+ else
232
+ @check_unknown_options.delete(key)
233
+ end
234
+ end
235
+ @check_unknown_options
236
+ end
237
+
238
+ # Overwrite check_unknown_options? to take subcommands and options into account.
239
+ def check_unknown_options?(config) #:nodoc:
240
+ options = check_unknown_options
241
+ return false unless options
242
+
243
+ command = config[:current_command]
244
+ return true unless command
245
+
246
+ name = command.name
247
+
248
+ if subcommands.include?(name)
249
+ false
250
+ elsif options[:except]
251
+ !options[:except].include?(name.to_sym)
252
+ elsif options[:only]
253
+ options[:only].include?(name.to_sym)
254
+ else
255
+ true
256
+ end
257
+ end
258
+
259
+ # Stop parsing of options as soon as an unknown option or a regular
260
+ # argument is encountered. All remaining arguments are passed to the command.
261
+ # This is useful if you have a command that can receive arbitrary additional
262
+ # options, and where those additional options should not be handled by
263
+ # Thor.
264
+ #
265
+ # ==== Example
266
+ #
267
+ # To better understand how this is useful, let's consider a command that calls
268
+ # an external command. A user may want to pass arbitrary options and
269
+ # arguments to that command. The command itself also accepts some options,
270
+ # which should be handled by Thor.
271
+ #
272
+ # class_option "verbose", :type => :boolean
273
+ # stop_on_unknown_option! :exec
274
+ # check_unknown_options! :except => :exec
275
+ #
276
+ # desc "exec", "Run a shell command"
277
+ # def exec(*args)
278
+ # puts "diagnostic output" if options[:verbose]
279
+ # Kernel.exec(*args)
280
+ # end
281
+ #
282
+ # Here +exec+ can be called with +--verbose+ to get diagnostic output,
283
+ # e.g.:
284
+ #
285
+ # $ thor exec --verbose echo foo
286
+ # diagnostic output
287
+ # foo
288
+ #
289
+ # But if +--verbose+ is given after +echo+, it is passed to +echo+ instead:
290
+ #
291
+ # $ thor exec echo --verbose foo
292
+ # --verbose foo
293
+ #
294
+ # ==== Parameters
295
+ # Symbol ...:: A list of commands that should be affected.
296
+ def stop_on_unknown_option!(*command_names)
297
+ @stop_on_unknown_option ||= Set.new
298
+ @stop_on_unknown_option.merge(command_names)
299
+ end
300
+
301
+ def stop_on_unknown_option?(command) #:nodoc:
302
+ !!@stop_on_unknown_option && @stop_on_unknown_option.include?(command.name.to_sym)
303
+ end
304
+
305
+ protected
306
+
307
+ # The method responsible for dispatching given the args.
308
+ def dispatch(meth, given_args, given_opts, config) #:nodoc:
309
+ # There is an edge case when dispatching from a subcommand.
310
+ # A problem occurs invoking the default command. This case occurs
311
+ # when arguments are passed and a default command is defined, and
312
+ # the first given_args does not match the default command.
313
+ # Thor use "help" by default so we skip that case.
314
+ # Note the call to retrieve_command_name. It's called with
315
+ # given_args.dup since that method calls args.shift. Then lookup
316
+ # the command normally. If the first item in given_args is not
317
+ # a command then use the default command. The given_args will be
318
+ # intact later since dup was used.
319
+ if config[:invoked_via_subcommand] && given_args.size >= 1 && default_command != "help" && given_args.first != default_command
320
+ meth ||= retrieve_command_name(given_args.dup)
321
+ command = all_commands[normalize_command_name(meth)]
322
+ command ||= all_commands[normalize_command_name(default_command)]
323
+ else
324
+ meth ||= retrieve_command_name(given_args)
325
+ command = all_commands[normalize_command_name(meth)]
326
+ end
327
+
328
+ if command
329
+ args, opts = Thor::Options.split(given_args)
330
+ if stop_on_unknown_option?(command) && !args.empty?
331
+ # given_args starts with a non-option, so we treat everything as
332
+ # ordinary arguments
333
+ args.concat opts
334
+ opts.clear
335
+ end
336
+ else
337
+ args, opts = given_args, nil
338
+ command = Thor::DynamicCommand.new(meth)
339
+ end
340
+
341
+ opts = given_opts || opts || []
342
+ config.merge!(:current_command => command, :command_options => command.options)
343
+
344
+ instance = new(args, opts, config)
345
+ yield instance if block_given?
346
+ args = instance.args
347
+ trailing = args[Range.new(arguments.size, -1)]
348
+ instance.invoke_command(command, trailing || [])
349
+ end
350
+
351
+ # The banner for this class. You can customize it if you are invoking the
352
+ # thor class by another ways which is not the Thor::Runner. It receives
353
+ # the command that is going to be invoked and a boolean which indicates if
354
+ # the namespace should be displayed as arguments.
355
+ #
356
+ def banner(command, namespace = nil, subcommand = false)
357
+ "#{basename} #{command.formatted_usage(self, $thor_runner, subcommand)}"
358
+ end
359
+
360
+ def baseclass #:nodoc:
361
+ Thor
362
+ end
363
+
364
+ def create_command(meth) #:nodoc:
365
+ if @usage && @desc
366
+ base_class = @hide ? Thor::HiddenCommand : Thor::Command
367
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
368
+ @usage, @desc, @long_desc, @method_options, @hide = nil
369
+ true
370
+ elsif self.all_commands[meth] || meth == "method_missing"
371
+ true
372
+ else
373
+ puts "[WARNING] Attempted to create command #{meth.inspect} without usage or description. " <<
374
+ "Call desc if you want this method to be available as command or declare it inside a " <<
375
+ "no_commands{} block. Invoked from #{caller[1].inspect}."
376
+ false
377
+ end
378
+ end
379
+ alias create_task create_command
380
+
381
+ def initialize_added #:nodoc:
382
+ class_options.merge!(method_options)
383
+ @method_options = nil
384
+ end
385
+
386
+ # Retrieve the command name from given args.
387
+ def retrieve_command_name(args) #:nodoc:
388
+ meth = args.first.to_s unless args.empty?
389
+ if meth && (map[meth] || meth !~ /^\-/)
390
+ args.shift
391
+ else
392
+ nil
393
+ end
394
+ end
395
+ alias retrieve_task_name retrieve_command_name
396
+
397
+ # receives a (possibly nil) command name and returns a name that is in
398
+ # the commands hash. In addition to normalizing aliases, this logic
399
+ # will determine if a shortened command is an unambiguous substring of
400
+ # a command or alias.
401
+ #
402
+ # +normalize_command_name+ also converts names like +animal-prison+
403
+ # into +animal_prison+.
404
+ def normalize_command_name(meth) #:nodoc:
405
+ return default_command.to_s.gsub('-', '_') unless meth
406
+
407
+ possibilities = find_command_possibilities(meth)
408
+ if possibilities.size > 1
409
+ raise ArgumentError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
410
+ elsif possibilities.size < 1
411
+ meth = meth || default_command
412
+ elsif map[meth]
413
+ meth = map[meth]
414
+ else
415
+ meth = possibilities.first
416
+ end
417
+
418
+ meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
419
+ end
420
+ alias normalize_task_name normalize_command_name
421
+
422
+ # this is the logic that takes the command name passed in by the user
423
+ # and determines whether it is an unambiguous substrings of a command or
424
+ # alias name.
425
+ def find_command_possibilities(meth)
426
+ len = meth.to_s.length
427
+ possibilities = all_commands.merge(map).keys.select { |n| meth == n[0, len] }.sort
428
+ unique_possibilities = possibilities.map { |k| map[k] || k }.uniq
429
+
430
+ if possibilities.include?(meth)
431
+ [meth]
432
+ elsif unique_possibilities.size == 1
433
+ unique_possibilities
434
+ else
435
+ possibilities
436
+ end
437
+ end
438
+ alias find_task_possibilities find_command_possibilities
439
+
440
+ def subcommand_help(cmd)
441
+ desc "help [COMMAND]", "Describe subcommands or one specific subcommand"
442
+ class_eval <<-RUBY
443
+ def help(command = nil, subcommand = true); super; end
444
+ RUBY
445
+ end
446
+ alias subtask_help subcommand_help
447
+
448
+ end
449
+
450
+ include Thor::Base
451
+
452
+ map HELP_MAPPINGS => :help
453
+
454
+ desc "help [COMMAND]", "Describe available commands or one specific command"
455
+ def help(command = nil, subcommand = false)
456
+ command ? self.class.command_help(shell, command) : self.class.help(shell, subcommand)
457
+ end
458
+ end