bundler 1.1.pre.5 → 1.1.pre.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (66) hide show
  1. data/CHANGELOG.md +52 -1
  2. data/ISSUES.md +1 -0
  3. data/Rakefile +3 -3
  4. data/UPGRADING.md +2 -2
  5. data/lib/bundler/cli.rb +6 -5
  6. data/lib/bundler/definition.rb +13 -2
  7. data/lib/bundler/endpoint_specification.rb +19 -0
  8. data/lib/bundler/fetcher.rb +34 -2
  9. data/lib/bundler/gem_helper.rb +6 -4
  10. data/lib/bundler/index.rb +29 -4
  11. data/lib/bundler/installer.rb +2 -1
  12. data/lib/bundler/lazy_specification.rb +4 -2
  13. data/lib/bundler/resolver.rb +14 -16
  14. data/lib/bundler/rubygems_ext.rb +1 -0
  15. data/lib/bundler/rubygems_integration.rb +22 -2
  16. data/lib/bundler/runtime.rb +2 -0
  17. data/lib/bundler/source.rb +52 -44
  18. data/lib/bundler/spec_set.rb +10 -9
  19. data/lib/bundler/templates/newgem/Rakefile.tt +1 -1
  20. data/lib/bundler/templates/newgem/newgem.gemspec.tt +2 -2
  21. data/lib/bundler/vendor/thor.rb +43 -4
  22. data/lib/bundler/vendor/thor/actions.rb +28 -11
  23. data/lib/bundler/vendor/thor/actions/create_file.rb +2 -2
  24. data/lib/bundler/vendor/thor/actions/create_link.rb +57 -0
  25. data/lib/bundler/vendor/thor/actions/directory.rb +2 -2
  26. data/lib/bundler/vendor/thor/actions/empty_directory.rb +0 -0
  27. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +56 -15
  28. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +13 -8
  29. data/lib/bundler/vendor/thor/base.rb +24 -4
  30. data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +0 -0
  31. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +0 -0
  32. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +0 -0
  33. data/lib/bundler/vendor/thor/error.rb +0 -0
  34. data/lib/bundler/vendor/thor/group.rb +273 -0
  35. data/lib/bundler/vendor/thor/invocation.rb +0 -0
  36. data/lib/bundler/vendor/thor/parser.rb +0 -0
  37. data/lib/bundler/vendor/thor/parser/argument.rb +0 -0
  38. data/lib/bundler/vendor/thor/parser/arguments.rb +2 -2
  39. data/lib/bundler/vendor/thor/parser/option.rb +0 -0
  40. data/lib/bundler/vendor/thor/parser/options.rb +17 -16
  41. data/lib/bundler/vendor/thor/rake_compat.rb +66 -0
  42. data/lib/bundler/vendor/thor/runner.rb +309 -0
  43. data/lib/bundler/vendor/thor/shell.rb +0 -0
  44. data/lib/bundler/vendor/thor/shell/basic.rb +40 -13
  45. data/lib/bundler/vendor/thor/shell/color.rb +0 -0
  46. data/lib/bundler/vendor/thor/task.rb +3 -4
  47. data/lib/bundler/vendor/thor/util.rb +2 -2
  48. data/lib/bundler/vendor/thor/version.rb +1 -1
  49. data/lib/bundler/version.rb +1 -1
  50. data/man/gemfile.5.ronn +3 -0
  51. data/spec/cache/git_spec.rb +5 -2
  52. data/spec/install/gems/dependency_api_spec.rb +69 -0
  53. data/spec/install/gems/simple_case_spec.rb +7 -0
  54. data/spec/install/gems/standalone_spec.rb +62 -0
  55. data/spec/install/git_spec.rb +63 -1
  56. data/spec/other/clean_spec.rb +22 -26
  57. data/spec/other/exec_spec.rb +2 -2
  58. data/spec/other/gem_helper_spec.rb +1 -1
  59. data/spec/runtime/setup_spec.rb +1 -1
  60. data/spec/support/artifice/endpoint.rb +2 -2
  61. data/spec/support/artifice/endpoint_api_missing.rb +16 -0
  62. data/spec/support/artifice/endpoint_extra.rb +27 -0
  63. data/spec/support/artifice/endpoint_extra_missing.rb +15 -0
  64. data/spec/support/helpers.rb +7 -6
  65. metadata +73 -40
  66. data/spec/pack/gems_spec.rb +0 -22
@@ -18,7 +18,7 @@ class Thor
18
18
  # "vhost.name = #{hostname}"
