Class: CommandLion::App

Inherits:
Base
  • Object
show all
Defined in:
lib/command_lion/app.rb

Overview

The App class provides what can be considered the “main” function for the a Command Lion application.

The App class is primarily used in one of two ways:

Building Block

To build an application using the DSL, but not run it right away, the build method block is available.

app = CommandLion::App.build do
  # ...
end

app.run!

Run Block

To build, parse, and run everything in one concise block, the run method block is available.

CommandLion::App.run do
  # ...
end

DSL Keywords:

name

The name of your application. This is how your application would be referenced in conversation. It’s also going to be used as the defualt banner for the application which will appear at the top of the help menu.

Example

app = CommandLion::App.build do
  name "Example"
end

app.name?
# => true

app.name = "Changed Name"
# => "Changed Name"

app.name
# => Changed Name
usage

Your usage string can be used to help show the basic information for how to use your application. You can make this as simple or as complex as you like. One will be generated for you by default when your application runs, but won’t be pre-built for you inside the build block for now.

Example

app = CommandLion::App.build do
  usage "example [commands] [options...]"
end

app.usage?
# => true

app.usage = <<USAGE
    /|
~~~/ |~
tsharky [command] [switches] [--] [arguments]
USAGE
# => "    /|\n" + "~~~/ |~\n" + "tsharky [command] [switches] [--] [arguments]\n"

app.usage
# => "    /|\n" + "~~~/ |~\n" + "tsharky [command] [switches] [--] [arguments]\n"

puts app.usage
#     /|
# ~~~/ |~
# tsharky [command] [switches] [--] [arguments]
description

To provide further context for your application’s existence, it’s fairly nice to have a description. Like, the usage statement, this can be as complex or as simple as you would like. It isn’t required either.

Example

app = CommandLion::App.build do
  description "Example"
end

app.description?
# => true

app.description = "Changed"
# => "Changed"

app.description
# => Changed

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

build, key_value, simple_attr, simple_attrs

Class Method Details

.default_help(app) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/command_lion/app.rb', line 86

def self.default_help(app)
  flagz = app.commands.map do |_, cmd|
    if cmd.flags?
      if cmd.flags.long?
        cmd.flags.short + cmd.flags.long
      else  
        cmd.flags.short
      end  
    elsif cmd.index?
      cmd.index.to_s if cmd.index?
    else
      raise "No flags or index was given!"
    end
  end 
  max_flag = flagz.map(&:length).max + 2
  max_desc = app.commands.values.map(&:description).select{|d| d unless d.nil? }.map(&:length).max
  puts app.name
  puts
  if app.version?
    puts "VERSION"
    puts app.version
    puts
  end
  if app.description?
    puts 
    puts "DESCRIPTION"
    puts app.description
    puts
  end
  if app.usage?
    puts
    puts "USAGE"
    puts usage
    puts
  end
  puts "COMMANDS"
  app.commands.values.select { |cmd| cmd unless cmd.is_a? CommandLion::Option }.each do |command|
    if command.flags?
      short = command.flags.long? ? command.flags.short + ", " : command.flags.short
      short_long = "#{short}#{command.flags.long}".ljust(max_flag)
    else
      short_long = "#{command.index.to_s}".ljust(max_flag)
    end
    puts "#{short_long}  #{command.description}"
    if command.options?
      command.options.each do |_, option|
        if option.flags?
          short = option.flags.long? ? option.flags.short + ", " : option.flags.short
          short_long = "  " + "#{short}#{option.flags.long}".ljust(max_flag - 2)
        else
          short_long = "  " + "#{option.index.to_s}".ljust(max_flag - 2)
        end
        puts "#{short_long}  #{option.description}"
      end
    end
    puts
  end
end

.run(&block) ⇒ Object

This run method is a pretty important method when using command lion typically.

Under the hood, an application object is initialized. The block of code passed to this method is then used as the code that is ran in the context of a application object. So all of those methods will be available.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/command_lion/app.rb', line 151

