Class: CommandLine::Application

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

Defined Under Namespace

Classes: ApplicationError, ArgumentError, InvalidArgumentArityError, MissingMainError, OptionError, UnknownOptionError

Constant Summary collapse

DEFAULT_CONSOLE_WIDTH =

TODO: Consolidate these with OptionParser - put in command line

70
MIN_CONSOLE_WIDTH =
10
DEFAULT_BODY_INDENT =
4

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeApplication

Returns a new instance of Application.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/commandline/application.rb', line 41

def initialize
  @synopsis    = ""
  @arg_arity   = [0,0]
  @options     = []
  @arg_names   = []
  @args        = []
  @replay      = false
  @replay_file = ".replay"

  __initialize_text_formatting

  # Call the child usurped initialize
  initAvailable = self.class.private_instance_methods(false).include?(:__child_initialize) || self.class.private_instance_methods(false).include?("__child_initialize")
  __child_initialize if initAvailable

  @option_parser ||= CommandLine::OptionParser.new(@options)
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



30
31
32
# File 'lib/commandline/application.rb', line 30

def args
  @args
end

#argvObject (readonly)

Returns the value of attribute argv.



30
31
32
# File 'lib/commandline/application.rb', line 30

def argv
  @argv
end

Class Method Details

.__set_auto_runObject



274
275
276
# File 'lib/commandline/application.rb', line 274

def self.__set_auto_run
  at_exit { @@child_class.run }
end

.inherited(child_class) ⇒ Object



265
266
267
268
269
270
271
272
# File 'lib/commandline/application.rb', line 265

def self.inherited(child_class)
  appname = caller[0]
  @@appname = appname[0..(appname.index(':')-1)]
  @@child_class = child_class
  if @@appname == $0
    __set_auto_run
  end
end

.run(argv = ARGV) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/commandline/application.rb', line 238

def self.run(argv=ARGV)
  # Usurp an existing initialize so ours can be called first.
  # We rename it __child_initialize and call it from initialize.
  
  # Used to work with 1.9.x and 1.8.x 
  initAvailable = self.private_instance_methods(false).include?(:initialize) || self.private_instance_methods(false).include?("initialize")
  
  if initAvailable
    $VERBOSE, verbose = nil, $VERBOSE
    self.class_eval {
      alias :__child_initialize :initialize
      remove_method :initialize
    }
    $VERBOSE = verbose
  end
  obj = self.new
  obj.__parse_command_line(argv)
  obj.main

  #alias :user_init :initialize
  #@@child_class.new.main if ($0 == @@appname)
  obj
  rescue => err
    puts "ERROR: #{err}"
    exit(-1)
end

Instance Method Details

#__debugObject



410
411
412
413
414
415
416
417
418
# File 'lib/commandline/application.rb', line 410

def __debug
   {
     :names           => %w(--debug -d),
     :arity           => [0,0],
     :opt_description => "Sets debug to true.",
     :arg_description => "",
     :opt_found       => lambda { $DEBUG = true }
   }
end

#__helpObject



369
370
371
372
373
374
375
376
377
378
# File 'lib/commandline/application.rb', line 369

def __help
   {
     :names           => %w(--help -h),
     :arity           => [0,0],
     :opt_description => "Displays help page.",
     :arg_description => "",
     :opt_found       => lambda { puts man; exit },
     :opt_not_found   => false
   }
end

#__initialize_text_formattingObject



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/commandline/application.rb', line 339

def __initialize_text_formatting
  #
  # Formatting defaults
  #
  console_width = ENV["COLUMNS"]
  @columns = 
    if console_width.nil?
      DEFAULT_CONSOLE_WIDTH
    elsif console_width < MIN_CONSOLE_WIDTH
      console_width
    else
      console_width - DEFAULT_BODY_INDENT
    end
  @body_indent   = DEFAULT_BODY_INDENT
  @tag_paragraph = false
  @order         = :index  # | :alpha
end

#__parse_command_line(argv) ⇒ Object



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/commandline/application.rb', line 302

def __parse_command_line(argv)
  @argv = argv
  if @replay && File.exist?(@replay_file) && !@argv.grep("-r").empty?
    __restore_argv
  elsif @argv.empty? && @arg_arity[0] != 0
    puts usage
    exit(0)
  end

  begin
    @option_data = @option_parser.parse(@argv)
    @args = @option_data.args
  rescue => err
    puts err
    puts
    puts usage
    exit(-1)
  end

  __validate_args(@option_data.args)
  @arg_names.each_with_index { |name, idx|
    instance_variable_set("@#{name}", @option_data.args[idx])
  }
  
  __save_argv
end

#__restore_argvObject



297
298
299
300
# File 'lib/commandline/application.rb', line 297

def __restore_argv
  @argv = File.read(@replay_file).gsub(/\n/, "").split
  raise "Bad @argv" unless @argv.kind_of?(Array)
end

#__save_argvObject



284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/commandline/application.rb', line 284

def __save_argv
  return unless @replay

  line = 0
  File.open(@replay_file, "w") { |f|
    @argv.each { |arg|
      f.puts "\n" if arg[0] == ?- && line != 0
      f.print " #{arg}"
      line += 1
    }
  }
end

#__validate_arg_arity(arity) ⇒ Object



329
330
331
332
333
334
335
336
337
# File 'lib/commandline/application.rb', line 329

def __validate_arg_arity(arity)
  min, max = *arity
  raise(InvalidArgumentArityError, "Minimum argument arity '#{min}' must be "+
    "greater than or equal to 0.") unless min >= 0
  raise(InvalidArgumentArityError, "Maximum argument arity '#{max}' must be "+
    "greater than or equal to -1.") if max < -1
  raise(InvalidArgumentArityError, "Maximum argument arity '#{max}' must be "+
    "greater than minimum arg_arity '#{min}'.") if max < min && max != -1
