engineyard-serverside 1.5.23.ruby19.8 → 1.5.23.ruby19.9

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.
Files changed (67) hide show
  1. data/lib/engineyard-serverside.rb +3 -1
  2. data/lib/engineyard-serverside/cli.rb +11 -19
  3. data/lib/engineyard-serverside/deploy.rb +3 -3
  4. data/lib/engineyard-serverside/future.rb +33 -0
  5. data/lib/engineyard-serverside/futures/celluloid.rb +25 -0
  6. data/lib/engineyard-serverside/futures/dataflow.rb +25 -0
  7. data/lib/engineyard-serverside/logged_output.rb +8 -3
  8. data/lib/engineyard-serverside/task.rb +9 -12
  9. data/lib/engineyard-serverside/version.rb +1 -1
  10. data/lib/vendor/celluloid/lib/celluloid.rb +261 -0
  11. data/lib/vendor/celluloid/lib/celluloid/actor.rb +242 -0
  12. data/lib/vendor/celluloid/lib/celluloid/actor_pool.rb +54 -0
  13. data/lib/vendor/celluloid/lib/celluloid/actor_proxy.rb +75 -0
  14. data/lib/vendor/celluloid/lib/celluloid/application.rb +78 -0
  15. data/lib/vendor/celluloid/lib/celluloid/calls.rb +94 -0
  16. data/lib/vendor/celluloid/lib/celluloid/core_ext.rb +14 -0
  17. data/lib/vendor/celluloid/lib/celluloid/events.rb +14 -0
  18. data/lib/vendor/celluloid/lib/celluloid/fiber.rb +33 -0
  19. data/lib/vendor/celluloid/lib/celluloid/fsm.rb +141 -0
  20. data/lib/vendor/celluloid/lib/celluloid/future.rb +60 -0
  21. data/lib/vendor/celluloid/lib/celluloid/links.rb +61 -0
  22. data/lib/vendor/celluloid/lib/celluloid/logger.rb +32 -0
  23. data/lib/vendor/celluloid/lib/celluloid/mailbox.rb +124 -0
  24. data/lib/vendor/celluloid/lib/celluloid/receivers.rb +66 -0
  25. data/lib/vendor/celluloid/lib/celluloid/registry.rb +33 -0
  26. data/lib/vendor/celluloid/lib/celluloid/responses.rb +26 -0
  27. data/lib/vendor/celluloid/lib/celluloid/rspec.rb +2 -0
  28. data/lib/vendor/celluloid/lib/celluloid/signals.rb +50 -0
  29. data/lib/vendor/celluloid/lib/celluloid/supervisor.rb +57 -0
  30. data/lib/vendor/celluloid/lib/celluloid/task.rb +73 -0
  31. data/lib/vendor/celluloid/lib/celluloid/tcp_server.rb +33 -0
  32. data/lib/vendor/celluloid/lib/celluloid/timers.rb +109 -0
  33. data/lib/vendor/celluloid/lib/celluloid/version.rb +4 -0
  34. data/lib/vendor/dataflow/dataflow.rb +124 -0
  35. data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
  36. data/lib/vendor/dataflow/dataflow/equality.rb +44 -0
  37. data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
  38. data/lib/vendor/dataflow/dataflow/port.rb +54 -0
  39. data/lib/vendor/open4/lib/open4.rb +432 -0
  40. data/lib/vendor/thor/lib/thor.rb +244 -0
  41. data/lib/vendor/thor/lib/thor/actions.rb +275 -0
  42. data/lib/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  43. data/lib/vendor/thor/lib/thor/actions/directory.rb +91 -0
  44. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
  45. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
  46. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
  47. data/lib/vendor/thor/lib/thor/base.rb +540 -0
  48. data/lib/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
  49. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  50. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  51. data/lib/vendor/thor/lib/thor/error.rb +30 -0
  52. data/lib/vendor/thor/lib/thor/group.rb +271 -0
  53. data/lib/vendor/thor/lib/thor/invocation.rb +180 -0
  54. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  55. data/lib/vendor/thor/lib/thor/parser/argument.rb +67 -0
  56. data/lib/vendor/thor/lib/thor/parser/arguments.rb +150 -0
  57. data/lib/vendor/thor/lib/thor/parser/option.rb +128 -0
  58. data/lib/vendor/thor/lib/thor/parser/options.rb +169 -0
  59. data/lib/vendor/thor/lib/thor/rake_compat.rb +66 -0
  60. data/lib/vendor/thor/lib/thor/runner.rb +314 -0
  61. data/lib/vendor/thor/lib/thor/shell.rb +83 -0
  62. data/lib/vendor/thor/lib/thor/shell/basic.rb +239 -0
  63. data/lib/vendor/thor/lib/thor/shell/color.rb +108 -0
  64. data/lib/vendor/thor/lib/thor/task.rb +102 -0
  65. data/lib/vendor/thor/lib/thor/util.rb +230 -0
  66. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  67. metadata +70 -10
