class Object

Constants

ZERO_CHAR

A string containing a single zero, with ASCII 8-bit encoding (i.e., plain old bytes)

Public Instance Methods

add_sp(s, indent = 0) click to toggle source

Append a particular number of spaces to a string

# File lib/tokn/tools.rb, line 77
def add_sp(s, indent = 0)
  s << ' ' * indent
end
assert!(cond, *msg) click to toggle source

Assert that a value is true. Should be considered a very temporary, debug-only option; it is slow and generates a warning that it is being called. @param cond condition @param msg generates additional message using printf(), if these arguments exist

# File lib/tokn/tools.rb, line 134
def assert!(cond, *msg)
  one_time_alert("warning",0,"Checking assertion")
  if not cond
    str = (msg.size == 0) ? "assertion error" : sprintf(*msg)
    raise Exception, str
  end
end
block() { || ... } click to toggle source

Method that takes a code block as an argument to achieve the same functionality as Java/C++'s

do {
  ...
  ...  possibly with 'break' to jump to the end ...
} while (false);
# File lib/tokn/tools.rb, line 281
def block
  yield
end
bytes_to_str(byte_array) click to toggle source

Construct a string from an array of bytes @param byte_array array of bytes, or string (in which case it

returns it unchanged)
# File lib/tokn/tools.rb, line 624
def bytes_to_str(byte_array)
  return byte_array if byte_array.is_a? String
  
  byte_array.pack('C*')
end
capture_begin() click to toggle source

Redirect standard output to an internal string

# File lib/tokn/tools.rb, line 405
def capture_begin
    raise IllegalStateException if $IODest
    $IODest = StringIO.new
    $OldStdOut, $stdout = $stdout, $IODest
end
capture_end() click to toggle source

Restore standard output; return captured text @return text that was redirected

# File lib/tokn/tools.rb, line 414
def capture_end
  raise IllegalStateException if !$IODest
  $stdout = $OldStdOut  
  ret = $IODest.string
  $IODest = nil
  ret
end
d(arg) click to toggle source

Convert an object to a human-readable string, or <nil>; should be considered a debug-only feature

# File lib/tokn/tools.rb, line 47
def d(arg)
  arg.nil? ? "<nil>" : arg.inspect
end
d2(arg, indent = 0) click to toggle source

Convert an object to a human-readable string, by calling a type-appropriate function: da, dh, or just d. @param arg object @param indent optional indentation for pretty printing; if result

spans multiple lines, each line should be indented by this amount
# File lib/tokn/tools.rb, line 57
def d2(arg, indent = 0)
  return da(arg, indent) if arg.is_a? Array
  return dh(arg, indent) if arg.is_a? Hash
  return df(arg) if arg.class == FalseClass || arg.class == TrueClass
  return d(arg)  
end
da(array, indent = 0) click to toggle source

Pretty-print an array, one element to a line @param indent indentation of each line, in spaces

# File lib/tokn/tools.rb, line 84
def da(array, indent = 0)
  return d(array) if !array
  s = 'Array ['
  indent += 2
  array.each do |x| 
    s << "\n"
    add_sp(s,indent)
    s2 = d2(x, indent + 2)
    s << s2
  end
  s << " ]"
  s
end
df(flag, label=nil) click to toggle source

Generate debug description of a boolean value @param flag value to interpret as a boolean; prints 'T' iff not nil @param label optional label

# File lib/tokn/tools.rb, line 119
def df(flag, label=nil)
  s = ''
  if label
    s << label << ':'
  end
  s << (flag ? "T" : "F")
  s << ' '
  s
end
dh(hash, indent = 0) click to toggle source

Pretty-print a hash, one element to a line @param indent indentation of each line, in spaces

# File lib/tokn/tools.rb, line 101
def dh(hash, indent = 0)
  return d(hash) if !hash
  s = 'Hash {'
  indent += 2
  hash.each_pair do |key,val| 
    s2 = d(key)
    s3 = d2(val, indent + 4)
    s << "\n " 
    add_sp(s,indent)
    s << s2.chomp << " => " << s3.chomp
  end
  s << " }"
  s
end
dir_entries(path) click to toggle source

Get directory entries, excluding '.' and '..'

# File lib/tokn/tools.rb, line 641
def dir_entries(path)
  ents = Dir.entries(path)
  ents.reject!{|entry| entry == '.' || entry == '..'}
end
dotToPDF(dotFile, name = "", test_dir = nil) click to toggle source

Convert a .dot file (string) to a PDF file “__mygraph__nnn.pdf”

It does this by making a system call to the 'dot' utility.

