Class: Thor

Inherits:
Object
  • Object
show all
Defined in:
lib/thor/lib/thor/options.rb,
lib/thor/lib/thor.rb,
lib/thor/lib/thor/task.rb,
lib/thor/lib/thor/util.rb,
lib/thor/lib/thor/error.rb,
lib/thor/lib/thor/tasks.rb,
lib/thor/lib/thor/ordered_hash.rb

Overview

This is a modified version of Daniel Berger’s Getopt::Long class, licensed under Ruby’s license.

Direct Known Subclasses

SC::Tools, Runner

Defined Under Namespace

Modules: Tasks, Util Classes: Error, Options, OrderedHash, PackageTask, Runner, Task, TaskHash

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}, *args) ⇒ Thor

Returns a new instance of Thor.



142
143
# File 'lib/thor/lib/thor.rb', line 142

def initialize(opts = {}, *args)
end

Instance Attribute Details

#optionsObject

Returns the value of attribute options.



8
9
10
# File 'lib/thor/lib/thor.rb', line 8

def options
  @options
end

Class Method Details

.[](task) ⇒ Object

Raises:



60
61
62
63
64
65
# File 'lib/thor/lib/thor.rb', line 60

def self.[](task)
  namespaces = task.split(":")
  klass = Thor::Util.constant_from_thor_path(namespaces[0...-1].join(":"))
  raise Error, "`#{klass}' is not a Thor class" unless klass <= Thor
  klass.tasks[namespaces.last]
end

.default_task(meth = nil) ⇒ Object



10
11
12
13
14
15
# File 'lib/thor/lib/thor.rb', line 10

def self.default_task(meth=nil)
  unless meth.nil?
    @default_task = (meth == :none) ? 'help' : meth.to_s
  end
  @default_task ||= (self == Thor ? 'help' : superclass.default_task)
end

.desc(usage, description) ⇒ Object



28
29
30
# File 'lib/thor/lib/thor.rb', line 28

def self.desc(usage, description)
  @usage, @desc = usage, description
end

.group(name) ⇒ Object



32
33
34
# File 'lib/thor/lib/thor.rb', line 32

def self.group(name)
  @group_name = name.to_s
end

.group_nameObject



36
37
38
# File 'lib/thor/lib/thor.rb', line 36

def self.group_name
  @group_name || 'standard'
end

.install_task(spec) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/thor/lib/thor/tasks.rb', line 14

