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.
Files changed (72) hide show
  1. data/.exrc +61 -0
  2. data/.gitignore +6 -0
  3. data/History.txt +6 -0
  4. data/Manifest.txt +46 -0
  5. data/Pratt.gemspec +173 -0
  6. data/Pratt.mm +1867 -0
  7. data/README.txt +67 -0
  8. data/Rakefile +96 -0
  9. data/TODO +56 -0
  10. data/VERSION +1 -0
  11. data/bin/pratt +13 -0
  12. data/config.rb +19 -0
  13. data/db/sqlite_databases_go_here +0 -0
  14. data/db/zips.csv.zip +0 -0
  15. data/lib/models.rb +8 -0
  16. data/lib/pratt.rb +308 -0
  17. data/lib/pratt/core_ext.rb +6 -0
  18. data/lib/pratt/core_ext/array.rb +20 -0
  19. data/lib/pratt/core_ext/float.rb +29 -0
  20. data/lib/pratt/core_ext/nil.rb +5 -0
  21. data/lib/pratt/core_ext/numeric.rb +9 -0
  22. data/lib/pratt/core_ext/string.rb +31 -0
  23. data/lib/pratt/core_ext/time.rb +20 -0
  24. data/lib/pratt/dialogs.rb +81 -0
  25. data/lib/pratt/formatting.rb +19 -0
  26. data/lib/pratt/project_actions.rb +25 -0
  27. data/lib/pratt/reports.rb +140 -0
  28. data/models/app.rb +39 -0
  29. data/models/customer.rb +50 -0
  30. data/models/invoice.rb +28 -0
  31. data/models/invoice_whence.rb +18 -0
  32. data/models/payment.rb +22 -0
  33. data/models/pratt.rb +15 -0
  34. data/models/project.rb +89 -0
  35. data/models/whence.rb +77 -0
  36. data/models/zip.rb +27 -0
  37. data/pratt.mm +1875 -0
  38. data/spec/app_spec.rb +48 -0
  39. data/spec/array_spec.rb +24 -0
  40. data/spec/customer_spec.rb +31 -0
  41. data/spec/fixtures/empty_graph.expectation +8 -0
  42. data/spec/fixtures/graph.expectation +13 -0
  43. data/spec/fixtures/proportions.expectation +4 -0
  44. data/spec/float_spec.rb +24 -0
  45. data/spec/formatting_spec.rb +7 -0
  46. data/spec/money_spec.rb +9 -0
  47. data/spec/nil_class_spec.rb +8 -0
  48. data/spec/numeric_spec.rb +30 -0
  49. data/spec/payment_spec.rb +19 -0
  50. data/spec/pratt_spec.rb +106 -0
  51. data/spec/project_spec.rb +182 -0
  52. data/spec/rcov.opts +0 -0
  53. data/spec/report_action_spec.rb +83 -0
  54. data/spec/report_spec.rb +205 -0
  55. data/spec/seed_data.rb +33 -0
  56. data/spec/spec.opts +1 -0
  57. data/spec/spec_helper.rb +24 -0
  58. data/spec/string_ext_spec.rb +33 -0
  59. data/spec/whence_spec.rb +54 -0
  60. data/tasks/pratt.rb +87 -0
  61. data/templates/model.eruby +12 -0
  62. data/templates/spec.eruby +8 -0
  63. data/views/current.eruby +5 -0
  64. data/views/general-invoice.eruby +538 -0
  65. data/views/graph.eruby +16 -0
  66. data/views/invoice.eruby +148 -0
  67. data/views/main.rb +90 -0
  68. data/views/pid.eruby +3 -0
  69. data/views/pop.rb +78 -0
  70. data/views/proportions.eruby +4 -0
  71. data/views/raw.eruby +11 -0
  72. metadata +275 -0
