Class: ShellOpts::Command

Inherits:
BasicObject
Defined in:
lib/shellopts/program.rb,
lib/shellopts/dump.rb

Overview

Command represents a program or a subcommand. It is derived from BasicObject to have only a minimum of inherited member methods.

The names of the inherited methods can’t be used as options or command namess. They are: instance_eval, instance_exec method_missing, singleton_method_added, singleton_method_removed, and singleton_method_undefined.

Additional methods defined in Command use the ‘__<identifier>__’ naming convention that doesn’t collide with option or subcommand names but they’re rarely used in application code

Command also defines #subcommand and #subcommand! but they can be overshadowed by an option or command declaration. Their values can still be accessed using the dashed name, though

Option and Command objects can be accessed using #[]. #key? is also defined

The following methods are created dynamically for each declared option with an attribute name

<identifier>(default = nil)
<identifier>=(value)
<identifier>?()

The default value is used if the option or its value is missing

Options without an an attribute can still be accessed using #[] or trough #option_values, #__option_hash, or #options_list

Each subcommand has a single method:

# Return the subcommand object or nil if not present
def <identifier>!() subcommand == :<identifier> ? @__subcommand__ : nil end

The general #subcommand method can be used to find out which subcommand is used

Direct Known Subclasses

Program

Constant Summary collapse

RESERVED_OPTION_NAMES =

These names can’t be used as option or command names

%w(
    is_a to_h instance_eval instance_exec method_missing singleton_method_added
    singleton_method_removed singleton_method_undefined
)
OVERRIDEABLE_METHOD_NAMES =

These methods can be overridden by an option or a command (this constant is not used - it is just for informational purposes)

%w(
    subcommand subcommand! subcommands subcommands! supercommand!
)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#__grammar__Object (readonly)

Grammar object



157
158
159
# File 'lib/shellopts/program.rb', line 157

def __grammar__
  @__grammar__
end

#__option_hash__Object (readonly)

Map from identifier to option object or to a list of option objects if the option is repeatable



173
174
175
# File 'lib/shellopts/program.rb', line 173

def __option_hash__
  @__option_hash__
end

#__option_list__Object (readonly)

List of Option objects for the subcommand in the same order as given by the user but note that options are reordered to come after their associated subcommand if float is true. Repeated options are not collapsed



169
170
171
# File 'lib/shellopts/program.rb', line 169

def __option_list__
  @__option_list__
end

#__option_values__Object (readonly)

Hash from identifier to value. Can be Integer, Float, or String depending on the option’s type. Repeated options options without arguments have the number of occurences as value, repeated option with arguments have the array of values as value



163
164
165
# File 'lib/shellopts/program.rb', line 163

def __option_values__
  @__option_values__
end

#__supercommand__Object

The parent command or nil. Initialized by #add_command



176
177
178
# File 'lib/shellopts/program.rb', line 176

def __supercommand__
  @__supercommand__
end

Class Method Details

.dump(expr, argv = []) ⇒ Object

Class-level accessor methods



149
# File 'lib/shellopts/dump.rb', line 149

def self.dump(expr, argv = []) expr.__dump__(argv) end

.new(grammar) ⇒ Object

Redefine ::new to call #__initialize__



59
60
61
62
63
# File 'lib/shellopts/program.rb', line 59

def self.new(grammar)
  object = super()
  object.__send__(:__initialize__, grammar)
  object
end

Instance Method Details

#[](uid) ⇒ Object

Returns the command or option object identified by the UID if present and otherwise nil. Returns a possibly empty array of option objects if the option is repeatable. Raise an ArgumentError if the key doesn’t exists

The key is the symbolic UID of the object. Eg. :command.option or :command.subcommand!



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/shellopts/program.rb', line 72

def [](uid)
  __grammar__.key?(uid) or ::Kernel.raise ::ArgumentError, "'#{uid}' is not a valid UID"
  idents = uid.to_s.gsub(/\./, "!.").split(/\./).map(&:to_sym)
  idents.inject(self) { |cmd, ident|
    case ident.to_s
      when /!$/
        return nil if cmd.__subcommand__ != ident
        cmd = cmd.__subcommand__!
      else
        opt = cmd.__option_hash__[ident]
        opt.nil? && cmd.__grammar__[ident].repeatable? ? [] : opt
    end
  }
end

#__dump__(argv = []) ⇒ Object



139
140
141
142
143
144
145
146
# File 'lib/shellopts/dump.rb', line 139

