module Obfusk::Util

Constants

DATE
VERSION

Public Class Methods

_die_msgs(msgs) click to toggle source

helper; modifies msgs -> OK b/c comes from *msgs

# File lib/obfusk/util/die.rb, line 37
def self._die_msgs(msgs)
  code = (msgs.last.is_a?(Hash) && msgs.pop[:status]) || 1
  msgs.each { |m| $stderr.puts "Error: #{m}" }
  code
end
_enoent_to_run(what, args, &b) click to toggle source

helper

# File lib/obfusk/util/run.rb, line 181
def self._enoent_to_run(what, args, &b)                       # {{{1
  begin
    b[args]
  rescue Errno::ENOENT => e
    raise RunError,
      "failed to #{what} command #{args}: #{e.message}"
  end
end
_owhat(what) click to toggle source

(helper for onow)

# File lib/obfusk/util/message.rb, line 58
def self._owhat(what)
  ': ' + what.map { |x| _tcol(:lgn) + x + _tcol(:non) } *', '
end
_pipeline_args(*args) click to toggle source

helper

# File lib/obfusk/util/run.rb, line 202
def self._pipeline_args(*args)                                # {{{1
  if args.last && (l = args.last.dup).is_a?(Hash)
    args[0..-2].map { |c| _spawn_args(*c) } + [l]
  else
    args.map { |c| _spawn_args(*c) }
  end
end
_sh(cmd, args) click to toggle source

helper

# File lib/obfusk/util/sh.rb, line 148
def self._sh(cmd, args)                                       # {{{1
  a, o  = args.last && (l = args.last.dup).is_a?(Hash) ?
            [args[0..-2],l] : [args,{}]
  shell = o.delete(:shell) || 'bash'
  print = o.delete :print
  exit  = o.delete :exit
  merge = o.delete :merge
  env   = o.delete(:env) || {}
  syms  = o.select { |k,v| Symbol === k }
  strs  = o.select { |k,v| String === k }
  opts  = syms.merge env: env.merge(strs)
  c     = [shell] + (print ? %w{-x} : []) + (exit ? %w{-e} : []) +
            ['-c', cmd, shell] + a
  { cmd: c, opts: opts, merge: merge }
end
_spawn_args(cmd, *args) click to toggle source

helper

# File lib/obfusk/util/run.rb, line 191
def self._spawn_args(cmd, *args)                              # {{{1
  c = [cmd, cmd]
  if args.last && (l = args.last.dup).is_a?(Hash) \
               && e = l.delete(:env)
    [e, c] + args[0..-2] + [l]
  else
    [c] + args
  end
end
_spawn_rm_opts(args) click to toggle source

helper

# File lib/obfusk/util/run.rb, line 211
def self._spawn_rm_opts(args)
  args.last.is_a?(Hash) ? args[0..-2] : args
end
assoc(x, h = {}) click to toggle source

assoc key(s) w/ value(s); array keys represent nested keys; will autovivivy missing (if false/nil) nested objects as hashes

“‘ x = { x: { y: 0 } }; assoc(x, [:x,:y] => 1); x[:y] == 1 “`

# File lib/obfusk/util/data.rb, line 21
def self.assoc(x, h = {})                                   # {{{1
  h.each do |k,v|
    if k.is_a? Array
      case k.length
      when 0; raise ArgumentError, 'empty array key'
      when 1; x[k.first] = v
      else    h, *t = k; assoc(x[h] ||= {}, t => v)
      end
    else
      x[k] = v
    end
  end
  x
end
capture2(*args) click to toggle source

better Open3.capture2; see capture3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 58
def self.capture2(*args)
  _enoent_to_run('capture2', args) do |a|
    Open3.capture2(*_spawn_args(*a))
  end
end
capture2e(*args) click to toggle source

better Open3.capture2e; see capture3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 66
def self.capture2e(*args)
  _enoent_to_run('capture2e', args) do |a|
    Open3.capture2e(*_spawn_args(*a))
  end
end
capture3(*args) click to toggle source

better Open3.capture3; see popen3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 74
def self.capture3(*args)
  _enoent_to_run('capture3', args) do |a|
    Open3.capture3(*_spawn_args(*a))
  end
end
capture_stderr(isatty = false, &b) click to toggle source

use StringIO to capture $stderr from block

# File lib/obfusk/util/spec.rb, line 42
def self.capture_stderr(isatty = false, &b)                   # {{{1
  old = $stderr
  begin
    StringIO.open('', 'w') do |s|
      def s.isatty; true; end if isatty; $stderr = s; b[]; s.string
    end
  ensure
    $stderr = old
  end
end
capture_stdout(isatty = false, &b) click to toggle source

use StringIO to capture $stdout from block

# File lib/obfusk/util/spec.rb, line 30
def self.capture_stdout(isatty = false, &b)                   # {{{1
  old = $stdout
  begin
    StringIO.open('', 'w') do |s|
      def s.isatty; true; end if isatty; $stdout = s; b[]; s.string
    end
  ensure
    $stdout = old
  end
end
chk_exit(args, &b) click to toggle source

run block w/ args, check ‘.exitstatus` @raise RunError if Process::Status’s exitstatus is non-zero

