freshtrack 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.3.0 2008-08-27
2
+
3
+ * 1 minor enhancement:
4
+ * Now using my one_inch_punch gem, getting the time data without having to shell out
5
+
1
6
  == 0.2.2 2008-02-27
2
7
 
3
8
  * 1 tiny enhancement:
data/Manifest.txt CHANGED
@@ -22,6 +22,7 @@ script/destroy
22
22
  script/generate
23
23
  setup.rb
24
24
  spec/base_object_spec.rb
25
+ spec/freshtrack_command_spec.rb
25
26
  spec/freshtrack_spec.rb
26
27
  spec/project_spec.rb
27
28
  spec/task_spec.rb
data/README.txt CHANGED
@@ -1,18 +1,36 @@
1
- Freshtrack is used to automatically create time entries in FreshBooks.
1
+ = freshtrack
2
2
 
3
- It presently depends on punch, the gem by Ara T. Howard, and any arguments given to
4
- freshtrack are passed along to punch as if freshtrack were an alias for 'punch list'.
3
+ == DESCRIPTION:
5
4
 
6
- For example
5
+ Freshtrack is used to automatically create time entries in FreshBooks from your own tracked time.
7
6
 
8
- freshtrack proj --after 2008-01-16 --before 2008-02-01
7
+ == FEATURES/PROBLEMS:
9
8
 
10
- would get time data for the second half of January 2008 by using the command
9
+ * Simple and easy to use
11
10
 
12
- punch list proj --after 2008-01-16 --before 2008-02-01
11
+ * Only works with data from one_inch_punch
13
12
 
13
+ == SYNOPSIS:
14
14
 
15
- Freshtrack requires a configuration file, ~/.freshtrack.yml, that looks something like
15
+ $ freshtrack proj
16
+
17
+ or
18
+
19
+ $ freshtrack proj --before 2008-08-16
20
+
21
+ or! (if you really want)
22
+
23
+ require 'freshtrack'
24
+
25
+ Freshtrack.init
26
+ Freshtrack.track('proj', :before => Time.parse('2008-08-16'))
27
+
28
+ == REQUIREMENTS:
29
+
30
+ * one_inch_punch (gem)
31
+ * freshbooks (gem)
32
+ * A FreshBooks account
33
+ * a configuration file located at ~/.freshtrack.yml and looking like
16
34
 
17
35
  ---
18
36
  company: Company Name
@@ -22,9 +40,13 @@ Freshtrack requires a configuration file, ~/.freshtrack.yml, that looks somethin
22
40
  :project: FreshBooks Project Name
23
41
  :task: FreshBooks Task Name
24
42
 
25
- The 'Company Name' is the XXX in 'XXX.freshbooks.com'. The 'project_name' is the XXX in 'punch list XXX'
43
+ (The 'Company Name' is the XXX in 'XXX.freshbooks.com'. The 'project_name' is the XXX in 'punch list XXX'.)
44
+
45
+ == INSTALL:
46
+
47
+ * gem install freshtrack
26
48
 
49
+ == THANKS:
27
50
 
28
- NOTE: As of this writing, punch (0.0.1) specifically requires attributes version 5.0.0 even though 5.0.1 is out.
29
- Because of the way gems work, punch will not work if both are installed. Make sure the specific installed version
30
- of attributes is 5.0.0.
51
+ * Kevin Barnes and Rick Bradley, for giving me a reason to track time and invoice people for it
52
+ * The FreshBooks team, for making invoicing easy
data/bin/freshtrack CHANGED
@@ -10,8 +10,34 @@ rescue LoadError
10
10
  end
11
11
 
12
12
  require 'freshtrack'