19
19
  # end
20
20
  #
21
- # create_file "config/apach.conf", "your apache config"
21
+ # create_file "config/apache.conf", "your apache config"
22
22
  #
23
23
  def create_file(destination, *args, &block)
24
24
  config = args.last.is_a?(Hash) ? args.pop : {}
@@ -27,7 +27,7 @@ class Thor
27
27
  end
28
28
  alias :add_file :create_file
29
29
 
30
- # AddFile is a subset of Template, which instead of rendering a file with
30
+ # CreateFile is a subset of Template, which instead of rendering a file with
31
31
  # ERB, it gets the content from the user.
32
32
  #
33
33
  class CreateFile < EmptyDirectory #:nodoc:
@@ -0,0 +1,57 @@
1
+ require 'thor/actions/create_file'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Create a new file relative to the destination root from the given source.
7
+ #
8
+ # ==== Parameters
9
+ # destination<String>:: the relative path to the destination root.
10
+ # source<String|NilClass>:: the relative path to the source root.
11
+ # config<Hash>:: give :verbose => false to not log the status.
12
+ # :: give :symbolic => false for hard link.
13
+ #
14
+ # ==== Examples
15
+ #
16
+ # create_link "config/apache.conf", "/etc/apache.conf"
17
+ #
18
+ def create_link(destination, *args, &block)
19
+ config = args.last.is_a?(Hash) ? args.pop : {}
20
+ source = args.first
21
+ action CreateLink.new(self, destination, source, config)
22
+ end
23
+ alias :add_link :create_link
24
+
25
+ # CreateLink is a subset of CreateFile, which instead of taking a block of
26
+ # data, just takes a source string from the user.
27
+ #
28
+ class CreateLink < CreateFile #:nodoc:
29
+ attr_reader :data
30
+
31
+ # Checks if the content of the file at the destination is identical to the rendered result.
32
+ #
33
+ # ==== Returns
34
+ # Boolean:: true if it is identical, false otherwise.
35
+ #
36
+ def identical?
37
+ exists? && File.identical?(render, destination)
38
+ end
39
+
40
+ def invoke!
41
+ invoke_with_conflict_check do
42
+ FileUtils.mkdir_p(File.dirname(destination))
43
+ # Create a symlink by default
44
+ config[:symbolic] ||= true
45
+ File.unlink(destination) if exists?
46
+ if config[:symbolic]
47
+ File.symlink(render, destination)
48
+ else
49
+ File.link(render, destination)
50
+ end
51
+ end
52
+ given_destination
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -21,7 +21,7 @@ class Thor
21
21
  # directory "doc"
22
22
  #
23
23
  # It will create a doc directory in the destination with the following
24
- # files (assuming that the app_name is "blog"):
24
+ # files (assuming that the `app_name` method returns the value "blog"):
25
25
  #
26
26
  # doc/
27
27
  # components/
@@ -70,7 +70,7 @@ class Thor
70
70
  lookup = config[:recursive] ? File.join(source, '**') : source
71
71
  lookup = File.join(lookup, '{*,.[a-z]*}')
72
72
 
73
- Dir[lookup].each do |file_source|
73
+ Dir[lookup].sort.each do |file_source|
74
74
  next if File.directory?(file_source)
75
75
  file_destination = File.join(given_destination, file_source.gsub(source, '.'))
76
76
  file_destination.gsub!('/./', '/')
@@ -30,6 +30,28 @@ class Thor
30
30
  end
31
31
  end
32
32
 
33
+ # Links the file from the relative source to the relative destination. If
34
+ # the destination is not given it's assumed to be equal to the source.
35
+ #
36
+ # ==== Parameters
37
+ # source<String>:: the relative path to the source root.
38
+ # destination<String>:: the relative path to the destination root.
39
+ # config<Hash>:: give :verbose => false to not log the status.
40
+ #
41
+ # ==== Examples
42
+ #
43
+ # link_file "README", "doc/README"
44
+ #
45
+ # link_file "doc/README"
46
+ #
47
+ def link_file(source, *args, &block)
48
+ config = args.last.is_a?(Hash) ? args.pop : {}
49
+ destination = args.first || source
50
+ source = File.expand_path(find_in_source_paths(source.to_s))
51
+
52
+ create_link destination, source, config
53
+ end
54
+
33
55
  # Gets the content at the given address and places it at the given relative
34
56
  # destination. If a block is given instead of destination, the content of
35
57
  # the url is yielded and used as location.