# File lib/obfusk/util/run.rb, line 164
def self.chk_exit(args, &b)
  chk_exitstatus args, b[args].exitstatus
end
chk_exitstatus(args, c) click to toggle source

@raise RunError if c != 0

# File lib/obfusk/util/run.rb, line 169
def self.chk_exitstatus(args, c)
  exit_non_zero! args, c if c != 0
end
deep_merge(h1, h2, &b) click to toggle source

merge hashes recursively

# File lib/obfusk/util/data.rb, line 91
def self.deep_merge(h1, h2, &b)                               # {{{1
  h1.merge(Hash[h2.map do |k,v2|
    if h1.has_key?(k)
      if (v1 = h1[k]).is_a?(Hash) && v2.is_a?(Hash)
        [k, deep_merge(v1, v2, &b)]
      else
        [k, b ? b[k,h1[k],v2] : v2]
      end
    else
      [k, v2]
    end
  end])
end
deep_stringify_keys(h) click to toggle source

convert nested hash keys to strings

# File lib/obfusk/util/data.rb, line 73
def self.deep_stringify_keys(h)
  deep_transform_keys(h, &:to_s)
end
deep_symbolize_keys(h, always = true) click to toggle source

convert nested hash keys to symbols @param always [Boolean] whether to always convert or ignore errors

# File lib/obfusk/util/data.rb, line 79
def self.deep_symbolize_keys(h, always = true)
  deep_transform_keys(h, &(always ? :to_sym : -> k { k.to_sym rescue k }))
end
deep_transform_keys(h, &b) click to toggle source

convert nested hash keys using block

# File lib/obfusk/util/data.rb, line 84
def self.deep_transform_keys(h, &b)
  Hash[h.map { |k,v| [b[k], v.is_a?(Hash) ? deep_transform_keys(v,&b) : v] }]
end
deepdup(obj) click to toggle source

deep copy using Marshal

# File lib/obfusk/util/data.rb, line 108
def self.deepdup(obj)
  Marshal.load Marshal.dump obj
end
die!(*msgs) click to toggle source

print msgs to stderr and exit 1; pass ‘{ status: code }` as last argument to use other statuscode

# File lib/obfusk/util/die.rb, line 17
def self.die!(*msgs)
  code = _die_msgs msgs; exit code
end
empty_as_nil(x) click to toggle source

nil if x is ‘.empty?`, x otherwise

# File lib/obfusk/util/data.rb, line 113
def self.empty_as_nil(x)
  x && x.empty? ? nil : x
end
exec(*args) click to toggle source

better Kernel.exec; should never return (if successful); see spawn, spawn_w, system @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 24
def self.exec(*args)
  _enoent_to_run('exec', args) do |a|
    Kernel.exec(*_spawn_args(*a))
  end
end
exit_non_zero!(args, c) click to toggle source

@raise RunError command returned non-zero

# File lib/obfusk/util/run.rb, line 174
def self.exit_non_zero!(args, c)
  raise RunError, "command returned non-zero: #{args} -> #{c}"
end
get_in(x, *ks, &b) click to toggle source

get the value in a nested associative structure; returns the value (if found), the result of the block (if passed), or nil.

“‘ get_in({ x: { y: 1 } }, :x, :y) # => 1 “`

# File lib/obfusk/util/data.rb, line 43
def self.get_in(x, *ks, &b)                                   # {{{1
  if ks.length == 0
    x
  else
    v = x.fetch(ks.first) { return b && b[] }
    get_in v, *ks.drop(1), &b
  end
end
h_to_struct(h = {}) click to toggle source

hash to struct

