timetrackr 0.1.4 → 0.1.5

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.
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source 'http://rubygems.org'
2
2
 
3
3
  group :development do
4
4
  gem 'sqlite3'
5
+ gem 'json'
5
6
  gem 'shoulda', '>= 0'
6
7
  gem 'bundler', '~> 1.0.0'
7
8
  gem 'jeweler', '~> 1.5.2'
data/Gemfile.lock CHANGED
@@ -6,6 +6,7 @@ GEM
6
6
  bundler (~> 1.0.0)
7
7
  git (>= 1.2.5)
8
8
  rake
9
+ json (1.5.1)
9
10
  rake (0.8.7)
10
11
  rcov (0.9.9)
11
12
  shoulda (2.11.3)
@@ -17,6 +18,7 @@ PLATFORMS
17
18
  DEPENDENCIES
18
19
  bundler (~> 1.0.0)
19
20
  jeweler (~> 1.5.2)
21
+ json
20
22
  rcov
21
23
  shoulda
22
24
  sqlite3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.5
data/bin/timetrackr CHANGED
@@ -1,168 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: utf-8
2
3
 
3
4
  lib_dir = File.dirname(__FILE__) + '/../lib'
4
5
  $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
5
6
 
6
7
  require 'timetrackr'
8
+ require 'timetrackr/cli'
7
9
 
8
- DEFAULTS = {
9
- 'backend' => 'yaml',
10
- 'verbose' => false,
11
- 'single_task' => false,
12
- 'path' => File.join(ENV['HOME'],'.timetrackr.db'),
13
- 'relative_format' => "%2<hours>dh %2<minutes>dm %2<seconds>ds",
14
- 'absolute_time' => "%H:%M",
15
- 'absolute_day' => "%Y-%m-%d"
16
- }
17
-
18
- def show_help
19
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
20
- puts "timetrackr version #{version}"
21
- puts <<HELP
22
-
23
- timetrackr [command] [options]
24
-
25
- Available commands:
26
-
27
- start [task] start a task
28
- stop [task] stop a task (or 'all')
29
- switch TASK switch tasks
30
- time [task] show time for a task (or 'all')
31
- log [task] show time log for a task (or 'all')
32
-
33
- Global options
34
- -h --help show this help
35
- -v --verbose be noisy
36
- HELP
37
- end
38
-
39
- def format_time(time, fmt_str)
40
- hours = time.to_i/3600.to_i
41
- minutes = (time/60 - hours * 60).to_i
42
- seconds = (time - (minutes * 60 + hours * 3600))
43
- format(fmt_str,{
44
- :hours => hours,
45
- :minutes => minutes,
46
- :seconds => seconds})
47
- end
48
-
49
- config = {}
50
- config_file = File.join(ENV['HOME'],'.timetrackrrc')
51
- if File.exist?(config_file)
52
- require 'yaml'
53
- config = YAML.load_file(config_file)
54
- end
55
-
56
- # global options
57
- while (cmd = ARGV.shift) && cmd.start_with?('-')
58
- if ['-v','--verbose'].include? cmd
59
- config['verbose'] = true
60
- end
61
- if ['-h','--help'].include? cmd
62
- show_help
63
- exit 1
64
- end
65
- end
66
-
67
- config = DEFAULTS.merge(config || {})
68
- $verbose = config['verbose']
69
- trackr = TimeTrackr.create(config['backend'], config)
70
-
71
- #
72
- # commands
73
- #
74
- case cmd
75
- when 'start','in','s'
76
- task = ARGV.shift
77
- notes = ARGV.join(' ')
78
- # switch tasks if config says so
79
- if config['single_task'] && trackr.current != task
80
- trackr.current.each { |t|
81
- trackr.stop(t) unless t == task
82
- }
83
- puts "Switched to task '#{task}'" if $verbose
84
- else
85
- puts "Started task '#{task}'" if $verbose
86
- end
87
- trackr.start(task, notes)
88
-
89
- when 'stop','out','kill','k'
90
- if ARGV[0] == 'all' || ARGV[0].nil?
91
- tasks = trackr.tasks
92
- else
93
- tasks = ARGV
94
- end
95
- tasks.each do |task|
96
- trackr.stop(task)
97
- puts "Stopped task '#{task}'" if $verbose
98
- end
99
-
100
- when 'switch','sw'
101
- task = ARGV.shift
102
- notes = ARGV.join(' ')
103
- trackr.current.each do |t|
104
- trackr.stop(t) unless t == task
105
- end
106
- trackr.start(task, notes)
107
- puts "Switched to task '#{task}'" if $verbose
108
-
109
- when 'time','status',nil
110
- task = ARGV.shift
111
- if task && trackr.tasks.include?(task)
112
- tasks = [*task]
113
- else
114
- tasks = trackr.tasks.each
115
- end
116
- tasks.each do |task|
117
- total = trackr.history(task).reduce(0){ |t, period|
118
- t = t + period.length
119
- }
120
- name = trackr.current.include?(task) ? task+' *' : task
121
- puts name.ljust(15) << format_time(total,config['relative_format'])
122
- end
123
-
124
- when 'log'
125
- if ARGV[0] == 'all' || ARGV[0].nil?
126
- tasks = trackr.tasks
127
- else
128
- tasks = ARGV
129
- end
130
- table = []
131
- periods = tasks.each.collect{ |t| trackr.history(t) }.flatten
132
- lastday = nil
133
- table << periods.sort{|x,y| x.start <=> y.start}.collect{ |period|
134
- currday = period.start.strftime(config['absolute_day'])
135
- day = (currday == lastday) ? ' ' : currday
136
- lastday = currday
137
- name = period.current? ? period.task+' *' : period.task
138
- start = period.start.strftime(config['absolute_time'])
139
- stop = period.current? ? ' ' : period.stop.strftime(config['absolute_time'])
140
- length = format_time(period.length, config['relative_format'])
141
- notes = period.notes
142
- "#{day.ljust(12)} #{name.ljust(15)} #{start} - #{stop.ljust(5)} #{length} #{notes}"
143
- }
144
- puts table
145
-
146
-
147
- when 'clear','delete','del'
148
- tasks = ARGV
149
- tasks = trackr.tasks if task == 'all'
150
- tasks.each do |task|
151
- trackr.clear(task)
152
- puts "Task '#{task}' cleared" if $verbose
153
- end
154
-
155
- when 'rename','mv'
156
- from = ARGV.shift
157
- to = ARGV.shift
158
- trackr.rename(from,to)
159
- puts "Renamed '#{from}' to '#{to}'" if $verbose
160
-
161
- else
162
- puts "'#{cmd}' is not a valid command"
163
- show_help
164
- end
165
-
166
- trackr.close
10
+ TimeTrackr::CLI.run(ARGV)
167
11
 
