Top Level Namespace
Defined Under Namespace
Modules: Better_URI_RFC3986_Parser, Colored, Digest, Enumerable, Epi, Hex, Kernel, Net, ObjectSpace, Oga, Sys, Term, URI, WM Classes: ARGV, Array, BOFError, Binding, Browser, Class, DateTime, Enumerator, FalseClass, File, Float, Fraction, Hash, IO, Integer, It, Iter, JobRunner, Line, MatchData, Matrix, Mechanize, MimeMagic, Module, NilClass, NotWrapper, Numeric, Object, OpenStruct, Path, Prime, Proc, ProgressBar, Range, Rash, Rational, ReversedProgressBar, SOCKSError, SemanticVersion, String, Struct, Symbol, Time, Trie, TrueClass, TypedStruct
Constant Summary collapse
- RbConfig =
Config
- Infinity =
Float::INFINITY
- Inf =
Float::INFINITY
- Number =
because “obj.is_a? Number” sounds better!
Numeric
Instance Method Summary collapse
-
#autoinstall(*packages) ⇒ Object
Automatically install a required commandline tool using the platform’s package manager (incomplete – only supports debian :).
- #cached_curl(url) ⇒ Object
-
#cmd(*args) ⇒ Object
Execute a ‘system()` command using SQL-style escaped arguments.
- #color_backtrace_1(lines) ⇒ Object
- #color_backtrace_2(lines, **options) ⇒ Object
-
#cputs(*args) ⇒ Object
Colorized puts (see: ‘String#colorize`).
- #curl(url) ⇒ Object
- #curl_json(url) ⇒ Object
- #curl_open(url, **headers) ⇒ Object
- #debug_backtrace(lines) ⇒ Object
-
#Fraction(*args) ⇒ Object
Fraction(a,b) is a wrapper for Fraction.
-
#geoip(addr, city_data = '/usr/share/GeoIP/GeoIPCity.dat', country_data = '/usr/share/GeoIP/GeoIP.dat') ⇒ Object
Lookup GeoIP information (city, state, country, etc.) for an IP address or hostname.
-
#lesspipe(*args) ⇒ Object
Create scrollable output via less!.
-
#longest_common_prefix(strings) ⇒ Object
Return the longest common prefix between two strings.
- #longest_common_subsequence(s1, s2) ⇒ Object
- #niceprint(o, level = 0, indent_first_line = true) ⇒ Object
-
#notify_send(title, body = nil, icon: nil, time: 5) ⇒ Object
Executes notify-send to create a desktop notification on the user’s desktop.
- #parse_lines(backtrace) ⇒ Object
-
#Path(arg) ⇒ Object
Path(“/some/path”) is a wrapper for Path.
-
#perms(size, n = 0, stack = [], &block) ⇒ Object
Returns all the ‘size`-sized selections of the elements from an array.
-
#primes ⇒ Object
Return an infinite enumerable of primes.
-
#prompt(message = "Are you sure?", options = "Yn") ⇒ Object
Prompt the user for confirmation.
- #python_backtrace(lines) ⇒ Object
-
#sudoifnotroot ⇒ Object
Re-execute the script using sudo if it’s not currently running as root.
-
#type ⇒ Object
Networking.
- #TypedStruct(schema) ⇒ Object
-
#which(*bins) ⇒ Object
Search the PATH environment variable for binaries, returning the first one that exists.
Instance Method Details
#autoinstall(*packages) ⇒ Object
Automatically install a required commandline tool using the platform’s package manager (incomplete – only supports debian :)
-
apt-get on debian/ubuntu
-
yum on fedora
-
fink/ports on OSX
-
cygwin on windows
162 163 164 165 166 167 168 |
# File 'lib/epitools/clitools.rb', line 162 def autoinstall(*packages) all_packages_installed = packages.all? { |pkg| Path.which pkg } unless all_packages_installed cmd(["sudo apt-get install ?", packages.join(' ')]) end end |
#cached_curl(url) ⇒ Object
258 259 260 261 262 263 264 265 266 |
# File 'lib/epitools/clitools.rb', line 258 def cached_curl(url) cache = "/tmp/curl-#{url.sha1}.cache" if File.exist?(cache) $stderr.puts "cached! => #{cache}" else File.write(cache, curl(url)) end File.read(cache) end |
#cmd(*args) ⇒ Object
Execute a ‘system()` command using SQL-style escaped arguments.
Example:
cmd( ["cp -arv ? ?", "/usr/src", "/home/you/A Folder/dest"] )
Which is equivalent to:
system( "cp", "-arv", "/usr/src", "/home/you/A Folder/dest" )
Notice that you don’t need to shell-escape anything. That’s done automagically!
If you don’t pass any arrays, ‘cmd` works the same as `system`:
cmd( "cp", "-arv", "etc", "etc" )
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/epitools/clitools.rb', line 81 def cmd(*args) cmd_args = [] for arg in args case arg when Array cmd_literals = arg.shift.split(/\s+/) for cmd_literal in cmd_literals if cmd_literal == "?" raise "Not enough substitution arguments" unless cmd_args.any? cmd_args << arg.shift else cmd_args << cmd_literal end end raise "More parameters than ?'s in cmd string" if arg.any? when String cmd_args << arg else cmd_args << arg.to_s end end p [:cmd_args, cmd_args] if $DEBUG system(*cmd_args) end |
#color_backtrace_1(lines) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/epitools/pretty_backtrace.rb', line 54 def color_backtrace_1(lines) groups = lines.split_before { |line,nextline| line.path != nextline.path } for group in groups dir, filename = File.split(group.first.path) puts "#{filename.green} (#{dir.light_white})" # /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb # 234: require | 553: new_constants_in | group.each do |line| puts " |_ #{line.num.magenta}: #{line.meth.light_yellow.underline}" end #puts " |_ " + group.map{|line| "#{line.num.magenta}: #{line.meth.light_yellow}"}.join(' | '.red) end end |
#color_backtrace_2(lines, **options) ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/epitools/pretty_backtrace.rb', line 70 def color_backtrace_2(lines, **) groups = lines.reverse.split_at { |line,nextline| line.path != nextline.path } if [:no_gems] groups = groups.split_when { |a, nexta| a.first.gem? != nexta.first.gem? } groups.map! { |group| group.first.gem? ? [] : group } end for group in groups if group.empty? puts " ... ignored ... " puts next end firstline = group.first # custom_require.rb (/usr/local/lib/site_ruby/1.8/rubygems) # 234: require => super # 553: new_constants_in => #puts "#{firstline.filename.green} (#{firstline.dir.light_white})" puts "#{firstline.filename.underline} (#{firstline.dir.light_white})" max_methsize = group.map { |line| line.meth.size}.max group.each do |line| pad = " " * (max_methsize - line.meth.size) puts " #{line.num.magenta}: #{line.meth.light_yellow}#{pad}" puts " #{"|_".blue} #{line.codeline.strip}" end puts end end |
#cputs(*args) ⇒ Object
Colorized puts (see: ‘String#colorize`)
62 63 64 |
# File 'lib/epitools/clitools.rb', line 62 def cputs(*args) puts args.join("\n").colorize end |
#curl(url) ⇒ Object
240 241 242 |
# File 'lib/epitools/clitools.rb', line 240 def curl(url) curl_open(url).read end |
#curl_json(url) ⇒ Object
254 255 256 |
# File 'lib/epitools/clitools.rb', line 254 def curl_json(url) JSON.parse(curl(url)) end |
#curl_open(url, **headers) ⇒ Object
244 245 246 247 248 249 250 251 252 |
# File 'lib/epitools/clitools.rb', line 244 def curl_open(url, **headers) # headers["User-Agent"] ||= "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/85 Version/11.1.1 Safari/605.1.15" cmd = ["curl", "-LSs"] headers.each { |k,v| cmd += ["-H", "#{k}: #{v}"] } cmd << url IO.popen(cmd) rescue Errno::ENOENT raise "Error: 'curl' isn't installed." end |
#debug_backtrace(lines) ⇒ Object
120 121 122 123 124 |
# File 'lib/epitools/pretty_backtrace.rb', line 120 def debug_backtrace(lines) lines.each do |line| p line.path end end |
#Fraction(*args) ⇒ Object
Fraction(a,b) is a wrapper for Fraction
129 130 131 |
# File 'lib/epitools/fraction.rb', line 129 def Fraction(*args) Fraction.new(*args) end |
#geoip(addr, city_data = '/usr/share/GeoIP/GeoIPCity.dat', country_data = '/usr/share/GeoIP/GeoIP.dat') ⇒ Object
Lookup GeoIP information (city, state, country, etc.) for an IP address or hostname
(Note: Must be able to find one of /usr/share/GeoIP/GeoIP,City.dat, or specified manually
as (an) extra argument(s).)
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/epitools/clitools.rb', line 186 def geoip(addr, city_data='/usr/share/GeoIP/GeoIPCity.dat', country_data='/usr/share/GeoIP/GeoIP.dat') ( $geoip ||= begin if city_data and File.exist? city_data geo = GeoIP.new city_data proc { |addr| geo.city(addr) } elsif country_data and File.exist? country_data geo = GeoIP.new country_data proc { |addr| geo.country(addr) } else raise "Can't find GeoIP data files." end end ).call(addr) end |
#lesspipe(*args) ⇒ Object
Create scrollable output via less!
This command runs ‘less` in a subprocess, and gives you the IO to its STDIN pipe so that you can communicate with it.
Example:
lesspipe do |less|
50.times { less.puts "Hi mom!" }
end
The default less parameters are:
-
Allow colour
-
Don’t wrap lines longer than the screen
-
Quit immediately (without paging) if there’s less than one screen of text.
You can change these options by passing a hash to ‘lesspipe`, like so:
lesspipe(:wrap=>false) { |less| less.puts essay.to_s }
It accepts the following boolean options:
:color => Allow ANSI colour codes?
:wrap => Wrap long lines?
:always => Always page, even if there's less than one page of text?
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/epitools/clitools.rb', line 27 def lesspipe(*args) if args.any? and args.last.is_a?(Hash) = args.pop else = {} end output = args.first if args.any? params = [] params << "-R" unless [:color] == false params << "-S" unless [:wrap] == true params << "-F" unless [:always] == true if [:tail] == true params << "+\\>" $stderr.puts "Seeking to end of stream..." end params << "-X" IO.popen("less #{params * ' '}", "w") do |less| if output less.puts output else yield less end end rescue Errno::EPIPE, Interrupt # less just quit -- eat the exception. end |
#longest_common_prefix(strings) ⇒ Object
Return the longest common prefix between two strings.
2 3 4 5 6 7 8 9 10 11 12 13 |
# File 'lib/epitools/lcs.rb', line 2 def longest_common_prefix(strings) p = nil strings.map{|s|s.size}.min.times do |c| if strings.map{|s|s[c]}.uniq.size == 1 p = c else break end end strings.first[0..p] unless p.nil? end |
#longest_common_subsequence(s1, s2) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/epitools/lcs.rb', line 16 def longest_common_subsequence(s1, s2) num = Array.new(s1.size) { Array.new(s2.size) } len, ans = 0 s1.chars.each_with_index do |l1, i| s2.chars.each_with_index do |l2, j| unless l1==l2 num[i][j]=0 else if (i==0 || j==0) num[i][j] = 1 else num[i][j] = 1 + num[i-1][j-1] end len = ans = num[i][j] if num[i][j] > len end end end ans end |
#niceprint(o, level = 0, indent_first_line = true) ⇒ Object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/epitools/niceprint.rb', line 1 def niceprint(o, level=0, indent_first_line=true) maxstring = 50 maxarray = 20 result = "" dent = " " indent = dent * level result << indent if indent_first_line case o when Hash #puts "Hash!" result << "{\n" o.each_with_index do |(k,v),i| result << "#{indent+dent}#{k.inspect} => #{niceprint(v,level+1,false)}" result << "," unless i == o.size result << "\n" end result << "#{indent}}" when Array #puts "Array!" indent_first = o.any? { |e| e.instance_of? Hash } if indent_first result << "[\n" else result << "[" end o = o[0..maxarray] if o.size > maxarray o.each do |e| result << niceprint(e,level+1,indent_first) result << ", " end result << "]" when String #puts "String!" o = o[0..maxstring] + "..." if o.size > maxstring result << o.inspect else result << o.inspect end if level == 0 print result else result end end |
#notify_send(title, body = nil, icon: nil, time: 5) ⇒ Object
Executes notify-send to create a desktop notification on the user’s desktop
Note: the ‘icon’ argument is the path to an image file
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/epitools/clitools.rb', line 224 def notify_send(title, body=nil, icon: nil, time: 5) $stderr.puts "* #{title}" $stderr.puts " |_ #{body}" if body time_in_ms = time * 1000 cmd = ["notify-send"] cmd << "--expire-time=#{time_in_ms}" cmd << "--app-name=#{Process.argv0}" cmd << "--icon=#{icon}" if icon cmd << CGI.escapeHTML(title) cmd << CGI.escapeHTML(body) if body fork { system *cmd } end |
#parse_lines(backtrace) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/epitools/pretty_backtrace.rb', line 38 def parse_lines(backtrace) backtrace.map do |line| case line when /^\s+(.+):(\d+):in \`(.+)'/ Line.new($1, $2, $3) when /^\s+(.+):(\d+)/ Line.new($1, $2, '') when /^\s+$/ next else raise "huh?!" end end.compact end |
#Path(arg) ⇒ Object
Path(“/some/path”) is a wrapper for Path
280 281 282 |
# File 'lib/epitools/minimal.rb', line 280 def Path(arg) Path[arg] end |
#perms(size, n = 0, stack = [], &block) ⇒ Object
Returns all the ‘size`-sized selections of the elements from an array.
I can’t remember why I wrote it like this, but the array you want to permute is passed in as a block. For example:
>> perms(1) { [1,2,3,4] }
=> [[1], [2], [3], [4]]
>> perms(2) { [1,2,3,4] }
=> [[1, 1], [1, 2], [1, 3], [1, 4], [2, 1], [2, 2], [2, 3], [2, 4],
[3, 1], [3, 2], [3, 3], [3, 4], [4, 1], [4, 2], [4, 3], [4, 4]]
The block also gets passed a parameter: the depth of the recursion. I can’t remember why I did that either! :D
66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/epitools/permutations.rb', line 66 def perms(size, n=0, stack=[], &block) ps = yield(n) results = [] if n >= size results << stack else ps.each do |p| results += perms(size, n+1, stack + [p], &block) end end results end |
#primes ⇒ Object
Return an infinite enumerable of primes
515 516 517 |
# File 'lib/epitools/core_ext/numbers.rb', line 515 def primes Prime.instance end |
#prompt(message = "Are you sure?", options = "Yn") ⇒ Object
Prompt the user for confirmation.
Usage:
prompt("Do you want a cookie?", "Ynqa") #=> returns the letter that the user pressed, in lowercase (and returns the default, 'y', if the user hits ENTER)
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/epitools/clitools.rb', line 125 def prompt(="Are you sure?", ="Yn") opts = .scan(/./) optstring = opts.join("/") # case maintained defaults = opts.select{|o| o.upcase == o } opts = opts.map{|o| o.downcase} raise "Error: Too many default values for the prompt: #{default.inspect}" if defaults.size > 1 default = defaults.first loop do print "#{} (#{optstring}) " response = STDIN.gets.strip.downcase case response when *opts return response when "" return default.downcase else puts " |_ Invalid option: #{response.inspect}. Try again." end end end |
#python_backtrace(lines) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/epitools/pretty_backtrace.rb', line 108 def python_backtrace(lines) #groups = lines.reverse.split_when { |line,nextline| line.path != nextline.path } lines = lines.reverse puts "Traceback (most recent call last):" for line in lines puts %{ File "#{line.path}", line #{line.num}, in #{line.meth}} puts %{ #{line.codeline.strip}} end end |
#sudoifnotroot ⇒ Object
Re-execute the script using sudo if it’s not currently running as root.
174 175 176 177 178 |
# File 'lib/epitools/clitools.rb', line 174 def sudoifnotroot unless Process.uid == 0 exit system("sudo", $PROGRAM_NAME, *ARGV) end end |
#type ⇒ Object
Networking
47 48 49 |
# File 'lib/epitools/autoloads.rb', line 47 ['IP', 'Basic', 'TCP', 'UDP', 'UNIX', ''].each do |type| autoload :"#{type}Socket", 'socket' end |
#TypedStruct(schema) ⇒ Object
139 140 141 |
# File 'lib/epitools/typed_struct.rb', line 139 def TypedStruct(schema) TypedStruct[schema] end |
#which(*bins) ⇒ Object
Search the PATH environment variable for binaries, returning the first one that exists
208 209 210 211 212 213 214 215 216 |
# File 'lib/epitools/clitools.rb', line 208 def which(*bins) bins.flatten.each do |bin| ENV["PATH"].split(":").each do |dir| full_path = File.join(dir, bin) return full_path if File.exist? full_path end end nil end |