@@ -51,7 +73,7 @@ class Thor
51
73
  config = args.last.is_a?(Hash) ? args.pop : {}
52
74
  destination = args.first
53
75
 
54
- source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^http\:\/\//
76
+ source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^https?\:\/\//
55
77
  render = open(source) {|input| input.binmode.read }
56
78
 
57
79
  destination ||= if block_given?
@@ -80,13 +102,13 @@ class Thor
80
102
  #
81
103
  def template(source, *args, &block)
82
104
  config = args.last.is_a?(Hash) ? args.pop : {}
83
- destination = args.first || source
105
+ destination = args.first || source.sub(/\.tt$/, '')
84
106
 
85
107
  source = File.expand_path(find_in_source_paths(source.to_s))
86
108
  context = instance_eval('binding')
87
109
 
88
110
  create_file destination, nil, config do
89
- content = ERB.new(::File.binread(source), nil, '-').result(context)
111
+ content = ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context)
90
112
  content = block.call(content) if block
91
113
  content
92
114
  end
@@ -110,7 +132,7 @@ class Thor
110
132
  FileUtils.chmod_R(mode, path) unless options[:pretend]
111
133
  end
112
134
 
113
- # Prepend text to a file. Since it depends on inject_into_file, it's reversible.
135
+ # Prepend text to a file. Since it depends on insert_into_file, it's reversible.
114
136
  #
115
137
  # ==== Parameters
116
138
  # path<String>:: path of the file to be changed
@@ -119,19 +141,20 @@ class Thor
119
141
  #
120
142
  # ==== Example
121
143
  #
122
- # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
144
+ # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"'
123
145
  #
124
- # prepend_file 'config/environments/test.rb' do
146
+ # prepend_to_file 'config/environments/test.rb' do
125
147
  # 'config.gem "rspec"'
126
148
  # end
127
149
  #
128
- def prepend_file(path, *args, &block)
150
+ def prepend_to_file(path, *args, &block)
129
151
  config = args.last.is_a?(Hash) ? args.pop : {}
130
152
  config.merge!(:after => /\A/)
131
- inject_into_file(path, *(args << config), &block)
153
+ insert_into_file(path, *(args << config), &block)
132
154
  end
155
+ alias_method :prepend_file, :prepend_to_file
133
156
 
134
- # Append text to a file. Since it depends on inject_into_file, it's reversible.
157
+ # Append text to a file. Since it depends on insert_into_file, it's reversible.
135
158
  #
136
159
  # ==== Parameters
137
160
  # path<String>:: path of the file to be changed
@@ -140,20 +163,21 @@ class Thor
140
163
  #
141
164
  # ==== Example
142
165
  #
143
- # append_file 'config/environments/test.rb', 'config.gem "rspec"'
166
+ # append_to_file 'config/environments/test.rb', 'config.gem "rspec"'
144
167
  #
145
- # append_file 'config/environments/test.rb' do
168
+ # append_to_file 'config/environments/test.rb' do
146
169
  # 'config.gem "rspec"'
147
170
  # end
148
171
  #
149
- def append_file(path, *args, &block)
172
+ def append_to_file(path, *args, &block)
150
173
  config = args.last.is_a?(Hash) ? args.pop : {}
151
174
  config.merge!(:before => /\z/)
152
- inject_into_file(path, *(args << config), &block)
175
+ insert_into_file(path, *(args << config), &block)
153
176
  end
177
+ alias_method :append_file, :append_to_file
154
178
 
155
179
  # Injects text right after the class definition. Since it depends on
156
- # inject_into_file, it's reversible.
180
+ # insert_into_file, it's reversible.
157
181
  #
158
182
  # ==== Parameters
159
183
  # path<String>:: path of the file to be changed
@@ -172,7 +196,7 @@ class Thor
172
196
  def inject_into_class(path, klass, *args, &block)
173
197
  config = args.last.is_a?(Hash) ? args.pop : {}
174
198
  config.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
175
- inject_into_file(path, *(args << config), &block)
199
+ insert_into_file(path, *(args << config), &block)
176
200
  end
177
201
 
178
202
  # Run a regular expression replacement on a file.
@@ -225,5 +249,22 @@ class Thor
225
249
  end
226
250
  alias :remove_dir :remove_file
227
251
 
