Something attentive, conservative and pretty stuff with zero dependencies.
- tested crystal versions : See ci
Since Crystal breaks backward compatibility casually, we need to pay the follow-up cost for every version upgrade. For example,
Time.nowdoesn't exist in recent versions, butPretty.nowworks on all versions.File.expand_pathdoesn't expand '~' in default in recent versions, butPretty.expand_pathworks the same for all versions.
Pretty.bar(83,100,width: 20).bar # => "|||||||||||||||| "
Pretty.bytes(123456789).to_s # => "123 MB"
Pretty.bytes("12.3GiB").mb # => 13207.024435
Pretty.kb(123456789).to_s # => "123GB"
Pretty.kib(123456789).to_s # => "117GiB"
Pretty.df("/").pcent # => 48
Pretty.df("/", inode: true).cmd # => "LC_ALL=C df -k / -i"
Pretty.number(123456789) # => "123,456,789"
Pretty.date("2001-02-03") # => 2001-02-03 00:00:00.0 Local
Pretty.time("2000-01-02 03:04:05.678") # => 2000-01-02 03:04:05 UTC
Pretty.local_time("2000-01-02") # => 2000-01-02 00:00:00.0 +09:00 Local
Pretty.epoch(981173106) # => 2001-02-03 04:05:06 UTC
Pretty.camelize("http_request") # => "httpRequest"
Pretty.classify("http_request") # => "HttpRequest"
Pretty.underscore("a1Id") # => "a1_id"
Pretty.diff(1,2).to_s # => "Expected '1', but got '2'"
Pretty.expand_path("~/") # => "/home/ubuntu"
Pretty.mem_info.total.gb # => 32.939736
Pretty.method(1.5).call("ceil") # => 2
Pretty.now(2000,1,2,3,4,5) # => 2000-01-02 03:04:05 (Local)
Pretty.utc(2000,1,2,3,4,5) # => 2000-01-02 03:04:05 (UTC)
Pretty.periodical(3.seconds) # => #<Pretty::Periodical::Executor>
Pretty.process_info.max.mb # => 3.568
Pretty.remove_ansi("foo\e\[0m") # => "foo"
Pretty.string_width("aあ") # => 3
Pretty.version("0.28.0-dev").minor # => 28
Pretty::Crystal.version.minor # => 27
Pretty::Dir.clean("a/b/c") # rm -rf a/b/c && mkdir -p a/b/c
Pretty::Logger.new # provides composite logger
Pretty::Stopwatch.new # provides Stopwatch
Pretty::URI.escape("%") # => "%25"
Pretty::URI.unescape("%25") # => "%"
Pretty::Crontab.parse("*/20 * * * * ls").next_time # => "2019-04-18 08:00"
# handy linux file operations
include Pretty::File # provides unix file commands via `FileUtil`
rm_f("foo.txt") # cd, cmp, touch, cp, cp_r, ln, ln_s, ln_sf, mkdir, mkdir_p, mtime, mv, pwd, rm, rm_r, rm_rf, rmdirLoggeris extended. See src/pretty/logger/logger.cr for details.
- use v0.5.7 for crystal-0.24 or lower
- use v1.1.3 for crystal-0.27 or lower
- v0.9.6:
Pretty.bytesreturnsPretty::Bytesrather thanString(useto_sfor backward compats) - v0.7.4:
Pretty.nowreturns Local rather than UTC - v0.7.0: drop
klassmacro (Do not define unnecessary macros at the top level)
Pretty.bar(val, max, width, mark, empty)
Pretty.bytes(value : Int, block = 1000, suffix = "B")
Pretty.camelize(str : String)
Pretty.classify(str : String)
Pretty.date(value : String)
Pretty.error(err : Exception)
Pretty.gb(value : Int)
Pretty.gib(value : Int)
Pretty.json(json : String, color : Bool = false)
Pretty.kb(value : Int)
Pretty.kib(value : Int)
Pretty.lines(lines : Array(Array(String)), headers : Array(String)? = nil, indent : String = "", delimiter : String = "")
Pretty.mem_info
Pretty.method(obj : T).call(name : String)
Pretty.mb(value : Int)
Pretty.mib(value : Int)
Pretty.number(n : Int)
Pretty.periodical(interval : Time::Span)
Pretty.underscore(str : String)
Pretty::Dir.clean(path : String)
Pretty::Stopwatch.new
Pretty::Time.parse(value : String)
Pretty::URI.escape(path : String, *args, **opts)
Pretty::URI.unescape(path : String, *args, **opts)Add this to your application's shard.yml:
dependencies:
pretty:
github: maiha/pretty.cr
version: 1.2.0Then require it in your app.
require "pretty"vals = [8793, 6917, 5534, 8720]
vals.each do |v|
Pretty.bar(v, max: 10000, width: 20)
end[||||||||||||||||| ] 8793/10000 ( 87%)
[||||||||||||| ] 6917/10000 ( 69%)
[||||||||||| ] 5534/10000 ( 55%)
[||||||||||||||||| ] 8720/10000 ( 87%)
Pretty.bytes(416) # => "416 B"
Pretty.bytes(12255736) # => "12.3 MB"
Pretty.bytes(12255736, block: 1024) # => "11.7 MiB"Pretty.camelize("http_request") # => "httpRequest"Pretty.classify("http_request") # => "HttpRequest"Pretty.date("2001-02-03") # => 2001-02-03 00:00:00.0 Local
Pretty.date("1 day ago") # => 2018-09-08 00:00:00.0 +09:00 LocalPretty.dates("20180901") # => [Time(20180901)]
Pretty.dates("20180908-20180909") # => [Time(20180908),Time(20180909)]
Pretty.dates("201809").size # => 30
Pretty.dates("201801-201802").size # => 59data1 = [[112433,15,0],[112465,7293,273]]
data2 = [[112433,15,0],[112465,1307,273]]
diff = Pretty.diff(data1, data2)
diff.size # => 1
diff.to_s # => "Expected '7293', but got '1307'"Absorbs the API difference that changes with each release of crystal.
Personally, epoch and epoch_ms are the most intuitive.
Pretty.epoch(981173106) # => 2001-02-03 04:05:06 UTC
Pretty.epoch_ms(981173106789) # => 2001-02-03 04:05:06.789 UTCUsers can always use this API even if crystal API will be changed again in the future.
err.backtrace # => ["0x48df77: *CallStack::unwind:Array(Pointer(Void))
Pretty.error(err).where # => "mysql at src/commands/db.cr 20:3"- We must call app with path for
where, otherwise the app will be killed.- ❌
foo# would kill your app in printing backtraces - ⭕
/usr/local/bin/foo# will work
- ❌
str = %({"id": "123", "name": "maiha"})
Pretty.json(str){
"id": "123",
"name": "maiha"
}array = [
["user", "maiha"],
["password", "123"],
]
Pretty.lines(array, delimiter: " = ")user = maiha
password = 123
represents memory information in "/proc/meminfo" as Pretty::MemInfo
Pretty.mem_info # => #<Pretty::MemInfo>
Pretty.mem_info.keys # => ["MemTotal", "MemFree", ...]
Pretty.mem_info["MemTotal"] # => Pretty::UsedMemory(@kb=32939736_i64)
Pretty.mem_info.total # => Pretty::UsedMemory(@kb=32939736_i64)
Pretty.mem_info.total.gb # => 32.939736Pretty::MemInfo.process returns a MemInfo of current process.
logger.info "max memory: %s GB" % Pretty::MemInfo.process.max.gbinvoke method by String
Pretty.method([1,2]).call("pop") # => 2
Pretty.method([1,2]).call?("xxx") # => nil- works only public methods, not trailing equals, defined in itself not ancestors
This ensures that it is executed only once within the specified time. This is useful if you want to write logs regularly.
ctx = Pretty.periodical(3.seconds)
10000.times do |i|
...
ctx.execute { logger.info "#{i} done" } # This will be executed once every 3 seconds.
end represents memory information in "/proc/*/status" as Pretty::MemInfo
Pretty.process_info # => #<Pretty::ProcessInfo>
Pretty.process_info.keys # => ["VmPeak", "VmSize", ...]
Pretty.process_info["VmPeak"] # => Pretty::UsedMemory(@kb=92644_i64)
Pretty.process_info.max.mb # => 3.568
Pretty.process_info(1234) # Error opening file '/proc/1234/status'Pretty.number(1000000) # => "1,000,000"parses numbers separated by dots.
Pretty.version("0.27.2").minor # => 27This can also sort ip addresses.
hosts = %w( 192.168.10.1 192.168.0.255 )
sorted = hosts.map{|s| Pretty.version(s)}.sort
sorted.map(&.to_s) # => ["192.168.0.255", "192.168.10.1"]
sorted.map(&.last) # => [255, 1]acts same as unix command rm -rf dir && mkdir -p dir.
Pretty::Dir.clean("tmp/work")Port from CompositeLogger. See above page for details.
parses time without format!
Pretty.time("2000-01-02") # => 2000-01-02 00:00:00 UTC
Pretty.time("2000-01-02 03:04:05") # => 2000-01-02 03:04:05 UTC
Pretty.time("2000-01-02 03:04:05.678") # => 2000-01-02 03:04:05 UTC
Pretty.time("2000-01-02T03:04:05.678+09:00") # => 2000-01-02 03:04:05 +0900$ makeRun make test/x.x.x to test crystal-x.x.x. And to test all the versions, run ci.
$ make test/1.1.1
$ ./ci- Fork it ( https://github.com/maiha/pretty.cr/fork )
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create a new Pull Request
- maiha maiha - creator, maintainer