module Obfusk::Util
Constants
- DATE
- VERSION
Public Class Methods
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
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
(helper for onow)
# File lib/obfusk/util/message.rb, line 58 def self._owhat(what) ': ' + what.map { |x| _tcol(:lgn) + x + _tcol(:non) } *', ' end
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
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
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
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 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
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
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
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
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
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
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
@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
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
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
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
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
deep copy using Marshal
# File lib/obfusk/util/data.rb, line 108 def self.deepdup(obj) Marshal.load Marshal.dump obj end
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
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
@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 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
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
create module method to.to_meth that calls from.from_meth
# File lib/obfusk/util/module.rb, line 16 def self.link_mod_method(from, from_meth, to, to_meth = from_meth) to.module_exec(from, from_meth, to_meth) do |f,fm,tm| (class << self; self; end).send(:define_method, tm) \ { |*a,&b| f.send(fm, *a, &b) } end end
init w/ hash
# File lib/obfusk/util/struct.rb, line 73 def initialize(h = {}) h.each { |k,v| self[k] = v } end
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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(…).ok!`
# File lib/obfusk/util/sh.rb, line 76 def self.sh!(cmd, *args) sh(cmd, *args).ok! end
‘sh(…).ok?`
# File lib/obfusk/util/sh.rb, line 71 def self.sh?(cmd, *args) sh(cmd, *args).ok? end
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(…).ok!`
# File lib/obfusk/util/sh.rb, line 107 def self.shc!(cmd, *args) shc(cmd, *args).ok! end
‘shc(…).ok?`
# File lib/obfusk/util/sh.rb, line 102 def self.shc?(cmd, *args) shc(cmd, *args).ok? end
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
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
convert hash keys to strings
# File lib/obfusk/util/data.rb, line 55 def self.stringify_keys(h) transform_keys(h, &:to_s) end
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
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
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
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
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