#!/usr/bin/env ruby require 'time' def die(str) $stderr.puts str exit end def usage die "Usage: nap { for [] | until | cycles [] }" + "\ne.g. nap for 3h\n nap until 10AM\n nap cycles 4\n " + "nap cycles 4+10 # 10 minutes to brush teeth" end def hourminutes(hours) wholes = hours.to_i minutes = (hours - hours.to_i) * 60 "#{ wholes }:#{ ("0" + minutes.to_i.to_s)[-2..-1] }" end def kind_for(time) aliases = {'m' => 60, 'h' => 3600, 's' => 1} prefix = aliases[(time.match('[hms]$') || ['s'])[0]] yield "# date format bogus" unless time.match(/^\d+(\.\d+)?([hms])?$/) "sudo rtcwake -m mem -t -s #{ time.to_f.*(prefix).to_i }" end def successfully(args) errors, pipe = IO.pipe IO.popen(args, err: pipe) do |p| p.read end.tap do pipe.close die errors.read unless $?.success? end end def kind_until(time) date = successfully(%w{date -d} + [time]) secs = successfully(%w{date -d} + [time] + %w{+%s}).to_i hours = (((secs.to_i - Time.now.to_i) / 36) / 100.0) yield "# %s hours" % hourminutes(hours) if (0.40..60).include? hours yield "# #{ date }" "sudo rtcwake -m mem -t #{ secs }" end def kind_cycles(n = nil, &block) # Print time, if n = nil. # n = '1' -> sleep one cycle + 14 minutes # n = '1+20' -> sleep one cylce + 14 minutes + 20 minutes to brush teeth gen = proc do |i, j| cycle = 3600 * 3 / 2 tts = 14 * 60 # a joke on Time To Live (Time.now + (cycle * i + tts + (j || 0) * 60)).strftime('%H:%M') end enough = 6 times = (1..enough).map { |i| gen.call i } if n m, o = n.split('+').map(&:to_i) unless (1..enough).include? m yield "# only cycles 1 through #{ enough } are meant to be used" end kind_until(gen.call(m, o), &block) else yield "# according to http://sleepyti.me" yield "# you should wake up at:" yield("# " + times.join(', ')) end end kind = ARGV[0] timedescr = ARGV[1..-1] if ARGV.length == 2 usage if !kind.match(/^(until|for|cycles)$/) elsif ARGV.length == 1 usage if kind != 'cycles' else usage end cmd = send(:"kind_#{ kind }", *timedescr) { |info| $stderr.puts info } puts cmd if cmd