168
12
  # vim: set ts=2 sw=2 tw=80 ft=ruby fdm=syntax et fen :
@@ -0,0 +1,180 @@
1
+ module TimeTrackr
2
+ class CLI
3
+ DEFAULTS = {
4
+ 'backend' => 'yaml',
5
+ 'verbose' => false,
6
+ 'single_task' => false,
7
+ 'path' => File.join(ENV['HOME'],'.timetrackr.db'),
8
+ 'relative_format' => "%2<hours>dh %2<minutes>dm %2<seconds>ds",
9
+ 'absolute_time' => "%H:%M",
10
+ 'absolute_day' => "%Y-%m-%d"
11
+ }
12
+
13
+ #
14
+ # static method to get config file and run the tracker
15
+ #
16
+ def self.run(args)
17
+ config = {}
18
+ config_file = File.join(ENV['HOME'],'.timetrackrrc')
19
+ if File.exist?(config_file)
20
+ require 'yaml'
21
+ config = YAML.load_file(config_file)
22
+ end
23
+
24
+ # global options
25
+ while (cmd = args.shift) && cmd.start_with?('-')
26
+ if ['-v','--verbose'].include? cmd
27
+ config['verbose'] = true
28
+ end
29
+ if ['-h','--help'].include? cmd
30
+ cmd = 'help'
31
+ end
32
+ end
33
+ config = DEFAULTS.merge(config || {})
34
+
35
+ cli = TimeTrackr::CLI.new(config)
36
+ cli.run(cmd, args)
37
+ end
38
+
39
+ def initialize(config)
40
+ @config = config
41
+ @verbose = config['verbose']
42
+ @trackr = TimeTrackr::Database.create(config['backend'], config)
43
+ end
44
+
45
+ #
46
+ # run a command on the tracker
47
+ #
48
+ def run(cmd,args)
49
+ case cmd
50
+ when 'start','in','s'
51
+ task = args.shift
52
+ notes = args.join(' ')
53
+ # switch tasks if config says so
54
+ if @config['single_task'] && @trackr.current != task
55
+ @trackr.current.each { |t|
56
+ @trackr.stop(t) unless t == task
57
+ }
58
+ puts "Switched to task '#{task}'" if @verbose
59
+ else
60
+ puts "Started task '#{task}'" if @verbose
61
+ end
62
+ @trackr.start(task, notes)
63
+
64
+ when 'stop','out','kill','k'
65
+ if args[0] == 'all' || args[0].nil?
66
+ tasks = @trackr.tasks
67
+ else
68
+ tasks = args
69
+ end
70
+ tasks.each do |task|
71
+ @trackr.stop(task)
72
+ puts "Stopped task '#{task}'" if @verbose
73
+ end
74
+
75
+ when 'switch','sw'
76
+ task = args.shift
77
+ notes = args.join(' ')
78
+ @trackr.current.each do |t|
79
+ @trackr.stop(t) unless t == task
80
+ end
81
+ @trackr.start(task, notes)
82
+ puts "Switched to task '#{task}'" if @verbose
83
+
84
+ when 'time','status',nil
85
+ task = args.shift
86
+ if task && @trackr.tasks.include?(task)
87
+ tasks = [*task]
88
+ else
89
+ tasks = @trackr.tasks.each
90
+ end
91
+ tasks.each do |task|
92
+ total = @trackr.history(task).reduce(0){ |t, period|
93
+ t = t + period.length
94
+ }
95
+ name = @trackr.current.include?(task) ? task+' *' : task
96
+ puts name.ljust(15) << format_time(total,@config['relative_format'])
97
+ end
98
+
99
+ when 'log'
100
+ if args[0] == 'all' || args[0].nil?
101
+ tasks = @trackr.tasks
102
+ else
103
+ tasks = args
104
+ end
105
+ table = []
106
+ periods = tasks.each.collect{ |t| @trackr.history(t) }.flatten
107
+ lastday = nil
108
+ table << periods.sort{|x,y| x.start <=> y.start}.collect{ |period|
109
+ currday = period.start.strftime(@config['absolute_day'])
110
+ day = (currday == lastday) ? ' ' : currday
111
+ lastday = currday
112
+ name = period.current? ? period.task+' *' : period.task
113
+ start = period.start.strftime(@config['absolute_time'])
114
+ stop = period.current? ? ' ' : period.stop.strftime(@config['absolute_time'])
115
+ length = format_time(period.length, @config['relative_format'])
116
+ notes = period.notes
117
+ "#{day.ljust(12)} #{name.ljust(15)} #{start} - #{stop.ljust(5)} #{length} #{notes}"
118
+ }
119
+ puts table
120
+
121
+
122
+ when 'clear','delete','del'
123
+ tasks = args
124
+ tasks = @trackr.tasks if task == 'all'
125
+ tasks.each do |task|
126
+ @trackr.clear(task)
127
+ puts "Task '#{task}' cleared" if @verbose
128
+ end
129
+
130
+ when 'rename','mv'
131
+ from = args.shift
132
+ to = args.shift
133
+ @trackr.rename(from,to)
134
+ puts "Renamed '#{from}' to '#{to}'" if @verbose
135
+
136
+ when 'help'
137
+ show_help
138
+
139
+ else
140
+ puts "'#{cmd}' is not a valid command"
141
+ show_help
142
+ end
143
+
144
+ @trackr.close
145
+ end
146
+
147
+ protected
148
+
149
+ def format_time(time, fmt_str)
150
+ hours = time.to_i/3600.to_i
151
+ minutes = (time/60 - hours * 60).to_i
152
+ seconds = (time - (minutes * 60 + hours * 3600))
153
+ format(fmt_str,{
154
+ :hours => hours,
155
+ :minutes => minutes,
156
+ :seconds => seconds})
157
+ end
158
+
159
+ def show_help
160
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
161
+ puts "timetrackr version #{version}"
162
+ puts <<HELP
163
+
164
+ timetrackr [command] [options]
165
+
166
+ Available commands:
167
+
168
+ start [task] start a task
169
+ stop [task] stop a task (or 'all')
170
+ switch TASK switch tasks
171
+ time [task] show time for a task (or 'all')
172
+ log [task] show time log for a task (or 'all')
173
+
174
+ Global options
175
+ -h --help show this help
176
+ -v --verbose be noisy
177
+ HELP
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,103 @@
1
+
2
+ module TimeTrackr
3
+ class Database
4
+ def self.create(type, options={})
5
+ case type.to_s
6
+ when 'yaml'
7
+ begin
8
+ require 'yaml'
9
+ db = TimeTrackr::YamlDatabase.new(options['path'])
10
+ puts 'Loaded YAML tracker' if options['verbose']
11
+ rescue LoadError
12
+ puts 'YAML not found'
13
+ end
14
+
15
+ when 'sqlite'
16
+ begin
17
+ require 'sqlite3'
18
+ db = TimeTrackr::SqliteDatabase.new(options['path'])
19
+ puts 'Loaded sqlite tracker' if options['verbose']
20
+ rescue LoadError
21
+ puts 'Sqlite not found'
22
+ end
23
+
24
+ when 'json'
25
+ begin
26
+ require 'json'
27
+ db = TimeTrackr::JsonDatabase.new(options['path'])
28
+ puts 'Loaded JSON database' if options['verbose']
29
+ rescue LoadError
30
+ puts 'JSON not found'
31
+ end
32
+
33
+ else
34
+ raise "Bad log type: #{type}"
35
+ end
36
+ db
37
+ end
38
+
39
+ #
40
+ # return an array of current tasks
41
+ #
42
+ def current
43
+ raise 'Not Implemented'
44
+ end
45
+
46
+ #
47
+ # start a period with optional notes
48
+ #
49
+ def start(task,notes)
50
+ raise 'Not implemented'
51
+ end
52
+
53
+ #
54
+ # stop a period
55
+ #
56
+ def stop(task)
57
+ raise 'Not implemented'
58
+ end
59
+
60
+ #
61
+ # return an array of all tasks
62
+ #
63
+ def tasks
64
+ raise 'Not Implemented'
65
+ end
66
+
67
+ #
68
+ # time in task in seconds
69
+ #
70
+ def time(task)
71
+ raise 'Not implemented'
72
+ end
73
+
74
+ #
75
+ # get task history as an array of Periods
76
+ #
77
+ def history(task)
78
+ raise 'Not Implemented'
79
+ end
80
+
81
+ #
82
+ # rename a task
83
+ #
84
+ def rename(from, to)
85
+ raise 'Not implemented'
86
+ end
87
+
88
+ #
89
+ # clear an task
90
+ #
91
+ def clear(task)
92
+ raise 'Not Implemented'
93
+ end
94
+
95
+ #
96
+ # cleanup and close
97
+ #
98
+ def close
99
+ end
100
+
101
+ end
102
+ end
103
+
@@ -0,0 +1,68 @@
1
+ module TimeTrackr
2
+ class JsonDatabase < TimeTrackr::Database
3
+
4
+ def initialize(path)
5
+ @log_path = path
6
+ if !File.exist? @log_path
7
+ @db = {'current' => [], 'tasks' => {}}
8
+ write_file
9
+ end
10
+ File.open(@log_path,'r') do |fh|
11
+ @db = JSON.load(fh)
12
+ end
13
+ end
14
+
15
+ def current
16
+ @db['current']
17
+ end
18
+
19
+ def tasks
20
+ @db['tasks'].keys.compact.uniq || []
21
+ end
22
+
23
+ def start(task, notes)
24
+ @db['tasks'][task] = Array[] unless @db['tasks'][task]
25
+ if !@db['current'].include?(task)
26
+ @db['current'].unshift(task)
27
+ @db['tasks'][task].push({'start' => Time.now, 'notes' => notes})
28
+ end
29
+ end
30
+
31
+ def stop(task)
32
+ if @db['current'].include?(task)
33
+ @db['current'].delete(task)
34
+ @db['tasks'][task].last['stop'] = Time.now
35
+ end
36
+ end
37
+
38
+ def history(task, p_begin=nil, p_end=nil)
39
+ @db['tasks'][task].sort{|x,y| x['start'] <=> y['start']}.collect {|p|
40
+ Period.new(task,p['start'],p['stop'],p['notes'])
41
+ } unless !@db['tasks'].include? task
42
+ end
43
+
44
+ def rename(from, to)
45
+ @db['tasks'][to] = @db['tasks'].delete(from)
46
+ if @db['current'].delete(from)
47
+ @db['current'].unshift(to)
48
+ end
49
+ end
50
+
51
+ def close
52
+ write_file
53
+ end
54
+
55
+ def clear(task)
56
+ @db['current'].delete(task)
57
+ @db['tasks'].delete(task)
58
+ end
59
+
60
+ private
61
+
62
+ def write_file
63
+ File.open(@log_path,'w') do |fh|
64
+ JSON.dump(@db,fh)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -9,13 +9,22 @@ class Period
9
9
  @notes = notes
