Module: Cmdapp

Defined in:
lib/bugzyrb/common/cmdapp.rb

Instance Method Summary collapse

Instance Method Details

#_choice(prompt, choices) ⇒ Object

get choice from user from a list of options

Parameters:

  • prompt (String)

    text

  • values (Array)

    to chose from



475
476
477
478
479
480
# File 'lib/bugzyrb/common/cmdapp.rb', line 475

def _choice prompt, choices
  choose do |menu|
    menu.prompt = prompt
    menu.choices(*choices) do |n|  return n; end
  end
end

#_gets(column, prompt, default = nil) ⇒ Object

get a string from user, using readline or gets if readline, then manage column specific history FIXME: move to Cmdapp.



456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'lib/bugzyrb/common/cmdapp.rb', line 456

def _gets column, prompt, default=nil
  text = "#{prompt}? "
  text << "|#{default}|" if default
  puts text
  if $use_readline
    Cmdapp::history_read column, default
    str = Readline::readline('>', false)
    Cmdapp::history_save column, str
    str = default if str.nil? or str == ""
    return str
  else
    str = $stdin.gets.chomp
    str = default if str.nil? or str == ""
    return str
  end
end

#_list_args(args) ⇒ Array

separates args to list-like operations +xxx means xxx should match in output -xxx means xxx should not exist in output that should not match.

Parameters:

  • list (Array)

    of search terms to match or not-match

Returns:

  • (Array, Array)

    array of terms that should match, and array of terms



361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/bugzyrb/common/cmdapp.rb', line 361

def _list_args args
  incl = []
  excl = []
  args.each do |e| 
    if e[0] == '+'
      incl << e[1..-1]
    elsif  e[0] == '-'
      excl << e[1..-1]
    else
      incl << e
    end
  end
  incl = nil if incl.empty?
  excl = nil if excl.empty?
  return incl, excl
end

#_separate(args, pattern = nil) ⇒ Object

separates args into tag or subcommand and items This allows user to pass e.g. a priority first and then item list or item list first and then priority. This can only be used if the tag or pri or status is non-numeric and the item is numeric.



414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/bugzyrb/common/cmdapp.rb', line 414

def _separate args, pattern=nil #/^[a-zA-Z]/ 
  tag = nil
  items = []
  args.each do |arg| 
    if arg =~ /^[0-9\.]+$/
      items << arg
    else
      tag = arg
      if pattern
        die "#{@action}: #{arg} appears invalid." if arg !~ pattern
      end
    end
  end
  items = nil if items.empty?
  return tag, items
end

#add_action(name, descr) ⇒ Object



97
98
99
100
# File 'lib/bugzyrb/common/cmdapp.rb', line 97

def add_action name, descr
  @actions ||= {}
  @actions[name.to_s] = desc
end

#alias_command(name, *args) ⇒ Object



93
94
95
96
# File 'lib/bugzyrb/common/cmdapp.rb', line 93

def alias_command name, *args
  @aliases ||= {}
  @aliases[name.to_s] = args
end

#backup(filename = @app_file_path) ⇒ Object

backup file to filename.org use prior to a modification operation that could be dangerous or risky



149
150
151
152
# File 'lib/bugzyrb/common/cmdapp.rb', line 149

def backup filename=@app_file_path
  require 'fileutils'
  FileUtils.cp filename, "#{filename}.org"
end

#check_aliases(action, args) ⇒ Boolean

external dependencies:

@app_default_action - action to run if none specified
@app_file_path - data file we are backing up, or reading into array
@app_serial_path - serial_number file

check whether this action is mapped to some alias and changes variables@action and @argv if true. NOTE: some of these are relevant only if we are not using subcommand, so we should move out to another file.

Parameters:

  • action (String)

    asked by user

  • rest (Array)

    of args on command line

Returns:

  • (Boolean)

    whether it is mapped or not.



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/bugzyrb/common/cmdapp.rb', line 32