end

#__validate_args(od_args) ⇒ Object

Raises:



357
358
359
360
361
362
363
364
365
366
367
# File 'lib/commandline/application.rb', line 357

def __validate_args(od_args)
  size = od_args.size
  min, max = @arg_arity
  max = 1.0/0.0 if -1 == max
  raise(ArgumentError,
    "Missing expected arguments. Found #{size} but expected #{min}. "+
    "#{od_args.inspect}\n"+
    "#{usage}") if size < min
  raise(ArgumentError, "Too many arguments. Found #{size} but "+
    "expected #{max}.\n#{usage}") if size > max
end

#__verboseObject



380
381
382
383
384
385
386
387
388
389
390
# File 'lib/commandline/application.rb', line 380

def __verbose
   {
     :names           => %w(--verbose -v),
     :arity           => [0,0],
     :opt_description => "Sets verbosity level. Subsequent "+
                         "flags increase verbosity level",
     :arg_description => "",
     :opt_found       => lambda { @verbose ||= -1; @verbose += 1 },
     :opt_not_found   => nil
   }
end

#__versionObject



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'lib/commandline/application.rb', line 392

def __version
   {
     :names           => %w(--version -V),
     :arity           => [0,0],
     :opt_description => "Displays application version.",
     :arg_description => "",
     :opt_found       => lambda { 
                           begin 
                             puts "#{name} - Version: #{version}"
                           rescue 
                             puts "No version specified" 
                           end; 
                           exit 
                         },
     :opt_not_found   => nil
   }
end

#append_argObject



230
231
232
# File 'lib/commandline/application.rb', line 230

def append_arg
  CommandLine::OptionParser::GET_ARG_ARRAY
end

#expected_args(*exp_args) ⇒ Object

expected_args :cmd

Now, what to do if command line has more args than expected
app --app-option cmd --cmd-option arg-for-cmd


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

def expected_args(*exp_args)
  @arg_names = []
  case exp_args.size
  when 0 then @arg_arity = [0,0]
  when 1
    case exp_args[0]
    when Fixnum 
      v = exp_args[0]
      @arg_arity = [v,v]
    when Symbol
      @arg_names = exp_args
      @arg_arity = [1,1]
    when Array
      v = exp_args[0]
      __validate_arg_arity(v)
      @arg_arity = v
    else 
      raise(InvalidArgumentArityError, 
        "Args must be a Fixnum or Array: #{exp_args[0].inspect}.")
    end
  else
    @arg_names = exp_args
    size = exp_args.size
    @arg_arity = [size, size]
  end
end

#get_argObject Also known as: get_args



225
226
227
# File 'lib/commandline/application.rb', line 225

def get_arg
  CommandLine::OptionParser::GET_ARGS
end

#mainObject



278
279
280
281
282
# File 'lib/commandline/application.rb', line 278

def main
  #raise(MissingMainError, "Method #main must be defined in class #{@@child_class}.")
  @@child_class.class_eval %{ def main; end }
  #self.class_eval %{ def main; end }
end

#manObject Also known as: help



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/commandline/application.rb', line 170

def man
  require 'text/format'
  f = Text::Format.new
  f = Text::Format.new
  f.columns = @columns
  f.first_indent  = 4
  f.body_indent   = @body_indent
  f.tag_paragraph = false

  s = []
  s << ["NAME\n"]

  nm = "#{short_description}".empty? ? name : "#{name} - #{short_description}"
  s << f.format(nm)

  sn = "#{synopsis}".empty? ? "" : "#{name} #{synopsis}"
  unless sn.empty?
    s << "SYNOPSIS\n"
    s << f.format(sn)
  end

  dc = "#{long_description}"
  unless dc.empty?
    s << "DESCRIPTION\n"
    s << f.format(dc)
  end

  op = option_parser.to_s
  unless op.empty?
    s << option_parser.to_s
  end

  ar = "#{author}"
  unless ar.empty?
    s << "AUTHOR:  #{ar}"
  end


  ct = "COPYRIGHT (c) #{copyright}"
  unless "#{copyright}".empty?
    s << ct
  end

  s.join("\n")
end

#nameObject



217
218
219
# File 'lib/commandline/application.rb', line 217

def name
  File.basename(pathname)
end

#optObject

Alternative for @option_data, but with symbols



81
82
83
# File 'lib/commandline/application.rb', line 81

def opt
  @option_data
end

#option(*args) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/commandline/application.rb', line 63

def option(*args)
  @options ||= []
  new_list = []
  args.each { |arg|
    new_list << 
    case arg
      when :help    then __help
      when :debug   then __debug
      when :verbose then __verbose
      when :version then __version
      else arg
    end
  }
  #p new_list
  @options << CommandLine::Option.new(*new_list)
end

#options(*opts) ⇒ Object



59
60
61
# File 'lib/commandline/application.rb', line 59

def options(*opts)
  opts.each { |opt| option(*[opt].flatten) }
end

#pathnameObject



221
222
223
# File 'lib/commandline/application.rb', line 221

def pathname
  @@appname
end

#requiredObject



234
235
236
# File 'lib/commandline/application.rb', line 234

def required
  CommandLine::OptionParser::OPT_NOT_FOUND_BUT_REQUIRED
end

#usageObject



166
167
168
# File 'lib/commandline/application.rb', line 166

def usage
  " Usage: #{name} #{synopsis}"
end

#use_replay(attribs = {}) ⇒ Object



161
162
163
164
# File 'lib/commandline/application.rb', line 161

def use_replay(attribs = {})
  @replay = true
  @replay_file = attribs[:replay_file] || @replay_file
end