252
+ private
253
+ attr_accessor :output_buffer
254
+ def concat(string)
255
+ @output_buffer.concat(string)
256
+ end
257
+
258
+ def capture(*args, &block)
259
+ with_output_buffer { block.call(*args) }
260
+ end
261
+
262
+ def with_output_buffer(buf = '') #:nodoc:
263
+ self.output_buffer, old_buffer = buf, output_buffer
264
+ yield
265
+ output_buffer
266
+ ensure
267
+ self.output_buffer = old_buffer
268
+ end
228
269
  end
229
270
  end
@@ -15,14 +15,14 @@ class Thor
15
15
  #
16
16
  # ==== Examples
17
17
  #
18
- # inject_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
18
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
19
19
  #
20
- # inject_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
20
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
21
21
  # gems = ask "Which gems would you like to add?"
22
22
  # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
23
23
  # end
24
24
  #
25
- def inject_into_file(destination, *args, &block)
25
+ def insert_into_file(destination, *args, &block)
26
26
  if block_given?
27
27
  data, config = block, args.shift
28
28
  else
@@ -30,6 +30,7 @@ class Thor
30
30
  end
31
31
  action InjectIntoFile.new(self, destination, data, config)
32
32
  end
33
+ alias_method :inject_into_file, :insert_into_file
33
34
 
34
35
  class InjectIntoFile < EmptyDirectory #:nodoc:
35
36
  attr_reader :replacement, :flag, :behavior
@@ -76,12 +77,16 @@ class Thor
76
77
  protected
77
78
 
78
79
  def say_status(behavior)
79
- status = if flag == /\A/
80
- behavior == :invoke ? :prepend : :unprepend
81
- elsif flag == /\z/
82
- behavior == :invoke ? :append : :unappend
80
+ status = if behavior == :invoke
81
+ if flag == /\A/
82
+ :prepend
83
+ elsif flag == /\z/
84
+ :append
85
+ else
86
+ :insert
87
+ end
83
88
  else
84
- behavior == :invoke ? :inject : :deinject
89
+ :subtract
85
90
  end
86
91
 
87
92
  super(status, config[:verbose])
@@ -94,8 +94,6 @@ class Thor
94
94
  end
95
95
 
96
96
  module ClassMethods
97
- attr_accessor :debugging
98
-
99
97
  def attr_reader(*) #:nodoc:
100
98
  no_tasks { super }
101
99
  end
@@ -384,14 +382,29 @@ class Thor
384
382
  # script.invoke(:task, first_arg, second_arg, third_arg)
385
383
  #
386
384
  def start(given_args=ARGV, config={})
387
- self.debugging = given_args.delete("--debug")
388
385
  config[:shell] ||= Thor::Base.shell.new
389
386
  dispatch(nil, given_args.dup, nil, config)
390
387
  rescue Thor::Error => e
391
- debugging ? (raise e) : config[:shell].error(e.message)
388
+ ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
392
389
  exit(1) if exit_on_failure?
393
390
  end
394
391
 
392
+ # Allows to use private methods from parent in child classes as tasks.
393
+ #
394
+ # ==== Paremeters
395
+ # names<Array>:: Method names to be used as tasks
396
+ #
397
+ # ==== Examples
398
+ #
399
+ # public_task :foo
400
+ # public_task :foo, :bar, :baz
401
+ #
402
+ def public_task(*names)
403
+ names.each do |name|
404
+ class_eval "def #{name}(*); super end"
405
+ end
406
+ end
407
+
395
408
  def handle_no_task_error(task) #:nodoc:
396
409
  if $thor_runner
397
410
  raise UndefinedTaskError, "Could not find task #{task.inspect} in #{namespace.inspect} namespace."
@@ -531,6 +544,13 @@ class Thor
531
544
  false
532
545
  end
533
546
 
547
+ #
548
+ # The basename of the program invoking the thor class.
549
+ #
550
+ def basename
551
+ File.basename($0).split(' ').first
552
+ end
553
+
534
554
  # SIGNATURE: Sets the baseclass. This is where the superclass lookup
535
555
  # finishes.
536
556
  def baseclass #:nodoc:
