timesheet 0.2.0
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/History.txt +4 -0
- data/Manifest.txt +24 -0
- data/README.rdoc +104 -0
- data/Rakefile +29 -0
- data/bin/timesheet +7 -0
- data/lib/timesheet.rb +82 -0
- data/lib/timesheet/range_extensions.rb +24 -0
- data/lib/timesheet/time_entry.rb +50 -0
- data/lib/timesheet/time_log.rb +71 -0
- data/lib/timesheet/time_report.rb +113 -0
- data/lib/timesheet/timesheet_parser.rb +242 -0
- data/lib/timesheet/trollop.rb +761 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/range_extensions_spec.rb +17 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/time_entry_spec.rb +137 -0
- data/spec/time_log_spec.rb +164 -0
- data/spec/time_report_spec.rb +104 -0
- data/spec/timesheet_parser_spec.rb +235 -0
- data/spec/timesheet_spec.rb +188 -0
- data/tasks/rspec.rake +21 -0
- metadata +274 -0
@@ -0,0 +1,235 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'chronic'
|
3
|
+
|
4
|
+
describe TimesheetParser do
|
5
|
+
|
6
|
+
context "when given empty parameters" do
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should show usage" do
|
12
|
+
lambda {TimesheetParser.parse([])}.should raise_error SystemExit
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when parsing in general" do
|
18
|
+
|
19
|
+
it "should dump the options hash if the debug flag is set" do
|
20
|
+
|
21
|
+
outstream = StringIO.new
|
22
|
+
hash = TimesheetParser.parse(%w[--debug add -p a\ project\ name --start 12/1/2009\ at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm --comment a\ comment], outstream)
|
23
|
+
outstream.string().should include("Command-line options hash...")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should report an error if the entire command line is not parsed" do
|
27
|
+
lambda {TimesheetParser.parse(%w[edit -r 100 -p a\ project\ name fiddle-dee-dee])}.should raise_error ArgumentError
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when parsing add command" do
|
33
|
+
|
34
|
+
before :each do
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should fail on a bare add" do
|
38
|
+
lambda {TimesheetParser.parse(["add"])}.should raise_error SystemExit
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should parse a valid complete add command" do
|
42
|
+
hash = TimesheetParser.parse(%w[add -p a\ project\ name --start 12/1/2009\ at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm --comment a\ comment])
|
43
|
+
hash[:command].should eql(:add)
|
44
|
+
hash[:project].should eql("a project name")
|
45
|
+
hash[:start].should eql(Time.local(2009, 12, 1, 11, 0, 0))
|
46
|
+
hash[:end].should eql(Time.local(2009, 12, 1, 14, 0, 0))
|
47
|
+
hash[:comment].should eql("a comment")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should allow comment to be optional" do
|
51
|
+
hash = TimesheetParser.parse(%w[add -p a\ project\ name --start 12/1/2009\at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm])
|
52
|
+
hash[:command].should eql(:add)
|
53
|
+
hash[:project].should eql("a project name")
|
54
|
+
hash[:start].should eql(Time.local(2009, 12, 1, 11, 0, 0))
|
55
|
+
hash[:end].should eql(Time.local(2009, 12, 1, 14, 0, 0))
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should require project" do
|
59
|
+
lambda {TimesheetParser.parse(%w[add --start 12/1/2009\at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm])}.should raise_error SystemExit
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should require start time" do
|
63
|
+
lambda {TimesheetParser.parse(%w[add -p a\ project\ name --end 12/1/2009\ at\ 2:00\ pm --comment a\ comment])}.should raise_error SystemExit
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should require end time" do
|
67
|
+
lambda {TimesheetParser.parse(%w[add -p a\ project\ name --start 12/1/2009\at\ 11:00\ am --comment a\ comment])}.should raise_error SystemExit
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when parsing list command" do
|
73
|
+
|
74
|
+
before :each do
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should accept a bare list" do
|
78
|
+
lambda {TimesheetParser.parse(["list"])}.should_not raise_error SystemExit
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should accept a start and end time" do
|
82
|
+
hash = TimesheetParser.parse(%w[list --start 12/1/2009\at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm])
|
83
|
+
hash[:command].should eql(:report)
|
84
|
+
hash[:detail].should be_true
|
85
|
+
hash[:start].should eql(Time.local(2009, 12, 1, 11, 0, 0))
|
86
|
+
hash[:end].should eql(Time.local(2009, 12, 1, 14, 0, 0))
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should accept --today" do
|
90
|
+
hash = TimesheetParser.parse(%w[list --today])
|
91
|
+
hash[:command].should eql(:report)
|
92
|
+
hash[:detail].should be_true
|
93
|
+
hash[:start].should eql(Chronic.parse('today at 12 am'))
|
94
|
+
hash[:end].should eql(Chronic.parse('tomorrow at 12 am'))
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should fail if start date and --today are used" do
|
98
|
+
lambda {TimesheetParser.parse(%w[list --today --start 12/1/2009\at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm])}.should raise_error SystemExit
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should fail if start date is missing end date" do
|
102
|
+
lambda {TimesheetParser.parse(%w[list --start 12/1/2009\at\ 11:00\ am])}.should raise_error SystemExit
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when parsing edit command" do
|
108
|
+
|
109
|
+
before :each do
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should fail on a bare edit" do
|
113
|
+
lambda {TimesheetParser.parse(["edit"])}.should raise_error SystemExit
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should parse a valid complete edit command" do
|
117
|
+
hash = TimesheetParser.parse(%w[edit -r 100 -p a\ project\ name --start 12/1/2009\at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm --comment a\ comment])
|
118
|
+
hash[:command].should eql(:edit)
|
119
|
+
hash[:record_number].should eql(100)
|
120
|
+
hash[:project].should eql("a project name")
|
121
|
+
hash[:start].should eql(Time.local(2009, 12, 1, 11, 0, 0))
|
122
|
+
hash[:end].should eql(Time.local(2009, 12, 1, 14, 0, 0))
|
123
|
+
hash[:comment].should eql("a comment")
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should allow just comment" do
|
127
|
+
hash = TimesheetParser.parse(%w[edit -r 12 -c a\ new\ comment])
|
128
|
+
hash[:command].should eql(:edit)
|
129
|
+
hash[:record_number].should eql(12)
|
130
|
+
hash[:project].should be_nil
|
131
|
+
hash[:start].should be_nil
|
132
|
+
hash[:end].should be_nil
|
133
|
+
hash[:comment].should eql("a new comment")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should allow just project" do
|
137
|
+
hash = TimesheetParser.parse(%w[edit --record-number 200 --project a\ new\ project])
|
138
|
+
hash[:command].should eql(:edit)
|
139
|
+
hash[:record_number].should eql(200)
|
140
|
+
hash[:project].should eql("a new project")
|
141
|
+
hash[:start].should be_nil
|
142
|
+
hash[:end].should be_nil
|
143
|
+
hash[:comment].should be_nil
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should allow just start time" do
|
147
|
+
hash = TimesheetParser.parse(%w[edit -r 1 -s 12/1/2009\at\ 11:00\ am])
|
148
|
+
hash[:command].should eql(:edit)
|
149
|
+
hash[:record_number].should eql(1)
|
150
|
+
hash[:project].should be_nil
|
151
|
+
hash[:start].should eql(Time.local(2009, 12, 1, 11, 0, 0))
|
152
|
+
hash[:end].should be_nil
|
153
|
+
hash[:comment].should be_nil
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should allow just end time" do
|
157
|
+
hash = TimesheetParser.parse(%w[edit -r 1 -e 12/1/2009\at\ 2:00\ pm])
|
158
|
+
hash[:command].should eql(:edit)
|
159
|
+
hash[:record_number].should eql(1)
|
160
|
+
hash[:project].should be_nil
|
161
|
+
hash[:start].should be_nil
|
162
|
+
hash[:end].should eql(Time.local(2009, 12, 1, 14, 0, 0))
|
163
|
+
hash[:comment].should be_nil
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
context "when parsing delete command" do
|
169
|
+
|
170
|
+
before :each do
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should fail on a bare delete" do
|
174
|
+
lambda {TimesheetParser.parse(["delete"])}.should raise_error SystemExit
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should parse a valid delete command" do
|
178
|
+
hash = TimesheetParser.parse(%w[delete -r 100])
|
179
|
+
hash[:command].should eql(:delete)
|
180
|
+
hash[:record_number].should eql(100)
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
context "when parsing report command" do
|
186
|
+
|
187
|
+
before :each do
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should accept a bare report" do
|
191
|
+
lambda {TimesheetParser.parse(["report"])}.should_not raise_error SystemExit
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should parse a valid complete report command" do
|
195
|
+
hash = TimesheetParser.parse(%w[report --summary --start 12/1/2009\at\ 11:00\ am --end 12/1/2009\ at\ 2:00\ pm])
|
196
|
+
hash[:command].should eql(:report)
|
197
|
+
hash[:summary].should be_true
|
198
|
+
hash[:detail].should be_false
|
199
|
+
hash[:byday].should be_false
|
200
|
+
hash[:start].should eql(Time.local(2009, 12, 1, 11, 0, 0))
|
201
|
+
hash[:end].should eql(Time.local(2009, 12, 1, 14, 0, 0))
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should reject conflicting parameters" do
|
205
|
+
lambda {TimesheetParser.parse(%w[report --summary --detail])}.should raise_error SystemExit
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should reject start without end" do
|
209
|
+
lambda {TimesheetParser.parse(%w[report --summary --start 12/1/2009\at\ 11:00\ am ])}.should raise_error SystemExit
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should allow shortcuts" do
|
213
|
+
hash = TimesheetParser.parse(%w[report --byday --yesterday])
|
214
|
+
hash[:command].should eql(:report)
|
215
|
+
hash[:summary].should be_false
|
216
|
+
hash[:detail].should be_false
|
217
|
+
hash[:byday].should be_true
|
218
|
+
hash[:start].should eql(Chronic.parse('yesterday at 12 am'))
|
219
|
+
hash[:end].should eql(Chronic.parse('today at 12 am'))
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
context "when given nonsense" do
|
225
|
+
|
226
|
+
before :each do
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should reject unknown commands" do
|
230
|
+
lambda {TimesheetParser.parse(%w[trundlebug])}.should raise_error SystemExit
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Timesheet do
|
4
|
+
|
5
|
+
context "when being invoked" do
|
6
|
+
|
7
|
+
it "should print an error when no environment values are defined" do
|
8
|
+
|
9
|
+
params = mock("ARGV")
|
10
|
+
command_hash = mock("command_hash")
|
11
|
+
|
12
|
+
TimesheetParser.should_receive(:parse).with(params).once.and_return(command_hash)
|
13
|
+
|
14
|
+
ENV.should_receive(:[]).with("TIMESHEET_DATA_FILE").once.and_return(nil)
|
15
|
+
ENV.should_receive(:[]).with("HOME").once.and_return(nil)
|
16
|
+
|
17
|
+
command_hash.should_receive(:[]).with(:debug).once.and_return(nil)
|
18
|
+
|
19
|
+
Timesheet.should_receive(:puts).with("Cannot determine location for data. Try timesheet --help for details.").once.and_return(nil)
|
20
|
+
|
21
|
+
Timesheet.run(params)
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should use the environment value for TIMESHEET_DATA_FILE if it is defined" do
|
26
|
+
|
27
|
+
params = mock("ARGV")
|
28
|
+
command_hash = mock("command_hash")
|
29
|
+
store = mock("store")
|
30
|
+
time_log = mock("time_log")
|
31
|
+
time_sheet = mock("time_sheet")
|
32
|
+
timesheet_data_file = mock('ENV["TIMESHEET_DATA_FILE"]')
|
33
|
+
|
34
|
+
expected_timesheet_data_file = "/somepath/someotherpath/somefile.someext"
|
35
|
+
expected_timesheet_data_file_path = "/somepath/someotherpath"
|
36
|
+
|
37
|
+
TimesheetParser.should_receive(:parse).with(params).once.and_return(command_hash)
|
38
|
+
|
39
|
+
ENV.should_receive(:[]).with("TIMESHEET_DATA_FILE").twice.and_return(expected_timesheet_data_file)
|
40
|
+
|
41
|
+
File.should_receive(:dirname).with(expected_timesheet_data_file).once.and_return(expected_timesheet_data_file_path)
|
42
|
+
FileUtils.should_receive(:makedirs).with(expected_timesheet_data_file_path).once.and_return(expected_timesheet_data_file_path)
|
43
|
+
|
44
|
+
YAML::Store.should_receive(:new).with(expected_timesheet_data_file).once.and_return(store)
|
45
|
+
TimeLog.should_receive(:new).with(store).once.and_return(time_log)
|
46
|
+
Timesheet.should_receive(:new).with(time_log).once.and_return(time_sheet)
|
47
|
+
time_sheet.should_receive(:process).with(command_hash)
|
48
|
+
|
49
|
+
Timesheet.run(params)
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should use the environment value for HOME if it is defined and TIMESHEET_DATA_FILE is not" do
|
54
|
+
|
55
|
+
params = mock("ARGV")
|
56
|
+
command_hash = mock("command_hash")
|
57
|
+
store = mock("store")
|
58
|
+
time_log = mock("time_log")
|
59
|
+
time_sheet = mock("time_sheet")
|
60
|
+
|
61
|
+
expected_home = "/Users/someuser"
|
62
|
+
expected_data_file = "/Users/someuser/.timesheet/store.yaml"
|
63
|
+
expected_data_file_path = "/Users/someuser/.timesheet"
|
64
|
+
|
65
|
+
TimesheetParser.should_receive(:parse).with(params).once.and_return(command_hash)
|
66
|
+
|
67
|
+
ENV.should_receive(:[]).with("TIMESHEET_DATA_FILE").twice.and_return(nil)
|
68
|
+
ENV.should_receive(:[]).with("HOME").twice.and_return(expected_home)
|
69
|
+
|
70
|
+
File.should_receive(:dirname).with(expected_data_file).once.and_return(expected_data_file_path)
|
71
|
+
FileUtils.should_receive(:makedirs).with(expected_data_file_path).once.and_return(expected_data_file_path)
|
72
|
+
|
73
|
+
YAML::Store.should_receive(:new).with(expected_data_file).once.and_return(store)
|
74
|
+
TimeLog.should_receive(:new).with(store).once.and_return(time_log)
|
75
|
+
Timesheet.should_receive(:new).with(time_log).once.and_return(time_sheet)
|
76
|
+
time_sheet.should_receive(:process).with(command_hash)
|
77
|
+
|
78
|
+
Timesheet.run(params)
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when processing command" do
|
85
|
+
|
86
|
+
before :each do
|
87
|
+
@command = mock("command")
|
88
|
+
@timelog = mock("timelog")
|
89
|
+
@timesheet = Timesheet.new(@timelog)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should dispatch to the proper command handler" do
|
93
|
+
valid_dispatch_cases = {
|
94
|
+
:add => :process_add_command,
|
95
|
+
:edit => :process_edit_command,
|
96
|
+
:report => :process_report_command}
|
97
|
+
|
98
|
+
valid_dispatch_cases.each do |key, value|
|
99
|
+
@command.should_receive(:[]).with(:command).once.and_return(key)
|
100
|
+
@timesheet.should_receive(value).with(@command).once
|
101
|
+
@timesheet.process(@command)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should raise error when the command is not understood" do
|
106
|
+
@command.should_receive(:[]).with(:command).once.and_return("invalid_command")
|
107
|
+
lambda { @timesheet.process(@command) }.should raise_error RuntimeError
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when processing add command" do
|
113
|
+
|
114
|
+
it "should perform an add" do
|
115
|
+
command = mock("add command")
|
116
|
+
timelog = mock("timelog")
|
117
|
+
timesheet = Timesheet.new(timelog)
|
118
|
+
|
119
|
+
project = mock("project")
|
120
|
+
start_time = mock("start time")
|
121
|
+
end_time = mock("end time")
|
122
|
+
entry = mock("time entry")
|
123
|
+
|
124
|
+
command.should_receive(:[]).with(:project).once.and_return(project)
|
125
|
+
command.should_receive(:[]).with(:start).once.and_return(start_time)
|
126
|
+
command.should_receive(:[]).with(:end).once.and_return(end_time)
|
127
|
+
command.should_receive(:[]).with(:comment).once.and_return(nil)
|
128
|
+
TimeEntry.should_receive(:new).with(project, start_time, end_time, nil).and_return(entry)
|
129
|
+
timelog.should_receive(:add).with(entry)
|
130
|
+
|
131
|
+
timesheet.process_add_command(command)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when processing edit command" do
|
137
|
+
|
138
|
+
it "should perform an edit" do
|
139
|
+
command = mock("edit command")
|
140
|
+
timelog = mock("timelog")
|
141
|
+
timesheet = Timesheet.new(timelog)
|
142
|
+
|
143
|
+
command.should_receive(:delete).with(:record_number).once.and_return(100)
|
144
|
+
timelog.should_receive(:update).with(100, command)
|
145
|
+
|
146
|
+
timesheet.process_edit_command(command)
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when processing delete command" do
|
152
|
+
|
153
|
+
it "should perform a delete" do
|
154
|
+
command = mock("delete command")
|
155
|
+
timelog = mock("timelog")
|
156
|
+
timesheet = Timesheet.new(timelog)
|
157
|
+
|
158
|
+
command.should_receive(:delete).with(:record_number).once.and_return(100)
|
159
|
+
timelog.should_receive(:delete).with(100)
|
160
|
+
|
161
|
+
timesheet.process_delete_command(command)
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
context "when processing report command" do
|
167
|
+
|
168
|
+
it "should produce a report" do
|
169
|
+
command = mock("report command")
|
170
|
+
timelog = mock("timelog")
|
171
|
+
start_time = mock("start time")
|
172
|
+
end_time = mock("end time")
|
173
|
+
entries = mock("entries")
|
174
|
+
time_report = mock("time report")
|
175
|
+
timesheet = Timesheet.new(timelog)
|
176
|
+
|
177
|
+
command.should_receive(:[]).with(:start).once.and_return(start_time)
|
178
|
+
command.should_receive(:[]).with(:end).once.and_return(end_time)
|
179
|
+
timelog.should_receive(:extract_entries).with(start_time, end_time).once.and_return(entries)
|
180
|
+
TimeReport.should_receive(:new).with(entries).once.and_return(time_report)
|
181
|
+
time_report.should_receive(:report).with(command)
|
182
|
+
|
183
|
+
timesheet.process_report_command(command)
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require 'spec'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'spec/rake/spectask'
|
9
|
+
rescue LoadError
|
10
|
+
puts <<-EOS
|
11
|
+
To use rspec for testing you must install rspec gem:
|
12
|
+
gem install rspec
|
13
|
+
EOS
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run the specs under spec/models"
|
18
|
+
Spec::Rake::SpecTask.new do |t|
|
19
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
20
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: timesheet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John F. Schank III
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-05 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: archive-tar-minitar
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: chronic
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: color
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: fastercsv
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: hoe
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: json_pure
|
77
|
+
type: :runtime
|
78
|
+
version_requirement:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: newgem
|
87
|
+
type: :runtime
|
88
|
+
version_requirement:
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: "0"
|
94
|
+
version:
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: pdf-writer
|
97
|
+
type: :runtime
|
98
|
+
version_requirement:
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: "0"
|
104
|
+
version:
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: rake
|
107
|
+
type: :runtime
|
108
|
+
version_requirement:
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
version:
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: RedCloth
|
117
|
+
type: :runtime
|
118
|
+
version_requirement:
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: "0"
|
124
|
+
version:
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rich_units
|
127
|
+
type: :runtime
|
128
|
+
version_requirement:
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: "0"
|
134
|
+
version:
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: rspec
|
137
|
+
type: :runtime
|
138
|
+
version_requirement:
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: "0"
|
144
|
+
version:
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: rubigen
|
147
|
+
type: :runtime
|
148
|
+
version_requirement:
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: "0"
|
154
|
+
version:
|
155
|
+
- !ruby/object:Gem::Dependency
|
156
|
+
name: rubyforge
|
157
|
+
type: :runtime
|
158
|
+
version_requirement:
|
159
|
+
version_requirements: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: "0"
|
164
|
+
version:
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: ruport
|
167
|
+
type: :runtime
|
168
|
+
version_requirement:
|
169
|
+
version_requirements: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: "0"
|
174
|
+
version:
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: syntax
|
177
|
+
type: :runtime
|
178
|
+
version_requirement:
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - ">="
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: "0"
|
184
|
+
version:
|
185
|
+
- !ruby/object:Gem::Dependency
|
186
|
+
name: transaction-simple
|
187
|
+
type: :runtime
|
188
|
+
version_requirement:
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: "0"
|
194
|
+
version:
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: hoe
|
197
|
+
type: :development
|
198
|
+
version_requirement:
|
199
|
+
version_requirements: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: 2.4.0
|
204
|
+
version:
|
205
|
+
description: |-
|
206
|
+
<i>Timesheet</i> is simple ruby application for tracking time spent on projects.
|
207
|
+
It is a console application that uses a simple text file storage back-end (YAML::Store)
|
208
|
+
|
209
|
+
The main idea is to be able to produce reports of hours spent, such that I can use geektool to display the reports.
|
210
|
+
email:
|
211
|
+
- jschank@mac.com
|
212
|
+
executables:
|
213
|
+
- timesheet
|
214
|
+
extensions: []
|
215
|
+
|
216
|
+
extra_rdoc_files:
|
217
|
+
- History.txt
|
218
|
+
- Manifest.txt
|
219
|
+
files:
|
220
|
+
- History.txt
|
221
|
+
- Manifest.txt
|
222
|
+
- README.rdoc
|
223
|
+
- Rakefile
|
224
|
+
- bin/timesheet
|
225
|
+
- lib/timesheet.rb
|
226
|
+
- lib/timesheet/range_extensions.rb
|
227
|
+
- lib/timesheet/time_entry.rb
|
228
|
+
- lib/timesheet/time_log.rb
|
229
|
+
- lib/timesheet/time_report.rb
|
230
|
+
- lib/timesheet/timesheet_parser.rb
|
231
|
+
- lib/timesheet/trollop.rb
|
232
|
+
- script/console
|
233
|
+
- script/destroy
|
234
|
+
- script/generate
|
235
|
+
- spec/range_extensions_spec.rb
|
236
|
+
- spec/spec.opts
|
237
|
+
- spec/spec_helper.rb
|
238
|
+
- spec/time_entry_spec.rb
|
239
|
+
- spec/time_log_spec.rb
|
240
|
+
- spec/time_report_spec.rb
|
241
|
+
- spec/timesheet_parser_spec.rb
|
242
|
+
- spec/timesheet_spec.rb
|
243
|
+
- tasks/rspec.rake
|
244
|
+
has_rdoc: true
|
245
|
+
homepage: http://github.com/jschank/timesheet
|
246
|
+
licenses: []
|
247
|
+
|
248
|
+
post_install_message:
|
249
|
+
rdoc_options:
|
250
|
+
- --main
|
251
|
+
- README.rdoc
|
252
|
+
require_paths:
|
253
|
+
- lib
|
254
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
255
|
+
requirements:
|
256
|
+
- - ">="
|
257
|
+
- !ruby/object:Gem::Version
|
258
|
+
version: "0"
|
259
|
+
version:
|
260
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - ">="
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: "0"
|
265
|
+
version:
|
266
|
+
requirements: []
|
267
|
+
|
268
|
+
rubyforge_project: timesheet
|
269
|
+
rubygems_version: 1.3.5
|
270
|
+
signing_key:
|
271
|
+
specification_version: 3
|
272
|
+
summary: <i>Timesheet</i> is simple ruby application for tracking time spent on projects
|
273
|
+
test_files: []
|
274
|
+
|