Permalink
Browse files

initial goodies

  • Loading branch information...
0 parents commit a1a5f29ffe312c91f58d9081e9cdd89113ddc35f Sam Stokes committed Jan 27, 2011
Showing with 204 additions and 0 deletions.
  1. +38 −0 bin/graph.rb
  2. +49 −0 bin/log.rb
  3. +59 −0 lib/backend.rb
  4. +15 −0 lib/config.rb
  5. +30 −0 lib/day.rb
  6. +13 −0 lib/enumerable.rb
@@ -0,0 +1,38 @@
+require 'date'
+require 'redis'
+require 'gerbilcharts'
+
+require File.join(File.dirname(__FILE__), *%w(.. lib backend))
+require File.join(File.dirname(__FILE__), *%w(.. lib config))
+require File.join(File.dirname(__FILE__), *%w(.. lib day))
+
+include Pomoplot
+
+config = Pomoplot::Config.user
+
+redis = Redis.connect(:url => config['redis'])
+backend = Backend.new(redis, config['bucket'])
+
+days = backend.days(Date.today - 28)
+
+GerbilCharts::Charts::LineChart.new(
+ :width => 600,
+ :height => 300,
+ :style => 'brushmetal.css',
+ :javascripts => 'gerbil.js',
+ :scaling_y => :auto_0,
+ :circle_data_points => true,
+ :auto_tooltips => true,
+ :enabletimetracker => true
+).tap do |chart|
+ GerbilCharts::Models::SimpleTimeSeriesModelGroup.new(
+ :title => "#{config['user']} Pomodoros",
+ :timeseries => days.map(&:date).map(&:to_time),
+ :models => [['Pomos', *days.map(&:pomos)]]
+ ).tap do |modelgroup|
+ chart.modelgroup = modelgroup
+ chart.render_string.tap do |svg|
+ puts svg
+ end
+ end
+end
@@ -0,0 +1,49 @@
+require 'date'
+require 'redis'
+
+require File.join(File.dirname(__FILE__), *%w(.. lib backend))
+require File.join(File.dirname(__FILE__), *%w(.. lib config))
+require File.join(File.dirname(__FILE__), *%w(.. lib day))
+
+include Pomoplot
+
+config = Pomoplot::Config.user
+
+redis = Redis.connect(:url => config['redis'])
+backend = Backend.new(redis, config['bucket'])
+
+puts "Hi, #{config['user']}!"
+backend.last_day.tap do |last|
+ if last
+ puts "You last logged #{last.pomos} pomos on #{last.date}."
+ else
+ puts "You've never logged any pomos!"
+ end
+ puts
+end
+
+response = nil
+days = []
+while response !~ /^q/i
+ print "Log pomos? ('quit' to quit) "
+ response = readline
+ words = response.split
+ pomos = words.grep(/^\d+$/).map(&:to_i).first
+ date = words.map do |word|
+ if word =~ /^\d+$/
+ nil
+ else
+ Date.parse(word) rescue nil
+ end
+ end.compact.first
+ next unless pomos
+ date ||= Date.today
+ day = Day[date]
+ day.pomos = pomos
+ days << day
+ puts "OK, #{pomos} pomos on #{date}."
+end
+
+backend.update_days(days)
+
+puts "Logged #{days.size} days."
@@ -0,0 +1,59 @@
+require File.join(File.dirname(__FILE__), 'day')
+require File.join(File.dirname(__FILE__), 'enumerable')
+
+module Pomoplot
+ class Backend
+ def initialize(redis, bucket)
+ @redis = redis
+ @bucket = "Pomoplot:#{bucket}"
+ end
+
+ def update_days(days)
+ @redis.multi do
+ days.each {|day| update_day(day) }
+ end
+ end
+
+ def update_all
+ update_days(Day.all)
+ end
+
+ def update_day(day)
+ @redis.zadd @bucket, day.timestamp, day_to_label(day)
+ end
+
+ def days(from_date = nil, to_date = nil)
+ from_stamp = from_date.to_time.tv_sec rescue '-inf'
+ to_stamp = to_date.to_time.tv_sec rescue '+inf'
+ @redis.zrangebyscore(@bucket, from_stamp, to_stamp, :with_scores => true).
+ paired.map {|value, score| load_day(value, score.to_i) }
+ end
+
+ def last_day
+ value, score = @redis.zrevrange @bucket, 0, 0, :with_scores => true
+ return nil unless value
+ load_day(value, score.to_i)
+ end
+
+ private
+ def day_to_label(day)
+ "#{day.iso8601}:#{day.pomos}"
+ end
+
+ def label_to_day(label)
+ date, pomos, junk = label.split(':', 3)
+ raise ArgumentError, "junk '#{junk}' at end of label '#{label}'" if junk
+ raise ArgumentError, "bad label format '#{label}'" unless pomos && pomos =~ /^\d+$/
+
+ Day[Date.parse(date)].tap {|day| day.pomos = pomos.to_i }
+ end
+
+ def load_day(value, score)
+ label_to_day(value).tap do |day|
+ unless day.timestamp == score
+ raise "timestamp #{score} and label date #{value} do not match!"
+ end
+ end
+ end
+ end
+end
@@ -0,0 +1,15 @@
+require 'yaml'
+
+module Pomoplot
+ module Config
+ class << self
+ def load(path)
+ open(path) {|yaml| YAML.load(yaml) }
+ end
+
+ def user
+ load(File.join(ENV['HOME'], '.pomoplot.yml'))
+ end
+ end
+ end
+end
@@ -0,0 +1,30 @@
+module Pomoplot
+ class Day
+ attr_accessor :pomos
+ attr_reader :date
+
+ def initialize(date)
+ @date = date
+ @pomos = 0
+ end
+
+ def iso8601
+ @date.iso8601
+ end
+
+ def timestamp
+ @date.to_time.tv_sec
+ end
+
+ class << self
+ def [](date)
+ @days ||= Hash.new {|hash, date| hash[date] = new(date) }
+ @days[date]
+ end
+
+ def all
+ @days.values
+ end
+ end
+ end
+end
@@ -0,0 +1,13 @@
+module Enumerable
+ def each_pair
+ rest = self
+ while rest.any?
+ yield(*rest.take(2))
+ rest = rest.drop(2)
+ end
+ end
+
+ def paired
+ Enumerator.new(self, :each_pair)
+ end
+end

0 comments on commit a1a5f29

Please sign in to comment.