# File lib/tokn/tokn_const.rb, line 40
def dotToPDF(dotFile, name = "", test_dir = nil)
  gr = dotFile
  
  raise ArgumentError if !test_dir
  
  dotPath = File.join(test_dir,".__mygraph__.dot")
  write_text_file(dotPath,gr)
  destName = File.join(test_dir,"__mygraph__"+name+".pdf")
  system("dot -Tpdf "+dotPath+" -o "+destName)
end
dt(arg) click to toggle source

Convert an object to a human-readable string, prefixed with its type

# File lib/tokn/tools.rb, line 66
def dt(arg)
  if arg.nil?
    return "<nil>"
  end
  s = arg.class.to_s
  s << ':'
  s << arg.inspect
  s
end
elapsed() click to toggle source

Calculate time elapsed, in seconds, from last call to this function; if it's never been called, returns zero

# File lib/tokn/tools.rb, line 377
def elapsed 
  curr = Time.now.to_f
  elap = 0
  if $prevTime
    elap = curr - $prevTime
  end
  $prevTime = curr
  elap
end
get_caller_location(nSkip = 2) click to toggle source

Get a nice, concise description of the file and line of some caller within the stack.

@param nSkip the number of items deep in the call stack to look

# File lib/tokn/tools.rb, line 179
def get_caller_location(nSkip = 2) 
  
  filename = nil
  linenumber = nil
  
  if nSkip >= 0 && nSkip < caller.size
    fi = caller[nSkip]   
    
    i = fi.index(':')
    j = nil
    if i
      j = fi.index(':',i+1)
    end
    if j
      pth = fi[0,i].split('/')
      if pth.size
        filename = pth[-1]
      end
      linenumber = fi[i+1,j-i-1]  
    end
  end
  if filename && linenumber
    loc = filename + " ("+linenumber+")"
  else 
    loc = "(UNKNOWN LOCATION)"
  end
  loc
end
hex_dump(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true) click to toggle source

Hex dump a string or byte array @param byte_array_or_string @param title @param offset offset to first value within array @param length number of values to dump @param bytes_per_row @param with_text if true, displays ASCII values to right of hex dump

# File lib/tokn/tools.rb, line 302
def hex_dump(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true) 
  ss = hex_dump_to_string(byte_array_or_string, title, offset, length, bytes_per_row, with_text)
  puts ss
end
hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true) click to toggle source

Hex dump a string or byte array to a string; see hex_dump for parameter descriptions

# File lib/tokn/tools.rb, line 309
def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
  
  byte_array = byte_array_or_string
  if byte_array.is_a? String
    byte_array = byte_array.bytes.to_a
  end
  
  ss = ''
  
  if title 
    ss << title << ":\n"
  end
  
  if length < 0 
    length = byte_array.size - offset
  end
    
  length = [length, byte_array.size - offset].min
  
  max_addr = offset + length - 1
  num_digits = 4
  while (1 << (4 * num_digits)) <= max_addr
    num_digits += 1
  end
  
  while true
    ss << to_hex(offset, num_digits)
    ss << ': '
    
    chunk = [length, bytes_per_row].min
    bytes_per_row.times do |i|
      if i % 4 == 0 
        ss << '  '
      end
      
      if i < chunk 
        v = byte_array[offset + i]
        ss << ((v != 0) ? to_hex(v,2) : '..')
        ss << ' '
      else
        ss << '   '
      end
    end
        
    if with_text 
      ss << '  |'
      bytes_per_row.times do |i|
        if i < chunk 
          v = byte_array[offset + i]
          ss << ((v >= 32 && v < 127) ? v : '_')
        end
      end
      ss << '|'
    end
    ss << "\n"
    
    length -= chunk
    offset += chunk
    break if length <= 0
  end
  ss
end
int_from_bytes(ba, offset=0) click to toggle source

Decode an int from an array of bytes (big-endian). @param ba array of bytes @param offset offset of first (most significant) byte

# File lib/tokn/tools.rb, line 666
def int_from_bytes(ba, offset=0) 
  (((((ba[offset] << 8) | ba[offset + 1]) << 8) | \
      ba[offset + 2]) << 8) | ba[offset + 3]
