epitools 0.5.133 → 0.5.136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +5 -7
- data/VERSION +1 -1
- data/lib/epitools/autoloads.rb +5 -2
- data/lib/epitools/browser/cache.rb +1 -1
- data/lib/epitools/browser.rb +4 -4
- data/lib/epitools/clitools.rb +21 -4
- data/lib/epitools/core_ext/array.rb +1 -1
- data/lib/epitools/core_ext/numbers.rb +34 -3
- data/lib/epitools/core_ext/object.rb +4 -1
- data/lib/epitools/core_ext/string.rb +99 -3
- data/lib/epitools/fraction.rb +131 -0
- data/lib/epitools/gem_ext/oga.rb +31 -0
- data/lib/epitools/hexdump.rb +1 -1
- data/lib/epitools/minimal.rb +2 -3
- data/lib/epitools/path.rb +34 -19
- data/lib/epitools/pretty_backtrace.rb +1 -1
- data/lib/epitools/rash.rb +1 -1
- data/lib/epitools/term.rb +73 -15
- data/spec/core_ext_spec.rb +26 -2
- data/spec/fraction_spec.rb +53 -0
- data/spec/numwords_spec.rb +2 -5
- data/spec/path_spec.rb +14 -4
- data/spec/sys_spec.rb +5 -0
- data/spec/zopen_spec.rb +37 -37
- metadata +8 -6
- data/lib/epitools/ratio.rb +0 -78
- /data/spec/{browser_spec.rb → manual/browser_spec.rb} +0 -0
- /data/spec/{wm_spec.rb → manual/wm_spec.rb} +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 4c080c53832ae049dd0ac7abedc41844d515b759fd081f4541855359a21eb75a
         | 
| 4 | 
            +
              data.tar.gz: f6871df3e1da9c2cdb315ab49a5c76cea1eb6dfc8f776d6a3f44b3e6d59844fd
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d93c4452eb2e0537265eb95497bf6a0ca9d9022f2ab099972a64904465eccabbe0d3f1901ff2b711940e4603bb6e7afd7c56f7b9b93eea4d9d7762f6453ed3ee
         | 
| 7 | 
            +
              data.tar.gz: 75a2d4e10cf13071f4a2cab7239f6a2db7c3b0bb66a68ce603c75bbe5051c15d742308d9f370cc9fb045e6db2492942f8cd37a65db40ba235655e1ea4d429ac8
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -9,7 +9,7 @@ task :release => :build do | |
| 9 9 | 
             
            end
         | 
| 10 10 |  | 
| 11 11 | 
             
            task :install => :build do
         | 
| 12 | 
            -
              system "gem install -- | 
| 12 | 
            +
              system "gem install --user epitools-#{gem_version}.gem"
         | 
| 13 13 | 
             
            end
         | 
| 14 14 |  | 
| 15 15 | 
             
            task :pry do
         | 
| @@ -17,13 +17,11 @@ task :pry do | |
| 17 17 | 
             
            end
         | 
| 18 18 |  | 
| 19 19 | 
             
            task :spec do
         | 