@@ -0,0 +1,169 @@
1
+ class Thor
2
+ # This is a modified version of Daniel Berger's Getopt::Long class, licensed
3
+ # under Ruby's license.
4
+ #
5
+ class Options < Arguments #:nodoc:
6
+ LONG_RE = /^(--\w+(?:-\w+)*)$/
7
+ SHORT_RE = /^(-[a-z])$/i
8
+ EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
9
+ SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args
10
+ SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i
11
+
12
+ # Receives a hash and makes it switches.
13
+ def self.to_switches(options)
14
+ options.map do |key, value|
15
+ case value
16
+ when true
17
+ "--#{key}"
18
+ when Array
19
+ "--#{key} #{value.map{ |v| v.inspect }.join(' ')}"
20
+ when Hash
21
+ "--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}"
22
+ when nil, false
23
+ ""
24
+ else
25
+ "--#{key} #{value.inspect}"
26
+ end
27
+ end.join(" ")
28
+ end
29
+
30
+ # Takes a hash of Thor::Option and a hash with defaults.
31
+ def initialize(hash_options={}, defaults={})
32
+ options = hash_options.values
33
+ super(options)
34
+
35
+ # Add defaults
36
+ defaults.each do |key, value|
37
+ @assigns[key.to_s] = value
38
+ @non_assigned_required.delete(hash_options[key])
39
+ end
40
+
41
+ @shorts, @switches, @unknown = {}, {}, []
42
+
43
+ options.each do |option|
44
+ @switches[option.switch_name] = option
45
+
46
+ option.aliases.each do |short|
47
+ @shorts[short.to_s] ||= option.switch_name
48
+ end
49
+ end
50
+ end
51
+
52
+ def parse(args)
53
+ @pile = args.dup
54
+
55
+ while peek
56
+ if current_is_switch?
57
+ case shift
58
+ when SHORT_SQ_RE
59
+ unshift($1.split('').map { |f| "-#{f}" })
60
+ next
61
+ when EQ_RE, SHORT_NUM
62
+ unshift($2)
63
+ switch = $1
64
+ when LONG_RE, SHORT_RE
65
+ switch = $1
66
+ end
67
+
68
+ switch = normalize_switch(switch)
69
+ option = switch_option(switch)
70
+ @assigns[option.human_name] = parse_peek(switch, option)
71
+ elsif current_is_switch_formatted?
72
+ @unknown << shift
73
+ else
74
+ shift
75
+ end
76
+ end
77
+
78
+ check_requirement!
79
+
80
+ assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
81
+ assigns.freeze
82
+ assigns
83
+ end
84
+
85
+ def check_unknown!
86
+ raise UnknownArgumentError, "Unknown switches '#{@unknown.join(', ')}'" unless @unknown.empty?
87
+ end
88
+
89
+ protected
90
+
91
+ # Returns true if the current value in peek is a registered switch.
92
+ #
93
+ def current_is_switch?
94
+ case peek
95
+ when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
96
+ switch?($1)
97
+ when SHORT_SQ_RE
98
+ $1.split('').any? { |f| switch?("-#{f}") }
99
+ end
100
+ end
101
+
102
+ def switch_formatted?(arg)
103
+ case arg
104
+ when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
105
+ true
106
+ else
107
+ false
108
+ end
109
+ end
110
+
111
+ def current_is_switch_formatted?
112
+ switch_formatted? peek
113
+ end
114
+
115
+ def switch?(arg)
116
+ switch_option(arg) || @shorts.key?(arg)
117
+ end
118
+
119
+ def switch_option(arg)
120
+ if match = no_or_skip?(arg)
121
+ @switches[arg] || @switches["--#{match}"]
122
+ else
123
+ @switches[arg]
124
+ end
125
+ end
126
+
127
+ def no_or_skip?(arg)
128
+ arg =~ /^--(no|skip)-([-\w]+)$/
129
+ $2
130
+ end
131
+
132
+ # Check if the given argument is actually a shortcut.
133
+ #
134
+ def normalize_switch(arg)
135
+ @shorts.key?(arg) ? @shorts[arg] : arg
136
+ end
137
+
138
+ # Parse boolean values which can be given as --foo=true, --foo or --no-foo.
139
+ #
140
+ def parse_boolean(switch)
141
+ if current_is_value?
142
+ ["true", "TRUE", "t", "T", true].include?(shift)
143
+ else
144
+ @switches.key?(switch) || !no_or_skip?(switch)
145
+ end
146
+ end
147
+
148
+ # Parse the value at the peek analyzing if it requires an input or not.
149
+ #
150
+ def parse_peek(switch, option)
151
+ if current_is_switch_formatted? || last?
152
+ if option.boolean?
153
+ # No problem for boolean types
154
+ elsif no_or_skip?(switch)
155
+ return nil # User set value to nil
156
+ elsif option.string? && !option.required?
157
+ # Return the default if there is one, else the human name
158
+ return option.default || option.human_name
159
+ else
160
+ raise MalformattedArgumentError, "No value provided for option '#{switch}'"
161
+ end
162
+ end
163
+
164
+ @non_assigned_required.delete(option)
165
+ send(:"parse_#{option.type}", switch)
166
+ end
167
+
168
+ end
169
+ end
@@ -0,0 +1,66 @@
1
+ require 'rake'
2
+
3
+ class Thor
4
+ # Adds a compatibility layer to your Thor classes which allows you to use
5
+ # rake package tasks. For example, to use rspec rake tasks, one can do:
6
+ #
7
+ # require 'thor/rake_compat'
8
+ #
9
+ # class Default < Thor
10
+ # include Thor::RakeCompat
11
+ #
12
+ # Spec::Rake::SpecTask.new(:spec) do |t|
13
+ # t.spec_opts = ['--options', "spec/spec.opts"]
14
+ # t.spec_files = FileList['spec/**/*_spec.rb']
15
+ # end
16
+ # end
17
+ #
18
+ module RakeCompat
19
+ def self.rake_classes
20
+ @rake_classes ||= []
21
+ end
22
+
23
+ def self.included(base)
24
+ # Hack. Make rakefile point to invoker, so rdoc task is generated properly.
25
+ rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
26
+ Rake.application.instance_variable_set(:@rakefile, rakefile)
27
+ self.rake_classes << base
28
+ end
29
+ end
30
+ end
31
+
32
+ class Object #:nodoc:
33
+ alias :rake_task :task
34
+ alias :rake_namespace :namespace
35
+
36
+ def task(*args, &block)
37
+ task = rake_task(*args, &block)
38
+
39
+ if klass = Thor::RakeCompat.rake_classes.last
40
+ non_namespaced_name = task.name.split(':').last
41
+
42
+ description = non_namespaced_name
43
+ description << task.arg_names.map{ |n| n.to_s.upcase }.join(' ')
44
+ description.strip!
45
+
46
+ klass.desc description, task.comment || non_namespaced_name
47
+ klass.send :define_method, non_namespaced_name do |*args|
48
+ Rake::Task[task.name.to_sym].invoke(*args)
49
+ end
50
+ end
51
+
52
+ task
53
+ end
54
+
55
+ def namespace(name, &block)
56
+ if klass = Thor::RakeCompat.rake_classes.last
57
+ const_name = Thor::Util.camel_case(name.to_s).to_sym
58
+ klass.const_set(const_name, Class.new(Thor))
59
+ new_klass = klass.const_get(const_name)
60
+ Thor::RakeCompat.rake_classes << new_klass
61
+ end
62
+
63
+ rake_namespace(name, &block)
64
+ Thor::RakeCompat.rake_classes.pop
65
+ end
66
+ end
@@ -0,0 +1,314 @@
1
+ require 'thor'
2
+ require 'thor/group'
3
+ require 'thor/core_ext/file_binary_read'
4
+
5
+ require 'fileutils'
6
+ require 'open-uri'
7
+ require 'yaml'
8
+ require 'digest/md5'
9
+ require 'pathname'
10
+
11
+ class Thor::Runner < Thor #:nodoc:
12
+ map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
13
+
14
+ # Override Thor#help so it can give information about any class and any method.
15
+ #
16
+ def help(meth=nil)
17
+ if meth && !self.respond_to?(meth)
18
+ initialize_thorfiles(meth)
19
+ klass, task = Thor::Util.find_class_and_task_by_namespace!(meth)
20
+ klass.start(["-h", task].compact, :shell => self.shell)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ # If a task is not found on Thor::Runner, method missing is invoked and
27
+ # Thor::Runner is then responsable for finding the task in all classes.
28
+ #
29
+ def method_missing(meth, *args)
30
+ meth = meth.to_s
31
+ initialize_thorfiles(meth)
32
+ klass, task = Thor::Util.find_class_and_task_by_namespace!(meth)
33
+ args.unshift(task) if task
34
+ klass.start(args, :shell => self.shell)
35
+ end
36
+
37
+ desc "install NAME", "Install an optionally named Thor file into your system tasks"
38
+ method_options :as => :string, :relative => :boolean, :force => :boolean
39
+ def install(name)
40
+ initialize_thorfiles
41
+
42
+ # If a directory name is provided as the argument, look for a 'main.thor'
43
+ # task in said directory.
44
+ begin
45
+ if File.directory?(File.expand_path(name))
46
+ base, package = File.join(name, "main.thor"), :directory
47
+ contents = open(base).read
48
+ else
49
+ base, package = name, :file
50
+ contents = open(name).read
51
+ end
52
+ rescue OpenURI::HTTPError
53
+ raise Error, "Error opening URI '#{name}'"
54
+ rescue Errno::ENOENT
55
+ raise Error, "Error opening file '#{name}'"
56
+ end
57
+
58
+ say "Your Thorfile contains:"
59
+ say contents
60
+
61
+ unless options["force"]
62
+ return false if no?("Do you wish to continue [y/N]?")
63
+ end
64
+
65
+ as = options["as"] || begin
66
+ first_line = contents.split("\n")[0]
67
+ (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
68
+ end
69
+
70
+ unless as
71
+ basename = File.basename(name)
72
+ as = ask("Please specify a name for #{name} in the system repository [#{basename}]:")
73
+ as = basename if as.empty?
74
+ end
75
+
76
+ location = if options[:relative] || name =~ /^http:\/\//
77
+ name
78
+ else
79
+ File.expand_path(name)
80
+ end
81
+
82
+ thor_yaml[as] = {
83
+ :filename => Digest::MD5.hexdigest(name + as),
84
+ :location => location,
85
+ :namespaces => Thor::Util.namespaces_in_content(contents, base)
86
+ }
87
+
88
+ save_yaml(thor_yaml)
89
+ say "Storing thor file in your system repository"
90
+ destination = File.join(thor_root, thor_yaml[as][:filename])
91
+
92
+ if package == :file
93
+ File.open(destination, "w") { |f| f.puts contents }
94
+ else
95
+ FileUtils.cp_r(name, destination)
96
+ end
97
+
98
+ thor_yaml[as][:filename] # Indicate success
99
+ end
100
+
101
+ desc "version", "Show Thor version"
102
+ def version
103
+ require 'thor/version'
104
+ say "Thor #{Thor::VERSION}"
105
+ end
106
+
107
+ desc "uninstall NAME", "Uninstall a named Thor module"
108
+ def uninstall(name)
109
+ raise Error, "Can't find module '#{name}'" unless thor_yaml[name]
110
+ say "Uninstalling #{name}."
111
+ FileUtils.rm_rf(File.join(thor_root, "#{thor_yaml[name][:filename]}"))
112
+
113
+ thor_yaml.delete(name)
114
+ save_yaml(thor_yaml)
115
+
116
+ puts "Done."
117
+ end
118
+
119
+ desc "update NAME", "Update a Thor file from its original location"
120
+ def update(name)
121
+ raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location]
122
+
123
+ say "Updating '#{name}' from #{thor_yaml[name][:location]}"
124
+
125
+ old_filename = thor_yaml[name][:filename]
126
+ self.options = self.options.merge("as" => name)
127
+ filename = install(thor_yaml[name][:location])
128
+
129
+ unless filename == old_filename
130
+ File.delete(File.join(thor_root, old_filename))
131
+ end
132
+ end
133
+
134
+ desc "installed", "List the installed Thor modules and tasks"
135
+ method_options :internal => :boolean
136
+ def installed
137
+ initialize_thorfiles(nil, true)
138
+ display_klasses(true, options["internal"])
139
+ end
140
+
141
+ desc "list [SEARCH]", "List the available thor tasks (--substring means .*SEARCH)"
142
+ method_options :substring => :boolean, :group => :string, :all => :boolean
143
+ def list(search="")
144
+ initialize_thorfiles
145
+
146
+ search = ".*#{search}" if options["substring"]
147
+ search = /^#{search}.*/i
148
+ group = options[:group] || "standard"
149
+
150
+ klasses = Thor::Base.subclasses.select do |k|
151
+ (options[:all] || k.group == group) && k.namespace =~ search
152
+ end
153
+
154
+ display_klasses(false, false, klasses)
155
+ end
156
+
157
+ private
158
+
159
+ def self.banner(task)
160
+ "thor " + task.formatted_usage(self, false)
161
+ end
162
+
163
+ def thor_root
164
+ Thor::Util.thor_root
165
+ end
166
+
167
+ def thor_yaml
168
+ @thor_yaml ||= begin
169
+ yaml_file = File.join(thor_root, "thor.yml")
170
+ yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
171
+ yaml || {}
172
+ end
173
+ end
174
+
175
+ # Save the yaml file. If none exists in thor root, creates one.
176
+ #
177
+ def save_yaml(yaml)
178
+ yaml_file = File.join(thor_root, "thor.yml")
179
+
180
+ unless File.exists?(yaml_file)
181
+ FileUtils.mkdir_p(thor_root)
182
+ yaml_file = File.join(thor_root, "thor.yml")
183
+ FileUtils.touch(yaml_file)
184
+ end
185
+
186
+ File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml }
187
+ end
188
+
189
+ def self.exit_on_failure?
190
+ true
191
+ end
192
+
193
+ # Load the thorfiles. If relevant_to is supplied, looks for specific files
194
+ # in the thor_root instead of loading them all.
195
+ #
196
+ # By default, it also traverses the current path until find Thor files, as
197
+ # described in thorfiles. This look up can be skipped by suppliying
198
+ # skip_lookup true.
199
+ #
200
+ def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
201
+ thorfiles(relevant_to, skip_lookup).each do |f|
202
+ Thor::Util.load_thorfile(f) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
203
+ end
204
+ end
205
+
206
+ # Finds Thorfiles by traversing from your current directory down to the root
207
+ # directory of your system. If at any time we find a Thor file, we stop.
208
+ #
209
+ # We also ensure that system-wide Thorfiles are loaded first, so local
210
+ # Thorfiles can override them.
211
+ #
212
+ # ==== Example
213
+ #
214
+ # If we start at /Users/wycats/dev/thor ...
215
+ #
216
+ # 1. /Users/wycats/dev/thor
217
+ # 2. /Users/wycats/dev
218
+ # 3. /Users/wycats <-- we find a Thorfile here, so we stop
219
+ #
220
+ # Suppose we start at c:\Documents and Settings\james\dev\thor ...
221
+ #
222
+ # 1. c:\Documents and Settings\james\dev\thor
223
+ # 2. c:\Documents and Settings\james\dev
224
+ # 3. c:\Documents and Settings\james
225
+ # 4. c:\Documents and Settings
226
+ # 5. c:\ <-- no Thorfiles found!
227
+ #
228
+ def thorfiles(relevant_to=nil, skip_lookup=false)
229
+ thorfiles = []
230
+
231
+ unless skip_lookup
232
+ Pathname.pwd.ascend do |path|
233
+ thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
234
+ break unless thorfiles.empty?
235
+ end
236
+ end
237
+
238
+ files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob)
239
+ files += thorfiles
240
+ files -= ["#{thor_root}/thor.yml"]
241
+
242
+ files.map! do |file|
243
+ File.directory?(file) ? File.join(file, "main.thor") : file
244
+ end
245
+ end
246
+
247
+ # Load thorfiles relevant to the given method. If you provide "foo:bar" it
248
+ # will load all thor files in the thor.yaml that has "foo" e "foo:bar"
249
+ # namespaces registered.
250
+ #
251
+ def thorfiles_relevant_to(meth)
252
+ lookup = [ meth, meth.split(":")[0...-1].join(":") ]
253
+
254
+ files = thor_yaml.select do |k, v|
255
+ v[:namespaces] && !(v[:namespaces] & lookup).empty?
256
+ end
257
+
258
+ files.map { |k, v| File.join(thor_root, "#{v[:filename]}") }
259
+ end
260
+
261
+ # Display information about the given klasses. If with_module is given,
262
+ # it shows a table with information extracted from the yaml file.
263
+ #
264
+ def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
265
+ klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
266
+
267
+ raise Error, "No Thor tasks available" if klasses.empty?
268
+ show_modules if with_modules && !thor_yaml.empty?
269
+
270
+ # Remove subclasses
271
+ klasses.dup.each do |klass|
272
+ klasses -= Thor::Util.thor_classes_in(klass)
273
+ end
274
+
275
+ list = Hash.new { |h,k| h[k] = [] }
276
+ groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
277
+
278
+ # Get classes which inherit from Thor
279
+ (klasses - groups).each { |k| list[k.namespace] += k.printable_tasks(false) }
280
+
281
+ # Get classes which inherit from Thor::Base
282
+ groups.map! { |k| k.printable_tasks(false).first }
283
+ list["root"] = groups
284
+
285
+ # Order namespaces with default coming first
286
+ list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
287
+ list.each { |n, tasks| display_tasks(n, tasks) unless tasks.empty? }
288
+ end
289
+
290
+ def display_tasks(namespace, list) #:nodoc:
291
+ list.sort!{ |a,b| a[0] <=> b[0] }
292
+
293
+ say shell.set_color(namespace, :blue, true)
294
+ say "-" * namespace.size
295
+
296
+ print_table(list, :truncate => true)
297
+ say
298
+ end
299
+
300
+ def show_modules #:nodoc:
301
+ info = []
302
+ labels = ["Modules", "Namespaces"]
303
+
304
+ info << labels
305
+ info << [ "-" * labels[0].size, "-" * labels[1].size ]
306
+
307
+ thor_yaml.each do |name, hash|
308
+ info << [ name, hash[:namespaces].join(", ") ]
309
+ end
310
+
311
+ print_table info
312
+ say ""
313
+ end
314
+ end