10
10
  end
11
11
 
12
+ def start
13
+ @start.class == Time ? @start : Time.parse(@start)
14
+ end
15
+
16
+ def stop
17
+ return nil if @stop.nil?
18
+ @stop.class == Time ? @stop : Time.parse(@stop)
19
+ end
20
+
12
21
  def length
13
- stop = @stop || Time.now
14
- stop - @start
22
+ stop = self.stop || Time.now
23
+ stop - self.start
15
24
  end
16
25
 
17
26
  def current?
18
- @stop.nil?
27
+ self.stop.nil?
19
28
  end
20
29
 
21
30
  end
@@ -1,70 +1,71 @@
1
- class SqliteTimeTrackr < TimeTrackr
1
+ module TimeTrackr
2
+ class SqliteDatabase < TimeTrackr::Database
2
3
 
3
- def initialize(path)
4
- @log_path = path
5
- if !File.exist? @log_path
6
- @db = SQLite3::Database.new(@log_path)
7
- sql_events = "CREATE TABLE events (
4
+ def initialize(path)
5
+ @log_path = path
6
+ if !File.exist? @log_path
7
+ @db = SQLite3::Database.new(@log_path)
8
+ sql_events = "CREATE TABLE events (
8
9
  id INTEGER PRIMARY KEY,
