Pratt 1.6.8-x86-linux
Sign up to get free protection for your applications and to get access to all the features.
- data/.exrc +61 -0
- data/.gitignore +6 -0
- data/History.txt +6 -0
- data/Manifest.txt +46 -0
- data/Pratt.gemspec +173 -0
- data/Pratt.mm +1867 -0
- data/README.txt +67 -0
- data/Rakefile +96 -0
- data/TODO +56 -0
- data/VERSION +1 -0
- data/bin/pratt +13 -0
- data/config.rb +19 -0
- data/db/sqlite_databases_go_here +0 -0
- data/db/zips.csv.zip +0 -0
- data/lib/models.rb +8 -0
- data/lib/pratt.rb +308 -0
- data/lib/pratt/core_ext.rb +6 -0
- data/lib/pratt/core_ext/array.rb +20 -0
- data/lib/pratt/core_ext/float.rb +29 -0
- data/lib/pratt/core_ext/nil.rb +5 -0
- data/lib/pratt/core_ext/numeric.rb +9 -0
- data/lib/pratt/core_ext/string.rb +31 -0
- data/lib/pratt/core_ext/time.rb +20 -0
- data/lib/pratt/dialogs.rb +81 -0
- data/lib/pratt/formatting.rb +19 -0
- data/lib/pratt/project_actions.rb +25 -0
- data/lib/pratt/reports.rb +140 -0
- data/models/app.rb +39 -0
- data/models/customer.rb +50 -0
- data/models/invoice.rb +28 -0
- data/models/invoice_whence.rb +18 -0
- data/models/payment.rb +22 -0
- data/models/pratt.rb +15 -0
- data/models/project.rb +89 -0
- data/models/whence.rb +77 -0
- data/models/zip.rb +27 -0
- data/pratt.mm +1875 -0
- data/spec/app_spec.rb +48 -0
- data/spec/array_spec.rb +24 -0
- data/spec/customer_spec.rb +31 -0
- data/spec/fixtures/empty_graph.expectation +8 -0
- data/spec/fixtures/graph.expectation +13 -0
- data/spec/fixtures/proportions.expectation +4 -0
- data/spec/float_spec.rb +24 -0
- data/spec/formatting_spec.rb +7 -0
- data/spec/money_spec.rb +9 -0
- data/spec/nil_class_spec.rb +8 -0
- data/spec/numeric_spec.rb +30 -0
- data/spec/payment_spec.rb +19 -0
- data/spec/pratt_spec.rb +106 -0
- data/spec/project_spec.rb +182 -0
- data/spec/rcov.opts +0 -0
- data/spec/report_action_spec.rb +83 -0
- data/spec/report_spec.rb +205 -0
- data/spec/seed_data.rb +33 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/string_ext_spec.rb +33 -0
- data/spec/whence_spec.rb +54 -0
- data/tasks/pratt.rb +87 -0
- data/templates/model.eruby +12 -0
- data/templates/spec.eruby +8 -0
- data/views/current.eruby +5 -0
- data/views/general-invoice.eruby +538 -0
- data/views/graph.eruby +16 -0
- data/views/invoice.eruby +148 -0
- data/views/main.rb +90 -0
- data/views/pid.eruby +3 -0
- data/views/pop.rb +78 -0
- data/views/proportions.eruby +4 -0
- data/views/raw.eruby +11 -0
- metadata +275 -0
data/README.txt
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
= pratt
|
2
|
+
|
3
|
+
* Pratt (url)
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Pratt (Pro/Re)-Active Time Tracker
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
(list of features or problems)
|
12
|
+
* Currently you'll need to manually fix the project data since I haven't
|
13
|
+
fully integrated the support for Projects to have a Customer.
|
14
|
+
* Upgrading versions looses your database. (See TODO)
|
15
|
+
* Windows doesn't work (no fork). (See TODO)
|
16
|
+
|
17
|
+
|
18
|
+
== SYNOPSIS:
|
19
|
+
|
20
|
+
* pratt (code sample of usage)
|
21
|
+
|
22
|
+
** PRATT_ENV=production pratt -D # daemonize (or if already daemonized init the
|
23
|
+
gui)
|
24
|
+
** pratt -h (as you'd expect lists available commands)
|
25
|
+
|
26
|
+
== REQUIREMENTS:
|
27
|
+
|
28
|
+
* pratt
|
29
|
+
debian: libtcltk-ruby tk-tile libsqlite3-dev
|
30
|
+
gems: activerecord sqlite3-ruby rspec mocha
|
31
|
+
tk: http://sourceforge.net/project/showfiles.php?group_id=11464&package_id=107795&release_id=562098
|
32
|
+
|
33
|
+
== INSTALL:
|
34
|
+
|
35
|
+
* sudo gem install
|
36
|
+
|
37
|
+
Credits
|
38
|
+
|
39
|
+
Michael Goff
|
40
|
+
Thanks for helping me with some of the workflow details
|
41
|
+
Michael and Kent Krenrich
|
42
|
+
Thanks for the UI input, suggestions, and testing.
|
43
|
+
|
44
|
+
== LICENSE:
|
45
|
+
|
46
|
+
(The MIT License)
|
47
|
+
|
48
|
+
Copyright (c) 2009 Frogstarr78 Software
|
49
|
+
|
50
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
51
|
+
a copy of this software and associated documentation files (the
|
52
|
+
'Software'), to deal in the Software without restriction, including
|
53
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
54
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
55
|
+
permit persons to whom the Software is furnished to do so, subject to
|
56
|
+
the following conditions:
|
57
|
+
|
58
|
+
The above copyright notice and this permission notice shall be
|
59
|
+
included in all copies or substantial portions of the Software.
|
60
|
+
|
61
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
62
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
63
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
64
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
65
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
66
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
67
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require 'lib/pratt'
|
6
|
+
require 'tasks/pratt'
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'jeweler'
|
12
|
+
Jeweler::Tasks.new do |gem|
|
13
|
+
gem.rubyforge_project = Pratt::NAME
|
14
|
+
gem.name = Pratt::NAME
|
15
|
+
gem.summary = Pratt::SUMMARY
|
16
|
+
gem.description = Pratt::DESCRIPTION
|
17
|
+
gem.email = "frogstarr78@gmail.com"
|
18
|
+
gem.homepage = "http://github.com/frogstarr78/pratt"
|
19
|
+
gem.authors = Pratt::AUTHORS
|
20
|
+
gem.add_development_dependency 'rspec', '>=1.2.6'
|
21
|
+
gem.add_development_dependency 'mocha', '>=0.9.5'
|
22
|
+
gem.add_runtime_dependency 'activerecord', '>=2.1.1'
|
23
|
+
gem.add_runtime_dependency 'sqlite3-ruby', '=1.2.4'
|
24
|
+
gem.add_runtime_dependency 'shifty_week', '>=0.1.0'
|
25
|
+
gem.add_runtime_dependency 'erubis', '=2.6.5'
|
26
|
+
gem.add_runtime_dependency 'chronic', '=0.2.3'
|
27
|
+
gem.add_runtime_dependency 'colored', '=1.2'
|
28
|
+
gem.platform = 'current'
|
29
|
+
gem.test_files = FileList['spec/**/*.{rb,opts}', 'spec/fixtures/*.expectation']
|
30
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
31
|
+
end
|
32
|
+
Jeweler::GemcutterTasks.new
|
33
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
34
|
+
rubyforge.doc_task = "rdoc"
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
38
|
+
end
|
39
|
+
|
40
|
+
require 'spec/rake/spectask'
|
41
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
42
|
+
spec.libs << 'lib' << 'spec'
|
43
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
44
|
+
end
|
45
|
+
|
46
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
47
|
+
spec.libs << 'lib' << 'spec'
|
48
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
49
|
+
spec.rcov = true
|
50
|
+
spec.rcov_opts = %w(--text-report --exclude=activerecord,ruby-debug,shifty_week,sqlite3-ruby,rspec,mocha,erubis,chronic,colored,columnize,builder,activesupport,i18n,linecache,json_pure,rcov,abstract,spec_helper.rb,config.rb,spec)
|
51
|
+
end
|
52
|
+
|
53
|
+
task :spec => :check_dependencies
|
54
|
+
|
55
|
+
begin
|
56
|
+
require 'reek/adapters/rake_task'
|
57
|
+
Reek::RakeTask.new do |t|
|
58
|
+
t.fail_on_error = true
|
59
|
+
t.verbose = false
|
60
|
+
t.source_files = 'lib/**/*.rb'
|
61
|
+
end
|
62
|
+
rescue LoadError
|
63
|
+
task :reek do
|
64
|
+
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
begin
|
69
|
+
require 'roodi'
|
70
|
+
require 'roodi_task'
|
71
|
+
RoodiTask.new do |t|
|
72
|
+
t.verbose = false
|
73
|
+
end
|
74
|
+
rescue LoadError
|
75
|
+
task :roodi do
|
76
|
+
abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
task :default => :spec
|
81
|
+
|
82
|
+
require 'rake/rdoctask'
|
83
|
+
Rake::RDocTask.new do |rdoc|
|
84
|
+
if File.exist?('VERSION')
|
85
|
+
version = File.read('VERSION')
|
86
|
+
else
|
87
|
+
version = ""
|
88
|
+
end
|
89
|
+
|
90
|
+
rdoc.rdoc_dir = 'rdoc'
|
91
|
+
rdoc.title = "pratt #{version}"
|
92
|
+
rdoc.rdoc_files.include('README*')
|
93
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
94
|
+
end
|
95
|
+
|
96
|
+
# vim: syntax=ruby
|
data/TODO
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
General:
|
2
|
+
[ ] Remove environment ability
|
3
|
+
[ ] Change to use raw command line arguments / Remove optparse lib
|
4
|
+
[ ] Update general package setup (It's messy)
|
5
|
+
[?] Add file watching like merb
|
6
|
+
[?] Move to Observer Pattern for reporting functionality
|
7
|
+
|
8
|
+
Invoicing:
|
9
|
+
[x] Add shifty week plugin
|
10
|
+
[ ] Add support for variable rates.
|
11
|
+
|
12
|
+
Templating:
|
13
|
+
[ ] Invoices
|
14
|
+
[x] Move other output to template based
|
15
|
+
|
16
|
+
Data:
|
17
|
+
[?] Change to Use DataMapper
|
18
|
+
[?] Put everything in the db? (logs, app locks, etc)
|
19
|
+
[ ] Move database location to central location that doesn't dissappear when upgrading the app.
|
20
|
+
|
21
|
+
GUI:
|
22
|
+
[ ] Add TrayIcon.
|
23
|
+
[ ] Customer CRUD
|
24
|
+
[ ] Payment CRUD
|
25
|
+
[ ] Re-design prompts
|
26
|
+
[ ] Remove fork in favor of ( eval OR (!?!) GUI classes )
|
27
|
+
[ ] Don't assume gui.
|
28
|
+
|
29
|
+
Test:
|
30
|
+
[ ] Add more I'm not testing everything
|
31
|
+
[ ] Flog
|
32
|
+
[ ] Flay
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
Done:
|
37
|
+
[x] Whence.last should be last unended.
|
38
|
+
[x] Add date range argument to timed report.
|
39
|
+
[x] Add validation for start/end at.
|
40
|
+
[x] Manual data manipulation date/time.
|
41
|
+
[x] Change pop prompt to show helpful time.
|
42
|
+
[x] Change Start/Continue interface.
|
43
|
+
[x] Add directoryless agnostic runner.
|
44
|
+
[x] Log output.
|
45
|
+
[x] Add Quiet option??
|
46
|
+
[x] Allow only one prompt at a time.
|
47
|
+
[x] Handle stop when there isn't a running project w/out errors
|
48
|
+
[x] fix gui so if last_unended is detected app knows which gui to display
|
49
|
+
[x] Intelligently detect correctly running stored pid.
|
50
|
+
[x] Fix pid directory access.
|
51
|
+
|
52
|
+
[x] Add support for Customer's model
|
53
|
+
[x] Add Template command
|
54
|
+
[x] Add Invoice command
|
55
|
+
[x] Fix colorability
|
56
|
+
[x] Add console command
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.6.8
|
data/bin/pratt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
bin_file = __FILE__
|
5
|
+
bin_file = File.symlink?(bin_file) ? File.readlink(bin_file) : bin_file
|
6
|
+
|
7
|
+
bin_path = File.expand_path( '..', bin_file )
|
8
|
+
pratt_dir = File.dirname( bin_path )
|
9
|
+
FileUtils.chdir pratt_dir
|
10
|
+
|
11
|
+
require "lib/pratt"
|
12
|
+
|
13
|
+
Pratt.parse(ARGV)
|
data/config.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
PRATT_ENV = ENV["PRATT_ENV"] || 'development' unless Object.const_defined? :PRATT_ENV
|
2
|
+
|
3
|
+
class Pratt
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def connect! to_env = :development
|
8
|
+
connect_to = "db/#{to_env}.sqlite3"
|
9
|
+
ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => connect_to )
|
10
|
+
unless File.exists? connect_to
|
11
|
+
Pratt.migrate
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def connected?
|
16
|
+
ActiveRecord::Base.connected?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
File without changes
|
data/db/zips.csv.zip
ADDED
Binary file
|
data/lib/models.rb
ADDED
data/lib/pratt.rb
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'fileutils'
|
3
|
+
require 'optparse'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'colored'
|
8
|
+
require 'chronic'
|
9
|
+
require 'active_record'
|
10
|
+
require 'erubis'
|
11
|
+
require 'config'
|
12
|
+
require 'shifty_week'
|
13
|
+
require 'shifty_week/time'
|
14
|
+
require 'shifty_week/date'
|
15
|
+
|
16
|
+
require 'lib/pratt/formatting'
|
17
|
+
require 'lib/pratt/core_ext'
|
18
|
+
require 'lib/pratt/dialogs'
|
19
|
+
require 'lib/pratt/project_actions'
|
20
|
+
require 'lib/pratt/reports'
|
21
|
+
require 'lib/models'
|
22
|
+
|
23
|
+
|
24
|
+
class Pratt
|
25
|
+
|
26
|
+
NAME = 'Pratt'
|
27
|
+
URL = 'http://www.frogstarr78.com/projects/pratt'
|
28
|
+
AUTHORS = ['Scott Noel-Hemming']
|
29
|
+
SUMMARY = "Pro/Re-Active Time Tracker. Track time based on what you expect to be working on, with frequent prompts to ensure accuracy."
|
30
|
+
DESCRIPTION = %q|
|
31
|
+
Need a way to keep track of your time, but get caught up in work? Or constant interruptions?
|
32
|
+
Yeah you know who I'm talking about. Those people from the [abc] department always "NEEDING xyz FEATURE NOW!!!".
|
33
|
+
Seriously though. I'm usually just loose track of time. I wanted an app that I could start with a task I think
|
34
|
+
I'll be working on, but that get's in my face constantly to ensure I'm still working on it. And if I'm not any longer,
|
35
|
+
provides an easy way of changing to another task, or if I have changed tasks and not already updated the app, would
|
36
|
+
provide an easy way of changing the task of the previously recorded interval. That's what this is intended to do.
|
37
|
+
|
38
|
+
Time Tracking.
|
39
|
+
Proactively set what you expect to work on.
|
40
|
+
Reactively modify what you are no longer working on.
|
41
|
+
|
|
42
|
+
DEPENDENCIES = ["activerecord >=2.1.1", "sqlite3-ruby >=1.2.4", "rspec >=1.2.6", "mocha >=0.9.5"]
|
43
|
+
VERSION = File.open( File.join(Dir.pwd, 'VERSION') ).read.strip
|
44
|
+
|
45
|
+
PID_FILE='pratt.pid'
|
46
|
+
FMT = "%a %X %b %d %Y"
|
47
|
+
INVOICE_FMT = "%x"
|
48
|
+
|
49
|
+
attr_accessor :when_to, :scale, :color, :show_all, :raw_conditions, :template, :week_day_start
|
50
|
+
attr_reader :project, :todo
|
51
|
+
def initialize proj = nil
|
52
|
+
@when_to = DateTime.now
|
53
|
+
@week = false
|
54
|
+
@day = false
|
55
|
+
@todo = []
|
56
|
+
@scale = nil
|
57
|
+
@show_all = false
|
58
|
+
@template = nil
|
59
|
+
@raw_conditions = ''
|
60
|
+
self.project = proj unless proj.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
# Set the project to something (Project/String)
|
64
|
+
# Conditionally creating a new project if the project
|
65
|
+
# named by the parameter isn't found
|
66
|
+
def project= proj
|
67
|
+
if proj.is_a?(Project)
|
68
|
+
@project = proj
|
69
|
+
else
|
70
|
+
@project = Project.find_or_create_by_name( { :name => proj } )
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# We should act like an array
|
75
|
+
def << what
|
76
|
+
@todo << what
|
77
|
+
end
|
78
|
+
|
79
|
+
# Connect to the database in irb for manual commands/investigation
|
80
|
+
def console
|
81
|
+
require 'irb'
|
82
|
+
require 'irb/completion'
|
83
|
+
ARGV.clear
|
84
|
+
IRB.start
|
85
|
+
end
|
86
|
+
|
87
|
+
# Stop everything and kill daemonized processes.
|
88
|
+
def quit
|
89
|
+
project.stop! if project? and project.whences.last_unended
|
90
|
+
Whence.last_unended.stop! if Whence.last_unended
|
91
|
+
begin
|
92
|
+
Process.kill("KILL", app.pid.to_i)
|
93
|
+
rescue Errno::ESRCH
|
94
|
+
puts "Unable to kill Pratt@pid(#{app.pid})."
|
95
|
+
end
|
96
|
+
app.pid = ''
|
97
|
+
app.gui = ''
|
98
|
+
app.save!
|
99
|
+
end
|
100
|
+
|
101
|
+
# Singleton Accessor for @app
|
102
|
+
def app
|
103
|
+
@app ||= App.last
|
104
|
+
@app
|
105
|
+
end
|
106
|
+
|
107
|
+
# "Unlock" the gui.
|
108
|
+
def unlock
|
109
|
+
self.app.unlock
|
110
|
+
end
|
111
|
+
|
112
|
+
def run
|
113
|
+
# ensure we've shifted the when_to value to the
|
114
|
+
# current start of week
|
115
|
+
self.when_to.week_day_start = self.week_day_start
|
116
|
+
|
117
|
+
# << order is semi important
|
118
|
+
self.end if i_should? :end
|
119
|
+
self.begin if i_should? :begin
|
120
|
+
self.change if i_should? :change
|
121
|
+
self.restart if i_should? :restart
|
122
|
+
|
123
|
+
self.destroy if i_should? :destroy
|
124
|
+
# end order is semi important
|
125
|
+
|
126
|
+
# << order doesn't matter within this set
|
127
|
+
self.pid if i_should? :pid
|
128
|
+
self.raw if i_should? :raw
|
129
|
+
self.current if i_should? :current
|
130
|
+
self.graph if i_should? :graph
|
131
|
+
self.proportions if i_should? :proportions
|
132
|
+
self.invoice if i_should? :invoice
|
133
|
+
self.console if i_should? :console
|
134
|
+
self.gui if i_should? :gui
|
135
|
+
self.detect if i_should? :detect
|
136
|
+
self.unlock if i_should? :unlock
|
137
|
+
# end order doesn't matter within this set
|
138
|
+
|
139
|
+
# << these should happen last
|
140
|
+
self.quit if i_should? :quit
|
141
|
+
self.daemonize! if i_should? :daemonize and not self.daemonized?
|
142
|
+
# end these should happen last
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
def i_should? what
|
147
|
+
@todo.include?(what)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Is there a project that can be operated on?
|
151
|
+
def project?
|
152
|
+
!@project.nil? and @project.name?
|
153
|
+
end
|
154
|
+
|
155
|
+
class << self
|
156
|
+
|
157
|
+
# Parse cli arguments and init Pratt
|
158
|
+
def parse args
|
159
|
+
me = Pratt.new
|
160
|
+
|
161
|
+
# There are aa few things we're parsing here
|
162
|
+
# Pratt config arguments (Ideally that should be all we do)
|
163
|
+
# Pratt actions. These may require ordering or not. They also may require an argument value.
|
164
|
+
#
|
165
|
+
# TODO: Redo the cli parsing...
|
166
|
+
# In some cases we require arguments to be run in a certain order, but we don't want some to be run concurrently w/ others.
|
167
|
+
# Sometimes it may be unexpected but helpful to allow that behavior.
|
168
|
+
opt = OptionParser.new do |opt|
|
169
|
+
Pratt.connect! ENV['PRATT_ENV'] || 'development' unless Pratt.connected?
|
170
|
+
|
171
|
+
# Actionable options
|
172
|
+
opt.on('-b', "--begin", String, "Begin project tracking.") do
|
173
|
+
me << :begin
|
174
|
+
end
|
175
|
+
opt.on('-r', "--restart", String, "Restart project log (stop last log and start a new one).
|
176
|
+
Applies to last un-ended project, unless a specific project is provided.") do
|
177
|
+
me << :restart
|
178
|
+
end
|
179
|
+
opt.on('-e', "--end", String, "Stop tracking interval for last project or supplied project if provided.") do
|
180
|
+
me << :end
|
181
|
+
end
|
182
|
+
opt.on('-c', "--change", String, "Change last time interval to this project.") do
|
183
|
+
me << :change
|
184
|
+
end
|
185
|
+
opt.on('-g', "--graph", String, "Display time spent on supplied project or all projects without argument value.") do
|
186
|
+
me << :graph
|
187
|
+
end
|
188
|
+
opt.on('-I', "--invoice", "Create an invoice.") do
|
189
|
+
me << :invoice
|
190
|
+
end
|
191
|
+
opt.on('-r', '--proportions', "") do
|
192
|
+
me << :proportions
|
193
|
+
end
|
194
|
+
opt.on('-p', '--pid', "Process id display. (Is it still running)") do
|
195
|
+
me << :pid
|
196
|
+
end
|
197
|
+
opt.on('-R', '--raw [CONDITIONS]', "Dump logs (semi-)raw") do |conditions|
|
198
|
+
me << :raw
|
199
|
+
me.raw_conditions = conditions
|
200
|
+
end
|
201
|
+
opt.on('-C', "--current", "Show available projects and current project (if there is one)") do
|
202
|
+
me << :current
|
203
|
+
end
|
204
|
+
opt.on("-d", "--daemonize", "Start daemon.") do
|
205
|
+
me << :daemonize
|
206
|
+
end
|
207
|
+
opt.on('-D', '--detect', 'Detect appropriate behavior. (Daemonize or Graphical).') do
|
208
|
+
me << :detect
|
209
|
+
end
|
210
|
+
opt.on('-G', '--gui', 'Show "smart" gui.') do
|
211
|
+
me << :gui
|
212
|
+
end
|
213
|
+
opt.on('-q', "--quit", "Stop daemon.") do
|
214
|
+
me << :quit
|
215
|
+
end
|
216
|
+
opt.on('-U', '--unlock', "Manually unlock a gui that has died but left it's lock around.") do
|
217
|
+
me << :unlock
|
218
|
+
end
|
219
|
+
opt.on '-V', '--version' do
|
220
|
+
puts "Pro-Reactive Time Tracker [Pratt] (#{VERSION})"
|
221
|
+
end
|
222
|
+
opt.on('--destroy', String, "Remove a project.") do
|
223
|
+
me << :destroy
|
224
|
+
end
|
225
|
+
|
226
|
+
# Strictly configuration options
|
227
|
+
project_names = Project.all.collect(&:name)
|
228
|
+
colored_project_names = project_names.collect{|name|
|
229
|
+
" #{name.cyan}"}
|
230
|
+
opt.on('-P', "--project PROJECT_NAME", project_names, "Set project.
|
231
|
+
Available projects are:\n#{colored_project_names*"\n"}") do |proj|
|
232
|
+
me.project = proj
|
233
|
+
end
|
234
|
+
|
235
|
+
templates = []
|
236
|
+
Pratt.root("views", "*.eruby") {|view| templates << File.basename(view, '.eruby') }
|
237
|
+
opt.on('-t', "--template TEMPLATE", templates, "Template to use for displaying work done.
|
238
|
+
Available templates are #{templates.to_sentence('or')}.") do |template|
|
239
|
+
me.template = template
|
240
|
+
end
|
241
|
+
opt.on '-w', '--when_to TIME', String, 'When to do something.
|
242
|
+
(e.g. log time start|stop, or what time interval to graph)
|
243
|
+
If graphing, silently ignored w/out scale argument.' do |when_to|
|
244
|
+
me.when_to = Chronic.parse(when_to).to_datetime
|
245
|
+
end
|
246
|
+
scales = %w(day week month quarter year)
|
247
|
+
opt.on('-l', '--scale SCALE', scales, "Granularity of time argument
|
248
|
+
Available scales are #{scales.to_sentence('or')}.
|
249
|
+
Only applies to graphing.") do |scale|
|
250
|
+
me.scale = scale
|
251
|
+
end
|
252
|
+
opt.on('-L', '--log', "Redirect errors") do
|
253
|
+
FileUtils.mkdir 'log' unless File.exists? 'log'
|
254
|
+
$stderr.reopen('log/pratt.log', 'a')
|
255
|
+
$stderr.sync = true
|
256
|
+
end
|
257
|
+
opt.on('-N', '--no-color', "Display output without color or special characters.") do
|
258
|
+
Pratt.color = false
|
259
|
+
end
|
260
|
+
opt.on('-A', '--show-all', "Display all project regardless of other options.") do
|
261
|
+
me.show_all = true
|
262
|
+
end
|
263
|
+
opt.on '-s', '--start-day WEEK_DAY_START', String, "" do |wday_start|
|
264
|
+
me.week_day_start = wday_start
|
265
|
+
end
|
266
|
+
opt.on('-i', "--interval INTERVAL", Float, "Set the remind interval/min (Only applies to daemonized process).") do |interval|
|
267
|
+
me.app.interval = interval
|
268
|
+
me.app.save
|
269
|
+
end
|
270
|
+
|
271
|
+
opt.parse!
|
272
|
+
end
|
273
|
+
|
274
|
+
me << :console if args.include? 'console'
|
275
|
+
|
276
|
+
me.run
|
277
|
+
end
|
278
|
+
|
279
|
+
# Where is Pratt installed.
|
280
|
+
# We've already chdir'd to it's base dir in the bin file
|
281
|
+
def root *globs, &block
|
282
|
+
root = Dir.pwd
|
283
|
+
if globs.empty?
|
284
|
+
subdir = root
|
285
|
+
else
|
286
|
+
subdir = File.join(root, *globs)
|
287
|
+
end
|
288
|
+
|
289
|
+
if block_given?
|
290
|
+
Pathname.glob(subdir) {|dir_files| yield dir_files }
|
291
|
+
else
|
292
|
+
Pathname.glob(subdir)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Migrate schema.
|
297
|
+
def migrate
|
298
|
+
Pratt.root( 'models', '*.rb' ) do |model_file|
|
299
|
+
klass = File.basename( model_file, '.rb' ).classify.constantize
|
300
|
+
begin
|
301
|
+
ActiveRecord::Base.connection.table_structure(model_file)
|
302
|
+
rescue ActiveRecord::StatementInvalid
|
303
|
+
klass.migrate :up if klass.superclass == ActiveRecord::Base
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|