def check_aliases action, args
  return false unless @aliases
  ret = @aliases[action]
  if ret
    a = ret.shift
    b = [*ret, *args]
    @action = a
    @argv = b
    #puts " #{@action} ; argv: #{@argv} "
    return true
  end
  return false
end

#check_file(filename = @app_file_path) ⇒ Object



405
406
407
# File 'lib/bugzyrb/common/cmdapp.rb', line 405

def check_file filename=@app_file_path
  File.exists?(filename) or die "#{filename} does not exist in this dir. "
end

#die(text) ⇒ Object

exit after printing an error message



154
155
156
157
# File 'lib/bugzyrb/common/cmdapp.rb', line 154

def die text
  $stderr.puts text
  exit ERRCODE
end

#edit_text(text) ⇒ String?

edits given text using EDITOR

Parameters:

  • text (String)

    to edit

Returns:

  • (String, nil)

    edited string, or nil if no change



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/bugzyrb/common/cmdapp.rb', line 247

def edit_text text
  # 2010-06-29 10:24 
  require 'fileutils'
  require 'tempfile'
  ed = ENV['EDITOR'] || "vim"
  temp = Tempfile.new "tmp"
  File.open(temp,"w"){ |f| f.write text }
  mtime =  File.mtime(temp.path)
  #system("#{ed} #{temp.path}")
  system(ed, temp.path)

  newmtime = File.mtime(temp.path)
  newstr = nil
  if mtime < newmtime
    # check timestamp, if updated ..
    newstr = File.read(temp)
  else
    #puts "user quit without saving"
    return nil
  end
  return newstr.chomp if newstr
  return nil
end

#file_append(filename, text) ⇒ Object

if File.exists? filename



401
402
403
404
# File 'lib/bugzyrb/common/cmdapp.rb', line 401

def file_append filename, text
  filename = File.expand_path filename
  File.open(filename,"a"){ |f| f.write text }
end

#file_read(filename) ⇒ Object

———– file operations ————-



391
392
393
394
395
# File 'lib/bugzyrb/common/cmdapp.rb', line 391

def file_read filename
  filename = File.expand_path filename
  return File.read(filename)
  #if File.exists? filename
end

#file_write(filename, text) ⇒ Object

if File.exists? filename



396
397
398
399
400
# File 'lib/bugzyrb/common/cmdapp.rb', line 396

def file_write filename, text
  filename = File.expand_path filename
  File.open(filename,"w"){ |f| f.write text }
  #if File.exists? filename
end

#filter_rows(rows, incl) ⇒ Object

creates a regexp and for each row returns the row and the regexp you can use the regexp on whatever part of the row you want to match or reject



380
381
382
383
384
385
386
387
388
# File 'lib/bugzyrb/common/cmdapp.rb', line 380

def filter_rows rows, incl
  if incl
    incl_str = incl.join "|"
    r = Regexp.new incl_str
    #rows = rows.select { |row| row['title'] =~ r }
    rows = rows.select { |row| yield(row, r) }
  end
  rows
end

#get_lines(prompt = nil) ⇒ String?

prompts user for multiline input NOTE: we do not take Ctrl-d as EOF then causes an error in next input in 1.9 (not 1.8) FIXME: move to Cmdapp

Parameters:

  • text (String)

    to use as prompt

Returns:

  • (String, nil)

    string with newlines or nil (if nothing entered).



436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/bugzyrb/common/cmdapp.rb', line 436

def get_lines prompt=nil
  #prompt ||= "Enter multiple lines, to quit enter . on empty line"
  message prompt if prompt
  str = ""
  while $stdin.gets                        # reads from STDIN
    case $_.chomp 
    when "."
      break
    when ".vim"
      return edit_text str
    end
    str << $_
    #puts "Read: #{$_}"                   # writes to STDOUT
  end
  return nil if str == ""
  return str.chomp
end

#get_serial_numberObject

