Class: Climate::Command

Inherits:
Object
  • Object
show all
Extended by:
ParsingMethods
Defined in:
lib/climate/command.rb

Overview

A Command is a unit of work, intended to be invoked from the command line. It should be extended to either do something itself by implementing run, or just be there as a conduit for subcommands to do their work.

See ParsingMethods for details on how to specify options and arguments

Direct Known Subclasses

Help::Man::Script

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ParsingMethods

arg, cli_arguments, cli_options, has_arguments?, has_options?, opt, parse, parse_arguments, stop_on, trollop_parser

Constructor Details

#initialize(argv, options = {}) ⇒ Command

Create an instance of this command to be run. You’ll probably want to use run

Options Hash (options):

  • :parent (Command)

    The parent command, made available as #parent

  • :stdout (IO)

    stream to use as stdout, defaulting to ‘$stdout`

  • :stderr (IO)

    stream to use as stderr, defaulting to ‘$stderr`

  • :stdin (IO)

    stream to use as stdin, defaulting to ‘$stdin`



135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/climate/command.rb', line 135

def initialize(argv, options={})
  @argv = argv.clone
  @parent = options[:parent]

  @stdout = options[:stdout] || $stdout
  @stderr = options[:stderr] || $stderr
  @stdin =  options[:stdin]  || $stdin

  if ! self.class.parsing_disabled
    @arguments, @options, @leftovers = self.class.parse(argv)
  end
end

Class Attribute Details

.parentObject

Set the parent of this command



84
85
86
# File 'lib/climate/command.rb', line 84

def parent
  @parent
end

.parsing_disabledObject

Returns true if parsing is disabled



81
82
83
# File 'lib/climate/command.rb', line 81

def parsing_disabled
  @parsing_disabled
end

Instance Attribute Details

#argumentsHash

Arguments that were given on the command line



159
160
161
# File 'lib/climate/command.rb', line 159

def arguments
  @arguments
end

#argvArray

The original list of unparsed argv style arguments that were given to the command



151
152
153
# File 'lib/climate/command.rb', line 151

def argv
  @argv
end

#leftoversArray

Unparsed arguments, usually for subcommands



163
164
165
# File 'lib/climate/command.rb', line 163

def leftovers
  @leftovers
end

#optionsHash

Options that were parsed from the command line



155
156
157
# File 'lib/climate/command.rb', line 155

def options
  @options
end

#parentCommand

The parent command, or nil if this is not a subcommand



167
168
169
# File 'lib/climate/command.rb', line 167

def parent
  @parent
end

#stderrIO

a possibly redirected stream



171
172
173
# File 'lib/climate/command.rb', line 171

def stderr
  @stderr
end

#stdinIO

a possibly redirected stream



171
172
173
# File 'lib/climate/command.rb', line 171

def stdin
  @stdin
end

#stdoutIO

a possibly redirected stream



171
172
173
# File 'lib/climate/command.rb', line 171

def stdout
  @stdout
end

Class Method Details

.add_subcommand(subcommand) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/climate/command.rb', line 86

def add_subcommand(subcommand)
  if cli_arguments.empty?
    subcommands << subcommand
    subcommand.parent = self
    stop_on(subcommands.map(&:name))
  else
    raise DefinitionError, 'can not mix subcommands with arguments'
  end
end

.ancestors(exclude_self = false) ⇒ Object



39
40
41
42
# File 'lib/climate/command.rb', line 39

def ancestors(exclude_self=false)
  our_list = exclude_self ? [] : [self]
  parent.nil?? our_list : parent.ancestors + our_list
end

.arg(*args) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/climate/command.rb', line 96

def arg(*args)
  if subcommands.empty?
    super(*args)
  else
    raise DefinitionError, 'can not mix subcommands with arguments'
  end
end

.class_nameObject

because we’ve extended Class.name, we expose the original method under another name FIXME: surely there is a saner way of doing this?



53
54
55
# File 'lib/climate/command.rb', line 53

def class_name
  Class.method(:name).unbind.bind(self).call
end

.description(string = nil) ⇒ Object

Set the description for this command



66
67
68
69
70
71
72
# File 'lib/climate/command.rb', line 66

def description(string=nil)
  if string
    @description = string
  else
    @description
  end
end

.disable_parsingObject

Call this during class definition time if you don’t want any of the usual command line parsing to happen



76
77
78
# File 'lib/climate/command.rb', line 76

def disable_parsing
  @parsing_disabled = true
end

.has_subcommands?Boolean



104
# File 'lib/climate/command.rb', line 104

def has_subcommands? ; not subcommands.empty?   ; end

.name(name = nil) ⇒ Object

Supply a name for this command, or return the existing name



45
46
47
48
# File 'lib/climate/command.rb', line 45

def name(name=nil)
  @name = name if name
  @name
end

.run(argv, options = {}) ⇒ Object

Create an instance of this command class and run it against the given arguments



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/climate/command.rb', line 19

def run(argv, options={})
  begin
    instance = new(argv, options)
  rescue Trollop::HelpNeeded
    raise HelpNeeded.new(self)
  end

  if subcommands.empty?
    begin
      instance.run
    rescue Climate::CommandError => e
      # make it easier on users
      e.command_class = self if e.command_class.nil?
      raise
    end
  else
    find_and_run_subcommand(instance, options)
  end
end

.subcommand_of(parent_class) ⇒ Object

Register this class as being a subcommand of another Climate::Command class

Raises:



59
60
61
62
# File 'lib/climate/command.rb', line 59

def subcommand_of(parent_class)
  raise DefinitionError, 'can not set subcommand before name' unless @name
  parent_class.add_subcommand(self)
end

.subcommandsObject



105
# File 'lib/climate/command.rb', line 105

def subcommands ; @subcommands ||= [] ; end

Instance Method Details

#ancestor(ancestor_class, include_self = true) ⇒ Object



173
174
175
176
177
178
179
180
181
182
# File 'lib/climate/command.rb', line 173

def ancestor(ancestor_class, include_self=true)
  if include_self && self.class == ancestor_class
    self
  elsif parent.nil?
    raise "no ancestor exists: #{ancestor_class}"
    nil
  else
    parent.ancestor(ancestor_class)
  end
end

#runObject

Run the command, must be implemented by all commands that are not parent commands (leaf commands)

Raises:

  • (NotImplementedError)


186
187
188
# File 'lib/climate/command.rb', line 186

def run
  raise NotImplementedError, "Leaf commands must implement a run method"
end