def self.install_task(spec)
  package_task spec

  null, sudo, gem = RUBY_PLATFORM =~ /w(in)?32$/ ? ['NUL', '', 'gem.bat'] :
                                                   ['/dev/null', 'sudo', 'gem']
  
  desc "install", "install the gem"
  define_method :install do
    old_stderr, $stderr = $stderr.dup, File.open(null, "w")
    package
    $stderr = old_stderr
    system %{#{sudo} #{Gem.ruby} -S #{gem} install pkg/#{spec.name}-#{spec.version} --no-rdoc --no-ri --no-update-sources}
  end
end

.invoke(task_name = nil, args = ARGV) ⇒ Object

Invokes a specific task. You can use this method instead of start() to run a thor task if you know the specific task you want to invoke.



94
95
96
97
98
# File 'lib/thor/lib/thor.rb', line 94

def self.invoke(task_name=nil, args = ARGV)
  args = args.dup
  args.unshift(task_name || default_task)
  start(args)
end

.map(map) ⇒ Object



17
18
19
20
21
22
23
24
25
26
# File 'lib/thor/lib/thor.rb', line 17

def self.map(map)
  @map ||= superclass.instance_variable_get("@map") || {}
  map.each do |key, value|
    if key.respond_to?(:each)
      key.each {|subkey| @map[subkey] = value}
    else
      @map[key] = value
    end
  end
end

.maximaObject



67
68
69
70
71
72
73
74
# File 'lib/thor/lib/thor.rb', line 67

def self.maxima
  @maxima ||= begin
    max_usage = tasks.map {|_, t| t.usage}.max {|x,y| x.to_s.size <=> y.to_s.size}.size
    max_desc  = tasks.map {|_, t| t.description}.max {|x,y| x.to_s.size <=> y.to_s.size}.size
    max_opts  = tasks.map {|_, t| t.opts ? t.opts.formatted_usage : ""}.max {|x,y| x.to_s.size <=> y.to_s.size}.size
    Struct.new(:description, :usage, :opt).new(max_desc, max_usage, max_opts)
  end
end

.method_options(opts) ⇒ Object



40
41
42
# File 'lib/thor/lib/thor.rb', line 40

def self.method_options(opts)
  @method_options = (@method_options || {}).merge(opts)
end

.optsObject



56
57
58
# File 'lib/thor/lib/thor.rb', line 56

def self.opts
  (@opts || {}).merge(self == Thor ? {} : superclass.opts)
end

.package_task(spec) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/thor/lib/thor/tasks.rb', line 5

def self.package_task(spec)
  desc "package", "package up the gem"
  define_method :package do
    FileUtils.mkdir_p(File.join(Dir.pwd, "pkg"))
    Gem::Builder.new(spec).build
    FileUtils.mv(spec.file_name, File.join(Dir.pwd, "pkg", spec.file_name))
  end
end

.spec_task(file_list, opts = {}) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/thor/lib/thor/tasks.rb', line 29

def self.spec_task(file_list, opts = {})
  name = opts.delete(:name) || "spec"
  rcov_dir = opts.delete(:rcov_dir) || "coverage"
  file_list = file_list.map {|f| %["#{f}"]}.join(" ")
  verbose = opts.delete(:verbose)
  opts = {:format => "specdoc", :color => true}.merge(opts)
  
  rcov_opts = convert_task_options(opts.delete(:rcov) || {})
  rcov = !rcov_opts.empty?
  options = convert_task_options(opts)
  
  if rcov
    FileUtils.rm_rf(File.join(Dir.pwd, rcov_dir))
  end
  
  desc(name, "spec task")
  define_method(name) do
    cmd = "ruby "
    if rcov
      cmd << "-S rcov -o #{rcov_dir} #{rcov_opts} "
    end
    cmd << `which spec`.chomp
    cmd << " -- " if rcov
    cmd << " "
    cmd << file_list
    cmd << " "
    cmd << options
    puts cmd if verbose
    system(cmd)
    exit($?.exitstatus)
  end
end

.start(args = ARGV) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/thor/lib/thor.rb', line 76

def self.start(args = ARGV)
  
  options = Thor::Options.new(self.opts)
  opts = options.parse(args, false)
  args = options.trailing_non_opts

  meth = args.first
  meth = @map[meth].to_s if @map && @map[meth]
  meth ||= default_task
  meth = meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
  
  tasks[meth].parse new(opts, *args), args[1..-1]
rescue Thor::Error => e
  $stderr.puts e.message
end

.subclass_filesObject



44
45
46
# File 'lib/thor/lib/thor.rb', line 44

def self.subclass_files
  @subclass_files ||= Hash.new {|h,k| h[k] = []}
end

.subclassesObject



48
49
50
# File 'lib/thor/lib/thor.rb', line 48

def self.subclasses
  @subclasses ||= []
end

.tasksObject



52
53
54
# File 'lib/thor/lib/thor.rb', line 52

def self.tasks
  @tasks ||= TaskHash.new(self)
end

Instance Method Details

#help(task = nil) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/thor/lib/thor.rb', line 148

def help(task = nil)
  if task
    if task.include? ?:
      task = self.class[task]
      namespace = true
    else
      task = self.class.tasks[task]
    end

    puts task.formatted_usage(namespace)
    puts task.description
  else
    puts "Options"
    puts "-------"
    self.class.tasks.each do |_, task|
      format = "%-" + (self.class.maxima.usage + self.class.maxima.opt + 4).to_s + "s"
      print format % ("#{task.formatted_usage}")      
      puts  task.description.split("\n").first
    end
  end
end

#invoke(meth, *args) ⇒ Object

Main entry point method that should actually invoke the method. You can override this to provide some class-wide processing. The default implementation simply invokes the named method



103
104
105
# File 'lib/thor/lib/thor.rb', line 103

def invoke(meth, *args)
  self.send(meth, *args)
end