def self.run(&block)
  # Initialize an instance of an App object.
  app = new
  # Evaluate the block of code within the context of that App object.
  app.instance_eval(&block)
  # Parse the application logic out.
  app.parse
  # Sometimes a command-line application is run without being given any arguments.
  if ARGV.empty?
    # Default to a help menu.
    if cmd = app.commands[:help]
      cmd.before.call if cmd.before?
      cmd.action.call if cmd.action?
      cmd.after.call  if cmd.after?
      # maybe exit?
    else
      # Use the default help menu for the application unless that's been
      # explictly removed by the author for whatever reason.
      default_help(app) unless app.default_help_menu_removed?
    end
  else
    threadz = false
    app.commands.each do |_, cmd|
      next unless cmd.given?
      if cmd.threaded?
        threadz = [] unless threadz
        threadz << Thread.new do 
          cmd.before.call if cmd.before?
          cmd.action.call if cmd.action?
          cmd.after.call  if cmd.after?
        end
      else
        cmd.before.call if cmd.before?
        cmd.action.call if cmd.action?
        cmd.after.call  if cmd.after?
      end
    end
    threadz.map(&:join) if threadz
  end
end

Instance Method Details

#command(index, &block) ⇒ Object

An application usually has multiple commands.

Example

app = CommandLion::App.build
  # meta information

  command :example1 do
    # more code
  end

  command :example2 do
    # more code
  end
end

app.commands.map(&:name)
# => [:example1, :example2]


247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/command_lion/app.rb', line 247

def command(index, &block)
  if index.is_a? Command
    cmd = index
  else
    cmd = Command.new
    cmd.index= index
    cmd.instance_eval(&block)
  end
  @commands = {} unless @commands
  @flags = [] unless @flags
  if cmd.flags?
    @flags << cmd.flags.short if cmd.flags.short?
    @flags << cmd.flags.long  if cmd.flags.long?
  elsif cmd.index # just use index
    @flags << cmd.index.to_s
  else
    raise "No index or flags were given to use this command."
  end
  if cmd.options?
    cmd.options.each do |_, option|
      if option.flags?
        @flags << option.flags.short if option.flags.short?
        @flags << option.flags.long  if option.flags.long?
      else # just use index
        @flags << option.index.to_s
      end
      @commands[option.index] = option
      #@commands << option
    end
  end
  @commands[cmd.index] = cmd
  cmd
end

#commandsObject

Direct access to the various commands an application has. Helpful for debugging.



299
300
301
# File 'lib/command_lion/app.rb', line 299

def commands
  @commands
end

#default_help_menu_removed?Boolean

Check if the default help menu for the application has been explicitly removed.

Returns:

  • (Boolean)


204
205
206
# File 'lib/command_lion/app.rb', line 204

def default_help_menu_removed?
  @remove_default_help_menu || false
end

#flagsObject

Direct access to the various flags an application has. Helpfulp for debugging.



294
295
296
# File 'lib/command_lion/app.rb', line 294

def flags
  @flags
end

#help(&block) ⇒ Object



281
282
283
# File 'lib/command_lion/app.rb', line 281

def help(&block)
  command :help, &block
end

#help?Boolean

Check if there has been an indexed help command.

Returns:

  • (Boolean)


193
194
195
196
# File 'lib/command_lion/app.rb', line 193

def help?
  return true if @commands[:help]
  false
end

#parseObject

Parse arguments off of ARGV.



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/command_lion/app.rb', line 306

def parse
  @commands.each do |_, cmd|
    if cmd.flags?
      # or for the || seems to not do what I want it to do...
      next unless argv_index = ARGV.index(cmd.flags.short) || ARGV.index(cmd.flags.long)
    else
      next unless argv_index = ARGV.index(cmd.index.to_s)
    end
    cmd.given = true unless argv_index.nil?
    if cmd.type.nil?
      yield cmd if block_given?
    else
      if parsed = parse_cmd(cmd, flags)
        cmd.arguments = parsed || cmd.default
        yield cmd if block_given?
      elsif cmd.default
        cmd.arguments = cmd.default
        yield cmd if block_given?
      end
    end
  end