# File lib/obfusk/util/data.rb, line 118
def self.h_to_struct(h = {})
  Struct.new(*h.keys).new(*h.values)
end
new(h = {}) click to toggle source

init w/ hash

# File lib/obfusk/util/struct.rb, line 73
def initialize(h = {})
  h.each { |k,v| self[k] = v }
end
odie!(msg, opts = {}) click to toggle source

onoe, exit; requires ‘obfusk/util/message`

# File lib/obfusk/util/die.rb, line 29
def self.odie!(msg, opts = {})
  o = opts.dup; c = o.delete(:status) || 1
  ::Obfusk::Util.onoe msg, o; exit c
end
ohai(msg) click to toggle source

info message w/ colours: “‘ “==> <msg>” “`

# File lib/obfusk/util/message.rb, line 22
def self.ohai(msg)
  puts _tcol(:lbl) + '==> ' + _tcol(:whi) + msg + _tcol(:non)
end
onoe(msg, opts = {}) click to toggle source

error message w/ colours: “‘ “<label>: <msg>” “`

opts` defaults to ’Error’; set ‘opts` to a lambda to pass message on to a logger

# File lib/obfusk/util/message.rb, line 44
def self.onoe(msg, opts = {})
  l = opts[:label] || 'Error'
  $stderr.puts _tcole(:lrd) + l + _tcole(:non) + ': ' + msg
  opts[:log]["#{l}: #{msg}"] if opts[:log]
end
onow(msg, *what) click to toggle source

info message w/ colours: “‘ “==> <msg>: <a>[, <b>, …]” “`

# File lib/obfusk/util/message.rb, line 30
def self.onow(msg, *what)
  puts _tcol(:lgn) + '==> ' + _tcol(:whi) + msg + _tcol(:non) +
    (what.empty? ? '' : _owhat(what))
end
opoo(msg, opts = {}) click to toggle source

warning message (onoe w/ label ‘Warning’)

# File lib/obfusk/util/message.rb, line 51
def self.opoo(msg, opts = {})
  onoe msg, opts.merge(label: 'Warning')
end
osh(*args) click to toggle source

onow + sh; requires ‘obfusk/util/message`

# File lib/obfusk/util/sh.rb, line 114
def self.osh(*args)
  ::Obfusk::Util.onow 'sh', *_spawn_rm_opts(args); sh(*args)
end
osh!(*args) click to toggle source

onow + sh!; requires ‘obfusk/util/message`

# File lib/obfusk/util/sh.rb, line 124
def self.osh!(*args)
  ::Obfusk::Util.onow 'sh', *_spawn_rm_opts(args); sh!(*args)
end
osh?(*args) click to toggle source

onow + sh?; requires ‘obfusk/util/message`

# File lib/obfusk/util/sh.rb, line 119
def self.osh?(*args)
  ::Obfusk::Util.onow 'sh', *_spawn_rm_opts(args); sh?(*args)
end
oshc(*args) click to toggle source

onow + shc; requires ‘obfusk/util/message`

# File lib/obfusk/util/sh.rb, line 131
def self.oshc(*args)
  ::Obfusk::Util.onow 'sh', *_spawn_rm_opts(args); shc(*args)
end
oshc!(*args) click to toggle source

onow + shc!; requires ‘obfusk/util/message`

# File lib/obfusk/util/sh.rb, line 141
def self.oshc!(*args)
  ::Obfusk::Util.onow 'sh', *_spawn_rm_opts(args); shc!(*args)
end
oshc?(*args) click to toggle source

onow + shc?; requires ‘obfusk/util/message`

# File lib/obfusk/util/sh.rb, line 136
def self.oshc?(*args)
  ::Obfusk::Util.onow 'sh', *_spawn_rm_opts(args); shc?(*args)
end
ospawn(*args) click to toggle source

ohai + spawn; requires ‘obfusk/util/message`

# File lib/obfusk/util/run.rb, line 151
def self.ospawn(*args)
  ::Obfusk::Util.ohai _spawn_rm_opts(args)*' '; spawn(*args)
end
ospawn_w(*args) click to toggle source

ohai + spawn_w; requires ‘obfusk/util/message`

# File lib/obfusk/util/run.rb, line 156
def self.ospawn_w(*args)
  ::Obfusk::Util.ohai _spawn_rm_opts(args)*' '; spawn_w(*args)
end
pipeline(*args) click to toggle source