TODO: move to serial_number.rb or a file that deals with file_data as against sql data which should also have backup, load_array and save_array.

reads serial_number file, returns serialno for this app and increments the serial number and writes back.



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/bugzyrb/common/cmdapp.rb', line 107

def get_serial_number
  require 'fileutils'
  appname = @appname
  filename = @app_serial_path || "serial_numbers"
  h = {}
  # check if serial file existing in curr dir. Else create
  if File.exists?(filename)
    File.open(filename).each { |line|
      #sn = $1 if line.match regex
      x = line.split ":"
      h[x[0]] = x[1].chomp
    }
  end
  sn = h[appname] || 1
  # update the sn in file
  nsn = sn.to_i + 1
  # this will create if not exists in addition to storing if it does
  h[appname] = nsn
  # write back to file
  File.open(filename, "w") do |f|
    h.each_pair {|k,v| f.print "#{k}:#{v}\n"}
  end
  return sn
end

#help(args) ⇒ Object

not required if using Subcommand



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/bugzyrb/common/cmdapp.rb', line 73

def help args
  if @actions.nil? 
    if defined? @commands
      unless @commands.empty?
        @actions = @commands
      end
    end
  end
  if @actions
    puts "Actions are "
    @actions.each_pair { |name, val| puts "#{name}\t#{val}" }
  end
  puts " "
  if @aliases
    puts "Aliases are "
    @aliases.each_pair { |name, val| puts "#{name}:\t#{val.join(' ')}" }
  end
  0
end

#history_read(column, default = nil) ⇒ Object


these 2 methods deal with with maintaining readline history for various columns. _read reads up any earlier values so user can select from them. _save saves the values for future use.


for a given column, check if there’s any previous data in our cache, and put in readlines history so user can use or edit. Also put default value in history.

Parameters:

  • name (String)

    of column for maintaining cache

  • default (String) (defaults to: nil)

    data for user to recall, or edit



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/bugzyrb/common/cmdapp.rb', line 316

def history_read column, default=nil
  values = []
  oldstr = ""
  if !defined? $history_hash
    require 'readline'
    require 'yaml'
    filename = File.expand_path "~/.bugzy_history.yml"
    $history_filename = filename
    # if file exists with values push them into history
    if File.exists? filename
      $history_hash = YAML::load( File.open( filename ) )
    else
      $history_hash = Hash.new
    end
  end
  values.push(*$history_hash[column]) if $history_hash.has_key? column
  # push existing value into history also, so it can be edited
  values.push(default) if default
  values.uniq!
  Readline::HISTORY.clear # else previous values of other fields also come in
  Readline::HISTORY.push(*values) unless values.empty?
  #puts Readline::HISTORY.to_a
end

#history_save(column, str) ⇒ Object

update our cache with str if not present in cache already

Parameters:

  • name (String)

    of column for maintaining cache

  • str (String)

    : data just entered by user



344
345
346
347
348
349
350
351
352
353
354
# File 'lib/bugzyrb/common/cmdapp.rb', line 344

def history_save column, str
  return if str.nil? or str == ""
  if $history_hash.has_key? column
    return if $history_hash[column].include? str
  end
  ($history_hash[column] ||= []) << str
  filename = $history_filename
  File.open( filename, 'w' ) do |f|
    f << $history_hash.to_yaml
  end
end

#indent(str, n) ⇒ Object

indents given string, n spaces redmine.ruby-lang.org/issues/show/749 Thomas Sawyer



515
516
517
518
519
520
521
522
# File 'lib/bugzyrb/common/cmdapp.rb', line 515

