Class: Consoler::Application

Inherits:
Object
  • Object
show all
Defined in:
lib/consoler/application.rb

Overview

Consoler application

Examples:

A simple application

# create a application
app = Consoler::Application.new description: 'A simple app'

# define a command
app.build 'target [--clean]' do |target, clean|
  # clean contains a boolean
  clean_up if clean

  # target contains a string
  build_project target
end
app.run(['build', 'production', '--clean'])

# this does not match, nothing is executed and the usage message is printed
app.run(['deploy', 'production'])

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Application

Create a consoler application

Parameters:

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

    Options for the application

Options Hash (options):

  • :description (String)

    The description for the application (optional)



32
33
34
35
# File 'lib/consoler/application.rb', line 32

def initialize(options={})
  @description = options[:description]
  @commands = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(command_name, input = nil) {|...| ... } ⇒ nil

Register a command for this app

Parameters:

  • command_name (Symbol)

    Name of the command

  • input (String, Consoler::Application) (defaults to: nil)

    Options definition or a complete subapp

Yields:

  • (...)

    Executed when the action is matched with parameters based on your options

Returns:

  • (nil)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/consoler/application.rb', line 43

def method_missing(command_name, input = nil, &block)
  action = nil
  options_def = ''

  unless block.nil? then
    action = block
    options_def = input

    if not options_def.nil? and not options_def.instance_of? String then
      raise 'Invalid options'
    end
  end

  if input.instance_of? Consoler::Application then
    action = input
    options_def = ''
  end

  if action.nil? then
    raise 'Invalid subapp/block'
  end

  command = command_name.to_s

  _add_command(command, options_def, action)

  return nil
end

Instance Method Details

#_add_command(command, options_def, action) ⇒ Consoler::Application (private)

Add a command

Parameters:

  • command (String)

    Command name

  • options_def (String)

    Definition of options

  • action (Proc, Consoler::Application)

    Action or subapp

Returns:



167
168
169
170
171
172
173
174
175
# File 'lib/consoler/application.rb', line 167

def _add_command(command, options_def, action)
  @commands.push(Consoler::Command.new(
    command: command,
    options: Consoler::Options.new(options_def),
    action: action,
  ))

  self
end

#_commands_usage(prefix = '') ⇒ Consoler::Application (protected)

Print the usage message for this command

Parameters:

  • prefix (String) (defaults to: '')

    A prefix for the command from a parent app

Returns:



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/consoler/application.rb', line 136

def _commands_usage(prefix='')
  @commands.each do |command|
    # print the usage message of a subapp with a prefix from the current command
    if command.action.instance_of? Consoler::Application then
      command.action._commands_usage "#{prefix} #{command.command}"
    else
      print "  #{prefix} #{command.command}"

      if command.options.size then
        print " #{command.options.to_definition}"
      end

      unless command.options.description.nil? then
        print "  -- #{command.options.description}"
      end

      print "\n"
    end
  end

  self
end

#_dispatch(action, match) ⇒ Object (private)

Execute an action with argument match info

Parameters:

  • action (Proc)

    Action

  • match (Hash)

    Argument match information



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/consoler/application.rb', line 181

def _dispatch(action, match)
  # match parameter names to indices of match information
  arguments = action.parameters.map do |parameter|
    parameter_name = parameter[1].to_s

    if match.has_key? parameter_name then
      match[parameter_name]
    else
      # check for the normalized name of every match to see
      # if it fits the parameter name
      match.each do |name, value|
        normalized_name = _normalize name

        if parameter_name == normalized_name then
          return value
        end
      end
    end
  end

  action.call(*arguments)
end

#_normalize(name) ⇒ String (private)

Normalize a name to be used as a variable name

Parameters:

  • name (String)

    Name

Returns:

  • (String)

    Normalized name



208
209
210
211
212
213
214
215
216
# File 'lib/consoler/application.rb', line 208

def _normalize(name)
  # maybe do something more, maybe not.. ruby does allow for
  # some weird stuff to be used as a variable name. the user
  # should use some common sense. and, other things might
  # also be an syntax error, like starting with a number.
  # this normalization is more of a comvenience than anything
  # else
  name.gsub('-', '_')
end

#_run(args) ⇒ (mixed, Boolean) (protected)

Run the app

Parameters:

  • args (Array<String>)

    Arguments

Returns:

  • ((mixed, Boolean))

    Result of the command, and, did the args match a command at all



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/consoler/application.rb', line 105

def _run(args)
  arg = args.shift
  arguments = Consoler::Arguments.new args

  @commands.each do |command|
    if command.command == arg then
      # the matched command contains a subapp, run subapp with the same
      # arguments (excluding the arg that matched this command)
      if command.action.instance_of? Consoler::Application then
        result, matched = command.action._run(args)

        if matched then
          return result, true
        end
      else
        match = arguments.match command.options

        next if match.nil?

        return _dispatch(command.action, match), true
      end
    end
  end

  return nil, false
end

#run(args = ARGV, disable_usage_message = false) ⇒ mixed

Run the application with a list of arguments

Parameters:

  • args (Array) (defaults to: ARGV)

    Arguments

  • disable_usage_message (Boolean) (defaults to: false)

    Disable the usage message when nothing it matched

Returns:

  • (mixed)

    Result of your matched command, nil otherwise



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/consoler/application.rb', line 77

def run(args = ARGV, disable_usage_message = false)
  # TODO signal handling of some kind?

  result, matched = _run(args.dup)

  if not matched and not disable_usage_message
    usage
  end

  return result
end

#usageObject

Show the usage message

Contains all commands and options, including subapps



92
93
94
95
96
97
# File 'lib/consoler/application.rb', line 92

def usage
  puts "#{@description}\n\n" unless @description.nil?
  puts 'Usage:'

  _commands_usage $0
end