module S4tUtils

Note, unless otherwise noted, all methods defined in S4tUtils are both module functions and instance functions.

Constants

Version

Public Instance Methods

ask(default_answer, *question_lines) click to toggle source

Ask the question contained in the question_lines, prompt, and wait for an answer. If the stripped value read from STDIN is empty, use the default_answer.

# File lib/s4t-utils/command-line.rb, line 8
def ask(default_answer, *question_lines)
  puts question_lines
  print "[#{default_answer}] => "
  answer = STDIN.readline.strip
  answer = default_answer.to_s if answer == ''
  answer
end
capturing_stderr() { || ... } click to toggle source

Run the block, capturing output to $stderr in a string. That string is the method’s return value.

# File lib/s4t-utils/capturing-globals.rb, line 9
def capturing_stderr
  old_stderr = $stderr
  new_stderr = StringIO.new
  begin
    $stderr = new_stderr
    yield
  ensure
    $stderr = old_stderr
  end
  new_stderr.string
end
capturing_stdout() { || ... } click to toggle source

Run the block, capturing output to $stdout in a string. That string is the method’s return value.

Note: this assigns to $stdout, which is deprecated in favor of $stdout.reopen. However, reopen can’t take a StringIO as an argument.

# File lib/s4t-utils/capturing-globals.rb, line 27
def capturing_stdout
  new_stdout = StringIO.new
  $stdout = new_stdout
  begin
    yield
  ensure
    $stdout = STDOUT
  end
  new_stdout.string
end
erasing_local_config_file(file) { || ... } click to toggle source

Run the block with the given file (named by a string) deleted before and after.

# File lib/s4t-utils/capturing-globals.rb, line 70
def erasing_local_config_file(file)
  with_home_right_here { 
    begin
      File.delete(file) if File.exist?(file)
      yield
    ensure
      File.delete(file) if File.exist?(file)
    end
  }
end
friendly_list(connector, array) click to toggle source

Use connector to join array into a human-friendly list.

friendly_list("or", [1])   => "'1'"
friendly_list("or"), [1, 2]  => "'1' or '2'"
friendly_list("or"), [1, 2, 3] => "'1', '2', or '3'"
# File lib/s4t-utils/friendly-format.rb, line 15
def friendly_list(connector, array)
  quoted = array.collect { | elt | "'" + elt.to_s + "'" }
  case array.length
  when 0
    ""
  when 1
    quoted[0]
  when 2
    quoted[0] + " #{connector} " + quoted[1]
  else
    quoted[0...-1].join(", ") + ", #{connector} #{quoted.last}"
  end
end
pi(arg, leader=nil) click to toggle source

A way of putting debugging statements in code that requires less typing than puts.

pi [1, 2, 3], 'input'    # => 'input: [1, 2, 3]

The arg is printed using inspect. If leader isn’t given, nothing is printed before arg. leader can be a string or symbol.

pi returns its arg, which is occasionally useful for sticking debugging into the middle of complicated expressions.

# File lib/s4t-utils/hacks.rb, line 28
def pi(arg, leader=nil)
  leader = leader.to_s if leader
  leader = (leader == nil) ? '' : leader + ': '
  prog1(arg) { puts leader + arg.inspect }
 end
prog1(retval) { |retval| ... } click to toggle source

The return value of prog1 is the retval. Before that’s returned, though, the retval is yielded to the block. This method is an alternative to stashing a value in a temporary, fiddling around, then returning the temporary. Here’s an example:

prog1(1+1) { | s | puts "Sum is #{s}."}   # => 2

The name “prog1” is ancient Lisp jargon.

# File lib/s4t-utils/hacks.rb, line 13
def prog1(retval)
  yield(retval)
  retval
end
symbol_safe_name(name) click to toggle source

Produces a version of a string that can be typed after a : (Can also be safely given at a command-line prompt.)

# File lib/s4t-utils/friendly-format.rb, line 31
def symbol_safe_name(name)
  name.to_s.gsub(/\W/, '')
end
user_claims(fact, &block) click to toggle source

A StandardError is thrown if the fact the user claims is true is actually false. The block is called to provide the exception message.

# File lib/s4t-utils/claims.rb, line 8
def user_claims(fact, &block)
  user_is_bewildered(block.call) unless fact
end
user_denies(fact, &block) click to toggle source
Alias for: user_disputes
user_disputes(fact, &block) click to toggle source

A StandardError is thrown if the fact the user disputes is nevertheless true. The block is called to provide the exception message.

# File lib/s4t-utils/claims.rb, line 15
def user_disputes(fact, &block)
  user_claims(!fact, &block)