better Open3.pipeline; see exec, popen3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 84
def self.pipeline(*args)
  _enoent_to_run('pipeline', args) do |a|
    Open3.pipeline(*_pipeline_args(*a))
  end
end
pipeline_r(*args, &b) click to toggle source

better Open3.pipeline_r; see pipeline_rw @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 92
def self.pipeline_r(*args, &b)
  _enoent_to_run('pipeline_r', args) do |a|
    Open3.pipeline_r(*_pipeline_args(*a), &b)
  end
end
pipeline_rw(*args, &b) click to toggle source

better Open3.pipeline_rw; see popen3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 100
def self.pipeline_rw(*args, &b)
  _enoent_to_run('pipeline_rw', args) do |a|
    Open3.pipeline_rw(*_pipeline_args(*a), &b)
  end
end
pipeline_start(*args, &b) click to toggle source

better Open3.pipeline_start; see popen3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 108
def self.pipeline_start(*args, &b)
  _enoent_to_run('pipeline_start', args) do |a|
    Open3.pipeline_start(*_pipeline_args(*a), &b)
  end
end
pipeline_w(*args, &b) click to toggle source

better Open3.pipeline_w; see pipeline_rw @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 116
def self.pipeline_w(*args, &b)
  _enoent_to_run('pipeline_w', args) do |a|
    Open3.pipeline_w(*_pipeline_args(*a), &b)
  end
end
popen2(*args, &b) click to toggle source

better Open3.popen2; see popen3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 126
def self.popen2(*args, &b)
  _enoent_to_run('popen2', args) do |a|
    Open3.popen2(*_spawn_args(*a), &b)
  end
end
popen2e(*args, &b) click to toggle source

better Open3.popen2e; see popen3 @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 134
def self.popen2e(*args, &b)
  _enoent_to_run('popen2e', args) do |a|
    Open3.popen2e(*_spawn_args(*a), &b)
  end
end
popen3(*args, &b) click to toggle source

better Open3.popen3; see exec, spawn, spawn_w, system @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 142
def self.popen3(*args, &b)
  _enoent_to_run('popen3', args) do |a|
    Open3.popen3(*_spawn_args(*a), &b)
  end
end
provide_stdin(str, isatty = false, &b) click to toggle source

use StringIO to provide $stdin to block

# File lib/obfusk/util/spec.rb, line 18
def self.provide_stdin(str, isatty = false, &b)               # {{{1
  old = $stdin
  begin
    StringIO.open(str, 'r') do |s|
      def s.isatty; true; end if isatty; $stdin = s; b[]
    end
  ensure
    $stdin = old
  end
end
require_all(dir) click to toggle source