9
10
  task TEXT,
10
11
  start TIME,
11
12
  stop TIME,
12
13
  notes TEXT);"
13
14
  @db.execute(sql_events)
14
- else
15
- @db = SQLite3::Database.open(@log_path)
15
+ else
16
+ @db = SQLite3::Database.open(@log_path)
17
+ end
18
+ @db.type_translation = true
16
19
  end
17
- @db.type_translation = true
18
- puts "Using DB file '#{@log_path}'" if $verbose
19
- end
20
20
 
21
- def current
22
- sql = "SELECT DISTINCT task FROM events WHERE stop IS NULL;"
23
- @db.execute(sql).collect{|row|
24
- row.first
25
- }
26
- end
21
+ def current
22
+ sql = "SELECT DISTINCT task FROM events WHERE stop IS NULL;"
23
+ @db.execute(sql).collect{|row|
24
+ row.first
25
+ }
26
+ end
27
27
 
28
- def tasks
29
- sql = "SELECT DISTINCT task FROM events;"
30
- @db.execute(sql).collect{ |row|
31
- row.first
32
- }
33
- end
28
+ def tasks
29
+ sql = "SELECT DISTINCT task FROM events;"
30
+ @db.execute(sql).collect{ |row|
31
+ row.first
32
+ }
33
+ end
34
34
 