13
+ require 'optparse'
14
+ require 'time'
15
+
16
+ OPTIONS = {}
17
+ MANDATORY_OPTIONS = %w[]
18
+
19
+ parser = OptionParser.new do |opts|
20
+ opts.banner = <<BANNER
21
+ Usage: #{File.basename($0)} [options]
22
+
23
+ Options are:
24
+ BANNER
25
+ opts.separator ''
26
+ opts.on('-v', '--version',
27
+ "Show the #{File.basename($0)} version number and exit") { require 'freshtrack/version'; puts "#{File.basename($0)} #{Freshtrack::VERSION::STRING}"; exit }
28
+ opts.on('--after [TIME]', String,
29
+ "Restrict command to only after the given time") { |time| OPTIONS[:after] = Time.parse(time) }
30
+ opts.on('--before [TIME]', String,
31
+ "Restrict command to only before the given time") { |time| OPTIONS[:before] = Time.parse(time) }
32
+ opts.on("-h", "--help",
33
+ "Show this help message.") { puts opts; exit }
34
+ opts.parse!(ARGV)
35
+
36
+ if MANDATORY_OPTIONS && MANDATORY_OPTIONS.find { |option| OPTIONS[option.to_sym].nil? }
37
+ puts opts; exit
38
+ end
39
+ end
13
40
 
14
- # do stuff
15
41
  project = ARGV.shift
16
42
 
17
43
  unless project
@@ -20,4 +46,4 @@ unless project
20
46
  end
21
47
 
22
48
  Freshtrack.init
23
- Freshtrack.track(project, ARGV.join(' '))
49
+ Freshtrack.track(project, OPTIONS)
data/config/hoe.rb CHANGED
@@ -2,7 +2,7 @@ require 'freshtrack/version'
2
2
 
3
3
  AUTHOR = 'Yossef Mendelssohn' # can also be an array of Authors
4
4
  EMAIL = 'ymendel@pobox.com'
5
- DESCRIPTION = "description of gem"
5
+ DESCRIPTION = "Track your time on FreshBooks"
6
6
  GEM_NAME = 'freshtrack' # what ppl will type to install your gem
7
7
  RUBYFORGE_PROJECT = 'yomendel' # The unix name for your project
8
8
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
@@ -60,8 +60,8 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
60
60
  # == Optional
61
61
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
62
62
  p.extra_deps = [ # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
- ['freshbooks', '>= 2.1'],
64
- ['punch', '>= 0.0.1']
63
+ ['freshbooks', '= 2.1'],
64
+ ['one_inch_punch', '>= 0.0.3']
65
65
  ]
66
66
 
67
67
  #p.spec_extras = {} # A hash of extra values to set in the gemspec.
@@ -1,8 +1,8 @@
1
1
  module Freshtrack #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 2
5
- TINY = 2
4
+ MINOR = 3
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/freshtrack.rb CHANGED
@@ -2,6 +2,7 @@ $:.unshift File.dirname(__FILE__)
2
2
  require 'freshbooks/extensions'
3
3
  require 'freshtrack/core_ext'
4
4
  require 'yaml'
5
+ require 'punch'
5
6
 
6
7
  module Freshtrack
7
8
  class << self
@@ -36,14 +37,10 @@ module Freshtrack
36
37
  raise unless @task
37
38
  end
38
39
 
39
- def get_time_data(project_name, options = '')
40
- time_data = IO.read("| punch list #{project_name} #{options}")
41
- convert_time_data(time_data)
42
- end
43
-
44
- def convert_time_data(time_data)
45
- raw = YAML.load(time_data)
46
- condense_time_data(raw)
40
+ def get_time_data(project_name, options = {})
41
+ Punch.load
42
+ time_data = Punch.list(project_name, options)
43
+ condense_time_data(time_data)
47
44
  end
48
45
 
49
46
  def condense_time_data(time_data)
@@ -73,12 +70,12 @@ module Freshtrack
73
70
  end
74
71
  end
75
72
 
76
- def get_data(project_name, options = '')
73
+ def get_data(project_name, options = {})
77
74
  get_project_data(project_name)
78
75
  get_time_data(project_name, options)
79
76
  end
80
77
 
81
- def track(project_name, options = '')
78
+ def track(project_name, options = {})
82
79
  data = get_data(project_name, options)