end

#parse_cmd(cmd, flags) ⇒ Object

Parse a given command with its



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/command_lion/app.rb', line 331

def parse_cmd(cmd, flags)
  if cmd.flags?
    args = Raw.arguments_to(cmd.flags.short, flags)
    if args.nil? || args.empty?
      args = Raw.arguments_to(cmd.flags.long, flags)
    end
  else
    args = Raw.arguments_to(cmd.index.to_s, flags)
  end
  return nil if args.nil?
  case cmd.type
  when :stdin
    args = STDIN.gets.strip
  when :stdin_stream
    args = STDIN
  when :stdin_string
    args = STDIN.gets.strip
  when :stdin_strings
    args = []
    while arg = STDIN.gets
      next if arg.nil?
      arg = arg.strip
      args << arg
    end
    args
  when :stdin_integer
    args = STDIN.gets.strip.to_i
  when :stdin_integers
    args = []
    while arg = STDIN.gets
      next if arg.nil?
      arg = arg.strip
      parse = arg.to_i
      if parse.to_s == arg
        args << parse
      end
    end
    args
  when :stdin_bool
    args = STDIN.gets.strip.downcase == "true"
  when :single, :string
    args = args.first
  when :strings, :multi
    if cmd.delimiter?
      if args.count > 1
        args = args.first.split(cmd.delimiter)
        #args = args.first.join.split(cmd.delimiter).flatten.select { |arg| arg unless arg.empty? }
        #args = args.select { |arg| arg if arg.include?(cmd.delimiter) }
        #args = args.map { |arg| arg.split(cmd.delimiter) }.flatten
      else
        args = args.map { |arg| arg.split(cmd.delimiter) }.flatten
      end
    end
    args
  when :integer
    args = args.first.to_i
  when :integers
    if cmd.delimiter?
      if args.count > 1
        args = args.join
        args = args.select { |arg| arg if arg.include?(cmd.delimiter) }
        args = args.map { |arg| arg.split(cmd.delimiter) }.flatten
      else
        args = args.map { |arg| arg.split(cmd.delimiter) }.flatten
      end
    end
    args = args.map(&:to_i)
  when :bool, :bools
    if cmd.delimiter?
      if args.count > 1
        args = args.join
        args = args.select { |arg| arg if arg.include?(cmd.delimiter) }
        args = args.map { |arg| arg.split(cmd.delimiter) }.flatten
      else
        args = args.map { |arg| arg.split(cmd.delimiter) }.flatten
      end
    end
    args = args.map { |arg| arg == "true" }
  end
rescue => e# this is dangerous
  puts e
  nil
end

#plugin(command) ⇒ Object

Plugin a command that’s probably been built outside of the application’s run or build block. This is helpful for sharing or reusing commands in applications.

Parameters:



289
290
291
# File 'lib/command_lion/app.rb', line 289

def plugin(command)
  command(command)
end

#rainbowsObject

A tiny bit of rainbow magic is included. You can simple include this option within your application and, if you have the ‘lolize` gem installed, then rainbows will automagically be hooked to STDOUT to make your application much prettier.

It’d be funny if this was turned on by default and you had to opt-out of the rainbows. Good thing I didn’t do that, right?



215
216
217
218
219
# File 'lib/command_lion/app.rb', line 215

def rainbows
  require 'lolize/auto'
rescue
  raise "The 'lolize' gem is not installed. Install it for rainbow magic!"
end

#remove_default_help_menuObject

Explicitly remove the default help menu from the application.



199
200
201
# File 'lib/command_lion/app.rb', line 199

def remove_default_help_menu
  @remove_default_help_menu = true
end

#run!Object



416
417
418
419
420
# File 'lib/command_lion/app.rb', line 416

def run!
  parse do |cmd|
    cmd.action.call
  end 
end