35
- def start(task, notes)
36
- sql = "SELECT id FROM events WHERE task = :task AND stop IS NULL;"
37
- exists = @db.get_first_value(sql, 'task' => task)
38
- if !exists
39
- sql = "INSERT INTO events (task,start,notes) VALUES (:task,:start,:notes);"
40
- @db.execute(sql,'task' => task, 'start' => Time.now.to_s, 'notes' => notes)
35
+ def start(task, notes)
36
+ sql = "SELECT id FROM events WHERE task = :task AND stop IS NULL;"
37
+ exists = @db.get_first_value(sql, 'task' => task)
38
+ if !exists
39
+ sql = "INSERT INTO events (task,start,notes) VALUES (:task,:start,:notes);"
40
+ @db.execute(sql,'task' => task, 'start' => Time.now.to_s, 'notes' => notes)
41
+ end
41
42
  end
42
- end
43
43
 
44
- def stop(task)
45
- sql = "SELECT id FROM events WHERE task = :task AND stop IS NULL;"
46
- exists = @db.get_first_value(sql, 'task' => task)
47
- if exists
48
- sql = "UPDATE events SET stop = :stop WHERE id = :current;"
49
- @db.execute(sql, 'current' => exists, 'stop' => Time.now.to_s)
44
+ def stop(task)
45
+ sql = "SELECT id FROM events WHERE task = :task AND stop IS NULL;"
46
+ exists = @db.get_first_value(sql, 'task' => task)
47
+ if exists
48
+ sql = "UPDATE events SET stop = :stop WHERE id = :current;"
49
+ @db.execute(sql, 'current' => exists, 'stop' => Time.now.to_s)
50
+ end
50
51
  end