83
80
  data.each do |entry_data|
84
81
  create_entry(entry_data)
data/script/destroy CHANGED
File without changes
data/script/generate CHANGED
File without changes
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe 'freshtrack command' do
4
+ def run_command(*args)
5
+ Object.const_set(:ARGV, args)
6
+ begin
7
+ eval File.read(File.join(File.dirname(__FILE__), *%w[.. bin freshtrack]))
8
+ rescue SystemExit
9
+ end
10
+ end
11
+
12
+ before :each do
13
+ [:ARGV, :OPTIONS, :MANDATORY_OPTIONS].each do |const|
14
+ Object.send(:remove_const, const) if Object.const_defined?(const)
15
+ end
16
+
17
+ Freshtrack.stubs(:init)
18
+ Freshtrack.stubs(:track)
19
+
20
+ @project = 'myproj'
21
+ end
22
+
23
+ it 'should exist' do
24
+ lambda { run_command(@project) }.should_not raise_error(Errno::ENOENT)
25
+ end
26
+
27
+ it 'should require a project' do
28
+ self.expects(:puts) { |text| text.match(/usage.+project/i) }
29
+ run_command
30
+ end
31
+
32
+ it 'should init Freshtrack' do
33
+ Freshtrack.expects(:init)
34
+ run_command(@project)
35
+ end
36
+
37
+ it 'should track time' do
38
+ Freshtrack.expects(:track)
39
+ run_command(@project)
40
+ end
41
+
42
+ it 'should track time for the given project' do
43
+ Freshtrack.expects(:track).with(@project, anything)
44
+ run_command(@project)
45
+ end
46
+
47
+ describe 'when options specified' do
48
+ it "should pass on an 'after' time option given by --after" do
49
+ time_option = '2008-08-26 09:47'
50
+ time = Time.local(2008, 8, 26, 9, 47)
51
+ Freshtrack.expects(:track).with(@project, has_entry(:after => time))
52
+ run_command(@project, '--after', time_option)
53
+ end
54
+
55
+ it "should pass on a 'before' time option given by --before" do
56
+ time_option = '2008-08-23 15:39'
57
+ time = Time.local(2008, 8, 23, 15, 39)
58
+ Freshtrack.expects(:track).with(@project, has_entry(:before => time))
59
+ run_command(@project, '--before', time_option)
60
+ end
61
+
62
+ it 'should handle a time option given as a date' do
63
+ time_option = '2008-08-23'
64
+ time = Time.local(2008, 8, 23)
65
+ Freshtrack.expects(:track).with(@project, has_entry(:before => time))
66
+ run_command(@project, '--before', time_option)
67
+ end
68
+ end
69
+
70
+ it 'should pass no options if none specified' do
71
+ Freshtrack.expects(:track).with(@project, {})
72
+ run_command(@project)
73
+ end
74
+ end
@@ -132,8 +132,9 @@ describe Freshtrack do
132
132
  before :each do
133
133
  @project_name = :proj
134
134
  @time_data = stub('time data')
135
- IO.stubs(:read).returns(@time_data)
136
- Freshtrack.stubs(:convert_time_data)
135
+ Punch.stubs(:load)
136
+ Punch.stubs(:list).returns(@time_data)
137
+ Freshtrack.stubs(:condense_time_data)
137
138
  end
138
139
 
139
140
  it 'should require an argument' do
@@ -144,74 +145,45 @@ describe Freshtrack do
144
145
  lambda { Freshtrack.get_time_data(@project_name) }.should_not raise_error(ArgumentError)
145
146
  end
146
147
 
147
- it 'should accept an option string' do
148
- lambda { Freshtrack.get_time_data(@project_name, 'option string') }.should_not raise_error(ArgumentError)
148
+ it 'should accept options' do
149
+ lambda { Freshtrack.get_time_data(@project_name, :after => Time.now) }.should_not raise_error(ArgumentError)
150
+ end
151
+
152
+ it 'should have punch load the time data' do
153
+ Punch.expects(:load)
154
+ Freshtrack.get_time_data(@project_name)
149
155
  end
