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
  __child_initialize if 
    self.class.private_instance_methods(false).include?("__child_initialize")

  @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



269
270
271
# File 'lib/commandline/application.rb', line 269

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

.inherited(child_class) ⇒ Object



261
262
263
264
265
266
267
# File 'lib/commandline/application.rb', line 261

def self.inherited(child_class)
  @@appname = caller[0][/.*:/][0..-2]
  @@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
# 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.
  if self.private_instance_methods(false).include?("initialize")
    $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



405
406
407
408
409
410
411
412
413
# File 'lib/commandline/application.rb', line 405

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

#__helpObject



364
365
366
367
368
369
370
371
372
373
# File 'lib/commandline/application.rb', line 364

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



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/commandline/application.rb', line 334

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



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/commandline/application.rb', line 297

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



292
293
294
295
# File 'lib/commandline/application.rb', line 292

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

#__save_argvObject



279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/commandline/application.rb', line 279

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



324
325
326
327
328
329
330
331
332
# File 'lib/commandline/application.rb', line 324

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:



352
353
354
355
356
357
358
359
360
361
362
# File 'lib/commandline/application.rb', line 352

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



375
376
377
378
379
380
381
382
383
384
385
# File 'lib/commandline/application.rb', line 375

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



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/commandline/application.rb', line 387

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



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

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