File without changes
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+ require 'pratt'
3
+
4
+ describe "Pratt report actions" do
5
+ include SeedData
6
+
7
+ before :each do
8
+ @pratt = Pratt.new
9
+ @when_to = DateTime.now
10
+ load_seed_data
11
+ end
12
+
13
+ after :each do
14
+ Whence.delete_all
15
+ end
16
+
17
+ it "calls project#start! in begin method" do
18
+ @pratt.project = Project.primary
19
+ @pratt.when_to = @when_to
20
+ @pratt.project.expects(:start!).with @when_to
21
+ @pratt.begin
22
+ end
23
+
24
+ it "calls project#restart! in restart method with defined project" do
25
+ @next_when_to = @when_to + 7.minutes
26
+ primary = Project.primary
27
+ primary.start! @when_to
28
+ @pratt.project = primary
29
+ @pratt.when_to = @next_when_to
30
+ whence = primary.whences.last
31
+ Whence.expects(:last_unended).never
32
+ primary.expects(:restart!).with @next_when_to
33
+ @pratt.restart
34
+ end
35
+
36
+ it "calls last unended project in restart method without defined project" do
37
+ @next_when_to = @when_to + 7.minutes
38
+ primary = Project.primary
39
+ primary.start! @when_to
40
+ @pratt.when_to = @next_when_to
41
+ whence = primary.whences.last
42
+ Whence.expects(:last_unended).returns whence
43
+ whence.project.expects(:restart!).with @next_when_to
44
+ @pratt.restart
45
+ whence.project.should eql(primary)
46
+ end
47
+
48
+ it "stops! defined project in end method" do
49
+ @pratt.project = Project.primary
50
+ @pratt.when_to = @when_to
51
+ @pratt.project.expects(:stop!).with @when_to
52
+ @pratt.end
53
+ end
54
+
55
+ it "stops! the last unended project in end method without defined project" do
56
+ primary = Project.primary
57
+ primary.start! @when_to
58
+ whence = primary.whences.last
59
+ Whence.expects(:last_unended).returns whence
60
+ whence.expects(:stop!).with @when_to
61
+ @pratt.when_to = @when_to
62
+ @pratt.end
63
+ end
64
+
65
+ it "changes last project in change method" do
66
+ primary = Project.primary
67
+ primary.start! @when_to
68
+ primary.stop! @when_to+10.minutes
69
+ other = Project.rest.first
70
+ whence = primary.whences.last
71
+ Whence.expects(:last).returns whence
72
+ whence.expects(:change!).with other.name
73
+ @pratt.project = other
74
+ @pratt.change
75
+ end
76
+
77
+ it "destroys defined project in destroy method" do
78
+ @pratt.project = Project.create :name => "to be destroyed"
79
+ lambda {
80
+ @pratt.destroy
81
+ }.should change(Project, :count).by -1
82
+ end
83
+ end
@@ -0,0 +1,205 @@
1
+ require 'spec_helper'
2
+ require 'pratt'
3
+
4
+ describe "Pratt report method" do
5
+
6
+ describe "#pid" do
7
+ @pratt = Pratt.new
8
+ @pratt.expects(:template=).with("pid")
9
+ @pratt.expects(:process_template!)
10
+ @pratt.pid
11
+ end
12
+
13
+ # FIXME: Get this working
14
+ describe "#cpid" #do
15
+ # @pratt = Pratt.new
16
+ # ::Kernel.expects(:`)
17
+ # @pratt.cpid
18
+ # end
19
+
20
+ describe "#graph" do
21
+ before :each do
22
+ @pratt = Pratt.new
23
+ end
24
+
25
+ it "with no project uses Project.all to generate output" do
26
+ @pratt.expects(:template=).with("graph")
27
+ @pratt.expects(:project?).returns false
28
+ Project.expects(:all).returns([])
29
+ @pratt.expects(:process_template!)
30
+ @pratt.graph
31
+ end
32
+
33
+ it "with project uses defined project to generate output" do
34
+ @pratt.project = Project.new
35
+ @pratt.expects(:template=).with("graph")
36
+ @pratt.expects(:project?).returns true
37
+ @pratt.expects(:process_template!)
38
+ @pratt.graph
39
+ @pratt.instance_variable_get("@projects").should eql([@pratt.project])
40
+ end
41
+ end
42
+
43
+ describe "output" do
44
+ include SeedData
45
+
46
+ before :each do
47
+ @pratt = Pratt.new
48
+ end
49
+ before :each do
50
+ @when_to = Chronic.parse('September 29 2009').beginning_of_week
51
+ @pratt.scale = 'week'
52
+ @pratt.when_to = @when_to
53
+ @customer = Customer.create :name => 'Bob Hope', :address => '123 Where St', :zip => '22222'
54
+ @tasks = []
55
+ end
56
+
57
+ after :each do
58
+ Whence.delete_all
59
+ @customer.destroy
60
+ @tasks.each(&:destroy)
61
+ end
62
+
63
+ def get_expected_display fixture_name
64
+ Pratt.root('spec', 'fixtures', "#{fixture_name}.expectation").first.read
65
+ end
66
+
67
+ it "graphs output as expected with no data" do
68
+ Pratt.color = false
69
+ Project.stubs(:longest_project_name).returns 12
70
+ Project.stubs(:all).returns([])
71
+ $stdout.expects(:puts)
72
+ @pratt.graph
73
+ @pratt.send(:output).should eql( get_expected_display("empty_graph") )
74
+ end
75
+
76
+ it "graphs output as expected with data" do
77
+ populate_with_data
78
+ Pratt.color = false
79
+ Project.stubs(:longest_project_name).returns 12
80
+ $stdout.expects(:puts)
81
+
82
+ @pratt.graph
83
+ @pratt.send(:output).should eql( get_expected_display("graph") )
84
+ end
85
+
86
+ it "generates proportions graphs output as expected with data" do
87
+ populate_with_data
88
+ Pratt.color = false
89
+ Project.stubs(:longest_project_name).returns 12
90
+ $stdout.expects(:puts)
91
+
92
+ @pratt.proportions
93
+ @pratt.send(:output).should eql( get_expected_display("proportions") )
94
+ end
95
+
96
+ def task name, time_spent
97
+ task = Project.find_or_create_by_name :name => name, :customer => @customer
98
+ task.start! @when_to
99
+ task.stop! @when_to+time_spent
100
+ @tasks << task
101
+ end
102
+
103
+ def populate_with_data
104
+ load_seed_data
105
+ @tasks << Project.primary
106
+ task 'Lunch/Break', 1.hour+21.minutes+0.seconds
107
+ task 'Task1', 1.hour+4.minutes+0.seconds
108
+ task 'Task2', 58.minutes+0.seconds
109
+ task 'Another Task', 5.minutes+0.seconds
110
+ task 'Task3', 1.day+17.hours+32.minutes+0.seconds
111
+ end
112
+ end
113
+
114
+ describe "#proportions" do
115
+ include SeedData
116
+
117
+ before :each do
118
+ @pratt = Pratt.new
119
+ end
120
+ before :each do
121
+ @when_to = Chronic.parse('last week').beginning_of_week
122
+ @pratt.scale = 'week'
123
+ @pratt.when_to = @when_to
124
+ @customer = Customer.create :name => 'Bob Hope', :address => '123 Where St', :zip => '22222'
125
+ @tasks = []
126
+ end
127
+
128
+ after :each do
129
+ Whence.delete_all
130
+ @customer.destroy
131
+ @tasks.each(&:destroy)
132
+ end
133
+
134
+ def task name, time_spent
135
+ task = Project.find_or_create_by_name :name => name, :customer => @customer, :weight => -1
136
+ task.start! @when_to
137
+ task.stop! @when_to+time_spent
138
+ @tasks << task
139
+ end
140
+
141
+ def populate_with_data
142
+ load_seed_data
143
+ primary = Project.primary
144
+ primary.start! @when_to
145
+ primary.stop! @when_to+20.hours
146
+ @tasks << primary
147
+ task 'Lunch/Break', 1.hour+21.minutes
148
+ task 'Task1', 1.hour+4.minutes
149
+ task 'Task2', 58.minutes
150
+ task 'Another Task', 5.minutes
151
+ task 'Task3', 1.day+17.hours+32.minutes
152
+ end
153
+
154
+ it "uses Project.all with data to generate output" do
155
+ populate_with_data
156
+ @pratt.expects(:template=).with("proportions")
157
+ @pratt.expects(:project?).returns false
158
+ @pratt.expects(:process_template!)
159
+ @pratt.proportions
160
+ @pratt.instance_variable_get("@primary").should eql(20.0)
161
+ @pratt.instance_variable_get("@off_total").should eql(1.35)
162
+ @pratt.instance_variable_get("@rest_total").should eql(43.65)
163
+ @pratt.instance_variable_get("@projects").should eql(Project.all)
164
+ @pratt.instance_variable_get("@scaled_total").should eql(63.65)
165
+ end
166
+
167
+ it "uses defined project with data to generate output" do
168
+ populate_with_data
169
+ @pratt.expects(:template=).with("proportions")
170
+ @pratt.expects(:project?).returns true
171
+ @pratt.project = Project.named('Task1')
172
+ @pratt.expects(:process_template!)
173
+ @pratt.proportions
174
+ @pratt.instance_variable_get("@primary").should eql(64/60.0)
175
+ @pratt.instance_variable_get("@off_total").should eql(0.0)
176
+ @pratt.instance_variable_get("@rest_total").should eql(0.0)
177
+ @pratt.instance_variable_get("@projects").should eql([@pratt.project])
178
+ @pratt.instance_variable_get("@scaled_total").should eql(64/60.0)
179
+ end
180
+
181
+ it "uses Project.all with no data to generate output" do
182
+ @pratt.expects(:template=).with("proportions")
183
+ @pratt.expects(:project?).returns false
184
+ Project.expects(:all).returns []
185
+ @pratt.expects(:process_template!).never
186
+ $stdout.expects(:puts).with "No data to report"
187
+ @pratt.proportions
188
+ end
189
+
190
+ it "uses defined project with no with data to generate output" do
191
+ @pratt.expects(:template=).with("proportions")
192
+ @pratt.expects(:project?).returns true
193
+ @pratt.project = Project.new
194
+ @pratt.project.expects(:time_spent).twice.returns 0.0
195
+ @pratt.expects(:process_template!).never
196
+ $stdout.expects(:puts).with "No data to report"
197
+ @pratt.proportions
198
+ @pratt.instance_variable_get("@primary").should eql(0.0)
199
+ @pratt.instance_variable_get("@off_total").should eql(0.0)
200
+ @pratt.instance_variable_get("@rest_total").should eql(0.0)
201
+ @pratt.instance_variable_get("@projects").should eql([@pratt.project])
202
+ @pratt.instance_variable_get("@scaled_total").should eql(0.0)
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,33 @@
1
+ module SeedData
2
+ def load_seed_data
3
+ Customer.delete_all
4
+ customer = Customer.create(
5
+ :name => 'Scott Noel-Hemming',
6
+ :company_name => 'Frogstarr78 Software',
7
+ :address => '312 NW 7th',
8
+ :phone => '509.730.5401',
9
+ :zip => '97862'
10
+ )
11
+
12
+ Project.delete_all
13
+ Project.create(
14
+ [
15
+ {
16
+ :name => 'Refactor',
17
+ :weight => 1,
18
+ :customer => customer
19
+ },
20
+ {
21
+ :name => 'Lunch/Break',
22
+ :weight => 0,
23
+ :customer => customer
24
+ },
25
+ {
26
+ :name => 'Other',
27
+ :weight => -1,
28
+ :customer => customer
29
+ }
30
+ ]
31
+ )
32
+ end
33
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,24 @@
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'mocha'
6
+ require 'lib/pratt'
7
+ require 'ruby-debug'
8
+ require 'seed_data'
9
+
10
+ Spec::Runner.configure do |config|
11
+ # config.mock_with :rspec
12
+ config.mock_with :mocha
13
+
14
+ Pratt.connect! 'test'
15
+ end
16
+
17
+ shared_examples_for "Time spent on a project" do
18
+ end
19
+
20
+ shared_examples_for "being a billable item" do
21
+ it "responds to amount" do
22
+ subject.class.new.should respond_to(:amount)
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'pratt'
3
+
4
+ describe String do
5
+ it { subject.should respond_to(:colorize) }
6
+ it { subject.should respond_to(:or) }
7
+ it { subject.should respond_to(:with_label) }
8
+
9
+ it "doesn't process alternate format when Pratt.color? == false" do
10
+ Pratt.color = false
11
+ "abc".or("xyz").should eql("abc")
12
+ end
13
+
14
+ it "processes alternate format when Pratt.color? == true" do
15
+ Pratt.color = true
16
+ "abc".or("xyz").should eql("xyz")
17
+ end
18
+
19
+ it "doesn't colorize when Pratt.color? == false" do
20
+ Pratt.color = false
21
+ "abc".blue.should eql("abc")
22
+ end
23
+
24
+ it "colorizes when Pratt.color? == true" do
25
+ Pratt.color = true
26
+ "abc".blue.should eql("\e[34mabc\e[0m")
27
+ end
28
+
29
+ it "handles with_label as expected" do
30
+ Project.expects(:longest_project_name).returns 11
31
+ "abc".with_label("label").should eql(" label abc")
32
+ end
33
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whence do
4
+
5
+ context "scopes" do
6
+ it "last_unended should return nil if there aren't any unended" do
7
+ Whence.expects(:first).with(:conditions => "end_at IS NULL", :order => "start_at DESC")
8
+ Whence.last_unended
9
+ end
10
+ end
11
+
12
+ context "instances" do
13
+ before :each do
14
+ @whence = Whence.new
15
+ end
16
+
17
+ it "parse a string argument to stop!" do
18
+ when_to = 'yesterday'
19
+ when_to = '2009-10-06 13:48:58'
20
+ expectation = Chronic.parse when_to
21
+
22
+ @whence.expects(:save!)
23
+ @whence.expects(:reload)
24
+ # don't work I'm not sure why
25
+ # @whence.expects(:end_at).with expectation
26
+ # Chronic.expects(:parse).with when_to
27
+
28
+ @whence.stop! when_to
29
+ @whence.end_at.should == expectation
30
+ end
31
+
32
+ it "doesn't parse a non-string thing on stop!" do
33
+ when_to = Chronic.parse 'last week'
34
+ Chronic.expects(:parse).never
35
+ @whence.expects(:save!)
36
+ @whence.expects(:reload)
37
+ @whence.stop! when_to
38
+ @whence.end_at.should == when_to
39
+ end
40
+
41
+ it "should change! to project correctly" do
42
+ project_name = 'proj'
43
+ @whence.expects(:save!)
44
+ @whence.expects(:reload)
45
+ @whence.change! project_name
46
+ @whence.project.name.should == project_name
47
+ end
48
+
49
+ it "should have a special output for start_at.to_s" do
50
+ @whence.start_at = Time.parse('Wed Oct 7 10:57:21 PDT 2009')
51
+ @whence.start_at.to_s.should eql('Wed 07 Oct 2009 10:57:21')
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,87 @@
1
+ # -*- ruby -*-
2
+
3
+ namespace :pratt do
4
+
5
+ task :establish_connection do
6
+ Pratt.connect!( ENV['PRATT_ENV'] || 'development' )
7
+ Pratt.root 'models', '*.rb' do |model|
8
+ require model
9
+ end
10
+ end
11
+
12
+ desc "DB Quick access"
13
+ namespace :db do
14
+
15
+ desc "Show App detail."
16
+ task :app => :establish_connection do
17
+ puts App.last.inspect
18
+ end
19
+
20
+ namespace :schema do
21
+ desc "Run schema file"
22
+ task :run, :file, :needs => :establish_connection do |t, args|
23
+ puts args.inspect
24
+ puts args.file.nil?
25
+ puts args.file.empty?
26
+ raise "Missing required file argument" if args.file.nil? or ( not args.file.nil? and args.file.empty? )
27
+ schema_change = File.open( args.file ).read
28
+
29
+ ActiveRecord::Schema.define do
30
+ ActiveRecord::Base.transaction do
31
+ begin
32
+ eval schema_change
33
+ rescue Exception => e
34
+ puts "There was an error:
35
+ #{e.inspect}.
36
+ Rolling back!"
37
+ raise ActiveRecord::Rollback
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ namespace :generate do
46
+ desc "Genarate model"
47
+ task :model do
48
+ raise "Missing required klass parameter" unless ENV.include? 'klass'
49
+ klass = ENV['klass'].downcase.singularize
50
+ outfile = File.join(Pratt.root('models'), "#{klass}.rb")
51
+ template = ''
52
+ Pratt.root('templates', 'model.eruby') {|model_gen| template = File.read(model_gen) }
53
+
54
+ eruby = Erubis::Eruby.new(template)
55
+ unless File.exists? outfile
56
+ File.open(outfile, 'w') {|file| file.write eruby.result(:klass => klass) }
57
+ else
58
+ puts "Model '#{klass}' already exists"
59
+ end
60
+
61
+ Rake::Task["generate:spec"].execute
62
+ end
63
+
64
+ desc "Generate spec test"
65
+ task :spec do
66
+ klass = ENV['klass'].downcase.singularize
67
+ raise "Missing required klass parameter" unless ENV.include? 'klass'
68
+
69
+ outpath = File.join(Pratt.root('spec'), "#{klass}_spec.rb")
70
+ inpath = File.join(Pratt.root('templates'), "spec.eruby")
71
+
72
+ if File.exists? outpath
73
+ puts "Spec '#{klass}' already exists"
74
+ else
75
+ File.open outpath, 'w' do |outfile|
76
+ File.open inpath do |infile|
77
+ eruby = Erubis::Eruby.new( infile.read )
78
+ outfile.write eruby.result( :klass => klass )
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ # vim: syntax=Ruby