def __dump__(argv = [])
  ::Kernel.puts __name__
  ::Kernel.indent {
    __options__.each { |ident, value| ::Kernel.puts "#{ident}: #{value.inspect}" }
    __subcommand__!&.__dump__
    ::Kernel.puts argv.map(&:inspect).join(" ") if !argv.empty?
  }
end

#__ident__Object

Identfier including the exclamation mark (Symbol)



151
# File 'lib/shellopts/program.rb', line 151

def __ident__() @__grammar__.ident end

#__name__Object

Name of command/program without the exclamation mark (String)



154
# File 'lib/shellopts/program.rb', line 154

def __name__() @__grammar__.name end

#__subcommand__Object

The subcommand identifier (a Symbol incl. the exclamation mark) or nil if not present. Use #subcommand!, or the dynamically generated ‘#<identifier>!’ method to get the actual subcommand object



181
# File 'lib/shellopts/program.rb', line 181

def __subcommand__() @__subcommand__&.__ident__ end

#__subcommand__!Object

The actual subcommand object or nil if not present



184
# File 'lib/shellopts/program.rb', line 184

def __subcommand__!() @__subcommand__ end

#__subcommands__Object

Implementation of the #subcommands method



187
188
189
# File 'lib/shellopts/program.rb', line 187

def __subcommands__()
  __subcommands__!.last&.__uid__&.to_sym
end

#__subcommands__!Object

Implementation of the #subcommands! method



192
193
194
# File 'lib/shellopts/program.rb', line 192

def __subcommands__!()
  ::Algorithm.follow(self.__subcommand__!, :__subcommand__!).to_a
end

#__uid__Object

UID of command/program (String)



148
# File 'lib/shellopts/program.rb', line 148

def __uid__() @__grammar__.uid end

#subcommandObject

Subcommand identifier or nil if not present. #subcommand is often used in case statement to branch out to code that handles the given subcommand:

prog, args = ShellOpts.parse("do_this! do_that!", ARGV)
case prog.subcommand
  when :do_this!; prog.do_this.operation # or prog[:subcommand!] or prog.subcommand!
  when :do_that!; prog.do_that.operation
end

Note: Can be overridden by option, in that case use #__subcommand__ or ShellOpts.subcommand(object) instead



120
# File 'lib/shellopts/program.rb', line 120

def subcommand() __subcommand__ end

#subcommand!Object

The subcommand object or nil if not present. Per-subcommand methods (#<identifier>!) are often used instead of #subcommand! to get the subcommand

Note: Can be overridden by a subcommand declaration (but not an option), in that case use #__subcommand__! or ShellOpts.subcommand!(object) instead



130
# File 'lib/shellopts/program.rb', line 130

def subcommand!() __subcommand__! end

#subcommandsObject

Returns the concatenated identifier of subcommands (eg. :cmd.subcmd!)



133
# File 'lib/shellopts/program.rb', line 133

def subcommands() __subcommands__ end

#subcommands!Object

Returns the subcommands in an array. This doesn’t include the top-level program object



137
# File 'lib/shellopts/program.rb', line 137

def subcommands!() __subcommands__! end

#supercommand!Object

The parent command or nil. Initialized by #add_command

Note: Can be overridden by a subcommand declaration (but not an option), in that case use #__supercommand__! or ShellOpts.supercommand!(object) instead



145
# File 'lib/shellopts/program.rb', line 145

def supercommand!() __supercommand__ end

#to_h(*keys) ⇒ Object

Returns a hash from option ident to value

The value depends on the option type: If it is not repeatable, the value is the argument or nil if not present (or allowed). If the option is repeatable and has an argument, the value is an array of the arguments, if it doesn’t have an argument, the value is the number of occurrences



94
95
96
97
# File 'lib/shellopts/program.rb', line 94

def to_h(*keys)
  keys = ::Kernel::Array(keys).flatten
  __option_values__.select { |key,_| keys.empty? || keys.include?(key) }
end

#to_h?(*keys) ⇒ Boolean

Like #to_h but present options without arguments have a true value

Returns:

  • (Boolean)


101
102
103
104
105
# File 'lib/shellopts/program.rb', line 101

def to_h?(*keys)
  keys = ::Kernel::Array(keys).flatten
  keys = keys.empty? ? __option_values__.keys : keys
  keys.filter_map { |key| __option_values__.key?(key) && [key, self.__send__(key)] }.to_h
end