51
- end
52
52
 
53
- def history(task, p_begin=nil, p_end=nil)
54
- sql = "SELECT start, stop, notes FROM events WHERE task = :task ORDER BY start;"
55
- @db.execute(sql,'task' => task).collect{ |row|
56
- Period.new(task,row[0],row[1],row[2])
57
- }
58
- end
53
+ def history(task, p_begin=nil, p_end=nil)
54
+ sql = "SELECT start, stop, notes FROM events WHERE task = :task ORDER BY start;"
55
+ @db.execute(sql,'task' => task).collect{ |row|
56
+ Period.new(task,row[0],row[1],row[2])
57
+ }
58
+ end
59
59
 
60
- def rename(from, to)
61
- sql = "UPDATE events SET task = :to WHERE task = :from;"
62
- @db.execute(sql, 'to' => to, 'from' => from)
63
- end
60
+ def rename(from, to)
61
+ sql = "UPDATE events SET task = :to WHERE task = :from;"
62
+ @db.execute(sql, 'to' => to, 'from' => from)
63
+ end
64
64
 
65
- def clear(task)
66
- sql = "DELETE FROM events WHERE task = :task;"
67
- @db.execute(sql, 'task' => task)
68
- end
65
+ def clear(task)
66
+ sql = "DELETE FROM events WHERE task = :task;"
67
+ @db.execute(sql, 'task' => task)
68
+ end
69
69
 
70
+ end
70
71
  end
@@ -10,68 +10,69 @@
10
10
  # :notes: "blah blah blah"
11
11
  #
12
12
 
13
- class YamlTimeTrackr < TimeTrackr
13
+ module TimeTrackr
14
+ class YamlDatabase < TimeTrackr::Database
14
15
 
15
- def initialize(path)
16
- @log_path = path
17
- if !File.exist? @log_path
18
- @db = {:current => [], :tasks => {}}
19
- write_file
16
+ def initialize(path)
17
+ @log_path = path
18
+ if !File.exist? @log_path
19
+ @db = {:current => [], :tasks => {}}
20
+ write_file
21
+ end
22
+ @db = YAML.load_file(@log_path)
20
23
  end
21
- @db = YAML.load_file(@log_path)
22
- puts "Using log file '#{@log_path}'" if $verbose
23
- end
24
24
 
25
- def current
26
- @db[:current]
27
- end
25
+ def current
26
+ @db[:current]
27
+ end
28
28
 
29
- def tasks
30
- @db[:tasks].keys.compact.uniq || []
31
- end
29
+ def tasks
30
+ @db[:tasks].keys.compact.uniq || []
31
+ end
32
32
 
33
- def start(task, notes)
34
- @db[:tasks][task] = Array[] unless @db[:tasks][task]
35
- if !@db[:current].include?(task)
36
- @db[:current].unshift(task)
37
- @db[:tasks][task].push({:start => Time.now, :notes => notes})
33
+ def start(task, notes)
34
+ @db[:tasks][task] = Array[] unless @db[:tasks][task]
35
+ if !@db[:current].include?(task)
36
+ @db[:current].unshift(task)
37
+ @db[:tasks][task].push({:start => Time.now, :notes => notes})
38
+ end
38
39
  end
39
- end
40
40
 
41
- def stop(task)
42
- if @db[:current].include?(task)
43
- @db[:current].delete(task)
44
- @db[:tasks][task].last[:stop] = Time.now
41
+ def stop(task)
42
+ if @db[:current].include?(task)
43
+ @db[:current].delete(task)
44
+ @db[:tasks][task].last[:stop] = Time.now
45
+ end
45
46
  end
46
- end
47
47
 
48
- def history(task, p_begin=nil, p_end=nil)
49
- @db[:tasks][task].sort{|x,y| x[:start] <=> y[:start]}.collect {|p|
50
- Period.new(task,p[:start],p[:stop],p[:notes])
51
- } unless !@db[:tasks].include? task
52
- end
48
+ def history(task, p_begin=nil, p_end=nil)
49
+ @db[:tasks][task].sort{|x,y| x[:start] <=> y[:start]}.collect {|p|
50
+ Period.new(task,p[:start],p[:stop],p[:notes])
51
+ } unless !@db[:tasks].include? task
52
+ end
53
53
 
