Pratt 1.6.8-x86-linux
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/.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
|