end
int_to_bytes(x) click to toggle source
# File lib/tokn/tools.rb, line 646
def int_to_bytes(x)
  [(x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]
end
main?(file) click to toggle source

Convenience method to detect if a script is being run e.g. as a 'main' method (for debug purposes only). If so, it changes the current directory to the directory containing the script (if such a directory exists).

@param file pass __FILE__ in here @return true if so

# File lib/tokn/tools.rb, line 497
def main?(file)
  
  scr = $0

  # The test/unit framework seems to be adding a suffix ": xxx#xxx.."
  # to the .rb filename, so adjust in this case
  i = scr.index(".rb: ")
  if i
    scr = scr[0...i+3]
  end

  if (ret = (file == scr))
    dr = File.dirname(file)
    if File.directory?(dr)
      Dir.chdir(dr)
    end
  end
  ret
end
match_expected_output(str = nil) click to toggle source

Compare a string with disk file; abort if different. Disk filename is derived from caller function name; e.g., test_xxx produces filename _output_xxx

@param str if not nil, string to compare; if nil, calls capture_end to get string

# File lib/tokn/tools.rb, line 427
def match_expected_output(str = nil)

  if !str
    str = capture_end
  end

  cl_method = caller[0][/`.*'/][1..-2]
  if (cl_method.start_with?("test_"))
    cl_method = cl_method[5..-1]
  end
  path = "_output_" + cl_method + ".txt"

  if !File.file?(path)
    printf("no such file #{path} exists, writing it...\n")
    write_text_file(path,str)
  else
    exp_cont = read_text_file(path)
    if str != exp_cont
      d1 = str
      d2 = exp_cont

      # Find location where they differ
      lines1 = d1.split("\n")
      lines2 = d2.split("\n")
      j = [lines1.size, lines2.size].max

      s = "???"
      found_diff = false
      hist = []

      found_count = 0
      j.times do |i|
        found_diff ||= (i >= lines1.size || i >= lines2.size || lines1[i] != lines2[i])
        s = sprintf("%3d:",i)
        if !found_diff
          hist << "#{s}  #{lines1[i]}\n      #{lines2[i]}\n"
        else
          if found_count < 3
            if i < lines1.size
              s << "  #{lines1[i]}\n"
            else
              s << "  ---END---\n"
            end
            if i < lines2.size
              s << "      #{lines2[i]}\n"
            else
              s << "      ---END---\n"
            end
            hist << s
          end
          found_count += 1
        end
        while hist.size > 6
          hist.shift
        end
      end
      dash = "-" * 95 + "\n"
      raise IllegalStateException,"output did not match expected:\n#{dash}#{hist.join('')}#{dash}"
    end
  end
end
one_time_alert(typeString, nSkip, *args) click to toggle source

Print a message if it hasn't yet been printed, which includes the caller's location

@param typeString e.g., “warning”, “unimplemented” @param nSkip the number of levels deep that the caller is in the stack @param args if present, calls sprintf(…) with these to append to the message

# File lib/tokn/tools.rb, line 220
def one_time_alert(typeString, nSkip, *args) 
  loc = get_caller_location(nSkip + 2)
  s = "*** "+typeString+" " + loc
  if args && args.size
    s2 = sprintf(args[0], *args[1..-1])
    msg = s + ": " + s2
  else 
    msg = s
  end

  if $AlertStrings.add?(msg)
    puts msg
  end
end
privatize(entity, add_non_suffix_versions = false) click to toggle source

Mark all constants ending with '_' as private constants

@param entity the class to examine @param add_non_suffix_versions if true, for each constant ABC_ found, also

defines a constant ABC with the same value that is also private
# File lib/tokn/tools.rb, line 712
def privatize(entity, add_non_suffix_versions = false)
  
  db = false
  
  # First command defines constants ABC = n for each constant ABC_ = n;
  # Second declares both versions to be private
  
  cmd1 = nil
  cmd2 = nil
  
  entity.constants.each do |c|
    nm = c.to_s
    
    if nm.end_with?('_')
      nm_small = nm[0..-2]
      
      if !cmd2
        if add_non_suffix_versions
          cmd1 = ''
        end
        cmd2 = 'private_constant '
      else
        cmd2 << ','
      end 
      
      
      !cmd1 || cmd1 << entity.to_s << '::' << nm_small << '=' << entity.const_get(c).to_s << "\n"
      !cmd1 || cmd2 << ':' << nm_small << ','
      cmd2 << ':' << nm
    end
  end
  
  if cmd2
     if cmd1
       !db || pr("about to eval:\n%s\n",cmd1)
       eval(cmd1)
     end
     !db || pr("about to eval:\n%s\n",cmd2)
     eval(cmd2)
  end
end
read_text_file(path) click to toggle source

Read a file's contents, return as a string

# File lib/tokn/tools.rb, line 268
def read_text_file(path)
  contents = nil
  File.open(path,"rb") {|f| contents = f.read }
  contents
end
remove_file_or_dir(pth) click to toggle source

Delete a file or directory, if it exists. Caution! If directory, deletes all files and subdirectories.

# File lib/tokn/tools.rb, line 390
def remove_file_or_dir(pth)
  if File.directory?(pth)
    FileUtils.remove_dir(pth)
  elsif File.file?(pth)
    FileUtils.remove_file(pth)
  end
end
req(fileListStr,subdir = nil) click to toggle source

Convenience method to perform 'require_relative' on a set of files

@param fileListStr space-delimited file/path items, without .rb extensions @param subdir optional path to files relative to this file

# File lib/tokn/tools.rb, line 30
def req(fileListStr,subdir = nil)
  fileListStr.split(' ').each do |x|
    if subdir
      x = File.join(subdir,x)
    end
    x += '.rb'
    require_relative(x)
  end
end
short_from_bytes(ba, offset=0) click to toggle source

Decode a short from an array of bytes (big-endian). @param ba array of bytes @param offset offset of first (most significant) byte

# File lib/tokn/tools.rb, line 658
def short_from_bytes(ba, offset=0) 
  (ba[offset] << 8) | ba[offset + 1] 
end
short_to_bytes(x) click to toggle source
# File lib/tokn/tools.rb, line 650
def short_to_bytes(x) 
  [(x >> 8) & 0xff, x & 0xff]
end
simple_str(s) click to toggle source

Verify that a string is encoded as ASCII-8BIT

# File lib/tokn/tools.rb, line 678
def simple_str(s)
  if s.encoding.name != 'ASCII-8BIT' && s.encoding.name != 'UTF-8'
    pr("string [%s]\n encoding is %s,\n expected ASCII-8BIT\n",s,s.encoding.name)
    assert!(false)
  end
end
str_sized(s, size, pad="\0") click to toggle source

Truncate or pad string so it has a particular size

@param s input string @param size @param pad padding character to use if string needs to grow @return modified string

# File lib/tokn/tools.rb, line 692
def str_sized(s, size, pad="\0")
  s[0...size].ljust(size,pad)
end
str_to_bytes(str) click to toggle source

Construct an array of bytes from a string

@param str string, or array of bytes (in which case it

returns it unchanged)
# File lib/tokn/tools.rb, line 634
def str_to_bytes(str)
  return str if str.is_a? Array
  str.bytes
end
to_ascii8(str) click to toggle source

Transform string to 8-bit ASCII (i.e., just treat each byte as-is)

# File lib/tokn/tools.rb, line 673
def to_ascii8(str)
  str.force_encoding("ASCII-8BIT")
end
to_hex(value, num_digits=4) click to toggle source

Construct hex representation of value @param value integer value @param num_digits number of hex digits

# File lib/tokn/tools.rb, line 289
def to_hex(value, num_digits=4) 
  s = sprintf("%x", value)
  s.rjust(num_digits,'0')
end
unimp(*args) click to toggle source

Print an 'unimplemented' alert, one time only @param args if present, calls printf() with these

# File lib/tokn/tools.rb, line 256
def unimp(*args)
  one_time_alert("unimplemented", 0, *args)
end
unimp!(msg = nil) click to toggle source

Abort with message about unimplemented code

# File lib/tokn/tools.rb, line 144
def unimp!(msg = nil)
  msg2 = "Unimplemented code"
  if msg
    msg2 << ": " << msg
  end
  raise Exception, msg2
end
warn(*args) click to toggle source

Print a 'warning' alert, one time only @param args if present, calls printf() with these

# File lib/tokn/tools.rb, line 237
def warn(*args) 
  one_time_alert("warning",0, *args)
end
warndb(val = true) click to toggle source

Convenience method for setting 'db' true within methods, and to print a one-time warning if so. @param val value to set db to; it is convenient to disable

debug printing quickly by adding a zero, e.g., 'warndb 0'
# File lib/tokn/tools.rb, line 246
def warndb(val = true)
  if !val || val == 0
    return false
  end
  one_time_alert("warning",1,"Debug printing enabled")
  true
end
windows?() click to toggle source

Determine if running on the Windows operating system. Note: there is some debate about the best way to do this.

# File lib/tokn/tools.rb, line 699
def windows?
  if !defined? $__windows__
    $__windows__ = (RUBY_PLATFORM =~ /mswin/)
  end
  $__windows__
end
write_text_file(path, contents) click to toggle source

Write a string to a text file

# File lib/tokn/tools.rb, line 262
def write_text_file(path, contents)
    File.open(path, "wb") {|f| f.write(contents) }
end
zero_bytes(count) click to toggle source

Construct a string of zeros @param count number of zeros

# File lib/tokn/tools.rb, line 21
def zero_bytes(count)
  ZERO_CHAR * count
end