54
- def rename(from, to)
55
- @db[:tasks][to] = @db[:tasks].delete(from)
56
- if @db[:current].delete(from)
57
- @db[:current].unshift(to)
54
+ def rename(from, to)
55
+ @db[:tasks][to] = @db[:tasks].delete(from)
56
+ if @db[:current].delete(from)
57
+ @db[:current].unshift(to)
58
+ end
58
59
  end
59
- end
60
60
 
61
- def close
62
- write_file
63
- end
61
+ def close
62
+ write_file
63
+ end
64
64
 
65
- def clear(task)
66
- @db[:current].delete(task)
67
- @db[:tasks].delete(task)
68
- end
65
+ def clear(task)
66
+ @db[:current].delete(task)
67
+ @db[:tasks].delete(task)
68
+ end
69
69
 
70
- private
70
+ private
71
71
 
72
- def write_file
73
- File.open(@log_path,'w') do |fh|
74
- YAML.dump(@db,fh)
72
+ def write_file
73
+ File.open(@log_path,'w') do |fh|
74
+ YAML.dump(@db,fh)
75
+ end
75
76
  end
76
77
  end
77
78
  end
data/lib/timetrackr.rb CHANGED
@@ -1,92 +1,10 @@
1
- autoload 'YamlTimeTrackr', 'timetrackr/yaml'
2
- autoload 'SqliteTimeTrackr', 'timetrackr/sqlite'
3
- autoload 'Period', 'timetrackr/period'
1
+ module TimeTrackr
4
2
 
5
- class TimeTrackr
6
- def self.create(type, options={})
7
- case type.to_s
8
- when 'yaml'
9
- begin
10
- require 'yaml'
11
- log = YamlTimeTrackr.new(options['path'])
12
- puts 'Loaded yaml tracker' if $verbose
13
- rescue LoadError
14
- puts 'Yaml not found'
15
- end
16
- when 'sqlite'
17
- begin
18
- require 'sqlite3'
19
- log = SqliteTimeTrackr.new(options['path'])
20
- puts 'Loaded sqlite tracker' if $verbose
21
- rescue LoadError
22
- puts 'Sqlite not found'
23
- end
24
- else
25
- raise "Bad log type: #{type}"
26
- end
27
- log
28
- end
29
-
30
- #
31
- # return an array of current tasks
32
- #
33
- def current
34
- raise 'Not Implemented'
35
- end
36
-
37
- #
38
- # start a period with optional notes
39
- #
40
- def start(task,notes)
41
- raise 'Not implemented'
42
- end
43
-
44
- #
45
- # stop a period
46
- #
47
- def stop(task)
48
- raise 'Not implemented'
49
- end
50
-
51
- #
52
- # return an array of all tasks
53
- #
54
- def tasks
55
- raise 'Not Implemented'
56
- end
57
-
58
- #
59
- # time in task in seconds
60
- #
61
- def time(task)
62
- end
63
-
64
- #
65
- # get task history as an array of Periods
66
- #
67
- def history(task)
68
- raise 'Not Implemented'
69
- end
70
-
71
- #
72
- # rename a task
73
- #
74
- def rename(from, to)
75
- raise 'Not implemented'
76
- end
77
-
78
- #
79
- # clear an task
80
- #
81
- def clear(task)
82
- raise 'Not Implemented'
83
- end
84
-
85
- #
86
- # cleanup and close
87
- #
88
- def close
89
- end
3
+ require 'time'
4
+ require 'timetrackr/database'
5
+ require 'timetrackr/period'
90
6
 
7
+ autoload 'YamlDatabase', 'timetrackr/yaml'
8
+ autoload 'SqliteDatabase', 'timetrackr/sqlite'
9
+ autoload 'JsonDatabase', 'timetrackr/json'
91
10
  end
92
-
data/timetrackr.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{timetrackr}
8
- s.version = "0.1.4"
8
+ s.version = "0.1.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Felix Hanley"]
12
- s.date = %q{2011-05-19}
12
+ s.date = %q{2011-05-23}
13
13
  s.default_executable = %q{timetrackr}
14
14
  s.description = %q{A simple time tracking utility}
15
15
  s.email = %q{felix@seconddrawer.com.au}
@@ -27,6 +27,9 @@ Gem::Specification.new do |s|
27
27
  "VERSION",
28
28
  "bin/timetrackr",