| 20 | 
            -
              cmd = %w[rspec  | 
| 20 | 
            +
              cmd = %w[rspec --format documentation --force-color --pattern spec/*_spec.rb]
         | 
| 21 | 
            +
              cmd.unshift "rescue" if system *%w[which rescue]
         | 
| 21 22 |  | 
| 22 | 
            -
               | 
| 23 | 
            -
             | 
| 24 | 
            -
              else
         | 
| 25 | 
            -
                system *cmd
         | 
| 26 | 
            -
              end
         | 
| 23 | 
            +
              p cmd
         | 
| 24 | 
            +
              system *cmd
         | 
| 27 25 | 
             
            end
         | 
| 28 26 |  | 
| 29 27 | 
             
            task :default => :spec
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.5. | 
| 1 | 
            +
            0.5.136
         | 
    
        data/lib/epitools/autoloads.rb
    CHANGED
    
    | @@ -69,7 +69,7 @@ autoload :Path,            'epitools/path' | |
| 69 69 | 
             
            autoload :Ezdb,            'epitools/ezdb'
         | 
| 70 70 | 
             
            autoload :Browser,         'epitools/browser'
         | 
| 71 71 | 
             
            autoload :Rash,            'epitools/rash'
         | 
| 72 | 
            -
            autoload : | 
| 72 | 
            +
            autoload :Fraction,        'epitools/fraction'
         | 
| 73 73 | 
             
            autoload :ProgressBar,     'epitools/progressbar'
         | 
| 74 74 | 
             
            autoload :Trie,            'epitools/trie'
         | 
| 75 75 | 
             
            autoload :MimeMagic,       'epitools/mimemagic'
         | 
| @@ -98,8 +98,11 @@ autoreq  :Mechanize,    'mechanize' | |
| 98 98 | 
             
            autoreq  :HTTP,         'http'
         | 
| 99 99 |  | 
| 100 100 | 
             
            autoreq  :Nokogiri,     'nokogiri'
         | 
| 101 | 
            -
            autoreq  :Oga,          'oga'
         | 
| 102 101 | 
             
            autoreq  :Ox,           'ox'
         | 
| 102 | 
            +
            autoreq  :Oga do
         | 
| 103 | 
            +
              require 'oga'
         | 
| 104 | 
            +
              require 'epitools/gem_ext/oga'
         | 
| 105 | 
            +
            end
         | 
| 103 106 |  | 
| 104 107 | 
             
            autoreq  :ANSI,         'ansi'
         | 
| 105 108 |  | 
    
        data/lib/epitools/browser.rb
    CHANGED
    
    | @@ -36,7 +36,7 @@ class Browser | |
| 36 36 | 
             
              #  :use_logs => false,               # Don't log the detailed transfer info
         | 
| 37 37 | 
             
              #  :cookie_file => "cookies.txt"     # Save cookies to file
         | 
| 38 38 | 
             
              #
         | 
| 39 | 
            -
              def initialize(options | 
| 39 | 
            +
              def initialize(**options)
         | 
| 40 40 | 
             
                @last_get     = Time.at(0)
         | 
| 41 41 | 
             
                @delay        = options[:delay]          || 1
         | 
| 42 42 | 
             
                @delay_jitter = options[:delay_jitter]   || 0.2
         | 
| @@ -85,7 +85,7 @@ class Browser | |
| 85 85 | 
             
              end
         | 
| 86 86 |  | 
| 87 87 | 
             
              def load_cookies!
         | 
| 88 | 
            -
                if File. | 
| 88 | 
            +
                if File.exist? @cookie_file
         | 
| 89 89 | 
             
                  agent.cookie_jar.load @cookie_file
         | 
| 90 90 | 
             
                  true
         | 
| 91 91 | 
             
                else
         | 
| @@ -126,7 +126,7 @@ class Browser | |
| 126 126 | 
             
              # Options:
         | 
| 127 127 | 
             
              #   :cached => true/false   | check cache before getting page
         | 
| 128 128 | 
             
              #
         | 
| 129 | 
            -
              def get(url, options | 
| 129 | 
            +
              def get(url, **options)
         | 
| 130 130 |  | 
| 131 131 | 
             
                # TODO: Have a base-URL option
         | 
| 132 132 |  | 
| @@ -151,7 +151,7 @@ class Browser | |
| 151 151 | 
             
                  if use_cache and page = cache.get(url)
         | 
| 152 152 | 
             
                    puts "  |_ cached (#{page.content_type})"
         | 
| 153 153 | 
             
                  else
         | 
| 154 | 
            -
                    page = agent.get(url)
         | 
| 154 | 
            +
                    page = agent.get(url, [], options[:referer])
         | 
| 155 155 | 
             
                    @last_get = Time.now
         | 
| 156 156 | 
             
                    cache_put(page, url) if use_cache
         | 
| 157 157 | 
             
                  end
         | 
    
        data/lib/epitools/clitools.rb
    CHANGED
    
    | @@ -56,6 +56,13 @@ rescue Errno::EPIPE, Interrupt | |
| 56 56 | 
             
            end
         | 
| 57 57 |  | 
| 58 58 |  | 
| 59 | 
            +
            #
         | 
| 60 | 
            +
            # Colorized puts (see: `String#colorize`)
         | 
| 61 | 
            +
            #
         | 
| 62 | 
            +
            def cputs(*args)
         | 
| 63 | 
            +
              puts args.join("\n").colorize
         | 
| 64 | 
            +
            end
         | 
| 65 | 
            +
             | 
| 59 66 | 
             
            #
         | 
| 60 67 | 
             
            # Execute a `system()` command using SQL-style escaped arguments.
         | 
| 61 68 | 
             
            #
         | 
| @@ -179,11 +186,11 @@ end | |
| 179 186 | 
             
            def geoip(addr, city_data='/usr/share/GeoIP/GeoIPCity.dat', country_data='/usr/share/GeoIP/GeoIP.dat')
         | 
| 180 187 | 
             
              (
         | 
| 181 188 | 
             
                $geoip ||= begin
         | 
| 182 | 
            -
                  if city_data and File. | 
| 189 | 
            +
                  if city_data and File.exist? city_data
         | 
| 183 190 | 
             
                    geo = GeoIP.new city_data
         | 
| 184 191 | 
             
                    proc { |addr| geo.city(addr) }
         | 
| 185 192 |  | 
| 186 | 
            -
                  elsif country_data and File. | 
| 193 | 
            +
                  elsif country_data and File.exist? country_data
         | 
| 187 194 | 
             
                    geo = GeoIP.new country_data
         | 
| 188 195 | 
             
                    proc { |addr| geo.country(addr) }
         | 
| 189 196 |  | 
| @@ -202,7 +209,7 @@ def which(*bins) | |
| 202 209 | 
             
              bins.flatten.each do |bin|
         | 
| 203 210 | 
             
                ENV["PATH"].split(":").each do |dir|
         | 
| 204 211 | 
             
                  full_path = File.join(dir, bin)
         | 
| 205 | 
            -
                  return full_path if File. | 
| 212 | 
            +
                  return full_path if File.exist? full_path
         | 
| 206 213 | 
             
                end
         | 
| 207 214 | 
             
              end
         | 
| 208 215 | 
             
              nil
         | 
| @@ -234,7 +241,7 @@ def curl(url) | |
| 234 241 | 
             
              curl_open(url).read
         | 
| 235 242 | 
             
            end
         | 
| 236 243 |  | 
| 237 | 
            -
            def curl_open(url, headers | 
| 244 | 
            +
            def curl_open(url, **headers)
         | 
| 238 245 | 
             
              # 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"
         | 
| 239 246 | 
             
              cmd = ["curl", "-LSs"]
         | 
| 240 247 | 
             
              headers.each { |k,v| cmd += ["-H", "#{k}: #{v}"] }
         | 
| @@ -247,3 +254,13 @@ end | |
| 247 254 | 
             
            def curl_json(url)
         | 
| 248 255 | 
             
              JSON.parse(curl(url))
         | 
| 249 256 | 
             
            end
         | 
| 257 | 
            +
             | 
| 258 | 
            +
            def cached_curl(url)
         | 
| 259 | 
            +
              cache = "/tmp/curl-#{url.sha1}.cache"
         | 
| 260 | 
            +
              if File.exist?(cache)
         | 
| 261 | 
            +
                $stderr.puts "cached! => #{cache}"
         | 
| 262 | 
            +
              else
         | 
| 263 | 
            +
                File.write(cache, curl(url))
         | 
| 264 | 
            +
              end
         | 
| 265 | 
            +
              File.read(cache)
         | 
| 266 | 
            +
            end
         | 
| @@ -283,6 +283,16 @@ class Integer | |
| 283 283 | 
             
              end
         | 
| 284 284 | 
             
              alias_method :bits, :to_bits
         | 
| 285 285 |  | 
| 286 | 
            +
              #
         | 
| 287 | 
            +
              # Convert this number to a Ruby-style string of platform-endian binary digits (eg: "0b011010101").
         | 
| 288 | 
            +
              # Note: The `min_length` argument tells how long the string should be (padding the missing digits with 0's); defaults to 8.
         | 
| 289 | 
            +
              #
         | 
| 290 | 
            +
              def binary(min_length=8)
         | 
| 291 | 
            +
                width = (log(2).ceil / min_length.to_f).ceil * min_length
         | 
| 292 | 
            +
                "0b%0.#{width}b" % self
         | 
| 293 | 
            +
              end
         | 
| 294 | 
            +
              alias_method :bin, :binary
         | 
| 295 | 
            +
             | 
| 286 296 | 
             
              #
         | 
| 287 297 | 
             
              # Cached constants for encoding numbers into bases up to 64
         | 
| 288 298 | 
             
              #
         | 
| @@ -443,20 +453,40 @@ end | |
| 443 453 | 
             
            class Float
         | 
| 444 454 |  | 
| 445 455 | 
             
              #
         | 
| 446 | 
            -
              # Convert the float to a rounded percentage string (eg: "42%").
         | 
| 456 | 
            +
              # Convert the float to a rounded percentage string (eg: "42.5%").
         | 
| 447 457 | 
             
              # Its argument lets you specify how many decimals to display
         | 
| 448 458 | 
             
              #
         | 
| 449 459 | 
             
              # eg:
         | 
| 450 | 
            -
              #    > 0.32786243.percent # => "33%"
         | 
| 460 | 
            +
              #    > 0.32786243.percent # => "33.8%"
         | 
| 451 461 | 
             
              #    > 0.32786243.percent(2) # => "32.79%"
         | 
| 452 462 | 
             
              #
         | 
| 453 | 
            -
              def percent(decimals= | 
| 463 | 
            +
              def percent(decimals=1)
         | 
| 454 464 | 
             
                "%0.#{decimals}f%%" % (self * 100)
         | 
| 455 465 | 
             
              end
         | 
| 456 466 |  | 
| 457 467 | 
             
            end
         | 
| 458 468 |  | 
| 459 469 |  | 
| 470 | 
            +
            class Rational
         | 
| 471 | 
            +
             | 
| 472 | 
            +
              #
         | 
| 473 | 
            +
              # Convert the float to a rounded percentage string (eg: "42.5%")
         | 
| 474 | 
            +
              # (see: Float#percent)
         | 
| 475 | 
            +
              #
         | 
| 476 | 
            +
              def percent(decimals=1)
         | 
| 477 | 
            +
                to_f.percent(decimals)
         | 
| 478 | 
            +
              end
         | 
| 479 | 
            +
             | 
| 480 | 
            +
              #
         | 
| 481 | 
            +
              # Alternate initializer (`Rational[1,2]`)
         | 
| 482 | 
            +
              #
         | 
| 483 | 
            +
              def self.[](*args)
         | 
| 484 | 
            +
                Rational(*args)
         | 
| 485 | 
            +
              end
         | 
| 486 | 
            +
             | 
| 487 | 
            +
            end
         | 
| 488 | 
            +
             | 
| 489 | 
            +
             | 
| 460 490 | 
             
            class Prime
         | 
| 461 491 |  | 
| 462 492 | 
             
              #
         | 
| @@ -485,3 +515,4 @@ end | |
| 485 515 | 
             
            def primes
         | 
| 486 516 | 
             
              Prime.instance
         | 
| 487 517 | 
             
            end
         | 
| 518 | 
            +
             | 
| @@ -11,6 +11,9 @@ class Object | |
| 11 11 | 
             
                Hash[ vars.zip(vals) ]
         | 
| 12 12 | 
             
              end
         | 
| 13 13 |  | 
| 14 | 
            +
              def write_to(file)
         | 
| 15 | 
            +
                open(file, "wb") { |f| f.write self.to_s }
         | 
| 16 | 
            +
              end
         | 
| 14 17 |  | 
| 15 18 | 
             
              #
         | 
| 16 19 | 
             
              # Gives you a copy of the object with its attributes changed to whatever was
         | 
| @@ -36,7 +39,7 @@ class Object | |
| 36 39 | 
             
              #
         | 
| 37 40 | 
             
              # Good for chaining lots of operations together in a REPL.
         | 
| 38 41 | 
             
              #
         | 
| 39 | 
            -
              def with(options | 
| 42 | 
            +
              def with(**options)
         | 
| 40 43 | 
             
                if block_given?
         | 
| 41 44 | 
             
                  yield self
         | 
| 42 45 | 
             
                else
         | 
| @@ -14,6 +14,13 @@ class String | |
| 14 14 | 
             
              #
         | 
| 15 15 | 
             
              STOP_WORDS = %w[a cannot into our thus about co is ours to above could it ourselves together across down its out too after during itself over toward afterwards each last own towards again eg latter per under against either latterly perhaps until all else least rather up almost elsewhere less same upon alone enough ltd seem us along etc many seemed very already even may seeming via also ever me seems was although every meanwhile several we always everyone might she well among everything more should were amongst everywhere moreover since what an except most so whatever and few mostly some when another first much somehow whence any for must someone whenever anyhow former my something where anyone formerly myself sometime whereafter anything from namely sometimes whereas anywhere further neither somewhere whereby are had never still wherein around has nevertheless such whereupon as have next than wherever at he no that whether be hence nobody the whither became her none their which because here noone them while become hereafter nor themselves who becomes hereby not then whoever becoming herein nothing thence whole been hereupon now there whom before hers nowhere thereafter whose beforehand herself of thereby why behind him off therefore will being himself often therein with below his on thereupon within beside how once these without besides however one they would between i only this yet beyond ie onto those you both if or though your but in other through yours by inc others throughout yourself can indeed otherwise thru yourselves]
         | 
| 16 16 |  | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              # Are there any non-whitespace characters in the string?
         | 
| 19 | 
            +
              #
         | 
| 20 | 
            +
              def any?
         | 
| 21 | 
            +
                not blank?
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 17 24 | 
             
              #
         | 
| 18 25 | 
             
              # Convert \r\n to \n
         | 
| 19 26 | 
             
              #
         | 
| @@ -28,6 +35,14 @@ class String | |
| 28 35 | 
             
                Shellwords.escape(self)
         | 
| 29 36 | 
             
              end
         | 
| 30 37 |  | 
| 38 | 
            +
              #
         | 
| 39 | 
            +
              # Do what a browser would do when you type something into the address bar
         | 
| 40 | 
            +
              #
         | 
| 41 | 
            +
              def urlescape
         | 
| 42 | 
            +
                @@uri_parser ||= URI::RFC2396_Parser.new
         | 
| 43 | 
            +
                @@uri_parser.escape(self)
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 31 46 | 
             
              #
         | 
| 32 47 | 
             
              # Remove redundant whitespaces (not including newlines).
         | 
| 33 48 | 
             
              #
         | 
| @@ -115,7 +130,7 @@ class String | |
| 115 130 | 
             
              alias_method :chomp_lines,   :each_chomped
         | 
| 116 131 |  | 
| 117 132 |  | 
| 118 | 
            -
              def split_at(boundary, options | 
| 133 | 
            +
              def split_at(boundary, **options)
         | 
| 119 134 | 
             
                include_boundary = options[:include_boundary] || false
         | 
| 120 135 |  | 
| 121 136 | 
             
                boundary = Regexp.new(Regexp.escape(boundary)) if boundary.is_a?(String)
         | 
| @@ -269,20 +284,39 @@ class String | |
| 269 284 | 
             
                tr('n-za-mN-ZA-M', 'a-zA-Z')
         | 
| 270 285 | 
             
              end
         | 
| 271 286 |  | 
| 287 | 
            +
              #
         | 
| 288 | 
            +
              # Cache an `URI::RFC2396_Parser` instance, because it's slowwww to initialize
         | 
| 289 | 
            +
              #
         | 
| 290 | 
            +
              def _rfc2396_parser
         | 
| 291 | 
            +
                @@rfc2396_parser ||= URI::RFC2396_Parser.new
         | 
| 292 | 
            +
              end
         | 
| 293 | 
            +
             | 
| 272 294 | 
             
              #
         | 
| 273 295 | 
             
              # Convert non-URI characters into %XXes.
         | 
| 274 296 | 
             
              #
         | 
| 275 297 | 
             
              def urlencode
         | 
| 276 | 
            -
                URI.escape(self)
         | 
| 298 | 
            +
                #URI.escape(self)
         | 
| 299 | 
            +
                _rfc2396_parser.escape(self)
         | 
| 277 300 | 
             
              end
         | 
| 278 301 |  | 
| 279 302 | 
             
              #
         | 
| 280 303 | 
             
              # Convert an URI's %XXes into regular characters.
         | 
| 281 304 | 
             
              #
         | 
| 282 305 | 
             
              def urldecode
         | 
| 283 | 
            -
                 | 
| 306 | 
            +
                _rfc2396_parser.unescape(self)
         | 
| 284 307 | 
             
              end
         | 
| 285 308 |  | 
| 309 | 
            +
              #
         | 
| 310 | 
            +
              #
         | 
| 311 | 
            +
              #
         | 
| 312 | 
            +
              def to_bigdecimal
         | 
| 313 | 
            +
                BigDecimal
         | 
| 314 | 
            +
                BigDecimal(self)
         | 
| 315 | 
            +
              end
         | 
| 316 | 
            +
              alias_method :to_d,       :to_bigdecimal
         | 
| 317 | 
            +
              alias_method :to_dec,     :to_bigdecimal
         | 
| 318 | 
            +
              alias_method :to_decimal, :to_bigdecimal
         | 
| 319 | 
            +
             | 
| 286 320 | 
             
              #
         | 
| 287 321 | 
             
              # URI.parse the string and return an URI object
         | 
| 288 322 | 
             
              #
         | 
| @@ -495,6 +529,68 @@ class String | |
| 495 529 | 
             
                nums_and_units.map { |num, units| num.send(units) }.sum
         | 
| 496 530 | 
             
              end
         | 
| 497 531 |  | 
| 532 | 
            +
             | 
| 533 | 
            +
              #
         | 
| 534 | 
            +
              # Translate numbers with units (like 25k, 150GB, 15%, 5 hours) into their expanded numeric value
         | 
| 535 | 
            +
              #
         | 
| 536 | 
            +
              def parse_units
         | 
| 537 | 
            +
                # extract the unit suffix
         | 
| 538 | 
            +
                if self =~ /(\d[\d_]*(?:\.\d+)?)\s*([a-zA-Z]+\b|%(?= \s|$))/
         | 
| 539 | 
            +
                  units = $2.downcase
         | 
| 540 | 
            +
                  num   = $1 #.to_f
         | 
| 541 | 
            +
                  num   = num["."] ? num.to_f : num.to_i
         | 
| 542 | 
            +
             | 
| 543 | 
            +
                  case units
         | 
| 544 | 
            +
                  when "%"
         | 
| 545 | 
            +
                    # 0.01
         | 
| 546 | 
            +
                    num / 100.0
         | 
| 547 | 
            +
                  when "k"
         | 
| 548 | 
            +
                    # 10**3
         | 
| 549 | 
            +
                    num.thousand
         | 
| 550 | 
            +
                  when "m", "mm"
         | 
| 551 | 
            +
                    # 10**6
         | 
| 552 | 
            +
                    num.million
         | 
| 553 | 
            +
                  when "b", "bn"
         | 
| 554 | 
            +
                    # 10**9
         | 
| 555 | 
            +
                    num.billion
         | 
| 556 | 
            +
                  when "gib", "gb", "g"
         | 
| 557 | 
            +
                    num * 2**30
         | 
| 558 | 
            +
                  when "mib", "mb"
         | 
| 559 | 
            +
                    num * 2**20
         | 
| 560 | 
            +
                  when "kib", "kb"
         | 
| 561 | 
            +
                    num * 2**10
         | 
| 562 | 
            +
                  when "t", "tb"
         | 
| 563 | 
            +
                    # 10**12
         | 
| 564 | 
            +
                    num.trillion
         | 
| 565 | 
            +
                  when "q"
         | 
| 566 | 
            +
                    # 10**15
         | 
| 567 | 
            +
                    num.quadrillion
         | 
| 568 | 
            +
                  when "Q"
         | 
| 569 | 
            +
                    # 10**18
         | 
| 570 | 
            +
                    num.quintillion
         | 
| 571 | 
            +
                  when "min"
         | 
| 572 | 
            +
                    # 1.minute
         | 
| 573 | 
            +
                    num.minutes
         | 
| 574 | 
            +
                  when "hours", "h", "hr", "hrs"
         | 
| 575 | 
            +
                    # 1.hour
         | 
| 576 | 
            +
                    num.hours
         | 
| 577 | 
            +
                  when "d", "days", "dy"
         | 
| 578 | 
            +
                    num.days
         | 
| 579 | 
            +
                  else
         | 
| 580 | 
            +
                    raise "Invalid units: #{units.inspect}, in: #{self.inspect}"
         | 
| 581 | 
            +
                  end
         | 
| 582 | 
            +
                else
         | 
| 583 | 
            +
                  raise "Couldn't find any units to parse! (expecting: '<a number><some letters>')"
         | 
| 584 | 
            +
                end
         | 
| 585 | 
            +
              end
         | 
| 586 | 
            +
             | 
| 587 | 
            +
              alias_method :from_units,   :parse_units
         | 
| 588 | 
            +
              alias_method :from_human,   :parse_units
         | 
| 589 | 
            +
              alias_method :from_size,    :parse_units
         | 
| 590 | 
            +
              alias_method :from_percent, :parse_units
         | 
| 591 | 
            +
              alias_method :from_time,    :parse_units
         | 
| 592 | 
            +
             | 
| 593 | 
            +
             | 
| 498 594 | 
             
              #
         | 
| 499 595 | 
             
              # Print a hexdump of the string to STDOUT (coloured, if the terminal supports it)
         | 
| 500 596 | 
             
              #
         | 
| @@ -0,0 +1,131 @@ | |
| 1 | 
            +
            #
         | 
| 2 | 
            +
            # A fraction! (Like a Rational, but ... uh ... in pure Ruby!)
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # Can be compared, added, multiplied, simplified, "percent"ed, "to_f"ed, and printed/inspected.
         | 
| 5 | 
            +
            #
         | 
| 6 | 
            +
            class Fraction
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              attr_accessor :first, :last
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              alias_method :top, :first
         | 
| 11 | 
            +
              alias_method :bottom, :last
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              alias_method :numerator, :first
         | 
| 14 | 
            +
              alias_method :denominator, :last
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              #
         | 
| 17 | 
            +
              # `first` is the top part of the fraction, `last` is the bottom (eg: `first/last`)
         | 
| 18 | 
            +
              #
         | 
| 19 | 
            +
              def initialize(first, last=1)
         | 
| 20 | 
            +
                @first = first
         | 
| 21 | 
            +
                @last = last
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def self.[](*args)
         | 
| 25 | 
            +
                new(*args)
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              include Comparable
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              def <=>(other)
         | 
| 31 | 
            +
                to_f <=> other.to_f
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              #
         | 
| 35 | 
            +
              # Returns a string representation: "a/b"
         | 
| 36 | 
            +
              #
         | 
| 37 | 
            +
              def to_s
         | 
| 38 | 
            +
                "#{@first}/#{@last}"
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
              alias_method :fraction, :to_s
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              #
         | 
| 43 | 
            +
              # Returns the fraction as a float. (eg: Fraction[1,2].to_f == 0.5)
         | 
| 44 | 
            +
              #
         | 
| 45 | 
            +
              def to_f
         | 
| 46 | 
            +
                if @last == 0
         | 
| 47 | 
            +
                  raise ZeroDivisionError
         | 
| 48 | 
            +
                else
         | 
| 49 | 
            +
                  @first.to_f / @last
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              #
         | 
| 54 | 
            +
              # Returns a string representing the number in percent
         | 
| 55 | 
            +
              #
         | 
| 56 | 
            +
              def percent
         | 
| 57 | 
            +
                "%0.1f%%" % (to_f * 100)
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
              alias_method :to_percent, :percent
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              #
         | 
| 62 | 
            +
              # "#<Fraction: 1/2>"
         | 
| 63 | 
            +
              #
         | 
| 64 | 
            +
              def inspect
         | 
| 65 | 
            +
                "#<Fraction: #{to_s}>"
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              #
         | 
| 69 | 
            +
              # Adds together the tops and bottoms of the fractions.
         | 
| 70 | 
            +
              #
         | 
| 71 | 
            +
              # Example: For the fractions `a/c` and `b/d`, returns `a+b/c+d`
         | 
| 72 | 
            +
              #
         | 
| 73 | 
            +
              def +(r)
         | 
| 74 | 
            +
                case r
         | 
| 75 | 
            +
                when Integer
         | 
| 76 | 
            +
                  self + Fraction[r]
         | 
| 77 | 
            +
                when Fraction
         | 
| 78 | 
            +
                  Fraction[ r.last*first + r.first*last, r.last*last ]
         | 
| 79 | 
            +
                else
         | 
| 80 | 
            +
                  raise TypeError.new("Sorry, I can't add a Fraction and a #{r.class}. :(")
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              #
         | 
| 85 | 
            +
              # Multiply the fractions
         | 
| 86 | 
            +
              #
         | 
| 87 | 
            +
              def *(v)
         | 
| 88 | 
            +
                case v
         | 
| 89 | 
            +
                when Integer
         | 
| 90 | 
            +
                  Fraction[ v*first, v*last ]
         | 
| 91 | 
            +
                when Fraction
         | 
| 92 | 
            +
                  Fraction[ v.first*first, v.last*last ]
         | 
| 93 | 
            +
                else
         | 
| 94 | 
            +
                  raise TypeError.new("I don't know how to multiply a Fraction and a #{v.class}. Sorry. :(")
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              def simplify
         | 
| 99 | 
            +
                require 'prime'
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                # factor the numerator and denominator into hashes of { factor => exponent } pairs
         | 
| 102 | 
            +
                n_fact, d_fact = [numerator, denominator].map { |n| Prime.prime_division(n).to_h }
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                # cancel out common factors by subtracting exponents
         | 
| 105 | 
            +
                d_fact.each do |v, d_exp|
         | 
| 106 | 
            +
                  if n_exp = n_fact[v]
         | 
| 107 | 
            +
                    if n_exp < d_exp
         | 
| 108 | 
            +
                      d_fact[v] = d_exp - n_exp
         | 
| 109 | 
            +
                      n_fact[v] = 0
         | 
| 110 | 
            +
                    else
         | 
| 111 | 
            +
                      n_fact[v] = n_exp - d_exp # <= if n_exp == d_exp, this is 0, which covers the 3rd case
         | 
| 112 | 
            +
                      d_fact[v] = 0
         | 
| 113 | 
            +
                    end
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                # multiply the simplified factors back into full numbers
         | 
| 118 | 
            +
                simp_n, simp_d = [n_fact, d_fact].map { |h| h.map{ |n, exp| n ** exp }.reduce(:*) }
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                Fraction[simp_n, simp_d]
         | 
| 121 | 
            +
              end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
            end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
            #####################################################################################
         | 
| 126 | 
            +
            #
         | 
| 127 | 
            +
            # Fraction(a,b) is a wrapper for Fraction[a,b]
         | 
| 128 | 
            +
            #
         | 
| 129 | 
            +
            def Fraction(*args)
         | 
| 130 | 
            +
              Fraction.new(*args)
         | 
| 131 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            module Oga
         | 
| 3 | 
            +
              module XML
         | 
| 4 | 
            +
                # Serialize this node to HAML
         | 
| 5 | 
            +
                module ElementToHAML
         | 
| 6 | 
            +
                  def to_haml
         | 
| 7 | 
            +
                    require 'html2haml'
         | 
| 8 | 
            +
                    require 'html2haml/html'
         | 
| 9 | 
            +
                    Html2haml::HTML.new(to_xml, {}).render.rstrip
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                  alias_method :haml, :to_haml
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def pretty
         | 
| 14 | 
            +
                    require 'coderay'
         | 
| 15 | 
            +
                    puts CodeRay.scan(haml, :haml).term
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  #alias_method :pp, :pretty
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                module PrettyNodeSet
         | 
| 21 | 
            +
                  def pretty
         | 
| 22 | 
            +
                    require 'coderay'
         | 
| 23 | 
            +
                    lesspipe(wrap: true) { |less| each { |node| less.puts CodeRay.scan(node.to_haml, :haml).term; less.puts; less.puts } }
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            Oga::XML::Element.include Oga::XML::ElementToHAML
         | 
| 31 | 
            +
            Oga::XML::NodeSet.include Oga::XML::PrettyNodeSet
         | 
    
        data/lib/epitools/hexdump.rb
    CHANGED
    
    
    
        data/lib/epitools/minimal.rb
    CHANGED
    
    | @@ -253,7 +253,7 @@ module Kernel | |
| 253 253 | 
             
              #
         | 
| 254 254 | 
             
              # Global AwesomePrint method (which triggers the loading of AwesomePrint the first time it's called)
         | 
| 255 255 | 
             
              #
         | 
| 256 | 
            -
              def ap(object, options | 
| 256 | 
            +
              def ap(object, **options)
         | 
| 257 257 | 
             
                AwesomePrint
         | 
| 258 258 | 
             
                Kernel.ap(object, options)
         | 
| 259 259 | 
             
              end
         | 
| @@ -275,13 +275,12 @@ end | |
| 275 275 |  | 
| 276 276 | 
             
            ####################################################################################
         | 
| 277 277 | 
             
            #
         | 
| 278 | 
            -
            # Path("/some/path") is  | 
| 278 | 
            +
            # Path("/some/path") is a wrapper for Path["/some/path"]
         | 
| 279 279 | 
             
            #
         | 
| 280 280 | 
             
            def Path(arg)
         | 
| 281 281 | 
             
              Path[arg]
         | 
| 282 282 | 
             
            end
         | 
| 283 283 |  | 
| 284 | 
            -
             | 
| 285 284 | 
             
            ####################################################################
         | 
| 286 285 | 
             
            require 'epitools/autoloads'
         | 
| 287 286 | 
             
            ####################################################################
         |