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

Parameters:

  • arguments (Array<String>)

    ARGV style arguments to be parsed

  • options (Hash) (defaults to: {})

    a customizable set of options

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

Returns:

  • (Hash)


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

Returns:

  • (Array)


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

def argv
  @argv
end

#leftoversArray

Unparsed arguments, usually for subcommands

Returns:

  • (Array)


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

def leftovers
  @leftovers
end

#optionsHash

Options that were parsed from the command line

Returns:

  • (Hash)


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

Returns:



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

def parent
  @parent
end

#stderrIO

a possibly redirected stream

Returns:

  • (IO)


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

def stderr
  @stderr
end

#stdinIO

a possibly redirected stream

Returns:

  • (IO)


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

def stdin
  @stdin
end

#stdoutIO

a possibly redirected stream

Returns:

  • (IO)


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

Parameters:

  • string (String) (defaults to: nil)

    Description/Banner/Help text



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

Returns:

  • (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

Parameters:

  • argv (Array<String>)

    A list of arguments, ARGV style

  • options (Hash) (defaults to: {})


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

Parameters:

  • parent_class (Command)

    The parent we hang off of

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