freshtrack 0.2.2 → 0.3.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 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