29
29
  "lib/timetrackr.rb",
30
+ "lib/timetrackr/cli.rb",
31
+ "lib/timetrackr/database.rb",
32
+ "lib/timetrackr/json.rb",
30
33
  "lib/timetrackr/period.rb",
31
34
  "lib/timetrackr/sqlite.rb",
32
35
  "lib/timetrackr/yaml.rb",
@@ -49,12 +52,14 @@ Gem::Specification.new do |s|
49
52
 
50
53
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
54
  s.add_development_dependency(%q<sqlite3>, [">= 0"])
55
+ s.add_development_dependency(%q<json>, [">= 0"])
52
56
  s.add_development_dependency(%q<shoulda>, [">= 0"])
53
57
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
54
58
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
55
59
  s.add_development_dependency(%q<rcov>, [">= 0"])
56
60
  else
57
61
  s.add_dependency(%q<sqlite3>, [">= 0"])
62
+ s.add_dependency(%q<json>, [">= 0"])
58
63
  s.add_dependency(%q<shoulda>, [">= 0"])
59
64
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
60
65
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
@@ -62,6 +67,7 @@ Gem::Specification.new do |s|
62
67
  end
63
68
  else
64
69
  s.add_dependency(%q<sqlite3>, [">= 0"])
70
+ s.add_dependency(%q<json>, [">= 0"])
65
71
  s.add_dependency(%q<shoulda>, [">= 0"])
66
72
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
67
73
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: timetrackr
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.4
5
+ version: 0.1.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Felix Hanley
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-19 00:00:00 +07:00
13
+ date: 2011-05-23 00:00:00 +07:00
14
14
  default_executable: timetrackr
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -25,7 +25,7 @@ dependencies:
25
25
  prerelease: false
26
26
  version_requirements: *id001
27
27
  - !ruby/object:Gem::Dependency
28
- name: shoulda
28
+ name: json
29
29
  requirement: &id002 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
@@ -36,8 +36,19 @@ dependencies:
36
36
  prerelease: false
37
37
  version_requirements: *id002
38
38
  - !ruby/object:Gem::Dependency
39
- name: bundler
39
+ name: shoulda
40
40
  requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: bundler
51
+ requirement: &id004 !ruby/object:Gem::Requirement
41
52
  none: false
42
53
  requirements:
43
54
  - - ~>
@@ -45,10 +56,10 @@ dependencies:
45
56
  version: 1.0.0
46
57
  type: :development
47
58
  prerelease: false
48
- version_requirements: *id003
59
+ version_requirements: *id004
49
60
  - !ruby/object:Gem::Dependency
50
61
  name: jeweler
51
- requirement: &id004 !ruby/object:Gem::Requirement
62
+ requirement: &id005 !ruby/object:Gem::Requirement
52
63
  none: false
53
64
  requirements:
54
65
  - - ~>
@@ -56,10 +67,10 @@ dependencies:
56
67
  version: 1.5.2
57
68
  type: :development
58
69
  prerelease: false
59
- version_requirements: *id004
70
+ version_requirements: *id005
60
71
  - !ruby/object:Gem::Dependency
61
72
  name: rcov
62
- requirement: &id005 !ruby/object:Gem::Requirement
73
+ requirement: &id006 !ruby/object:Gem::Requirement
63
74
  none: false
64
75
  requirements:
65
76
  - - ">="
@@ -67,7 +78,7 @@ dependencies:
67
78
  version: "0"
68
79
  type: :development
69
80
  prerelease: false
70
- version_requirements: *id005
81
+ version_requirements: *id006
71
82
  description: A simple time tracking utility
72
83
  email: felix@seconddrawer.com.au
73
84
  executables:
@@ -86,6 +97,9 @@ files:
86
97
  - VERSION
87
98
  - bin/timetrackr
88
99
  - lib/timetrackr.rb
100
+ - lib/timetrackr/cli.rb
101
+ - lib/timetrackr/database.rb
102
+ - lib/timetrackr/json.rb
89
103
  - lib/timetrackr/period.rb
90
104
  - lib/timetrackr/sqlite.rb
91
105
  - lib/timetrackr/yaml.rb
@@ -106,7 +120,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
120
  requirements:
107
121
  - - ">="
108
122
  - !ruby/object:Gem::Version
109
- hash: 317875573549099611
123
+ hash: -2538018453800347300
110
124
  segments:
111
125
  - 0
112
126
  version: "0"