File without changes
@@ -0,0 +1,273 @@
1
+ require 'thor/base'
2
+
3
+ # Thor has a special class called Thor::Group. The main difference to Thor class
4
+ # is that it invokes all tasks at once. It also include some methods that allows
5
+ # invocations to be done at the class method, which are not available to Thor
6
+ # tasks.
7
+ class Thor::Group
8
+ class << self
9
+ # The description for this Thor::Group. If none is provided, but a source root
10
+ # exists, tries to find the USAGE one folder above it, otherwise searches
11
+ # in the superclass.
12
+ #
13
+ # ==== Parameters
14
+ # description<String>:: The description for this Thor::Group.
15
+ #
16
+ def desc(description=nil)
17
+ case description
18
+ when nil
19
+ @desc ||= from_superclass(:desc, nil)
20
+ else
21
+ @desc = description
22
+ end
23
+ end
24
+
25
+ # Prints help information.
26
+ #
27
+ # ==== Options
28
+ # short:: When true, shows only usage.
29
+ #
30
+ def help(shell)
31
+ shell.say "Usage:"
32
+ shell.say " #{banner}\n"
33
+ shell.say
34
+ class_options_help(shell)
35
+ shell.say self.desc if self.desc
36
+ end
37
+
38
+ # Stores invocations for this class merging with superclass values.
39
+ #
40
+ def invocations #:nodoc:
41
+ @invocations ||= from_superclass(:invocations, {})
42
+ end
43
+
44
+ # Stores invocation blocks used on invoke_from_option.
45
+ #
46
+ def invocation_blocks #:nodoc:
47
+ @invocation_blocks ||= from_superclass(:invocation_blocks, {})
48
+ end
49
+
50
+ # Invoke the given namespace or class given. It adds an instance
51
+ # method that will invoke the klass and task. You can give a block to
52
+ # configure how it will be invoked.
53
+ #
54
+ # The namespace/class given will have its options showed on the help
55
+ # usage. Check invoke_from_option for more information.
56
+ #
57
+ def invoke(*names, &block)
58
+ options = names.last.is_a?(Hash) ? names.pop : {}
59
+ verbose = options.fetch(:verbose, true)
60
+
61
+ names.each do |name|
62
+ invocations[name] = false
63
+ invocation_blocks[name] = block if block_given?
64
+
65
+ class_eval <<-METHOD, __FILE__, __LINE__
66
+ def _invoke_#{name.to_s.gsub(/\W/, '_')}
67
+ klass, task = self.class.prepare_for_invocation(nil, #{name.inspect})
68
+
69
+ if klass
70
+ say_status :invoke, #{name.inspect}, #{verbose.inspect}
71
+ block = self.class.invocation_blocks[#{name.inspect}]
72
+ _invoke_for_class_method klass, task, &block
73
+ else
74
+ say_status :error, %(#{name.inspect} [not found]), :red
75
+ end
76
+ end
77
+ METHOD
78
+ end
79
+ end
80
+
81
+ # Invoke a thor class based on the value supplied by the user to the
82
+ # given option named "name". A class option must be created before this
83
+ # method is invoked for each name given.
84
+ #
85
+ # ==== Examples
86
+ #
87
+ # class GemGenerator < Thor::Group
88
+ # class_option :test_framework, :type => :string
89
+ # invoke_from_option :test_framework
90
+ # end
91
+ #
92
+ # ==== Boolean options
93
+ #
94
+ # In some cases, you want to invoke a thor class if some option is true or
95
+ # false. This is automatically handled by invoke_from_option. Then the
96
+ # option name is used to invoke the generator.
97
+ #
98
+ # ==== Preparing for invocation
99
+ #
100
+ # In some cases you want to customize how a specified hook is going to be
101
+ # invoked. You can do that by overwriting the class method
102
+ # prepare_for_invocation. The class method must necessarily return a klass
103
+ # and an optional task.
104
+ #
105
+ # ==== Custom invocations
106
+ #
107
+ # You can also supply a block to customize how the option is giong to be
108
+ # invoked. The block receives two parameters, an instance of the current
109
+ # class and the klass to be invoked.
110
+ #
111
+ def invoke_from_option(*names, &block)
112
+ options = names.last.is_a?(Hash) ? names.pop : {}
113
+ verbose = options.fetch(:verbose, :white)
114
+
115
+ names.each do |name|
116
+ unless class_options.key?(name)
117
+ raise ArgumentError, "You have to define the option #{name.inspect} " <<
118
+ "before setting invoke_from_option."
119
+ end
120
+
121
+ invocations[name] = true
122
+ invocation_blocks[name] = block if block_given?
123
+
124
+ class_eval <<-METHOD, __FILE__, __LINE__
125
+ def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
126
+ return unless options[#{name.inspect}]
127
+
128
+ value = options[#{name.inspect}]
129
+ value = #{name.inspect} if TrueClass === value
130
+ klass, task = self.class.prepare_for_invocation(#{name.inspect}, value)
131
+
132
+ if klass
133
+ say_status :invoke, value, #{verbose.inspect}
134
+ block = self.class.invocation_blocks[#{name.inspect}]
135
+ _invoke_for_class_method klass, task, &block
136
+ else
137
+ say_status :error, %(\#{value} [not found]), :red
138
+ end
139
+ end
140
+ METHOD
141
+ end
142
+ end
143
+
144
+ # Remove a previously added invocation.
145
+ #
146
+ # ==== Examples
147
+ #
148
+ # remove_invocation :test_framework
149
+ #
150
+ def remove_invocation(*names)
151
+ names.each do |name|
152
+ remove_task(name)
153
+ remove_class_option(name)
154
+ invocations.delete(name)
155
+ invocation_blocks.delete(name)
156
+ end
157
+ end
158
+
159
+ # Overwrite class options help to allow invoked generators options to be
160
+ # shown recursively when invoking a generator.
161
+ #
162
+ def class_options_help(shell, groups={}) #:nodoc:
163
+ get_options_from_invocations(groups, class_options) do |klass|
164
+ klass.send(:get_options_from_invocations, groups, class_options)
165
+ end
166
+ super(shell, groups)
167
+ end
168
+
169
+ # Get invocations array and merge options from invocations. Those
170
+ # options are added to group_options hash. Options that already exists
171
+ # in base_options are not added twice.
172
+ #
173
+ def get_options_from_invocations(group_options, base_options) #:nodoc:
174
+ invocations.each do |name, from_option|
175
+ value = if from_option
176
+ option = class_options[name]
177
+ option.type == :boolean ? name : option.default
178
+ else
179
+ name
180
+ end
181
+ next unless value
182
+
183
+ klass, task = prepare_for_invocation(name, value)
184
+ next unless klass && klass.respond_to?(:class_options)
185
+
186
+ value = value.to_s
187
+ human_name = value.respond_to?(:classify) ? value.classify : value
188
+
189
+ group_options[human_name] ||= []
190
+ group_options[human_name] += klass.class_options.values.select do |option|
191
+ base_options[option.name.to_sym].nil? && option.group.nil? &&
192
+ !group_options.values.flatten.any? { |i| i.name == option.name }
193
+ end
194
+
195
+ yield klass if block_given?
196
+ end
197
+ end
198
+
199
+ # Returns tasks ready to be printed.
200
+ def printable_tasks(*)
201
+ item = []
202
+ item << banner
203
+ item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
204
+ [item]
205
+ end
206
+
207
+ def handle_argument_error(task, error) #:nodoc:
208
+ raise error, "#{task.name.inspect} was called incorrectly. Are you sure it has arity equals to 0?"
209
+ end
210
+
211
+ protected
212
+
213
+ # The method responsible for dispatching given the args.
214
+ def dispatch(task, given_args, given_opts, config) #:nodoc:
215
+ if Thor::HELP_MAPPINGS.include?(given_args.first)
216
+ help(config[:shell])
217
+ return
218
+ end
219
+
220
+ args, opts = Thor::Options.split(given_args)
221
+ opts = given_opts || opts
222
+
223
+ if task
224
+ new(args, opts, config).invoke_task(all_tasks[task])
225
+ else
226
+ new(args, opts, config).invoke_all
227
+ end
228
+ end
229
+
230
+ # The banner for this class. You can customize it if you are invoking the
231
+ # thor class by another ways which is not the Thor::Runner.
232
+ def banner
233
+ "#{basename} #{self_task.formatted_usage(self, false)}"
234
+ end
235
+
236
+ # Represents the whole class as a task.
237
+ def self_task #:nodoc:
238
+ Thor::DynamicTask.new(self.namespace, class_options)
239
+ end
240
+
241
+ def baseclass #:nodoc:
242
+ Thor::Group
243
+ end
244
+
245
+ def create_task(meth) #:nodoc:
246
+ tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil, nil)
247
+ true
248
+ end
249
+ end
250
+
251
+ include Thor::Base
252
+
253
+ protected
254
+
255
+ # Shortcut to invoke with padding and block handling. Use internally by
256
+ # invoke and invoke_from_option class methods.
257
+ def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
258
+ with_padding do
259
+ if block
260
+ case block.arity
261
+ when 3
262
+ block.call(self, klass, task)
263
+ when 2
264
+ block.call(self, klass)
265
+ when 1
266
+ instance_exec(klass, &block)
267
+ end
268
+ else
269
+ invoke klass, task, *args
270
+ end
271
+ end
272
+ end
273
+ end