load ‘dir/*` (by searching for `dir/*.rb` in `$LOAD_PATH`)

“‘ require_all(’napp/types’) ~> require ‘napp/types/*’ “‘

@return [Hash] ‘{ module => result-of-require }`

# File lib/obfusk/util/module.rb, line 30
def self.require_all(dir)
  Hash[ $LOAD_PATH.map { |x| Dir["#{x}/#{dir}/*.rb"] } .flatten \
          .map { |x| "#{dir}/" + File.basename(x, '.rb') } .uniq \
          .map { |x| y = require x; [x,y] } ]
end
sh(cmd, *args) click to toggle source

run a command using bash (w/ arguments); see also {shc}; uses {spawn_w}

“‘ sh ’echo “$0” “>>$1<<” “>>$FOO<<”‘, ’“one”‘, ’FOO’ => ‘foo’ # stdout: bash >>“one”<< >>foo<< “‘

@param [Hash] args.last

* `:shell`  the shell to use                    (default: `'bash'`)
* `:print`  whether to pass `-x` to the shell   (default: `false`)
* `:exit`   whether to pass `-e` to the shell   (default: `false`)
* `:merge`  whether to merge stdout and stderr  (default: `false`)
* `:env`    the environment
* any other `String` key is added to the `env`
* any other `Symbol` key is passed as an option to `capture3`

@return [Sh]

# File lib/obfusk/util/sh.rb, line 64
def self.sh(cmd, *args)
  c   = _sh cmd, args; o = c[:opts]
  o_  = c[:merge] ? o.merge(:err => o[:out] ? [:child, :out] : :out) : o
  Sh.new c[:cmd], spawn_w(*c[:cmd], o_)
end
sh!(cmd, *args) click to toggle source

‘sh(…).ok!`

# File lib/obfusk/util/sh.rb, line 76
def self.sh!(cmd, *args)
  sh(cmd, *args).ok!
end
sh?(cmd, *args) click to toggle source

‘sh(…).ok?`

# File lib/obfusk/util/sh.rb, line 71
def self.sh?(cmd, *args)
  sh(cmd, *args).ok?
end
shc(cmd, *args) click to toggle source

run a command using bash (w/ arguments) and capture its stdout and stderr; accepts the same arguments as {sh}; uses ‘capture{2e,3}`

“‘ shc(’echo “$0” “>>$1<<” “>>$FOO<<”‘, ’“one”‘, ’FOO’ => ‘foo’).stdout # => %Q{bash >>“one”<< >>foo<<} “‘

@return [Shc]

# File lib/obfusk/util/sh.rb, line 91
def self.shc(cmd, *args)                                       # {{{1
  c = _sh cmd, args
  if c[:merge]
    stderr = nil; stdout, status = capture2e(*c[:cmd], c[:opts])
  else
    stdout, stderr, status = capture3(*c[:cmd], c[:opts])
  end
  Shc.new c[:cmd], status, stdout, stderr
end
shc!(cmd, *args) click to toggle source

‘shc(…).ok!`

# File lib/obfusk/util/sh.rb, line 107
def self.shc!(cmd, *args)
  shc(cmd, *args).ok!
end
shc?(cmd, *args) click to toggle source

‘shc(…).ok?`

# File lib/obfusk/util/sh.rb, line 102
def self.shc?(cmd, *args)
  shc(cmd, *args).ok?
end
spawn(*args) click to toggle source

better Kernel.spawn; options can be passed as last arg like w/ Kernel.spawn, but instead of env as optional first arg, options takes an :env key as well; also, no shell is ever used; returns PID; see exec, spawn_w, system @raise RunError on ENOENT

# File lib/obfusk/util/run.rb, line 35
def self.spawn(*args)
  _enoent_to_run('spawn', args) do |a|
    Kernel.spawn(*_spawn_args(*a))
  end
end
spawn_w(*args) click to toggle source

better system: spawn + wait; returns $?; see exec, spawn, system

# File lib/obfusk/util/run.rb, line 42
def self.spawn_w(*args)
  pid = spawn(*args); ::Process.wait pid; $?
end
stringify_keys(h) click to toggle source

convert hash keys to strings

# File lib/obfusk/util/data.rb, line 55
def self.stringify_keys(h)
  transform_keys(h, &:to_s)
end
struct(*fields, &b) click to toggle source

better struct; see examples in README.md

# File lib/obfusk/util/struct.rb, line 67
def self.struct(*fields, &b)                                  # {{{1
  Class.new(Struct.new(*fields.map(&:to_sym))) do

    include BetterStruct

    # init w/ hash
    def initialize(h = {})
      h.each { |k,v| self[k] = v }
    end

    self.class_eval(&b) if b

  end
end
submodules(mod) click to toggle source

get submodules as hash

“‘ submodules(Foo) -> { ’bar’ => Foo::Bar, … } “‘

# File lib/obfusk/util/module.rb, line 41
def self.submodules(mod)
  Hash[ mod.constants \
        .map { |x| [x.downcase.to_s, mod.const_get(x)] } \
        .select { |k,v| v.class == Module } ]
end
symbolize_keys(h, always = true) click to toggle source

convert hash keys to symbols @param always [Boolean] whether to always convert or ignore errors

# File lib/obfusk/util/data.rb, line 61
def self.symbolize_keys(h, always = true)
  transform_keys(h, &(always ? :to_sym : -> k { k.to_sym rescue k }))
end
system(*args) click to toggle source

better Kernel.system; returns true/false; see exec, spawn, spawn_w @raise RunError on failure (Kernel.system -> nil)

# File lib/obfusk/util/run.rb, line 48
def self.system(*args)
  r = Kernel.system(*_spawn_args(*args))
  raise RunError, "failed to run command #{args} (#$?)" if r.nil?
  r
end
transform_keys(h, &b) click to toggle source

convert hash keys using block

# File lib/obfusk/util/data.rb, line 66
def self.transform_keys(h, &b)
  Hash[h.map { |k,v| [b[k],v] }]
end
udie!(usage, *msgs) click to toggle source

print msgs to stderr, show usage, exit

# File lib/obfusk/util/die.rb, line 22
def self.udie!(usage, *msgs)
  code = _die_msgs msgs; $stderr.puts "Usage: #{usage}"; exit code
end