end
Also aliased as: user_denies
user_is_bewildered(msg = "How could this point be reached?") click to toggle source

An unconditional claim that the user is bewildered by something that should not have happened. Most usually, it’s that the code should never have gotten to this point.

# File lib/s4t-utils/claims.rb, line 23
def user_is_bewildered(msg = "How could this point be reached?")
  raise StandardError.new(msg)
end
with_command_args(string) { || ... } click to toggle source

Run the block. During execution, ARGV’s is set as if the script had been executed with string as its argument list. If the block tries to exit, #with_command_args will instead throw a StandardError.

# File lib/s4t-utils/capturing-globals.rb, line 96
def with_command_args(string)
  begin
    old_argv = ARGV.dup
    ARGV.replace(string.split)
    yield
  rescue SystemExit => ex
    replacement = StandardError.new(ex.message)
    replacement.set_backtrace(ex.backtrace)
    raise replacement
  ensure
    ARGV.replace(old_argv)
  end
end
with_environment_vars(settings) { || ... } click to toggle source

Run the block, replacing the values of environment variables with the values given in the hash settings. The environment variables are restored when the method returns.

# File lib/s4t-utils/capturing-globals.rb, line 41
def with_environment_vars(settings)
  begin
    old = {}
    settings.each { | key, value |
      old[key] = ENV[key]
      ENV[key] = value
    }
    yield
  ensure
    settings.each_key { | key |
      ENV[key] = old[key]
    }
  end
end
with_home_right_here() { || ... } click to toggle source

Run the block with the HOME environment variable set to the current working directory.

# File lib/s4t-utils/capturing-globals.rb, line 58
def with_home_right_here
  begin
    old_home = ENV['HOME']
    ENV['HOME'] = '.'
    yield
  ensure
    ENV['HOME'] = old_home
  end
end
with_local_config_file(file, contents) { || ... } click to toggle source

Run the block. During the execution, the contents of file (named by a string) is replaced with contents.

# File lib/s4t-utils/capturing-globals.rb, line 83
def with_local_config_file(file, contents)
  erasing_local_config_file(file) do
    File.open(file, 'w') do | io |
      io.puts(contents.to_s)
    end
    yield
  end
end
with_pleasant_exceptions() { || ... } click to toggle source

Typically used to wrap the execution of an entire script. If an exception is thrown, a terse message is printed (to $stderr) instead of a stack dump. The message printed is gotten from the exception.

# File lib/s4t-utils/error-handling.rb, line 9
def with_pleasant_exceptions
  yield
rescue SystemExit
  raise
rescue Exception => ex
  $stderr.puts(ex.message)
end
with_stdin(string) { || ... } click to toggle source
# File lib/s4t-utils/capturing-globals.rb, line 110
def with_stdin(string)
  old_stdin = $stdin
  $stdin = StringIO.new(string)
  yield
ensure
  $stdin = old_stdin
end
without_pleasant_exceptions() { || ... } click to toggle source

#with_pleasant_exceptions swallows the stack trace, which you want to see during debugging. The easy way to see it is to add ‘out’ to that message, producing this one. To reduce the chance you’ll forget to make exceptions pleasant again, a note that exceptions are turned off is always printed to $stderr.

# File lib/s4t-utils/error-handling.rb, line 22
def without_pleasant_exceptions
  $stderr.puts "Note: exception handling turned off."
  yield
end

Public Class Methods

set_script_lib_path(given) click to toggle source

If the given file lives as a script inside a typical Ruby development structure, put ../lib at the front of the path. That includes files from there in preference to old gems lying around.

# File lib/s4t-utils/os.rb, line 47
def set_script_lib_path(given) 
  path = File.expand_path(given)
  p = lambda { | x | File.join(File.dirname(path), '..', x) }
  l = p['lib']
  t = p['test']
  s = p['setup.rb']
  $:.unshift(l) if File.exists?(l) && File.exists?(t) && File.exists?(s)
end
set_test_paths(given) click to toggle source

Find and set the paths a test needs to run, given the normal Ruby directory structure. given is something below the test directory. PACKAGE_ROOT becomes the root of the structure. PACKAGE_ROOT/lib and PACKAGE_ROOT itself are put on the front of the path (the latter is so that tests can require ‘test/something’.

# File lib/s4t-utils/os.rb, line 33
def set_test_paths(given)
  return if S4tUtils.const_defined?("PACKAGE_ROOT")

  path = File.expand_path(given)
  i = path.index("/test/")
  S4tUtils.const_set("PACKAGE_ROOT", path[0...i])
  $:.unshift("#{PACKAGE_ROOT}/lib")
  $:.unshift("#{PACKAGE_ROOT}")
end