150
156
 
151
- it 'should get the time data (from punch)' do
152
- IO.expects(:read).with(regexp_matches(/^\| punch list\b/))
157
+ it 'should get the time data from punch' do
158
+ Punch.expects(:list)
153
159
  Freshtrack.get_time_data(@project_name)
154
160
  end
155
161
 
156
162
  it 'should pass the supplied project when getting the time data' do
157
- IO.expects(:read).with(regexp_matches(/\b#{@project_name}\b/))
163
+ Punch.expects(:list).with(@project_name, anything)
158
164
  Freshtrack.get_time_data(@project_name)
159
165
  end
160
166
 
161
- it 'should pass the supplied option string on when getting the time data' do
162
- options = 'options go here'
163
- IO.expects(:read).with(regexp_matches(/\b#{@project_name} #{options}\b/))
167
+ it 'should pass the supplied options on when getting the time data' do
168
+ options = { :after => Time.now - 12345 }
169
+ Punch.expects(:list).with(@project_name, options)
164
170
  Freshtrack.get_time_data(@project_name, options)
165
171
  end
166
172
 
167
- it 'should default option string to empty string' do
168
- IO.expects(:read).with(regexp_matches(/\b#{@project_name} $/))
173
+ it 'should pass an empty hash by default' do
174
+ Punch.expects(:list).with(@project_name, {})
169
175
  Freshtrack.get_time_data(@project_name)
170
176
  end
171
177
 
172
- it 'should convert the time data' do
173
- Freshtrack.expects(:convert_time_data).with(@time_data)
178
+ it 'should condense the time data' do
179
+ Freshtrack.expects(:condense_time_data).with(@time_data)
174
180
  Freshtrack.get_time_data(@project_name)
175
181
  end
176
182
 
177
- it 'should return the converted data' do
178
- converted = stub('converted time data')
179
- Freshtrack.stubs(:convert_time_data).returns(converted)
180
- Freshtrack.get_time_data(@project_name).should == converted
181
- end
182
- end
183
-
184
- describe 'converting time data' do
185
- before :each do
186
- @time_data = stub('time data')
187
- YAML.stubs(:load)
188
- Freshtrack.stubs(:condense_time_data)
189
- end
190
-
191
- it 'should require an argument' do
192
- lambda { Freshtrack.convert_time_data }.should raise_error(ArgumentError)
193
- end
194
-
195
- it 'should accept an argument' do
196
- lambda { Freshtrack.convert_time_data(@time_data) }.should_not raise_error(ArgumentError)
197
- end
198
-
199
- it 'should convert the time data from YAML' do
200
- YAML.expects(:load).with(@time_data)
201
- Freshtrack.convert_time_data(@time_data)
202
- end
203
-
204
- it 'should condense the raw data' do
205
- raw = stub('raw time data')
206
- YAML.stubs(:load).returns(raw)
207
- Freshtrack.expects(:condense_time_data).with(raw)
208
- Freshtrack.convert_time_data(@project_name)
209
- end
210
-
211
183
  it 'should return the condensed data' do
212
184
  condensed = stub('condensed time data')
213
185
  Freshtrack.stubs(:condense_time_data).returns(condensed)
214
- Freshtrack.convert_time_data(@time_data).should == condensed
186
+ Freshtrack.get_time_data(@project_name).should == condensed
215
187
  end
216
188
  end
217
189
 
@@ -394,8 +366,8 @@ describe Freshtrack do
394
366
  lambda { Freshtrack.get_data(@project_name) }.should_not raise_error(ArgumentError)
395
367
  end
396
368
 
397
- it 'should accept an option string' do
398
- lambda { Freshtrack.get_data(@project_name, 'option string') }.should_not raise_error(ArgumentError)
369
+ it 'should accept options' do
370
+ lambda { Freshtrack.get_data(@project_name, :before => Time.now) }.should_not raise_error(ArgumentError)
399
371
  end
400
372
 
401
373
  it 'should get project data for supplied project' do
@@ -408,14 +380,14 @@ describe Freshtrack do
408
380
  Freshtrack.get_data(@project_name)
409
381
  end
410
382
 
411
- it 'should pass option string on when getting time data' do
412
- options = 'here be options'
383
+ it 'should pass options on when getting time data' do
384
+ options = { :after => Time.now - 12345 }
413
385
  Freshtrack.expects(:get_time_data).with(@project_name, options)
414
386
  Freshtrack.get_data(@project_name, options)
415
387
  end
416
388
 
417
- it 'should default option string to empty string' do
418
- Freshtrack.expects(:get_time_data).with(@project_name, '')
389
+ it 'should default options to an empty hash' do
390
+ Freshtrack.expects(:get_time_data).with(@project_name, {})
419
391
  Freshtrack.get_data(@project_name)
420
392
  end
421
393
 
@@ -441,8 +413,8 @@ describe Freshtrack do
441
413
  lambda { Freshtrack.track(@project_name) }.should_not raise_error(ArgumentError)
442
414
  end
443
415
 
444
- it 'should accept an option string' do
445
- lambda { Freshtrack.track(@project_name, 'option string') }.should_not raise_error(ArgumentError)
416
+ it 'should accept options' do
417
+ lambda { Freshtrack.track(@project_name, :before => Time.now) }.should_not raise_error(ArgumentError)
446
418
  end
447
419
 
448
420
  it 'should get data for supplied project' do
@@ -450,14 +422,14 @@ describe Freshtrack do
450
422
  Freshtrack.track(@project_name)
451
423
  end
452
424
 
453
- it 'should pass option string on when getting data' do
454
- options = 'here be options'
425
+ it 'should pass options on when getting data' do
426
+ options = { :after => Time.now - 12345 }
455
427
  Freshtrack.expects(:get_data).with(@project_name, options).returns(@data)
456
428
  Freshtrack.track(@project_name, options)
457
429
  end
458
430
 
459
- it 'should default option string to empty string' do
460
- Freshtrack.expects(:get_data).with(@project_name, '').returns(@data)
431
+ it 'should default options to an empty hash' do
432
+ Freshtrack.expects(:get_data).with(@project_name, {}).returns(@data)
461
433
  Freshtrack.track(@project_name)
462
434
  end
463
435
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: freshtrack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yossef Mendelssohn
@@ -9,28 +9,40 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-27 00:00:00 -06:00
12
+ date: 2008-08-27 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: freshbooks
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
20
- - - ">="
21
+ - - "="
21
22
  - !ruby/object:Gem::Version
22
23
  version: "2.1"
23
24
  version:
24
25
  - !ruby/object:Gem::Dependency
25
- name: punch
26
+ name: one_inch_punch
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.3
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
26
38
  version_requirement:
27
39
  version_requirements: !ruby/object:Gem::Requirement
28
40
  requirements:
29
41
  - - ">="
30
42
  - !ruby/object:Gem::Version
31
- version: 0.0.1
43
+ version: 1.7.0
32
44
  version:
33
- description: description of gem
45
+ description: Track your time on FreshBooks
34
46
  email: ymendel@pobox.com
35
47
  executables:
36
48
  - freshtrack
@@ -66,6 +78,7 @@ files:
66
78
  - script/generate
67
79
  - setup.rb
68
80
  - spec/base_object_spec.rb
81
+ - spec/freshtrack_command_spec.rb
69
82
  - spec/freshtrack_spec.rb
70
83
  - spec/project_spec.rb
71
84
  - spec/task_spec.rb
@@ -102,9 +115,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
115
  requirements: []
103
116
 
104
117
  rubyforge_project: yomendel
105
- rubygems_version: 1.0.1
118
+ rubygems_version: 1.2.0
106
119
  signing_key:
107
120
  specification_version: 2
108
- summary: description of gem
121
+ summary: Track your time on FreshBooks
109
122
  test_files: []
110
123