def indent(str,n)
  return '' unless str
  if n >= 0
    str.gsub(/^/, ' ' * n)
  else
    str.gsub(/^ {0,#{-n}}/, "")
  end
end

#indent2(str, count) ⇒ Object

indents a string, indenting all but first line. This allows us to print a string as follows:

Description :  The description starts here.
               And continues here. The first line was not indented.

www.ralfebert.de/blog/ruby/string_helpers/ Ralf Ebert



528
529
530
531
532
533
534
# File 'lib/bugzyrb/common/cmdapp.rb', line 528

def indent2(str, count)
  if str
    char = ' '
    #(char * count) + gsub(/(\n+)/) { $1 + (char * count) }
    str.gsub(/(\n+)/) { $1 + (char * count) }
  end
end

#load_arrayObject

load data into array as item and task

See Also:



182
183
184
185
186
187
188
189
190
191
# File 'lib/bugzyrb/common/cmdapp.rb', line 182

def load_array
  #return if $valid_array
  $valid_array = false
  @data = []
  File.open(@app_file_path).each do |line|
    row = line.chomp.split( @app_delim ) 
    @data << row
  end
  $valid_array = true
end

#message(text) ⇒ Object

prints messages to stderr All messages should go to stderr. Keep stdout only for output which can be used by other programs



161
162
163
# File 'lib/bugzyrb/common/cmdapp.rb', line 161

def message text
  $stderr.puts text
end

#old_get_linesString?

reads multiple lines of input until EOF (Ctrl-d) and returns as a string. Add newline after each line

Returns:

  • (String, nil)

    newline delimited string, or nil



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/bugzyrb/common/cmdapp.rb', line 226

def old_get_lines
  lines = nil
  #$stdin.flush
  $stdin.each_line do |line|
    line.chomp!
    if line =~ /^bye$/
      break
    end
    if lines
      lines << "\n" + line
    else
      lines = line
    end
  end
  return lines
end

#pipe_output(pipeto, str) ⇒ Object

pipes given string to command FIXME: not clear how to return error. NOTE: this is obviously more portable than using system echo or system cat.

Examples:

cmd = %{mail -s "my title" rahul}
pipe_output(cmd, "some long text")

Parameters:

  • command (String)

    to pipe data to

  • data (String)

    to pipe to command



279
280
281
282
283
284
285
286
287
288
# File 'lib/bugzyrb/common/cmdapp.rb', line 279

def pipe_output (pipeto, str)
  #pipeto = '/usr/sbin/sendmail -t'
  #pipeto = %q{mail -s "my title" rahul}
  if pipeto != nil  # i was taking pipeto from a hash, so checking
    proc = IO.popen(pipeto, "w+")
    proc.puts str
    proc.close_write
    #puts proc.gets
  end
end


175
176
177
# File 'lib/bugzyrb/common/cmdapp.rb', line 175

def print_green text
  message "#{GREEN}#{text}#{CLEAR}"
end


172
173
174
# File 'lib/bugzyrb/common/cmdapp.rb', line 172

def print_red text
  message "#{RED}#{text}#{CLEAR}"
end

#run0, ERRCODE

runs method after checking if valid or alias. If not found prints help.

Returns:



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/bugzyrb/common/cmdapp.rb', line 49

def run
  @action = @argv[0] || @app_default_action
  @action = @action.downcase
  init_defaults


  ret = 0
  @argv.shift
  if respond_to? @action
    ret = send(@action, @argv)
  else
    # check aliases
    if check_aliases @action, @argv
      ret = send(@action, @argv)
    else
      help @argv
      ret = ERRCODE
    end
  end
  ret ||= 0
  ret = 0 if ret != ERRCODE
  return ret
end

#save_arrayObject

saves the task array to disk Please use load_array to load, and not populate



195
196
197
198
199
200
201
202
# File 'lib/bugzyrb/common/cmdapp.rb', line 195

def save_array
  raise "Cannot save array! Please use load_array to load" if $valid_array == false

  File.open(@app_file_path, "w") do |file| 
    #@data.each { |row| file.puts "#{row[0]}\t#{row[1]}" }
    @data.each { |row| file.puts row.join(@app_delim) }
  end
end

#set_serial_number(number) ⇒ Object

After doing a redo of the numbering, we need to reset the numbers for that app



133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/bugzyrb/common/cmdapp.rb', line 133

def set_serial_number number
  appname = @appname
  pattern = Regexp.new "^#{appname}:.*$"
  filename = @app_serial_path || "serial_numbers"
  # during testing redo this file does not exist, so i get errors
  if !File.exists? filename
    get_serial_number
  end
  backup filename
  # from Sed
  change_row filename, pattern, "#{appname}:#{number}"
end

#template_replace(template, myhash) ⇒ String

reads up template, and substirutes values from myhash NOTE: probably better to use rdoc/template which can handle arrays as well.

Parameters:

  • template (String)

    text

  • values (Hash)

    to replace in template

Returns:

  • (String)

    template output



295
296
297
298
299
300
301
302
303
304
# File 'lib/bugzyrb/common/cmdapp.rb', line 295

def template_replace template, myhash
  #tmpltext=File::read(template);

  t = template.dup
  t.gsub!( /##(.*?)##/ ) {
    #raise "Key '#{$1}' found in template but the value has not been set" unless ( myhash.has_key?( $1 ) )
    myhash[ $1 ].to_s
  }
  t
end

#truncate(string, count) ⇒ Object

for updating in log file truncates long strings comments, descriptions, fix etc and removed newlines



537
538
539
540
541
542
# File 'lib/bugzyrb/common/cmdapp.rb', line 537

def truncate string, count
  string = string.to_s
  string.tr!("\n",' ')
  return string if string.length <= count
  (string[0..(count-4)] + " ...")
end

#user_input(column, prompt_flag, prompt_text = nil, choices = nil, default = nil) ⇒ String?

take user input based on value of flag TODO: should we not check for the ask_x methods and call them if present. FIXME: move to Cmdapp

Parameters:

  • column (String)

    name

  • true, (Boolean, Symbol)

    false, :freeform, :choice

  • text (String, nil)

    to prompt

  • choices (Array, nil) (defaults to: nil)

    array or nil

  • default (Object) (defaults to: nil)

    value

Returns:

  • (String, nil)

    users choice



492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'lib/bugzyrb/common/cmdapp.rb', line 492

def user_input column, prompt_flag, prompt_text=nil, choices=nil, default=nil
  if prompt_flag == true
    prompt_flag = :freeform
    prompt_flag = :choice if choices
  end
  case prompt_flag
  when :freeform
    prompt_text ||= "#{column.capitalize}"
    #str = ask(prompt_text){ |q| q.default = default if default  }
    str = _gets(column, prompt_text, default)
    return str
  when :choice
    prompt_text ||= "Select #{column}:"
    str = _choice(prompt_text, choices)
    return str
  when :multiline, :ml
    return Cmdapp::edit_text default
  when false
    return default
  end
end

#verbose(text) ⇒ Object

print to stderr only if verbose set



165
166
167
# File 'lib/bugzyrb/common/cmdapp.rb', line 165

def verbose text
  message(text) if @options[:verbose]
end

#version_infoString?

retrieve version info updated by jeweler. Typically used by –version option of any command. FIXME: link VERSION to version.rb in lib/buzg.. and read from same dir

Returns:

  • (String, nil)

    version as string, or nil if file not found



208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/bugzyrb/common/cmdapp.rb', line 208

def version_info
  # thanks to Roger Pack on ruby-forum for how to get to the version
  # file
  filename = File.open(File.dirname(__FILE__) + "/../../../VERSION")
  v = nil
  if File.exists?(filename)
    v = File.open(filename).read.chomp if File.exists?(filename)
  #else
    #$stderr.puts "could not locate file #{filename}. " 
    #puts `pwd`
  end
  v
end

#warning(text) ⇒ Object

print to stderr only if verbose set



169
170
171
# File 'lib/bugzyrb/common/cmdapp.rb', line 169

def warning text
  print_red("WARNING: #{text}") 
end